diff options
Diffstat (limited to 'clang/lib/Driver')
107 files changed, 41021 insertions, 0 deletions
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp new file mode 100644 index 0000000000000..0eb4c7257e7a8 --- /dev/null +++ b/clang/lib/Driver/Action.cpp @@ -0,0 +1,417 @@ +//===- Action.cpp - Abstract compilation steps ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Action.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <string> + +using namespace clang; +using namespace driver; +using namespace llvm::opt; + +Action::~Action() = default; + +const char *Action::getClassName(ActionClass AC) { +  switch (AC) { +  case InputClass: return "input"; +  case BindArchClass: return "bind-arch"; +  case OffloadClass: +    return "offload"; +  case PreprocessJobClass: return "preprocessor"; +  case PrecompileJobClass: return "precompiler"; +  case HeaderModulePrecompileJobClass: return "header-module-precompiler"; +  case AnalyzeJobClass: return "analyzer"; +  case MigrateJobClass: return "migrator"; +  case CompileJobClass: return "compiler"; +  case BackendJobClass: return "backend"; +  case AssembleJobClass: return "assembler"; +  case IfsMergeJobClass: return "interface-stub-merger"; +  case LinkJobClass: return "linker"; +  case LipoJobClass: return "lipo"; +  case DsymutilJobClass: return "dsymutil"; +  case VerifyDebugInfoJobClass: return "verify-debug-info"; +  case VerifyPCHJobClass: return "verify-pch"; +  case OffloadBundlingJobClass: +    return "clang-offload-bundler"; +  case OffloadUnbundlingJobClass: +    return "clang-offload-unbundler"; +  case OffloadWrapperJobClass: +    return "clang-offload-wrapper"; +  } + +  llvm_unreachable("invalid class"); +} + +void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) { +  // Offload action set its own kinds on their dependences. +  if (Kind == OffloadClass) +    return; +  // Unbundling actions use the host kinds. +  if (Kind == OffloadUnbundlingJobClass) +    return; + +  assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) && +         "Setting device kind to a different device??"); +  assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??"); +  OffloadingDeviceKind = OKind; +  OffloadingArch = OArch; + +  for (auto *A : Inputs) +    A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch); +} + +void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) { +  // Offload action set its own kinds on their dependences. +  if (Kind == OffloadClass) +    return; + +  assert(OffloadingDeviceKind == OFK_None && +         "Setting a host kind in a device action."); +  ActiveOffloadKindMask |= OKinds; +  OffloadingArch = OArch; + +  for (auto *A : Inputs) +    A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch); +} + +void Action::propagateOffloadInfo(const Action *A) { +  if (unsigned HK = A->getOffloadingHostActiveKinds()) +    propagateHostOffloadInfo(HK, A->getOffloadingArch()); +  else +    propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(), +                               A->getOffloadingArch()); +} + +std::string Action::getOffloadingKindPrefix() const { +  switch (OffloadingDeviceKind) { +  case OFK_None: +    break; +  case OFK_Host: +    llvm_unreachable("Host kind is not an offloading device kind."); +    break; +  case OFK_Cuda: +    return "device-cuda"; +  case OFK_OpenMP: +    return "device-openmp"; +  case OFK_HIP: +    return "device-hip"; + +    // TODO: Add other programming models here. +  } + +  if (!ActiveOffloadKindMask) +    return {}; + +  std::string Res("host"); +  assert(!((ActiveOffloadKindMask & OFK_Cuda) && +           (ActiveOffloadKindMask & OFK_HIP)) && +         "Cannot offload CUDA and HIP at the same time"); +  if (ActiveOffloadKindMask & OFK_Cuda) +    Res += "-cuda"; +  if (ActiveOffloadKindMask & OFK_HIP) +    Res += "-hip"; +  if (ActiveOffloadKindMask & OFK_OpenMP) +    Res += "-openmp"; + +  // TODO: Add other programming models here. + +  return Res; +} + +/// Return a string that can be used as prefix in order to generate unique files +/// for each offloading kind. +std::string +Action::GetOffloadingFileNamePrefix(OffloadKind Kind, +                                    StringRef NormalizedTriple, +                                    bool CreatePrefixForHost) { +  // Don't generate prefix for host actions unless required. +  if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host)) +    return {}; + +  std::string Res("-"); +  Res += GetOffloadKindName(Kind); +  Res += "-"; +  Res += NormalizedTriple; +  return Res; +} + +/// Return a string with the offload kind name. If that is not defined, we +/// assume 'host'. +StringRef Action::GetOffloadKindName(OffloadKind Kind) { +  switch (Kind) { +  case OFK_None: +  case OFK_Host: +    return "host"; +  case OFK_Cuda: +    return "cuda"; +  case OFK_OpenMP: +    return "openmp"; +  case OFK_HIP: +    return "hip"; + +    // TODO: Add other programming models here. +  } + +  llvm_unreachable("invalid offload kind"); +} + +void InputAction::anchor() {} + +InputAction::InputAction(const Arg &_Input, types::ID _Type) +    : Action(InputClass, _Type), Input(_Input) {} + +void BindArchAction::anchor() {} + +BindArchAction::BindArchAction(Action *Input, StringRef ArchName) +    : Action(BindArchClass, Input), ArchName(ArchName) {} + +void OffloadAction::anchor() {} + +OffloadAction::OffloadAction(const HostDependence &HDep) +    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) { +  OffloadingArch = HDep.getBoundArch(); +  ActiveOffloadKindMask = HDep.getOffloadKinds(); +  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(), +                                             HDep.getBoundArch()); +} + +OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty) +    : Action(OffloadClass, DDeps.getActions(), Ty), +      DevToolChains(DDeps.getToolChains()) { +  auto &OKinds = DDeps.getOffloadKinds(); +  auto &BArchs = DDeps.getBoundArchs(); + +  // If all inputs agree on the same kind, use it also for this action. +  if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); })) +    OffloadingDeviceKind = OKinds.front(); + +  // If we have a single dependency, inherit the architecture from it. +  if (OKinds.size() == 1) +    OffloadingArch = BArchs.front(); + +  // Propagate info to the dependencies. +  for (unsigned i = 0, e = getInputs().size(); i != e; ++i) +    getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]); +} + +OffloadAction::OffloadAction(const HostDependence &HDep, +                             const DeviceDependences &DDeps) +    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()), +      DevToolChains(DDeps.getToolChains()) { +  // We use the kinds of the host dependence for this action. +  OffloadingArch = HDep.getBoundArch(); +  ActiveOffloadKindMask = HDep.getOffloadKinds(); +  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(), +                                             HDep.getBoundArch()); + +  // Add device inputs and propagate info to the device actions. Do work only if +  // we have dependencies. +  for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) +    if (auto *A = DDeps.getActions()[i]) { +      getInputs().push_back(A); +      A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i], +                                    DDeps.getBoundArchs()[i]); +    } +} + +void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const { +  if (!HostTC) +    return; +  assert(!getInputs().empty() && "No dependencies for offload action??"); +  auto *A = getInputs().front(); +  Work(A, HostTC, A->getOffloadingArch()); +} + +void OffloadAction::doOnEachDeviceDependence( +    const OffloadActionWorkTy &Work) const { +  auto I = getInputs().begin(); +  auto E = getInputs().end(); +  if (I == E) +    return; + +  // We expect to have the same number of input dependences and device tool +  // chains, except if we also have a host dependence. In that case we have one +  // more dependence than we have device tool chains. +  assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) && +         "Sizes of action dependences and toolchains are not consistent!"); + +  // Skip host action +  if (HostTC) +    ++I; + +  auto TI = DevToolChains.begin(); +  for (; I != E; ++I, ++TI) +    Work(*I, *TI, (*I)->getOffloadingArch()); +} + +void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const { +  doOnHostDependence(Work); +  doOnEachDeviceDependence(Work); +} + +void OffloadAction::doOnEachDependence(bool IsHostDependence, +                                       const OffloadActionWorkTy &Work) const { +  if (IsHostDependence) +    doOnHostDependence(Work); +  else +    doOnEachDeviceDependence(Work); +} + +bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; } + +Action *OffloadAction::getHostDependence() const { +  assert(hasHostDependence() && "Host dependence does not exist!"); +  assert(!getInputs().empty() && "No dependencies for offload action??"); +  return HostTC ? getInputs().front() : nullptr; +} + +bool OffloadAction::hasSingleDeviceDependence( +    bool DoNotConsiderHostActions) const { +  if (DoNotConsiderHostActions) +    return getInputs().size() == (HostTC ? 2 : 1); +  return !HostTC && getInputs().size() == 1; +} + +Action * +OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const { +  assert(hasSingleDeviceDependence(DoNotConsiderHostActions) && +         "Single device dependence does not exist!"); +  // The previous assert ensures the number of entries in getInputs() is +  // consistent with what we are doing here. +  return HostTC ? getInputs()[1] : getInputs().front(); +} + +void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, +                                           const char *BoundArch, +                                           OffloadKind OKind) { +  DeviceActions.push_back(&A); +  DeviceToolChains.push_back(&TC); +  DeviceBoundArchs.push_back(BoundArch); +  DeviceOffloadKinds.push_back(OKind); +} + +OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC, +                                              const char *BoundArch, +                                              const DeviceDependences &DDeps) +    : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) { +  for (auto K : DDeps.getOffloadKinds()) +    HostOffloadKinds |= K; +} + +void JobAction::anchor() {} + +JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type) +    : Action(Kind, Input, Type) {} + +JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type) +    : Action(Kind, Inputs, Type) {} + +void PreprocessJobAction::anchor() {} + +PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType) +    : JobAction(PreprocessJobClass, Input, OutputType) {} + +void PrecompileJobAction::anchor() {} + +PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType) +    : JobAction(PrecompileJobClass, Input, OutputType) {} + +PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input, +                                         types::ID OutputType) +    : JobAction(Kind, Input, OutputType) { +  assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind"); +} + +void HeaderModulePrecompileJobAction::anchor() {} + +HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction( +    Action *Input, types::ID OutputType, const char *ModuleName) +    : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType), +      ModuleName(ModuleName) {} + +void AnalyzeJobAction::anchor() {} + +AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType) +    : JobAction(AnalyzeJobClass, Input, OutputType) {} + +void MigrateJobAction::anchor() {} + +MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType) +    : JobAction(MigrateJobClass, Input, OutputType) {} + +void CompileJobAction::anchor() {} + +CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType) +    : JobAction(CompileJobClass, Input, OutputType) {} + +void BackendJobAction::anchor() {} + +BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType) +    : JobAction(BackendJobClass, Input, OutputType) {} + +void AssembleJobAction::anchor() {} + +AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType) +    : JobAction(AssembleJobClass, Input, OutputType) {} + +void IfsMergeJobAction::anchor() {} + +IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type) +    : JobAction(IfsMergeJobClass, Inputs, Type) {} + +void LinkJobAction::anchor() {} + +LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) +    : JobAction(LinkJobClass, Inputs, Type) {} + +void LipoJobAction::anchor() {} + +LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type) +    : JobAction(LipoJobClass, Inputs, Type) {} + +void DsymutilJobAction::anchor() {} + +DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type) +    : JobAction(DsymutilJobClass, Inputs, Type) {} + +void VerifyJobAction::anchor() {} + +VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input, +                                 types::ID Type) +    : JobAction(Kind, Input, Type) { +  assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) && +         "ActionClass is not a valid VerifyJobAction"); +} + +void VerifyDebugInfoJobAction::anchor() {} + +VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input, +                                                   types::ID Type) +    : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {} + +void VerifyPCHJobAction::anchor() {} + +VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type) +    : VerifyJobAction(VerifyPCHJobClass, Input, Type) {} + +void OffloadBundlingJobAction::anchor() {} + +OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs) +    : JobAction(OffloadBundlingJobClass, Inputs, Inputs.back()->getType()) {} + +void OffloadUnbundlingJobAction::anchor() {} + +OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input) +    : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {} + +void OffloadWrapperJobAction::anchor() {} + +OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs, +                                                 types::ID Type) +  : JobAction(OffloadWrapperJobClass, Inputs, Type) {} diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp new file mode 100644 index 0000000000000..ba188f5c4083c --- /dev/null +++ b/clang/lib/Driver/Compilation.cpp @@ -0,0 +1,282 @@ +//===- Compilation.cpp - Compilation Task Implementation ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Compilation.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptSpecifier.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <string> +#include <system_error> +#include <utility> + +using namespace clang; +using namespace driver; +using namespace llvm::opt; + +Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, +                         InputArgList *_Args, DerivedArgList *_TranslatedArgs, +                         bool ContainsError) +    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args), +      TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) { +  // The offloading host toolchain is the default toolchain. +  OrderedOffloadingToolchains.insert( +      std::make_pair(Action::OFK_Host, &DefaultToolChain)); +} + +Compilation::~Compilation() { +  // Remove temporary files. This must be done before arguments are freed, as +  // the file names might be derived from the input arguments. +  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles) +    CleanupFileList(TempFiles); + +  delete TranslatedArgs; +  delete Args; + +  // Free any derived arg lists. +  for (auto Arg : TCArgs) +    if (Arg.second != TranslatedArgs) +      delete Arg.second; +} + +const DerivedArgList & +Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, +                                 Action::OffloadKind DeviceOffloadKind) { +  if (!TC) +    TC = &DefaultToolChain; + +  DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}]; +  if (!Entry) { +    SmallVector<Arg *, 4> AllocatedArgs; +    DerivedArgList *OpenMPArgs = nullptr; +    // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags. +    if (DeviceOffloadKind == Action::OFK_OpenMP) { +      const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>(); +      bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple()); +      OpenMPArgs = TC->TranslateOpenMPTargetArgs( +          *TranslatedArgs, SameTripleAsHost, AllocatedArgs); +    } + +    if (!OpenMPArgs) { +      Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); +      if (!Entry) +        Entry = TranslatedArgs; +    } else { +      Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind); +      if (!Entry) +        Entry = OpenMPArgs; +      else +        delete OpenMPArgs; +    } + +    // Add allocated arguments to the final DAL. +    for (auto ArgPtr : AllocatedArgs) +      Entry->AddSynthesizedArg(ArgPtr); +  } + +  return *Entry; +} + +bool Compilation::CleanupFile(const char *File, bool IssueErrors) const { +  // FIXME: Why are we trying to remove files that we have not created? For +  // example we should only try to remove a temporary assembly file if +  // "clang -cc1" succeed in writing it. Was this a workaround for when +  // clang was writing directly to a .s file and sometimes leaving it behind +  // during a failure? + +  // FIXME: If this is necessary, we can still try to split +  // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the +  // duplicated stat from is_regular_file. + +  // Don't try to remove files which we don't have write access to (but may be +  // able to remove), or non-regular files. Underlying tools may have +  // intentionally not overwritten them. +  if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File)) +    return true; + +  if (std::error_code EC = llvm::sys::fs::remove(File)) { +    // Failure is only failure if the file exists and is "regular". We checked +    // for it being regular before, and llvm::sys::fs::remove ignores ENOENT, +    // so we don't need to check again. + +    if (IssueErrors) +      getDriver().Diag(diag::err_drv_unable_to_remove_file) +        << EC.message(); +    return false; +  } +  return true; +} + +bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files, +                                  bool IssueErrors) const { +  bool Success = true; +  for (const auto &File: Files) +    Success &= CleanupFile(File, IssueErrors); +  return Success; +} + +bool Compilation::CleanupFileMap(const ArgStringMap &Files, +                                 const JobAction *JA, +                                 bool IssueErrors) const { +  bool Success = true; +  for (const auto &File : Files) { +    // If specified, only delete the files associated with the JobAction. +    // Otherwise, delete all files in the map. +    if (JA && File.first != JA) +      continue; +    Success &= CleanupFile(File.second, IssueErrors); +  } +  return Success; +} + +int Compilation::ExecuteCommand(const Command &C, +                                const Command *&FailingCommand) const { +  if ((getDriver().CCPrintOptions || +       getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { +    raw_ostream *OS = &llvm::errs(); +    std::unique_ptr<llvm::raw_fd_ostream> OwnedStream; + +    // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the +    // output stream. +    if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) { +      std::error_code EC; +      OwnedStream.reset(new llvm::raw_fd_ostream( +          getDriver().CCPrintOptionsFilename, EC, +          llvm::sys::fs::OF_Append | llvm::sys::fs::OF_Text)); +      if (EC) { +        getDriver().Diag(diag::err_drv_cc_print_options_failure) +            << EC.message(); +        FailingCommand = &C; +        return 1; +      } +      OS = OwnedStream.get(); +    } + +    if (getDriver().CCPrintOptions) +      *OS << "[Logging clang options]"; + +    C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); +  } + +  std::string Error; +  bool ExecutionFailed; +  int Res = C.Execute(Redirects, &Error, &ExecutionFailed); +  if (!Error.empty()) { +    assert(Res && "Error string set with 0 result code!"); +    getDriver().Diag(diag::err_drv_command_failure) << Error; +  } + +  if (Res) +    FailingCommand = &C; + +  return ExecutionFailed ? 1 : Res; +} + +using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>; + +static bool ActionFailed(const Action *A, +                         const FailingCommandList &FailingCommands) { +  if (FailingCommands.empty()) +    return false; + +  // CUDA/HIP can have the same input source code compiled multiple times so do +  // not compiled again if there are already failures. It is OK to abort the +  // CUDA pipeline on errors. +  if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP)) +    return true; + +  for (const auto &CI : FailingCommands) +    if (A == &(CI.second->getSource())) +      return true; + +  for (const auto *AI : A->inputs()) +    if (ActionFailed(AI, FailingCommands)) +      return true; + +  return false; +} + +static bool InputsOk(const Command &C, +                     const FailingCommandList &FailingCommands) { +  return !ActionFailed(&C.getSource(), FailingCommands); +} + +void Compilation::ExecuteJobs(const JobList &Jobs, +                              FailingCommandList &FailingCommands) const { +  // According to UNIX standard, driver need to continue compiling all the +  // inputs on the command line even one of them failed. +  // In all but CLMode, execute all the jobs unless the necessary inputs for the +  // job is missing due to previous failures. +  for (const auto &Job : Jobs) { +    if (!InputsOk(Job, FailingCommands)) +      continue; +    const Command *FailingCommand = nullptr; +    if (int Res = ExecuteCommand(Job, FailingCommand)) { +      FailingCommands.push_back(std::make_pair(Res, FailingCommand)); +      // Bail as soon as one command fails in cl driver mode. +      if (TheDriver.IsCLMode()) +        return; +    } +  } +} + +void Compilation::initCompilationForDiagnostics() { +  ForDiagnostics = true; + +  // Free actions and jobs. +  Actions.clear(); +  AllActions.clear(); +  Jobs.clear(); + +  // Remove temporary files. +  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles) +    CleanupFileList(TempFiles); + +  // 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. +  OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD, +                                options::OPT_MMD }; +  for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) { +    if (TranslatedArgs->hasArg(OutputOpts[i])) +      TranslatedArgs->eraseArg(OutputOpts[i]); +  } +  TranslatedArgs->ClaimAllArgs(); + +  // Redirect stdout/stderr to /dev/null. +  Redirects = {None, {""}, {""}}; + +  // Temporary files added by diagnostics should be kept. +  ForceKeepTempFiles = true; +} + +StringRef Compilation::getSysRoot() const { +  return getDriver().SysRoot; +} + +void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) { +  this->Redirects = Redirects; +} diff --git a/clang/lib/Driver/DarwinSDKInfo.cpp b/clang/lib/Driver/DarwinSDKInfo.cpp new file mode 100644 index 0000000000000..761c6717266bf --- /dev/null +++ b/clang/lib/Driver/DarwinSDKInfo.cpp @@ -0,0 +1,43 @@ +//===--- DarwinSDKInfo.cpp - SDK Information parser for darwin - ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/DarwinSDKInfo.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang; + +Expected<Optional<DarwinSDKInfo>> +driver::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) { +  llvm::SmallString<256> Filepath = SDKRootPath; +  llvm::sys::path::append(Filepath, "SDKSettings.json"); +  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = +      VFS.getBufferForFile(Filepath); +  if (!File) { +    // If the file couldn't be read, assume it just doesn't exist. +    return None; +  } +  Expected<llvm::json::Value> Result = +      llvm::json::parse(File.get()->getBuffer()); +  if (!Result) +    return Result.takeError(); + +  if (const auto *Obj = Result->getAsObject()) { +    auto VersionString = Obj->getString("Version"); +    if (VersionString) { +      VersionTuple Version; +      if (!Version.tryParse(*VersionString)) +        return DarwinSDKInfo(Version); +    } +  } +  return llvm::make_error<llvm::StringError>("invalid SDKSettings.json", +                                             llvm::inconvertibleErrorCode()); +} diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp new file mode 100644 index 0000000000000..f2a3074d1e701 --- /dev/null +++ b/clang/lib/Driver/Distro.cpp @@ -0,0 +1,151 @@ +//===--- Distro.cpp - Linux distribution detection support ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Distro.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace clang::driver; +using namespace clang; + +static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { +  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = +      VFS.getBufferForFile("/etc/lsb-release"); +  if (File) { +    StringRef Data = File.get()->getBuffer(); +    SmallVector<StringRef, 16> Lines; +    Data.split(Lines, "\n"); +    Distro::DistroType Version = Distro::UnknownDistro; +    for (StringRef Line : Lines) +      if (Version == Distro::UnknownDistro && Line.startswith("DISTRIB_CODENAME=")) +        Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17)) +                      .Case("hardy", Distro::UbuntuHardy) +                      .Case("intrepid", Distro::UbuntuIntrepid) +                      .Case("jaunty", Distro::UbuntuJaunty) +                      .Case("karmic", Distro::UbuntuKarmic) +                      .Case("lucid", Distro::UbuntuLucid) +                      .Case("maverick", Distro::UbuntuMaverick) +                      .Case("natty", Distro::UbuntuNatty) +                      .Case("oneiric", Distro::UbuntuOneiric) +                      .Case("precise", Distro::UbuntuPrecise) +                      .Case("quantal", Distro::UbuntuQuantal) +                      .Case("raring", Distro::UbuntuRaring) +                      .Case("saucy", Distro::UbuntuSaucy) +                      .Case("trusty", Distro::UbuntuTrusty) +                      .Case("utopic", Distro::UbuntuUtopic) +                      .Case("vivid", Distro::UbuntuVivid) +                      .Case("wily", Distro::UbuntuWily) +                      .Case("xenial", Distro::UbuntuXenial) +                      .Case("yakkety", Distro::UbuntuYakkety) +                      .Case("zesty", Distro::UbuntuZesty) +                      .Case("artful", Distro::UbuntuArtful) +                      .Case("bionic", Distro::UbuntuBionic) +                      .Case("cosmic", Distro::UbuntuCosmic) +                      .Case("disco", Distro::UbuntuDisco) +                      .Case("eoan", Distro::UbuntuEoan) +                      .Default(Distro::UnknownDistro); +    if (Version != Distro::UnknownDistro) +      return Version; +  } + +  File = VFS.getBufferForFile("/etc/redhat-release"); +  if (File) { +    StringRef Data = File.get()->getBuffer(); +    if (Data.startswith("Fedora release")) +      return Distro::Fedora; +    if (Data.startswith("Red Hat Enterprise Linux") || +        Data.startswith("CentOS") || +        Data.startswith("Scientific Linux")) { +      if (Data.find("release 7") != StringRef::npos) +        return Distro::RHEL7; +      else if (Data.find("release 6") != StringRef::npos) +        return Distro::RHEL6; +      else if (Data.find("release 5") != StringRef::npos) +        return Distro::RHEL5; +    } +    return Distro::UnknownDistro; +  } + +  File = VFS.getBufferForFile("/etc/debian_version"); +  if (File) { +    StringRef Data = File.get()->getBuffer(); +    // Contents: < major.minor > or < codename/sid > +    int MajorVersion; +    if (!Data.split('.').first.getAsInteger(10, MajorVersion)) { +      switch (MajorVersion) { +      case 5: +        return Distro::DebianLenny; +      case 6: +        return Distro::DebianSqueeze; +      case 7: +        return Distro::DebianWheezy; +      case 8: +        return Distro::DebianJessie; +      case 9: +        return Distro::DebianStretch; +      case 10: +        return Distro::DebianBuster; +      case 11: +        return Distro::DebianBullseye; +      default: +        return Distro::UnknownDistro; +      } +    } +    return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first) +        .Case("squeeze/sid", Distro::DebianSqueeze) +        .Case("wheezy/sid", Distro::DebianWheezy) +        .Case("jessie/sid", Distro::DebianJessie) +        .Case("stretch/sid", Distro::DebianStretch) +        .Case("buster/sid", Distro::DebianBuster) +        .Case("bullseye/sid", Distro::DebianBullseye) +        .Default(Distro::UnknownDistro); +  } + +  File = VFS.getBufferForFile("/etc/SuSE-release"); +  if (File) { +    StringRef Data = File.get()->getBuffer(); +    SmallVector<StringRef, 8> Lines; +    Data.split(Lines, "\n"); +    for (const StringRef& Line : Lines) { +      if (!Line.trim().startswith("VERSION")) +        continue; +      std::pair<StringRef, StringRef> SplitLine = Line.split('='); +      // Old versions have split VERSION and PATCHLEVEL +      // Newer versions use VERSION = x.y +      std::pair<StringRef, StringRef> SplitVer = SplitLine.second.trim().split('.'); +      int Version; + +      // OpenSUSE/SLES 10 and older are not supported and not compatible +      // with our rules, so just treat them as Distro::UnknownDistro. +      if (!SplitVer.first.getAsInteger(10, Version) && Version > 10) +        return Distro::OpenSUSE; +      return Distro::UnknownDistro; +    } +    return Distro::UnknownDistro; +  } + +  if (VFS.exists("/etc/exherbo-release")) +    return Distro::Exherbo; + +  if (VFS.exists("/etc/alpine-release")) +    return Distro::AlpineLinux; + +  if (VFS.exists("/etc/arch-release")) +    return Distro::ArchLinux; + +  if (VFS.exists("/etc/gentoo-release")) +    return Distro::Gentoo; + +  return Distro::UnknownDistro; +} + +Distro::Distro(llvm::vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp new file mode 100644 index 0000000000000..f6016b43b6920 --- /dev/null +++ b/clang/lib/Driver/Driver.cpp @@ -0,0 +1,4959 @@ +//===--- Driver.cpp - Clang GCC Compatible Driver -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Driver.h" +#include "InputInfo.h" +#include "ToolChains/AMDGPU.h" +#include "ToolChains/AVR.h" +#include "ToolChains/Ananas.h" +#include "ToolChains/BareMetal.h" +#include "ToolChains/Clang.h" +#include "ToolChains/CloudABI.h" +#include "ToolChains/Contiki.h" +#include "ToolChains/CrossWindows.h" +#include "ToolChains/Cuda.h" +#include "ToolChains/Darwin.h" +#include "ToolChains/DragonFly.h" +#include "ToolChains/FreeBSD.h" +#include "ToolChains/Fuchsia.h" +#include "ToolChains/Gnu.h" +#include "ToolChains/HIP.h" +#include "ToolChains/Haiku.h" +#include "ToolChains/Hexagon.h" +#include "ToolChains/Hurd.h" +#include "ToolChains/Lanai.h" +#include "ToolChains/Linux.h" +#include "ToolChains/MSP430.h" +#include "ToolChains/MSVC.h" +#include "ToolChains/MinGW.h" +#include "ToolChains/Minix.h" +#include "ToolChains/MipsLinux.h" +#include "ToolChains/Myriad.h" +#include "ToolChains/NaCl.h" +#include "ToolChains/NetBSD.h" +#include "ToolChains/OpenBSD.h" +#include "ToolChains/PS4CPU.h" +#include "ToolChains/PPCLinux.h" +#include "ToolChains/RISCVToolchain.h" +#include "ToolChains/Solaris.h" +#include "ToolChains/TCE.h" +#include "ToolChains/WebAssembly.h" +#include "ToolChains/XCore.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptSpecifier.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include <map> +#include <memory> +#include <utility> +#if LLVM_ON_UNIX +#include <unistd.h> // getpid +#include <sysexits.h> // EX_IOERR +#endif + +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +// static +std::string Driver::GetResourcesPath(StringRef BinaryPath, +                                     StringRef CustomResourceDir) { +  // Since the resource directory is embedded in the module hash, it's important +  // that all places that need it call this function, so that they get the +  // exact same string ("a/../b/" and "b/" get different hashes, for example). + +  // Dir is bin/ or lib/, depending on where BinaryPath is. +  std::string Dir = llvm::sys::path::parent_path(BinaryPath); + +  SmallString<128> P(Dir); +  if (CustomResourceDir != "") { +    llvm::sys::path::append(P, CustomResourceDir); +  } else { +    // On Windows, libclang.dll is in bin/. +    // On non-Windows, libclang.so/.dylib is in lib/. +    // With a static-library build of libclang, LibClangPath will contain the +    // path of the embedding binary, which for LLVM binaries will be in bin/. +    // ../lib gets us to lib/ in both cases. +    P = llvm::sys::path::parent_path(Dir); +    llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang", +                            CLANG_VERSION_STRING); +  } + +  return P.str(); +} + +Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, +               DiagnosticsEngine &Diags, +               IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) +    : Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), +      SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), +      ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), +      DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), +      CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), +      CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), +      CCLogDiagnostics(false), CCGenDiagnostics(false), +      TargetTriple(TargetTriple), CCCGenericGCCName(""), Saver(Alloc), +      CheckInputsExist(true), GenReproducer(false), +      SuppressMissingInputWarning(false) { + +  // Provide a sane fallback if no VFS is specified. +  if (!this->VFS) +    this->VFS = llvm::vfs::getRealFileSystem(); + +  Name = llvm::sys::path::filename(ClangExecutable); +  Dir = llvm::sys::path::parent_path(ClangExecutable); +  InstalledDir = Dir; // Provide a sensible default installed dir. + +#if defined(CLANG_CONFIG_FILE_SYSTEM_DIR) +  SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR; +#endif +#if defined(CLANG_CONFIG_FILE_USER_DIR) +  UserConfigDir = CLANG_CONFIG_FILE_USER_DIR; +#endif + +  // Compute the path to the resource directory. +  ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); +} + +void Driver::ParseDriverMode(StringRef ProgramName, +                             ArrayRef<const char *> Args) { +  if (ClangNameParts.isEmpty()) +    ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName); +  setDriverModeFromOption(ClangNameParts.DriverMode); + +  for (const char *ArgPtr : Args) { +    // Ignore nullptrs, they are the response file's EOL markers. +    if (ArgPtr == nullptr) +      continue; +    const StringRef Arg = ArgPtr; +    setDriverModeFromOption(Arg); +  } +} + +void Driver::setDriverModeFromOption(StringRef Opt) { +  const std::string OptName = +      getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); +  if (!Opt.startswith(OptName)) +    return; +  StringRef Value = Opt.drop_front(OptName.size()); + +  if (auto M = llvm::StringSwitch<llvm::Optional<DriverMode>>(Value) +                   .Case("gcc", GCCMode) +                   .Case("g++", GXXMode) +                   .Case("cpp", CPPMode) +                   .Case("cl", CLMode) +                   .Default(None)) +    Mode = *M; +  else +    Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; +} + +InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, +                                     bool IsClCompatMode, +                                     bool &ContainsError) { +  llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); +  ContainsError = false; + +  unsigned IncludedFlagsBitmask; +  unsigned ExcludedFlagsBitmask; +  std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = +      getIncludeExcludeOptionFlagMasks(IsClCompatMode); + +  unsigned MissingArgIndex, MissingArgCount; +  InputArgList Args = +      getOpts().ParseArgs(ArgStrings, MissingArgIndex, MissingArgCount, +                          IncludedFlagsBitmask, ExcludedFlagsBitmask); + +  // Check for missing argument error. +  if (MissingArgCount) { +    Diag(diag::err_drv_missing_argument) +        << Args.getArgString(MissingArgIndex) << MissingArgCount; +    ContainsError |= +        Diags.getDiagnosticLevel(diag::err_drv_missing_argument, +                                 SourceLocation()) > DiagnosticsEngine::Warning; +  } + +  // Check for unsupported options. +  for (const Arg *A : Args) { +    if (A->getOption().hasFlag(options::Unsupported)) { +      unsigned DiagID; +      auto ArgString = A->getAsString(Args); +      std::string Nearest; +      if (getOpts().findNearest( +            ArgString, Nearest, IncludedFlagsBitmask, +            ExcludedFlagsBitmask | options::Unsupported) > 1) { +        DiagID = diag::err_drv_unsupported_opt; +        Diag(DiagID) << ArgString; +      } else { +        DiagID = diag::err_drv_unsupported_opt_with_suggestion; +        Diag(DiagID) << ArgString << Nearest; +      } +      ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) > +                       DiagnosticsEngine::Warning; +      continue; +    } + +    // Warn about -mcpu= without an argument. +    if (A->getOption().matches(options::OPT_mcpu_EQ) && A->containsValue("")) { +      Diag(diag::warn_drv_empty_joined_argument) << A->getAsString(Args); +      ContainsError |= Diags.getDiagnosticLevel( +                           diag::warn_drv_empty_joined_argument, +                           SourceLocation()) > DiagnosticsEngine::Warning; +    } +  } + +  for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) { +    unsigned DiagID; +    auto ArgString = A->getAsString(Args); +    std::string Nearest; +    if (getOpts().findNearest( +          ArgString, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) > 1) { +      DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl +                          : diag::err_drv_unknown_argument; +      Diags.Report(DiagID) << ArgString; +    } else { +      DiagID = IsCLMode() +                   ? diag::warn_drv_unknown_argument_clang_cl_with_suggestion +                   : diag::err_drv_unknown_argument_with_suggestion; +      Diags.Report(DiagID) << ArgString << Nearest; +    } +    ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) > +                     DiagnosticsEngine::Warning; +  } + +  return Args; +} + +// Determine which compilation mode we are in. We look for options which +// affect the phase, starting with the earliest phases, and record which +// option we used to determine the final phase. +phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, +                                 Arg **FinalPhaseArg) const { +  Arg *PhaseArg = nullptr; +  phases::ID FinalPhase; + +  // -{E,EP,P,M,MM} only run the preprocessor. +  if (CCCIsCPP() || (PhaseArg = DAL.getLastArg(options::OPT_E)) || +      (PhaseArg = DAL.getLastArg(options::OPT__SLASH_EP)) || +      (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM)) || +      (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { +    FinalPhase = phases::Preprocess; + +  // --precompile only runs up to precompilation. +  } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { +    FinalPhase = phases::Precompile; + +  // -{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_print_supported_cpus)) || +             (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || +             (PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) || +             (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || +             (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || +             (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || +             (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || +             (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { +    FinalPhase = phases::Compile; + +  // clang interface stubs +  } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) { +    FinalPhase = phases::IfsMerge; + +  // -S only runs up to the backend. +  } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { +    FinalPhase = phases::Backend; + +  // -c compilation only runs up to the assembler. +  } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { +    FinalPhase = phases::Assemble; + +  // Otherwise do everything. +  } else +    FinalPhase = phases::Link; + +  if (FinalPhaseArg) +    *FinalPhaseArg = PhaseArg; + +  return FinalPhase; +} + +static Arg *MakeInputArg(DerivedArgList &Args, const OptTable &Opts, +                         StringRef Value, bool Claim = true) { +  Arg *A = new Arg(Opts.getOption(options::OPT_INPUT), Value, +                   Args.getBaseArgs().MakeIndex(Value), Value.data()); +  Args.AddSynthesizedArg(A); +  if (Claim) +    A->claim(); +  return A; +} + +DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { +  const llvm::opt::OptTable &Opts = getOpts(); +  DerivedArgList *DAL = new DerivedArgList(Args); + +  bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); +  bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx); +  bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs); +  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'). + +    // Rewrite linker options, to replace --no-demangle with a custom internal +    // option. +    if ((A->getOption().matches(options::OPT_Wl_COMMA) || +         A->getOption().matches(options::OPT_Xlinker)) && +        A->containsValue("--no-demangle")) { +      // Add the rewritten no-demangle argument. +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_Z_Xlinker__no_demangle)); + +      // Add the remaining values as Xlinker arguments. +      for (StringRef Val : A->getValues()) +        if (Val != "--no-demangle") +          DAL->AddSeparateArg(A, Opts.getOption(options::OPT_Xlinker), Val); + +      continue; +    } + +    // Rewrite preprocessor options, to replace -Wp,-MD,FOO which is used by +    // some build systems. We don't try to be complete here because we don't +    // care to encourage this usage model. +    if (A->getOption().matches(options::OPT_Wp_COMMA) && +        (A->getValue(0) == StringRef("-MD") || +         A->getValue(0) == StringRef("-MMD"))) { +      // Rewrite to -MD/-MMD along with -MF. +      if (A->getValue(0) == StringRef("-MD")) +        DAL->AddFlagArg(A, Opts.getOption(options::OPT_MD)); +      else +        DAL->AddFlagArg(A, Opts.getOption(options::OPT_MMD)); +      if (A->getNumValues() == 2) +        DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue(1)); +      continue; +    } + +    // Rewrite reserved library names. +    if (A->getOption().matches(options::OPT_l)) { +      StringRef Value = A->getValue(); + +      // Rewrite unless -nostdlib is present. +      if (!HasNostdlib && !HasNodefaultlib && !HasNostdlibxx && +          Value == "stdc++") { +        DAL->AddFlagArg(A, Opts.getOption(options::OPT_Z_reserved_lib_stdcxx)); +        continue; +      } + +      // Rewrite unconditionally. +      if (Value == "cc_kext") { +        DAL->AddFlagArg(A, Opts.getOption(options::OPT_Z_reserved_lib_cckext)); +        continue; +      } +    } + +    // Pick up inputs via the -- option. +    if (A->getOption().matches(options::OPT__DASH_DASH)) { +      A->claim(); +      for (StringRef Val : A->getValues()) +        DAL->append(MakeInputArg(*DAL, Opts, Val, false)); +      continue; +    } + +    DAL->append(A); +  } + +  // Enforce -static if -miamcu is present. +  if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) +    DAL->AddFlagArg(0, Opts.getOption(options::OPT_static)); + +// Add a default value of -mlinker-version=, if one was given and the user +// didn't specify one. +#if defined(HOST_LINK_VERSION) +  if (!Args.hasArg(options::OPT_mlinker_version_EQ) && +      strlen(HOST_LINK_VERSION) > 0) { +    DAL->AddJoinedArg(0, Opts.getOption(options::OPT_mlinker_version_EQ), +                      HOST_LINK_VERSION); +    DAL->getLastArg(options::OPT_mlinker_version_EQ)->claim(); +  } +#endif + +  return DAL; +} + +/// Compute target triple from args. +/// +/// This routine provides the logic to compute a target triple from various +/// args passed to the driver and the default triple string. +static llvm::Triple computeTargetTriple(const Driver &D, +                                        StringRef TargetTriple, +                                        const ArgList &Args, +                                        StringRef DarwinArchName = "") { +  // FIXME: Already done in Compilation *Driver::BuildCompilation +  if (const Arg *A = Args.getLastArg(options::OPT_target)) +    TargetTriple = A->getValue(); + +  llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); + +  // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made +  // -gnu* only, and we can not change this, so we have to detect that case as +  // being the Hurd OS. +  if (TargetTriple.find("-unknown-gnu") != StringRef::npos || +      TargetTriple.find("-pc-gnu") != StringRef::npos) +    Target.setOSName("hurd"); + +  // Handle Apple-specific options available here. +  if (Target.isOSBinFormatMachO()) { +    // If an explicit Darwin arch name is given, that trumps all. +    if (!DarwinArchName.empty()) { +      tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName); +      return Target; +    } + +    // Handle the Darwin '-arch' flag. +    if (Arg *A = Args.getLastArg(options::OPT_arch)) { +      StringRef ArchName = A->getValue(); +      tools::darwin::setTripleTypeForMachOArchName(Target, ArchName); +    } +  } + +  // Handle pseudo-target flags '-mlittle-endian'/'-EL' and +  // '-mbig-endian'/'-EB'. +  if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, +                               options::OPT_mbig_endian)) { +    if (A->getOption().matches(options::OPT_mlittle_endian)) { +      llvm::Triple LE = Target.getLittleEndianArchVariant(); +      if (LE.getArch() != llvm::Triple::UnknownArch) +        Target = std::move(LE); +    } else { +      llvm::Triple BE = Target.getBigEndianArchVariant(); +      if (BE.getArch() != llvm::Triple::UnknownArch) +        Target = std::move(BE); +    } +  } + +  // Skip further flag support on OSes which don't support '-m32' or '-m64'. +  if (Target.getArch() == llvm::Triple::tce || +      Target.getOS() == llvm::Triple::Minix) +    return Target; + +  // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. +  Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, +                           options::OPT_m32, options::OPT_m16); +  if (A) { +    llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; + +    if (A->getOption().matches(options::OPT_m64)) { +      AT = Target.get64BitArchVariant().getArch(); +      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)) { +      AT = Target.get32BitArchVariant().getArch(); +      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 && AT != Target.getArch()) +      Target.setArch(AT); +  } + +  // Handle -miamcu flag. +  if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { +    if (Target.get32BitArchVariant().getArch() != llvm::Triple::x86) +      D.Diag(diag::err_drv_unsupported_opt_for_target) << "-miamcu" +                                                       << Target.str(); + +    if (A && !A->getOption().matches(options::OPT_m32)) +      D.Diag(diag::err_drv_argument_not_allowed_with) +          << "-miamcu" << A->getBaseArg().getAsString(Args); + +    Target.setArch(llvm::Triple::x86); +    Target.setArchName("i586"); +    Target.setEnvironment(llvm::Triple::UnknownEnvironment); +    Target.setEnvironmentName(""); +    Target.setOS(llvm::Triple::ELFIAMCU); +    Target.setVendor(llvm::Triple::UnknownVendor); +    Target.setVendorName("intel"); +  } + +  // If target is MIPS adjust the target triple +  // accordingly to provided ABI name. +  A = Args.getLastArg(options::OPT_mabi_EQ); +  if (A && Target.isMIPS()) { +    StringRef ABIName = A->getValue(); +    if (ABIName == "32") { +      Target = Target.get32BitArchVariant(); +      if (Target.getEnvironment() == llvm::Triple::GNUABI64 || +          Target.getEnvironment() == llvm::Triple::GNUABIN32) +        Target.setEnvironment(llvm::Triple::GNU); +    } else if (ABIName == "n32") { +      Target = Target.get64BitArchVariant(); +      if (Target.getEnvironment() == llvm::Triple::GNU || +          Target.getEnvironment() == llvm::Triple::GNUABI64) +        Target.setEnvironment(llvm::Triple::GNUABIN32); +    } else if (ABIName == "64") { +      Target = Target.get64BitArchVariant(); +      if (Target.getEnvironment() == llvm::Triple::GNU || +          Target.getEnvironment() == llvm::Triple::GNUABIN32) +        Target.setEnvironment(llvm::Triple::GNUABI64); +    } +  } + +  return Target; +} + +// Parse the LTO options and record the type of LTO compilation +// based on which -f(no-)?lto(=.*)? option occurs last. +void Driver::setLTOMode(const llvm::opt::ArgList &Args) { +  LTOMode = LTOK_None; +  if (!Args.hasFlag(options::OPT_flto, options::OPT_flto_EQ, +                    options::OPT_fno_lto, false)) +    return; + +  StringRef LTOName("full"); + +  const Arg *A = Args.getLastArg(options::OPT_flto_EQ); +  if (A) +    LTOName = A->getValue(); + +  LTOMode = llvm::StringSwitch<LTOKind>(LTOName) +                .Case("full", LTOK_Full) +                .Case("thin", LTOK_Thin) +                .Default(LTOK_Unknown); + +  if (LTOMode == LTOK_Unknown) { +    assert(A); +    Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() +                                                    << A->getValue(); +  } +} + +/// Compute the desired OpenMP runtime from the flags provided. +Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const { +  StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME); + +  const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ); +  if (A) +    RuntimeName = A->getValue(); + +  auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName) +                .Case("libomp", OMPRT_OMP) +                .Case("libgomp", OMPRT_GOMP) +                .Case("libiomp5", OMPRT_IOMP5) +                .Default(OMPRT_Unknown); + +  if (RT == OMPRT_Unknown) { +    if (A) +      Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << A->getValue(); +    else +      // FIXME: We could use a nicer diagnostic here. +      Diag(diag::err_drv_unsupported_opt) << "-fopenmp"; +  } + +  return RT; +} + +void Driver::CreateOffloadingDeviceToolChains(Compilation &C, +                                              InputList &Inputs) { + +  // +  // CUDA/HIP +  // +  // We need to generate a CUDA/HIP toolchain if any of the inputs has a CUDA +  // or HIP type. However, mixed CUDA/HIP compilation is not supported. +  bool IsCuda = +      llvm::any_of(Inputs, [](std::pair<types::ID, const llvm::opt::Arg *> &I) { +        return types::isCuda(I.first); +      }); +  bool IsHIP = +      llvm::any_of(Inputs, +                   [](std::pair<types::ID, const llvm::opt::Arg *> &I) { +                     return types::isHIP(I.first); +                   }) || +      C.getInputArgs().hasArg(options::OPT_hip_link); +  if (IsCuda && IsHIP) { +    Diag(clang::diag::err_drv_mix_cuda_hip); +    return; +  } +  if (IsCuda) { +    const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); +    const llvm::Triple &HostTriple = HostTC->getTriple(); +    StringRef DeviceTripleStr; +    auto OFK = Action::OFK_Cuda; +    DeviceTripleStr = +        HostTriple.isArch64Bit() ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda"; +    llvm::Triple CudaTriple(DeviceTripleStr); +    // Use the CUDA and host triples as the key into the ToolChains map, +    // because the device toolchain we create depends on both. +    auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()]; +    if (!CudaTC) { +      CudaTC = std::make_unique<toolchains::CudaToolChain>( +          *this, CudaTriple, *HostTC, C.getInputArgs(), OFK); +    } +    C.addOffloadDeviceToolChain(CudaTC.get(), OFK); +  } else if (IsHIP) { +    const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); +    const llvm::Triple &HostTriple = HostTC->getTriple(); +    StringRef DeviceTripleStr; +    auto OFK = Action::OFK_HIP; +    DeviceTripleStr = "amdgcn-amd-amdhsa"; +    llvm::Triple HIPTriple(DeviceTripleStr); +    // Use the HIP and host triples as the key into the ToolChains map, +    // because the device toolchain we create depends on both. +    auto &HIPTC = ToolChains[HIPTriple.str() + "/" + HostTriple.str()]; +    if (!HIPTC) { +      HIPTC = std::make_unique<toolchains::HIPToolChain>( +          *this, HIPTriple, *HostTC, C.getInputArgs()); +    } +    C.addOffloadDeviceToolChain(HIPTC.get(), OFK); +  } + +  // +  // OpenMP +  // +  // We need to generate an OpenMP toolchain if the user specified targets with +  // the -fopenmp-targets option. +  if (Arg *OpenMPTargets = +          C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) { +    if (OpenMPTargets->getNumValues()) { +      // We expect that -fopenmp-targets is always used in conjunction with the +      // option -fopenmp specifying a valid runtime with offloading support, +      // i.e. libomp or libiomp. +      bool HasValidOpenMPRuntime = C.getInputArgs().hasFlag( +          options::OPT_fopenmp, options::OPT_fopenmp_EQ, +          options::OPT_fno_openmp, false); +      if (HasValidOpenMPRuntime) { +        OpenMPRuntimeKind OpenMPKind = getOpenMPRuntime(C.getInputArgs()); +        HasValidOpenMPRuntime = +            OpenMPKind == OMPRT_OMP || OpenMPKind == OMPRT_IOMP5; +      } + +      if (HasValidOpenMPRuntime) { +        llvm::StringMap<const char *> FoundNormalizedTriples; +        for (const char *Val : OpenMPTargets->getValues()) { +          llvm::Triple TT(Val); +          std::string NormalizedName = TT.normalize(); + +          // Make sure we don't have a duplicate triple. +          auto Duplicate = FoundNormalizedTriples.find(NormalizedName); +          if (Duplicate != FoundNormalizedTriples.end()) { +            Diag(clang::diag::warn_drv_omp_offload_target_duplicate) +                << Val << Duplicate->second; +            continue; +          } + +          // Store the current triple so that we can check for duplicates in the +          // following iterations. +          FoundNormalizedTriples[NormalizedName] = Val; + +          // If the specified target is invalid, emit a diagnostic. +          if (TT.getArch() == llvm::Triple::UnknownArch) +            Diag(clang::diag::err_drv_invalid_omp_target) << Val; +          else { +            const ToolChain *TC; +            // CUDA toolchains have to be selected differently. They pair host +            // and device in their implementation. +            if (TT.isNVPTX()) { +              const ToolChain *HostTC = +                  C.getSingleOffloadToolChain<Action::OFK_Host>(); +              assert(HostTC && "Host toolchain should be always defined."); +              auto &CudaTC = +                  ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()]; +              if (!CudaTC) +                CudaTC = std::make_unique<toolchains::CudaToolChain>( +                    *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP); +              TC = CudaTC.get(); +            } else +              TC = &getToolChain(C.getInputArgs(), TT); +            C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); +          } +        } +      } else +        Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets); +    } else +      Diag(clang::diag::warn_drv_empty_joined_argument) +          << OpenMPTargets->getAsString(C.getInputArgs()); +  } + +  // +  // TODO: Add support for other offloading programming models here. +  // +} + +/// Looks the given directories for the specified file. +/// +/// \param[out] FilePath File path, if the file was found. +/// \param[in]  Dirs Directories used for the search. +/// \param[in]  FileName Name of the file to search for. +/// \return True if file was found. +/// +/// Looks for file specified by FileName sequentially in directories specified +/// by Dirs. +/// +static bool searchForFile(SmallVectorImpl<char> &FilePath, +                          ArrayRef<std::string> Dirs, +                          StringRef FileName) { +  SmallString<128> WPath; +  for (const StringRef &Dir : Dirs) { +    if (Dir.empty()) +      continue; +    WPath.clear(); +    llvm::sys::path::append(WPath, Dir, FileName); +    llvm::sys::path::native(WPath); +    if (llvm::sys::fs::is_regular_file(WPath)) { +      FilePath = std::move(WPath); +      return true; +    } +  } +  return false; +} + +bool Driver::readConfigFile(StringRef FileName) { +  // Try reading the given file. +  SmallVector<const char *, 32> NewCfgArgs; +  if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) { +    Diag(diag::err_drv_cannot_read_config_file) << FileName; +    return true; +  } + +  // Read options from config file. +  llvm::SmallString<128> CfgFileName(FileName); +  llvm::sys::path::native(CfgFileName); +  ConfigFile = CfgFileName.str(); +  bool ContainErrors; +  CfgOptions = std::make_unique<InputArgList>( +      ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors)); +  if (ContainErrors) { +    CfgOptions.reset(); +    return true; +  } + +  if (CfgOptions->hasArg(options::OPT_config)) { +    CfgOptions.reset(); +    Diag(diag::err_drv_nested_config_file); +    return true; +  } + +  // Claim all arguments that come from a configuration file so that the driver +  // does not warn on any that is unused. +  for (Arg *A : *CfgOptions) +    A->claim(); +  return false; +} + +bool Driver::loadConfigFile() { +  std::string CfgFileName; +  bool FileSpecifiedExplicitly = false; + +  // Process options that change search path for config files. +  if (CLOptions) { +    if (CLOptions->hasArg(options::OPT_config_system_dir_EQ)) { +      SmallString<128> CfgDir; +      CfgDir.append( +          CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ)); +      if (!CfgDir.empty()) { +        if (llvm::sys::fs::make_absolute(CfgDir).value() != 0) +          SystemConfigDir.clear(); +        else +          SystemConfigDir = std::string(CfgDir.begin(), CfgDir.end()); +      } +    } +    if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) { +      SmallString<128> CfgDir; +      CfgDir.append( +          CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ)); +      if (!CfgDir.empty()) { +        if (llvm::sys::fs::make_absolute(CfgDir).value() != 0) +          UserConfigDir.clear(); +        else +          UserConfigDir = std::string(CfgDir.begin(), CfgDir.end()); +      } +    } +  } + +  // First try to find config file specified in command line. +  if (CLOptions) { +    std::vector<std::string> ConfigFiles = +        CLOptions->getAllArgValues(options::OPT_config); +    if (ConfigFiles.size() > 1) { +      Diag(diag::err_drv_duplicate_config); +      return true; +    } + +    if (!ConfigFiles.empty()) { +      CfgFileName = ConfigFiles.front(); +      assert(!CfgFileName.empty()); + +      // If argument contains directory separator, treat it as a path to +      // configuration file. +      if (llvm::sys::path::has_parent_path(CfgFileName)) { +        SmallString<128> CfgFilePath; +        if (llvm::sys::path::is_relative(CfgFileName)) +          llvm::sys::fs::current_path(CfgFilePath); +        llvm::sys::path::append(CfgFilePath, CfgFileName); +        if (!llvm::sys::fs::is_regular_file(CfgFilePath)) { +          Diag(diag::err_drv_config_file_not_exist) << CfgFilePath; +          return true; +        } +        return readConfigFile(CfgFilePath); +      } + +      FileSpecifiedExplicitly = true; +    } +  } + +  // If config file is not specified explicitly, try to deduce configuration +  // from executable name. For instance, an executable 'armv7l-clang' will +  // search for config file 'armv7l-clang.cfg'. +  if (CfgFileName.empty() && !ClangNameParts.TargetPrefix.empty()) +    CfgFileName = ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix; + +  if (CfgFileName.empty()) +    return false; + +  // Determine architecture part of the file name, if it is present. +  StringRef CfgFileArch = CfgFileName; +  size_t ArchPrefixLen = CfgFileArch.find('-'); +  if (ArchPrefixLen == StringRef::npos) +    ArchPrefixLen = CfgFileArch.size(); +  llvm::Triple CfgTriple; +  CfgFileArch = CfgFileArch.take_front(ArchPrefixLen); +  CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch)); +  if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch) +    ArchPrefixLen = 0; + +  if (!StringRef(CfgFileName).endswith(".cfg")) +    CfgFileName += ".cfg"; + +  // If config file starts with architecture name and command line options +  // redefine architecture (with options like -m32 -LE etc), try finding new +  // config file with that architecture. +  SmallString<128> FixedConfigFile; +  size_t FixedArchPrefixLen = 0; +  if (ArchPrefixLen) { +    // Get architecture name from config file name like 'i386.cfg' or +    // 'armv7l-clang.cfg'. +    // Check if command line options changes effective triple. +    llvm::Triple EffectiveTriple = computeTargetTriple(*this, +                                             CfgTriple.getTriple(), *CLOptions); +    if (CfgTriple.getArch() != EffectiveTriple.getArch()) { +      FixedConfigFile = EffectiveTriple.getArchName(); +      FixedArchPrefixLen = FixedConfigFile.size(); +      // Append the rest of original file name so that file name transforms +      // like: i386-clang.cfg -> x86_64-clang.cfg. +      if (ArchPrefixLen < CfgFileName.size()) +        FixedConfigFile += CfgFileName.substr(ArchPrefixLen); +    } +  } + +  // Prepare list of directories where config file is searched for. +  SmallVector<std::string, 3> CfgFileSearchDirs; +  CfgFileSearchDirs.push_back(UserConfigDir); +  CfgFileSearchDirs.push_back(SystemConfigDir); +  CfgFileSearchDirs.push_back(Dir); + +  // Try to find config file. First try file with corrected architecture. +  llvm::SmallString<128> CfgFilePath; +  if (!FixedConfigFile.empty()) { +    if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile)) +      return readConfigFile(CfgFilePath); +    // If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'. +    FixedConfigFile.resize(FixedArchPrefixLen); +    FixedConfigFile.append(".cfg"); +    if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile)) +      return readConfigFile(CfgFilePath); +  } + +  // Then try original file name. +  if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName)) +    return readConfigFile(CfgFilePath); + +  // Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'. +  if (!ClangNameParts.ModeSuffix.empty() && +      !ClangNameParts.TargetPrefix.empty()) { +    CfgFileName.assign(ClangNameParts.TargetPrefix); +    CfgFileName.append(".cfg"); +    if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName)) +      return readConfigFile(CfgFilePath); +  } + +  // Report error but only if config file was specified explicitly, by option +  // --config. If it was deduced from executable name, it is not an error. +  if (FileSpecifiedExplicitly) { +    Diag(diag::err_drv_config_file_not_found) << CfgFileName; +    for (const std::string &SearchDir : CfgFileSearchDirs) +      if (!SearchDir.empty()) +        Diag(diag::note_drv_config_file_searched_in) << SearchDir; +    return true; +  } + +  return false; +} + +Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { +  llvm::PrettyStackTraceString CrashInfo("Compilation construction"); + +  // FIXME: Handle environment options which affect driver behavior, somewhere +  // (client?). GCC_EXEC_PREFIX, LPATH, CC_PRINT_OPTIONS. + +  if (Optional<std::string> CompilerPathValue = +          llvm::sys::Process::GetEnv("COMPILER_PATH")) { +    StringRef CompilerPath = *CompilerPathValue; +    while (!CompilerPath.empty()) { +      std::pair<StringRef, StringRef> Split = +          CompilerPath.split(llvm::sys::EnvPathSeparator); +      PrefixDirs.push_back(Split.first); +      CompilerPath = Split.second; +    } +  } + +  // We look for the driver mode option early, because the mode can affect +  // how other options are parsed. +  ParseDriverMode(ClangExecutable, ArgList.slice(1)); + +  // FIXME: What are we going to do with -V and -b? + +  // Arguments specified in command line. +  bool ContainsError; +  CLOptions = std::make_unique<InputArgList>( +      ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError)); + +  // Try parsing configuration file. +  if (!ContainsError) +    ContainsError = loadConfigFile(); +  bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr); + +  // All arguments, from both config file and command line. +  InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions) +                                              : std::move(*CLOptions)); + +  // The args for config files or /clang: flags belong to different InputArgList +  // objects than Args. This copies an Arg from one of those other InputArgLists +  // to the ownership of Args. +  auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) { +      unsigned Index = Args.MakeIndex(Opt->getSpelling()); +      Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(), +                                     Index, BaseArg); +      Copy->getValues() = Opt->getValues(); +      if (Opt->isClaimed()) +        Copy->claim(); +      Args.append(Copy); +  }; + +  if (HasConfigFile) +    for (auto *Opt : *CLOptions) { +      if (Opt->getOption().matches(options::OPT_config)) +        continue; +      const Arg *BaseArg = &Opt->getBaseArg(); +      if (BaseArg == Opt) +        BaseArg = nullptr; +      appendOneArg(Opt, BaseArg); +    } + +  // In CL mode, look for any pass-through arguments +  if (IsCLMode() && !ContainsError) { +    SmallVector<const char *, 16> CLModePassThroughArgList; +    for (const auto *A : Args.filtered(options::OPT__SLASH_clang)) { +      A->claim(); +      CLModePassThroughArgList.push_back(A->getValue()); +    } + +    if (!CLModePassThroughArgList.empty()) { +      // Parse any pass through args using default clang processing rather +      // than clang-cl processing. +      auto CLModePassThroughOptions = std::make_unique<InputArgList>( +          ParseArgStrings(CLModePassThroughArgList, false, ContainsError)); + +      if (!ContainsError) +        for (auto *Opt : *CLModePassThroughOptions) { +          appendOneArg(Opt, nullptr); +        } +    } +  } + +  // Check for working directory option before accessing any files +  if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) +    if (VFS->setCurrentWorkingDirectory(WD->getValue())) +      Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); + +  // FIXME: This stuff needs to go into the Compilation, not the driver. +  bool CCCPrintPhases; + +  // Silence driver warnings if requested +  Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w)); + +  // -no-canonical-prefixes is used very early in main. +  Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); + +  // Ignore -pipe. +  Args.ClaimAllArgs(options::OPT_pipe); + +  // Extract -ccc args. +  // +  // FIXME: We need to figure out where this behavior should live. Most of it +  // should be outside in the client; the parts that aren't should have proper +  // options, either by introducing new ones or by overloading gcc ones like -V +  // or -b. +  CCCPrintPhases = Args.hasArg(options::OPT_ccc_print_phases); +  CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); +  if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) +    CCCGenericGCCName = A->getValue(); +  GenReproducer = Args.hasFlag(options::OPT_gen_reproducer, +                               options::OPT_fno_crash_diagnostics, +                               !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")); +  // FIXME: TargetTriple is used by the target-prefixed calls to as/ld +  // and getToolChain is const. +  if (IsCLMode()) { +    // clang-cl targets MSVC-style Win32. +    llvm::Triple T(TargetTriple); +    T.setOS(llvm::Triple::Win32); +    T.setVendor(llvm::Triple::PC); +    T.setEnvironment(llvm::Triple::MSVC); +    T.setObjectFormat(llvm::Triple::COFF); +    TargetTriple = T.str(); +  } +  if (const Arg *A = Args.getLastArg(options::OPT_target)) +    TargetTriple = A->getValue(); +  if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir)) +    Dir = InstalledDir = A->getValue(); +  for (const Arg *A : Args.filtered(options::OPT_B)) { +    A->claim(); +    PrefixDirs.push_back(A->getValue(0)); +  } +  if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) +    SysRoot = A->getValue(); +  if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) +    DyldPrefix = A->getValue(); + +  if (const Arg *A = Args.getLastArg(options::OPT_resource_dir)) +    ResourceDir = A->getValue(); + +  if (const Arg *A = Args.getLastArg(options::OPT_save_temps_EQ)) { +    SaveTemps = llvm::StringSwitch<SaveTempsMode>(A->getValue()) +                    .Case("cwd", SaveTempsCwd) +                    .Case("obj", SaveTempsObj) +                    .Default(SaveTempsCwd); +  } + +  setLTOMode(Args); + +  // Process -fembed-bitcode= flags. +  if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { +    StringRef Name = A->getValue(); +    unsigned Model = llvm::StringSwitch<unsigned>(Name) +        .Case("off", EmbedNone) +        .Case("all", EmbedBitcode) +        .Case("bitcode", EmbedBitcode) +        .Case("marker", EmbedMarker) +        .Default(~0U); +    if (Model == ~0U) { +      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) +                                                << Name; +    } else +      BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); +  } + +  std::unique_ptr<llvm::opt::InputArgList> UArgs = +      std::make_unique<InputArgList>(std::move(Args)); + +  // Perform the default argument translations. +  DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); + +  // Owned by the host. +  const ToolChain &TC = getToolChain( +      *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs)); + +  // The compilation takes ownership of Args. +  Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs, +                                   ContainsError); + +  if (!HandleImmediateArgs(*C)) +    return C; + +  // Construct the list of inputs. +  InputList Inputs; +  BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); + +  // Populate the tool chains for the offloading devices, if any. +  CreateOffloadingDeviceToolChains(*C, Inputs); + +  // Construct the list of abstract actions to perform for this compilation. On +  // MachO targets this uses the driver-driver and universal actions. +  if (TC.getTriple().isOSBinFormatMachO()) +    BuildUniversalActions(*C, C->getDefaultToolChain(), Inputs); +  else +    BuildActions(*C, C->getArgs(), Inputs, C->getActions()); + +  if (CCCPrintPhases) { +    PrintActions(*C); +    return C; +  } + +  BuildJobs(*C); + +  return C; +} + +static void printArgList(raw_ostream &OS, const llvm::opt::ArgList &Args) { +  llvm::opt::ArgStringList ASL; +  for (const auto *A : Args) +    A->render(Args, ASL); + +  for (auto I = ASL.begin(), E = ASL.end(); I != E; ++I) { +    if (I != ASL.begin()) +      OS << ' '; +    Command::printArg(OS, *I, true); +  } +  OS << '\n'; +} + +bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, +                                    SmallString<128> &CrashDiagDir) { +  using namespace llvm::sys; +  assert(llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin() && +         "Only knows about .crash files on Darwin"); + +  // The .crash file can be found on at ~/Library/Logs/DiagnosticReports/ +  // (or /Library/Logs/DiagnosticReports for root) and has the filename pattern +  // clang-<VERSION>_<YYYY-MM-DD-HHMMSS>_<hostname>.crash. +  path::home_directory(CrashDiagDir); +  if (CrashDiagDir.startswith("/var/root")) +    CrashDiagDir = "/"; +  path::append(CrashDiagDir, "Library/Logs/DiagnosticReports"); +  int PID = +#if LLVM_ON_UNIX +      getpid(); +#else +      0; +#endif +  std::error_code EC; +  fs::file_status FileStatus; +  TimePoint<> LastAccessTime; +  SmallString<128> CrashFilePath; +  // Lookup the .crash files and get the one generated by a subprocess spawned +  // by this driver invocation. +  for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd; +       File != FileEnd && !EC; File.increment(EC)) { +    StringRef FileName = path::filename(File->path()); +    if (!FileName.startswith(Name)) +      continue; +    if (fs::status(File->path(), FileStatus)) +      continue; +    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CrashFile = +        llvm::MemoryBuffer::getFile(File->path()); +    if (!CrashFile) +      continue; +    // The first line should start with "Process:", otherwise this isn't a real +    // .crash file. +    StringRef Data = CrashFile.get()->getBuffer(); +    if (!Data.startswith("Process:")) +      continue; +    // Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]" +    size_t ParentProcPos = Data.find("Parent Process:"); +    if (ParentProcPos == StringRef::npos) +      continue; +    size_t LineEnd = Data.find_first_of("\n", ParentProcPos); +    if (LineEnd == StringRef::npos) +      continue; +    StringRef ParentProcess = Data.slice(ParentProcPos+15, LineEnd).trim(); +    int OpenBracket = -1, CloseBracket = -1; +    for (size_t i = 0, e = ParentProcess.size(); i < e; ++i) { +      if (ParentProcess[i] == '[') +        OpenBracket = i; +      if (ParentProcess[i] == ']') +        CloseBracket = i; +    } +    // Extract the parent process PID from the .crash file and check whether +    // it matches this driver invocation pid. +    int CrashPID; +    if (OpenBracket < 0 || CloseBracket < 0 || +        ParentProcess.slice(OpenBracket + 1, CloseBracket) +            .getAsInteger(10, CrashPID) || CrashPID != PID) { +      continue; +    } + +    // Found a .crash file matching the driver pid. To avoid getting an older +    // and misleading crash file, continue looking for the most recent. +    // FIXME: the driver can dispatch multiple cc1 invocations, leading to +    // multiple crashes poiting to the same parent process. Since the driver +    // does not collect pid information for the dispatched invocation there's +    // currently no way to distinguish among them. +    const auto FileAccessTime = FileStatus.getLastModificationTime(); +    if (FileAccessTime > LastAccessTime) { +      CrashFilePath.assign(File->path()); +      LastAccessTime = FileAccessTime; +    } +  } + +  // If found, copy it over to the location of other reproducer files. +  if (!CrashFilePath.empty()) { +    EC = fs::copy_file(CrashFilePath, ReproCrashFilename); +    if (EC) +      return false; +    return true; +  } + +  return false; +} + +// When clang crashes, produce diagnostic information including the fully +// preprocessed source file(s).  Request that the developer attach the +// diagnostic information to a bug report. +void Driver::generateCompilationDiagnostics( +    Compilation &C, const Command &FailingCommand, +    StringRef AdditionalInformation, CompilationDiagnosticReport *Report) { +  if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics)) +    return; + +  // Don't try to generate diagnostics for link or dsymutil jobs. +  if (FailingCommand.getCreator().isLinkJob() || +      FailingCommand.getCreator().isDsymutilJob()) +    return; + +  // Print the version of the compiler. +  PrintVersion(C, llvm::errs()); + +  Diag(clang::diag::note_drv_command_failed_diag_msg) +      << "PLEASE submit a bug report to " BUG_REPORT_URL " and include the " +         "crash backtrace, preprocessed source, and associated run script."; + +  // Suppress driver output and emit preprocessor output to temp file. +  Mode = CPPMode; +  CCGenDiagnostics = true; + +  // Save the original job command(s). +  Command Cmd = FailingCommand; + +  // Keep track of whether we produce any errors while trying to produce +  // preprocessed sources. +  DiagnosticErrorTrap Trap(Diags); + +  // Suppress tool output. +  C.initCompilationForDiagnostics(); + +  // Construct the list of inputs. +  InputList Inputs; +  BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs); + +  for (InputList::iterator it = Inputs.begin(), ie = Inputs.end(); it != ie;) { +    bool IgnoreInput = false; + +    // Ignore input from stdin or any inputs that cannot be preprocessed. +    // Check type first as not all linker inputs have a value. +    if (types::getPreprocessedType(it->first) == types::TY_INVALID) { +      IgnoreInput = true; +    } else if (!strcmp(it->second->getValue(), "-")) { +      Diag(clang::diag::note_drv_command_failed_diag_msg) +          << "Error generating preprocessed source(s) - " +             "ignoring input from stdin."; +      IgnoreInput = true; +    } + +    if (IgnoreInput) { +      it = Inputs.erase(it); +      ie = Inputs.end(); +    } else { +      ++it; +    } +  } + +  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; +  for (const Arg *A : C.getArgs()) { +    if (A->getOption().matches(options::OPT_arch)) { +      StringRef ArchName = A->getValue(); +      ArchNames.insert(ArchName); +    } +  } +  if (ArchNames.size() > 1) { +    Diag(clang::diag::note_drv_command_failed_diag_msg) +        << "Error generating preprocessed source(s) - cannot generate " +           "preprocessed source with multiple -arch options."; +    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(); +  if (TC.getTriple().isOSBinFormatMachO()) +    BuildUniversalActions(C, TC, Inputs); +  else +    BuildActions(C, C.getArgs(), Inputs, C.getActions()); + +  BuildJobs(C); + +  // If there were errors building the compilation, quit now. +  if (Trap.hasErrorOccurred()) { +    Diag(clang::diag::note_drv_command_failed_diag_msg) +        << "Error generating preprocessed source(s)."; +    return; +  } + +  // Generate preprocessed output. +  SmallVector<std::pair<int, const Command *>, 4> FailingCommands; +  C.ExecuteJobs(C.getJobs(), FailingCommands); + +  // If any of the preprocessing commands failed, clean up and exit. +  if (!FailingCommands.empty()) { +    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:"; + +  SmallString<128> VFS; +  SmallString<128> ReproCrashFilename; +  for (const char *TempFile : TempFiles) { +    Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile; +    if (Report) +      Report->TemporaryFiles.push_back(TempFile); +    if (ReproCrashFilename.empty()) { +      ReproCrashFilename = TempFile; +      llvm::sys::path::replace_extension(ReproCrashFilename, ".crash"); +    } +    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. +      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); + +  llvm::SmallString<128> Script(CrashInfo.Filename); +  llvm::sys::path::replace_extension(Script, "sh"); +  std::error_code EC; +  llvm::raw_fd_ostream ScriptOS(Script, EC, llvm::sys::fs::CD_CreateNew); +  if (EC) { +    Diag(clang::diag::note_drv_command_failed_diag_msg) +        << "Error generating run script: " << Script << " " << EC.message(); +  } else { +    ScriptOS << "# Crash reproducer for " << getClangFullVersion() << "\n" +             << "# Driver args: "; +    printArgList(ScriptOS, C.getInputArgs()); +    ScriptOS << "# Original command: "; +    Cmd.Print(ScriptOS, "\n", /*Quote=*/true); +    Cmd.Print(ScriptOS, "\n", /*Quote=*/true, &CrashInfo); +    if (!AdditionalInformation.empty()) +      ScriptOS << "\n# Additional information: " << AdditionalInformation +               << "\n"; +    if (Report) +      Report->TemporaryFiles.push_back(Script.str()); +    Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; +  } + +  // On darwin, provide information about the .crash diagnostic report. +  if (llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin()) { +    SmallString<128> CrashDiagDir; +    if (getCrashDiagnosticFile(ReproCrashFilename, CrashDiagDir)) { +      Diag(clang::diag::note_drv_command_failed_diag_msg) +          << ReproCrashFilename.str(); +    } else { // Suggest a directory for the user to look for .crash files. +      llvm::sys::path::append(CrashDiagDir, Name); +      CrashDiagDir += "_<YYYY-MM-DD-HHMMSS>_<hostname>.crash"; +      Diag(clang::diag::note_drv_command_failed_diag_msg) +          << "Crash backtrace is located in"; +      Diag(clang::diag::note_drv_command_failed_diag_msg) +          << CrashDiagDir.str(); +      Diag(clang::diag::note_drv_command_failed_diag_msg) +          << "(choose the .crash file that corresponds to your crash)"; +    } +  } + +  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, Command &Cmd) { +  // Since commandLineFitsWithinSystemLimits() 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 (Cmd.getCreator().getResponseFilesSupport() == Tool::RF_None || +      llvm::sys::commandLineFitsWithinSystemLimits(Cmd.getExecutable(), +                                                   Cmd.getArguments())) +    return; + +  std::string TmpName = GetTemporaryPath("response", "txt"); +  Cmd.setResponseFile(C.addTempFile(C.getArgs().MakeArgString(TmpName))); +} + +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); +    return 0; +  } + +  // If there were errors building the compilation, quit now. +  if (Diags.hasErrorOccurred()) +    return 1; + +  // Set up response file names for each command, if necessary +  for (auto &Job : C.getJobs()) +    setUpResponseFiles(C, Job); + +  C.ExecuteJobs(C.getJobs(), FailingCommands); + +  // If the command succeeded, we are done. +  if (FailingCommands.empty()) +    return 0; + +  // Otherwise, remove result files and print extra information about abnormal +  // failures. +  int Res = 0; +  for (const auto &CmdPair : FailingCommands) { +    int CommandRes = CmdPair.first; +    const Command *FailingCommand = CmdPair.second; + +    // Remove result files if we're not saving temps. +    if (!isSaveTempsEnabled()) { +      const JobAction *JA = cast<JobAction>(&FailingCommand->getSource()); +      C.CleanupFileMap(C.getResultFiles(), JA, true); + +      // Failure result files are valid unless we crashed. +      if (CommandRes < 0) +        C.CleanupFileMap(C.getFailureResultFiles(), JA, true); +    } + +#if LLVM_ON_UNIX +    // llvm/lib/Support/Unix/Signals.inc will exit with a special return code +    // for SIGPIPE. Do not print diagnostics for this case. +    if (CommandRes == EX_IOERR) { +      Res = CommandRes; +      continue; +    } +#endif + +    // 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() || CommandRes != 1) { +      // FIXME: See FIXME above regarding result code interpretation. +      if (CommandRes < 0) +        Diag(clang::diag::err_drv_command_signalled) +            << FailingTool.getShortName(); +      else +        Diag(clang::diag::err_drv_command_failed) +            << FailingTool.getShortName() << CommandRes; +    } +  } +  return Res; +} + +void Driver::PrintHelp(bool ShowHidden) const { +  unsigned IncludedFlagsBitmask; +  unsigned ExcludedFlagsBitmask; +  std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = +      getIncludeExcludeOptionFlagMasks(IsCLMode()); + +  ExcludedFlagsBitmask |= options::NoDriverOption; +  if (!ShowHidden) +    ExcludedFlagsBitmask |= HelpHidden; + +  std::string Usage = llvm::formatv("{0} [options] file...", Name).str(); +  getOpts().PrintHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(), +                      IncludedFlagsBitmask, ExcludedFlagsBitmask, +                      /*ShowAllAliases=*/false); +} + +void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { +  // FIXME: The following handlers should use a callback mechanism, we don't +  // know what the client would like to do. +  OS << getClangFullVersion() << '\n'; +  const ToolChain &TC = C.getDefaultToolChain(); +  OS << "Target: " << TC.getTripleString() << '\n'; + +  // Print the threading model. +  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'; + +  // Print out the install directory. +  OS << "InstalledDir: " << InstalledDir << '\n'; + +  // If configuration file was used, print its path. +  if (!ConfigFile.empty()) +    OS << "Configuration file: " << ConfigFile << '\n'; +} + +/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories +/// option. +static void PrintDiagnosticCategories(raw_ostream &OS) { +  // Skip the empty category. +  for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories(); i != max; +       ++i) +    OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n'; +} + +void Driver::HandleAutocompletions(StringRef PassedFlags) const { +  if (PassedFlags == "") +    return; +  // Print out all options that start with a given argument. This is used for +  // shell autocompletion. +  std::vector<std::string> SuggestedCompletions; +  std::vector<std::string> Flags; + +  unsigned short DisableFlags = +      options::NoDriverOption | options::Unsupported | options::Ignored; + +  // Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag," +  // because the latter indicates that the user put space before pushing tab +  // which should end up in a file completion. +  const bool HasSpace = PassedFlags.endswith(","); + +  // Parse PassedFlags by "," as all the command-line flags are passed to this +  // function separated by "," +  StringRef TargetFlags = PassedFlags; +  while (TargetFlags != "") { +    StringRef CurFlag; +    std::tie(CurFlag, TargetFlags) = TargetFlags.split(","); +    Flags.push_back(std::string(CurFlag)); +  } + +  // We want to show cc1-only options only when clang is invoked with -cc1 or +  // -Xclang. +  if (llvm::is_contained(Flags, "-Xclang") || llvm::is_contained(Flags, "-cc1")) +    DisableFlags &= ~options::NoDriverOption; + +  const llvm::opt::OptTable &Opts = getOpts(); +  StringRef Cur; +  Cur = Flags.at(Flags.size() - 1); +  StringRef Prev; +  if (Flags.size() >= 2) { +    Prev = Flags.at(Flags.size() - 2); +    SuggestedCompletions = Opts.suggestValueCompletions(Prev, Cur); +  } + +  if (SuggestedCompletions.empty()) +    SuggestedCompletions = Opts.suggestValueCompletions(Cur, ""); + +  // If Flags were empty, it means the user typed `clang [tab]` where we should +  // list all possible flags. If there was no value completion and the user +  // pressed tab after a space, we should fall back to a file completion. +  // We're printing a newline to be consistent with what we print at the end of +  // this function. +  if (SuggestedCompletions.empty() && HasSpace && !Flags.empty()) { +    llvm::outs() << '\n'; +    return; +  } + +  // When flag ends with '=' and there was no value completion, return empty +  // string and fall back to the file autocompletion. +  if (SuggestedCompletions.empty() && !Cur.endswith("=")) { +    // If the flag is in the form of "--autocomplete=-foo", +    // we were requested to print out all option names that start with "-foo". +    // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". +    SuggestedCompletions = Opts.findByPrefix(Cur, DisableFlags); + +    // We have to query the -W flags manually as they're not in the OptTable. +    // TODO: Find a good way to add them to OptTable instead and them remove +    // this code. +    for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) +      if (S.startswith(Cur)) +        SuggestedCompletions.push_back(S); +  } + +  // Sort the autocomplete candidates so that shells print them out in a +  // deterministic order. We could sort in any way, but we chose +  // case-insensitive sorting for consistency with the -help option +  // which prints out options in the case-insensitive alphabetical order. +  llvm::sort(SuggestedCompletions, [](StringRef A, StringRef B) { +    if (int X = A.compare_lower(B)) +      return X < 0; +    return A.compare(B) > 0; +  }); + +  llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; +} + +bool Driver::HandleImmediateArgs(const Compilation &C) { +  // The order these options are handled in gcc is all over the place, but we +  // don't expect inconsistencies w.r.t. that to matter in practice. + +  if (C.getArgs().hasArg(options::OPT_dumpmachine)) { +    llvm::outs() << C.getDefaultToolChain().getTripleString() << '\n'; +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_dumpversion)) { +    // Since -dumpversion is only implemented for pedantic GCC compatibility, we +    // return an answer which matches our definition of __VERSION__. +    llvm::outs() << CLANG_VERSION_STRING << "\n"; +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT__print_diagnostic_categories)) { +    PrintDiagnosticCategories(llvm::outs()); +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_help) || +      C.getArgs().hasArg(options::OPT__help_hidden)) { +    PrintHelp(C.getArgs().hasArg(options::OPT__help_hidden)); +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT__version)) { +    // Follow gcc behavior and use stdout for --version and stderr for -v. +    PrintVersion(C, llvm::outs()); +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_v) || +      C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) || +      C.getArgs().hasArg(options::OPT_print_supported_cpus)) { +    PrintVersion(C, llvm::errs()); +    SuppressMissingInputWarning = true; +  } + +  if (C.getArgs().hasArg(options::OPT_v)) { +    if (!SystemConfigDir.empty()) +      llvm::errs() << "System configuration file directory: " +                   << SystemConfigDir << "\n"; +    if (!UserConfigDir.empty()) +      llvm::errs() << "User configuration file directory: " +                   << UserConfigDir << "\n"; +  } + +  const ToolChain &TC = C.getDefaultToolChain(); + +  if (C.getArgs().hasArg(options::OPT_v)) +    TC.printVerboseInfo(llvm::errs()); + +  if (C.getArgs().hasArg(options::OPT_print_resource_dir)) { +    llvm::outs() << ResourceDir << '\n'; +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_print_search_dirs)) { +    llvm::outs() << "programs: ="; +    bool separator = false; +    for (const std::string &Path : TC.getProgramPaths()) { +      if (separator) +        llvm::outs() << llvm::sys::EnvPathSeparator; +      llvm::outs() << Path; +      separator = true; +    } +    llvm::outs() << "\n"; +    llvm::outs() << "libraries: =" << ResourceDir; + +    StringRef sysroot = C.getSysRoot(); + +    for (const std::string &Path : TC.getFilePaths()) { +      // Always print a separator. ResourceDir was the first item shown. +      llvm::outs() << llvm::sys::EnvPathSeparator; +      // Interpretation of leading '=' is needed only for NetBSD. +      if (Path[0] == '=') +        llvm::outs() << sysroot << Path.substr(1); +      else +        llvm::outs() << Path; +    } +    llvm::outs() << "\n"; +    return false; +  } + +  // FIXME: The following handlers should use a callback mechanism, we don't +  // know what the client would like to do. +  if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) { +    llvm::outs() << GetFilePath(A->getValue(), TC) << "\n"; +    return false; +  } + +  if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) { +    StringRef ProgName = A->getValue(); + +    // Null program name cannot have a path. +    if (! ProgName.empty()) +      llvm::outs() << GetProgramPath(ProgName, TC); + +    llvm::outs() << "\n"; +    return false; +  } + +  if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) { +    StringRef PassedFlags = A->getValue(); +    HandleAutocompletions(PassedFlags); +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) { +    ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs()); +    const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(C.getArgs())); +    RegisterEffectiveTriple TripleRAII(TC, Triple); +    switch (RLT) { +    case ToolChain::RLT_CompilerRT: +      llvm::outs() << TC.getCompilerRT(C.getArgs(), "builtins") << "\n"; +      break; +    case ToolChain::RLT_Libgcc: +      llvm::outs() << GetFilePath("libgcc.a", TC) << "\n"; +      break; +    } +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_print_multi_lib)) { +    for (const Multilib &Multilib : TC.getMultilibs()) +      llvm::outs() << Multilib << "\n"; +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_print_multi_directory)) { +    const Multilib &Multilib = TC.getMultilib(); +    if (Multilib.gccSuffix().empty()) +      llvm::outs() << ".\n"; +    else { +      StringRef Suffix(Multilib.gccSuffix()); +      assert(Suffix.front() == '/'); +      llvm::outs() << Suffix.substr(1) << "\n"; +    } +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_print_target_triple)) { +    llvm::outs() << TC.getTripleString() << "\n"; +    return false; +  } + +  if (C.getArgs().hasArg(options::OPT_print_effective_triple)) { +    const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(C.getArgs())); +    llvm::outs() << Triple.getTriple() << "\n"; +    return false; +  } + +  return true; +} + +enum { +  TopLevelAction = 0, +  HeadSibAction = 1, +  OtherSibAction = 2, +}; + +// Display an action graph human-readably.  Action A is the "sink" node +// and latest-occuring action. Traversal is in pre-order, visiting the +// inputs to each action before printing the action itself. +static unsigned PrintActions1(const Compilation &C, Action *A, +                              std::map<Action *, unsigned> &Ids, +                              Twine Indent = {}, int Kind = TopLevelAction) { +  if (Ids.count(A)) // A was already visited. +    return Ids[A]; + +  std::string str; +  llvm::raw_string_ostream os(str); + +  auto getSibIndent = [](int K) -> Twine { +    return (K == HeadSibAction) ? "   " : (K == OtherSibAction) ? "|  " : ""; +  }; + +  Twine SibIndent = Indent + getSibIndent(Kind); +  int SibKind = HeadSibAction; +  os << Action::getClassName(A->getKind()) << ", "; +  if (InputAction *IA = dyn_cast<InputAction>(A)) { +    os << "\"" << IA->getInputArg().getValue() << "\""; +  } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { +    os << '"' << BIA->getArchName() << '"' << ", {" +       << PrintActions1(C, *BIA->input_begin(), Ids, SibIndent, SibKind) << "}"; +  } else if (OffloadAction *OA = dyn_cast<OffloadAction>(A)) { +    bool IsFirst = true; +    OA->doOnEachDependence( +        [&](Action *A, const ToolChain *TC, const char *BoundArch) { +          // E.g. for two CUDA device dependences whose bound arch is sm_20 and +          // sm_35 this will generate: +          // "cuda-device" (nvptx64-nvidia-cuda:sm_20) {#ID}, "cuda-device" +          // (nvptx64-nvidia-cuda:sm_35) {#ID} +          if (!IsFirst) +            os << ", "; +          os << '"'; +          if (TC) +            os << A->getOffloadingKindPrefix(); +          else +            os << "host"; +          os << " ("; +          os << TC->getTriple().normalize(); + +          if (BoundArch) +            os << ":" << BoundArch; +          os << ")"; +          os << '"'; +          os << " {" << PrintActions1(C, A, Ids, SibIndent, SibKind) << "}"; +          IsFirst = false; +          SibKind = OtherSibAction; +        }); +  } else { +    const ActionList *AL = &A->getInputs(); + +    if (AL->size()) { +      const char *Prefix = "{"; +      for (Action *PreRequisite : *AL) { +        os << Prefix << PrintActions1(C, PreRequisite, Ids, SibIndent, SibKind); +        Prefix = ", "; +        SibKind = OtherSibAction; +      } +      os << "}"; +    } else +      os << "{}"; +  } + +  // Append offload info for all options other than the offloading action +  // itself (e.g. (cuda-device, sm_20) or (cuda-host)). +  std::string offload_str; +  llvm::raw_string_ostream offload_os(offload_str); +  if (!isa<OffloadAction>(A)) { +    auto S = A->getOffloadingKindPrefix(); +    if (!S.empty()) { +      offload_os << ", (" << S; +      if (A->getOffloadingArch()) +        offload_os << ", " << A->getOffloadingArch(); +      offload_os << ")"; +    } +  } + +  auto getSelfIndent = [](int K) -> Twine { +    return (K == HeadSibAction) ? "+- " : (K == OtherSibAction) ? "|- " : ""; +  }; + +  unsigned Id = Ids.size(); +  Ids[A] = Id; +  llvm::errs() << Indent + getSelfIndent(Kind) << Id << ": " << os.str() << ", " +               << types::getTypeName(A->getType()) << offload_os.str() << "\n"; + +  return Id; +} + +// Print the action graphs in a compilation C. +// For example "clang -c file1.c file2.c" is composed of two subgraphs. +void Driver::PrintActions(const Compilation &C) const { +  std::map<Action *, unsigned> Ids; +  for (Action *A : C.getActions()) +    PrintActions1(C, A, Ids); +} + +/// Check whether the given input tree contains any compilation or +/// assembly actions. +static bool ContainsCompileOrAssembleAction(const Action *A) { +  if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A) || +      isa<AssembleJobAction>(A)) +    return true; + +  for (const Action *Input : A->inputs()) +    if (ContainsCompileOrAssembleAction(Input)) +      return true; + +  return false; +} + +void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, +                                   const InputList &BAInputs) const { +  DerivedArgList &Args = C.getArgs(); +  ActionList &Actions = C.getActions(); +  llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); +  // Collect the list of architectures. Duplicates are allowed, but should only +  // be handled once (in the order seen). +  llvm::StringSet<> ArchNames; +  SmallVector<const char *, 4> Archs; +  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. +      llvm::Triple::ArchType Arch = +          tools::darwin::getArchTypeForMachOArchName(A->getValue()); +      if (Arch == llvm::Triple::UnknownArch) { +        Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); +        continue; +      } + +      A->claim(); +      if (ArchNames.insert(A->getValue()).second) +        Archs.push_back(A->getValue()); +    } +  } + +  // When there is no explicit arch for this platform, make sure we still bind +  // the architecture (to the default) so that -Xarch_ is handled correctly. +  if (!Archs.size()) +    Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); + +  ActionList SingleActions; +  BuildActions(C, Args, BAInputs, SingleActions); + +  // Add in arch bindings for every top level action, as well as lipo and +  // dsymutil steps if needed. +  for (Action* Act : SingleActions) { +    // Make sure we can lipo this kind of output. If not (and it is an actual +    // output) then we disallow, since we can't create an output file with the +    // right name without overwriting it. We could remove this oddity by just +    // changing the output names to include the arch, which would also fix +    // -save-temps. Compatibility wins for now. + +    if (Archs.size() > 1 && !types::canLipoType(Act->getType())) +      Diag(clang::diag::err_drv_invalid_output_with_multiple_archs) +          << types::getTypeName(Act->getType()); + +    ActionList Inputs; +    for (unsigned i = 0, e = Archs.size(); i != e; ++i) +      Inputs.push_back(C.MakeAction<BindArchAction>(Act, Archs[i])); + +    // Lipo if necessary, we do it this way because we need to set the arch flag +    // so that -Xarch_ gets overwritten. +    if (Inputs.size() == 1 || Act->getType() == types::TY_Nothing) +      Actions.append(Inputs.begin(), Inputs.end()); +    else +      Actions.push_back(C.MakeAction<LipoJobAction>(Inputs, Act->getType())); + +    // Handle debug info queries. +    Arg *A = Args.getLastArg(options::OPT_g_Group); +    if (A && !A->getOption().matches(options::OPT_g0) && +        !A->getOption().matches(options::OPT_gstabs) && +        ContainsCompileOrAssembleAction(Actions.back())) { + +      // 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 +      // will be removed at the end of the compilation process. +      if (Act->getType() == types::TY_Image) { +        ActionList Inputs; +        Inputs.push_back(Actions.back()); +        Actions.pop_back(); +        Actions.push_back( +            C.MakeAction<DsymutilJobAction>(Inputs, types::TY_dSYM)); +      } + +      // Verify the debug info output. +      if (Args.hasArg(options::OPT_verify_debug_info)) { +        Action* LastAction = Actions.back(); +        Actions.pop_back(); +        Actions.push_back(C.MakeAction<VerifyDebugInfoJobAction>( +            LastAction, types::TY_Nothing)); +      } +    } +  } +} + +bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, +                                    types::ID Ty, bool TypoCorrect) const { +  if (!getCheckInputsExist()) +    return true; + +  // stdin always exists. +  if (Value == "-") +    return true; + +  if (getVFS().exists(Value)) +    return true; + +  if (IsCLMode()) { +    if (!llvm::sys::path::is_absolute(Twine(Value)) && +        llvm::sys::Process::FindInEnvPath("LIB", Value)) +      return true; + +    if (Args.hasArg(options::OPT__SLASH_link) && Ty == types::TY_Object) { +      // Arguments to the /link flag might cause the linker to search for object +      // and library files in paths we don't know about. Don't error in such +      // cases. +      return true; +    } +  } + +  if (TypoCorrect) { +    // Check if the filename is a typo for an option flag. OptTable thinks +    // that all args that are not known options and that start with / are +    // filenames, but e.g. `/diagnostic:caret` is more likely a typo for +    // the option `/diagnostics:caret` than a reference to a file in the root +    // directory. +    unsigned IncludedFlagsBitmask; +    unsigned ExcludedFlagsBitmask; +    std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = +        getIncludeExcludeOptionFlagMasks(IsCLMode()); +    std::string Nearest; +    if (getOpts().findNearest(Value, Nearest, IncludedFlagsBitmask, +                              ExcludedFlagsBitmask) <= 1) { +      Diag(clang::diag::err_drv_no_such_file_with_suggestion) +          << Value << Nearest; +      return false; +    } +  } + +  Diag(clang::diag::err_drv_no_such_file) << Value; +  return false; +} + +// Construct a the list of inputs and their types. +void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, +                         InputList &Inputs) const { +  const llvm::opt::OptTable &Opts = getOpts(); +  // Track the current user specified (-x) input. We also explicitly track the +  // argument used to set the type; we only want to claim the type when we +  // actually use it, so we warn about unused -x arguments. +  types::ID InputType = types::TY_Nothing; +  Arg *InputTypeArg = nullptr; + +  // The last /TC or /TP option sets the input type to C or C++ globally. +  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; + +    Arg *Previous = nullptr; +    bool ShowNote = false; +    for (Arg *A : +         Args.filtered(options::OPT__SLASH_TC, options::OPT__SLASH_TP)) { +      if (Previous) { +        Diag(clang::diag::warn_drv_overriding_flag_option) +          << Previous->getSpelling() << A->getSpelling(); +        ShowNote = true; +      } +      Previous = A; +    } +    if (ShowNote) +      Diag(clang::diag::note_drv_t_option_is_global); + +    // No driver mode exposes -x and /TC or /TP; we don't support mixing them. +    assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed"); +  } + +  for (Arg *A : Args) { +    if (A->getOption().getKind() == Option::InputClass) { +      const char *Value = A->getValue(); +      types::ID Ty = types::TY_INVALID; + +      // Infer the input type if necessary. +      if (InputType == types::TY_Nothing) { +        // If there was an explicit arg for this, claim it. +        if (InputTypeArg) +          InputTypeArg->claim(); + +        // stdin must be handled specially. +        if (memcmp(Value, "-", 2) == 0) { +          // If running with -E, treat as a C input (this changes the builtin +          // macros, for example). This may be overridden by -ObjC below. +          // +          // Otherwise emit an error but still use a valid type to avoid +          // spurious errors (e.g., no inputs). +          if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP()) +            Diag(IsCLMode() ? clang::diag::err_drv_unknown_stdin_type_clang_cl +                            : clang::diag::err_drv_unknown_stdin_type); +          Ty = types::TY_C; +        } else { +          // Otherwise lookup by extension. +          // Fallback is C if invoked as C preprocessor, C++ if invoked with +          // clang-cl /E, or Object otherwise. +          // We use a host hook here because Darwin at least has its own +          // idea of what .s is. +          if (const char *Ext = strrchr(Value, '.')) +            Ty = TC.LookupTypeForExtension(Ext + 1); + +          if (Ty == types::TY_INVALID) { +            if (CCCIsCPP()) +              Ty = types::TY_C; +            else if (IsCLMode() && Args.hasArgNoClaim(options::OPT_E)) +              Ty = types::TY_CXX; +            else +              Ty = types::TY_Object; +          } + +          // If the driver is invoked as C++ compiler (like clang++ or c++) it +          // should autodetect some input files as C++ for g++ compatibility. +          if (CCCIsCXX()) { +            types::ID OldTy = Ty; +            Ty = types::lookupCXXTypeForCType(Ty); + +            if (Ty != OldTy) +              Diag(clang::diag::warn_drv_treating_input_as_cxx) +                  << getTypeName(OldTy) << getTypeName(Ty); +          } + +          // If running with -fthinlto-index=, extensions that normally identify +          // native object files actually identify LLVM bitcode files. +          if (Args.hasArgNoClaim(options::OPT_fthinlto_index_EQ) && +              Ty == types::TY_Object) +            Ty = types::TY_LLVM_BC; +        } + +        // -ObjC and -ObjC++ override the default language, but only for "source +        // files". We just treat everything that isn't a linker input as a +        // source file. +        // +        // FIXME: Clean this up if we move the phase sequence into the type. +        if (Ty != types::TY_Object) { +          if (Args.hasArg(options::OPT_ObjC)) +            Ty = types::TY_ObjC; +          else if (Args.hasArg(options::OPT_ObjCXX)) +            Ty = types::TY_ObjCXX; +        } +      } else { +        assert(InputTypeArg && "InputType set w/o InputTypeArg"); +        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(Args, Value, Ty, /*TypoCorrect=*/true)) +        Inputs.push_back(std::make_pair(Ty, A)); + +    } else if (A->getOption().matches(options::OPT__SLASH_Tc)) { +      StringRef Value = A->getValue(); +      if (DiagnoseInputExistence(Args, Value, types::TY_C, +                                 /*TypoCorrect=*/false)) { +        Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); +        Inputs.push_back(std::make_pair(types::TY_C, InputArg)); +      } +      A->claim(); +    } else if (A->getOption().matches(options::OPT__SLASH_Tp)) { +      StringRef Value = A->getValue(); +      if (DiagnoseInputExistence(Args, Value, types::TY_CXX, +                                 /*TypoCorrect=*/false)) { +        Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); +        Inputs.push_back(std::make_pair(types::TY_CXX, InputArg)); +      } +      A->claim(); +    } else if (A->getOption().hasFlag(options::LinkerInput)) { +      // Just treat as object type, we could make a special type for this if +      // necessary. +      Inputs.push_back(std::make_pair(types::TY_Object, A)); + +    } else if (A->getOption().matches(options::OPT_x)) { +      InputTypeArg = A; +      InputType = types::lookupTypeForTypeSpecifier(A->getValue()); +      A->claim(); + +      // Follow gcc behavior and treat as linker input for invalid -x +      // options. Its not clear why we shouldn't just revert to unknown; but +      // this isn't very important, we might as well be bug compatible. +      if (!InputType) { +        Diag(clang::diag::err_drv_unknown_language) << A->getValue(); +        InputType = types::TY_Object; +      } +    } else if (A->getOption().getID() == options::OPT_U) { +      assert(A->getNumValues() == 1 && "The /U option has one value."); +      StringRef Val = A->getValue(0); +      if (Val.find_first_of("/\\") != StringRef::npos) { +        // Warn about e.g. "/Users/me/myfile.c". +        Diag(diag::warn_slash_u_filename) << Val; +        Diag(diag::note_use_dashdash); +      } +    } +  } +  if (CCCIsCPP() && Inputs.empty()) { +    // If called as standalone preprocessor, stdin is processed +    // if no other input is present. +    Arg *A = MakeInputArg(Args, Opts, "-"); +    Inputs.push_back(std::make_pair(types::TY_C, A)); +  } +} + +namespace { +/// Provides a convenient interface for different programming models to generate +/// the required device actions. +class OffloadingActionBuilder final { +  /// Flag used to trace errors in the builder. +  bool IsValid = false; + +  /// The compilation that is using this builder. +  Compilation &C; + +  /// Map between an input argument and the offload kinds used to process it. +  std::map<const Arg *, unsigned> InputArgToOffloadKindMap; + +  /// Builder interface. It doesn't build anything or keep any state. +  class DeviceActionBuilder { +  public: +    typedef const llvm::SmallVectorImpl<phases::ID> PhasesTy; + +    enum ActionBuilderReturnCode { +      // The builder acted successfully on the current action. +      ABRT_Success, +      // The builder didn't have to act on the current action. +      ABRT_Inactive, +      // The builder was successful and requested the host action to not be +      // generated. +      ABRT_Ignore_Host, +    }; + +  protected: +    /// Compilation associated with this builder. +    Compilation &C; + +    /// Tool chains associated with this builder. The same programming +    /// model may have associated one or more tool chains. +    SmallVector<const ToolChain *, 2> ToolChains; + +    /// The derived arguments associated with this builder. +    DerivedArgList &Args; + +    /// The inputs associated with this builder. +    const Driver::InputList &Inputs; + +    /// The associated offload kind. +    Action::OffloadKind AssociatedOffloadKind = Action::OFK_None; + +  public: +    DeviceActionBuilder(Compilation &C, DerivedArgList &Args, +                        const Driver::InputList &Inputs, +                        Action::OffloadKind AssociatedOffloadKind) +        : C(C), Args(Args), Inputs(Inputs), +          AssociatedOffloadKind(AssociatedOffloadKind) {} +    virtual ~DeviceActionBuilder() {} + +    /// Fill up the array \a DA with all the device dependences that should be +    /// added to the provided host action \a HostAction. By default it is +    /// inactive. +    virtual ActionBuilderReturnCode +    getDeviceDependences(OffloadAction::DeviceDependences &DA, +                         phases::ID CurPhase, phases::ID FinalPhase, +                         PhasesTy &Phases) { +      return ABRT_Inactive; +    } + +    /// Update the state to include the provided host action \a HostAction as a +    /// dependency of the current device action. By default it is inactive. +    virtual ActionBuilderReturnCode addDeviceDepences(Action *HostAction) { +      return ABRT_Inactive; +    } + +    /// Append top level actions generated by the builder. +    virtual void appendTopLevelActions(ActionList &AL) {} + +    /// Append linker actions generated by the builder. +    virtual void appendLinkActions(ActionList &AL) {} + +    /// Append linker actions generated by the builder. +    virtual void appendLinkDependences(OffloadAction::DeviceDependences &DA) {} + +    /// Initialize the builder. Return true if any initialization errors are +    /// found. +    virtual bool initialize() { return false; } + +    /// Return true if the builder can use bundling/unbundling. +    virtual bool canUseBundlerUnbundler() const { return false; } + +    /// Return true if this builder is valid. We have a valid builder if we have +    /// associated device tool chains. +    bool isValid() { return !ToolChains.empty(); } + +    /// Return the associated offload kind. +    Action::OffloadKind getAssociatedOffloadKind() { +      return AssociatedOffloadKind; +    } +  }; + +  /// Base class for CUDA/HIP action builder. It injects device code in +  /// the host backend action. +  class CudaActionBuilderBase : public DeviceActionBuilder { +  protected: +    /// Flags to signal if the user requested host-only or device-only +    /// compilation. +    bool CompileHostOnly = false; +    bool CompileDeviceOnly = false; +    bool EmitLLVM = false; +    bool EmitAsm = false; + +    /// List of GPU architectures to use in this compilation. +    SmallVector<CudaArch, 4> GpuArchList; + +    /// The CUDA actions for the current input. +    ActionList CudaDeviceActions; + +    /// The CUDA fat binary if it was generated for the current input. +    Action *CudaFatBinary = nullptr; + +    /// Flag that is set to true if this builder acted on the current input. +    bool IsActive = false; + +    /// Flag for -fgpu-rdc. +    bool Relocatable = false; + +    /// Default GPU architecture if there's no one specified. +    CudaArch DefaultCudaArch = CudaArch::UNKNOWN; + +  public: +    CudaActionBuilderBase(Compilation &C, DerivedArgList &Args, +                          const Driver::InputList &Inputs, +                          Action::OffloadKind OFKind) +        : DeviceActionBuilder(C, Args, Inputs, OFKind) {} + +    ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { +      // While generating code for CUDA, we only depend on the host input action +      // to trigger the creation of all the CUDA device actions. + +      // If we are dealing with an input action, replicate it for each GPU +      // architecture. If we are in host-only mode we return 'success' so that +      // the host uses the CUDA offload kind. +      if (auto *IA = dyn_cast<InputAction>(HostAction)) { +        assert(!GpuArchList.empty() && +               "We should have at least one GPU architecture."); + +        // If the host input is not CUDA or HIP, we don't need to bother about +        // this input. +        if (IA->getType() != types::TY_CUDA && +            IA->getType() != types::TY_HIP) { +          // The builder will ignore this input. +          IsActive = false; +          return ABRT_Inactive; +        } + +        // Set the flag to true, so that the builder acts on the current input. +        IsActive = true; + +        if (CompileHostOnly) +          return ABRT_Success; + +        // Replicate inputs for each GPU architecture. +        auto Ty = IA->getType() == types::TY_HIP ? types::TY_HIP_DEVICE +                                                 : types::TY_CUDA_DEVICE; +        for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { +          CudaDeviceActions.push_back( +              C.MakeAction<InputAction>(IA->getInputArg(), Ty)); +        } + +        return ABRT_Success; +      } + +      // If this is an unbundling action use it as is for each CUDA toolchain. +      if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { + +        // If -fgpu-rdc is disabled, should not unbundle since there is no +        // device code to link. +        if (!Relocatable) +          return ABRT_Inactive; + +        CudaDeviceActions.clear(); +        auto *IA = cast<InputAction>(UA->getInputs().back()); +        std::string FileName = IA->getInputArg().getAsString(Args); +        // Check if the type of the file is the same as the action. Do not +        // unbundle it if it is not. Do not unbundle .so files, for example, +        // which are not object files. +        if (IA->getType() == types::TY_Object && +            (!llvm::sys::path::has_extension(FileName) || +             types::lookupTypeForExtension( +                 llvm::sys::path::extension(FileName).drop_front()) != +                 types::TY_Object)) +          return ABRT_Inactive; + +        for (auto Arch : GpuArchList) { +          CudaDeviceActions.push_back(UA); +          UA->registerDependentActionInfo(ToolChains[0], CudaArchToString(Arch), +                                          AssociatedOffloadKind); +        } +        return ABRT_Success; +      } + +      return IsActive ? ABRT_Success : ABRT_Inactive; +    } + +    void appendTopLevelActions(ActionList &AL) override { +      // Utility to append actions to the top level list. +      auto AddTopLevel = [&](Action *A, CudaArch BoundArch) { +        OffloadAction::DeviceDependences Dep; +        Dep.add(*A, *ToolChains.front(), CudaArchToString(BoundArch), +                AssociatedOffloadKind); +        AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); +      }; + +      // If we have a fat binary, add it to the list. +      if (CudaFatBinary) { +        AddTopLevel(CudaFatBinary, CudaArch::UNKNOWN); +        CudaDeviceActions.clear(); +        CudaFatBinary = nullptr; +        return; +      } + +      if (CudaDeviceActions.empty()) +        return; + +      // If we have CUDA actions at this point, that's because we have a have +      // partial compilation, so we should have an action for each GPU +      // architecture. +      assert(CudaDeviceActions.size() == GpuArchList.size() && +             "Expecting one action per GPU architecture."); +      assert(ToolChains.size() == 1 && +             "Expecting to have a sing CUDA toolchain."); +      for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) +        AddTopLevel(CudaDeviceActions[I], GpuArchList[I]); + +      CudaDeviceActions.clear(); +    } + +    bool initialize() override { +      assert(AssociatedOffloadKind == Action::OFK_Cuda || +             AssociatedOffloadKind == Action::OFK_HIP); + +      // We don't need to support CUDA. +      if (AssociatedOffloadKind == Action::OFK_Cuda && +          !C.hasOffloadToolChain<Action::OFK_Cuda>()) +        return false; + +      // We don't need to support HIP. +      if (AssociatedOffloadKind == Action::OFK_HIP && +          !C.hasOffloadToolChain<Action::OFK_HIP>()) +        return false; + +      Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, +          options::OPT_fno_gpu_rdc, /*Default=*/false); + +      const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); +      assert(HostTC && "No toolchain for host compilation."); +      if (HostTC->getTriple().isNVPTX() || +          HostTC->getTriple().getArch() == llvm::Triple::amdgcn) { +        // We do not support targeting NVPTX/AMDGCN for host compilation. Throw +        // an error and abort pipeline construction early so we don't trip +        // asserts that assume device-side compilation. +        C.getDriver().Diag(diag::err_drv_cuda_host_arch) +            << HostTC->getTriple().getArchName(); +        return true; +      } + +      ToolChains.push_back( +          AssociatedOffloadKind == Action::OFK_Cuda +              ? C.getSingleOffloadToolChain<Action::OFK_Cuda>() +              : C.getSingleOffloadToolChain<Action::OFK_HIP>()); + +      Arg *PartialCompilationArg = Args.getLastArg( +          options::OPT_cuda_host_only, options::OPT_cuda_device_only, +          options::OPT_cuda_compile_host_device); +      CompileHostOnly = PartialCompilationArg && +                        PartialCompilationArg->getOption().matches( +                            options::OPT_cuda_host_only); +      CompileDeviceOnly = PartialCompilationArg && +                          PartialCompilationArg->getOption().matches( +                              options::OPT_cuda_device_only); +      EmitLLVM = Args.getLastArg(options::OPT_emit_llvm); +      EmitAsm = Args.getLastArg(options::OPT_S); + +      // Collect all cuda_gpu_arch parameters, removing duplicates. +      std::set<CudaArch> GpuArchs; +      bool Error = false; +      for (Arg *A : Args) { +        if (!(A->getOption().matches(options::OPT_cuda_gpu_arch_EQ) || +              A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ))) +          continue; +        A->claim(); + +        const StringRef ArchStr = A->getValue(); +        if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ) && +            ArchStr == "all") { +          GpuArchs.clear(); +          continue; +        } +        CudaArch Arch = StringToCudaArch(ArchStr); +        if (Arch == CudaArch::UNKNOWN) { +          C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; +          Error = true; +        } else if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) +          GpuArchs.insert(Arch); +        else if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ)) +          GpuArchs.erase(Arch); +        else +          llvm_unreachable("Unexpected option."); +      } + +      // Collect list of GPUs remaining in the set. +      for (CudaArch Arch : GpuArchs) +        GpuArchList.push_back(Arch); + +      // Default to sm_20 which is the lowest common denominator for +      // supported GPUs.  sm_20 code should work correctly, if +      // suboptimally, on all newer GPUs. +      if (GpuArchList.empty()) +        GpuArchList.push_back(DefaultCudaArch); + +      return Error; +    } +  }; + +  /// \brief CUDA action builder. It injects device code in the host backend +  /// action. +  class CudaActionBuilder final : public CudaActionBuilderBase { +  public: +    CudaActionBuilder(Compilation &C, DerivedArgList &Args, +                      const Driver::InputList &Inputs) +        : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) { +      DefaultCudaArch = CudaArch::SM_20; +    } + +    ActionBuilderReturnCode +    getDeviceDependences(OffloadAction::DeviceDependences &DA, +                         phases::ID CurPhase, phases::ID FinalPhase, +                         PhasesTy &Phases) override { +      if (!IsActive) +        return ABRT_Inactive; + +      // If we don't have more CUDA actions, we don't have any dependences to +      // create for the host. +      if (CudaDeviceActions.empty()) +        return ABRT_Success; + +      assert(CudaDeviceActions.size() == GpuArchList.size() && +             "Expecting one action per GPU architecture."); +      assert(!CompileHostOnly && +             "Not expecting CUDA actions in host-only compilation."); + +      // If we are generating code for the device or we are in a backend phase, +      // we attempt to generate the fat binary. We compile each arch to ptx and +      // assemble to cubin, then feed the cubin *and* the ptx into a device +      // "link" action, which uses fatbinary to combine these cubins into one +      // fatbin.  The fatbin is then an input to the host action if not in +      // device-only mode. +      if (CompileDeviceOnly || CurPhase == phases::Backend) { +        ActionList DeviceActions; +        for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { +          // Produce the device action from the current phase up to the assemble +          // phase. +          for (auto Ph : Phases) { +            // Skip the phases that were already dealt with. +            if (Ph < CurPhase) +              continue; +            // We have to be consistent with the host final phase. +            if (Ph > FinalPhase) +              break; + +            CudaDeviceActions[I] = C.getDriver().ConstructPhaseAction( +                C, Args, Ph, CudaDeviceActions[I], Action::OFK_Cuda); + +            if (Ph == phases::Assemble) +              break; +          } + +          // If we didn't reach the assemble phase, we can't generate the fat +          // binary. We don't need to generate the fat binary if we are not in +          // device-only mode. +          if (!isa<AssembleJobAction>(CudaDeviceActions[I]) || +              CompileDeviceOnly) +            continue; + +          Action *AssembleAction = CudaDeviceActions[I]; +          assert(AssembleAction->getType() == types::TY_Object); +          assert(AssembleAction->getInputs().size() == 1); + +          Action *BackendAction = AssembleAction->getInputs()[0]; +          assert(BackendAction->getType() == types::TY_PP_Asm); + +          for (auto &A : {AssembleAction, BackendAction}) { +            OffloadAction::DeviceDependences DDep; +            DDep.add(*A, *ToolChains.front(), CudaArchToString(GpuArchList[I]), +                     Action::OFK_Cuda); +            DeviceActions.push_back( +                C.MakeAction<OffloadAction>(DDep, A->getType())); +          } +        } + +        // We generate the fat binary if we have device input actions. +        if (!DeviceActions.empty()) { +          CudaFatBinary = +              C.MakeAction<LinkJobAction>(DeviceActions, types::TY_CUDA_FATBIN); + +          if (!CompileDeviceOnly) { +            DA.add(*CudaFatBinary, *ToolChains.front(), /*BoundArch=*/nullptr, +                   Action::OFK_Cuda); +            // Clear the fat binary, it is already a dependence to an host +            // action. +            CudaFatBinary = nullptr; +          } + +          // Remove the CUDA actions as they are already connected to an host +          // action or fat binary. +          CudaDeviceActions.clear(); +        } + +        // We avoid creating host action in device-only mode. +        return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; +      } else if (CurPhase > phases::Backend) { +        // If we are past the backend phase and still have a device action, we +        // don't have to do anything as this action is already a device +        // top-level action. +        return ABRT_Success; +      } + +      assert(CurPhase < phases::Backend && "Generating single CUDA " +                                           "instructions should only occur " +                                           "before the backend phase!"); + +      // By default, we produce an action for each device arch. +      for (Action *&A : CudaDeviceActions) +        A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A); + +      return ABRT_Success; +    } +  }; +  /// \brief HIP action builder. It injects device code in the host backend +  /// action. +  class HIPActionBuilder final : public CudaActionBuilderBase { +    /// The linker inputs obtained for each device arch. +    SmallVector<ActionList, 8> DeviceLinkerInputs; + +  public: +    HIPActionBuilder(Compilation &C, DerivedArgList &Args, +                     const Driver::InputList &Inputs) +        : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) { +      DefaultCudaArch = CudaArch::GFX803; +    } + +    bool canUseBundlerUnbundler() const override { return true; } + +    ActionBuilderReturnCode +    getDeviceDependences(OffloadAction::DeviceDependences &DA, +                         phases::ID CurPhase, phases::ID FinalPhase, +                         PhasesTy &Phases) override { +      // amdgcn does not support linking of object files, therefore we skip +      // backend and assemble phases to output LLVM IR. Except for generating +      // non-relocatable device coee, where we generate fat binary for device +      // code and pass to host in Backend phase. +      if (CudaDeviceActions.empty() || +          (CurPhase == phases::Backend && Relocatable) || +          CurPhase == phases::Assemble) +        return ABRT_Success; + +      assert(((CurPhase == phases::Link && Relocatable) || +              CudaDeviceActions.size() == GpuArchList.size()) && +             "Expecting one action per GPU architecture."); +      assert(!CompileHostOnly && +             "Not expecting CUDA actions in host-only compilation."); + +      if (!Relocatable && CurPhase == phases::Backend && !EmitLLVM && +          !EmitAsm) { +        // If we are in backend phase, we attempt to generate the fat binary. +        // We compile each arch to IR and use a link action to generate code +        // object containing ISA. Then we use a special "link" action to create +        // a fat binary containing all the code objects for different GPU's. +        // The fat binary is then an input to the host action. +        for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { +          // Create a link action to link device IR with device library +          // and generate ISA. +          ActionList AL; +          AL.push_back(CudaDeviceActions[I]); +          CudaDeviceActions[I] = +              C.MakeAction<LinkJobAction>(AL, types::TY_Image); + +          // OffloadingActionBuilder propagates device arch until an offload +          // action. Since the next action for creating fatbin does +          // not have device arch, whereas the above link action and its input +          // have device arch, an offload action is needed to stop the null +          // device arch of the next action being propagated to the above link +          // action. +          OffloadAction::DeviceDependences DDep; +          DDep.add(*CudaDeviceActions[I], *ToolChains.front(), +                   CudaArchToString(GpuArchList[I]), AssociatedOffloadKind); +          CudaDeviceActions[I] = C.MakeAction<OffloadAction>( +              DDep, CudaDeviceActions[I]->getType()); +        } +        // Create HIP fat binary with a special "link" action. +        CudaFatBinary = +            C.MakeAction<LinkJobAction>(CudaDeviceActions, +                types::TY_HIP_FATBIN); + +        if (!CompileDeviceOnly) { +          DA.add(*CudaFatBinary, *ToolChains.front(), /*BoundArch=*/nullptr, +                 AssociatedOffloadKind); +          // Clear the fat binary, it is already a dependence to an host +          // action. +          CudaFatBinary = nullptr; +        } + +        // Remove the CUDA actions as they are already connected to an host +        // action or fat binary. +        CudaDeviceActions.clear(); + +        return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; +      } else if (CurPhase == phases::Link) { +        // Save CudaDeviceActions to DeviceLinkerInputs for each GPU subarch. +        // This happens to each device action originated from each input file. +        // Later on, device actions in DeviceLinkerInputs are used to create +        // device link actions in appendLinkDependences and the created device +        // link actions are passed to the offload action as device dependence. +        DeviceLinkerInputs.resize(CudaDeviceActions.size()); +        auto LI = DeviceLinkerInputs.begin(); +        for (auto *A : CudaDeviceActions) { +          LI->push_back(A); +          ++LI; +        } + +        // We will pass the device action as a host dependence, so we don't +        // need to do anything else with them. +        CudaDeviceActions.clear(); +        return ABRT_Success; +      } + +      // By default, we produce an action for each device arch. +      for (Action *&A : CudaDeviceActions) +        A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A, +                                               AssociatedOffloadKind); + +      return (CompileDeviceOnly && CurPhase == FinalPhase) ? ABRT_Ignore_Host +                                                           : ABRT_Success; +    } + +    void appendLinkDependences(OffloadAction::DeviceDependences &DA) override { +      // Append a new link action for each device. +      unsigned I = 0; +      for (auto &LI : DeviceLinkerInputs) { +        auto *DeviceLinkAction = +            C.MakeAction<LinkJobAction>(LI, types::TY_Image); +        DA.add(*DeviceLinkAction, *ToolChains[0], +               CudaArchToString(GpuArchList[I]), AssociatedOffloadKind); +        ++I; +      } +    } +  }; + +  /// OpenMP action builder. The host bitcode is passed to the device frontend +  /// and all the device linked images are passed to the host link phase. +  class OpenMPActionBuilder final : public DeviceActionBuilder { +    /// The OpenMP actions for the current input. +    ActionList OpenMPDeviceActions; + +    /// The linker inputs obtained for each toolchain. +    SmallVector<ActionList, 8> DeviceLinkerInputs; + +  public: +    OpenMPActionBuilder(Compilation &C, DerivedArgList &Args, +                        const Driver::InputList &Inputs) +        : DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {} + +    ActionBuilderReturnCode +    getDeviceDependences(OffloadAction::DeviceDependences &DA, +                         phases::ID CurPhase, phases::ID FinalPhase, +                         PhasesTy &Phases) override { +      if (OpenMPDeviceActions.empty()) +        return ABRT_Inactive; + +      // We should always have an action for each input. +      assert(OpenMPDeviceActions.size() == ToolChains.size() && +             "Number of OpenMP actions and toolchains do not match."); + +      // The host only depends on device action in the linking phase, when all +      // the device images have to be embedded in the host image. +      if (CurPhase == phases::Link) { +        assert(ToolChains.size() == DeviceLinkerInputs.size() && +               "Toolchains and linker inputs sizes do not match."); +        auto LI = DeviceLinkerInputs.begin(); +        for (auto *A : OpenMPDeviceActions) { +          LI->push_back(A); +          ++LI; +        } + +        // We passed the device action as a host dependence, so we don't need to +        // do anything else with them. +        OpenMPDeviceActions.clear(); +        return ABRT_Success; +      } + +      // By default, we produce an action for each device arch. +      for (Action *&A : OpenMPDeviceActions) +        A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A); + +      return ABRT_Success; +    } + +    ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { + +      // If this is an input action replicate it for each OpenMP toolchain. +      if (auto *IA = dyn_cast<InputAction>(HostAction)) { +        OpenMPDeviceActions.clear(); +        for (unsigned I = 0; I < ToolChains.size(); ++I) +          OpenMPDeviceActions.push_back( +              C.MakeAction<InputAction>(IA->getInputArg(), IA->getType())); +        return ABRT_Success; +      } + +      // If this is an unbundling action use it as is for each OpenMP toolchain. +      if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { +        OpenMPDeviceActions.clear(); +        auto *IA = cast<InputAction>(UA->getInputs().back()); +        std::string FileName = IA->getInputArg().getAsString(Args); +        // Check if the type of the file is the same as the action. Do not +        // unbundle it if it is not. Do not unbundle .so files, for example, +        // which are not object files. +        if (IA->getType() == types::TY_Object && +            (!llvm::sys::path::has_extension(FileName) || +             types::lookupTypeForExtension( +                 llvm::sys::path::extension(FileName).drop_front()) != +                 types::TY_Object)) +          return ABRT_Inactive; +        for (unsigned I = 0; I < ToolChains.size(); ++I) { +          OpenMPDeviceActions.push_back(UA); +          UA->registerDependentActionInfo( +              ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP); +        } +        return ABRT_Success; +      } + +      // When generating code for OpenMP we use the host compile phase result as +      // a dependence to the device compile phase so that it can learn what +      // declarations should be emitted. However, this is not the only use for +      // the host action, so we prevent it from being collapsed. +      if (isa<CompileJobAction>(HostAction)) { +        HostAction->setCannotBeCollapsedWithNextDependentAction(); +        assert(ToolChains.size() == OpenMPDeviceActions.size() && +               "Toolchains and device action sizes do not match."); +        OffloadAction::HostDependence HDep( +            *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), +            /*BoundArch=*/nullptr, Action::OFK_OpenMP); +        auto TC = ToolChains.begin(); +        for (Action *&A : OpenMPDeviceActions) { +          assert(isa<CompileJobAction>(A)); +          OffloadAction::DeviceDependences DDep; +          DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); +          A = C.MakeAction<OffloadAction>(HDep, DDep); +          ++TC; +        } +      } +      return ABRT_Success; +    } + +    void appendTopLevelActions(ActionList &AL) override { +      if (OpenMPDeviceActions.empty()) +        return; + +      // We should always have an action for each input. +      assert(OpenMPDeviceActions.size() == ToolChains.size() && +             "Number of OpenMP actions and toolchains do not match."); + +      // Append all device actions followed by the proper offload action. +      auto TI = ToolChains.begin(); +      for (auto *A : OpenMPDeviceActions) { +        OffloadAction::DeviceDependences Dep; +        Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP); +        AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); +        ++TI; +      } +      // We no longer need the action stored in this builder. +      OpenMPDeviceActions.clear(); +    } + +    void appendLinkActions(ActionList &AL) override { +      assert(ToolChains.size() == DeviceLinkerInputs.size() && +             "Toolchains and linker inputs sizes do not match."); + +      // Append a new link action for each device. +      auto TC = ToolChains.begin(); +      for (auto &LI : DeviceLinkerInputs) { +        auto *DeviceLinkAction = +            C.MakeAction<LinkJobAction>(LI, types::TY_Image); +        OffloadAction::DeviceDependences DeviceLinkDeps; +        DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr, +		        Action::OFK_OpenMP); +        AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps, +            DeviceLinkAction->getType())); +        ++TC; +      } +      DeviceLinkerInputs.clear(); +    } + +    void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} + +    bool initialize() override { +      // Get the OpenMP toolchains. If we don't get any, the action builder will +      // know there is nothing to do related to OpenMP offloading. +      auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); +      for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE; +           ++TI) +        ToolChains.push_back(TI->second); + +      DeviceLinkerInputs.resize(ToolChains.size()); +      return false; +    } + +    bool canUseBundlerUnbundler() const override { +      // OpenMP should use bundled files whenever possible. +      return true; +    } +  }; + +  /// +  /// TODO: Add the implementation for other specialized builders here. +  /// + +  /// Specialized builders being used by this offloading action builder. +  SmallVector<DeviceActionBuilder *, 4> SpecializedBuilders; + +  /// Flag set to true if all valid builders allow file bundling/unbundling. +  bool CanUseBundler; + +public: +  OffloadingActionBuilder(Compilation &C, DerivedArgList &Args, +                          const Driver::InputList &Inputs) +      : C(C) { +    // Create a specialized builder for each device toolchain. + +    IsValid = true; + +    // Create a specialized builder for CUDA. +    SpecializedBuilders.push_back(new CudaActionBuilder(C, Args, Inputs)); + +    // Create a specialized builder for HIP. +    SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs)); + +    // Create a specialized builder for OpenMP. +    SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs)); + +    // +    // TODO: Build other specialized builders here. +    // + +    // Initialize all the builders, keeping track of errors. If all valid +    // builders agree that we can use bundling, set the flag to true. +    unsigned ValidBuilders = 0u; +    unsigned ValidBuildersSupportingBundling = 0u; +    for (auto *SB : SpecializedBuilders) { +      IsValid = IsValid && !SB->initialize(); + +      // Update the counters if the builder is valid. +      if (SB->isValid()) { +        ++ValidBuilders; +        if (SB->canUseBundlerUnbundler()) +          ++ValidBuildersSupportingBundling; +      } +    } +    CanUseBundler = +        ValidBuilders && ValidBuilders == ValidBuildersSupportingBundling; +  } + +  ~OffloadingActionBuilder() { +    for (auto *SB : SpecializedBuilders) +      delete SB; +  } + +  /// Generate an action that adds device dependences (if any) to a host action. +  /// If no device dependence actions exist, just return the host action \a +  /// HostAction. If an error is found or if no builder requires the host action +  /// to be generated, return nullptr. +  Action * +  addDeviceDependencesToHostAction(Action *HostAction, const Arg *InputArg, +                                   phases::ID CurPhase, phases::ID FinalPhase, +                                   DeviceActionBuilder::PhasesTy &Phases) { +    if (!IsValid) +      return nullptr; + +    if (SpecializedBuilders.empty()) +      return HostAction; + +    assert(HostAction && "Invalid host action!"); + +    OffloadAction::DeviceDependences DDeps; +    // Check if all the programming models agree we should not emit the host +    // action. Also, keep track of the offloading kinds employed. +    auto &OffloadKind = InputArgToOffloadKindMap[InputArg]; +    unsigned InactiveBuilders = 0u; +    unsigned IgnoringBuilders = 0u; +    for (auto *SB : SpecializedBuilders) { +      if (!SB->isValid()) { +        ++InactiveBuilders; +        continue; +      } + +      auto RetCode = +          SB->getDeviceDependences(DDeps, CurPhase, FinalPhase, Phases); + +      // If the builder explicitly says the host action should be ignored, +      // we need to increment the variable that tracks the builders that request +      // the host object to be ignored. +      if (RetCode == DeviceActionBuilder::ABRT_Ignore_Host) +        ++IgnoringBuilders; + +      // Unless the builder was inactive for this action, we have to record the +      // offload kind because the host will have to use it. +      if (RetCode != DeviceActionBuilder::ABRT_Inactive) +        OffloadKind |= SB->getAssociatedOffloadKind(); +    } + +    // If all builders agree that the host object should be ignored, just return +    // nullptr. +    if (IgnoringBuilders && +        SpecializedBuilders.size() == (InactiveBuilders + IgnoringBuilders)) +      return nullptr; + +    if (DDeps.getActions().empty()) +      return HostAction; + +    // We have dependences we need to bundle together. We use an offload action +    // for that. +    OffloadAction::HostDependence HDep( +        *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), +        /*BoundArch=*/nullptr, DDeps); +    return C.MakeAction<OffloadAction>(HDep, DDeps); +  } + +  /// Generate an action that adds a host dependence to a device action. The +  /// results will be kept in this action builder. Return true if an error was +  /// found. +  bool addHostDependenceToDeviceActions(Action *&HostAction, +                                        const Arg *InputArg) { +    if (!IsValid) +      return true; + +    // If we are supporting bundling/unbundling and the current action is an +    // input action of non-source file, we replace the host action by the +    // unbundling action. The bundler tool has the logic to detect if an input +    // is a bundle or not and if the input is not a bundle it assumes it is a +    // host file. Therefore it is safe to create an unbundling action even if +    // the input is not a bundle. +    if (CanUseBundler && isa<InputAction>(HostAction) && +        InputArg->getOption().getKind() == llvm::opt::Option::InputClass && +        !types::isSrcFile(HostAction->getType())) { +      auto UnbundlingHostAction = +          C.MakeAction<OffloadUnbundlingJobAction>(HostAction); +      UnbundlingHostAction->registerDependentActionInfo( +          C.getSingleOffloadToolChain<Action::OFK_Host>(), +          /*BoundArch=*/StringRef(), Action::OFK_Host); +      HostAction = UnbundlingHostAction; +    } + +    assert(HostAction && "Invalid host action!"); + +    // Register the offload kinds that are used. +    auto &OffloadKind = InputArgToOffloadKindMap[InputArg]; +    for (auto *SB : SpecializedBuilders) { +      if (!SB->isValid()) +        continue; + +      auto RetCode = SB->addDeviceDepences(HostAction); + +      // Host dependences for device actions are not compatible with that same +      // action being ignored. +      assert(RetCode != DeviceActionBuilder::ABRT_Ignore_Host && +             "Host dependence not expected to be ignored.!"); + +      // Unless the builder was inactive for this action, we have to record the +      // offload kind because the host will have to use it. +      if (RetCode != DeviceActionBuilder::ABRT_Inactive) +        OffloadKind |= SB->getAssociatedOffloadKind(); +    } + +    // Do not use unbundler if the Host does not depend on device action. +    if (OffloadKind == Action::OFK_None && CanUseBundler) +      if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) +        HostAction = UA->getInputs().back(); + +    return false; +  } + +  /// Add the offloading top level actions to the provided action list. This +  /// function can replace the host action by a bundling action if the +  /// programming models allow it. +  bool appendTopLevelActions(ActionList &AL, Action *HostAction, +                             const Arg *InputArg) { +    // Get the device actions to be appended. +    ActionList OffloadAL; +    for (auto *SB : SpecializedBuilders) { +      if (!SB->isValid()) +        continue; +      SB->appendTopLevelActions(OffloadAL); +    } + +    // If we can use the bundler, replace the host action by the bundling one in +    // the resulting list. Otherwise, just append the device actions. For +    // device only compilation, HostAction is a null pointer, therefore only do +    // this when HostAction is not a null pointer. +    if (CanUseBundler && HostAction && +        HostAction->getType() != types::TY_Nothing && !OffloadAL.empty()) { +      // Add the host action to the list in order to create the bundling action. +      OffloadAL.push_back(HostAction); + +      // We expect that the host action was just appended to the action list +      // before this method was called. +      assert(HostAction == AL.back() && "Host action not in the list??"); +      HostAction = C.MakeAction<OffloadBundlingJobAction>(OffloadAL); +      AL.back() = HostAction; +    } else +      AL.append(OffloadAL.begin(), OffloadAL.end()); + +    // Propagate to the current host action (if any) the offload information +    // associated with the current input. +    if (HostAction) +      HostAction->propagateHostOffloadInfo(InputArgToOffloadKindMap[InputArg], +                                           /*BoundArch=*/nullptr); +    return false; +  } + +  Action* makeHostLinkAction() { +    // Build a list of device linking actions. +    ActionList DeviceAL; +    for (DeviceActionBuilder *SB : SpecializedBuilders) { +      if (!SB->isValid()) +        continue; +      SB->appendLinkActions(DeviceAL); +    } + +    if (DeviceAL.empty()) +      return nullptr; + +    // Create wrapper bitcode from the result of device link actions and compile +    // it to an object which will be added to the host link command. +    auto *BC = C.MakeAction<OffloadWrapperJobAction>(DeviceAL, types::TY_LLVM_BC); +    auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm); +    return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object); +  } + +  /// Processes the host linker action. This currently consists of replacing it +  /// with an offload action if there are device link objects and propagate to +  /// the host action all the offload kinds used in the current compilation. The +  /// resulting action is returned. +  Action *processHostLinkAction(Action *HostAction) { +    // Add all the dependences from the device linking actions. +    OffloadAction::DeviceDependences DDeps; +    for (auto *SB : SpecializedBuilders) { +      if (!SB->isValid()) +        continue; + +      SB->appendLinkDependences(DDeps); +    } + +    // Calculate all the offload kinds used in the current compilation. +    unsigned ActiveOffloadKinds = 0u; +    for (auto &I : InputArgToOffloadKindMap) +      ActiveOffloadKinds |= I.second; + +    // If we don't have device dependencies, we don't have to create an offload +    // action. +    if (DDeps.getActions().empty()) { +      // Propagate all the active kinds to host action. Given that it is a link +      // action it is assumed to depend on all actions generated so far. +      HostAction->propagateHostOffloadInfo(ActiveOffloadKinds, +                                           /*BoundArch=*/nullptr); +      return HostAction; +    } + +    // Create the offload action with all dependences. When an offload action +    // is created the kinds are propagated to the host action, so we don't have +    // to do that explicitly here. +    OffloadAction::HostDependence HDep( +        *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), +        /*BoundArch*/ nullptr, ActiveOffloadKinds); +    return C.MakeAction<OffloadAction>(HDep, DDeps); +  } +}; +} // anonymous namespace. + +void Driver::handleArguments(Compilation &C, DerivedArgList &Args, +                             const InputList &Inputs, +                             ActionList &Actions) const { + +  // Ignore /Yc/Yu if both /Yc and /Yu passed but with different filenames. +  Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); +  Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); +  if (YcArg && YuArg && strcmp(YcArg->getValue(), YuArg->getValue()) != 0) { +    Diag(clang::diag::warn_drv_ycyu_different_arg_clang_cl); +    Args.eraseArg(options::OPT__SLASH_Yc); +    Args.eraseArg(options::OPT__SLASH_Yu); +    YcArg = YuArg = nullptr; +  } +  if (YcArg && Inputs.size() > 1) { +    Diag(clang::diag::warn_drv_yc_multiple_inputs_clang_cl); +    Args.eraseArg(options::OPT__SLASH_Yc); +    YcArg = nullptr; +  } + +  Arg *FinalPhaseArg; +  phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); + +  if (FinalPhase == phases::Link) { +    if (Args.hasArg(options::OPT_emit_llvm)) +      Diag(clang::diag::err_drv_emit_llvm_link); +    if (IsCLMode() && LTOMode != LTOK_None && +        !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld")) +      Diag(clang::diag::err_drv_lto_without_lld); +  } + +  if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { +    // If only preprocessing or /Y- is used, all pch handling is disabled. +    // Rather than check for it everywhere, just remove clang-cl pch-related +    // flags here. +    Args.eraseArg(options::OPT__SLASH_Fp); +    Args.eraseArg(options::OPT__SLASH_Yc); +    Args.eraseArg(options::OPT__SLASH_Yu); +    YcArg = YuArg = nullptr; +  } + +  unsigned LastPLSize = 0; +  for (auto &I : Inputs) { +    types::ID InputType = I.first; +    const Arg *InputArg = I.second; + +    llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; +    types::getCompilationPhases(InputType, PL); +    LastPLSize = PL.size(); + +    // 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 = PL[0]; +    if (InitialPhase > FinalPhase) { +      if (InputArg->isClaimed()) +        continue; + +      // Claim here to avoid the more general unused warning. +      InputArg->claim(); + +      // Suppress all unused style warnings with -Qunused-arguments +      if (Args.hasArg(options::OPT_Qunused_arguments)) +        continue; + +      // Special case when final phase determined by binary name, rather than +      // by a command-line argument with a corresponding Arg. +      if (CCCIsCPP()) +        Diag(clang::diag::warn_drv_input_file_unused_by_cpp) +            << InputArg->getAsString(Args) << getPhaseName(InitialPhase); +      // Special case '-E' warning on a previously preprocessed file to make +      // more sense. +      else if (InitialPhase == phases::Compile && +               (Args.getLastArg(options::OPT__SLASH_EP, +                                options::OPT__SLASH_P) || +                Args.getLastArg(options::OPT_E) || +                Args.getLastArg(options::OPT_M, options::OPT_MM)) && +               getPreprocessedType(InputType) == types::TY_INVALID) +        Diag(clang::diag::warn_drv_preprocessed_input_file_unused) +            << InputArg->getAsString(Args) << !!FinalPhaseArg +            << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); +      else +        Diag(clang::diag::warn_drv_input_file_unused) +            << InputArg->getAsString(Args) << getPhaseName(InitialPhase) +            << !!FinalPhaseArg +            << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); +      continue; +    } + +    if (YcArg) { +      // Add a separate precompile phase for the compile phase. +      if (FinalPhase >= phases::Compile) { +        const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); +        llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL; +        types::getCompilationPhases(HeaderType, PCHPL); +        // Build the pipeline for the pch file. +        Action *ClangClPch = C.MakeAction<InputAction>(*InputArg, HeaderType); +        for (phases::ID Phase : PCHPL) +          ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); +        assert(ClangClPch); +        Actions.push_back(ClangClPch); +        // The driver currently exits after the first failed command.  This +        // relies on that behavior, to make sure if the pch generation fails, +        // the main compilation won't run. +        // FIXME: If the main compilation fails, the PCH generation should +        // probably not be considered successful either. +      } +    } +  } + +  // If we are linking, claim any options which are obviously only used for +  // compilation. +  // FIXME: Understand why the last Phase List length is used here. +  if (FinalPhase == phases::Link && LastPLSize == 1) { +    Args.ClaimAllArgs(options::OPT_CompileOnly_Group); +    Args.ClaimAllArgs(options::OPT_cl_compile_Group); +  } +} + +void Driver::BuildActions(Compilation &C, DerivedArgList &Args, +                          const InputList &Inputs, ActionList &Actions) const { +  llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); + +  if (!SuppressMissingInputWarning && Inputs.empty()) { +    Diag(clang::diag::err_drv_no_input_files); +    return; +  } + +  // Reject -Z* at the top level, these options should never have been exposed +  // by gcc. +  if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) +    Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); + +  // Diagnose misuse of /Fo. +  if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) { +    StringRef V = A->getValue(); +    if (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; +      Args.eraseArg(options::OPT__SLASH_Fo); +    } +  } + +  // Diagnose misuse of /Fa. +  if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) { +    StringRef V = A->getValue(); +    if (Inputs.size() > 1 && !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; +      Args.eraseArg(options::OPT__SLASH_Fa); +    } +  } + +  // 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_o); +    } +  } + +  handleArguments(C, Args, Inputs, Actions); + +  // Builder to be used to build offloading actions. +  OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); + +  // Construct the actions to perform. +  HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; +  ActionList LinkerInputs; +  ActionList MergerInputs; + +  for (auto &I : Inputs) { +    types::ID InputType = I.first; +    const Arg *InputArg = I.second; + +    llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; +    types::getCompilationPhases(*this, Args, InputType, PL); +    if (PL.empty()) +      continue; + +    llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> FullPL; +    types::getCompilationPhases(InputType, FullPL); + +    // Build the pipeline for this file. +    Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); + +    // Use the current host action in any of the offloading actions, if +    // required. +    if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) +      break; + +    for (phases::ID Phase : PL) { + +      // Add any offload action the host action depends on. +      Current = OffloadBuilder.addDeviceDependencesToHostAction( +          Current, InputArg, Phase, PL.back(), FullPL); +      if (!Current) +        break; + +      // Queue linker inputs. +      if (Phase == phases::Link) { +        assert(Phase == PL.back() && "linking must be final compilation step."); +        LinkerInputs.push_back(Current); +        Current = nullptr; +        break; +      } + +      // TODO: Consider removing this because the merged may not end up being +      // the final Phase in the pipeline. Perhaps the merged could just merge +      // and then pass an artifact of some sort to the Link Phase. +      // Queue merger inputs. +      if (Phase == phases::IfsMerge) { +        assert(Phase == PL.back() && "merging must be final compilation step."); +        MergerInputs.push_back(Current); +        Current = nullptr; +        break; +      } + +      // Each precompiled header file after a module file action is a module +      // header of that same module file, rather than being compiled to a +      // separate PCH. +      if (Phase == phases::Precompile && HeaderModuleAction && +          getPrecompiledType(InputType) == types::TY_PCH) { +        HeaderModuleAction->addModuleHeaderInput(Current); +        Current = nullptr; +        break; +      } + +      // FIXME: Should we include any prior module file outputs as inputs of +      // later actions in the same command line? + +      // Otherwise construct the appropriate action. +      Action *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current); + +      // We didn't create a new action, so we will just move to the next phase. +      if (NewCurrent == Current) +        continue; + +      if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent)) +        HeaderModuleAction = HMA; + +      Current = NewCurrent; + +      // Use the current host action in any of the offloading actions, if +      // required. +      if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) +        break; + +      if (Current->getType() == types::TY_Nothing) +        break; +    } + +    // If we ended with something, add to the output list. +    if (Current) +      Actions.push_back(Current); + +    // Add any top level actions generated for offloading. +    OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg); +  } + +  // Add a link action if necessary. +  if (!LinkerInputs.empty()) { +    if (Action *Wrapper = OffloadBuilder.makeHostLinkAction()) +      LinkerInputs.push_back(Wrapper); +    Action *LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image); +    LA = OffloadBuilder.processHostLinkAction(LA); +    Actions.push_back(LA); +  } + +  // Add an interface stubs merge action if necessary. +  if (!MergerInputs.empty()) +    Actions.push_back( +        C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + +  // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom +  // Compile phase that prints out supported cpu models and quits. +  if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { +    // Use the -mcpu=? flag as the dummy input to cc1. +    Actions.clear(); +    Action *InputAc = C.MakeAction<InputAction>(*A, types::TY_C); +    Actions.push_back( +        C.MakeAction<PrecompileJobAction>(InputAc, types::TY_Nothing)); +    for (auto &I : Inputs) +      I.second->claim(); +  } + +  // Claim ignored clang-cl options. +  Args.ClaimAllArgs(options::OPT_cl_ignored_Group); + +  // Claim --cuda-host-only and --cuda-compile-host-device, which may be passed +  // to non-CUDA compilations and should not trigger warnings there. +  Args.ClaimAllArgs(options::OPT_cuda_host_only); +  Args.ClaimAllArgs(options::OPT_cuda_compile_host_device); +} + +Action *Driver::ConstructPhaseAction( +    Compilation &C, const ArgList &Args, phases::ID Phase, Action *Input, +    Action::OffloadKind TargetDeviceOffloadKind) const { +  llvm::PrettyStackTraceString CrashInfo("Constructing phase actions"); + +  // Some types skip the assembler phase (e.g., llvm-bc), but we can't +  // encode this in the steps because the intermediate type depends on +  // arguments. Just special case here. +  if (Phase == phases::Assemble && Input->getType() != types::TY_PP_Asm) +    return Input; + +  // Build the appropriate action. +  switch (Phase) { +  case phases::Link: +    llvm_unreachable("link action invalid here."); +  case phases::IfsMerge: +    llvm_unreachable("ifsmerge action invalid here."); +  case phases::Preprocess: { +    types::ID OutputTy; +    // -M and -MM specify the dependency file name by altering the output type, +    // -if -MD and -MMD are not specified. +    if (Args.hasArg(options::OPT_M, options::OPT_MM) && +        !Args.hasArg(options::OPT_MD, options::OPT_MMD)) { +      OutputTy = types::TY_Dependencies; +    } else { +      OutputTy = Input->getType(); +      if (!Args.hasFlag(options::OPT_frewrite_includes, +                        options::OPT_fno_rewrite_includes, false) && +          !Args.hasFlag(options::OPT_frewrite_imports, +                        options::OPT_fno_rewrite_imports, false) && +          !CCGenDiagnostics) +        OutputTy = types::getPreprocessedType(OutputTy); +      assert(OutputTy != types::TY_INVALID && +             "Cannot preprocess this input type!"); +    } +    return C.MakeAction<PreprocessJobAction>(Input, OutputTy); +  } +  case phases::Precompile: { +    types::ID OutputTy = getPrecompiledType(Input->getType()); +    assert(OutputTy != types::TY_INVALID && +           "Cannot precompile this input type!"); + +    // If we're given a module name, precompile header file inputs as a +    // module, not as a precompiled header. +    const char *ModName = nullptr; +    if (OutputTy == types::TY_PCH) { +      if (Arg *A = Args.getLastArg(options::OPT_fmodule_name_EQ)) +        ModName = A->getValue(); +      if (ModName) +        OutputTy = types::TY_ModuleFile; +    } + +    if (Args.hasArg(options::OPT_fsyntax_only)) { +      // Syntax checks should not emit a PCH file +      OutputTy = types::TY_Nothing; +    } + +    if (ModName) +      return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy, +                                                           ModName); +    return C.MakeAction<PrecompileJobAction>(Input, OutputTy); +  } +  case phases::Compile: { +    if (Args.hasArg(options::OPT_fsyntax_only)) +      return C.MakeAction<CompileJobAction>(Input, types::TY_Nothing); +    if (Args.hasArg(options::OPT_rewrite_objc)) +      return C.MakeAction<CompileJobAction>(Input, types::TY_RewrittenObjC); +    if (Args.hasArg(options::OPT_rewrite_legacy_objc)) +      return C.MakeAction<CompileJobAction>(Input, +                                            types::TY_RewrittenLegacyObjC); +    if (Args.hasArg(options::OPT__analyze)) +      return C.MakeAction<AnalyzeJobAction>(Input, types::TY_Plist); +    if (Args.hasArg(options::OPT__migrate)) +      return C.MakeAction<MigrateJobAction>(Input, types::TY_Remap); +    if (Args.hasArg(options::OPT_emit_ast)) +      return C.MakeAction<CompileJobAction>(Input, types::TY_AST); +    if (Args.hasArg(options::OPT_module_file_info)) +      return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); +    if (Args.hasArg(options::OPT_verify_pch)) +      return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); +    if (Args.hasArg(options::OPT_emit_interface_stubs)) +      return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP); +    return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); +  } +  case phases::Backend: { +    if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) { +      types::ID Output = +          Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; +      return C.MakeAction<BackendJobAction>(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 C.MakeAction<BackendJobAction>(Input, Output); +    } +    return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm); +  } +  case phases::Assemble: +    return C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object); +  } + +  llvm_unreachable("invalid phase in ConstructPhaseAction"); +} + +void Driver::BuildJobs(Compilation &C) const { +  llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); + +  Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); + +  // It is an error to provide a -o option if we are making multiple output +  // files. +  if (FinalOutput) { +    unsigned NumOutputs = 0; +    for (const Action *A : C.getActions()) +      if (A->getType() != types::TY_Nothing) +        ++NumOutputs; + +    if (NumOutputs > 1) { +      Diag(clang::diag::err_drv_output_argument_with_multiple_files); +      FinalOutput = nullptr; +    } +  } + +  // Collect the list of architectures. +  llvm::StringSet<> ArchNames; +  if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO()) +    for (const Arg *A : C.getArgs()) +      if (A->getOption().matches(options::OPT_arch)) +        ArchNames.insert(A->getValue()); + +  // Set of (Action, canonical ToolChain triple) pairs we've built jobs for. +  std::map<std::pair<const Action *, std::string>, InputInfo> CachedResults; +  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. +    // +    // FIXME: This is a hack; find a cleaner way to integrate this into the +    // process. +    const char *LinkingOutput = nullptr; +    if (isa<LipoJobAction>(A)) { +      if (FinalOutput) +        LinkingOutput = FinalOutput->getValue(); +      else +        LinkingOutput = getDefaultImageName(); +    } + +    BuildJobsForAction(C, A, &C.getDefaultToolChain(), +                       /*BoundArch*/ StringRef(), +                       /*AtTopLevel*/ true, +                       /*MultipleArchs*/ ArchNames.size() > 1, +                       /*LinkingOutput*/ LinkingOutput, CachedResults, +                       /*TargetDeviceOffloadKind*/ Action::OFK_None); +  } + +  // If the user passed -Qunused-arguments or there were errors, don't warn +  // about any unused arguments. +  if (Diags.hasErrorOccurred() || +      C.getArgs().hasArg(options::OPT_Qunused_arguments)) +    return; + +  // Claim -### here. +  (void)C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); + +  // Claim --driver-mode, --rsp-quoting, it was handled earlier. +  (void)C.getArgs().hasArg(options::OPT_driver_mode); +  (void)C.getArgs().hasArg(options::OPT_rsp_quoting); + +  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. +    if (!A->isClaimed()) { +      if (A->getOption().hasFlag(options::NoArgumentUnused)) +        continue; + +      // Suppress the warning automatically if this is just a flag, and it is an +      // instance of an argument we already claimed. +      const Option &Opt = A->getOption(); +      if (Opt.getKind() == Option::FlagClass) { +        bool DuplicateClaimed = false; + +        for (const Arg *AA : C.getArgs().filtered(&Opt)) { +          if (AA->isClaimed()) { +            DuplicateClaimed = true; +            break; +          } +        } + +        if (DuplicateClaimed) +          continue; +      } + +      // In clang-cl, don't mention unknown arguments here since they have +      // already been warned about. +      if (!IsCLMode() || !A->getOption().matches(options::OPT_UNKNOWN)) +        Diag(clang::diag::warn_drv_unused_argument) +            << A->getAsString(C.getArgs()); +    } +  } +} + +namespace { +/// Utility class to control the collapse of dependent actions and select the +/// tools accordingly. +class ToolSelector final { +  /// The tool chain this selector refers to. +  const ToolChain &TC; + +  /// The compilation this selector refers to. +  const Compilation &C; + +  /// The base action this selector refers to. +  const JobAction *BaseAction; + +  /// Set to true if the current toolchain refers to host actions. +  bool IsHostSelector; + +  /// Set to true if save-temps and embed-bitcode functionalities are active. +  bool SaveTemps; +  bool EmbedBitcode; + +  /// Get previous dependent action or null if that does not exist. If +  /// \a CanBeCollapsed is false, that action must be legal to collapse or +  /// null will be returned. +  const JobAction *getPrevDependentAction(const ActionList &Inputs, +                                          ActionList &SavedOffloadAction, +                                          bool CanBeCollapsed = true) { +    // An option can be collapsed only if it has a single input. +    if (Inputs.size() != 1) +      return nullptr; + +    Action *CurAction = *Inputs.begin(); +    if (CanBeCollapsed && +        !CurAction->isCollapsingWithNextDependentActionLegal()) +      return nullptr; + +    // If the input action is an offload action. Look through it and save any +    // offload action that can be dropped in the event of a collapse. +    if (auto *OA = dyn_cast<OffloadAction>(CurAction)) { +      // If the dependent action is a device action, we will attempt to collapse +      // only with other device actions. Otherwise, we would do the same but +      // with host actions only. +      if (!IsHostSelector) { +        if (OA->hasSingleDeviceDependence(/*DoNotConsiderHostActions=*/true)) { +          CurAction = +              OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true); +          if (CanBeCollapsed && +              !CurAction->isCollapsingWithNextDependentActionLegal()) +            return nullptr; +          SavedOffloadAction.push_back(OA); +          return dyn_cast<JobAction>(CurAction); +        } +      } else if (OA->hasHostDependence()) { +        CurAction = OA->getHostDependence(); +        if (CanBeCollapsed && +            !CurAction->isCollapsingWithNextDependentActionLegal()) +          return nullptr; +        SavedOffloadAction.push_back(OA); +        return dyn_cast<JobAction>(CurAction); +      } +      return nullptr; +    } + +    return dyn_cast<JobAction>(CurAction); +  } + +  /// Return true if an assemble action can be collapsed. +  bool canCollapseAssembleAction() const { +    return TC.useIntegratedAs() && !SaveTemps && +           !C.getArgs().hasArg(options::OPT_via_file_asm) && +           !C.getArgs().hasArg(options::OPT__SLASH_FA) && +           !C.getArgs().hasArg(options::OPT__SLASH_Fa); +  } + +  /// Return true if a preprocessor action can be collapsed. +  bool canCollapsePreprocessorAction() const { +    return !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && +           !C.getArgs().hasArg(options::OPT_traditional_cpp) && !SaveTemps && +           !C.getArgs().hasArg(options::OPT_rewrite_objc); +  } + +  /// Struct that relates an action with the offload actions that would be +  /// collapsed with it. +  struct JobActionInfo final { +    /// The action this info refers to. +    const JobAction *JA = nullptr; +    /// The offload actions we need to take care off if this action is +    /// collapsed. +    ActionList SavedOffloadAction; +  }; + +  /// Append collapsed offload actions from the give nnumber of elements in the +  /// action info array. +  static void AppendCollapsedOffloadAction(ActionList &CollapsedOffloadAction, +                                           ArrayRef<JobActionInfo> &ActionInfo, +                                           unsigned ElementNum) { +    assert(ElementNum <= ActionInfo.size() && "Invalid number of elements."); +    for (unsigned I = 0; I < ElementNum; ++I) +      CollapsedOffloadAction.append(ActionInfo[I].SavedOffloadAction.begin(), +                                    ActionInfo[I].SavedOffloadAction.end()); +  } + +  /// Functions that attempt to perform the combining. They detect if that is +  /// legal, and if so they update the inputs \a Inputs and the offload action +  /// that were collapsed in \a CollapsedOffloadAction. A tool that deals with +  /// the combined action is returned. If the combining is not legal or if the +  /// tool does not exist, null is returned. +  /// Currently three kinds of collapsing are supported: +  ///  - Assemble + Backend + Compile; +  ///  - Assemble + Backend ; +  ///  - Backend + Compile. +  const Tool * +  combineAssembleBackendCompile(ArrayRef<JobActionInfo> ActionInfo, +                                ActionList &Inputs, +                                ActionList &CollapsedOffloadAction) { +    if (ActionInfo.size() < 3 || !canCollapseAssembleAction()) +      return nullptr; +    auto *AJ = dyn_cast<AssembleJobAction>(ActionInfo[0].JA); +    auto *BJ = dyn_cast<BackendJobAction>(ActionInfo[1].JA); +    auto *CJ = dyn_cast<CompileJobAction>(ActionInfo[2].JA); +    if (!AJ || !BJ || !CJ) +      return nullptr; + +    // Get compiler tool. +    const Tool *T = TC.SelectTool(*CJ); +    if (!T) +      return nullptr; + +    // When using -fembed-bitcode, it is required to have the same tool (clang) +    // for both CompilerJA and BackendJA. Otherwise, combine two stages. +    if (EmbedBitcode) { +      const Tool *BT = TC.SelectTool(*BJ); +      if (BT == T) +        return nullptr; +    } + +    if (!T->hasIntegratedAssembler()) +      return nullptr; + +    Inputs = CJ->getInputs(); +    AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, +                                 /*NumElements=*/3); +    return T; +  } +  const Tool *combineAssembleBackend(ArrayRef<JobActionInfo> ActionInfo, +                                     ActionList &Inputs, +                                     ActionList &CollapsedOffloadAction) { +    if (ActionInfo.size() < 2 || !canCollapseAssembleAction()) +      return nullptr; +    auto *AJ = dyn_cast<AssembleJobAction>(ActionInfo[0].JA); +    auto *BJ = dyn_cast<BackendJobAction>(ActionInfo[1].JA); +    if (!AJ || !BJ) +      return nullptr; + +    // Get backend tool. +    const Tool *T = TC.SelectTool(*BJ); +    if (!T) +      return nullptr; + +    if (!T->hasIntegratedAssembler()) +      return nullptr; + +    Inputs = BJ->getInputs(); +    AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, +                                 /*NumElements=*/2); +    return T; +  } +  const Tool *combineBackendCompile(ArrayRef<JobActionInfo> ActionInfo, +                                    ActionList &Inputs, +                                    ActionList &CollapsedOffloadAction) { +    if (ActionInfo.size() < 2) +      return nullptr; +    auto *BJ = dyn_cast<BackendJobAction>(ActionInfo[0].JA); +    auto *CJ = dyn_cast<CompileJobAction>(ActionInfo[1].JA); +    if (!BJ || !CJ) +      return nullptr; + +    // Check if the initial input (to the compile job or its predessor if one +    // exists) is LLVM bitcode. In that case, no preprocessor step is required +    // and we can still collapse the compile and backend jobs when we have +    // -save-temps. I.e. there is no need for a separate compile job just to +    // emit unoptimized bitcode. +    bool InputIsBitcode = true; +    for (size_t i = 1; i < ActionInfo.size(); i++) +      if (ActionInfo[i].JA->getType() != types::TY_LLVM_BC && +          ActionInfo[i].JA->getType() != types::TY_LTO_BC) { +        InputIsBitcode = false; +        break; +      } +    if (!InputIsBitcode && !canCollapsePreprocessorAction()) +      return nullptr; + +    // Get compiler tool. +    const Tool *T = TC.SelectTool(*CJ); +    if (!T) +      return nullptr; + +    if (T->canEmitIR() && ((SaveTemps && !InputIsBitcode) || EmbedBitcode)) +      return nullptr; + +    Inputs = CJ->getInputs(); +    AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo, +                                 /*NumElements=*/2); +    return T; +  } + +  /// Updates the inputs if the obtained tool supports combining with +  /// preprocessor action, and the current input is indeed a preprocessor +  /// action. If combining results in the collapse of offloading actions, those +  /// are appended to \a CollapsedOffloadAction. +  void combineWithPreprocessor(const Tool *T, ActionList &Inputs, +                               ActionList &CollapsedOffloadAction) { +    if (!T || !canCollapsePreprocessorAction() || !T->hasIntegratedCPP()) +      return; + +    // Attempt to get a preprocessor action dependence. +    ActionList PreprocessJobOffloadActions; +    ActionList NewInputs; +    for (Action *A : Inputs) { +      auto *PJ = getPrevDependentAction({A}, PreprocessJobOffloadActions); +      if (!PJ || !isa<PreprocessJobAction>(PJ)) { +        NewInputs.push_back(A); +        continue; +      } + +      // This is legal to combine. Append any offload action we found and add the +      // current input to preprocessor inputs. +      CollapsedOffloadAction.append(PreprocessJobOffloadActions.begin(), +                                    PreprocessJobOffloadActions.end()); +      NewInputs.append(PJ->input_begin(), PJ->input_end()); +    } +    Inputs = NewInputs; +  } + +public: +  ToolSelector(const JobAction *BaseAction, const ToolChain &TC, +               const Compilation &C, bool SaveTemps, bool EmbedBitcode) +      : TC(TC), C(C), BaseAction(BaseAction), SaveTemps(SaveTemps), +        EmbedBitcode(EmbedBitcode) { +    assert(BaseAction && "Invalid base action."); +    IsHostSelector = BaseAction->getOffloadingDeviceKind() == Action::OFK_None; +  } + +  /// Check if a chain of actions can be combined and return the tool that can +  /// handle the combination of actions. The pointer to the current inputs \a +  /// Inputs and the list of offload actions \a CollapsedOffloadActions +  /// connected to collapsed actions are updated accordingly. The latter enables +  /// the caller of the selector to process them afterwards instead of just +  /// dropping them. If no suitable tool is found, null will be returned. +  const Tool *getTool(ActionList &Inputs, +                      ActionList &CollapsedOffloadAction) { +    // +    // Get the largest chain of actions that we could combine. +    // + +    SmallVector<JobActionInfo, 5> ActionChain(1); +    ActionChain.back().JA = BaseAction; +    while (ActionChain.back().JA) { +      const Action *CurAction = ActionChain.back().JA; + +      // Grow the chain by one element. +      ActionChain.resize(ActionChain.size() + 1); +      JobActionInfo &AI = ActionChain.back(); + +      // Attempt to fill it with the +      AI.JA = +          getPrevDependentAction(CurAction->getInputs(), AI.SavedOffloadAction); +    } + +    // Pop the last action info as it could not be filled. +    ActionChain.pop_back(); + +    // +    // Attempt to combine actions. If all combining attempts failed, just return +    // the tool of the provided action. At the end we attempt to combine the +    // action with any preprocessor action it may depend on. +    // + +    const Tool *T = combineAssembleBackendCompile(ActionChain, Inputs, +                                                  CollapsedOffloadAction); +    if (!T) +      T = combineAssembleBackend(ActionChain, Inputs, CollapsedOffloadAction); +    if (!T) +      T = combineBackendCompile(ActionChain, Inputs, CollapsedOffloadAction); +    if (!T) { +      Inputs = BaseAction->getInputs(); +      T = TC.SelectTool(*BaseAction); +    } + +    combineWithPreprocessor(T, Inputs, CollapsedOffloadAction); +    return T; +  } +}; +} + +/// Return a string that uniquely identifies the result of a job. The bound arch +/// is not necessarily represented in the toolchain's triple -- for example, +/// armv7 and armv7s both map to the same triple -- so we need both in our map. +/// Also, we need to add the offloading device kind, as the same tool chain can +/// be used for host and device for some programming models, e.g. OpenMP. +static std::string GetTriplePlusArchString(const ToolChain *TC, +                                           StringRef BoundArch, +                                           Action::OffloadKind OffloadKind) { +  std::string TriplePlusArch = TC->getTriple().normalize(); +  if (!BoundArch.empty()) { +    TriplePlusArch += "-"; +    TriplePlusArch += BoundArch; +  } +  TriplePlusArch += "-"; +  TriplePlusArch += Action::GetOffloadKindName(OffloadKind); +  return TriplePlusArch; +} + +InputInfo Driver::BuildJobsForAction( +    Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, +    bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, +    std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, +    Action::OffloadKind TargetDeviceOffloadKind) const { +  std::pair<const Action *, std::string> ActionTC = { +      A, GetTriplePlusArchString(TC, BoundArch, TargetDeviceOffloadKind)}; +  auto CachedResult = CachedResults.find(ActionTC); +  if (CachedResult != CachedResults.end()) { +    return CachedResult->second; +  } +  InputInfo Result = BuildJobsForActionNoCache( +      C, A, TC, BoundArch, AtTopLevel, MultipleArchs, LinkingOutput, +      CachedResults, TargetDeviceOffloadKind); +  CachedResults[ActionTC] = Result; +  return Result; +} + +InputInfo Driver::BuildJobsForActionNoCache( +    Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, +    bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, +    std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, +    Action::OffloadKind TargetDeviceOffloadKind) const { +  llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); + +  InputInfoList OffloadDependencesInputInfo; +  bool BuildingForOffloadDevice = TargetDeviceOffloadKind != Action::OFK_None; +  if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) { +    // The 'Darwin' toolchain is initialized only when its arguments are +    // computed. Get the default arguments for OFK_None to ensure that +    // initialization is performed before processing the offload action. +    // FIXME: Remove when darwin's toolchain is initialized during construction. +    C.getArgsForToolChain(TC, BoundArch, Action::OFK_None); + +    // The offload action is expected to be used in four different situations. +    // +    // a) Set a toolchain/architecture/kind for a host action: +    //    Host Action 1 -> OffloadAction -> Host Action 2 +    // +    // b) Set a toolchain/architecture/kind for a device action; +    //    Device Action 1 -> OffloadAction -> Device Action 2 +    // +    // c) Specify a device dependence to a host action; +    //    Device Action 1  _ +    //                      \ +    //      Host Action 1  ---> OffloadAction -> Host Action 2 +    // +    // d) Specify a host dependence to a device action. +    //      Host Action 1  _ +    //                      \ +    //    Device Action 1  ---> OffloadAction -> Device Action 2 +    // +    // For a) and b), we just return the job generated for the dependence. For +    // c) and d) we override the current action with the host/device dependence +    // if the current toolchain is host/device and set the offload dependences +    // info with the jobs obtained from the device/host dependence(s). + +    // If there is a single device option, just generate the job for it. +    if (OA->hasSingleDeviceDependence()) { +      InputInfo DevA; +      OA->doOnEachDeviceDependence([&](Action *DepA, const ToolChain *DepTC, +                                       const char *DepBoundArch) { +        DevA = +            BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel, +                               /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, +                               CachedResults, DepA->getOffloadingDeviceKind()); +      }); +      return DevA; +    } + +    // If 'Action 2' is host, we generate jobs for the device dependences and +    // override the current action with the host dependence. Otherwise, we +    // generate the host dependences and override the action with the device +    // dependence. The dependences can't therefore be a top-level action. +    OA->doOnEachDependence( +        /*IsHostDependence=*/BuildingForOffloadDevice, +        [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { +          OffloadDependencesInputInfo.push_back(BuildJobsForAction( +              C, DepA, DepTC, DepBoundArch, /*AtTopLevel=*/false, +              /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, CachedResults, +              DepA->getOffloadingDeviceKind())); +        }); + +    A = BuildingForOffloadDevice +            ? OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true) +            : OA->getHostDependence(); +  } + +  if (const InputAction *IA = dyn_cast<InputAction>(A)) { +    // FIXME: It would be nice to not claim this here; maybe the old scheme of +    // just using Args was better? +    const Arg &Input = IA->getInputArg(); +    Input.claim(); +    if (Input.getOption().matches(options::OPT_INPUT)) { +      const char *Name = Input.getValue(); +      return InputInfo(A, Name, /* _BaseInput = */ Name); +    } +    return InputInfo(A, &Input, /* _BaseInput = */ ""); +  } + +  if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) { +    const ToolChain *TC; +    StringRef ArchName = BAA->getArchName(); + +    if (!ArchName.empty()) +      TC = &getToolChain(C.getArgs(), +                         computeTargetTriple(*this, TargetTriple, +                                             C.getArgs(), ArchName)); +    else +      TC = &C.getDefaultToolChain(); + +    return BuildJobsForAction(C, *BAA->input_begin(), TC, ArchName, AtTopLevel, +                              MultipleArchs, LinkingOutput, CachedResults, +                              TargetDeviceOffloadKind); +  } + + +  ActionList Inputs = A->getInputs(); + +  const JobAction *JA = cast<JobAction>(A); +  ActionList CollapsedOffloadActions; + +  ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(), +                  embedBitcodeInObject() && !isUsingLTO()); +  const Tool *T = TS.getTool(Inputs, CollapsedOffloadActions); + +  if (!T) +    return InputInfo(); + +  // If we've collapsed action list that contained OffloadAction we +  // need to build jobs for host/device-side inputs it may have held. +  for (const auto *OA : CollapsedOffloadActions) +    cast<OffloadAction>(OA)->doOnEachDependence( +        /*IsHostDependence=*/BuildingForOffloadDevice, +        [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { +          OffloadDependencesInputInfo.push_back(BuildJobsForAction( +              C, DepA, DepTC, DepBoundArch, /* AtTopLevel */ false, +              /*MultipleArchs=*/!!DepBoundArch, LinkingOutput, CachedResults, +              DepA->getOffloadingDeviceKind())); +        }); + +  // Only use pipes when there is exactly one input. +  InputInfoList InputInfos; +  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. +    bool SubJobAtTopLevel = +        AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)); +    InputInfos.push_back(BuildJobsForAction( +        C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, LinkingOutput, +        CachedResults, A->getOffloadingDeviceKind())); +  } + +  // Always use the first input as the base input. +  const char *BaseInput = InputInfos[0].getBaseInput(); + +  // ... except dsymutil actions, which use their actual input as the base +  // input. +  if (JA->getType() == types::TY_dSYM) +    BaseInput = InputInfos[0].getFilename(); + +  // ... and in header module compilations, which use the module name. +  if (auto *ModuleJA = dyn_cast<HeaderModulePrecompileJobAction>(JA)) +    BaseInput = ModuleJA->getModuleName(); + +  // Append outputs of offload device jobs to the input list +  if (!OffloadDependencesInputInfo.empty()) +    InputInfos.append(OffloadDependencesInputInfo.begin(), +                      OffloadDependencesInputInfo.end()); + +  // Set the effective triple of the toolchain for the duration of this job. +  llvm::Triple EffectiveTriple; +  const ToolChain &ToolTC = T->getToolChain(); +  const ArgList &Args = +      C.getArgsForToolChain(TC, BoundArch, A->getOffloadingDeviceKind()); +  if (InputInfos.size() != 1) { +    EffectiveTriple = llvm::Triple(ToolTC.ComputeEffectiveClangTriple(Args)); +  } else { +    // Pass along the input type if it can be unambiguously determined. +    EffectiveTriple = llvm::Triple( +        ToolTC.ComputeEffectiveClangTriple(Args, InputInfos[0].getType())); +  } +  RegisterEffectiveTriple TripleRAII(ToolTC, EffectiveTriple); + +  // Determine the place to write output to, if any. +  InputInfo Result; +  InputInfoList UnbundlingResults; +  if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(JA)) { +    // If we have an unbundling job, we need to create results for all the +    // outputs. We also update the results cache so that other actions using +    // this unbundling action can get the right results. +    for (auto &UI : UA->getDependentActionsInfo()) { +      assert(UI.DependentOffloadKind != Action::OFK_None && +             "Unbundling with no offloading??"); + +      // Unbundling actions are never at the top level. When we generate the +      // offloading prefix, we also do that for the host file because the +      // unbundling action does not change the type of the output which can +      // cause a overwrite. +      std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( +          UI.DependentOffloadKind, +          UI.DependentToolChain->getTriple().normalize(), +          /*CreatePrefixForHost=*/true); +      auto CurI = InputInfo( +          UA, +          GetNamedOutputPath(C, *UA, BaseInput, UI.DependentBoundArch, +                             /*AtTopLevel=*/false, +                             MultipleArchs || +                                 UI.DependentOffloadKind == Action::OFK_HIP, +                             OffloadingPrefix), +          BaseInput); +      // Save the unbundling result. +      UnbundlingResults.push_back(CurI); + +      // Get the unique string identifier for this dependence and cache the +      // result. +      StringRef Arch; +      if (TargetDeviceOffloadKind == Action::OFK_HIP) { +        if (UI.DependentOffloadKind == Action::OFK_Host) +          Arch = StringRef(); +        else +          Arch = UI.DependentBoundArch; +      } else +        Arch = BoundArch; + +      CachedResults[{A, GetTriplePlusArchString(UI.DependentToolChain, Arch, +                                                UI.DependentOffloadKind)}] = +          CurI; +    } + +    // Now that we have all the results generated, select the one that should be +    // returned for the current depending action. +    std::pair<const Action *, std::string> ActionTC = { +        A, GetTriplePlusArchString(TC, BoundArch, TargetDeviceOffloadKind)}; +    assert(CachedResults.find(ActionTC) != CachedResults.end() && +           "Result does not exist??"); +    Result = CachedResults[ActionTC]; +  } else if (JA->getType() == types::TY_Nothing) +    Result = InputInfo(A, BaseInput); +  else { +    // We only have to generate a prefix for the host if this is not a top-level +    // action. +    std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( +        A->getOffloadingDeviceKind(), TC->getTriple().normalize(), +        /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() && +            !AtTopLevel); +    if (isa<OffloadWrapperJobAction>(JA)) { +      OffloadingPrefix += "-wrapper"; +      if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) +        BaseInput = FinalOutput->getValue(); +      else +        BaseInput = getDefaultImageName(); +    } +    Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, +                                             AtTopLevel, MultipleArchs, +                                             OffloadingPrefix), +                       BaseInput); +  } + +  if (CCCPrintBindings && !CCGenDiagnostics) { +    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) +        llvm::errs() << ", "; +    } +    if (UnbundlingResults.empty()) +      llvm::errs() << "], output: " << Result.getAsString() << "\n"; +    else { +      llvm::errs() << "], outputs: ["; +      for (unsigned i = 0, e = UnbundlingResults.size(); i != e; ++i) { +        llvm::errs() << UnbundlingResults[i].getAsString(); +        if (i + 1 != e) +          llvm::errs() << ", "; +      } +      llvm::errs() << "] \n"; +    } +  } else { +    if (UnbundlingResults.empty()) +      T->ConstructJob( +          C, *JA, Result, InputInfos, +          C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), +          LinkingOutput); +    else +      T->ConstructJobMultipleOutputs( +          C, *JA, UnbundlingResults, InputInfos, +          C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), +          LinkingOutput); +  } +  return Result; +} + +const char *Driver::getDefaultImageName() const { +  llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); +  return Target.isOSWindows() ? "a.exe" : "a.out"; +} + +/// Create output filename based on ArgValue, which could either be a +/// full filename, filename without extension, or a directory. If ArgValue +/// does not provide a filename, then use BaseName, and use the extension +/// suitable for FileType. +static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue, +                                        StringRef BaseName, +                                        types::ID FileType) { +  SmallString<128> Filename = ArgValue; + +  if (ArgValue.empty()) { +    // If the argument is empty, output to BaseName in the current dir. +    Filename = BaseName; +  } else if (llvm::sys::path::is_separator(Filename.back())) { +    // If the argument is a directory, output to BaseName in that dir. +    llvm::sys::path::append(Filename, BaseName); +  } + +  if (!llvm::sys::path::has_extension(ArgValue)) { +    // If the argument didn't provide an extension, then set it. +    const char *Extension = types::getTypeTempSuffix(FileType, true); + +    if (FileType == types::TY_Image && +        Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd)) { +      // The output file is a dll. +      Extension = "dll"; +    } + +    llvm::sys::path::replace_extension(Filename, Extension); +  } + +  return Args.MakeArgString(Filename.c_str()); +} + +const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, +                                       const char *BaseInput, +                                       StringRef BoundArch, bool AtTopLevel, +                                       bool MultipleArchs, +                                       StringRef OffloadingPrefix) const { +  llvm::PrettyStackTraceString CrashInfo("Computing output path"); +  // Output to a user requested destination? +  if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { +    if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) +      return C.addResultFile(FinalOutput->getValue(), &JA); +  } + +  // For /P, preprocess to file named after BaseInput. +  if (C.getArgs().hasArg(options::OPT__SLASH_P)) { +    assert(AtTopLevel && isa<PreprocessJobAction>(JA)); +    StringRef BaseName = llvm::sys::path::filename(BaseInput); +    StringRef NameArg; +    if (Arg *A = C.getArgs().getLastArg(options::OPT__SLASH_Fi)) +      NameArg = A->getValue(); +    return C.addResultFile( +        MakeCLOutputFilename(C.getArgs(), NameArg, BaseName, types::TY_PP_C), +        &JA); +  } + +  // Default to writing to stdout? +  if (AtTopLevel && !CCGenDiagnostics && isa<PreprocessJobAction>(JA)) +    return "-"; + +  // Is this the assembly listing for /FA? +  if (JA.getType() == types::TY_PP_Asm && +      (C.getArgs().hasArg(options::OPT__SLASH_FA) || +       C.getArgs().hasArg(options::OPT__SLASH_Fa))) { +    // Use /Fa and the input filename to determine the asm file name. +    StringRef BaseName = llvm::sys::path::filename(BaseInput); +    StringRef FaValue = C.getArgs().getLastArgValue(options::OPT__SLASH_Fa); +    return C.addResultFile( +        MakeCLOutputFilename(C.getArgs(), FaValue, BaseName, JA.getType()), +        &JA); +  } + +  // Output to a temporary file? +  if ((!AtTopLevel && !isSaveTempsEnabled() && +       !C.getArgs().hasArg(options::OPT__SLASH_Fo)) || +      CCGenDiagnostics) { +    StringRef Name = llvm::sys::path::filename(BaseInput); +    std::pair<StringRef, StringRef> Split = Name.split('.'); +    SmallString<128> TmpName; +    const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); +    Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir); +    if (CCGenDiagnostics && A) { +      SmallString<128> CrashDirectory(A->getValue()); +      if (!getVFS().exists(CrashDirectory)) +        llvm::sys::fs::create_directories(CrashDirectory); +      llvm::sys::path::append(CrashDirectory, Split.first); +      const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%"; +      std::error_code EC = llvm::sys::fs::createUniqueFile( +          CrashDirectory + Middle + Suffix, TmpName); +      if (EC) { +        Diag(clang::diag::err_unable_to_make_temp) << EC.message(); +        return ""; +      } +    } else { +      TmpName = GetTemporaryPath(Split.first, Suffix); +    } +    return C.addTempFile(C.getArgs().MakeArgString(TmpName)); +  } + +  SmallString<128> BasePath(BaseInput); +  StringRef BaseName; + +  // Dsymutil actions should use the full path. +  if (isa<DsymutilJobAction>(JA) || isa<VerifyJobAction>(JA)) +    BaseName = BasePath; +  else +    BaseName = llvm::sys::path::filename(BasePath); + +  // Determine what the derived output name should be. +  const char *NamedOutput; + +  if ((JA.getType() == types::TY_Object || JA.getType() == types::TY_LTO_BC) && +      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, +                                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) { +    if (IsCLMode()) { +      // clang-cl uses BaseName for the executable name. +      NamedOutput = +          MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image); +    } else { +      SmallString<128> Output(getDefaultImageName()); +      // HIP image for device compilation with -fno-gpu-rdc is per compilation +      // unit. +      bool IsHIPNoRDC = JA.getOffloadingDeviceKind() == Action::OFK_HIP && +                        !C.getArgs().hasFlag(options::OPT_fgpu_rdc, +                                             options::OPT_fno_gpu_rdc, false); +      if (IsHIPNoRDC) { +        Output = BaseName; +        llvm::sys::path::replace_extension(Output, ""); +      } +      Output += OffloadingPrefix; +      if (MultipleArchs && !BoundArch.empty()) { +        Output += "-"; +        Output.append(BoundArch); +      } +      if (IsHIPNoRDC) +        Output += ".out"; +      NamedOutput = C.getArgs().MakeArgString(Output.c_str()); +    } +  } else if (JA.getType() == types::TY_PCH && IsCLMode()) { +    NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName)); +  } else { +    const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); +    assert(Suffix && "All types used for output should have a suffix."); + +    std::string::size_type End = std::string::npos; +    if (!types::appendSuffixForType(JA.getType())) +      End = BaseName.rfind('.'); +    SmallString<128> Suffixed(BaseName.substr(0, End)); +    Suffixed += OffloadingPrefix; +    if (MultipleArchs && !BoundArch.empty()) { +      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()); +  } + +  // Prepend object file path if -save-temps=obj +  if (!AtTopLevel && isSaveTempsObj() && C.getArgs().hasArg(options::OPT_o) && +      JA.getType() != types::TY_PCH) { +    Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); +    SmallString<128> TempPath(FinalOutput->getValue()); +    llvm::sys::path::remove_filename(TempPath); +    StringRef OutputFileName = llvm::sys::path::filename(NamedOutput); +    llvm::sys::path::append(TempPath, OutputFileName); +    NamedOutput = C.getArgs().MakeArgString(TempPath.c_str()); +  } + +  // If we're saving temps and the temp file conflicts with the input file, +  // then avoid overwriting input file. +  if (!AtTopLevel && isSaveTempsEnabled() && NamedOutput == BaseName) { +    bool SameFile = false; +    SmallString<256> Result; +    llvm::sys::fs::current_path(Result); +    llvm::sys::path::append(Result, BaseName); +    llvm::sys::fs::equivalent(BaseInput, Result.c_str(), SameFile); +    // Must share the same path to conflict. +    if (SameFile) { +      StringRef Name = llvm::sys::path::filename(BaseInput); +      std::pair<StringRef, StringRef> Split = Name.split('.'); +      std::string TmpName = GetTemporaryPath( +          Split.first, types::getTypeTempSuffix(JA.getType(), IsCLMode())); +      return C.addTempFile(C.getArgs().MakeArgString(TmpName)); +    } +  } + +  // As an annoying special case, PCH generation doesn't strip the pathname. +  if (JA.getType() == types::TY_PCH && !IsCLMode()) { +    llvm::sys::path::remove_filename(BasePath); +    if (BasePath.empty()) +      BasePath = NamedOutput; +    else +      llvm::sys::path::append(BasePath, NamedOutput); +    return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA); +  } else { +    return C.addResultFile(NamedOutput, &JA); +  } +} + +std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { +  // Search for Name in a list of paths. +  auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P) +      -> llvm::Optional<std::string> { +    // Respect a limited subset of the '-Bprefix' functionality in GCC by +    // attempting to use this prefix when looking for file paths. +    for (const auto &Dir : P) { +      if (Dir.empty()) +        continue; +      SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir); +      llvm::sys::path::append(P, Name); +      if (llvm::sys::fs::exists(Twine(P))) +        return P.str().str(); +    } +    return None; +  }; + +  if (auto P = SearchPaths(PrefixDirs)) +    return *P; + +  SmallString<128> R(ResourceDir); +  llvm::sys::path::append(R, Name); +  if (llvm::sys::fs::exists(Twine(R))) +    return R.str(); + +  SmallString<128> P(TC.getCompilerRTPath()); +  llvm::sys::path::append(P, Name); +  if (llvm::sys::fs::exists(Twine(P))) +    return P.str(); + +  SmallString<128> D(Dir); +  llvm::sys::path::append(D, "..", Name); +  if (llvm::sys::fs::exists(Twine(D))) +    return D.str(); + +  if (auto P = SearchPaths(TC.getLibraryPaths())) +    return *P; + +  if (auto P = SearchPaths(TC.getFilePaths())) +    return *P; + +  return Name; +} + +void Driver::generatePrefixedToolNames( +    StringRef Tool, const ToolChain &TC, +    SmallVectorImpl<std::string> &Names) const { +  // FIXME: Needs a better variable than TargetTriple +  Names.emplace_back((TargetTriple + "-" + Tool).str()); +  Names.emplace_back(Tool); + +  // Allow the discovery of tools prefixed with LLVM's default target triple. +  std::string DefaultTargetTriple = llvm::sys::getDefaultTargetTriple(); +  if (DefaultTargetTriple != TargetTriple) +    Names.emplace_back((DefaultTargetTriple + "-" + Tool).str()); +} + +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(StringRef Name, const ToolChain &TC) const { +  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 (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((PrefixDir + Name).str()); +      if (llvm::sys::fs::can_execute(Twine(P))) +        return P.str(); +    } +  } + +  const ToolChain::path_list &List = TC.getProgramPaths(); +  for (const auto &Path : List) { +    SmallString<128> P(Path); +    if (ScanDirForExecutable(P, TargetSpecificExecutables)) +      return P.str(); +  } + +  // If all else failed, search the path. +  for (const auto &TargetSpecificExecutable : TargetSpecificExecutables) +    if (llvm::ErrorOr<std::string> P = +            llvm::sys::findProgramByName(TargetSpecificExecutable)) +      return *P; + +  return Name; +} + +std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const { +  SmallString<128> Path; +  std::error_code EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path); +  if (EC) { +    Diag(clang::diag::err_unable_to_make_temp) << EC.message(); +    return ""; +  } + +  return Path.str(); +} + +std::string Driver::GetTemporaryDirectory(StringRef Prefix) const { +  SmallString<128> Path; +  std::error_code EC = llvm::sys::fs::createUniqueDirectory(Prefix, Path); +  if (EC) { +    Diag(clang::diag::err_unable_to_make_temp) << EC.message(); +    return ""; +  } + +  return Path.str(); +} + +std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { +  SmallString<128> Output; +  if (Arg *FpArg = C.getArgs().getLastArg(options::OPT__SLASH_Fp)) { +    // FIXME: If anybody needs it, implement this obscure rule: +    // "If you specify a directory without a file name, the default file name +    // is VCx0.pch., where x is the major version of Visual C++ in use." +    Output = FpArg->getValue(); + +    // "If you do not specify an extension as part of the path name, an +    // extension of .pch is assumed. " +    if (!llvm::sys::path::has_extension(Output)) +      Output += ".pch"; +  } else { +    if (Arg *YcArg = C.getArgs().getLastArg(options::OPT__SLASH_Yc)) +      Output = YcArg->getValue(); +    if (Output.empty()) +      Output = BaseName; +    llvm::sys::path::replace_extension(Output, ".pch"); +  } +  return Output.str(); +} + +const ToolChain &Driver::getToolChain(const ArgList &Args, +                                      const llvm::Triple &Target) const { + +  auto &TC = ToolChains[Target.str()]; +  if (!TC) { +    switch (Target.getOS()) { +    case llvm::Triple::Haiku: +      TC = std::make_unique<toolchains::Haiku>(*this, Target, Args); +      break; +    case llvm::Triple::Ananas: +      TC = std::make_unique<toolchains::Ananas>(*this, Target, Args); +      break; +    case llvm::Triple::CloudABI: +      TC = std::make_unique<toolchains::CloudABI>(*this, Target, Args); +      break; +    case llvm::Triple::Darwin: +    case llvm::Triple::MacOSX: +    case llvm::Triple::IOS: +    case llvm::Triple::TvOS: +    case llvm::Triple::WatchOS: +      TC = std::make_unique<toolchains::DarwinClang>(*this, Target, Args); +      break; +    case llvm::Triple::DragonFly: +      TC = std::make_unique<toolchains::DragonFly>(*this, Target, Args); +      break; +    case llvm::Triple::OpenBSD: +      TC = std::make_unique<toolchains::OpenBSD>(*this, Target, Args); +      break; +    case llvm::Triple::NetBSD: +      TC = std::make_unique<toolchains::NetBSD>(*this, Target, Args); +      break; +    case llvm::Triple::FreeBSD: +      TC = std::make_unique<toolchains::FreeBSD>(*this, Target, Args); +      break; +    case llvm::Triple::Minix: +      TC = std::make_unique<toolchains::Minix>(*this, Target, Args); +      break; +    case llvm::Triple::Linux: +    case llvm::Triple::ELFIAMCU: +      if (Target.getArch() == llvm::Triple::hexagon) +        TC = std::make_unique<toolchains::HexagonToolChain>(*this, Target, +                                                             Args); +      else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) && +               !Target.hasEnvironment()) +        TC = std::make_unique<toolchains::MipsLLVMToolChain>(*this, Target, +                                                              Args); +      else if (Target.getArch() == llvm::Triple::ppc || +               Target.getArch() == llvm::Triple::ppc64 || +               Target.getArch() == llvm::Triple::ppc64le) +        TC = std::make_unique<toolchains::PPCLinuxToolChain>(*this, Target, +                                                              Args); +      else +        TC = std::make_unique<toolchains::Linux>(*this, Target, Args); +      break; +    case llvm::Triple::NaCl: +      TC = std::make_unique<toolchains::NaClToolChain>(*this, Target, Args); +      break; +    case llvm::Triple::Fuchsia: +      TC = std::make_unique<toolchains::Fuchsia>(*this, Target, Args); +      break; +    case llvm::Triple::Solaris: +      TC = std::make_unique<toolchains::Solaris>(*this, Target, Args); +      break; +    case llvm::Triple::AMDHSA: +    case llvm::Triple::AMDPAL: +    case llvm::Triple::Mesa3D: +      TC = std::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args); +      break; +    case llvm::Triple::Win32: +      switch (Target.getEnvironment()) { +      default: +        if (Target.isOSBinFormatELF()) +          TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args); +        else if (Target.isOSBinFormatMachO()) +          TC = std::make_unique<toolchains::MachO>(*this, Target, Args); +        else +          TC = std::make_unique<toolchains::Generic_GCC>(*this, Target, Args); +        break; +      case llvm::Triple::GNU: +        TC = std::make_unique<toolchains::MinGW>(*this, Target, Args); +        break; +      case llvm::Triple::Itanium: +        TC = std::make_unique<toolchains::CrossWindowsToolChain>(*this, Target, +                                                                  Args); +        break; +      case llvm::Triple::MSVC: +      case llvm::Triple::UnknownEnvironment: +        if (Args.getLastArgValue(options::OPT_fuse_ld_EQ) +                .startswith_lower("bfd")) +          TC = std::make_unique<toolchains::CrossWindowsToolChain>( +              *this, Target, Args); +        else +          TC = +              std::make_unique<toolchains::MSVCToolChain>(*this, Target, Args); +        break; +      } +      break; +    case llvm::Triple::PS4: +      TC = std::make_unique<toolchains::PS4CPU>(*this, Target, Args); +      break; +    case llvm::Triple::Contiki: +      TC = std::make_unique<toolchains::Contiki>(*this, Target, Args); +      break; +    case llvm::Triple::Hurd: +      TC = std::make_unique<toolchains::Hurd>(*this, Target, Args); +      break; +    default: +      // Of these targets, Hexagon is the only one that might have +      // an OS of Linux, in which case it got handled above already. +      switch (Target.getArch()) { +      case llvm::Triple::tce: +        TC = std::make_unique<toolchains::TCEToolChain>(*this, Target, Args); +        break; +      case llvm::Triple::tcele: +        TC = std::make_unique<toolchains::TCELEToolChain>(*this, Target, Args); +        break; +      case llvm::Triple::hexagon: +        TC = std::make_unique<toolchains::HexagonToolChain>(*this, Target, +                                                             Args); +        break; +      case llvm::Triple::lanai: +        TC = std::make_unique<toolchains::LanaiToolChain>(*this, Target, Args); +        break; +      case llvm::Triple::xcore: +        TC = std::make_unique<toolchains::XCoreToolChain>(*this, Target, Args); +        break; +      case llvm::Triple::wasm32: +      case llvm::Triple::wasm64: +        TC = std::make_unique<toolchains::WebAssembly>(*this, Target, Args); +        break; +      case llvm::Triple::avr: +        TC = std::make_unique<toolchains::AVRToolChain>(*this, Target, Args); +        break; +      case llvm::Triple::msp430: +        TC = +            std::make_unique<toolchains::MSP430ToolChain>(*this, Target, Args); +        break; +      case llvm::Triple::riscv32: +      case llvm::Triple::riscv64: +        TC = std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args); +        break; +      default: +        if (Target.getVendor() == llvm::Triple::Myriad) +          TC = std::make_unique<toolchains::MyriadToolChain>(*this, Target, +                                                              Args); +        else if (toolchains::BareMetal::handlesTarget(Target)) +          TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args); +        else if (Target.isOSBinFormatELF()) +          TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args); +        else if (Target.isOSBinFormatMachO()) +          TC = std::make_unique<toolchains::MachO>(*this, Target, Args); +        else +          TC = std::make_unique<toolchains::Generic_GCC>(*this, Target, Args); +      } +    } +  } + +  // Intentionally omitted from the switch above: llvm::Triple::CUDA.  CUDA +  // compiles always need two toolchains, the CUDA toolchain and the host +  // toolchain.  So the only valid way to create a CUDA toolchain is via +  // CreateOffloadingDeviceToolChains. + +  return *TC; +} + +bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { +  // Say "no" if there is not exactly one input of a type clang understands. +  if (JA.size() != 1 || +      !types::isAcceptedByClang((*JA.input_begin())->getType())) +    return false; + +  // And say "no" if this is not a kind of action clang understands. +  if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) && +      !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) +    return false; + +  return true; +} + +/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the +/// grouped values as integers. Numbers which are not provided are set to 0. +/// +/// \return True if the entire string was parsed (9.2), or all groups were +/// parsed (10.3.5extrastuff). +bool Driver::GetReleaseVersion(StringRef Str, unsigned &Major, unsigned &Minor, +                               unsigned &Micro, bool &HadExtra) { +  HadExtra = false; + +  Major = Minor = Micro = 0; +  if (Str.empty()) +    return false; + +  if (Str.consumeInteger(10, Major)) +    return false; +  if (Str.empty()) +    return true; +  if (Str[0] != '.') +    return false; + +  Str = Str.drop_front(1); + +  if (Str.consumeInteger(10, Minor)) +    return false; +  if (Str.empty()) +    return true; +  if (Str[0] != '.') +    return false; +  Str = Str.drop_front(1); + +  if (Str.consumeInteger(10, Micro)) +    return false; +  if (!Str.empty()) +    HadExtra = true; +  return true; +} + +/// Parse digits from a string \p Str and fulfill \p Digits with +/// the parsed numbers. This method assumes that the max number of +/// digits to look for is equal to Digits.size(). +/// +/// \return True if the entire string was parsed and there are +/// no extra characters remaining at the end. +bool Driver::GetReleaseVersion(StringRef Str, +                               MutableArrayRef<unsigned> Digits) { +  if (Str.empty()) +    return false; + +  unsigned CurDigit = 0; +  while (CurDigit < Digits.size()) { +    unsigned Digit; +    if (Str.consumeInteger(10, Digit)) +      return false; +    Digits[CurDigit] = Digit; +    if (Str.empty()) +      return true; +    if (Str[0] != '.') +      return false; +    Str = Str.drop_front(1); +    CurDigit++; +  } + +  // More digits than requested, bail out... +  return false; +} + +std::pair<unsigned, unsigned> +Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { +  unsigned IncludedFlagsBitmask = 0; +  unsigned ExcludedFlagsBitmask = options::NoDriverOption; + +  if (IsClCompatMode) { +    // Include CL and Core options. +    IncludedFlagsBitmask |= options::CLOption; +    IncludedFlagsBitmask |= options::CoreOption; +  } else { +    ExcludedFlagsBitmask |= options::CLOption; +  } + +  return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask); +} + +bool clang::driver::isOptimizationLevelFast(const ArgList &Args) { +  return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false); +} diff --git a/clang/lib/Driver/DriverOptions.cpp b/clang/lib/Driver/DriverOptions.cpp new file mode 100644 index 0000000000000..67d4198d222aa --- /dev/null +++ b/clang/lib/Driver/DriverOptions.cpp @@ -0,0 +1,55 @@ +//===--- DriverOptions.cpp - Driver Options Table -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Options.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include <cassert> + +using namespace clang::driver; +using namespace clang::driver::options; +using namespace llvm::opt; + +#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; +#include "clang/Driver/Options.inc" +#undef PREFIX + +static const OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \ +               HELPTEXT, METAVAR, VALUES)                                      \ +  {PREFIX, NAME,  HELPTEXT,    METAVAR,     OPT_##ID,  Option::KIND##Class,    \ +   PARAM,  FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES}, +#include "clang/Driver/Options.inc" +#undef OPTION +}; + +namespace { + +class DriverOptTable : public OptTable { +public: +  DriverOptTable() +    : OptTable(InfoTable) {} +}; + +} + +const llvm::opt::OptTable &clang::driver::getDriverOptTable() { +  static const DriverOptTable *Table = []() { +    auto Result = std::make_unique<DriverOptTable>(); +    // Options.inc is included in DriverOptions.cpp, and calls OptTable's +    // addValues function. +    // Opt is a variable used in the code fragment in Options.inc. +    OptTable &Opt = *Result; +#define OPTTABLE_ARG_INIT +#include "clang/Driver/Options.inc" +#undef OPTTABLE_ARG_INIT +    return Result.release(); +  }(); +  return *Table; +} diff --git a/clang/lib/Driver/InputInfo.h b/clang/lib/Driver/InputInfo.h new file mode 100644 index 0000000000000..a6b6f7f344bc5 --- /dev/null +++ b/clang/lib/Driver/InputInfo.h @@ -0,0 +1,107 @@ +//===--- InputInfo.h - Input Source & Type Information ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_INPUTINFO_H +#define LLVM_CLANG_LIB_DRIVER_INPUTINFO_H + +#include "clang/Driver/Action.h" +#include "clang/Driver/Types.h" +#include "llvm/Option/Arg.h" +#include <cassert> +#include <string> + +namespace clang { +namespace driver { + +/// InputInfo - Wrapper for information about an input source. +class InputInfo { +  // FIXME: The distinction between filenames and inputarg here is +  // gross; we should probably drop the idea of a "linker +  // input". Doing so means tweaking pipelining to still create link +  // steps when it sees linker inputs (but not treat them as +  // arguments), and making sure that arguments get rendered +  // correctly. +  enum Class { +    Nothing, +    Filename, +    InputArg, +    Pipe +  }; + +  union { +    const char *Filename; +    const llvm::opt::Arg *InputArg; +  } Data; +  Class Kind; +  const Action* Act; +  types::ID Type; +  const char *BaseInput; + +  static types::ID GetActionType(const Action *A) { +    return A != nullptr ? A->getType() : types::TY_Nothing; +  } + +public: +  InputInfo() : InputInfo(nullptr, nullptr) {} +  InputInfo(const Action *A, const char *_BaseInput) +      : Kind(Nothing), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {} + +  InputInfo(types::ID _Type, const char *_Filename, const char *_BaseInput) +      : Kind(Filename), Act(nullptr), Type(_Type), BaseInput(_BaseInput) { +    Data.Filename = _Filename; +  } +  InputInfo(const Action *A, const char *_Filename, const char *_BaseInput) +      : Kind(Filename), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) { +    Data.Filename = _Filename; +  } + +  InputInfo(types::ID _Type, const llvm::opt::Arg *_InputArg, +            const char *_BaseInput) +      : Kind(InputArg), Act(nullptr), Type(_Type), BaseInput(_BaseInput) { +    Data.InputArg = _InputArg; +  } +  InputInfo(const Action *A, const llvm::opt::Arg *_InputArg, +            const char *_BaseInput) +      : Kind(InputArg), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) { +    Data.InputArg = _InputArg; +  } + +  bool isNothing() const { return Kind == Nothing; } +  bool isFilename() const { return Kind == Filename; } +  bool isInputArg() const { return Kind == InputArg; } +  types::ID getType() const { return Type; } +  const char *getBaseInput() const { return BaseInput; } +  /// The action for which this InputInfo was created.  May be null. +  const Action *getAction() const { return Act; } +  void setAction(const Action *A) { Act = A; } + +  const char *getFilename() const { +    assert(isFilename() && "Invalid accessor."); +    return Data.Filename; +  } +  const llvm::opt::Arg &getInputArg() const { +    assert(isInputArg() && "Invalid accessor."); +    return *Data.InputArg; +  } + +  /// getAsString - Return a string name for this input, for +  /// debugging. +  std::string getAsString() const { +    if (isFilename()) +      return std::string("\"") + getFilename() + '"'; +    else if (isInputArg()) +      return "(input arg)"; +    else +      return "(nothing)"; +  } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp new file mode 100644 index 0000000000000..0a95e49694f95 --- /dev/null +++ b/clang/lib/Driver/Job.cpp @@ -0,0 +1,441 @@ +//===- Job.cpp - Command to Execute ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Job.h" +#include "InputInfo.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <string> +#include <system_error> +#include <utility> + +using namespace clang; +using namespace driver; + +Command::Command(const Action &Source, const Tool &Creator, +                 const char *Executable, +                 const llvm::opt::ArgStringList &Arguments, +                 ArrayRef<InputInfo> Inputs) +    : Source(Source), Creator(Creator), Executable(Executable), +      Arguments(Arguments) { +  for (const auto &II : Inputs) +    if (II.isFilename()) +      InputFilenames.push_back(II.getFilename()); +} + +/// Check if the compiler flag in question should be skipped when +/// emitting a reproducer. Also track how many arguments it has and if the +/// option is some kind of include path. +static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, +                     bool &IsInclude) { +  SkipNum = 2; +  // These flags are all of the form -Flag <Arg> and are treated as two +  // arguments.  Therefore, we need to skip the flag and the next argument. +  bool ShouldSkip = llvm::StringSwitch<bool>(Flag) +    .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) +    .Cases("-o", "-dependency-file", true) +    .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) +    .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) +    .Default(false); +  if (ShouldSkip) +    return true; + +  // Some include flags shouldn't be skipped if we have a crash VFS +  IsInclude = llvm::StringSwitch<bool>(Flag) +    .Cases("-include", "-header-include-file", true) +    .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true) +    .Cases("-internal-externc-isystem", "-iprefix", true) +    .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) +    .Cases("-isysroot", "-I", "-F", "-resource-dir", true) +    .Cases("-iframework", "-include-pch", true) +    .Default(false); +  if (IsInclude) +    return !HaveCrashVFS; + +  // The remaining flags are treated as a single argument. + +  // These flags are all of the form -Flag and have no second argument. +  ShouldSkip = llvm::StringSwitch<bool>(Flag) +    .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) +    .Case("-MMD", true) +    .Default(false); + +  // Match found. +  SkipNum = 1; +  if (ShouldSkip) +    return true; + +  // These flags are treated as a single argument (e.g., -F<Dir>). +  StringRef FlagRef(Flag); +  IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I"); +  if (IsInclude) +    return !HaveCrashVFS; +  if (FlagRef.startswith("-fmodules-cache-path=")) +    return true; + +  SkipNum = 0; +  return false; +} + +void Command::printArg(raw_ostream &OS, StringRef Arg, bool Quote) { +  const bool Escape = Arg.find_first_of(" \"\\$") != StringRef::npos; + +  if (!Quote && !Escape) { +    OS << Arg; +    return; +  } + +  // Quote and escape. This isn't really complete, but good enough. +  OS << '"'; +  for (const auto c : Arg) { +    if (c == '"' || c == '\\' || c == '$') +      OS << '\\'; +    OS << c; +  } +  OS << '"'; +} + +void Command::writeResponseFile(raw_ostream &OS) const { +  // In a file list, we only write the set of inputs to the response file +  if (Creator.getResponseFilesSupport() == Tool::RF_FileList) { +    for (const auto *Arg : InputFileList) { +      OS << Arg << '\n'; +    } +    return; +  } + +  // In regular response files, we send all arguments to the response file. +  // Wrapping all arguments in double quotes ensures that both Unix tools and +  // Windows tools understand the response file. +  for (const auto *Arg : Arguments) { +    OS << '"'; + +    for (; *Arg != '\0'; Arg++) { +      if (*Arg == '\"' || *Arg == '\\') { +        OS << '\\'; +      } +      OS << *Arg; +    } + +    OS << "\" "; +  } +} + +void Command::buildArgvForResponseFile( +    llvm::SmallVectorImpl<const char *> &Out) const { +  // When not a file list, all arguments are sent to the response file. +  // This leaves us to set the argv to a single parameter, requesting the tool +  // to read the response file. +  if (Creator.getResponseFilesSupport() != Tool::RF_FileList) { +    Out.push_back(Executable); +    Out.push_back(ResponseFileFlag.c_str()); +    return; +  } + +  llvm::StringSet<> Inputs; +  for (const auto *InputName : InputFileList) +    Inputs.insert(InputName); +  Out.push_back(Executable); +  // In a file list, build args vector ignoring parameters that will go in the +  // response file (elements of the InputFileList vector) +  bool FirstInput = true; +  for (const auto *Arg : Arguments) { +    if (Inputs.count(Arg) == 0) { +      Out.push_back(Arg); +    } else if (FirstInput) { +      FirstInput = false; +      Out.push_back(Creator.getResponseFileFlag()); +      Out.push_back(ResponseFile); +    } +  } +} + +/// Rewrite relative include-like flag paths to absolute ones. +static void +rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx, +                size_t NumArgs, +                llvm::SmallVectorImpl<llvm::SmallString<128>> &IncFlags) { +  using namespace llvm; +  using namespace sys; + +  auto getAbsPath = [](StringRef InInc, SmallVectorImpl<char> &OutInc) -> bool { +    if (path::is_absolute(InInc)) // Nothing to do here... +      return false; +    std::error_code EC = fs::current_path(OutInc); +    if (EC) +      return false; +    path::append(OutInc, InInc); +    return true; +  }; + +  SmallString<128> NewInc; +  if (NumArgs == 1) { +    StringRef FlagRef(Args[Idx + NumArgs - 1]); +    assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) && +            "Expecting -I or -F"); +    StringRef Inc = FlagRef.slice(2, StringRef::npos); +    if (getAbsPath(Inc, NewInc)) { +      SmallString<128> NewArg(FlagRef.slice(0, 2)); +      NewArg += NewInc; +      IncFlags.push_back(std::move(NewArg)); +    } +    return; +  } + +  assert(NumArgs == 2 && "Not expecting more than two arguments"); +  StringRef Inc(Args[Idx + NumArgs - 1]); +  if (!getAbsPath(Inc, NewInc)) +    return; +  IncFlags.push_back(SmallString<128>(Args[Idx])); +  IncFlags.push_back(std::move(NewInc)); +} + +void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, +                    CrashReportInfo *CrashInfo) const { +  // Always quote the exe. +  OS << ' '; +  printArg(OS, Executable, /*Quote=*/true); + +  ArrayRef<const char *> Args = Arguments; +  SmallVector<const char *, 128> ArgsRespFile; +  if (ResponseFile != nullptr) { +    buildArgvForResponseFile(ArgsRespFile); +    Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name +  } + +  bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty(); +  for (size_t i = 0, e = Args.size(); i < e; ++i) { +    const char *const Arg = Args[i]; + +    if (CrashInfo) { +      int NumArgs = 0; +      bool IsInclude = false; +      if (skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) { +        i += NumArgs - 1; +        continue; +      } + +      // Relative includes need to be expanded to absolute paths. +      if (HaveCrashVFS && IsInclude) { +        SmallVector<SmallString<128>, 2> NewIncFlags; +        rewriteIncludes(Args, i, NumArgs, NewIncFlags); +        if (!NewIncFlags.empty()) { +          for (auto &F : NewIncFlags) { +            OS << ' '; +            printArg(OS, F.c_str(), Quote); +          } +          i += NumArgs - 1; +          continue; +        } +      } + +      auto Found = llvm::find_if(InputFilenames, +                                 [&Arg](StringRef IF) { return IF == Arg; }); +      if (Found != InputFilenames.end() && +          (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) { +        // Replace the input file name with the crashinfo's file name. +        OS << ' '; +        StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); +        printArg(OS, ShortName.str(), Quote); +        continue; +      } +    } + +    OS << ' '; +    printArg(OS, Arg, Quote); +  } + +  if (CrashInfo && HaveCrashVFS) { +    OS << ' '; +    printArg(OS, "-ivfsoverlay", Quote); +    OS << ' '; +    printArg(OS, CrashInfo->VFSPath.str(), Quote); + +    // The leftover modules from the crash are stored in +    //  <name>.cache/vfs/modules +    // Leave it untouched for pcm inspection and provide a clean/empty dir +    // path to contain the future generated module cache: +    //  <name>.cache/vfs/repro-modules +    SmallString<128> RelModCacheDir = llvm::sys::path::parent_path( +        llvm::sys::path::parent_path(CrashInfo->VFSPath)); +    llvm::sys::path::append(RelModCacheDir, "repro-modules"); + +    std::string ModCachePath = "-fmodules-cache-path="; +    ModCachePath.append(RelModCacheDir.c_str()); + +    OS << ' '; +    printArg(OS, ModCachePath, Quote); +  } + +  if (ResponseFile != nullptr) { +    OS << "\n Arguments passed via response file:\n"; +    writeResponseFile(OS); +    // Avoiding duplicated newline terminator, since FileLists are +    // newline-separated. +    if (Creator.getResponseFilesSupport() != Tool::RF_FileList) +      OS << "\n"; +    OS << " (end of response file)"; +  } + +  OS << Terminator; +} + +void Command::setResponseFile(const char *FileName) { +  ResponseFile = FileName; +  ResponseFileFlag = Creator.getResponseFileFlag(); +  ResponseFileFlag += FileName; +} + +void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { +  Environment.reserve(NewEnvironment.size() + 1); +  Environment.assign(NewEnvironment.begin(), NewEnvironment.end()); +  Environment.push_back(nullptr); +} + +int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, +                     std::string *ErrMsg, bool *ExecutionFailed) const { +  if (PrintInputFilenames) { +    for (const char *Arg : InputFilenames) +      llvm::outs() << llvm::sys::path::filename(Arg) << "\n"; +    llvm::outs().flush(); +  } + +  SmallVector<const char*, 128> Argv; + +  Optional<ArrayRef<StringRef>> Env; +  std::vector<StringRef> ArgvVectorStorage; +  if (!Environment.empty()) { +    assert(Environment.back() == nullptr && +           "Environment vector should be null-terminated by now"); +    ArgvVectorStorage = llvm::toStringRefArray(Environment.data()); +    Env = makeArrayRef(ArgvVectorStorage); +  } + +  if (ResponseFile == nullptr) { +    Argv.push_back(Executable); +    Argv.append(Arguments.begin(), Arguments.end()); +    Argv.push_back(nullptr); + +    auto Args = llvm::toStringRefArray(Argv.data()); +    return llvm::sys::ExecuteAndWait( +        Executable, Args, Env, Redirects, /*secondsToWait*/ 0, +        /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +  } + +  // We need to put arguments in a response file (command is too large) +  // Open stream to store the response file contents +  std::string RespContents; +  llvm::raw_string_ostream SS(RespContents); + +  // Write file contents and build the Argv vector +  writeResponseFile(SS); +  buildArgvForResponseFile(Argv); +  Argv.push_back(nullptr); +  SS.flush(); + +  // Save the response file in the appropriate encoding +  if (std::error_code EC = writeFileWithEncoding( +          ResponseFile, RespContents, Creator.getResponseFileEncoding())) { +    if (ErrMsg) +      *ErrMsg = EC.message(); +    if (ExecutionFailed) +      *ExecutionFailed = true; +    return -1; +  } + +  auto Args = llvm::toStringRefArray(Argv.data()); +  return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, +                                   /*secondsToWait*/ 0, +                                   /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +} + +FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, +                                 const char *Executable_, +                                 const llvm::opt::ArgStringList &Arguments_, +                                 ArrayRef<InputInfo> Inputs, +                                 std::unique_ptr<Command> Fallback_) +    : Command(Source_, Creator_, Executable_, Arguments_, Inputs), +      Fallback(std::move(Fallback_)) {} + +void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, +                            bool Quote, CrashReportInfo *CrashInfo) const { +  Command::Print(OS, "", Quote, CrashInfo); +  OS << " ||"; +  Fallback->Print(OS, Terminator, Quote, CrashInfo); +} + +static bool ShouldFallback(int ExitCode) { +  // FIXME: We really just want to fall back for internal errors, such +  // as when some symbol cannot be mangled, when we should be able to +  // parse something but can't, etc. +  return ExitCode != 0; +} + +int FallbackCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, +                             std::string *ErrMsg, bool *ExecutionFailed) const { +  int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed); +  if (!ShouldFallback(PrimaryStatus)) +    return PrimaryStatus; + +  // Clear ExecutionFailed and ErrMsg before falling back. +  if (ErrMsg) +    ErrMsg->clear(); +  if (ExecutionFailed) +    *ExecutionFailed = false; + +  const Driver &D = getCreator().getToolChain().getDriver(); +  D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable(); + +  int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed); +  return SecondaryStatus; +} + +ForceSuccessCommand::ForceSuccessCommand( +    const Action &Source_, const Tool &Creator_, const char *Executable_, +    const llvm::opt::ArgStringList &Arguments_, ArrayRef<InputInfo> Inputs) +    : Command(Source_, Creator_, Executable_, Arguments_, Inputs) {} + +void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator, +                            bool Quote, CrashReportInfo *CrashInfo) const { +  Command::Print(OS, "", Quote, CrashInfo); +  OS << " || (exit 0)" << Terminator; +} + +int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, +                                 std::string *ErrMsg, +                                 bool *ExecutionFailed) const { +  int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed); +  (void)Status; +  if (ExecutionFailed) +    *ExecutionFailed = false; +  return 0; +} + +void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, +                    CrashReportInfo *CrashInfo) const { +  for (const auto &Job : *this) +    Job.Print(OS, Terminator, Quote, CrashInfo); +} + +void JobList::clear() { Jobs.clear(); } diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp new file mode 100644 index 0000000000000..303047e05f78d --- /dev/null +++ b/clang/lib/Driver/Multilib.cpp @@ -0,0 +1,308 @@ +//===- Multilib.cpp - Multilib Implementation -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Multilib.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <string> + +using namespace clang; +using namespace driver; +using namespace llvm::sys; + +/// normalize Segment to "/foo/bar" or "". +static void normalizePathSegment(std::string &Segment) { +  StringRef seg = Segment; + +  // Prune trailing "/" or "./" +  while (true) { +    StringRef last = path::filename(seg); +    if (last != ".") +      break; +    seg = path::parent_path(seg); +  } + +  if (seg.empty() || seg == "/") { +    Segment.clear(); +    return; +  } + +  // Add leading '/' +  if (seg.front() != '/') { +    Segment = "/" + seg.str(); +  } else { +    Segment = seg; +  } +} + +Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, +                   StringRef IncludeSuffix, int Priority) +    : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), +      Priority(Priority) { +  normalizePathSegment(this->GCCSuffix); +  normalizePathSegment(this->OSSuffix); +  normalizePathSegment(this->IncludeSuffix); +} + +Multilib &Multilib::gccSuffix(StringRef S) { +  GCCSuffix = S; +  normalizePathSegment(GCCSuffix); +  return *this; +} + +Multilib &Multilib::osSuffix(StringRef S) { +  OSSuffix = S; +  normalizePathSegment(OSSuffix); +  return *this; +} + +Multilib &Multilib::includeSuffix(StringRef S) { +  IncludeSuffix = S; +  normalizePathSegment(IncludeSuffix); +  return *this; +} + +LLVM_DUMP_METHOD void Multilib::dump() const { +  print(llvm::errs()); +} + +void Multilib::print(raw_ostream &OS) const { +  assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/')); +  if (GCCSuffix.empty()) +    OS << "."; +  else { +    OS << StringRef(GCCSuffix).drop_front(); +  } +  OS << ";"; +  for (StringRef Flag : Flags) { +    if (Flag.front() == '+') +      OS << "@" << Flag.substr(1); +  } +} + +bool Multilib::isValid() const { +  llvm::StringMap<int> FlagSet; +  for (unsigned I = 0, N = Flags.size(); I != N; ++I) { +    StringRef Flag(Flags[I]); +    llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1)); + +    assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-'); + +    if (SI == FlagSet.end()) +      FlagSet[Flag.substr(1)] = I; +    else if (Flags[I] != Flags[SI->getValue()]) +      return false; +  } +  return true; +} + +bool Multilib::operator==(const Multilib &Other) const { +  // Check whether the flags sets match +  // allowing for the match to be order invariant +  llvm::StringSet<> MyFlags; +  for (const auto &Flag : Flags) +    MyFlags.insert(Flag); + +  for (const auto &Flag : Other.Flags) +    if (MyFlags.find(Flag) == MyFlags.end()) +      return false; + +  if (osSuffix() != Other.osSuffix()) +    return false; + +  if (gccSuffix() != Other.gccSuffix()) +    return false; + +  if (includeSuffix() != Other.includeSuffix()) +    return false; + +  return true; +} + +raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) { +  M.print(OS); +  return OS; +} + +MultilibSet &MultilibSet::Maybe(const Multilib &M) { +  Multilib Opposite; +  // Negate any '+' flags +  for (StringRef Flag : M.flags()) { +    if (Flag.front() == '+') +      Opposite.flags().push_back(("-" + Flag.substr(1)).str()); +  } +  return Either(M, Opposite); +} + +MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) { +  return Either({M1, M2}); +} + +MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, +                                 const Multilib &M3) { +  return Either({M1, M2, M3}); +} + +MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, +                                 const Multilib &M3, const Multilib &M4) { +  return Either({M1, M2, M3, M4}); +} + +MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, +                                 const Multilib &M3, const Multilib &M4, +                                 const Multilib &M5) { +  return Either({M1, M2, M3, M4, M5}); +} + +static Multilib compose(const Multilib &Base, const Multilib &New) { +  SmallString<128> GCCSuffix; +  llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); +  SmallString<128> OSSuffix; +  llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); +  SmallString<128> IncludeSuffix; +  llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), +                          New.includeSuffix()); + +  Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix); + +  Multilib::flags_list &Flags = Composed.flags(); + +  Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); +  Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); + +  return Composed; +} + +MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) { +  multilib_list Composed; + +  if (Multilibs.empty()) +    Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), +                     MultilibSegments.end()); +  else { +    for (const auto &New : MultilibSegments) { +      for (const auto &Base : *this) { +        Multilib MO = compose(Base, New); +        if (MO.isValid()) +          Composed.push_back(MO); +      } +    } + +    Multilibs = Composed; +  } + +  return *this; +} + +MultilibSet &MultilibSet::FilterOut(FilterCallback F) { +  filterInPlace(F, Multilibs); +  return *this; +} + +MultilibSet &MultilibSet::FilterOut(const char *Regex) { +  llvm::Regex R(Regex); +#ifndef NDEBUG +  std::string Error; +  if (!R.isValid(Error)) { +    llvm::errs() << Error; +    llvm_unreachable("Invalid regex!"); +  } +#endif + +  filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); }, +                Multilibs); +  return *this; +} + +void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } + +void MultilibSet::combineWith(const MultilibSet &Other) { +  Multilibs.insert(Multilibs.end(), Other.begin(), Other.end()); +} + +static bool isFlagEnabled(StringRef Flag) { +  char Indicator = Flag.front(); +  assert(Indicator == '+' || Indicator == '-'); +  return Indicator == '+'; +} + +bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { +  llvm::StringMap<bool> FlagSet; + +  // Stuff all of the flags into the FlagSet such that a true mappend indicates +  // the flag was enabled, and a false mappend indicates the flag was disabled. +  for (StringRef Flag : Flags) +    FlagSet[Flag.substr(1)] = isFlagEnabled(Flag); + +  multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) { +    for (StringRef Flag : M.flags()) { +      llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1)); +      if (SI != FlagSet.end()) +        if (SI->getValue() != isFlagEnabled(Flag)) +          return true; +    } +    return false; +  }, Multilibs); + +  if (Filtered.empty()) +    return false; +  if (Filtered.size() == 1) { +    M = Filtered[0]; +    return true; +  } + +  // Sort multilibs by priority and select the one with the highest priority. +  llvm::sort(Filtered.begin(), Filtered.end(), +             [](const Multilib &a, const Multilib &b) -> bool { +               return a.priority() > b.priority(); +             }); + +  if (Filtered[0].priority() > Filtered[1].priority()) { +    M = Filtered[0]; +    return true; +  } + +  // TODO: We should consider returning llvm::Error rather than aborting. +  assert(false && "More than one multilib with the same priority"); +  return false; +} + +LLVM_DUMP_METHOD void MultilibSet::dump() const { +  print(llvm::errs()); +} + +void MultilibSet::print(raw_ostream &OS) const { +  for (const auto &M : *this) +    OS << M << "\n"; +} + +MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F, +                                                   const multilib_list &Ms) { +  multilib_list Copy(Ms); +  filterInPlace(F, Copy); +  return Copy; +} + +void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) { +  Ms.erase(std::remove_if(Ms.begin(), Ms.end(), F), Ms.end()); +} + +raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { +  MS.print(OS); +  return OS; +} diff --git a/clang/lib/Driver/Phases.cpp b/clang/lib/Driver/Phases.cpp new file mode 100644 index 0000000000000..01598c59bd9eb --- /dev/null +++ b/clang/lib/Driver/Phases.cpp @@ -0,0 +1,27 @@ +//===--- Phases.cpp - Transformations on Driver Types ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Phases.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> + +using namespace clang::driver; + +const char *phases::getPhaseName(ID Id) { +  switch (Id) { +  case Preprocess: return "preprocessor"; +  case Precompile: return "precompiler"; +  case Compile: return "compiler"; +  case Backend: return "backend"; +  case Assemble: return "assembler"; +  case Link: return "linker"; +  case IfsMerge: return "ifsmerger"; +  } + +  llvm_unreachable("Invalid phase id."); +} diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp new file mode 100644 index 0000000000000..cc6c5e6ef438d --- /dev/null +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -0,0 +1,1160 @@ +//===--- SanitizerArgs.cpp - Arguments for sanitizer tools  ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "clang/Driver/SanitizerArgs.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SpecialCaseList.h" +#include "llvm/Support/TargetParser.h" +#include <memory> + +using namespace clang; +using namespace clang::driver; +using namespace llvm::opt; + +static const SanitizerMask NeedsUbsanRt = +    SanitizerKind::Undefined | SanitizerKind::Integer | +    SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | +    SanitizerKind::CFI | SanitizerKind::FloatDivideByZero; +static const SanitizerMask NeedsUbsanCxxRt = +    SanitizerKind::Vptr | SanitizerKind::CFI; +static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; +static const SanitizerMask NotAllowedWithMinimalRuntime = +    SanitizerKind::Function | SanitizerKind::Vptr; +static const SanitizerMask RequiresPIE = +    SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo; +static const SanitizerMask NeedsUnwindTables = +    SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | +    SanitizerKind::Memory | SanitizerKind::DataFlow; +static const SanitizerMask SupportsCoverage = +    SanitizerKind::Address | SanitizerKind::HWAddress | +    SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | +    SanitizerKind::MemTag | SanitizerKind::Memory | +    SanitizerKind::KernelMemory | SanitizerKind::Leak | +    SanitizerKind::Undefined | SanitizerKind::Integer | +    SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | +    SanitizerKind::DataFlow | SanitizerKind::Fuzzer | +    SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero | +    SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack; +static const SanitizerMask RecoverableByDefault = +    SanitizerKind::Undefined | SanitizerKind::Integer | +    SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | +    SanitizerKind::FloatDivideByZero; +static const SanitizerMask Unrecoverable = +    SanitizerKind::Unreachable | SanitizerKind::Return; +static const SanitizerMask AlwaysRecoverable = +    SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress; +static const SanitizerMask LegacyFsanitizeRecoverMask = +    SanitizerKind::Undefined | SanitizerKind::Integer; +static const SanitizerMask NeedsLTO = SanitizerKind::CFI; +static const SanitizerMask TrappingSupported = +    (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | +    SanitizerKind::UnsignedIntegerOverflow | SanitizerKind::ImplicitConversion | +    SanitizerKind::Nullability | SanitizerKind::LocalBounds | +    SanitizerKind::CFI | SanitizerKind::FloatDivideByZero; +static const SanitizerMask TrappingDefault = SanitizerKind::CFI; +static const SanitizerMask CFIClasses = +    SanitizerKind::CFIVCall | SanitizerKind::CFINVCall | +    SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast | +    SanitizerKind::CFIUnrelatedCast; +static const SanitizerMask CompatibleWithMinimalRuntime = +    TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack; + +enum CoverageFeature { +  CoverageFunc = 1 << 0, +  CoverageBB = 1 << 1, +  CoverageEdge = 1 << 2, +  CoverageIndirCall = 1 << 3, +  CoverageTraceBB = 1 << 4,  // Deprecated. +  CoverageTraceCmp = 1 << 5, +  CoverageTraceDiv = 1 << 6, +  CoverageTraceGep = 1 << 7, +  Coverage8bitCounters = 1 << 8,  // Deprecated. +  CoverageTracePC = 1 << 9, +  CoverageTracePCGuard = 1 << 10, +  CoverageNoPrune = 1 << 11, +  CoverageInline8bitCounters = 1 << 12, +  CoveragePCTable = 1 << 13, +  CoverageStackDepth = 1 << 14, +}; + +/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any +/// invalid components. Returns a SanitizerMask. +static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, +                                    bool DiagnoseErrors); + +/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid +/// components. Returns OR of members of \c CoverageFeature enumeration. +static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A); + +/// Produce an argument string from ArgList \p Args, which shows how it +/// provides some sanitizer kind from \p Mask. For example, the argument list +/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt +/// would produce "-fsanitize=vptr". +static std::string lastArgumentForMask(const Driver &D, +                                       const llvm::opt::ArgList &Args, +                                       SanitizerMask Mask); + +/// Produce an argument string from argument \p A, which shows how it provides +/// a value in \p Mask. For instance, the argument +/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce +/// "-fsanitize=alignment". +static std::string describeSanitizeArg(const llvm::opt::Arg *A, +                                       SanitizerMask Mask); + +/// Produce a string containing comma-separated names of sanitizers in \p +/// Sanitizers set. +static std::string toString(const clang::SanitizerSet &Sanitizers); + +static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds, +                                 std::vector<std::string> &BlacklistFiles) { +  struct Blacklist { +    const char *File; +    SanitizerMask Mask; +  } Blacklists[] = {{"asan_blacklist.txt", SanitizerKind::Address}, +                    {"hwasan_blacklist.txt", SanitizerKind::HWAddress}, +                    {"memtag_blacklist.txt", SanitizerKind::MemTag}, +                    {"msan_blacklist.txt", SanitizerKind::Memory}, +                    {"tsan_blacklist.txt", SanitizerKind::Thread}, +                    {"dfsan_abilist.txt", SanitizerKind::DataFlow}, +                    {"cfi_blacklist.txt", SanitizerKind::CFI}, +                    {"ubsan_blacklist.txt", +                     SanitizerKind::Undefined | SanitizerKind::Integer | +                         SanitizerKind::Nullability | +                         SanitizerKind::FloatDivideByZero}}; + +  for (auto BL : Blacklists) { +    if (!(Kinds & BL.Mask)) +      continue; + +    clang::SmallString<64> Path(D.ResourceDir); +    llvm::sys::path::append(Path, "share", BL.File); +    if (llvm::sys::fs::exists(Path)) +      BlacklistFiles.push_back(Path.str()); +    else if (BL.Mask == SanitizerKind::CFI) +      // If cfi_blacklist.txt cannot be found in the resource dir, driver +      // should fail. +      D.Diag(clang::diag::err_drv_no_such_file) << Path; +  } +} + +/// Sets group bits for every group that has at least one representative already +/// enabled in \p Kinds. +static SanitizerMask setGroupBits(SanitizerMask Kinds) { +#define SANITIZER(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \ +  if (Kinds & SanitizerKind::ID)                                               \ +    Kinds |= SanitizerKind::ID##Group; +#include "clang/Basic/Sanitizers.def" +  return Kinds; +} + +static SanitizerMask parseSanitizeTrapArgs(const Driver &D, +                                           const llvm::opt::ArgList &Args) { +  SanitizerMask TrapRemove;     // During the loop below, the accumulated set of +                                // sanitizers disabled by the current sanitizer +                                // argument or any argument after it. +  SanitizerMask TrappingKinds; +  SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); + +  for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); +       I != E; ++I) { +    const auto *Arg = *I; +    if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) { +      Arg->claim(); +      SanitizerMask Add = parseArgValues(D, Arg, true); +      Add &= ~TrapRemove; +      if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) { +        SanitizerSet S; +        S.Mask = InvalidValues; +        D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap" +                                                          << toString(S); +      } +      TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { +      Arg->claim(); +      TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true)); +    } else if (Arg->getOption().matches( +                   options::OPT_fsanitize_undefined_trap_on_error)) { +      Arg->claim(); +      TrappingKinds |= +          expandSanitizerGroups(SanitizerKind::UndefinedGroup & ~TrapRemove) & +          ~TrapRemove; +    } else if (Arg->getOption().matches( +                   options::OPT_fno_sanitize_undefined_trap_on_error)) { +      Arg->claim(); +      TrapRemove |= expandSanitizerGroups(SanitizerKind::UndefinedGroup); +    } +  } + +  // Apply default trapping behavior. +  TrappingKinds |= TrappingDefault & ~TrapRemove; + +  return TrappingKinds; +} + +bool SanitizerArgs::needsUbsanRt() const { +  // All of these include ubsan. +  if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt() || +      needsDfsanRt() || needsLsanRt() || needsCfiDiagRt() || +      (needsScudoRt() && !requiresMinimalRuntime())) +    return false; + +  return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || +         CoverageFeatures; +} + +bool SanitizerArgs::needsCfiRt() const { +  return !(Sanitizers.Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) && +         CfiCrossDso && !ImplicitCfiRuntime; +} + +bool SanitizerArgs::needsCfiDiagRt() const { +  return (Sanitizers.Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) && +         CfiCrossDso && !ImplicitCfiRuntime; +} + +bool SanitizerArgs::requiresPIE() const { +  return NeedPIE || (Sanitizers.Mask & RequiresPIE); +} + +bool SanitizerArgs::needsUnwindTables() const { +  return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables); +} + +bool SanitizerArgs::needsLTO() const { +  return static_cast<bool>(Sanitizers.Mask & NeedsLTO); +} + +SanitizerArgs::SanitizerArgs(const ToolChain &TC, +                             const llvm::opt::ArgList &Args) { +  SanitizerMask AllRemove;      // During the loop below, the accumulated set of +                                // sanitizers disabled by the current sanitizer +                                // argument or any argument after it. +  SanitizerMask AllAddedKinds;      // Mask of all sanitizers ever enabled by +                                    // -fsanitize= flags (directly or via group +                                    // expansion), some of which may be disabled +                                    // later. Used to carefully prune +                                    // unused-argument diagnostics. +  SanitizerMask DiagnosedKinds;      // All Kinds we have diagnosed up to now. +                                     // Used to deduplicate diagnostics. +  SanitizerMask Kinds; +  const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); + +  CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, +                             options::OPT_fno_sanitize_cfi_cross_dso, false); + +  ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); + +  const Driver &D = TC.getDriver(); +  SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); +  SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; + +  MinimalRuntime = +      Args.hasFlag(options::OPT_fsanitize_minimal_runtime, +                   options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); + +  // The object size sanitizer should not be enabled at -O0. +  Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); +  bool RemoveObjectSizeAtO0 = +      !OptLevel || OptLevel->getOption().matches(options::OPT_O0); + +  for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); +       I != E; ++I) { +    const auto *Arg = *I; +    if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { +      Arg->claim(); +      SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true); + +      if (RemoveObjectSizeAtO0) { +        AllRemove |= SanitizerKind::ObjectSize; + +        // The user explicitly enabled the object size sanitizer. Warn +        // that this does nothing at -O0. +        if (Add & SanitizerKind::ObjectSize) +          D.Diag(diag::warn_drv_object_size_disabled_O0) +              << Arg->getAsString(Args); +      } + +      AllAddedKinds |= expandSanitizerGroups(Add); + +      // Avoid diagnosing any sanitizer which is disabled later. +      Add &= ~AllRemove; +      // At this point we have not expanded groups, so any unsupported +      // sanitizers in Add are those which have been explicitly enabled. +      // Diagnose them. +      if (SanitizerMask KindsToDiagnose = +              Add & InvalidTrappingKinds & ~DiagnosedKinds) { +        std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); +        D.Diag(diag::err_drv_argument_not_allowed_with) +            << Desc << "-fsanitize-trap=undefined"; +        DiagnosedKinds |= KindsToDiagnose; +      } +      Add &= ~InvalidTrappingKinds; + +      if (MinimalRuntime) { +        if (SanitizerMask KindsToDiagnose = +                Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) { +          std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); +          D.Diag(diag::err_drv_argument_not_allowed_with) +              << Desc << "-fsanitize-minimal-runtime"; +          DiagnosedKinds |= KindsToDiagnose; +        } +        Add &= ~NotAllowedWithMinimalRuntime; +      } + +      // FIXME: Make CFI on member function calls compatible with cross-DSO CFI. +      // There are currently two problems: +      // - Virtual function call checks need to pass a pointer to the function +      //   address to llvm.type.test and a pointer to the address point to the +      //   diagnostic function. Currently we pass the same pointer to both +      //   places. +      // - Non-virtual function call checks may need to check multiple type +      //   identifiers. +      // Fixing both of those may require changes to the cross-DSO CFI +      // interface. +      if (CfiCrossDso && (Add & SanitizerKind::CFIMFCall & ~DiagnosedKinds)) { +        D.Diag(diag::err_drv_argument_not_allowed_with) +            << "-fsanitize=cfi-mfcall" +            << "-fsanitize-cfi-cross-dso"; +        Add &= ~SanitizerKind::CFIMFCall; +        DiagnosedKinds |= SanitizerKind::CFIMFCall; +      } + +      if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { +        std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); +        D.Diag(diag::err_drv_unsupported_opt_for_target) +            << Desc << TC.getTriple().str(); +        DiagnosedKinds |= KindsToDiagnose; +      } +      Add &= Supported; + +      // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups +      // so we don't error out if -fno-rtti and -fsanitize=undefined were +      // passed. +      if ((Add & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { +        if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) { +          assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) && +                  "RTTI disabled without -fno-rtti option?"); +          // The user explicitly passed -fno-rtti with -fsanitize=vptr, but +          // the vptr sanitizer requires RTTI, so this is a user error. +          D.Diag(diag::err_drv_argument_not_allowed_with) +              << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); +        } else { +          // The vptr sanitizer requires RTTI, but RTTI is disabled (by +          // default). Warn that the vptr sanitizer is being disabled. +          D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); +        } + +        // Take out the Vptr sanitizer from the enabled sanitizers +        AllRemove |= SanitizerKind::Vptr; +      } + +      Add = expandSanitizerGroups(Add); +      // Group expansion may have enabled a sanitizer which is disabled later. +      Add &= ~AllRemove; +      // Silently discard any unsupported sanitizers implicitly enabled through +      // group expansion. +      Add &= ~InvalidTrappingKinds; +      if (MinimalRuntime) { +        Add &= ~NotAllowedWithMinimalRuntime; +      } +      if (CfiCrossDso) +        Add &= ~SanitizerKind::CFIMFCall; +      Add &= Supported; + +      if (Add & SanitizerKind::Fuzzer) +        Add |= SanitizerKind::FuzzerNoLink; + +      // Enable coverage if the fuzzing flag is set. +      if (Add & SanitizerKind::FuzzerNoLink) { +        CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall | +                            CoverageTraceCmp | CoveragePCTable; +        // Due to TLS differences, stack depth tracking is only enabled on Linux +        if (TC.getTriple().isOSLinux()) +          CoverageFeatures |= CoverageStackDepth; +      } + +      Kinds |= Add; +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { +      Arg->claim(); +      SanitizerMask Remove = parseArgValues(D, Arg, true); +      AllRemove |= expandSanitizerGroups(Remove); +    } +  } + +  std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = { +      std::make_pair(SanitizerKind::Address, +                     SanitizerKind::Thread | SanitizerKind::Memory), +      std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory), +      std::make_pair(SanitizerKind::Leak, +                     SanitizerKind::Thread | SanitizerKind::Memory), +      std::make_pair(SanitizerKind::KernelAddress, +                     SanitizerKind::Address | SanitizerKind::Leak | +                         SanitizerKind::Thread | SanitizerKind::Memory), +      std::make_pair(SanitizerKind::HWAddress, +                     SanitizerKind::Address | SanitizerKind::Thread | +                         SanitizerKind::Memory | SanitizerKind::KernelAddress), +      std::make_pair(SanitizerKind::Scudo, +                     SanitizerKind::Address | SanitizerKind::HWAddress | +                         SanitizerKind::Leak | SanitizerKind::Thread | +                         SanitizerKind::Memory | SanitizerKind::KernelAddress), +      std::make_pair(SanitizerKind::SafeStack, +                     SanitizerKind::Address | SanitizerKind::HWAddress | +                         SanitizerKind::Leak | SanitizerKind::Thread | +                         SanitizerKind::Memory | SanitizerKind::KernelAddress), +      std::make_pair(SanitizerKind::KernelHWAddress, +                     SanitizerKind::Address | SanitizerKind::HWAddress | +                         SanitizerKind::Leak | SanitizerKind::Thread | +                         SanitizerKind::Memory | SanitizerKind::KernelAddress | +                         SanitizerKind::SafeStack), +      std::make_pair(SanitizerKind::KernelMemory, +                     SanitizerKind::Address | SanitizerKind::HWAddress | +                         SanitizerKind::Leak | SanitizerKind::Thread | +                         SanitizerKind::Memory | SanitizerKind::KernelAddress | +                         SanitizerKind::Scudo | SanitizerKind::SafeStack), +      std::make_pair(SanitizerKind::MemTag, +                     SanitizerKind::Address | SanitizerKind::KernelAddress | +                         SanitizerKind::HWAddress | +                         SanitizerKind::KernelHWAddress)}; +  // Enable toolchain specific default sanitizers if not explicitly disabled. +  SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove; + +  // Disable default sanitizers that are incompatible with explicitly requested +  // ones. +  for (auto G : IncompatibleGroups) { +    SanitizerMask Group = G.first; +    if ((Default & Group) && (Kinds & G.second)) +      Default &= ~Group; +  } + +  Kinds |= Default; + +  // We disable the vptr sanitizer if it was enabled by group expansion but RTTI +  // is disabled. +  if ((Kinds & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { +    Kinds &= ~SanitizerKind::Vptr; +  } + +  // Check that LTO is enabled if we need it. +  if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { +    D.Diag(diag::err_drv_argument_only_allowed_with) +        << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; +  } + +  if ((Kinds & SanitizerKind::ShadowCallStack) && +      TC.getTriple().getArch() == llvm::Triple::aarch64 && +      !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && +      !Args.hasArg(options::OPT_ffixed_x18)) { +    D.Diag(diag::err_drv_argument_only_allowed_with) +        << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack) +        << "-ffixed-x18"; +  } + +  // Report error if there are non-trapping sanitizers that require +  // c++abi-specific  parts of UBSan runtime, and they are not provided by the +  // toolchain. We don't have a good way to check the latter, so we just +  // check if the toolchan supports vptr. +  if (~Supported & SanitizerKind::Vptr) { +    SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; +    // The runtime library supports the Microsoft C++ ABI, but only well enough +    // for CFI. FIXME: Remove this once we support vptr on Windows. +    if (TC.getTriple().isOSWindows()) +      KindsToDiagnose &= ~SanitizerKind::CFI; +    if (KindsToDiagnose) { +      SanitizerSet S; +      S.Mask = KindsToDiagnose; +      D.Diag(diag::err_drv_unsupported_opt_for_target) +          << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); +      Kinds &= ~KindsToDiagnose; +    } +  } + +  // Warn about incompatible groups of sanitizers. +  for (auto G : IncompatibleGroups) { +    SanitizerMask Group = G.first; +    if (Kinds & Group) { +      if (SanitizerMask Incompatible = Kinds & G.second) { +        D.Diag(clang::diag::err_drv_argument_not_allowed_with) +            << lastArgumentForMask(D, Args, Group) +            << lastArgumentForMask(D, Args, Incompatible); +        Kinds &= ~Incompatible; +      } +    } +  } +  // FIXME: Currently -fsanitize=leak is silently ignored in the presence of +  // -fsanitize=address. Perhaps it should print an error, or perhaps +  // -f(-no)sanitize=leak should change whether leak detection is enabled by +  // default in ASan? + +  // Parse -f(no-)?sanitize-recover flags. +  SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable; +  SanitizerMask DiagnosedUnrecoverableKinds; +  SanitizerMask DiagnosedAlwaysRecoverableKinds; +  for (const auto *Arg : Args) { +    const char *DeprecatedReplacement = nullptr; +    if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { +      DeprecatedReplacement = +          "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all"; +      RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask); +      Arg->claim(); +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) { +      DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer' or " +                              "'-fno-sanitize-recover=all"; +      RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask); +      Arg->claim(); +    } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { +      SanitizerMask Add = parseArgValues(D, Arg, true); +      // Report error if user explicitly tries to recover from unrecoverable +      // sanitizer. +      if (SanitizerMask KindsToDiagnose = +              Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { +        SanitizerSet SetToDiagnose; +        SetToDiagnose.Mask |= KindsToDiagnose; +        D.Diag(diag::err_drv_unsupported_option_argument) +            << Arg->getOption().getName() << toString(SetToDiagnose); +        DiagnosedUnrecoverableKinds |= KindsToDiagnose; +      } +      RecoverableKinds |= expandSanitizerGroups(Add); +      Arg->claim(); +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { +      SanitizerMask Remove = parseArgValues(D, Arg, true); +      // Report error if user explicitly tries to disable recovery from +      // always recoverable sanitizer. +      if (SanitizerMask KindsToDiagnose = +              Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) { +        SanitizerSet SetToDiagnose; +        SetToDiagnose.Mask |= KindsToDiagnose; +        D.Diag(diag::err_drv_unsupported_option_argument) +            << Arg->getOption().getName() << toString(SetToDiagnose); +        DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; +      } +      RecoverableKinds &= ~expandSanitizerGroups(Remove); +      Arg->claim(); +    } +    if (DeprecatedReplacement) { +      D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) +                                            << DeprecatedReplacement; +    } +  } +  RecoverableKinds &= Kinds; +  RecoverableKinds &= ~Unrecoverable; + +  TrappingKinds &= Kinds; +  RecoverableKinds &= ~TrappingKinds; + +  // Setup blacklist files. +  // Add default blacklist from resource directory. +  addDefaultBlacklists(D, Kinds, BlacklistFiles); +  // Parse -f(no-)sanitize-blacklist options. +  for (const auto *Arg : Args) { +    if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { +      Arg->claim(); +      std::string BLPath = Arg->getValue(); +      if (llvm::sys::fs::exists(BLPath)) { +        BlacklistFiles.push_back(BLPath); +        ExtraDeps.push_back(BLPath); +      } else { +        D.Diag(clang::diag::err_drv_no_such_file) << BLPath; +      } +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { +      Arg->claim(); +      BlacklistFiles.clear(); +      ExtraDeps.clear(); +    } +  } +  // Validate blacklists format. +  { +    std::string BLError; +    std::unique_ptr<llvm::SpecialCaseList> SCL( +        llvm::SpecialCaseList::create(BlacklistFiles, BLError)); +    if (!SCL.get()) +      D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; +  } + +  // Parse -f[no-]sanitize-memory-track-origins[=level] options. +  if (AllAddedKinds & SanitizerKind::Memory) { +    if (Arg *A = +            Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, +                            options::OPT_fsanitize_memory_track_origins, +                            options::OPT_fno_sanitize_memory_track_origins)) { +      if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { +        MsanTrackOrigins = 2; +      } else if (A->getOption().matches( +                     options::OPT_fno_sanitize_memory_track_origins)) { +        MsanTrackOrigins = 0; +      } else { +        StringRef S = A->getValue(); +        if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || +            MsanTrackOrigins > 2) { +          D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; +        } +      } +    } +    MsanUseAfterDtor = +        Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, +                     options::OPT_fno_sanitize_memory_use_after_dtor, +                     MsanUseAfterDtor); +    NeedPIE |= !(TC.getTriple().isOSLinux() && +                 TC.getTriple().getArch() == llvm::Triple::x86_64); +  } else { +    MsanUseAfterDtor = false; +  } + +  if (AllAddedKinds & SanitizerKind::Thread) { +    TsanMemoryAccess = Args.hasFlag( +        options::OPT_fsanitize_thread_memory_access, +        options::OPT_fno_sanitize_thread_memory_access, TsanMemoryAccess); +    TsanFuncEntryExit = Args.hasFlag( +        options::OPT_fsanitize_thread_func_entry_exit, +        options::OPT_fno_sanitize_thread_func_entry_exit, TsanFuncEntryExit); +    TsanAtomics = +        Args.hasFlag(options::OPT_fsanitize_thread_atomics, +                     options::OPT_fno_sanitize_thread_atomics, TsanAtomics); +  } + +  if (AllAddedKinds & SanitizerKind::CFI) { +    // Without PIE, external function address may resolve to a PLT record, which +    // can not be verified by the target module. +    NeedPIE |= CfiCrossDso; +    CfiICallGeneralizePointers = +        Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers); + +    if (CfiCrossDso && CfiICallGeneralizePointers) +      D.Diag(diag::err_drv_argument_not_allowed_with) +          << "-fsanitize-cfi-cross-dso" +          << "-fsanitize-cfi-icall-generalize-pointers"; + +    CfiCanonicalJumpTables = +        Args.hasFlag(options::OPT_fsanitize_cfi_canonical_jump_tables, +                     options::OPT_fno_sanitize_cfi_canonical_jump_tables, true); +  } + +  Stats = Args.hasFlag(options::OPT_fsanitize_stats, +                       options::OPT_fno_sanitize_stats, false); + +  if (MinimalRuntime) { +    SanitizerMask IncompatibleMask = +        Kinds & ~setGroupBits(CompatibleWithMinimalRuntime); +    if (IncompatibleMask) +      D.Diag(clang::diag::err_drv_argument_not_allowed_with) +          << "-fsanitize-minimal-runtime" +          << lastArgumentForMask(D, Args, IncompatibleMask); + +    SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds; +    if (NonTrappingCfi) +      D.Diag(clang::diag::err_drv_argument_only_allowed_with) +          << "fsanitize-minimal-runtime" +          << "fsanitize-trap=cfi"; +  } + +  // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the +  // enabled sanitizers. +  for (const auto *Arg : Args) { +    if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { +      int LegacySanitizeCoverage; +      if (Arg->getNumValues() == 1 && +          !StringRef(Arg->getValue(0)) +               .getAsInteger(0, LegacySanitizeCoverage)) { +        CoverageFeatures = 0; +        Arg->claim(); +        if (LegacySanitizeCoverage != 0) { +          D.Diag(diag::warn_drv_deprecated_arg) +              << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; +        } +        continue; +      } +      CoverageFeatures |= parseCoverageFeatures(D, Arg); + +      // Disable coverage and not claim the flags if there is at least one +      // non-supporting sanitizer. +      if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) { +        Arg->claim(); +      } else { +        CoverageFeatures = 0; +      } +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { +      Arg->claim(); +      CoverageFeatures &= ~parseCoverageFeatures(D, Arg); +    } +  } +  // Choose at most one coverage type: function, bb, or edge. +  if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) +    D.Diag(clang::diag::err_drv_argument_not_allowed_with) +        << "-fsanitize-coverage=func" +        << "-fsanitize-coverage=bb"; +  if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) +    D.Diag(clang::diag::err_drv_argument_not_allowed_with) +        << "-fsanitize-coverage=func" +        << "-fsanitize-coverage=edge"; +  if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) +    D.Diag(clang::diag::err_drv_argument_not_allowed_with) +        << "-fsanitize-coverage=bb" +        << "-fsanitize-coverage=edge"; +  // Basic block tracing and 8-bit counters require some type of coverage +  // enabled. +  if (CoverageFeatures & CoverageTraceBB) +    D.Diag(clang::diag::warn_drv_deprecated_arg) +        << "-fsanitize-coverage=trace-bb" +        << "-fsanitize-coverage=trace-pc-guard"; +  if (CoverageFeatures & Coverage8bitCounters) +    D.Diag(clang::diag::warn_drv_deprecated_arg) +        << "-fsanitize-coverage=8bit-counters" +        << "-fsanitize-coverage=trace-pc-guard"; + +  int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; +  int InstrumentationTypes = +      CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters; +  if ((CoverageFeatures & InsertionPointTypes) && +      !(CoverageFeatures & InstrumentationTypes)) { +    D.Diag(clang::diag::warn_drv_deprecated_arg) +        << "-fsanitize-coverage=[func|bb|edge]" +        << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; +  } + +  // trace-pc w/o func/bb/edge implies edge. +  if (!(CoverageFeatures & InsertionPointTypes)) { +    if (CoverageFeatures & +        (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) +      CoverageFeatures |= CoverageEdge; + +    if (CoverageFeatures & CoverageStackDepth) +      CoverageFeatures |= CoverageFunc; +  } + +  SharedRuntime = +      Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, +                   TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || +                       TC.getTriple().isOSDarwin()); + +  ImplicitCfiRuntime = TC.getTriple().isAndroid(); + +  if (AllAddedKinds & SanitizerKind::Address) { +    NeedPIE |= TC.getTriple().isOSFuchsia(); +    if (Arg *A = +            Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { +        StringRef S = A->getValue(); +        // Legal values are 0 and 1, 2, but in future we may add more levels. +        if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || +            AsanFieldPadding > 2) { +          D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; +        } +    } + +    if (Arg *WindowsDebugRTArg = +            Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, +                            options::OPT__SLASH_MDd, options::OPT__SLASH_MD, +                            options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { +      switch (WindowsDebugRTArg->getOption().getID()) { +      case options::OPT__SLASH_MTd: +      case options::OPT__SLASH_MDd: +      case options::OPT__SLASH_LDd: +        D.Diag(clang::diag::err_drv_argument_not_allowed_with) +            << WindowsDebugRTArg->getAsString(Args) +            << lastArgumentForMask(D, Args, SanitizerKind::Address); +        D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); +      } +    } + +    AsanUseAfterScope = Args.hasFlag( +        options::OPT_fsanitize_address_use_after_scope, +        options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope); + +    AsanPoisonCustomArrayCookie = Args.hasFlag( +        options::OPT_fsanitize_address_poison_custom_array_cookie, +        options::OPT_fno_sanitize_address_poison_custom_array_cookie, +        AsanPoisonCustomArrayCookie); + +    // As a workaround for a bug in gold 2.26 and earlier, dead stripping of +    // globals in ASan is disabled by default on ELF targets. +    // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 +    AsanGlobalsDeadStripping = +        !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || +        TC.getTriple().isPS4() || +        Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); + +    AsanUseOdrIndicator = +        Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator, +                     options::OPT_fno_sanitize_address_use_odr_indicator, +                     AsanUseOdrIndicator); + +    if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) { +      AsanInvalidPointerCmp = true; +    } + +    if (AllAddedKinds & SanitizerKind::PointerSubtract & ~AllRemove) { +      AsanInvalidPointerSub = true; +    } + +  } else { +    AsanUseAfterScope = false; +    // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address. +    SanitizerMask DetectInvalidPointerPairs = +        SanitizerKind::PointerCompare | SanitizerKind::PointerSubtract; +    if (AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) { +      TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) +          << lastArgumentForMask(D, Args, +                                 SanitizerKind::PointerCompare | +                                     SanitizerKind::PointerSubtract) +          << "-fsanitize=address"; +    } +  } + +  if (AllAddedKinds & SanitizerKind::HWAddress) { +    if (Arg *HwasanAbiArg = +            Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) { +      HwasanAbi = HwasanAbiArg->getValue(); +      if (HwasanAbi != "platform" && HwasanAbi != "interceptor") +        D.Diag(clang::diag::err_drv_invalid_value) +            << HwasanAbiArg->getAsString(Args) << HwasanAbi; +    } else { +      HwasanAbi = "interceptor"; +    } +  } + +  if (AllAddedKinds & SanitizerKind::SafeStack) { +    // SafeStack runtime is built into the system on Fuchsia. +    SafeStackRuntime = !TC.getTriple().isOSFuchsia(); +  } + +  LinkRuntimes = +      Args.hasFlag(options::OPT_fsanitize_link_runtime, +                   options::OPT_fno_sanitize_link_runtime, LinkRuntimes); + +  // Parse -link-cxx-sanitizer flag. +  LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime, +                                options::OPT_fno_sanitize_link_cxx_runtime, +                                LinkCXXRuntimes) || +                    D.CCCIsCXX(); + +  // Finally, initialize the set of available and recoverable sanitizers. +  Sanitizers.Mask |= Kinds; +  RecoverableSanitizers.Mask |= RecoverableKinds; +  TrapSanitizers.Mask |= TrappingKinds; +  assert(!(RecoverableKinds & TrappingKinds) && +         "Overlap between recoverable and trapping sanitizers"); +} + +static std::string toString(const clang::SanitizerSet &Sanitizers) { +  std::string Res; +#define SANITIZER(NAME, ID)                                                    \ +  if (Sanitizers.has(SanitizerKind::ID)) {                                     \ +    if (!Res.empty())                                                          \ +      Res += ",";                                                              \ +    Res += NAME;                                                               \ +  } +#include "clang/Basic/Sanitizers.def" +  return Res; +} + +static void addIncludeLinkerOption(const ToolChain &TC, +                                   const llvm::opt::ArgList &Args, +                                   llvm::opt::ArgStringList &CmdArgs, +                                   StringRef SymbolName) { +  SmallString<64> LinkerOptionFlag; +  LinkerOptionFlag = "--linker-option=/include:"; +  if (TC.getTriple().getArch() == llvm::Triple::x86) { +    // Win32 mangles C function names with a '_' prefix. +    LinkerOptionFlag += '_'; +  } +  LinkerOptionFlag += SymbolName; +  CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag)); +} + +static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs) { +  for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End; ++Start) { +    auto It = std::find(Start, End, StringRef("+mte")); +    if (It == End) +      break; +    if (It > Start && *std::prev(It) == StringRef("-target-feature")) +      return true; +    Start = It; +  } +  return false; +} + +void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, +                            llvm::opt::ArgStringList &CmdArgs, +                            types::ID InputType) const { +  // NVPTX doesn't currently support sanitizers.  Bailing out here means that +  // e.g. -fsanitize=address applies only to host code, which is what we want +  // for now. +  if (TC.getTriple().isNVPTX()) +    return; + +  // Translate available CoverageFeatures to corresponding clang-cc1 flags. +  // Do it even if Sanitizers.empty() since some forms of coverage don't require +  // sanitizers. +  std::pair<int, const char *> CoverageFlags[] = { +    std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), +    std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), +    std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), +    std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), +    std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), +    std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), +    std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), +    std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), +    std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), +    std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), +    std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"), +    std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"), +    std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), +    std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), +    std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; +  for (auto F : CoverageFlags) { +    if (CoverageFeatures & F.first) +      CmdArgs.push_back(F.second); +  } + +  if (TC.getTriple().isOSWindows() && needsUbsanRt()) { +    // Instruct the code generator to embed linker directives in the object file +    // that cause the required runtime libraries to be linked. +    CmdArgs.push_back(Args.MakeArgString( +        "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone"))); +    if (types::isCXX(InputType)) +      CmdArgs.push_back(Args.MakeArgString( +          "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx"))); +  } +  if (TC.getTriple().isOSWindows() && needsStatsRt()) { +    CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + +                                         TC.getCompilerRT(Args, "stats_client"))); + +    // The main executable must export the stats runtime. +    // FIXME: Only exporting from the main executable (e.g. based on whether the +    // translation unit defines main()) would save a little space, but having +    // multiple copies of the runtime shouldn't hurt. +    CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + +                                         TC.getCompilerRT(Args, "stats"))); +    addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register"); +  } + +  if (Sanitizers.empty()) +    return; +  CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); + +  if (!RecoverableSanitizers.empty()) +    CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + +                                         toString(RecoverableSanitizers))); + +  if (!TrapSanitizers.empty()) +    CmdArgs.push_back( +        Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); + +  for (const auto &BLPath : BlacklistFiles) { +    SmallString<64> BlacklistOpt("-fsanitize-blacklist="); +    BlacklistOpt += BLPath; +    CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); +  } +  for (const auto &Dep : ExtraDeps) { +    SmallString<64> ExtraDepOpt("-fdepfile-entry="); +    ExtraDepOpt += Dep; +    CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); +  } + +  if (MsanTrackOrigins) +    CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + +                                         Twine(MsanTrackOrigins))); + +  if (MsanUseAfterDtor) +    CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); + +  // FIXME: Pass these parameters as function attributes, not as -llvm flags. +  if (!TsanMemoryAccess) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-tsan-instrument-memory-accesses=0"); +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-tsan-instrument-memintrinsics=0"); +  } +  if (!TsanFuncEntryExit) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-tsan-instrument-func-entry-exit=0"); +  } +  if (!TsanAtomics) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-tsan-instrument-atomics=0"); +  } + +  if (CfiCrossDso) +    CmdArgs.push_back("-fsanitize-cfi-cross-dso"); + +  if (CfiICallGeneralizePointers) +    CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers"); + +  if (CfiCanonicalJumpTables) +    CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables"); + +  if (Stats) +    CmdArgs.push_back("-fsanitize-stats"); + +  if (MinimalRuntime) +    CmdArgs.push_back("-fsanitize-minimal-runtime"); + +  if (AsanFieldPadding) +    CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + +                                         Twine(AsanFieldPadding))); + +  if (AsanUseAfterScope) +    CmdArgs.push_back("-fsanitize-address-use-after-scope"); + +  if (AsanPoisonCustomArrayCookie) +    CmdArgs.push_back("-fsanitize-address-poison-custom-array-cookie"); + +  if (AsanGlobalsDeadStripping) +    CmdArgs.push_back("-fsanitize-address-globals-dead-stripping"); + +  if (AsanUseOdrIndicator) +    CmdArgs.push_back("-fsanitize-address-use-odr-indicator"); + +  if (AsanInvalidPointerCmp) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-asan-detect-invalid-pointer-cmp"); +  } + +  if (AsanInvalidPointerSub) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-asan-detect-invalid-pointer-sub"); +  } + +  if (!HwasanAbi.empty()) { +    CmdArgs.push_back("-default-function-attr"); +    CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi)); +  } + +  if (Sanitizers.has(SanitizerKind::HWAddress)) { +    CmdArgs.push_back("-target-feature"); +    CmdArgs.push_back("+tagged-globals"); +  } + +  // MSan: Workaround for PR16386. +  // ASan: This is mainly to help LSan with cases such as +  // https://github.com/google/sanitizers/issues/373 +  // We can't make this conditional on -fsanitize=leak, as that flag shouldn't +  // affect compilation. +  if (Sanitizers.has(SanitizerKind::Memory) || +      Sanitizers.has(SanitizerKind::Address)) +    CmdArgs.push_back("-fno-assume-sane-operator-new"); + +  // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is +  // enabled. +  if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() && +      !Args.hasArg(options::OPT_fvisibility_EQ)) { +    TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) +        << lastArgumentForMask(TC.getDriver(), Args, +                               Sanitizers.Mask & CFIClasses) +        << "-fvisibility="; +  } + +  if (Sanitizers.has(SanitizerKind::MemTag) && !hasTargetFeatureMTE(CmdArgs)) +    TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature); +} + +SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, +                             bool DiagnoseErrors) { +  assert((A->getOption().matches(options::OPT_fsanitize_EQ) || +          A->getOption().matches(options::OPT_fno_sanitize_EQ) || +          A->getOption().matches(options::OPT_fsanitize_recover_EQ) || +          A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || +          A->getOption().matches(options::OPT_fsanitize_trap_EQ) || +          A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && +         "Invalid argument in parseArgValues!"); +  SanitizerMask Kinds; +  for (int i = 0, n = A->getNumValues(); i != n; ++i) { +    const char *Value = A->getValue(i); +    SanitizerMask Kind; +    // Special case: don't accept -fsanitize=all. +    if (A->getOption().matches(options::OPT_fsanitize_EQ) && +        0 == strcmp("all", Value)) +      Kind = SanitizerMask(); +    else +      Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); + +    if (Kind) +      Kinds |= Kind; +    else if (DiagnoseErrors) +      D.Diag(clang::diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Value; +  } +  return Kinds; +} + +int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { +  assert(A->getOption().matches(options::OPT_fsanitize_coverage) || +         A->getOption().matches(options::OPT_fno_sanitize_coverage)); +  int Features = 0; +  for (int i = 0, n = A->getNumValues(); i != n; ++i) { +    const char *Value = A->getValue(i); +    int F = llvm::StringSwitch<int>(Value) +        .Case("func", CoverageFunc) +        .Case("bb", CoverageBB) +        .Case("edge", CoverageEdge) +        .Case("indirect-calls", CoverageIndirCall) +        .Case("trace-bb", CoverageTraceBB) +        .Case("trace-cmp", CoverageTraceCmp) +        .Case("trace-div", CoverageTraceDiv) +        .Case("trace-gep", CoverageTraceGep) +        .Case("8bit-counters", Coverage8bitCounters) +        .Case("trace-pc", CoverageTracePC) +        .Case("trace-pc-guard", CoverageTracePCGuard) +        .Case("no-prune", CoverageNoPrune) +        .Case("inline-8bit-counters", CoverageInline8bitCounters) +        .Case("pc-table", CoveragePCTable) +        .Case("stack-depth", CoverageStackDepth) +        .Default(0); +    if (F == 0) +      D.Diag(clang::diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Value; +    Features |= F; +  } +  return Features; +} + +std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, +                                SanitizerMask Mask) { +  for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), +                                                  E = Args.rend(); +       I != E; ++I) { +    const auto *Arg = *I; +    if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { +      SanitizerMask AddKinds = +          expandSanitizerGroups(parseArgValues(D, Arg, false)); +      if (AddKinds & Mask) +        return describeSanitizeArg(Arg, Mask); +    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { +      SanitizerMask RemoveKinds = +          expandSanitizerGroups(parseArgValues(D, Arg, false)); +      Mask &= ~RemoveKinds; +    } +  } +  llvm_unreachable("arg list didn't provide expected value"); +} + +std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) { +  assert(A->getOption().matches(options::OPT_fsanitize_EQ) +         && "Invalid argument in describeSanitizerArg!"); + +  std::string Sanitizers; +  for (int i = 0, n = A->getNumValues(); i != n; ++i) { +    if (expandSanitizerGroups( +            parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) & +        Mask) { +      if (!Sanitizers.empty()) +        Sanitizers += ","; +      Sanitizers += A->getValue(i); +    } +  } + +  assert(!Sanitizers.empty() && "arg didn't provide expected value"); +  return "-fsanitize=" + Sanitizers; +} diff --git a/clang/lib/Driver/Tool.cpp b/clang/lib/Driver/Tool.cpp new file mode 100644 index 0000000000000..9ff6e863a1242 --- /dev/null +++ b/clang/lib/Driver/Tool.cpp @@ -0,0 +1,32 @@ +//===--- Tool.cpp - Compilation Tools -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Tool.h" +#include "InputInfo.h" + +using namespace clang::driver; + +Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC, +           ResponseFileSupport _ResponseSupport, +           llvm::sys::WindowsEncodingMethod _ResponseEncoding, +           const char *_ResponseFlag) +    : Name(_Name), ShortName(_ShortName), TheToolChain(TC), +      ResponseSupport(_ResponseSupport), ResponseEncoding(_ResponseEncoding), +      ResponseFlag(_ResponseFlag) {} + +Tool::~Tool() { +} + +void Tool::ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA, +                                       const InputInfoList &Outputs, +                                       const InputInfoList &Inputs, +                                       const llvm::opt::ArgList &TCArgs, +                                       const char *LinkingOutput) const { +  assert(Outputs.size() == 1 && "Expected only one output by default!"); +  ConstructJob(C, JA, Outputs.front(), Inputs, TCArgs, LinkingOutput); +} diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp new file mode 100644 index 0000000000000..357a5106ab393 --- /dev/null +++ b/clang/lib/Driver/ToolChain.cpp @@ -0,0 +1,1076 @@ +//===- ToolChain.cpp - Collections of tools for one platform --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/ToolChain.h" +#include "InputInfo.h" +#include "ToolChains/Arch/ARM.h" +#include "ToolChains/Clang.h" +#include "ToolChains/InterfaceStubs.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/XRayArgs.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <cassert> +#include <cstddef> +#include <cstring> +#include <string> + +using namespace clang; +using namespace driver; +using namespace tools; +using namespace llvm; +using namespace llvm::opt; + +static llvm::opt::Arg *GetRTTIArgument(const ArgList &Args) { +  return Args.getLastArg(options::OPT_mkernel, options::OPT_fapple_kext, +                         options::OPT_fno_rtti, options::OPT_frtti); +} + +static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, +                                             const llvm::Triple &Triple, +                                             const Arg *CachedRTTIArg) { +  // Explicit rtti/no-rtti args +  if (CachedRTTIArg) { +    if (CachedRTTIArg->getOption().matches(options::OPT_frtti)) +      return ToolChain::RM_Enabled; +    else +      return ToolChain::RM_Disabled; +  } + +  // -frtti is default, except for the PS4 CPU. +  return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; +} + +ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, +                     const ArgList &Args) +    : D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)), +      CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)) { +  if (D.CCCIsCXX()) { +    if (auto CXXStdlibPath = getCXXStdlibPath()) +      getFilePaths().push_back(*CXXStdlibPath); +  } + +  if (auto RuntimePath = getRuntimePath()) +    getLibraryPaths().push_back(*RuntimePath); + +  std::string CandidateLibPath = getArchSpecificLibPath(); +  if (getVFS().exists(CandidateLibPath)) +    getFilePaths().push_back(CandidateLibPath); +} + +void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) { +  Triple.setEnvironment(Env); +  if (EffectiveTriple != llvm::Triple()) +    EffectiveTriple.setEnvironment(Env); +} + +ToolChain::~ToolChain() = default; + +llvm::vfs::FileSystem &ToolChain::getVFS() const { +  return getDriver().getVFS(); +} + +bool ToolChain::useIntegratedAs() const { +  return Args.hasFlag(options::OPT_fintegrated_as, +                      options::OPT_fno_integrated_as, +                      IsIntegratedAssemblerDefault()); +} + +bool ToolChain::useRelaxRelocations() const { +  return ENABLE_X86_RELAX_RELOCATIONS; +} + +bool ToolChain::isNoExecStackDefault() const { +    return false; +} + +const SanitizerArgs& ToolChain::getSanitizerArgs() const { +  if (!SanitizerArguments.get()) +    SanitizerArguments.reset(new SanitizerArgs(*this, Args)); +  return *SanitizerArguments.get(); +} + +const XRayArgs& ToolChain::getXRayArgs() const { +  if (!XRayArguments.get()) +    XRayArguments.reset(new XRayArgs(*this, Args)); +  return *XRayArguments.get(); +} + +namespace { + +struct DriverSuffix { +  const char *Suffix; +  const char *ModeFlag; +}; + +} // namespace + +static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { +  // A list of known driver suffixes. Suffixes are compared against the +  // program name in order. If there is a match, the frontend type is updated as +  // necessary by applying the ModeFlag. +  static const DriverSuffix DriverSuffixes[] = { +      {"clang", nullptr}, +      {"clang++", "--driver-mode=g++"}, +      {"clang-c++", "--driver-mode=g++"}, +      {"clang-cc", nullptr}, +      {"clang-cpp", "--driver-mode=cpp"}, +      {"clang-g++", "--driver-mode=g++"}, +      {"clang-gcc", nullptr}, +      {"clang-cl", "--driver-mode=cl"}, +      {"cc", nullptr}, +      {"cpp", "--driver-mode=cpp"}, +      {"cl", "--driver-mode=cl"}, +      {"++", "--driver-mode=g++"}, +  }; + +  for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { +    StringRef Suffix(DriverSuffixes[i].Suffix); +    if (ProgName.endswith(Suffix)) { +      Pos = ProgName.size() - Suffix.size(); +      return &DriverSuffixes[i]; +    } +  } +  return nullptr; +} + +/// Normalize the program name from argv[0] by stripping the file extension if +/// present and lower-casing the string on Windows. +static std::string normalizeProgramName(llvm::StringRef Argv0) { +  std::string ProgName = llvm::sys::path::stem(Argv0); +#ifdef _WIN32 +  // Transform to lowercase for case insensitive file systems. +  std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); +#endif +  return ProgName; +} + +static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) { +  // Try to infer frontend type and default target from the program name by +  // comparing it against DriverSuffixes in order. + +  // If there is a match, the function tries to identify a target as prefix. +  // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target +  // prefix "x86_64-linux". If such a target prefix is found, it may be +  // added via -target as implicit first argument. +  const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos); + +  if (!DS) { +    // Try again after stripping any trailing version number: +    // clang++3.5 -> clang++ +    ProgName = ProgName.rtrim("0123456789."); +    DS = FindDriverSuffix(ProgName, Pos); +  } + +  if (!DS) { +    // Try again after stripping trailing -component. +    // clang++-tot -> clang++ +    ProgName = ProgName.slice(0, ProgName.rfind('-')); +    DS = FindDriverSuffix(ProgName, Pos); +  } +  return DS; +} + +ParsedClangName +ToolChain::getTargetAndModeFromProgramName(StringRef PN) { +  std::string ProgName = normalizeProgramName(PN); +  size_t SuffixPos; +  const DriverSuffix *DS = parseDriverSuffix(ProgName, SuffixPos); +  if (!DS) +    return {}; +  size_t SuffixEnd = SuffixPos + strlen(DS->Suffix); + +  size_t LastComponent = ProgName.rfind('-', SuffixPos); +  if (LastComponent == std::string::npos) +    return ParsedClangName(ProgName.substr(0, SuffixEnd), DS->ModeFlag); +  std::string ModeSuffix = ProgName.substr(LastComponent + 1, +                                           SuffixEnd - LastComponent - 1); + +  // Infer target from the prefix. +  StringRef Prefix(ProgName); +  Prefix = Prefix.slice(0, LastComponent); +  std::string IgnoredError; +  bool IsRegistered = llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError); +  return ParsedClangName{Prefix, ModeSuffix, DS->ModeFlag, IsRegistered}; +} + +StringRef 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 +  // an inverse of the darwin::getArchTypeForDarwinArchName() function, but the +  // only interesting special case is powerpc. +  switch (Triple.getArch()) { +  case llvm::Triple::ppc: +    return "ppc"; +  case llvm::Triple::ppc64: +    return "ppc64"; +  case llvm::Triple::ppc64le: +    return "ppc64le"; +  default: +    return Triple.getArchName(); +  } +} + +std::string ToolChain::getInputFilename(const InputInfo &Input) const { +  return Input.getFilename(); +} + +bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) 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::getIfsMerge() const { +  if (!IfsMerge) +    IfsMerge.reset(new tools::ifstool::Merger(*this)); +  return IfsMerge.get(); +} + +Tool *ToolChain::getOffloadBundler() const { +  if (!OffloadBundler) +    OffloadBundler.reset(new tools::OffloadBundler(*this)); +  return OffloadBundler.get(); +} + +Tool *ToolChain::getOffloadWrapper() const { +  if (!OffloadWrapper) +    OffloadWrapper.reset(new tools::OffloadWrapper(*this)); +  return OffloadWrapper.get(); +} + +Tool *ToolChain::getTool(Action::ActionClass AC) const { +  switch (AC) { +  case Action::AssembleJobClass: +    return getAssemble(); + +  case Action::IfsMergeJobClass: +    return getIfsMerge(); + +  case Action::LinkJobClass: +    return getLink(); + +  case Action::InputClass: +  case Action::BindArchClass: +  case Action::OffloadClass: +  case Action::LipoJobClass: +  case Action::DsymutilJobClass: +  case Action::VerifyDebugInfoJobClass: +    llvm_unreachable("Invalid tool kind."); + +  case Action::CompileJobClass: +  case Action::PrecompileJobClass: +  case Action::HeaderModulePrecompileJobClass: +  case Action::PreprocessJobClass: +  case Action::AnalyzeJobClass: +  case Action::MigrateJobClass: +  case Action::VerifyPCHJobClass: +  case Action::BackendJobClass: +    return getClang(); + +  case Action::OffloadBundlingJobClass: +  case Action::OffloadUnbundlingJobClass: +    return getOffloadBundler(); + +  case Action::OffloadWrapperJobClass: +    return getOffloadWrapper(); +  } + +  llvm_unreachable("Invalid tool kind."); +} + +static StringRef getArchNameForCompilerRTLib(const ToolChain &TC, +                                             const ArgList &Args) { +  const llvm::Triple &Triple = TC.getTriple(); +  bool IsWindows = Triple.isOSWindows(); + +  if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) +    return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) +               ? "armhf" +               : "arm"; + +  // For historic reasons, Android library is using i686 instead of i386. +  if (TC.getArch() == llvm::Triple::x86 && Triple.isAndroid()) +    return "i686"; + +  return llvm::Triple::getArchTypeName(TC.getArch()); +} + +StringRef ToolChain::getOSLibName() const { +  switch (Triple.getOS()) { +  case llvm::Triple::FreeBSD: +    return "freebsd"; +  case llvm::Triple::NetBSD: +    return "netbsd"; +  case llvm::Triple::OpenBSD: +    return "openbsd"; +  case llvm::Triple::Solaris: +    return "sunos"; +  default: +    return getOS(); +  } +} + +std::string ToolChain::getCompilerRTPath() const { +  SmallString<128> Path(getDriver().ResourceDir); +  if (Triple.isOSUnknown()) { +    llvm::sys::path::append(Path, "lib"); +  } else { +    llvm::sys::path::append(Path, "lib", getOSLibName()); +  } +  return Path.str(); +} + +std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, +                                     FileType Type) const { +  const llvm::Triple &TT = getTriple(); +  bool IsITANMSVCWindows = +      TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment(); + +  const char *Prefix = +      IsITANMSVCWindows || Type == ToolChain::FT_Object ? "" : "lib"; +  const char *Suffix; +  switch (Type) { +  case ToolChain::FT_Object: +    Suffix = IsITANMSVCWindows ? ".obj" : ".o"; +    break; +  case ToolChain::FT_Static: +    Suffix = IsITANMSVCWindows ? ".lib" : ".a"; +    break; +  case ToolChain::FT_Shared: +    Suffix = Triple.isOSWindows() +                 ? (Triple.isWindowsGNUEnvironment() ? ".dll.a" : ".lib") +                 : ".so"; +    break; +  } + +  for (const auto &LibPath : getLibraryPaths()) { +    SmallString<128> P(LibPath); +    llvm::sys::path::append(P, Prefix + Twine("clang_rt.") + Component + Suffix); +    if (getVFS().exists(P)) +      return P.str(); +  } + +  StringRef Arch = getArchNameForCompilerRTLib(*this, Args); +  const char *Env = TT.isAndroid() ? "-android" : ""; +  SmallString<128> Path(getCompilerRTPath()); +  llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + +                                    Arch + Env + Suffix); +  return Path.str(); +} + +const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, +                                              StringRef Component, +                                              FileType Type) const { +  return Args.MakeArgString(getCompilerRT(Args, Component, Type)); +} + + +Optional<std::string> ToolChain::getRuntimePath() const { +  SmallString<128> P; + +  // First try the triple passed to driver as --target=<triple>. +  P.assign(D.ResourceDir); +  llvm::sys::path::append(P, "lib", D.getTargetTriple()); +  if (getVFS().exists(P)) +    return llvm::Optional<std::string>(P.str()); + +  // Second try the normalized triple. +  P.assign(D.ResourceDir); +  llvm::sys::path::append(P, "lib", Triple.str()); +  if (getVFS().exists(P)) +    return llvm::Optional<std::string>(P.str()); + +  return None; +} + +Optional<std::string> ToolChain::getCXXStdlibPath() const { +  SmallString<128> P; + +  // First try the triple passed to driver as --target=<triple>. +  P.assign(D.Dir); +  llvm::sys::path::append(P, "..", "lib", D.getTargetTriple(), "c++"); +  if (getVFS().exists(P)) +    return llvm::Optional<std::string>(P.str()); + +  // Second try the normalized triple. +  P.assign(D.Dir); +  llvm::sys::path::append(P, "..", "lib", Triple.str(), "c++"); +  if (getVFS().exists(P)) +    return llvm::Optional<std::string>(P.str()); + +  return None; +} + +std::string ToolChain::getArchSpecificLibPath() const { +  SmallString<128> Path(getDriver().ResourceDir); +  llvm::sys::path::append(Path, "lib", getOSLibName(), +                          llvm::Triple::getArchTypeName(getArch())); +  return Path.str(); +} + +bool ToolChain::needsProfileRT(const ArgList &Args) { +  if (Args.hasArg(options::OPT_noprofilelib)) +    return false; + +  if (needsGCovInstrumentation(Args) || +      Args.hasArg(options::OPT_fprofile_generate) || +      Args.hasArg(options::OPT_fprofile_generate_EQ) || +      Args.hasArg(options::OPT_fcs_profile_generate) || +      Args.hasArg(options::OPT_fcs_profile_generate_EQ) || +      Args.hasArg(options::OPT_fprofile_instr_generate) || +      Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || +      Args.hasArg(options::OPT_fcreate_profile) || +      Args.hasArg(options::OPT_forder_file_instrumentation)) +    return true; + +  return false; +} + +bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) { +  return Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, +                      false) || +         Args.hasArg(options::OPT_coverage); +} + +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); +} + +std::string ToolChain::GetProgramPath(const char *Name) const { +  return D.GetProgramPath(Name, *this); +} + +std::string ToolChain::GetLinkerPath() const { +  const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ); +  StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; + +  if (llvm::sys::path::is_absolute(UseLinker)) { +    // If we're passed what looks like an absolute path, don't attempt to +    // second-guess that. +    if (llvm::sys::fs::can_execute(UseLinker)) +      return UseLinker; +  } else if (UseLinker.empty() || UseLinker == "ld") { +    // If we're passed -fuse-ld= with no argument, or with the argument ld, +    // then use whatever the default system linker is. +    return GetProgramPath(getDefaultLinker()); +  } else { +    llvm::SmallString<8> LinkerName; +    if (Triple.isOSDarwin()) +      LinkerName.append("ld64."); +    else +      LinkerName.append("ld."); +    LinkerName.append(UseLinker); + +    std::string LinkerPath(GetProgramPath(LinkerName.c_str())); +    if (llvm::sys::fs::can_execute(LinkerPath)) +      return LinkerPath; +  } + +  if (A) +    getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); + +  return GetProgramPath(getDefaultLinker()); +} + +types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const { +  return types::lookupTypeForExtension(Ext); +} + +bool ToolChain::HasNativeLLVMSupport() const { +  return false; +} + +bool ToolChain::isCrossCompiling() const { +  llvm::Triple HostTriple(LLVM_HOST_TRIPLE); +  switch (HostTriple.getArch()) { +  // The A32/T32/T16 instruction sets are not separate architectures in this +  // context. +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +    return getArch() != llvm::Triple::arm && getArch() != llvm::Triple::thumb && +           getArch() != llvm::Triple::armeb && getArch() != llvm::Triple::thumbeb; +  default: +    return HostTriple.getArch() != getArch(); +  } +} + +ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const { +  return ObjCRuntime(isNonFragile ? ObjCRuntime::GNUstep : ObjCRuntime::GCC, +                     VersionTuple()); +} + +llvm::ExceptionHandling +ToolChain::GetExceptionModel(const llvm::opt::ArgList &Args) const { +  return llvm::ExceptionHandling::None; +} + +bool ToolChain::isThreadModelSupported(const StringRef Model) const { +  if (Model == "single") { +    // FIXME: 'single' is only supported on ARM and WebAssembly so far. +    return Triple.getArch() == llvm::Triple::arm || +           Triple.getArch() == llvm::Triple::armeb || +           Triple.getArch() == llvm::Triple::thumb || +           Triple.getArch() == llvm::Triple::thumbeb || +           Triple.getArch() == llvm::Triple::wasm32 || +           Triple.getArch() == llvm::Triple::wasm64; +  } else if (Model == "posix") +    return true; + +  return false; +} + +std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, +                                         types::ID InputType) const { +  switch (getTriple().getArch()) { +  default: +    return getTripleString(); + +  case llvm::Triple::x86_64: { +    llvm::Triple Triple = getTriple(); +    if (!Triple.isOSBinFormatMachO()) +      return getTripleString(); + +    if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { +      // x86_64h goes in the triple. Other -march options just use the +      // vanilla triple we already have. +      StringRef MArch = A->getValue(); +      if (MArch == "x86_64h") +        Triple.setArchName(MArch); +    } +    return Triple.getTriple(); +  } +  case llvm::Triple::aarch64: { +    llvm::Triple Triple = getTriple(); +    if (!Triple.isOSBinFormatMachO()) +      return getTripleString(); + +    // FIXME: older versions of ld64 expect the "arm64" component in the actual +    // triple string and query it to determine whether an LTO file can be +    // handled. Remove this when we don't care any more. +    Triple.setArchName("arm64"); +    return Triple.getTriple(); +  } +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: { +    // FIXME: Factor into subclasses. +    llvm::Triple Triple = getTriple(); +    bool IsBigEndian = getTriple().getArch() == llvm::Triple::armeb || +                       getTriple().getArch() == llvm::Triple::thumbeb; + +    // Handle pseudo-target flags '-mlittle-endian'/'-EL' and +    // '-mbig-endian'/'-EB'. +    if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, +                                 options::OPT_mbig_endian)) { +      IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); +    } + +    // Thumb2 is the default for V7 on Darwin. +    // +    // FIXME: Thumb should just be another -target-feaure, not in the triple. +    StringRef MCPU, MArch; +    if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) +      MCPU = A->getValue(); +    if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) +      MArch = A->getValue(); +    std::string CPU = +        Triple.isOSBinFormatMachO() +            ? tools::arm::getARMCPUForMArch(MArch, Triple).str() +            : tools::arm::getARMTargetCPU(MCPU, MArch, Triple); +    StringRef Suffix = +      tools::arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); +    bool IsMProfile = ARM::parseArchProfile(Suffix) == ARM::ProfileKind::M; +    bool ThumbDefault = IsMProfile || (ARM::parseArchVersion(Suffix) == 7 && +                                       getTriple().isOSBinFormatMachO()); +    // FIXME: this is invalid for WindowsCE +    if (getTriple().isOSWindows()) +      ThumbDefault = true; +    std::string ArchName; +    if (IsBigEndian) +      ArchName = "armeb"; +    else +      ArchName = "arm"; + +    // Check if ARM ISA was explicitly selected (using -mno-thumb or -marm) for +    // M-Class CPUs/architecture variants, which is not supported. +    bool ARMModeRequested = !Args.hasFlag(options::OPT_mthumb, +                                          options::OPT_mno_thumb, ThumbDefault); +    if (IsMProfile && ARMModeRequested) { +      if (!MCPU.empty()) +        getDriver().Diag(diag::err_cpu_unsupported_isa) << CPU << "ARM"; +       else +        getDriver().Diag(diag::err_arch_unsupported_isa) +          << tools::arm::getARMArch(MArch, getTriple()) << "ARM"; +    } + +    // Check to see if an explicit choice to use thumb has been made via +    // -mthumb. For assembler files we must check for -mthumb in the options +    // passed to the assembler via -Wa or -Xassembler. +    bool IsThumb = false; +    if (InputType != types::TY_PP_Asm) +      IsThumb = Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, +                              ThumbDefault); +    else { +      // Ideally we would check for these flags in +      // CollectArgsForIntegratedAssembler but we can't change the ArchName at +      // that point. There is no assembler equivalent of -mno-thumb, -marm, or +      // -mno-arm. +      for (const auto *A : +           Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { +        for (StringRef Value : A->getValues()) { +          if (Value == "-mthumb") +            IsThumb = true; +        } +      } +    } +    // Assembly files should start in ARM mode, unless arch is M-profile, or +    // -mthumb has been passed explicitly to the assembler. Windows is always +    // thumb. +    if (IsThumb || IsMProfile || getTriple().isOSWindows()) { +      if (IsBigEndian) +        ArchName = "thumbeb"; +      else +        ArchName = "thumb"; +    } +    Triple.setArchName(ArchName + Suffix.str()); + +    return Triple.getTriple(); +  } +  } +} + +std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args, +                                                   types::ID InputType) const { +  return ComputeLLVMTriple(Args, InputType); +} + +void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                          ArgStringList &CC1Args) const { +  // Each toolchain should provide the appropriate include flags. +} + +void ToolChain::addClangTargetOptions( +    const ArgList &DriverArgs, ArgStringList &CC1Args, +    Action::OffloadKind DeviceOffloadKind) const {} + +void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} + +void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, +                                 llvm::opt::ArgStringList &CmdArgs) const { +  if (!needsProfileRT(Args)) return; + +  CmdArgs.push_back(getCompilerRTArgString(Args, "profile")); +} + +ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( +    const ArgList &Args) const { +  const Arg* A = Args.getLastArg(options::OPT_rtlib_EQ); +  StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_RTLIB; + +  // Only use "platform" in tests to override CLANG_DEFAULT_RTLIB! +  if (LibName == "compiler-rt") +    return ToolChain::RLT_CompilerRT; +  else if (LibName == "libgcc") +    return ToolChain::RLT_Libgcc; +  else if (LibName == "platform") +    return GetDefaultRuntimeLibType(); + +  if (A) +    getDriver().Diag(diag::err_drv_invalid_rtlib_name) << A->getAsString(Args); + +  return GetDefaultRuntimeLibType(); +} + +ToolChain::UnwindLibType ToolChain::GetUnwindLibType( +    const ArgList &Args) const { +  const Arg *A = Args.getLastArg(options::OPT_unwindlib_EQ); +  StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_UNWINDLIB; + +  if (LibName == "none") +    return ToolChain::UNW_None; +  else if (LibName == "platform" || LibName == "") { +    ToolChain::RuntimeLibType RtLibType = GetRuntimeLibType(Args); +    if (RtLibType == ToolChain::RLT_CompilerRT) +      return ToolChain::UNW_None; +    else if (RtLibType == ToolChain::RLT_Libgcc) +      return ToolChain::UNW_Libgcc; +  } else if (LibName == "libunwind") { +    if (GetRuntimeLibType(Args) == RLT_Libgcc) +      getDriver().Diag(diag::err_drv_incompatible_unwindlib); +    return ToolChain::UNW_CompilerRT; +  } else if (LibName == "libgcc") +    return ToolChain::UNW_Libgcc; + +  if (A) +    getDriver().Diag(diag::err_drv_invalid_unwindlib_name) +        << A->getAsString(Args); + +  return GetDefaultUnwindLibType(); +} + +ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ +  const Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); +  StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_CXX_STDLIB; + +  // Only use "platform" in tests to override CLANG_DEFAULT_CXX_STDLIB! +  if (LibName == "libc++") +    return ToolChain::CST_Libcxx; +  else if (LibName == "libstdc++") +    return ToolChain::CST_Libstdcxx; +  else if (LibName == "platform") +    return GetDefaultCXXStdlibType(); + +  if (A) +    getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); + +  return GetDefaultCXXStdlibType(); +} + +/// Utility function to add a system include directory to CC1 arguments. +/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs, +                                            ArgStringList &CC1Args, +                                            const Twine &Path) { +  CC1Args.push_back("-internal-isystem"); +  CC1Args.push_back(DriverArgs.MakeArgString(Path)); +} + +/// Utility function to add a system include directory with extern "C" +/// semantics to CC1 arguments. +/// +/// Note that this should be used rarely, and only for directories that +/// historically and for legacy reasons are treated as having implicit extern +/// "C" semantics. These semantics are *ignored* by and large today, but its +/// important to preserve the preprocessor changes resulting from the +/// classification. +/*static*/ void ToolChain::addExternCSystemInclude(const ArgList &DriverArgs, +                                                   ArgStringList &CC1Args, +                                                   const Twine &Path) { +  CC1Args.push_back("-internal-externc-isystem"); +  CC1Args.push_back(DriverArgs.MakeArgString(Path)); +} + +void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, +                                                ArgStringList &CC1Args, +                                                const Twine &Path) { +  if (llvm::sys::fs::exists(Path)) +    addExternCSystemInclude(DriverArgs, CC1Args, Path); +} + +/// Utility function to add a list of system include directories to CC1. +/*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, +                                             ArgStringList &CC1Args, +                                             ArrayRef<StringRef> Paths) { +  for (const auto Path : Paths) { +    CC1Args.push_back("-internal-isystem"); +    CC1Args.push_back(DriverArgs.MakeArgString(Path)); +  } +} + +void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, +                                             ArgStringList &CC1Args) const { +  // Header search paths should be handled by each of the subclasses. +  // Historically, they have not been, and instead have been handled inside of +  // the CC1-layer frontend. As the logic is hoisted out, this generic function +  // will slowly stop being called. +  // +  // While it is being called, replicate a bit of a hack to propagate the +  // '-stdlib=' flag down to CC1 so that it can in turn customize the C++ +  // header search paths with it. Once all systems are overriding this +  // function, the CC1 flag and this line can be removed. +  DriverArgs.AddAllArgs(CC1Args, options::OPT_stdlib_EQ); +} + +void ToolChain::AddClangCXXStdlibIsystemArgs( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  DriverArgs.ClaimAllArgs(options::OPT_stdlibxx_isystem); +  if (!DriverArgs.hasArg(options::OPT_nostdincxx)) +    for (const auto &P : +         DriverArgs.getAllArgValues(options::OPT_stdlibxx_isystem)) +      addSystemInclude(DriverArgs, CC1Args, P); +} + +bool ToolChain::ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const { +  return getDriver().CCCIsCXX() && +         !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, +                      options::OPT_nostdlibxx); +} + +void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, +                                    ArgStringList &CmdArgs) const { +  assert(!Args.hasArg(options::OPT_nostdlibxx) && +         "should not have called this"); +  CXXStdlibType Type = GetCXXStdlibType(Args); + +  switch (Type) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    break; + +  case ToolChain::CST_Libstdcxx: +    CmdArgs.push_back("-lstdc++"); +    break; +  } +} + +void ToolChain::AddFilePathLibArgs(const ArgList &Args, +                                   ArgStringList &CmdArgs) const { +  for (const auto &LibPath : getFilePaths()) +    if(LibPath.length() > 0) +      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); +} + +void ToolChain::AddCCKextLibArgs(const ArgList &Args, +                                 ArgStringList &CmdArgs) const { +  CmdArgs.push_back("-lcc_kext"); +} + +bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args, +                                              ArgStringList &CmdArgs) const { +  // Do not check for -fno-fast-math or -fno-unsafe-math when -Ofast passed +  // (to keep the linker options consistent with gcc and clang itself). +  if (!isOptimizationLevelFast(Args)) { +    // Check if -ffast-math or -funsafe-math. +    Arg *A = +        Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math, +                        options::OPT_funsafe_math_optimizations, +                        options::OPT_fno_unsafe_math_optimizations); + +    if (!A || A->getOption().getID() == options::OPT_fno_fast_math || +        A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations) +      return false; +  } +  // If crtfastmath.o exists add it to the arguments. +  std::string Path = GetFilePath("crtfastmath.o"); +  if (Path == "crtfastmath.o") // Not found. +    return false; + +  CmdArgs.push_back(Args.MakeArgString(Path)); +  return true; +} + +SanitizerMask ToolChain::getSupportedSanitizers() const { +  // Return sanitizers which don't require runtime support and are not +  // platform dependent. + +  SanitizerMask Res = (SanitizerKind::Undefined & ~SanitizerKind::Vptr & +                       ~SanitizerKind::Function) | +                      (SanitizerKind::CFI & ~SanitizerKind::CFIICall) | +                      SanitizerKind::CFICastStrict | +                      SanitizerKind::FloatDivideByZero | +                      SanitizerKind::UnsignedIntegerOverflow | +                      SanitizerKind::ImplicitConversion | +                      SanitizerKind::Nullability | SanitizerKind::LocalBounds; +  if (getTriple().getArch() == llvm::Triple::x86 || +      getTriple().getArch() == llvm::Triple::x86_64 || +      getTriple().getArch() == llvm::Triple::arm || +      getTriple().getArch() == llvm::Triple::aarch64 || +      getTriple().getArch() == llvm::Triple::wasm32 || +      getTriple().getArch() == llvm::Triple::wasm64) +    Res |= SanitizerKind::CFIICall; +  if (getTriple().getArch() == llvm::Triple::x86_64 || +      getTriple().getArch() == llvm::Triple::aarch64) +    Res |= SanitizerKind::ShadowCallStack; +  if (getTriple().getArch() == llvm::Triple::aarch64 || +      getTriple().getArch() == llvm::Triple::aarch64_be) +    Res |= SanitizerKind::MemTag; +  return Res; +} + +void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, +                                   ArgStringList &CC1Args) const {} + +void ToolChain::AddIAMCUIncludeArgs(const ArgList &DriverArgs, +                                    ArgStringList &CC1Args) const {} + +static VersionTuple separateMSVCFullVersion(unsigned Version) { +  if (Version < 100) +    return VersionTuple(Version); + +  if (Version < 10000) +    return VersionTuple(Version / 100, Version % 100); + +  unsigned Build = 0, Factor = 1; +  for (; Version > 10000; Version = Version / 10, Factor = Factor * 10) +    Build = Build + (Version % 10) * Factor; +  return VersionTuple(Version / 100, Version % 100, Build); +} + +VersionTuple +ToolChain::computeMSVCVersion(const Driver *D, +                              const llvm::opt::ArgList &Args) const { +  const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version); +  const Arg *MSCompatibilityVersion = +      Args.getLastArg(options::OPT_fms_compatibility_version); + +  if (MSCVersion && MSCompatibilityVersion) { +    if (D) +      D->Diag(diag::err_drv_argument_not_allowed_with) +          << MSCVersion->getAsString(Args) +          << MSCompatibilityVersion->getAsString(Args); +    return VersionTuple(); +  } + +  if (MSCompatibilityVersion) { +    VersionTuple MSVT; +    if (MSVT.tryParse(MSCompatibilityVersion->getValue())) { +      if (D) +        D->Diag(diag::err_drv_invalid_value) +            << MSCompatibilityVersion->getAsString(Args) +            << MSCompatibilityVersion->getValue(); +    } else { +      return MSVT; +    } +  } + +  if (MSCVersion) { +    unsigned Version = 0; +    if (StringRef(MSCVersion->getValue()).getAsInteger(10, Version)) { +      if (D) +        D->Diag(diag::err_drv_invalid_value) +            << MSCVersion->getAsString(Args) << MSCVersion->getValue(); +    } else { +      return separateMSVCFullVersion(Version); +    } +  } + +  return VersionTuple(); +} + +llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( +    const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, +    SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const { +  DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); +  const OptTable &Opts = getDriver().getOpts(); +  bool Modified = false; + +  // Handle -Xopenmp-target flags +  for (auto *A : Args) { +    // Exclude flags which may only apply to the host toolchain. +    // Do not exclude flags when the host triple (AuxTriple) +    // matches the current toolchain triple. If it is not present +    // at all, target and host share a toolchain. +    if (A->getOption().matches(options::OPT_m_Group)) { +      if (SameTripleAsHost) +        DAL->append(A); +      else +        Modified = true; +      continue; +    } + +    unsigned Index; +    unsigned Prev; +    bool XOpenMPTargetNoTriple = +        A->getOption().matches(options::OPT_Xopenmp_target); + +    if (A->getOption().matches(options::OPT_Xopenmp_target_EQ)) { +      // Passing device args: -Xopenmp-target=<triple> -opt=val. +      if (A->getValue(0) == getTripleString()) +        Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); +      else +        continue; +    } else if (XOpenMPTargetNoTriple) { +      // Passing device args: -Xopenmp-target -opt=val. +      Index = Args.getBaseArgs().MakeIndex(A->getValue(0)); +    } else { +      DAL->append(A); +      continue; +    } + +    // Parse the argument to -Xopenmp-target. +    Prev = Index; +    std::unique_ptr<Arg> XOpenMPTargetArg(Opts.ParseOneArg(Args, Index)); +    if (!XOpenMPTargetArg || Index > Prev + 1) { +      getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args) +          << A->getAsString(Args); +      continue; +    } +    if (XOpenMPTargetNoTriple && XOpenMPTargetArg && +        Args.getAllArgValues(options::OPT_fopenmp_targets_EQ).size() != 1) { +      getDriver().Diag(diag::err_drv_Xopenmp_target_missing_triple); +      continue; +    } +    XOpenMPTargetArg->setBaseArg(A); +    A = XOpenMPTargetArg.release(); +    AllocatedArgs.push_back(A); +    DAL->append(A); +    Modified = true; +  } + +  if (Modified) +    return DAL; + +  delete DAL; +  return nullptr; +} diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp new file mode 100644 index 0000000000000..71a2c68b4197b --- /dev/null +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -0,0 +1,117 @@ +//===--- AMDGPU.cpp - AMDGPU ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AMDGPU.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const ArgList &Args, +                                  const char *LinkingOutput) const { + +  std::string Linker = getToolChain().GetProgramPath(getShortName()); +  ArgStringList CmdArgs; +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); +  CmdArgs.push_back("-shared"); +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), +                                          CmdArgs, Inputs)); +} + +void amdgpu::getAMDGPUTargetFeatures(const Driver &D, +                                     const llvm::opt::ArgList &Args, +                                     std::vector<StringRef> &Features) { +  if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) +    D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); + +  if (Args.getLastArg(options::OPT_mwavefrontsize64)) { +    Features.push_back("-wavefrontsize16"); +    Features.push_back("-wavefrontsize32"); +    Features.push_back("+wavefrontsize64"); +  } +  if (Args.getLastArg(options::OPT_mno_wavefrontsize64)) { +    Features.push_back("-wavefrontsize16"); +    Features.push_back("+wavefrontsize32"); +    Features.push_back("-wavefrontsize64"); +  } + +  handleTargetFeaturesGroup( +    Args, Features, options::OPT_m_amdgpu_Features_Group); +} + +/// AMDGPU Toolchain +AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, +                                 const ArgList &Args) +    : Generic_ELF(D, Triple, Args), +      OptionsDefault({{options::OPT_O, "3"}, +                      {options::OPT_cl_std_EQ, "CL1.2"}}) {} + +Tool *AMDGPUToolChain::buildLinker() const { +  return new tools::amdgpu::Linker(*this); +} + +DerivedArgList * +AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, +                               Action::OffloadKind DeviceOffloadKind) const { + +  DerivedArgList *DAL = +      Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind); + +  // Do nothing if not OpenCL (-x cl) +  if (!Args.getLastArgValue(options::OPT_x).equals("cl")) +    return DAL; + +  if (!DAL) +    DAL = new DerivedArgList(Args.getBaseArgs()); +  for (auto *A : Args) +    DAL->append(A); + +  const OptTable &Opts = getDriver().getOpts(); + +  // Phase 1 (.cl -> .bc) +  if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) { +    DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit() +                                                ? options::OPT_m64 +                                                : options::OPT_m32)); + +    // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately +    // as they defined that way in Options.td +    if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4, +                     options::OPT_Ofast)) +      DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), +                        getOptionDefault(options::OPT_O)); +  } + +  return DAL; +} + +void AMDGPUToolChain::addClangTargetOptions( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args, +    Action::OffloadKind DeviceOffloadingKind) const { +  // Default to "hidden" visibility, as object level linking will not be +  // supported for the foreseeable future. +  if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, +                         options::OPT_fvisibility_ms_compat)) { +    CC1Args.push_back("-fvisibility"); +    CC1Args.push_back("hidden"); +    CC1Args.push_back("-fapply-global-visibility-to-externs"); +  } +} diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h new file mode 100644 index 0000000000000..5585cc5348615 --- /dev/null +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -0,0 +1,75 @@ +//===--- AMDGPU.h - AMDGPU ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H + +#include "Gnu.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include <map> + +namespace clang { +namespace driver { +namespace tools { +namespace amdgpu { + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {} +  bool isLinkJob() const override { return true; } +  bool hasIntegratedCPP() const override { return false; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +void getAMDGPUTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +                             std::vector<StringRef> &Features); + +} // end namespace amdgpu +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { + +private: +  const std::map<options::ID, const StringRef> OptionsDefault; + +protected: +  Tool *buildLinker() const override; +  const StringRef getOptionDefault(options::ID OptID) const { +    auto opt = OptionsDefault.find(OptID); +    assert(opt != OptionsDefault.end() && "No Default for Option"); +    return opt->second; +  } + +public: +  AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, +                  const llvm::opt::ArgList &Args); +  unsigned GetDefaultDwarfVersion() const override { return 5; } +  bool IsIntegratedAssemblerDefault() const override { return true; } +  bool IsMathErrnoDefault() const override { return false; } + +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; + +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp new file mode 100644 index 0000000000000..e8a3a7b38c31f --- /dev/null +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -0,0 +1,159 @@ +//===--- AVR.cpp - AVR ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AVR.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +namespace { + +// TODO: Consider merging this into the AVR device table +// array in Targets/AVR.cpp. +llvm::Optional<StringRef> GetMcuFamilyName(StringRef MCU) { +  return llvm::StringSwitch<llvm::Optional<StringRef>>(MCU) +      .Case("atmega328", Optional<StringRef>("avr5")) +      .Case("atmega328p", Optional<StringRef>("avr5")) +      .Default(Optional<StringRef>()); +} + +const StringRef PossibleAVRLibcLocations[] = { +    "/usr/avr", +    "/usr/lib/avr", +}; + +} // end anonymous namespace + +/// AVR Toolchain +AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, +                           const ArgList &Args) +    : Generic_ELF(D, Triple, Args), LinkStdlib(false) { +  GCCInstallation.init(Triple, Args); + +  // Only add default libraries if the user hasn't explicitly opted out. +  if (!Args.hasArg(options::OPT_nostdlib) && +      !Args.hasArg(options::OPT_nodefaultlibs) && +      !Args.hasArg(options::OPT_c /* does not apply when not linking */)) { +    std::string CPU = getCPUName(Args, Triple); + +    if (CPU.empty()) { +      // We cannot link any standard libraries without an MCU specified. +      D.Diag(diag::warn_drv_avr_mcu_not_specified); +    } else { +      Optional<StringRef> FamilyName = GetMcuFamilyName(CPU); +      Optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); + +      if (!FamilyName.hasValue()) { +        // We do not have an entry for this CPU in the family +        // mapping table yet. +        D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented) +            << CPU; +      } else if (!GCCInstallation.isValid()) { +        // No avr-gcc found and so no runtime linked. +        D.Diag(diag::warn_drv_avr_gcc_not_found); +      } else if (!AVRLibcRoot.hasValue()) { +        // No avr-libc found and so no runtime linked. +        D.Diag(diag::warn_drv_avr_libc_not_found); +      } else { // We have enough information to link stdlibs +        std::string GCCRoot = GCCInstallation.getInstallPath(); +        std::string LibcRoot = AVRLibcRoot.getValue(); + +        getFilePaths().push_back(LibcRoot + std::string("/lib/") + +                                 std::string(*FamilyName)); +        getFilePaths().push_back(LibcRoot + std::string("/lib/") + +                                 std::string(*FamilyName)); +        getFilePaths().push_back(GCCRoot + std::string("/") + +                                 std::string(*FamilyName)); + +        LinkStdlib = true; +      } +    } + +    if (!LinkStdlib) +      D.Diag(diag::warn_drv_avr_stdlib_not_linked); +  } +} + +Tool *AVRToolChain::buildLinker() const { +  return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); +} + +void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                               const InputInfo &Output, +                               const InputInfoList &Inputs, +                               const ArgList &Args, +                               const char *LinkingOutput) const { +  // Compute information about the target AVR. +  std::string CPU = getCPUName(Args, getToolChain().getTriple()); +  llvm::Optional<StringRef> FamilyName = GetMcuFamilyName(CPU); + +  std::string Linker = getToolChain().GetProgramPath(getShortName()); +  ArgStringList CmdArgs; +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  // Enable garbage collection of unused sections. +  CmdArgs.push_back("--gc-sections"); + +  // Add library search paths before we specify libraries. +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  getToolChain().AddFilePathLibArgs(Args, CmdArgs); + +  // If the family name is known, we can link with the device-specific libgcc. +  // Without it, libgcc will simply not be linked. This matches avr-gcc +  // behavior. +  if (LinkStdlib) { +    assert(!CPU.empty() && "CPU name must be known in order to link stdlibs"); + +    // Add the object file for the CRT. +    std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); +    CmdArgs.push_back(Args.MakeArgString(CrtFileName)); + +    CmdArgs.push_back("-lgcc"); +    CmdArgs.push_back("-lm"); +    CmdArgs.push_back("-lc"); + +    // Add the link library specific to the MCU. +    CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); + +    // Specify the family name as the emulation mode to use. +    // This is almost always required because otherwise avr-ld +    // will assume 'avr2' and warn about the program being larger +    // than the bare minimum supports. +    CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); +  } + +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), +                                          CmdArgs, Inputs)); +} + +llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { +  for (StringRef PossiblePath : PossibleAVRLibcLocations) { +    // Return the first avr-libc installation that exists. +    if (llvm::sys::fs::is_directory(PossiblePath)) +      return Optional<std::string>(std::string(PossiblePath)); +  } + +  return llvm::None; +} diff --git a/clang/lib/Driver/ToolChains/AVR.h b/clang/lib/Driver/ToolChains/AVR.h new file mode 100644 index 0000000000000..d244fc4f90e90 --- /dev/null +++ b/clang/lib/Driver/ToolChains/AVR.h @@ -0,0 +1,65 @@ +//===--- AVR.h - AVR Tool and ToolChain Implementations ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H + +#include "Gnu.h" +#include "InputInfo.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Tool.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF { +public: +  AVRToolChain(const Driver &D, const llvm::Triple &Triple, +               const llvm::opt::ArgList &Args); + +protected: +  Tool *buildLinker() const override; + +private: +  /// Whether libgcc, libct, and friends should be linked. +  /// +  /// This is not done if the user does not specify a +  /// microcontroller on the command line. +  bool LinkStdlib; + +  llvm::Optional<std::string> findAVRLibcInstallation() const; +}; + +} // end namespace toolchains + +namespace tools { +namespace AVR { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const llvm::Triple &Triple, const ToolChain &TC, bool LinkStdlib) +      : GnuTool("AVR::Linker", "avr-ld", TC), Triple(Triple), +        LinkStdlib(LinkStdlib) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; + +protected: +  const llvm::Triple &Triple; +  bool LinkStdlib; +}; +} // end namespace AVR +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H diff --git a/clang/lib/Driver/ToolChains/Ananas.cpp b/clang/lib/Driver/ToolChains/Ananas.cpp new file mode 100644 index 0000000000000..2f11c9739a0eb --- /dev/null +++ b/clang/lib/Driver/ToolChains/Ananas.cpp @@ -0,0 +1,140 @@ +//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Ananas.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                     const InputInfo &Output, +                                     const InputInfoList &Inputs, +                                     const ArgList &Args, +                                     const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const ArgList &Args, +                                  const char *LinkingOutput) const { +  const ToolChain &ToolChain = getToolChain(); +  const Driver &D = ToolChain.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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-Bshareable"); +    } else { +      Args.AddAllArgs(CmdArgs, options::OPT_pie); +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/lib/ld-ananas.so"); +    } +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); +    } +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); +    } else { +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); +    } +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_T_Group, options::OPT_e, options::OPT_s, +                   options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + +  if (D.isUsingLTO()) { +    assert(!Inputs.empty() && "Must have at least one input."); +    AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], +                  D.getLTOMode() == LTOK_Thin); +  } + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (ToolChain.ShouldLinkCXXStdlib(Args)) +    ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) +    CmdArgs.push_back("-lc"); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); +    else +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +  } + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// Ananas - Ananas tool chain which can call as(1) and ld(1) directly. + +Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +Tool *Ananas::buildAssembler() const { +  return new tools::ananas::Assembler(*this); +} + +Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/Ananas.h b/clang/lib/Driver/ToolChains/Ananas.h new file mode 100644 index 0000000000000..5e45b47fc1083 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Ananas.h @@ -0,0 +1,66 @@ +//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// ananas -- Directly call GNU Binutils assembler and linker +namespace ananas { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("ananas::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace ananas +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF { +public: +  Ananas(const Driver &D, const llvm::Triple &Triple, +         const llvm::opt::ArgList &Args); + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp new file mode 100644 index 0000000000000..3a5fe6ddeaed5 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -0,0 +1,430 @@ +//===--- AArch64.cpp - AArch64 (not ARM) Helpers for Tools ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AArch64.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/Host.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +/// \returns true if the given triple can determine the default CPU type even +/// if -arch is not specified. +static bool isCPUDeterminedByTriple(const llvm::Triple &Triple) { +  return Triple.isOSDarwin(); +} + +/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are +/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is +/// provided, or to nullptr otherwise. +std::string aarch64::getAArch64TargetCPU(const ArgList &Args, +                                         const llvm::Triple &Triple, Arg *&A) { +  std::string CPU; +  // If we have -mcpu, use that. +  if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { +    StringRef Mcpu = A->getValue(); +    CPU = Mcpu.split("+").first.lower(); +  } + +  // Handle CPU name is 'native'. +  if (CPU == "native") +    return llvm::sys::getHostCPUName(); +  else if (CPU.size()) +    return CPU; + +  // Make sure we pick "cyclone" if -arch is used or when targetting a Darwin +  // OS. +  if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin()) +    return "cyclone"; + +  return "generic"; +} + +// Decode AArch64 features from string like +[no]featureA+[no]featureB+... +static bool DecodeAArch64Features(const Driver &D, StringRef text, +                                  std::vector<StringRef> &Features) { +  SmallVector<StringRef, 8> Split; +  text.split(Split, StringRef("+"), -1, false); + +  for (StringRef Feature : Split) { +    StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature); +    if (!FeatureName.empty()) +      Features.push_back(FeatureName); +    else if (Feature == "neon" || Feature == "noneon") +      D.Diag(clang::diag::err_drv_no_neon_modifier); +    else +      return false; +  } +  return true; +} + +// Check if the CPU name and feature modifiers in -mcpu are legal. If yes, +// decode CPU and feature. +static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, +                              std::vector<StringRef> &Features) { +  std::pair<StringRef, StringRef> Split = Mcpu.split("+"); +  CPU = Split.first; + +  if (CPU == "native") +    CPU = llvm::sys::getHostCPUName(); + +  if (CPU == "generic") { +    Features.push_back("+neon"); +  } else { +    llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU); +    if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) +      return false; + +    unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind); +    if (!llvm::AArch64::getExtensionFeatures(Extension, Features)) +      return false; +   } + +  if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)) +    return false; + +  return true; +} + +static bool +getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, +                                const ArgList &Args, +                                std::vector<StringRef> &Features) { +  std::string MarchLowerCase = March.lower(); +  std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); + +  llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); +  if (ArchKind == llvm::AArch64::ArchKind::INVALID || +      !llvm::AArch64::getArchFeatures(ArchKind, Features) || +      (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))) +    return false; + +  return true; +} + +static bool +getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, +                               const ArgList &Args, +                               std::vector<StringRef> &Features) { +  StringRef CPU; +  std::string McpuLowerCase = Mcpu.lower(); +  if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features)) +    return false; + +  return true; +} + +static bool +getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, +                                     const ArgList &Args, +                                     std::vector<StringRef> &Features) { +  std::string MtuneLowerCase = Mtune.lower(); +  // Check CPU name is valid +  std::vector<StringRef> MtuneFeatures; +  StringRef Tune; +  if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) +    return false; + +  // Handle CPU name is 'native'. +  if (MtuneLowerCase == "native") +    MtuneLowerCase = llvm::sys::getHostCPUName(); +  if (MtuneLowerCase == "cyclone") { +    Features.push_back("+zcm"); +    Features.push_back("+zcz"); +  } +  return true; +} + +static bool +getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, +                                    const ArgList &Args, +                                    std::vector<StringRef> &Features) { +  StringRef CPU; +  std::vector<StringRef> DecodedFeature; +  std::string McpuLowerCase = Mcpu.lower(); +  if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature)) +    return false; + +  return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features); +} + +void aarch64::getAArch64TargetFeatures(const Driver &D, +                                       const llvm::Triple &Triple, +                                       const ArgList &Args, +                                       std::vector<StringRef> &Features) { +  Arg *A; +  bool success = true; +  // Enable NEON by default. +  Features.push_back("+neon"); +  if ((A = Args.getLastArg(options::OPT_march_EQ))) +    success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); +  else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) +    success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features); +  else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)) +    success = getAArch64ArchFeaturesFromMcpu( +        D, getAArch64TargetCPU(Args, Triple, A), Args, Features); + +  if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) +    success = +        getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features); +  else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ))) +    success = +        getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features); +  else if (success && +           (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))) +    success = getAArch64MicroArchFeaturesFromMcpu( +        D, getAArch64TargetCPU(Args, Triple, A), Args, Features); + +  if (!success) +    D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); + +  if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { +    Features.push_back("-fp-armv8"); +    Features.push_back("-crypto"); +    Features.push_back("-neon"); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { +    StringRef Mtp = A->getValue(); +    if (Mtp == "el3") +      Features.push_back("+tpidr-el3"); +    else if (Mtp == "el2") +      Features.push_back("+tpidr-el2"); +    else if (Mtp == "el1") +      Features.push_back("+tpidr-el1"); +    else if (Mtp != "el0") +      D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); +  } + +  // En/disable crc +  if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { +    if (A->getOption().matches(options::OPT_mcrc)) +      Features.push_back("+crc"); +    else +      Features.push_back("-crc"); +  } + +  // Handle (arch-dependent) fp16fml/fullfp16 relationship. +  // FIXME: this fp16fml option handling will be reimplemented after the +  // TargetParser rewrite. +  const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16"); +  const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml"); +  if (llvm::is_contained(Features, "+v8.4a")) { +    const auto ItRFullFP16  = std::find(Features.rbegin(), Features.rend(), "+fullfp16"); +    if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { +      // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. +      // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. +      if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16) +        Features.push_back("+fp16fml"); +    } +    else +      goto fp16_fml_fallthrough; +  } else { +fp16_fml_fallthrough: +    // In both of these cases, putting the 'other' feature on the end of the vector will +    // result in the same effect as placing it immediately after the current feature. +    if (ItRNoFullFP16 < ItRFP16FML) +      Features.push_back("-fp16fml"); +    else if (ItRNoFullFP16 > ItRFP16FML) +      Features.push_back("+fullfp16"); +  } + +  // FIXME: this needs reimplementation too after the TargetParser rewrite +  // +  // Context sensitive meaning of Crypto: +  // 1) For Arch >= ARMv8.4a:  crypto = sm4 + sha3 + sha2 + aes +  // 2) For Arch <= ARMv8.3a:  crypto = sha2 + aes +  const auto ItBegin = Features.begin(); +  const auto ItEnd = Features.end(); +  const auto ItRBegin = Features.rbegin(); +  const auto ItREnd = Features.rend(); +  const auto ItRCrypto = std::find(ItRBegin, ItREnd, "+crypto"); +  const auto ItRNoCrypto = std::find(ItRBegin, ItREnd, "-crypto"); +  const auto HasCrypto  = ItRCrypto != ItREnd; +  const auto HasNoCrypto = ItRNoCrypto != ItREnd; +  const ptrdiff_t PosCrypto = ItRCrypto - ItRBegin; +  const ptrdiff_t PosNoCrypto = ItRNoCrypto - ItRBegin; + +  bool NoCrypto = false; +  if (HasCrypto && HasNoCrypto) { +    if (PosNoCrypto < PosCrypto) +      NoCrypto = true; +  } + +  if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd) { +    if (HasCrypto && !NoCrypto) { +      // Check if we have NOT disabled an algorithm with something like: +      //   +crypto, -algorithm +      // And if "-algorithm" does not occur, we enable that crypto algorithm. +      const bool HasSM4  = (std::find(ItBegin, ItEnd, "-sm4") == ItEnd); +      const bool HasSHA3 = (std::find(ItBegin, ItEnd, "-sha3") == ItEnd); +      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); +      const bool HasAES  = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); +      if (HasSM4) +        Features.push_back("+sm4"); +      if (HasSHA3) +        Features.push_back("+sha3"); +      if (HasSHA2) +        Features.push_back("+sha2"); +      if (HasAES) +        Features.push_back("+aes"); +    } else if (HasNoCrypto) { +      // Check if we have NOT enabled a crypto algorithm with something like: +      //   -crypto, +algorithm +      // And if "+algorithm" does not occur, we disable that crypto algorithm. +      const bool HasSM4  = (std::find(ItBegin, ItEnd, "+sm4") != ItEnd); +      const bool HasSHA3 = (std::find(ItBegin, ItEnd, "+sha3") != ItEnd); +      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); +      const bool HasAES  = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); +      if (!HasSM4) +        Features.push_back("-sm4"); +      if (!HasSHA3) +        Features.push_back("-sha3"); +      if (!HasSHA2) +        Features.push_back("-sha2"); +      if (!HasAES) +        Features.push_back("-aes"); +    } +  } else { +    if (HasCrypto && !NoCrypto) { +      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); +      const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); +      if (HasSHA2) +        Features.push_back("+sha2"); +      if (HasAES) +        Features.push_back("+aes"); +    } else if (HasNoCrypto) { +      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); +      const bool HasAES  = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); +      const bool HasV82a = (std::find(ItBegin, ItEnd, "+v8.2a") != ItEnd); +      const bool HasV83a = (std::find(ItBegin, ItEnd, "+v8.3a") != ItEnd); +      const bool HasV84a = (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd); +      if (!HasSHA2) +        Features.push_back("-sha2"); +      if (!HasAES) +        Features.push_back("-aes"); +      if (HasV82a || HasV83a || HasV84a) { +        Features.push_back("-sm4"); +        Features.push_back("-sha3"); +      } +    } +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, +                               options::OPT_munaligned_access)) +    if (A->getOption().matches(options::OPT_mno_unaligned_access)) +      Features.push_back("+strict-align"); + +  if (Args.hasArg(options::OPT_ffixed_x1)) +    Features.push_back("+reserve-x1"); + +  if (Args.hasArg(options::OPT_ffixed_x2)) +    Features.push_back("+reserve-x2"); + +  if (Args.hasArg(options::OPT_ffixed_x3)) +    Features.push_back("+reserve-x3"); + +  if (Args.hasArg(options::OPT_ffixed_x4)) +    Features.push_back("+reserve-x4"); + +  if (Args.hasArg(options::OPT_ffixed_x5)) +    Features.push_back("+reserve-x5"); + +  if (Args.hasArg(options::OPT_ffixed_x6)) +    Features.push_back("+reserve-x6"); + +  if (Args.hasArg(options::OPT_ffixed_x7)) +    Features.push_back("+reserve-x7"); + +  if (Args.hasArg(options::OPT_ffixed_x9)) +    Features.push_back("+reserve-x9"); + +  if (Args.hasArg(options::OPT_ffixed_x10)) +    Features.push_back("+reserve-x10"); + +  if (Args.hasArg(options::OPT_ffixed_x11)) +    Features.push_back("+reserve-x11"); + +  if (Args.hasArg(options::OPT_ffixed_x12)) +    Features.push_back("+reserve-x12"); + +  if (Args.hasArg(options::OPT_ffixed_x13)) +    Features.push_back("+reserve-x13"); + +  if (Args.hasArg(options::OPT_ffixed_x14)) +    Features.push_back("+reserve-x14"); + +  if (Args.hasArg(options::OPT_ffixed_x15)) +    Features.push_back("+reserve-x15"); + +  if (Args.hasArg(options::OPT_ffixed_x18)) +    Features.push_back("+reserve-x18"); + +  if (Args.hasArg(options::OPT_ffixed_x20)) +    Features.push_back("+reserve-x20"); + +  if (Args.hasArg(options::OPT_ffixed_x21)) +    Features.push_back("+reserve-x21"); + +  if (Args.hasArg(options::OPT_ffixed_x22)) +    Features.push_back("+reserve-x22"); + +  if (Args.hasArg(options::OPT_ffixed_x23)) +    Features.push_back("+reserve-x23"); + +  if (Args.hasArg(options::OPT_ffixed_x24)) +    Features.push_back("+reserve-x24"); + +  if (Args.hasArg(options::OPT_ffixed_x25)) +    Features.push_back("+reserve-x25"); + +  if (Args.hasArg(options::OPT_ffixed_x26)) +    Features.push_back("+reserve-x26"); + +  if (Args.hasArg(options::OPT_ffixed_x27)) +    Features.push_back("+reserve-x27"); + +  if (Args.hasArg(options::OPT_ffixed_x28)) +    Features.push_back("+reserve-x28"); + +  if (Args.hasArg(options::OPT_fcall_saved_x8)) +    Features.push_back("+call-saved-x8"); + +  if (Args.hasArg(options::OPT_fcall_saved_x9)) +    Features.push_back("+call-saved-x9"); + +  if (Args.hasArg(options::OPT_fcall_saved_x10)) +    Features.push_back("+call-saved-x10"); + +  if (Args.hasArg(options::OPT_fcall_saved_x11)) +    Features.push_back("+call-saved-x11"); + +  if (Args.hasArg(options::OPT_fcall_saved_x12)) +    Features.push_back("+call-saved-x12"); + +  if (Args.hasArg(options::OPT_fcall_saved_x13)) +    Features.push_back("+call-saved-x13"); + +  if (Args.hasArg(options::OPT_fcall_saved_x14)) +    Features.push_back("+call-saved-x14"); + +  if (Args.hasArg(options::OPT_fcall_saved_x15)) +    Features.push_back("+call-saved-x15"); + +  if (Args.hasArg(options::OPT_fcall_saved_x18)) +    Features.push_back("+call-saved-x18"); + +  if (Args.hasArg(options::OPT_mno_neg_immediates)) +    Features.push_back("+no-neg-immediates"); +} diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h new file mode 100644 index 0000000000000..713af870d69fb --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h @@ -0,0 +1,35 @@ +//===--- AArch64.h - AArch64-specific (not ARM) Tool Helpers ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace aarch64 { + +void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, +                              const llvm::opt::ArgList &Args, +                              std::vector<llvm::StringRef> &Features); + +std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args, +                                const llvm::Triple &Triple, llvm::opt::Arg *&A); + +} // end namespace aarch64 +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp new file mode 100644 index 0000000000000..68a57310ad402 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -0,0 +1,709 @@ +//===--- ARM.cpp - ARM (not AArch64) Helpers for Tools ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/Host.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +// Get SubArch (vN). +int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) { +  llvm::StringRef Arch = Triple.getArchName(); +  return llvm::ARM::parseArchVersion(Arch); +} + +// True if M-profile. +bool arm::isARMMProfile(const llvm::Triple &Triple) { +  llvm::StringRef Arch = Triple.getArchName(); +  return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; +} + +// Get Arch/CPU from args. +void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, +                                llvm::StringRef &CPU, bool FromAs) { +  if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) +    CPU = A->getValue(); +  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) +    Arch = A->getValue(); +  if (!FromAs) +    return; + +  for (const Arg *A : +       Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { +    StringRef Value = A->getValue(); +    if (Value.startswith("-mcpu=")) +      CPU = Value.substr(6); +    if (Value.startswith("-march=")) +      Arch = Value.substr(7); +  } +} + +// Handle -mhwdiv=. +// FIXME: Use ARMTargetParser. +static void getARMHWDivFeatures(const Driver &D, const Arg *A, +                                const ArgList &Args, StringRef HWDiv, +                                std::vector<StringRef> &Features) { +  unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv); +  if (!llvm::ARM::getHWDivFeatures(HWDivID, Features)) +    D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + +// Handle -mfpu=. +static void getARMFPUFeatures(const Driver &D, const Arg *A, +                              const ArgList &Args, StringRef FPU, +                              std::vector<StringRef> &Features) { +  unsigned FPUID = llvm::ARM::parseFPU(FPU); +  if (!llvm::ARM::getFPUFeatures(FPUID, Features)) +    D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + +// Decode ARM features from string like +[no]featureA+[no]featureB+... +static bool DecodeARMFeatures(const Driver &D, StringRef text, +                              StringRef CPU, llvm::ARM::ArchKind ArchKind, +                              std::vector<StringRef> &Features) { +  SmallVector<StringRef, 8> Split; +  text.split(Split, StringRef("+"), -1, false); + +  for (StringRef Feature : Split) { +    if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features)) +      return false; +  } +  return true; +} + +static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, +                                     std::vector<StringRef> &Features) { +  CPU = CPU.split("+").first; +  if (CPU != "generic") { +    llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); +    unsigned Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); +    llvm::ARM::getExtensionFeatures(Extension, Features); +  } +} + +// Check if -march is valid by checking if it can be canonicalised and parsed. +// getARMArch is used here instead of just checking the -march value in order +// to handle -march=native correctly. +static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, +                             llvm::StringRef ArchName, llvm::StringRef CPUName, +                             std::vector<StringRef> &Features, +                             const llvm::Triple &Triple) { +  std::pair<StringRef, StringRef> Split = ArchName.split("+"); + +  std::string MArch = arm::getARMArch(ArchName, Triple); +  llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); +  if (ArchKind == llvm::ARM::ArchKind::INVALID || +      (Split.second.size() && !DecodeARMFeatures( +        D, Split.second, CPUName, ArchKind, Features))) +    D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + +// Check -mcpu=. Needs ArchName to handle -mcpu=generic. +static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, +                            llvm::StringRef CPUName, llvm::StringRef ArchName, +                            std::vector<StringRef> &Features, +                            const llvm::Triple &Triple) { +  std::pair<StringRef, StringRef> Split = CPUName.split("+"); + +  std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); +  llvm::ARM::ArchKind ArchKind = +    arm::getLLVMArchKindForARM(CPU, ArchName, Triple); +  if (ArchKind == llvm::ARM::ArchKind::INVALID || +      (Split.second.size() && !DecodeARMFeatures( +        D, Split.second, CPU, ArchKind, Features))) +    D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + +bool arm::useAAPCSForMachO(const llvm::Triple &T) { +  // The backend is hardwired to assume AAPCS for M-class processors, ensure +  // the frontend matches that. +  return T.getEnvironment() == llvm::Triple::EABI || +         T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T); +} + +// Select mode for reading thread pointer (-mtp=soft/cp15). +arm::ReadTPMode arm::getReadTPMode(const ToolChain &TC, const ArgList &Args) { +  if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { +    const Driver &D = TC.getDriver(); +    arm::ReadTPMode ThreadPointer = +        llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) +            .Case("cp15", ReadTPMode::Cp15) +            .Case("soft", ReadTPMode::Soft) +            .Default(ReadTPMode::Invalid); +    if (ThreadPointer != ReadTPMode::Invalid) +      return ThreadPointer; +    if (StringRef(A->getValue()).empty()) +      D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args); +    else +      D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); +    return ReadTPMode::Invalid; +  } +  return ReadTPMode::Soft; +} + +// Select the float ABI as determined by -msoft-float, -mhard-float, and +// -mfloat-abi=. +arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { +  const Driver &D = TC.getDriver(); +  const llvm::Triple &Triple = TC.getEffectiveTriple(); +  auto SubArch = getARMSubArchVersionNumber(Triple); +  arm::FloatABI ABI = FloatABI::Invalid; +  if (Arg *A = +          Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, +                          options::OPT_mfloat_abi_EQ)) { +    if (A->getOption().matches(options::OPT_msoft_float)) { +      ABI = FloatABI::Soft; +    } else if (A->getOption().matches(options::OPT_mhard_float)) { +      ABI = FloatABI::Hard; +    } else { +      ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue()) +                .Case("soft", FloatABI::Soft) +                .Case("softfp", FloatABI::SoftFP) +                .Case("hard", FloatABI::Hard) +                .Default(FloatABI::Invalid); +      if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) { +        D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); +        ABI = FloatABI::Soft; +      } +    } + +    // It is incorrect to select hard float ABI on MachO platforms if the ABI is +    // "apcs-gnu". +    if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple) && +        ABI == FloatABI::Hard) { +      D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) +                                                       << Triple.getArchName(); +    } +  } + +  // If unspecified, choose the default based on the platform. +  if (ABI == FloatABI::Invalid) { +    switch (Triple.getOS()) { +    case llvm::Triple::Darwin: +    case llvm::Triple::MacOSX: +    case llvm::Triple::IOS: +    case llvm::Triple::TvOS: { +      // Darwin defaults to "softfp" for v6 and v7. +      ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; +      ABI = Triple.isWatchABI() ? FloatABI::Hard : ABI; +      break; +    } +    case llvm::Triple::WatchOS: +      ABI = FloatABI::Hard; +      break; + +    // FIXME: this is invalid for WindowsCE +    case llvm::Triple::Win32: +      ABI = FloatABI::Hard; +      break; + +    case llvm::Triple::NetBSD: +      switch (Triple.getEnvironment()) { +      case llvm::Triple::EABIHF: +      case llvm::Triple::GNUEABIHF: +        ABI = FloatABI::Hard; +        break; +      default: +        ABI = FloatABI::Soft; +        break; +      } +      break; + +    case llvm::Triple::FreeBSD: +      switch (Triple.getEnvironment()) { +      case llvm::Triple::GNUEABIHF: +        ABI = FloatABI::Hard; +        break; +      default: +        // FreeBSD defaults to soft float +        ABI = FloatABI::Soft; +        break; +      } +      break; + +    case llvm::Triple::OpenBSD: +      ABI = FloatABI::SoftFP; +      break; + +    default: +      switch (Triple.getEnvironment()) { +      case llvm::Triple::GNUEABIHF: +      case llvm::Triple::MuslEABIHF: +      case llvm::Triple::EABIHF: +        ABI = FloatABI::Hard; +        break; +      case llvm::Triple::GNUEABI: +      case llvm::Triple::MuslEABI: +      case llvm::Triple::EABI: +        // EABI is always AAPCS, and if it was not marked 'hard', it's softfp +        ABI = FloatABI::SoftFP; +        break; +      case llvm::Triple::Android: +        ABI = (SubArch >= 7) ? FloatABI::SoftFP : FloatABI::Soft; +        break; +      default: +        // Assume "soft", but warn the user we are guessing. +        if (Triple.isOSBinFormatMachO() && +            Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em) +          ABI = FloatABI::Hard; +        else +          ABI = FloatABI::Soft; + +        if (Triple.getOS() != llvm::Triple::UnknownOS || +            !Triple.isOSBinFormatMachO()) +          D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; +        break; +      } +    } +  } + +  assert(ABI != FloatABI::Invalid && "must select an ABI"); +  return ABI; +} + +void arm::getARMTargetFeatures(const ToolChain &TC, +                               const llvm::Triple &Triple, +                               const ArgList &Args, +                               ArgStringList &CmdArgs, +                               std::vector<StringRef> &Features, +                               bool ForAS) { +  const Driver &D = TC.getDriver(); + +  bool KernelOrKext = +      Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); +  arm::FloatABI ABI = arm::getARMFloatABI(TC, Args); +  arm::ReadTPMode ThreadPointer = arm::getReadTPMode(TC, Args); +  const Arg *WaCPU = nullptr, *WaFPU = nullptr; +  const Arg *WaHDiv = nullptr, *WaArch = nullptr; + +  // This vector will accumulate features from the architecture +  // extension suffixes on -mcpu and -march (e.g. the 'bar' in +  // -mcpu=foo+bar). We want to apply those after the features derived +  // from the FPU, in case -mfpu generates a negative feature which +  // the +bar is supposed to override. +  std::vector<StringRef> ExtensionFeatures; + +  if (!ForAS) { +    // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these +    // yet (it uses the -mfloat-abi and -msoft-float options), and it is +    // stripped out by the ARM target. We should probably pass this a new +    // -target-option, which is handled by the -cc1/-cc1as invocation. +    // +    // FIXME2:  For consistency, it would be ideal if we set up the target +    // machine state the same when using the frontend or the assembler. We don't +    // currently do that for the assembler, we pass the options directly to the +    // backend and never even instantiate the frontend TargetInfo. If we did, +    // and used its handleTargetFeatures hook, then we could ensure the +    // assembler and the frontend behave the same. + +    // Use software floating point operations? +    if (ABI == arm::FloatABI::Soft) +      Features.push_back("+soft-float"); + +    // Use software floating point argument passing? +    if (ABI != arm::FloatABI::Hard) +      Features.push_back("+soft-float-abi"); +  } else { +    // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down +    // to the assembler correctly. +    for (const Arg *A : +         Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { +      StringRef Value = A->getValue(); +      if (Value.startswith("-mfpu=")) { +        WaFPU = A; +      } else if (Value.startswith("-mcpu=")) { +        WaCPU = A; +      } else if (Value.startswith("-mhwdiv=")) { +        WaHDiv = A; +      } else if (Value.startswith("-march=")) { +        WaArch = A; +      } +    } +  } + +  if (ThreadPointer == arm::ReadTPMode::Cp15) +    Features.push_back("+read-tp-hard"); + +  const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); +  const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); +  StringRef ArchName; +  StringRef CPUName; + +  // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. +  if (WaCPU) { +    if (CPUArg) +      D.Diag(clang::diag::warn_drv_unused_argument) +          << CPUArg->getAsString(Args); +    CPUName = StringRef(WaCPU->getValue()).substr(6); +    CPUArg = WaCPU; +  } else if (CPUArg) +    CPUName = CPUArg->getValue(); + +  // Check -march. ClangAs gives preference to -Wa,-march=. +  if (WaArch) { +    if (ArchArg) +      D.Diag(clang::diag::warn_drv_unused_argument) +          << ArchArg->getAsString(Args); +    ArchName = StringRef(WaArch->getValue()).substr(7); +    checkARMArchName(D, WaArch, Args, ArchName, CPUName, +                     ExtensionFeatures, Triple); +    // FIXME: Set Arch. +    D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args); +  } else if (ArchArg) { +    ArchName = ArchArg->getValue(); +    checkARMArchName(D, ArchArg, Args, ArchName, CPUName, +                     ExtensionFeatures, Triple); +  } + +  // Add CPU features for generic CPUs +  if (CPUName == "native") { +    llvm::StringMap<bool> HostFeatures; +    if (llvm::sys::getHostCPUFeatures(HostFeatures)) +      for (auto &F : HostFeatures) +        Features.push_back( +            Args.MakeArgString((F.second ? "+" : "-") + F.first())); +  } else if (!CPUName.empty()) { +    // This sets the default features for the specified CPU. We certainly don't +    // want to override the features that have been explicitly specified on the +    // command line. Therefore, process them directly instead of appending them +    // at the end later. +    DecodeARMFeaturesFromCPU(D, CPUName, Features); +  } + +  if (CPUArg) +    checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, +                    ExtensionFeatures, Triple); +  // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. +  const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); +  if (WaFPU) { +    if (FPUArg) +      D.Diag(clang::diag::warn_drv_unused_argument) +          << FPUArg->getAsString(Args); +    getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), +                      Features); +  } else if (FPUArg) { +    getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); +  } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { +    const char *AndroidFPU = "neon"; +    if (!llvm::ARM::getFPUFeatures(llvm::ARM::parseFPU(AndroidFPU), Features)) +      D.Diag(clang::diag::err_drv_clang_unsupported) +          << std::string("-mfpu=") + AndroidFPU; +  } + +  // Now we've finished accumulating features from arch, cpu and fpu, +  // we can append the ones for architecture extensions that we +  // collected separately. +  Features.insert(std::end(Features), +                  std::begin(ExtensionFeatures), std::end(ExtensionFeatures)); + +  // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. +  const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); +  if (WaHDiv) { +    if (HDivArg) +      D.Diag(clang::diag::warn_drv_unused_argument) +          << HDivArg->getAsString(Args); +    getARMHWDivFeatures(D, WaHDiv, Args, +                        StringRef(WaHDiv->getValue()).substr(8), Features); +  } else if (HDivArg) +    getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); + +  // Handle (arch-dependent) fp16fml/fullfp16 relationship. +  // Must happen before any features are disabled due to soft-float. +  // FIXME: this fp16fml option handling will be reimplemented after the +  // TargetParser rewrite. +  const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16"); +  const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml"); +  if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_4a) { +    const auto ItRFullFP16  = std::find(Features.rbegin(), Features.rend(), "+fullfp16"); +    if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { +      // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. +      // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. +      if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16) +        Features.push_back("+fp16fml"); +    } +    else +      goto fp16_fml_fallthrough; +  } +  else { +fp16_fml_fallthrough: +    // In both of these cases, putting the 'other' feature on the end of the vector will +    // result in the same effect as placing it immediately after the current feature. +    if (ItRNoFullFP16 < ItRFP16FML) +      Features.push_back("-fp16fml"); +    else if (ItRNoFullFP16 > ItRFP16FML) +      Features.push_back("+fullfp16"); +  } + +  // Setting -msoft-float/-mfloat-abi=soft effectively disables the FPU (GCC +  // ignores the -mfpu options in this case). +  // Note that the ABI can also be set implicitly by the target selected. +  if (ABI == arm::FloatABI::Soft) { +    llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); + +    // Disable all features relating to hardware FP. +    // FIXME: Disabling fpregs should be enough all by itself, since all +    //        the other FP features are dependent on it. However +    //        there is currently no easy way to test this in clang, so for +    //        now just be explicit and disable all known dependent features +    //        as well. +    for (std::string Feature : { +            "vfp2", "vfp2sp", +            "vfp3", "vfp3sp", "vfp3d16", "vfp3d16sp", +            "vfp4", "vfp4sp", "vfp4d16", "vfp4d16sp", +            "fp-armv8", "fp-armv8sp", "fp-armv8d16", "fp-armv8d16sp", +            "fullfp16", "neon", "crypto", "dotprod", "fp16fml", +            "mve", "mve.fp", +            "fp64", "d32", "fpregs"}) +      Features.push_back(Args.MakeArgString("-" + Feature)); +  } + +  // En/disable crc code generation. +  if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { +    if (A->getOption().matches(options::OPT_mcrc)) +      Features.push_back("+crc"); +    else +      Features.push_back("-crc"); +  } + +  // For Arch >= ARMv8.0 && A profile:  crypto = sha2 + aes +  // FIXME: this needs reimplementation after the TargetParser rewrite +  auto CryptoIt = llvm::find_if(llvm::reverse(Features), [](const StringRef F) { +    return F.contains("crypto"); +  }); +  if (CryptoIt != Features.rend()) { +    if (CryptoIt->take_front() == "+") { +      StringRef ArchSuffix = arm::getLLVMArchSuffixForARM( +          arm::getARMTargetCPU(CPUName, ArchName, Triple), ArchName, Triple); +      if (llvm::ARM::parseArchVersion(ArchSuffix) >= 8 && +          llvm::ARM::parseArchProfile(ArchSuffix) == +              llvm::ARM::ProfileKind::A) { +        if (ArchName.find_lower("+nosha2") == StringRef::npos && +            CPUName.find_lower("+nosha2") == StringRef::npos) +          Features.push_back("+sha2"); +        if (ArchName.find_lower("+noaes") == StringRef::npos && +            CPUName.find_lower("+noaes") == StringRef::npos) +          Features.push_back("+aes"); +      } else { +        D.Diag(clang::diag::warn_target_unsupported_extension) +            << "crypto" +            << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix)); +        // With -fno-integrated-as -mfpu=crypto-neon-fp-armv8 some assemblers such as the GNU assembler +        // will permit the use of crypto instructions as the fpu will override the architecture. +        // We keep the crypto feature in this case to preserve compatibility. +        // In all other cases we remove the crypto feature. +        if (!Args.hasArg(options::OPT_fno_integrated_as)) +          Features.push_back("-crypto"); +      } +    } +  } + +  // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later. +  if (Args.getLastArg(options::OPT_mcmse)) +    Features.push_back("+8msecext"); + +  // Look for the last occurrence of -mlong-calls or -mno-long-calls. If +  // neither options are specified, see if we are compiling for kernel/kext and +  // decide whether to pass "+long-calls" based on the OS and its version. +  if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, +                               options::OPT_mno_long_calls)) { +    if (A->getOption().matches(options::OPT_mlong_calls)) +      Features.push_back("+long-calls"); +  } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) && +             !Triple.isWatchOS()) { +      Features.push_back("+long-calls"); +  } + +  // Generate execute-only output (no data access to code sections). +  // This only makes sense for the compiler, not for the assembler. +  if (!ForAS) { +    // Supported only on ARMv6T2 and ARMv7 and above. +    // Cannot be combined with -mno-movt or -mlong-calls +    if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { +      if (A->getOption().matches(options::OPT_mexecute_only)) { +        if (getARMSubArchVersionNumber(Triple) < 7 && +            llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2) +              D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); +        else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) +          D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); +        // Long calls create constant pool entries and have not yet been fixed up +        // to play nicely with execute-only. Hence, they cannot be used in +        // execute-only code for now +        else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { +          if (B->getOption().matches(options::OPT_mlong_calls)) +            D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); +        } +        Features.push_back("+execute-only"); +      } +    } +  } + +  // Kernel code has more strict alignment requirements. +  if (KernelOrKext) +    Features.push_back("+strict-align"); +  else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, +                                    options::OPT_munaligned_access)) { +    if (A->getOption().matches(options::OPT_munaligned_access)) { +      // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). +      if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) +        D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; +      // v8M Baseline follows on from v6M, so doesn't support unaligned memory +      // access either. +      else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) +        D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; +    } else +      Features.push_back("+strict-align"); +  } else { +    // Assume pre-ARMv6 doesn't support unaligned accesses. +    // +    // ARMv6 may or may not support unaligned accesses depending on the +    // SCTLR.U bit, which is architecture-specific. We assume ARMv6 +    // Darwin and NetBSD targets support unaligned accesses, and others don't. +    // +    // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit +    // which raises an alignment fault on unaligned accesses. Linux +    // defaults this bit to 0 and handles it as a system-wide (not +    // per-process) setting. It is therefore safe to assume that ARMv7+ +    // Linux targets support unaligned accesses. The same goes for NaCl. +    // +    // The above behavior is consistent with GCC. +    int VersionNum = getARMSubArchVersionNumber(Triple); +    if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { +      if (VersionNum < 6 || +          Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) +        Features.push_back("+strict-align"); +    } else if (Triple.isOSLinux() || Triple.isOSNaCl()) { +      if (VersionNum < 7) +        Features.push_back("+strict-align"); +    } else +      Features.push_back("+strict-align"); +  } + +  // llvm does not support reserving registers in general. There is support +  // for reserving r9 on ARM though (defined as a platform-specific register +  // in ARM EABI). +  if (Args.hasArg(options::OPT_ffixed_r9)) +    Features.push_back("+reserve-r9"); + +  // The kext linker doesn't know how to deal with movw/movt. +  if (KernelOrKext || Args.hasArg(options::OPT_mno_movt)) +    Features.push_back("+no-movt"); + +  if (Args.hasArg(options::OPT_mno_neg_immediates)) +    Features.push_back("+no-neg-immediates"); +} + +const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { +  std::string MArch; +  if (!Arch.empty()) +    MArch = Arch; +  else +    MArch = Triple.getArchName(); +  MArch = StringRef(MArch).split("+").first.lower(); + +  // Handle -march=native. +  if (MArch == "native") { +    std::string CPU = llvm::sys::getHostCPUName(); +    if (CPU != "generic") { +      // Translate the native cpu into the architecture suffix for that CPU. +      StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); +      // If there is no valid architecture suffix for this CPU we don't know how +      // to handle it, so return no architecture. +      if (Suffix.empty()) +        MArch = ""; +      else +        MArch = std::string("arm") + Suffix.str(); +    } +  } + +  return MArch; +} + +/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. +StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { +  std::string MArch = getARMArch(Arch, Triple); +  // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch +  // here means an -march=native that we can't handle, so instead return no CPU. +  if (MArch.empty()) +    return StringRef(); + +  // We need to return an empty string here on invalid MArch values as the +  // various places that call this function can't cope with a null result. +  return Triple.getARMCPUForArch(MArch); +} + +/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. +std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, +                                 const llvm::Triple &Triple) { +  // FIXME: Warn on inconsistent use of -mcpu and -march. +  // If we have -mcpu=, use that. +  if (!CPU.empty()) { +    std::string MCPU = StringRef(CPU).split("+").first.lower(); +    // Handle -mcpu=native. +    if (MCPU == "native") +      return llvm::sys::getHostCPUName(); +    else +      return MCPU; +  } + +  return getARMCPUForMArch(Arch, Triple); +} + +/// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a +/// particular CPU (or Arch, if CPU is generic). This is needed to +/// pass to functions like llvm::ARM::getDefaultFPU which need an +/// ArchKind as well as a CPU name. +llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, +                                               const llvm::Triple &Triple) { +  llvm::ARM::ArchKind ArchKind; +  if (CPU == "generic" || CPU.empty()) { +    std::string ARMArch = tools::arm::getARMArch(Arch, Triple); +    ArchKind = llvm::ARM::parseArch(ARMArch); +    if (ArchKind == llvm::ARM::ArchKind::INVALID) +      // In case of generic Arch, i.e. "arm", +      // extract arch from default cpu of the Triple +      ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); +  } else { +    // FIXME: horrible hack to get around the fact that Cortex-A7 is only an +    // armv7k triple if it's actually been specified via "-arch armv7k". +    ArchKind = (Arch == "armv7k" || Arch == "thumbv7k") +                          ? llvm::ARM::ArchKind::ARMV7K +                          : llvm::ARM::parseCPUArch(CPU); +  } +  return ArchKind; +} + +/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular +/// CPU  (or Arch, if CPU is generic). +// FIXME: This is redundant with -mcpu, why does LLVM use this. +StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, +                                       const llvm::Triple &Triple) { +  llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple); +  if (ArchKind == llvm::ARM::ArchKind::INVALID) +    return ""; +  return llvm::ARM::getSubArch(ArchKind); +} + +void arm::appendBE8LinkFlag(const ArgList &Args, ArgStringList &CmdArgs, +                            const llvm::Triple &Triple) { +  if (Args.hasArg(options::OPT_r)) +    return; + +  // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker +  // to generate BE-8 executables. +  if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple)) +    CmdArgs.push_back("--be8"); +} diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h new file mode 100644 index 0000000000000..5640f8371262a --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -0,0 +1,69 @@ +//===--- ARM.h - ARM-specific (not AArch64) Tool Helpers --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H + +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/TargetParser.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace arm { + +std::string getARMTargetCPU(StringRef CPU, llvm::StringRef Arch, +                            const llvm::Triple &Triple); +const std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +StringRef getARMCPUForMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +llvm::ARM::ArchKind getLLVMArchKindForARM(StringRef CPU, StringRef Arch, +                                          const llvm::Triple &Triple); +StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch, +                                  const llvm::Triple &Triple); + +void appendBE8LinkFlag(const llvm::opt::ArgList &Args, +                       llvm::opt::ArgStringList &CmdArgs, +                       const llvm::Triple &Triple); +enum class ReadTPMode { +  Invalid, +  Soft, +  Cp15, +}; + +enum class FloatABI { +  Invalid, +  Soft, +  SoftFP, +  Hard, +}; + +FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); +ReadTPMode getReadTPMode(const ToolChain &TC, const llvm::opt::ArgList &Args); + +bool useAAPCSForMachO(const llvm::Triple &T); +void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, +                           llvm::StringRef &Arch, llvm::StringRef &CPU, +                           bool FromAs = false); +void getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, +                          const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs, +                          std::vector<llvm::StringRef> &Features, bool ForAS); +int getARMSubArchVersionNumber(const llvm::Triple &Triple); +bool isARMMProfile(const llvm::Triple &Triple); + +} // end namespace arm +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp new file mode 100644 index 0000000000000..7b4dd703c0c7e --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -0,0 +1,520 @@ +//===--- Mips.cpp - Tools Implementations -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +// Get CPU and ABI names. They are not independent +// so we have to calculate them together. +void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, +                            StringRef &CPUName, StringRef &ABIName) { +  const char *DefMips32CPU = "mips32r2"; +  const char *DefMips64CPU = "mips64r2"; + +  // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the +  // default for mips64(el)?-img-linux-gnu. +  if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && +      Triple.isGNUEnvironment()) { +    DefMips32CPU = "mips32r6"; +    DefMips64CPU = "mips64r6"; +  } + +  if (Triple.getSubArch() == llvm::Triple::MipsSubArch_r6) { +    DefMips32CPU = "mips32r6"; +    DefMips64CPU = "mips64r6"; +  } + +  // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android). +  if (Triple.isAndroid()) { +    DefMips32CPU = "mips32"; +    DefMips64CPU = "mips64r6"; +  } + +  // MIPS3 is the default for mips64*-unknown-openbsd. +  if (Triple.isOSOpenBSD()) +    DefMips64CPU = "mips3"; + +  // MIPS2 is the default for mips(el)?-unknown-freebsd. +  // MIPS3 is the default for mips64(el)?-unknown-freebsd. +  if (Triple.isOSFreeBSD()) { +    DefMips32CPU = "mips2"; +    DefMips64CPU = "mips3"; +  } + +  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ, +                               options::OPT_mcpu_EQ)) +    CPUName = A->getValue(); + +  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { +    ABIName = A->getValue(); +    // Convert a GNU style Mips ABI name to the name +    // accepted by LLVM Mips backend. +    ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName) +                  .Case("32", "o32") +                  .Case("64", "n64") +                  .Default(ABIName); +  } + +  // Setup default CPU and ABI names. +  if (CPUName.empty() && ABIName.empty()) { +    switch (Triple.getArch()) { +    default: +      llvm_unreachable("Unexpected triple arch name"); +    case llvm::Triple::mips: +    case llvm::Triple::mipsel: +      CPUName = DefMips32CPU; +      break; +    case llvm::Triple::mips64: +    case llvm::Triple::mips64el: +      CPUName = DefMips64CPU; +      break; +    } +  } + +  if (ABIName.empty() && (Triple.getEnvironment() == llvm::Triple::GNUABIN32)) +    ABIName = "n32"; + +  if (ABIName.empty() && +      (Triple.getVendor() == llvm::Triple::MipsTechnologies || +       Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) { +    ABIName = llvm::StringSwitch<const char *>(CPUName) +                  .Case("mips1", "o32") +                  .Case("mips2", "o32") +                  .Case("mips3", "n64") +                  .Case("mips4", "n64") +                  .Case("mips5", "n64") +                  .Case("mips32", "o32") +                  .Case("mips32r2", "o32") +                  .Case("mips32r3", "o32") +                  .Case("mips32r5", "o32") +                  .Case("mips32r6", "o32") +                  .Case("mips64", "n64") +                  .Case("mips64r2", "n64") +                  .Case("mips64r3", "n64") +                  .Case("mips64r5", "n64") +                  .Case("mips64r6", "n64") +                  .Case("octeon", "n64") +                  .Case("p5600", "o32") +                  .Default(""); +  } + +  if (ABIName.empty()) { +    // Deduce ABI name from the target triple. +    ABIName = Triple.isMIPS32() ? "o32" : "n64"; +  } + +  if (CPUName.empty()) { +    // Deduce CPU name from ABI name. +    CPUName = llvm::StringSwitch<const char *>(ABIName) +                  .Case("o32", DefMips32CPU) +                  .Cases("n32", "n64", DefMips64CPU) +                  .Default(""); +  } + +  // FIXME: Warn on inconsistent use of -march and -mabi. +} + +std::string mips::getMipsABILibSuffix(const ArgList &Args, +                                      const llvm::Triple &Triple) { +  StringRef CPUName, ABIName; +  tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); +  return llvm::StringSwitch<std::string>(ABIName) +      .Case("o32", "") +      .Case("n32", "32") +      .Case("n64", "64"); +} + +// Convert ABI name to the GNU tools acceptable variant. +StringRef mips::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=. +mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args, +                                     const llvm::Triple &Triple) { +  mips::FloatABI ABI = mips::FloatABI::Invalid; +  if (Arg *A = +          Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, +                          options::OPT_mfloat_abi_EQ)) { +    if (A->getOption().matches(options::OPT_msoft_float)) +      ABI = mips::FloatABI::Soft; +    else if (A->getOption().matches(options::OPT_mhard_float)) +      ABI = mips::FloatABI::Hard; +    else { +      ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue()) +                .Case("soft", mips::FloatABI::Soft) +                .Case("hard", mips::FloatABI::Hard) +                .Default(mips::FloatABI::Invalid); +      if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { +        D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); +        ABI = mips::FloatABI::Hard; +      } +    } +  } + +  // If unspecified, choose the default based on the platform. +  if (ABI == mips::FloatABI::Invalid) { +    if (Triple.isOSFreeBSD()) { +      // For FreeBSD, assume "soft" on all flavors of MIPS. +      ABI = mips::FloatABI::Soft; +    } else { +      // Assume "hard", because it's a default value used by gcc. +      // When we start to recognize specific target MIPS processors, +      // we will be able to select the default more correctly. +      ABI = mips::FloatABI::Hard; +    } +  } + +  assert(ABI != mips::FloatABI::Invalid && "must select an ABI"); +  return ABI; +} + +void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, +                                 const ArgList &Args, +                                 std::vector<StringRef> &Features) { +  StringRef CPUName; +  StringRef ABIName; +  getMipsCPUAndABI(Args, Triple, CPUName, ABIName); +  ABIName = getGnuCompatibleMipsABIName(ABIName); + +  // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a +  // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI +  // extension was developed by Richard Sandiford & Code Sourcery to support +  // static code calling PIC code (CPIC). For O32 and N32 this means we have +  // several combinations of PIC/static and abicalls. Pure static, static +  // with the CPIC extension, and pure PIC code. + +  // At final link time, O32 and N32 with CPIC will have another section +  // added to the binary which contains the stub functions to perform +  // any fixups required for PIC code. + +  // For N64, the situation is more regular: code can either be static +  // (non-abicalls) or PIC (abicalls). GCC has traditionally picked PIC code +  // code for N64. Since Clang has already built the relocation model portion +  // of the commandline, we pick add +noabicalls feature in the N64 static +  // case. + +  // The is another case to be accounted for: -msym32, which enforces that all +  // symbols have 32 bits in size. In this case, N64 can in theory use CPIC +  // but it is unsupported. + +  // The combinations for N64 are: +  // a) Static without abicalls and 64bit symbols. +  // b) Static with abicalls and 32bit symbols. +  // c) PIC with abicalls and 64bit symbols. + +  // For case (a) we need to add +noabicalls for N64. + +  bool IsN64 = ABIName == "64"; +  bool IsPIC = false; +  bool NonPIC = false; + +  Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, +                                    options::OPT_fpic, options::OPT_fno_pic, +                                    options::OPT_fPIE, options::OPT_fno_PIE, +                                    options::OPT_fpie, options::OPT_fno_pie); +  if (LastPICArg) { +    Option O = LastPICArg->getOption(); +    NonPIC = +        (O.matches(options::OPT_fno_PIC) || O.matches(options::OPT_fno_pic) || +         O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie)); +    IsPIC = +        (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || +         O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)); +  } + +  bool UseAbiCalls = false; + +  Arg *ABICallsArg = +      Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); +  UseAbiCalls = +      !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls); + +  if (IsN64 && NonPIC && (!ABICallsArg || UseAbiCalls)) { +    D.Diag(diag::warn_drv_unsupported_pic_with_mabicalls) +        << LastPICArg->getAsString(Args) << (!ABICallsArg ? 0 : 1); +  } + +  if (ABICallsArg && !UseAbiCalls && IsPIC) { +    D.Diag(diag::err_drv_unsupported_noabicalls_pic); +  } + +  if (!UseAbiCalls) +    Features.push_back("+noabicalls"); +  else +    Features.push_back("-noabicalls"); + +  if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, +                               options::OPT_mno_long_calls)) { +    if (A->getOption().matches(options::OPT_mno_long_calls)) +      Features.push_back("-long-calls"); +    else if (!UseAbiCalls) +      Features.push_back("+long-calls"); +    else +      D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) { +    if (A->getOption().matches(options::OPT_mxgot)) +      Features.push_back("+xgot"); +    else +      Features.push_back("-xgot"); +  } + +  mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args, Triple); +  if (FloatABI == mips::FloatABI::Soft) { +    // FIXME: Note, this is a hack. We need to pass the selected float +    // mode to the MipsTargetInfoBase to define appropriate macros there. +    // Now it is the only method. +    Features.push_back("+soft-float"); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { +    StringRef Val = StringRef(A->getValue()); +    if (Val == "2008") { +      if (mips::getIEEE754Standard(CPUName) & mips::Std2008) +        Features.push_back("+nan2008"); +      else { +        Features.push_back("-nan2008"); +        D.Diag(diag::warn_target_unsupported_nan2008) << CPUName; +      } +    } else if (Val == "legacy") { +      if (mips::getIEEE754Standard(CPUName) & mips::Legacy) +        Features.push_back("-nan2008"); +      else { +        Features.push_back("+nan2008"); +        D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName; +      } +    } else +      D.Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Val; +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) { +    StringRef Val = StringRef(A->getValue()); +    if (Val == "2008") { +      if (mips::getIEEE754Standard(CPUName) & mips::Std2008) { +        Features.push_back("+abs2008"); +      } else { +        Features.push_back("-abs2008"); +        D.Diag(diag::warn_target_unsupported_abs2008) << CPUName; +      } +    } else if (Val == "legacy") { +      if (mips::getIEEE754Standard(CPUName) & mips::Legacy) { +        Features.push_back("-abs2008"); +      } else { +        Features.push_back("+abs2008"); +        D.Diag(diag::warn_target_unsupported_abslegacy) << CPUName; +      } +    } else { +      D.Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Val; +    } +  } + +  AddTargetFeature(Args, Features, options::OPT_msingle_float, +                   options::OPT_mdouble_float, "single-float"); +  AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16, +                   "mips16"); +  AddTargetFeature(Args, Features, options::OPT_mmicromips, +                   options::OPT_mno_micromips, "micromips"); +  AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp, +                   "dsp"); +  AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2, +                   "dspr2"); +  AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa, +                   "msa"); + +  // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32 +  // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and +  // nooddspreg. +  if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, +                               options::OPT_mfp64)) { +    if (A->getOption().matches(options::OPT_mfp32)) +      Features.push_back("-fp64"); +    else if (A->getOption().matches(options::OPT_mfpxx)) { +      Features.push_back("+fpxx"); +      Features.push_back("+nooddspreg"); +    } else +      Features.push_back("+fp64"); +  } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { +    Features.push_back("+fpxx"); +    Features.push_back("+nooddspreg"); +  } else if (mips::isFP64ADefault(Triple, CPUName)) { +    Features.push_back("+fp64"); +    Features.push_back("+nooddspreg"); +  } + +  AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, +                   options::OPT_modd_spreg, "nooddspreg"); +  AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, +                   "nomadd4"); +  AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt"); +  AddTargetFeature(Args, Features, options::OPT_mcrc, options::OPT_mno_crc, +                   "crc"); +  AddTargetFeature(Args, Features, options::OPT_mvirt, options::OPT_mno_virt, +                   "virt"); +  AddTargetFeature(Args, Features, options::OPT_mginv, options::OPT_mno_ginv, +                   "ginv"); + +  if (Arg *A = Args.getLastArg(options::OPT_mindirect_jump_EQ)) { +    StringRef Val = StringRef(A->getValue()); +    if (Val == "hazard") { +      Arg *B = +          Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); +      Arg *C = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); + +      if (B && B->getOption().matches(options::OPT_mmicromips)) +        D.Diag(diag::err_drv_unsupported_indirect_jump_opt) +            << "hazard" << "micromips"; +      else if (C && C->getOption().matches(options::OPT_mips16)) +        D.Diag(diag::err_drv_unsupported_indirect_jump_opt) +            << "hazard" << "mips16"; +      else if (mips::supportsIndirectJumpHazardBarrier(CPUName)) +        Features.push_back("+use-indirect-jump-hazard"); +      else +        D.Diag(diag::err_drv_unsupported_indirect_jump_opt) +            << "hazard" << CPUName; +    } else +      D.Diag(diag::err_drv_unknown_indirect_jump_opt) << Val; +  } +} + +mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { +  // Strictly speaking, mips32r2 and mips64r2 do not conform to the +  // IEEE754-2008 standard. Support for this standard was first introduced +  // in Release 3. However, other compilers have traditionally allowed it +  // for Release 2 so we should do the same. +  return (IEEE754Standard)llvm::StringSwitch<int>(CPU) +      .Case("mips1", Legacy) +      .Case("mips2", Legacy) +      .Case("mips3", Legacy) +      .Case("mips4", Legacy) +      .Case("mips5", Legacy) +      .Case("mips32", Legacy) +      .Case("mips32r2", Legacy | Std2008) +      .Case("mips32r3", Legacy | Std2008) +      .Case("mips32r5", Legacy | Std2008) +      .Case("mips32r6", Std2008) +      .Case("mips64", Legacy) +      .Case("mips64r2", Legacy | Std2008) +      .Case("mips64r3", Legacy | Std2008) +      .Case("mips64r5", Legacy | Std2008) +      .Case("mips64r6", Std2008) +      .Default(Std2008); +} + +bool mips::hasCompactBranches(StringRef &CPU) { +  // mips32r6 and mips64r6 have compact branches. +  return llvm::StringSwitch<bool>(CPU) +      .Case("mips32r6", true) +      .Case("mips64r6", true) +      .Default(false); +} + +bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) { +  Arg *A = Args.getLastArg(options::OPT_mabi_EQ); +  return A && (A->getValue() == StringRef(Value)); +} + +bool mips::isUCLibc(const ArgList &Args) { +  Arg *A = Args.getLastArg(options::OPT_m_libc_Group); +  return A && A->getOption().matches(options::OPT_muclibc); +} + +bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { +  if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ)) +    return llvm::StringSwitch<bool>(NaNArg->getValue()) +        .Case("2008", true) +        .Case("legacy", false) +        .Default(false); + +  // NaN2008 is the default for MIPS32r6/MIPS64r6. +  return llvm::StringSwitch<bool>(getCPUName(Args, Triple)) +      .Cases("mips32r6", "mips64r6", true) +      .Default(false); + +  return false; +} + +bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { +  if (!Triple.isAndroid()) +    return false; + +  // Android MIPS32R6 defaults to FP64A. +  return llvm::StringSwitch<bool>(CPUName) +      .Case("mips32r6", true) +      .Default(false); +} + +bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, +                         StringRef ABIName, mips::FloatABI FloatABI) { +  if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && +      Triple.getVendor() != llvm::Triple::MipsTechnologies && +      !Triple.isAndroid()) +    return false; + +  if (ABIName != "32") +    return false; + +  // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is +  // present. +  if (FloatABI == mips::FloatABI::Soft) +    return false; + +  return llvm::StringSwitch<bool>(CPUName) +      .Cases("mips2", "mips3", "mips4", "mips5", true) +      .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true) +      .Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true) +      .Default(false); +} + +bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, +                         StringRef CPUName, StringRef ABIName, +                         mips::FloatABI FloatABI) { +  bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI); + +  // FPXX shouldn't be used if -msingle-float is present. +  if (Arg *A = Args.getLastArg(options::OPT_msingle_float, +                               options::OPT_mdouble_float)) +    if (A->getOption().matches(options::OPT_msingle_float)) +      UseFPXX = false; + +  return UseFPXX; +} + +bool mips::supportsIndirectJumpHazardBarrier(StringRef &CPU) { +  // Supporting the hazard barrier method of dealing with indirect +  // jumps requires MIPSR2 support. +  return llvm::StringSwitch<bool>(CPU) +      .Case("mips32r2", true) +      .Case("mips32r3", true) +      .Case("mips32r5", true) +      .Case("mips32r6", true) +      .Case("mips64r2", true) +      .Case("mips64r3", true) +      .Case("mips64r5", true) +      .Case("mips64r6", true) +      .Case("octeon", true) +      .Case("p5600", true) +      .Default(false); +} diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.h b/clang/lib/Driver/ToolChains/Arch/Mips.h new file mode 100644 index 0000000000000..074012f40fe58 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -0,0 +1,61 @@ +//===--- Mips.h - Mips-specific Tool Helpers ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { + +namespace mips { +typedef enum { Legacy = 1, Std2008 = 2 } IEEE754Standard; + +enum class FloatABI { +  Invalid, +  Soft, +  Hard, +}; + +IEEE754Standard getIEEE754Standard(StringRef &CPU); +bool hasCompactBranches(StringRef &CPU); +void getMipsCPUAndABI(const llvm::opt::ArgList &Args, +                      const llvm::Triple &Triple, StringRef &CPUName, +                      StringRef &ABIName); +void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, +                           const llvm::opt::ArgList &Args, +                           std::vector<StringRef> &Features); +StringRef getGnuCompatibleMipsABIName(StringRef ABI); +mips::FloatABI getMipsFloatABI(const Driver &D, const llvm::opt::ArgList &Args, +                               const llvm::Triple &Triple); +std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, +                                const llvm::Triple &Triple); +bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); +bool isUCLibc(const llvm::opt::ArgList &Args); +bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName); +bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, +                   StringRef ABIName, mips::FloatABI FloatABI); +bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, +                   StringRef CPUName, StringRef ABIName, +                   mips::FloatABI FloatABI); +bool supportsIndirectJumpHazardBarrier(StringRef &CPU); + +} // end namespace mips +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp new file mode 100644 index 0000000000000..3e02e57e0f6c7 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -0,0 +1,158 @@ +//===--- PPC.cpp - PPC Helpers for Tools ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PPC.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Host.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. +std::string ppc::getPPCTargetCPU(const ArgList &Args) { +  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { +    StringRef CPUName = A->getValue(); + +    if (CPUName == "native") { +      std::string CPU = llvm::sys::getHostCPUName(); +      if (!CPU.empty() && CPU != "generic") +        return CPU; +      else +        return ""; +    } + +    return llvm::StringSwitch<const char *>(CPUName) +        .Case("common", "generic") +        .Case("440", "440") +        .Case("440fp", "440") +        .Case("450", "450") +        .Case("601", "601") +        .Case("602", "602") +        .Case("603", "603") +        .Case("603e", "603e") +        .Case("603ev", "603ev") +        .Case("604", "604") +        .Case("604e", "604e") +        .Case("620", "620") +        .Case("630", "pwr3") +        .Case("G3", "g3") +        .Case("7400", "7400") +        .Case("G4", "g4") +        .Case("7450", "7450") +        .Case("G4+", "g4+") +        .Case("750", "750") +        .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("power8", "pwr8") +        .Case("power9", "pwr9") +        .Case("pwr3", "pwr3") +        .Case("pwr4", "pwr4") +        .Case("pwr5", "pwr5") +        .Case("pwr5x", "pwr5x") +        .Case("pwr6", "pwr6") +        .Case("pwr6x", "pwr6x") +        .Case("pwr7", "pwr7") +        .Case("pwr8", "pwr8") +        .Case("pwr9", "pwr9") +        .Case("powerpc", "ppc") +        .Case("powerpc64", "ppc64") +        .Case("powerpc64le", "ppc64le") +        .Default(""); +  } + +  return ""; +} + +const char *ppc::getPPCAsmModeForCPU(StringRef Name) { +  return llvm::StringSwitch<const char *>(Name) +        .Case("pwr7", "-mpower7") +        .Case("power7", "-mpower7") +        .Case("pwr8", "-mpower8") +        .Case("power8", "-mpower8") +        .Case("ppc64le", "-mpower8") +        .Case("pwr9", "-mpower9") +        .Case("power9", "-mpower9") +        .Default("-many"); +} + +void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, +                               const ArgList &Args, +                               std::vector<StringRef> &Features) { +  handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); + +  ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); +  if (FloatABI == ppc::FloatABI::Soft) +    Features.push_back("-hard-float"); + +  ppc::ReadGOTPtrMode ReadGOT = ppc::getPPCReadGOTPtrMode(D, Triple, Args); +  if (ReadGOT == ppc::ReadGOTPtrMode::SecurePlt) +    Features.push_back("+secure-plt"); +} + +ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, +                                              const ArgList &Args) { +  if (Args.getLastArg(options::OPT_msecure_plt)) +    return ppc::ReadGOTPtrMode::SecurePlt; +  if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) || +      Triple.isOSNetBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) +    return ppc::ReadGOTPtrMode::SecurePlt; +  else +    return ppc::ReadGOTPtrMode::Bss; +} + +ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) { +  ppc::FloatABI ABI = ppc::FloatABI::Invalid; +  if (Arg *A = +          Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, +                          options::OPT_mfloat_abi_EQ)) { +    if (A->getOption().matches(options::OPT_msoft_float)) +      ABI = ppc::FloatABI::Soft; +    else if (A->getOption().matches(options::OPT_mhard_float)) +      ABI = ppc::FloatABI::Hard; +    else { +      ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue()) +                .Case("soft", ppc::FloatABI::Soft) +                .Case("hard", ppc::FloatABI::Hard) +                .Default(ppc::FloatABI::Invalid); +      if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { +        D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); +        ABI = ppc::FloatABI::Hard; +      } +    } +  } + +  // If unspecified, choose the default based on the platform. +  if (ABI == ppc::FloatABI::Invalid) { +    ABI = ppc::FloatABI::Hard; +  } + +  return ABI; +} + +bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) { +  Arg *A = Args.getLastArg(options::OPT_mabi_EQ); +  return A && (A->getValue() == StringRef(Value)); +} diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.h b/clang/lib/Driver/ToolChains/Arch/PPC.h new file mode 100644 index 0000000000000..e1c943955e812 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/PPC.h @@ -0,0 +1,52 @@ +//===--- PPC.h - PPC-specific Tool Helpers ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace ppc { + +bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value); + +enum class FloatABI { +  Invalid, +  Soft, +  Hard, +}; + +enum class ReadGOTPtrMode { +  Bss, +  SecurePlt, +}; + +FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + +std::string getPPCTargetCPU(const llvm::opt::ArgList &Args); +const char *getPPCAsmModeForCPU(StringRef Name); +ReadGOTPtrMode getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, +                                    const llvm::opt::ArgList &Args); + +void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, +                          const llvm::opt::ArgList &Args, +                          std::vector<llvm::StringRef> &Features); + +} // end namespace ppc +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp new file mode 100644 index 0000000000000..624788a5874e3 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -0,0 +1,402 @@ +//===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/raw_ostream.h" +#include "ToolChains/CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +static StringRef getExtensionTypeDesc(StringRef Ext) { +  if (Ext.startswith("sx")) +    return "non-standard supervisor-level extension"; +  if (Ext.startswith("s")) +    return "standard supervisor-level extension"; +  if (Ext.startswith("x")) +    return "non-standard user-level extension"; +  return StringRef(); +} + +static StringRef getExtensionType(StringRef Ext) { +  if (Ext.startswith("sx")) +    return "sx"; +  if (Ext.startswith("s")) +    return "s"; +  if (Ext.startswith("x")) +    return "x"; +  return StringRef(); +} + +static bool isSupportedExtension(StringRef Ext) { +  // LLVM does not support "sx", "s" nor "x" extensions. +  return false; +} + +// Extensions may have a version number, and may be separated by +// an underscore '_' e.g.: rv32i2_m2. +// Version number is divided into major and minor version numbers, +// separated by a 'p'. If the minor version is 0 then 'p0' can be +// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. +static bool getExtensionVersion(const Driver &D, StringRef MArch, +                                StringRef Ext, StringRef In, +                                std::string &Major, std::string &Minor) { +  Major = In.take_while(isDigit); +  In = In.substr(Major.size()); +  if (Major.empty()) +    return true; + +  if (In.consume_front("p")) { +    Minor = In.take_while(isDigit); +    In = In.substr(Major.size()); + +    // Expected 'p' to be followed by minor version number. +    if (Minor.empty()) { +      std::string Error = +        "minor version number missing after 'p' for extension"; +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +        << MArch << Error << Ext; +      return false; +    } +  } + +  // TODO: Handle extensions with version number. +  std::string Error = "unsupported version number " + Major; +  if (!Minor.empty()) +    Error += "." + Minor; +  Error += " for extension"; +  D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext; + +  return false; +} + +// Handle other types of extensions other than the standard +// general purpose and standard user-level extensions. +// Parse the ISA string containing non-standard user-level +// extensions, standard supervisor-level extensions and +// non-standard supervisor-level extensions. +// These extensions start with 'x', 's', 'sx' prefixes, follow a +// canonical order, might have a version number (major, minor) +// and are separated by a single underscore '_'. +// Set the hardware features for the extensions that are supported. +static void getExtensionFeatures(const Driver &D, +                                 const ArgList &Args, +                                 std::vector<StringRef> &Features, +                                 StringRef &MArch, StringRef &Exts) { +  if (Exts.empty()) +    return; + +  // Multi-letter extensions are seperated by a single underscore +  // as described in RISC-V User-Level ISA V2.2. +  SmallVector<StringRef, 8> Split; +  Exts.split(Split, StringRef("_")); + +  SmallVector<StringRef, 3> Prefix{"x", "s", "sx"}; +  auto I = Prefix.begin(); +  auto E = Prefix.end(); + +  SmallVector<StringRef, 8> AllExts; + +  for (StringRef Ext : Split) { +    if (Ext.empty()) { +      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch +        << "extension name missing after separator '_'"; +      return; +    } + +    StringRef Type = getExtensionType(Ext); +    StringRef Name(Ext.substr(Type.size())); +    StringRef Desc = getExtensionTypeDesc(Ext); + +    if (Type.empty()) { +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +        << MArch << "invalid extension prefix" << Ext; +      return; +    } + +    // Check ISA extensions are specified in the canonical order. +    while (I != E && *I != Type) +      ++I; + +    if (I == E) { +      std::string Error = Desc; +      Error += " not given in canonical order"; +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +        << MArch <<  Error << Ext; +      return; +    } + +    // The order is OK, do not advance I to the next prefix +    // to allow repeated extension type, e.g.: rv32ixabc_xdef. + +    if (Name.empty()) { +      std::string Error = Desc; +      Error += " name missing after"; +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +        << MArch << Error << Ext; +      return; +    } + +    std::string Major, Minor; +    auto Pos = Name.find_if(isDigit); +    if (Pos != StringRef::npos) { +      auto Next =  Name.substr(Pos); +      Name = Name.substr(0, Pos); +      if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor)) +        return; +    } + +    // Check if duplicated extension. +    if (llvm::is_contained(AllExts, Ext)) { +      std::string Error = "duplicated "; +      Error += Desc; +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +        << MArch << Error << Ext; +      return; +    } + +    // Extension format is correct, keep parsing the extensions. +    // TODO: Save Type, Name, Major, Minor to avoid parsing them later. +    AllExts.push_back(Ext); +  } + +  // Set target features. +  // TODO: Hardware features to be handled in Support/TargetParser.cpp. +  // TODO: Use version number when setting target features. +  for (auto Ext : AllExts) { +    if (!isSupportedExtension(Ext)) { +      StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); +      std::string Error = "unsupported "; +      Error += Desc; +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +        << MArch << Error << Ext; +      return; +    } +    Features.push_back(Args.MakeArgString("+" + Ext)); +  } +} + +// Returns false if an error is diagnosed. +static bool getArchFeatures(const Driver &D, StringRef MArch, +                            std::vector<StringRef> &Features, +                            const ArgList &Args) { +  // RISC-V ISA strings must be lowercase. +  if (llvm::any_of(MArch, [](char c) { return isupper(c); })) { +    D.Diag(diag::err_drv_invalid_riscv_arch_name) +        << MArch << "string must be lowercase"; +    return false; +  } + +  // ISA string must begin with rv32 or rv64. +  if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) || +      (MArch.size() < 5)) { +    D.Diag(diag::err_drv_invalid_riscv_arch_name) +        << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}"; +    return false; +  } + +  bool HasRV64 = MArch.startswith("rv64"); + +  // The canonical order specified in ISA manual. +  // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 +  StringRef StdExts = "mafdqlcbjtpvn"; +  bool HasF = false, HasD = false; +  char Baseline = MArch[4]; + +  // First letter should be 'e', 'i' or 'g'. +  switch (Baseline) { +  default: +    D.Diag(diag::err_drv_invalid_riscv_arch_name) +        << MArch << "first letter should be 'e', 'i' or 'g'"; +    return false; +  case 'e': { +    StringRef Error; +    // Currently LLVM does not support 'e'. +    // Extension 'e' is not allowed in rv64. +    if (HasRV64) +      Error = "standard user-level extension 'e' requires 'rv32'"; +    else +      Error = "unsupported standard user-level extension 'e'"; +    D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error; +    return false; +  } +  case 'i': +    break; +  case 'g': +    // g = imafd +    StdExts = StdExts.drop_front(4); +    Features.push_back("+m"); +    Features.push_back("+a"); +    Features.push_back("+f"); +    Features.push_back("+d"); +    HasF = true; +    HasD = true; +    break; +  } + +  // Skip rvxxx +  StringRef Exts = MArch.substr(5); + +  // Remove non-standard extensions and supervisor-level extensions. +  // They have 'x', 's', 'sx' prefixes. Parse them at the end. +  // Find the very first occurrence of 's' or 'x'. +  StringRef OtherExts; +  size_t Pos = Exts.find_first_of("sx"); +  if (Pos != StringRef::npos) { +    OtherExts = Exts.substr(Pos); +    Exts = Exts.substr(0, Pos); +  } + +  std::string Major, Minor; +  if (!getExtensionVersion(D, MArch, std::string(1, Baseline), Exts, Major, +                           Minor)) +    return false; + +  // TODO: Use version number when setting target features +  // and consume the underscore '_' that might follow. + +  auto StdExtsItr = StdExts.begin(); +  auto StdExtsEnd = StdExts.end(); + +  for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) { +    char c = *I; + +    // Check ISA extensions are specified in the canonical order. +    while (StdExtsItr != StdExtsEnd && *StdExtsItr != c) +      ++StdExtsItr; + +    if (StdExtsItr == StdExtsEnd) { +      // Either c contains a valid extension but it was not given in +      // canonical order or it is an invalid extension. +      StringRef Error; +      if (StdExts.contains(c)) +        Error = "standard user-level extension not given in canonical order"; +      else +        Error = "invalid standard user-level extension"; +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +          << MArch << Error << std::string(1, c); +      return false; +    } + +    // Move to next char to prevent repeated letter. +    ++StdExtsItr; + +    if (std::next(I) != E) { +      // Skip c. +      std::string Next = std::string(std::next(I), E); +      std::string Major, Minor; +      if (!getExtensionVersion(D, MArch, std::string(1, c), Next, Major, Minor)) +        return false; + +      // TODO: Use version number when setting target features +      // and consume the underscore '_' that might follow. +    } + +    // The order is OK, then push it into features. +    switch (c) { +    default: +      // Currently LLVM supports only "mafdc". +      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) +          << MArch << "unsupported standard user-level extension" +          << std::string(1, c); +      return false; +    case 'm': +      Features.push_back("+m"); +      break; +    case 'a': +      Features.push_back("+a"); +      break; +    case 'f': +      Features.push_back("+f"); +      HasF = true; +      break; +    case 'd': +      Features.push_back("+d"); +      HasD = true; +      break; +    case 'c': +      Features.push_back("+c"); +      break; +    } +  } + +  // Dependency check. +  // It's illegal to specify the 'd' (double-precision floating point) +  // extension without also specifying the 'f' (single precision +  // floating-point) extension. +  if (HasD && !HasF) { +    D.Diag(diag::err_drv_invalid_riscv_arch_name) +        << MArch << "d requires f extension to also be specified"; +    return false; +  } + +  // Additional dependency checks. +  // TODO: The 'q' extension requires rv64. +  // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. + +  // Handle all other types of extensions. +  getExtensionFeatures(D, Args, Features, MArch, OtherExts); + +  return true; +} + +void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, +                                   const ArgList &Args, +                                   std::vector<StringRef> &Features) { +  llvm::Optional<StringRef> MArch; +  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) +    MArch = A->getValue(); +  else if (Triple.getOS() == llvm::Triple::Linux) +    // RISC-V Linux defaults to rv{32,64}gc. +    MArch = Triple.getArch() == llvm::Triple::riscv32 ? "rv32gc" : "rv64gc"; + +  if (MArch.hasValue() && !getArchFeatures(D, *MArch, Features, Args)) +    return; + +  // -mrelax is default, unless -mno-relax is specified. +  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) +    Features.push_back("+relax"); +  else +    Features.push_back("-relax"); + +  // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is +  // specified... +  if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) { +    // ... but we don't support -msave-restore, so issue a warning. +    D.Diag(diag::warn_drv_clang_unsupported) +      << Args.getLastArg(options::OPT_msave_restore)->getAsString(Args); +  } + +  // Now add any that the user explicitly requested on the command line, +  // which may override the defaults. +  handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); +} + +StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { +  assert((Triple.getArch() == llvm::Triple::riscv32 || +          Triple.getArch() == llvm::Triple::riscv64) && +         "Unexpected triple"); + +  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) +    return A->getValue(); + +  // RISC-V Linux defaults to ilp32d/lp64d +  if (Triple.getOS() == llvm::Triple::Linux) +    return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32d" : "lp64d"; +  else +    return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64"; +} diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.h b/clang/lib/Driver/ToolChains/Arch/RISCV.h new file mode 100644 index 0000000000000..10eaf3c897b68 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.h @@ -0,0 +1,32 @@ +//===--- RISCV.h - RISCV-specific Tool Helpers ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_RISCV_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_RISCV_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace riscv { +void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, +                            const llvm::opt::ArgList &Args, +                            std::vector<llvm::StringRef> &Features); +StringRef getRISCVABI(const llvm::opt::ArgList &Args, +                      const llvm::Triple &Triple); +} // end namespace riscv +} // namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_RISCV_H diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp new file mode 100644 index 0000000000000..043b7f257c01d --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -0,0 +1,114 @@ +//===--- Sparc.cpp - Tools Implementations ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Sparc.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +const char *sparc::getSparcAsmModeForCPU(StringRef Name, +                                         const llvm::Triple &Triple) { +  if (Triple.getArch() == llvm::Triple::sparcv9) { +    return llvm::StringSwitch<const char *>(Name) +        .Case("niagara", "-Av9b") +        .Case("niagara2", "-Av9b") +        .Case("niagara3", "-Av9d") +        .Case("niagara4", "-Av9d") +        .Default("-Av9"); +  } else { +    return llvm::StringSwitch<const char *>(Name) +        .Case("v8", "-Av8") +        .Case("supersparc", "-Av8") +        .Case("sparclite", "-Asparclite") +        .Case("f934", "-Asparclite") +        .Case("hypersparc", "-Av8") +        .Case("sparclite86x", "-Asparclite") +        .Case("sparclet", "-Asparclet") +        .Case("tsc701", "-Asparclet") +        .Case("v9", "-Av8plus") +        .Case("ultrasparc", "-Av8plus") +        .Case("ultrasparc3", "-Av8plus") +        .Case("niagara", "-Av8plusb") +        .Case("niagara2", "-Av8plusb") +        .Case("niagara3", "-Av8plusd") +        .Case("niagara4", "-Av8plusd") +        .Case("ma2100", "-Aleon") +        .Case("ma2150", "-Aleon") +        .Case("ma2155", "-Aleon") +        .Case("ma2450", "-Aleon") +        .Case("ma2455", "-Aleon") +        .Case("ma2x5x", "-Aleon") +        .Case("ma2080", "-Aleon") +        .Case("ma2085", "-Aleon") +        .Case("ma2480", "-Aleon") +        .Case("ma2485", "-Aleon") +        .Case("ma2x8x", "-Aleon") +        .Case("myriad2", "-Aleon") +        .Case("myriad2.1", "-Aleon") +        .Case("myriad2.2", "-Aleon") +        .Case("myriad2.3", "-Aleon") +        .Case("leon2", "-Av8") +        .Case("at697e", "-Av8") +        .Case("at697f", "-Av8") +        .Case("leon3", "-Aleon") +        .Case("ut699", "-Av8") +        .Case("gr712rc", "-Aleon") +        .Case("leon4", "-Aleon") +        .Case("gr740", "-Aleon") +        .Default("-Av8"); +  } +} + +sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, +                                        const ArgList &Args) { +  sparc::FloatABI ABI = sparc::FloatABI::Invalid; +  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float, +                               options::OPT_mhard_float, +                               options::OPT_mfloat_abi_EQ)) { +    if (A->getOption().matches(clang::driver::options::OPT_msoft_float)) +      ABI = sparc::FloatABI::Soft; +    else if (A->getOption().matches(options::OPT_mhard_float)) +      ABI = sparc::FloatABI::Hard; +    else { +      ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue()) +                .Case("soft", sparc::FloatABI::Soft) +                .Case("hard", sparc::FloatABI::Hard) +                .Default(sparc::FloatABI::Invalid); +      if (ABI == sparc::FloatABI::Invalid && +          !StringRef(A->getValue()).empty()) { +        D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); +        ABI = sparc::FloatABI::Hard; +      } +    } +  } + +  // If unspecified, choose the default based on the platform. +  // Only the hard-float ABI on Sparc is standardized, and it is the +  // default. GCC also supports a nonstandard soft-float ABI mode, also +  // implemented in LLVM. However as this is not standard we set the default +  // to be hard-float. +  if (ABI == sparc::FloatABI::Invalid) { +    ABI = sparc::FloatABI::Hard; +  } + +  return ABI; +} + +void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args, +                                   std::vector<StringRef> &Features) { +  sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args); +  if (FloatABI == sparc::FloatABI::Soft) +    Features.push_back("+soft-float"); +} diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.h b/clang/lib/Driver/ToolChains/Arch/Sparc.h new file mode 100644 index 0000000000000..d12a9a70e264c --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/Sparc.h @@ -0,0 +1,41 @@ +//===--- Sparc.h - Sparc-specific Tool Helpers ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace sparc { + +enum class FloatABI { +  Invalid, +  Soft, +  Hard, +}; + +FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + +void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +                            std::vector<llvm::StringRef> &Features); +const char *getSparcAsmModeForCPU(llvm::StringRef Name, +                                  const llvm::Triple &Triple); + +} // end namespace sparc +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp new file mode 100644 index 0000000000000..ca60b85cf8a05 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -0,0 +1,40 @@ +//===--- SystemZ.cpp - SystemZ Helpers for Tools ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +const char *systemz::getSystemZTargetCPU(const ArgList &Args) { +  if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) +    return A->getValue(); +  return "z10"; +} + +void systemz::getSystemZTargetFeatures(const ArgList &Args, +                                       std::vector<llvm::StringRef> &Features) { +  // -m(no-)htm overrides use of the transactional-execution facility. +  if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) { +    if (A->getOption().matches(options::OPT_mhtm)) +      Features.push_back("+transactional-execution"); +    else +      Features.push_back("-transactional-execution"); +  } +  // -m(no-)vx overrides use of the vector facility. +  if (Arg *A = Args.getLastArg(options::OPT_mvx, options::OPT_mno_vx)) { +    if (A->getOption().matches(options::OPT_mvx)) +      Features.push_back("+vector"); +    else +      Features.push_back("-vector"); +  } +} diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/clang/lib/Driver/ToolChains/Arch/SystemZ.h new file mode 100644 index 0000000000000..11d77fa01cc88 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h @@ -0,0 +1,31 @@ +//===--- SystemZ.h - SystemZ-specific Tool Helpers --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace systemz { + +const char *getSystemZTargetCPU(const llvm::opt::ArgList &Args); + +void getSystemZTargetFeatures(const llvm::opt::ArgList &Args, +                              std::vector<llvm::StringRef> &Features); + +} // end namespace systemz +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp new file mode 100644 index 0000000000000..d2b97bf6ad719 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -0,0 +1,175 @@ +//===--- X86.cpp - X86 Helpers for Tools ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "X86.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Host.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +const char *x86::getX86TargetCPU(const ArgList &Args, +                                 const llvm::Triple &Triple) { +  if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { +    if (StringRef(A->getValue()) != "native") +      return A->getValue(); + +    // FIXME: Reject attempts to use -march=native unless the target matches +    // the host. +    // +    // FIXME: We should also incorporate the detected target features for use +    // with -native. +    std::string CPU = llvm::sys::getHostCPUName(); +    if (!CPU.empty() && CPU != "generic") +      return Args.MakeArgString(CPU); +  } + +  if (const Arg *A = Args.getLastArgNoClaim(options::OPT__SLASH_arch)) { +    // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap(). +    StringRef Arch = A->getValue(); +    const char *CPU = nullptr; +    if (Triple.getArch() == llvm::Triple::x86) {  // 32-bit-only /arch: flags. +      CPU = llvm::StringSwitch<const char *>(Arch) +                .Case("IA32", "i386") +                .Case("SSE", "pentium3") +                .Case("SSE2", "pentium4") +                .Default(nullptr); +    } +    if (CPU == nullptr) {  // 32-bit and 64-bit /arch: flags. +      CPU = llvm::StringSwitch<const char *>(Arch) +                .Case("AVX", "sandybridge") +                .Case("AVX2", "haswell") +                .Case("AVX512F", "knl") +                .Case("AVX512", "skylake-avx512") +                .Default(nullptr); +    } +    if (CPU) { +      A->claim(); +      return CPU; +    } +  } + +  // Select the default CPU if none was given (or detection failed). + +  if (Triple.getArch() != llvm::Triple::x86_64 && +      Triple.getArch() != llvm::Triple::x86) +    return nullptr; // This routine is only handling x86 targets. + +  bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64; + +  // FIXME: Need target hooks. +  if (Triple.isOSDarwin()) { +    if (Triple.getArchName() == "x86_64h") +      return "core-avx2"; +    // macosx10.12 drops support for all pre-Penryn Macs. +    // Simulators can still run on 10.11 though, like Xcode. +    if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12)) +      return "penryn"; +    // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah. +    return Is64Bit ? "core2" : "yonah"; +  } + +  // Set up default CPU name for PS4 compilers. +  if (Triple.isPS4CPU()) +    return "btver2"; + +  // On Android use targets compatible with gcc +  if (Triple.isAndroid()) +    return Is64Bit ? "x86-64" : "i686"; + +  // Everything else goes to x86-64 in 64-bit mode. +  if (Is64Bit) +    return "x86-64"; + +  switch (Triple.getOS()) { +  case llvm::Triple::FreeBSD: +  case llvm::Triple::NetBSD: +  case llvm::Triple::OpenBSD: +    return "i486"; +  case llvm::Triple::Haiku: +    return "i586"; +  default: +    // Fallback to p4. +    return "pentium4"; +  } +} + +void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, +                               const ArgList &Args, +                               std::vector<StringRef> &Features) { +  // If -march=native, autodetect the feature list. +  if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { +    if (StringRef(A->getValue()) == "native") { +      llvm::StringMap<bool> HostFeatures; +      if (llvm::sys::getHostCPUFeatures(HostFeatures)) +        for (auto &F : HostFeatures) +          Features.push_back( +              Args.MakeArgString((F.second ? "+" : "-") + F.first())); +    } +  } + +  if (Triple.getArchName() == "x86_64h") { +    // x86_64h implies quite a few of the more modern subtarget features +    // for Haswell class CPUs, but not all of them. Opt-out of a few. +    Features.push_back("-rdrnd"); +    Features.push_back("-aes"); +    Features.push_back("-pclmul"); +    Features.push_back("-rtm"); +    Features.push_back("-fsgsbase"); +  } + +  const llvm::Triple::ArchType ArchType = Triple.getArch(); +  // Add features to be compatible with gcc for Android. +  if (Triple.isAndroid()) { +    if (ArchType == llvm::Triple::x86_64) { +      Features.push_back("+sse4.2"); +      Features.push_back("+popcnt"); +      Features.push_back("+cx16"); +    } else +      Features.push_back("+ssse3"); +  } + +  // Translate the high level `-mretpoline` flag to the specific target feature +  // flags. We also detect if the user asked for retpoline external thunks but +  // failed to ask for retpolines themselves (through any of the different +  // flags). This is a bit hacky but keeps existing usages working. We should +  // consider deprecating this and instead warn if the user requests external +  // retpoline thunks and *doesn't* request some form of retpolines. +  if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline, +                         options::OPT_mspeculative_load_hardening, +                         options::OPT_mno_speculative_load_hardening)) { +    if (Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline, +                     false)) { +      Features.push_back("+retpoline-indirect-calls"); +      Features.push_back("+retpoline-indirect-branches"); +    } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening, +                            options::OPT_mno_speculative_load_hardening, +                            false)) { +      // On x86, speculative load hardening relies on at least using retpolines +      // for indirect calls. +      Features.push_back("+retpoline-indirect-calls"); +    } +  } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk, +                          options::OPT_mno_retpoline_external_thunk, false)) { +    // FIXME: Add a warning about failing to specify `-mretpoline` and +    // eventually switch to an error here. +    Features.push_back("+retpoline-indirect-calls"); +    Features.push_back("+retpoline-indirect-branches"); +  } + +  // Now add any that the user explicitly requested on the command line, +  // which may override the defaults. +  handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group); +} diff --git a/clang/lib/Driver/ToolChains/Arch/X86.h b/clang/lib/Driver/ToolChains/Arch/X86.h new file mode 100644 index 0000000000000..9f9c2b8c4b499 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/X86.h @@ -0,0 +1,36 @@ +//===--- X86.h - X86-specific Tool Helpers ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace x86 { + +const char *getX86TargetCPU(const llvm::opt::ArgList &Args, +                            const llvm::Triple &Triple); + +void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, +                          const llvm::opt::ArgList &Args, +                          std::vector<llvm::StringRef> &Features); + +} // end namespace x86 +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp new file mode 100644 index 0000000000000..dff0e04183ef9 --- /dev/null +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -0,0 +1,197 @@ +//===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BareMetal.h" + +#include "CommonArgs.h" +#include "InputInfo.h" +#include "Gnu.h" + +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::opt; +using namespace clang; +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; + +BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, +                           const ArgList &Args) +    : ToolChain(D, Triple, Args) { +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); +} + +BareMetal::~BareMetal() {} + +/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? +static bool isARMBareMetal(const llvm::Triple &Triple) { +  if (Triple.getArch() != llvm::Triple::arm && +      Triple.getArch() != llvm::Triple::thumb) +    return false; + +  if (Triple.getVendor() != llvm::Triple::UnknownVendor) +    return false; + +  if (Triple.getOS() != llvm::Triple::UnknownOS) +    return false; + +  if (Triple.getEnvironment() != llvm::Triple::EABI && +      Triple.getEnvironment() != llvm::Triple::EABIHF) +    return false; + +  return true; +} + +bool BareMetal::handlesTarget(const llvm::Triple &Triple) { +  return isARMBareMetal(Triple); +} + +Tool *BareMetal::buildLinker() const { +  return new tools::baremetal::Linker(*this); +} + +std::string BareMetal::getRuntimesDir() const { +  SmallString<128> Dir(getDriver().ResourceDir); +  llvm::sys::path::append(Dir, "lib", "baremetal"); +  return Dir.str(); +} + +void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                          ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> Dir(getDriver().ResourceDir); +    llvm::sys::path::append(Dir, "include"); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +  } + +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { +    SmallString<128> Dir(getDriver().SysRoot); +    llvm::sys::path::append(Dir, "include"); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +  } +} + +void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, +                                      ArgStringList &CC1Args, +                                      Action::OffloadKind) const { +  CC1Args.push_back("-nostdsysteminc"); +} + +void BareMetal::AddClangCXXStdlibIncludeArgs( +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  StringRef SysRoot = getDriver().SysRoot; +  if (SysRoot.empty()) +    return; + +  switch (GetCXXStdlibType(DriverArgs)) { +  case ToolChain::CST_Libcxx: { +    SmallString<128> Dir(SysRoot); +    llvm::sys::path::append(Dir, "include", "c++", "v1"); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +    break; +  } +  case ToolChain::CST_Libstdcxx: { +    SmallString<128> Dir(SysRoot); +    llvm::sys::path::append(Dir, "include", "c++"); +    std::error_code EC; +    Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; +    // Walk the subdirs, and find the one with the newest gcc version: +    for (llvm::vfs::directory_iterator +             LI = getDriver().getVFS().dir_begin(Dir.str(), EC), +             LE; +         !EC && LI != LE; LI = LI.increment(EC)) { +      StringRef VersionText = llvm::sys::path::filename(LI->path()); +      auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); +      if (CandidateVersion.Major == -1) +        continue; +      if (CandidateVersion <= Version) +        continue; +      Version = CandidateVersion; +    } +    if (Version.Major == -1) +      return; +    llvm::sys::path::append(Dir, Version.Text); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +    break; +  } +  } +} + +void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, +                                    ArgStringList &CmdArgs) const { +  switch (GetCXXStdlibType(Args)) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    CmdArgs.push_back("-lc++abi"); +    break; +  case ToolChain::CST_Libstdcxx: +    CmdArgs.push_back("-lstdc++"); +    CmdArgs.push_back("-lsupc++"); +    break; +  } +  CmdArgs.push_back("-lunwind"); +} + +void BareMetal::AddLinkRuntimeLib(const ArgList &Args, +                                  ArgStringList &CmdArgs) const { +  CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" + +                                       getTriple().getArchName() + ".a")); +} + +void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                     const InputInfo &Output, +                                     const InputInfoList &Inputs, +                                     const ArgList &Args, +                                     const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); + +  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + +  CmdArgs.push_back("-Bstatic"); + +  CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + +  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, +                            options::OPT_e, options::OPT_s, options::OPT_t, +                            options::OPT_Z_Flag, options::OPT_r}); + +  if (TC.ShouldLinkCXXStdlib(Args)) +    TC.AddCXXStdlibLibArgs(Args, CmdArgs); +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    CmdArgs.push_back("-lc"); +    CmdArgs.push_back("-lm"); + +    TC.AddLinkRuntimeLib(Args, CmdArgs); +  } + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  C.addCommand(std::make_unique<Command>(JA, *this, +                                          Args.MakeArgString(TC.GetLinkerPath()), +                                          CmdArgs, Inputs)); +} diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h new file mode 100644 index 0000000000000..4c0c739307b14 --- /dev/null +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -0,0 +1,86 @@ +//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +#include <string> + +namespace clang { +namespace driver { + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { +public: +  BareMetal(const Driver &D, const llvm::Triple &Triple, +            const llvm::opt::ArgList &Args); +  ~BareMetal() override; + +  static bool handlesTarget(const llvm::Triple &Triple); +protected: +  Tool *buildLinker() const override; + +public: +  bool useIntegratedAs() const override { return true; } +  bool isCrossCompiling() const override { return true; } +  bool isPICDefault() const override { return false; } +  bool isPIEDefault() const override { return false; } +  bool isPICDefaultForced() const override { return false; } +  bool SupportsProfiling() const override { return false; } + +  RuntimeLibType GetDefaultRuntimeLibType() const override { +    return ToolChain::RLT_CompilerRT; +  } +  CXXStdlibType GetDefaultCXXStdlibType() const override { +    return ToolChain::CST_Libcxx; +  } + +  const char *getDefaultLinker() const override { return "ld.lld"; } + +  std::string getRuntimesDir() const; +  void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                                 llvm::opt::ArgStringList &CC1Args) const override; +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; +  void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs) const; +}; + +} // namespace toolchains + +namespace tools { +namespace baremetal { + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {} +  bool isLinkJob() const override { return true; } +  bool hasIntegratedCPP() const override { return false; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +} // namespace baremetal +} // namespace tools + +} // namespace driver +} // namespace clang + +#endif diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp new file mode 100644 index 0000000000000..55d631733add2 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -0,0 +1,6451 @@ +//===-- Clang.cpp - Clang+LLVM ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Clang.h" +#include "Arch/AArch64.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "Arch/RISCV.h" +#include "Arch/Sparc.h" +#include "Arch/SystemZ.h" +#include "Arch/X86.h" +#include "AMDGPU.h" +#include "CommonArgs.h" +#include "Hexagon.h" +#include "MSP430.h" +#include "InputInfo.h" +#include "PS4CPU.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Distro.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/XRayArgs.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/YAMLParser.h" + +#ifdef LLVM_ON_UNIX +#include <unistd.h> // For getuid(). +#endif + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { +  if (Arg *A = +          Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) { +    if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && +        !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { +      D.Diag(clang::diag::err_drv_argument_only_allowed_with) +          << A->getBaseArg().getAsString(Args) +          << (D.IsCLMode() ? "/E, /P or /EP" : "-E"); +    } +  } +} + +static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { +  // In gcc, only ARM checks this, but it seems reasonable to check universally. +  if (Args.hasArg(options::OPT_static)) +    if (const Arg *A = +            Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic)) +      D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) +                                                      << "-static"; +} + +// Add backslashes to escape spaces and other backslashes. +// This is used for the space-separated argument list specified with +// the -dwarf-debug-flags option. +static void EscapeSpacesAndBackslashes(const char *Arg, +                                       SmallVectorImpl<char> &Res) { +  for (; *Arg; ++Arg) { +    switch (*Arg) { +    default: +      break; +    case ' ': +    case '\\': +      Res.push_back('\\'); +      break; +    } +    Res.push_back(*Arg); +  } +} + +// Quote target names for inclusion in GNU Make dependency files. +// Only the characters '$', '#', ' ', '\t' are quoted. +static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) { +  for (unsigned i = 0, e = Target.size(); i != e; ++i) { +    switch (Target[i]) { +    case ' ': +    case '\t': +      // Escape the preceding backslashes +      for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) +        Res.push_back('\\'); + +      // Escape the space/tab +      Res.push_back('\\'); +      break; +    case '$': +      Res.push_back('$'); +      break; +    case '#': +      Res.push_back('\\'); +      break; +    default: +      break; +    } + +    Res.push_back(Target[i]); +  } +} + +/// Apply \a Work on the current tool chain \a RegularToolChain and any other +/// offloading tool chain that is associated with the current action \a JA. +static void +forAllAssociatedToolChains(Compilation &C, const JobAction &JA, +                           const ToolChain &RegularToolChain, +                           llvm::function_ref<void(const ToolChain &)> Work) { +  // Apply Work on the current/regular tool chain. +  Work(RegularToolChain); + +  // Apply Work on all the offloading tool chains associated with the current +  // action. +  if (JA.isHostOffloading(Action::OFK_Cuda)) +    Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>()); +  else if (JA.isDeviceOffloading(Action::OFK_Cuda)) +    Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); +  else if (JA.isHostOffloading(Action::OFK_HIP)) +    Work(*C.getSingleOffloadToolChain<Action::OFK_HIP>()); +  else if (JA.isDeviceOffloading(Action::OFK_HIP)) +    Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + +  if (JA.isHostOffloading(Action::OFK_OpenMP)) { +    auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>(); +    for (auto II = TCs.first, IE = TCs.second; II != IE; ++II) +      Work(*II->second); +  } else if (JA.isDeviceOffloading(Action::OFK_OpenMP)) +    Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + +  // +  // TODO: Add support for other offloading programming models here. +  // +} + +/// This is a helper function for validating the optional refinement step +/// parameter in reciprocal argument strings. Return false if there is an error +/// parsing the refinement step. Otherwise, return true and set the Position +/// of the refinement step in the input string. +static bool getRefinementStep(StringRef In, const Driver &D, +                              const Arg &A, size_t &Position) { +  const char RefinementStepToken = ':'; +  Position = In.find(RefinementStepToken); +  if (Position != StringRef::npos) { +    StringRef Option = A.getOption().getName(); +    StringRef RefStep = In.substr(Position + 1); +    // Allow exactly one numeric character for the additional refinement +    // step parameter. This is reasonable for all currently-supported +    // operations and architectures because we would expect that a larger value +    // of refinement steps would cause the estimate "optimization" to +    // under-perform the native operation. Also, if the estimate does not +    // converge quickly, it probably will not ever converge, so further +    // refinement steps will not produce a better answer. +    if (RefStep.size() != 1) { +      D.Diag(diag::err_drv_invalid_value) << Option << RefStep; +      return false; +    } +    char RefStepChar = RefStep[0]; +    if (RefStepChar < '0' || RefStepChar > '9') { +      D.Diag(diag::err_drv_invalid_value) << Option << RefStep; +      return false; +    } +  } +  return true; +} + +/// The -mrecip flag requires processing of many optional parameters. +static void ParseMRecip(const Driver &D, const ArgList &Args, +                        ArgStringList &OutStrings) { +  StringRef DisabledPrefixIn = "!"; +  StringRef DisabledPrefixOut = "!"; +  StringRef EnabledPrefixOut = ""; +  StringRef Out = "-mrecip="; + +  Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); +  if (!A) +    return; + +  unsigned NumOptions = A->getNumValues(); +  if (NumOptions == 0) { +    // No option is the same as "all". +    OutStrings.push_back(Args.MakeArgString(Out + "all")); +    return; +  } + +  // Pass through "all", "none", or "default" with an optional refinement step. +  if (NumOptions == 1) { +    StringRef Val = A->getValue(0); +    size_t RefStepLoc; +    if (!getRefinementStep(Val, D, *A, RefStepLoc)) +      return; +    StringRef ValBase = Val.slice(0, RefStepLoc); +    if (ValBase == "all" || ValBase == "none" || ValBase == "default") { +      OutStrings.push_back(Args.MakeArgString(Out + Val)); +      return; +    } +  } + +  // Each reciprocal type may be enabled or disabled individually. +  // Check each input value for validity, concatenate them all back together, +  // and pass through. + +  llvm::StringMap<bool> OptionStrings; +  OptionStrings.insert(std::make_pair("divd", false)); +  OptionStrings.insert(std::make_pair("divf", false)); +  OptionStrings.insert(std::make_pair("vec-divd", false)); +  OptionStrings.insert(std::make_pair("vec-divf", false)); +  OptionStrings.insert(std::make_pair("sqrtd", false)); +  OptionStrings.insert(std::make_pair("sqrtf", false)); +  OptionStrings.insert(std::make_pair("vec-sqrtd", false)); +  OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + +  for (unsigned i = 0; i != NumOptions; ++i) { +    StringRef Val = A->getValue(i); + +    bool IsDisabled = Val.startswith(DisabledPrefixIn); +    // Ignore the disablement token for string matching. +    if (IsDisabled) +      Val = Val.substr(1); + +    size_t RefStep; +    if (!getRefinementStep(Val, D, *A, RefStep)) +      return; + +    StringRef ValBase = Val.slice(0, RefStep); +    llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase); +    if (OptionIter == OptionStrings.end()) { +      // Try again specifying float suffix. +      OptionIter = OptionStrings.find(ValBase.str() + 'f'); +      if (OptionIter == OptionStrings.end()) { +        // The input name did not match any known option string. +        D.Diag(diag::err_drv_unknown_argument) << Val; +        return; +      } +      // The option was specified without a float or double suffix. +      // Make sure that the double entry was not already specified. +      // The float entry will be checked below. +      if (OptionStrings[ValBase.str() + 'd']) { +        D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; +        return; +      } +    } + +    if (OptionIter->second == true) { +      // Duplicate option specified. +      D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; +      return; +    } + +    // Mark the matched option as found. Do not allow duplicate specifiers. +    OptionIter->second = true; + +    // If the precision was not specified, also mark the double entry as found. +    if (ValBase.back() != 'f' && ValBase.back() != 'd') +      OptionStrings[ValBase.str() + 'd'] = true; + +    // Build the output string. +    StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; +    Out = Args.MakeArgString(Out + Prefix + Val); +    if (i != NumOptions - 1) +      Out = Args.MakeArgString(Out + ","); +  } + +  OutStrings.push_back(Args.MakeArgString(Out)); +} + +/// The -mprefer-vector-width option accepts either a positive integer +/// or the string "none". +static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, +                                    ArgStringList &CmdArgs) { +  Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); +  if (!A) +    return; + +  StringRef Value = A->getValue(); +  if (Value == "none") { +    CmdArgs.push_back("-mprefer-vector-width=none"); +  } else { +    unsigned Width; +    if (Value.getAsInteger(10, Width)) { +      D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value; +      return; +    } +    CmdArgs.push_back(Args.MakeArgString("-mprefer-vector-width=" + Value)); +  } +} + +static bool +shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, +                                          const llvm::Triple &Triple) { +  // We use the zero-cost exception tables for Objective-C if the non-fragile +  // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and +  // later. +  if (runtime.isNonFragile()) +    return true; + +  if (!Triple.isMacOSX()) +    return false; + +  return (!Triple.isMacOSXVersionLT(10, 5) && +          (Triple.getArch() == llvm::Triple::x86_64 || +           Triple.getArch() == llvm::Triple::arm)); +} + +/// Adds exception related arguments to the driver command arguments. There's a +/// master flag, -fexceptions and also language specific flags to enable/disable +/// C++ and Objective-C exceptions. This makes it possible to for example +/// disable C++ exceptions but enable Objective-C exceptions. +static void addExceptionArgs(const ArgList &Args, types::ID InputType, +                             const ToolChain &TC, bool KernelOrKext, +                             const ObjCRuntime &objcRuntime, +                             ArgStringList &CmdArgs) { +  const llvm::Triple &Triple = TC.getTriple(); + +  if (KernelOrKext) { +    // -mkernel and -fapple-kext imply no exceptions, so claim exception related +    // arguments now to avoid warnings about unused arguments. +    Args.ClaimAllArgs(options::OPT_fexceptions); +    Args.ClaimAllArgs(options::OPT_fno_exceptions); +    Args.ClaimAllArgs(options::OPT_fobjc_exceptions); +    Args.ClaimAllArgs(options::OPT_fno_objc_exceptions); +    Args.ClaimAllArgs(options::OPT_fcxx_exceptions); +    Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions); +    return; +  } + +  // See if the user explicitly enabled exceptions. +  bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, +                         false); + +  // Obj-C exceptions are enabled by default, regardless of -fexceptions. This +  // is not necessarily sensible, but follows GCC. +  if (types::isObjC(InputType) && +      Args.hasFlag(options::OPT_fobjc_exceptions, +                   options::OPT_fno_objc_exceptions, true)) { +    CmdArgs.push_back("-fobjc-exceptions"); + +    EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple); +  } + +  if (types::isCXX(InputType)) { +    // Disable C++ EH by default on XCore and PS4. +    bool CXXExceptionsEnabled = +        Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); +    Arg *ExceptionArg = Args.getLastArg( +        options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, +        options::OPT_fexceptions, options::OPT_fno_exceptions); +    if (ExceptionArg) +      CXXExceptionsEnabled = +          ExceptionArg->getOption().matches(options::OPT_fcxx_exceptions) || +          ExceptionArg->getOption().matches(options::OPT_fexceptions); + +    if (CXXExceptionsEnabled) { +      CmdArgs.push_back("-fcxx-exceptions"); + +      EH = true; +    } +  } + +  if (EH) +    CmdArgs.push_back("-fexceptions"); +} + +static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) { +  bool Default = true; +  if (TC.getTriple().isOSDarwin()) { +    // The native darwin assembler doesn't support the linker_option directives, +    // so we disable them if we think the .s file will be passed to it. +    Default = TC.useIntegratedAs(); +  } +  return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, +                       Default); +} + +static bool ShouldDisableDwarfDirectory(const ArgList &Args, +                                        const ToolChain &TC) { +  bool UseDwarfDirectory = +      Args.hasFlag(options::OPT_fdwarf_directory_asm, +                   options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs()); +  return !UseDwarfDirectory; +} + +// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases +// to the corresponding DebugInfoKind. +static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { +  assert(A.getOption().matches(options::OPT_gN_Group) && +         "Not a -g option that specifies a debug-info level"); +  if (A.getOption().matches(options::OPT_g0) || +      A.getOption().matches(options::OPT_ggdb0)) +    return codegenoptions::NoDebugInfo; +  if (A.getOption().matches(options::OPT_gline_tables_only) || +      A.getOption().matches(options::OPT_ggdb1)) +    return codegenoptions::DebugLineTablesOnly; +  if (A.getOption().matches(options::OPT_gline_directives_only)) +    return codegenoptions::DebugDirectivesOnly; +  return codegenoptions::LimitedDebugInfo; +} + +static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { +  switch (Triple.getArch()){ +  default: +    return false; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    // ARM Darwin targets require a frame pointer to be always present to aid +    // offline debugging via backtraces. +    return Triple.isOSDarwin(); +  } +} + +static bool useFramePointerForTargetByDefault(const ArgList &Args, +                                              const llvm::Triple &Triple) { +  if (Args.hasArg(options::OPT_pg)) +    return true; + +  switch (Triple.getArch()) { +  case llvm::Triple::xcore: +  case llvm::Triple::wasm32: +  case llvm::Triple::wasm64: +  case llvm::Triple::msp430: +    // XCore never wants frame pointers, regardless of OS. +    // WebAssembly never wants frame pointers. +    return false; +  case llvm::Triple::ppc: +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +    return !areOptimizationsEnabled(Args); +  default: +    break; +  } + +  if (Triple.isOSNetBSD()) { +    return !areOptimizationsEnabled(Args); +  } + +  if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI || +      Triple.isOSHurd()) { +    switch (Triple.getArch()) { +    // Don't use a frame pointer on linux if optimizing for certain targets. +    case llvm::Triple::mips64: +    case llvm::Triple::mips64el: +    case llvm::Triple::mips: +    case llvm::Triple::mipsel: +    case llvm::Triple::systemz: +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      return !areOptimizationsEnabled(Args); +    default: +      return true; +    } +  } + +  if (Triple.isOSWindows()) { +    switch (Triple.getArch()) { +    case llvm::Triple::x86: +      return !areOptimizationsEnabled(Args); +    case llvm::Triple::x86_64: +      return Triple.isOSBinFormatMachO(); +    case llvm::Triple::arm: +    case llvm::Triple::thumb: +      // Windows on ARM builds with FPO disabled to aid fast stack walking +      return true; +    default: +      // All other supported Windows ISAs use xdata unwind information, so frame +      // pointers are not generally useful. +      return false; +    } +  } + +  return true; +} + +static CodeGenOptions::FramePointerKind +getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { +  // We have 4 states: +  // +  //  00) leaf retained, non-leaf retained +  //  01) leaf retained, non-leaf omitted (this is invalid) +  //  10) leaf omitted, non-leaf retained +  //      (what -momit-leaf-frame-pointer was designed for) +  //  11) leaf omitted, non-leaf omitted +  // +  //  "omit" options taking precedence over "no-omit" options is the only way +  //  to make 3 valid states representable +  Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, +                           options::OPT_fno_omit_frame_pointer); +  bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); +  bool NoOmitFP = +      A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); +  bool KeepLeaf = +      Args.hasFlag(options::OPT_momit_leaf_frame_pointer, +                   options::OPT_mno_omit_leaf_frame_pointer, Triple.isPS4CPU()); +  if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || +      (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { +    if (KeepLeaf) +      return CodeGenOptions::FramePointerKind::NonLeaf; +    return CodeGenOptions::FramePointerKind::All; +  } +  return CodeGenOptions::FramePointerKind::None; +} + +/// Add a CC1 option to specify the debug compilation directory. +static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, +                               const llvm::vfs::FileSystem &VFS) { +  if (Arg *A = Args.getLastArg(options::OPT_fdebug_compilation_dir)) { +    CmdArgs.push_back("-fdebug-compilation-dir"); +    CmdArgs.push_back(A->getValue()); +  } else if (llvm::ErrorOr<std::string> CWD = +                 VFS.getCurrentWorkingDirectory()) { +    CmdArgs.push_back("-fdebug-compilation-dir"); +    CmdArgs.push_back(Args.MakeArgString(*CWD)); +  } +} + +/// Add a CC1 and CC1AS option to specify the debug file path prefix map. +static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { +  for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { +    StringRef Map = A->getValue(); +    if (Map.find('=') == StringRef::npos) +      D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; +    else +      CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); +    A->claim(); +  } +} + +/// Vectorize at all optimization levels greater than 1 except for -Oz. +/// For -Oz the loop vectorizer is disabled, while the slp vectorizer is +/// enabled. +static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { +    if (A->getOption().matches(options::OPT_O4) || +        A->getOption().matches(options::OPT_Ofast)) +      return true; + +    if (A->getOption().matches(options::OPT_O0)) +      return false; + +    assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag"); + +    // Vectorize -Os. +    StringRef S(A->getValue()); +    if (S == "s") +      return true; + +    // Don't vectorize -Oz, unless it's the slp vectorizer. +    if (S == "z") +      return isSlpVec; + +    unsigned OptLevel = 0; +    if (S.getAsInteger(10, OptLevel)) +      return false; + +    return OptLevel > 1; +  } + +  return false; +} + +/// Add -x lang to \p CmdArgs for \p Input. +static void addDashXForInput(const ArgList &Args, const InputInfo &Input, +                             ArgStringList &CmdArgs) { +  // When using -verify-pch, we don't want to provide the type +  // 'precompiled-header' if it was inferred from the file extension +  if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH) +    return; + +  CmdArgs.push_back("-x"); +  if (Args.hasArg(options::OPT_rewrite_objc)) +    CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); +  else { +    // Map the driver type to the frontend type. This is mostly an identity +    // mapping, except that the distinction between module interface units +    // and other source files does not exist at the frontend layer. +    const char *ClangType; +    switch (Input.getType()) { +    case types::TY_CXXModule: +      ClangType = "c++"; +      break; +    case types::TY_PP_CXXModule: +      ClangType = "c++-cpp-output"; +      break; +    default: +      ClangType = types::getTypeName(Input.getType()); +      break; +    } +    CmdArgs.push_back(ClangType); +  } +} + +static void appendUserToPath(SmallVectorImpl<char> &Result) { +#ifdef LLVM_ON_UNIX +  const char *Username = getenv("LOGNAME"); +#else +  const char *Username = getenv("USERNAME"); +#endif +  if (Username) { +    // Validate that LoginName can be used in a path, and get its length. +    size_t Len = 0; +    for (const char *P = Username; *P; ++P, ++Len) { +      if (!clang::isAlphanumeric(*P) && *P != '_') { +        Username = nullptr; +        break; +      } +    } + +    if (Username && Len > 0) { +      Result.append(Username, Username + Len); +      return; +    } +  } + +// Fallback to user id. +#ifdef LLVM_ON_UNIX +  std::string UID = llvm::utostr(getuid()); +#else +  // FIXME: Windows seems to have an 'SID' that might work. +  std::string UID = "9999"; +#endif +  Result.append(UID.begin(), UID.end()); +} + +static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, +                                   const Driver &D, const InputInfo &Output, +                                   const ArgList &Args, +                                   ArgStringList &CmdArgs) { + +  auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, +                                         options::OPT_fprofile_generate_EQ, +                                         options::OPT_fno_profile_generate); +  if (PGOGenerateArg && +      PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) +    PGOGenerateArg = nullptr; + +  auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate, +                                           options::OPT_fcs_profile_generate_EQ, +                                           options::OPT_fno_profile_generate); +  if (CSPGOGenerateArg && +      CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) +    CSPGOGenerateArg = nullptr; + +  auto *ProfileGenerateArg = Args.getLastArg( +      options::OPT_fprofile_instr_generate, +      options::OPT_fprofile_instr_generate_EQ, +      options::OPT_fno_profile_instr_generate); +  if (ProfileGenerateArg && +      ProfileGenerateArg->getOption().matches( +          options::OPT_fno_profile_instr_generate)) +    ProfileGenerateArg = nullptr; + +  if (PGOGenerateArg && ProfileGenerateArg) +    D.Diag(diag::err_drv_argument_not_allowed_with) +        << PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling(); + +  auto *ProfileUseArg = getLastProfileUseArg(Args); + +  if (PGOGenerateArg && ProfileUseArg) +    D.Diag(diag::err_drv_argument_not_allowed_with) +        << ProfileUseArg->getSpelling() << PGOGenerateArg->getSpelling(); + +  if (ProfileGenerateArg && ProfileUseArg) +    D.Diag(diag::err_drv_argument_not_allowed_with) +        << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling(); + +  if (CSPGOGenerateArg && PGOGenerateArg) +    D.Diag(diag::err_drv_argument_not_allowed_with) +        << CSPGOGenerateArg->getSpelling() << PGOGenerateArg->getSpelling(); + +  if (ProfileGenerateArg) { +    if (ProfileGenerateArg->getOption().matches( +            options::OPT_fprofile_instr_generate_EQ)) +      CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instrument-path=") + +                                           ProfileGenerateArg->getValue())); +    // The default is to use Clang Instrumentation. +    CmdArgs.push_back("-fprofile-instrument=clang"); +    if (TC.getTriple().isWindowsMSVCEnvironment()) { +      // Add dependent lib for clang_rt.profile +      CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + +                                           TC.getCompilerRT(Args, "profile"))); +    } +  } + +  Arg *PGOGenArg = nullptr; +  if (PGOGenerateArg) { +    assert(!CSPGOGenerateArg); +    PGOGenArg = PGOGenerateArg; +    CmdArgs.push_back("-fprofile-instrument=llvm"); +  } +  if (CSPGOGenerateArg) { +    assert(!PGOGenerateArg); +    PGOGenArg = CSPGOGenerateArg; +    CmdArgs.push_back("-fprofile-instrument=csllvm"); +  } +  if (PGOGenArg) { +    if (TC.getTriple().isWindowsMSVCEnvironment()) { +      CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + +                                           TC.getCompilerRT(Args, "profile"))); +    } +    if (PGOGenArg->getOption().matches( +            PGOGenerateArg ? options::OPT_fprofile_generate_EQ +                           : options::OPT_fcs_profile_generate_EQ)) { +      SmallString<128> Path(PGOGenArg->getValue()); +      llvm::sys::path::append(Path, "default_%m.profraw"); +      CmdArgs.push_back( +          Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path)); +    } +  } + +  if (ProfileUseArg) { +    if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) +      CmdArgs.push_back(Args.MakeArgString( +          Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue())); +    else if ((ProfileUseArg->getOption().matches( +                  options::OPT_fprofile_use_EQ) || +              ProfileUseArg->getOption().matches( +                  options::OPT_fprofile_instr_use))) { +      SmallString<128> Path( +          ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); +      if (Path.empty() || llvm::sys::fs::is_directory(Path)) +        llvm::sys::path::append(Path, "default.profdata"); +      CmdArgs.push_back( +          Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path)); +    } +  } + +  bool EmitCovNotes = Args.hasArg(options::OPT_ftest_coverage) || +                      Args.hasArg(options::OPT_coverage); +  bool EmitCovData = Args.hasFlag(options::OPT_fprofile_arcs, +                                  options::OPT_fno_profile_arcs, false) || +                     Args.hasArg(options::OPT_coverage); +  if (EmitCovNotes) +    CmdArgs.push_back("-femit-coverage-notes"); +  if (EmitCovData) +    CmdArgs.push_back("-femit-coverage-data"); + +  if (Args.hasFlag(options::OPT_fcoverage_mapping, +                   options::OPT_fno_coverage_mapping, false)) { +    if (!ProfileGenerateArg) +      D.Diag(clang::diag::err_drv_argument_only_allowed_with) +          << "-fcoverage-mapping" +          << "-fprofile-instr-generate"; + +    CmdArgs.push_back("-fcoverage-mapping"); +  } + +  if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) { +    auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ); +    if (!Args.hasArg(options::OPT_coverage)) +      D.Diag(clang::diag::err_drv_argument_only_allowed_with) +          << "-fprofile-exclude-files=" +          << "--coverage"; + +    StringRef v = Arg->getValue(); +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-fprofile-exclude-files=" + v))); +  } + +  if (Args.hasArg(options::OPT_fprofile_filter_files_EQ)) { +    auto *Arg = Args.getLastArg(options::OPT_fprofile_filter_files_EQ); +    if (!Args.hasArg(options::OPT_coverage)) +      D.Diag(clang::diag::err_drv_argument_only_allowed_with) +          << "-fprofile-filter-files=" +          << "--coverage"; + +    StringRef v = Arg->getValue(); +    CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-filter-files=" + v))); +  } + +  // Leave -fprofile-dir= an unused argument unless .gcda emission is +  // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider +  // the flag used. There is no -fno-profile-dir, so the user has no +  // targeted way to suppress the warning. +  Arg *FProfileDir = nullptr; +  if (Args.hasArg(options::OPT_fprofile_arcs) || +      Args.hasArg(options::OPT_coverage)) +    FProfileDir = Args.getLastArg(options::OPT_fprofile_dir); + +  // Put the .gcno and .gcda files (if needed) next to the object file or +  // bitcode file in the case of LTO. +  // FIXME: There should be a simpler way to find the object file for this +  // input, and this code probably does the wrong thing for commands that +  // compile and link all at once. +  if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && +      (EmitCovNotes || EmitCovData) && Output.isFilename()) { +    SmallString<128> OutputFilename; +    if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) +      OutputFilename = FinalOutput->getValue(); +    else +      OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); +    SmallString<128> CoverageFilename = OutputFilename; +    if (llvm::sys::path::is_relative(CoverageFilename)) +      (void)D.getVFS().makeAbsolute(CoverageFilename); +    llvm::sys::path::replace_extension(CoverageFilename, "gcno"); + +    CmdArgs.push_back("-coverage-notes-file"); +    CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + +    if (EmitCovData) { +      if (FProfileDir) { +        CoverageFilename = FProfileDir->getValue(); +        llvm::sys::path::append(CoverageFilename, OutputFilename); +      } +      llvm::sys::path::replace_extension(CoverageFilename, "gcda"); +      CmdArgs.push_back("-coverage-data-file"); +      CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); +    } +  } +} + +/// Check whether the given input tree contains any compilation actions. +static bool ContainsCompileAction(const Action *A) { +  if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) +    return true; + +  for (const auto &AI : A->inputs()) +    if (ContainsCompileAction(AI)) +      return true; + +  return false; +} + +/// Check if -relax-all should be passed to the internal assembler. +/// This is done by default when compiling non-assembler source with -O0. +static bool UseRelaxAll(Compilation &C, const ArgList &Args) { +  bool RelaxDefault = true; + +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) +    RelaxDefault = A->getOption().matches(options::OPT_O0); + +  if (RelaxDefault) { +    RelaxDefault = false; +    for (const auto &Act : C.getActions()) { +      if (ContainsCompileAction(Act)) { +        RelaxDefault = true; +        break; +      } +    } +  } + +  return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, +                      RelaxDefault); +} + +// Extract the integer N from a string spelled "-dwarf-N", returning 0 +// on mismatch. The StringRef input (rather than an Arg) allows +// for use by the "-Xassembler" option parser. +static unsigned DwarfVersionNum(StringRef ArgValue) { +  return llvm::StringSwitch<unsigned>(ArgValue) +      .Case("-gdwarf-2", 2) +      .Case("-gdwarf-3", 3) +      .Case("-gdwarf-4", 4) +      .Case("-gdwarf-5", 5) +      .Default(0); +} + +static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, +                                    codegenoptions::DebugInfoKind DebugInfoKind, +                                    unsigned DwarfVersion, +                                    llvm::DebuggerKind DebuggerTuning) { +  switch (DebugInfoKind) { +  case codegenoptions::DebugDirectivesOnly: +    CmdArgs.push_back("-debug-info-kind=line-directives-only"); +    break; +  case codegenoptions::DebugLineTablesOnly: +    CmdArgs.push_back("-debug-info-kind=line-tables-only"); +    break; +  case codegenoptions::LimitedDebugInfo: +    CmdArgs.push_back("-debug-info-kind=limited"); +    break; +  case codegenoptions::FullDebugInfo: +    CmdArgs.push_back("-debug-info-kind=standalone"); +    break; +  default: +    break; +  } +  if (DwarfVersion > 0) +    CmdArgs.push_back( +        Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); +  switch (DebuggerTuning) { +  case llvm::DebuggerKind::GDB: +    CmdArgs.push_back("-debugger-tuning=gdb"); +    break; +  case llvm::DebuggerKind::LLDB: +    CmdArgs.push_back("-debugger-tuning=lldb"); +    break; +  case llvm::DebuggerKind::SCE: +    CmdArgs.push_back("-debugger-tuning=sce"); +    break; +  default: +    break; +  } +} + +static bool checkDebugInfoOption(const Arg *A, const ArgList &Args, +                                 const Driver &D, const ToolChain &TC) { +  assert(A && "Expected non-nullptr argument."); +  if (TC.supportsDebugInfoOption(A)) +    return true; +  D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target) +      << A->getAsString(Args) << TC.getTripleString(); +  return false; +} + +static void RenderDebugInfoCompressionArgs(const ArgList &Args, +                                           ArgStringList &CmdArgs, +                                           const Driver &D, +                                           const ToolChain &TC) { +  const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ); +  if (!A) +    return; +  if (checkDebugInfoOption(A, Args, D, TC)) { +    if (A->getOption().getID() == options::OPT_gz) { +      if (llvm::zlib::isAvailable()) +        CmdArgs.push_back("--compress-debug-sections"); +      else +        D.Diag(diag::warn_debug_compression_unavailable); +      return; +    } + +    StringRef Value = A->getValue(); +    if (Value == "none") { +      CmdArgs.push_back("--compress-debug-sections=none"); +    } else if (Value == "zlib" || Value == "zlib-gnu") { +      if (llvm::zlib::isAvailable()) { +        CmdArgs.push_back( +            Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); +      } else { +        D.Diag(diag::warn_debug_compression_unavailable); +      } +    } else { +      D.Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Value; +    } +  } +} + +static const char *RelocationModelName(llvm::Reloc::Model Model) { +  switch (Model) { +  case llvm::Reloc::Static: +    return "static"; +  case llvm::Reloc::PIC_: +    return "pic"; +  case llvm::Reloc::DynamicNoPIC: +    return "dynamic-no-pic"; +  case llvm::Reloc::ROPI: +    return "ropi"; +  case llvm::Reloc::RWPI: +    return "rwpi"; +  case llvm::Reloc::ROPI_RWPI: +    return "ropi-rwpi"; +  } +  llvm_unreachable("Unknown Reloc::Model kind"); +} + +void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, +                                    const Driver &D, const ArgList &Args, +                                    ArgStringList &CmdArgs, +                                    const InputInfo &Output, +                                    const InputInfoList &Inputs) const { +  const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); + +  CheckPreprocessingOptions(D, Args); + +  Args.AddLastArg(CmdArgs, options::OPT_C); +  Args.AddLastArg(CmdArgs, options::OPT_CC); + +  // Handle dependency file generation. +  Arg *ArgM = Args.getLastArg(options::OPT_MM); +  if (!ArgM) +    ArgM = Args.getLastArg(options::OPT_M); +  Arg *ArgMD = Args.getLastArg(options::OPT_MMD); +  if (!ArgMD) +    ArgMD = Args.getLastArg(options::OPT_MD); + +  // -M and -MM imply -w. +  if (ArgM) +    CmdArgs.push_back("-w"); +  else +    ArgM = ArgMD; + +  if (ArgM) { +    // Determine the output location. +    const char *DepFile; +    if (Arg *MF = Args.getLastArg(options::OPT_MF)) { +      DepFile = MF->getValue(); +      C.addFailureResultFile(DepFile, &JA); +    } else if (Output.getType() == types::TY_Dependencies) { +      DepFile = Output.getFilename(); +    } else if (!ArgMD) { +      DepFile = "-"; +    } else { +      DepFile = getDependencyFileName(Args, Inputs); +      C.addFailureResultFile(DepFile, &JA); +    } +    CmdArgs.push_back("-dependency-file"); +    CmdArgs.push_back(DepFile); + +    bool HasTarget = false; +    for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) { +      HasTarget = true; +      A->claim(); +      if (A->getOption().matches(options::OPT_MT)) { +        A->render(Args, CmdArgs); +      } else { +        CmdArgs.push_back("-MT"); +        SmallString<128> Quoted; +        QuoteTarget(A->getValue(), Quoted); +        CmdArgs.push_back(Args.MakeArgString(Quoted)); +      } +    } + +    // Add a default target if one wasn't specified. +    if (!HasTarget) { +      const char *DepTarget; + +      // If user provided -o, that is the dependency target, except +      // when we are only generating a dependency file. +      Arg *OutputOpt = Args.getLastArg(options::OPT_o); +      if (OutputOpt && Output.getType() != types::TY_Dependencies) { +        DepTarget = OutputOpt->getValue(); +      } else { +        // Otherwise derive from the base input. +        // +        // FIXME: This should use the computed output file location. +        SmallString<128> P(Inputs[0].getBaseInput()); +        llvm::sys::path::replace_extension(P, "o"); +        DepTarget = Args.MakeArgString(llvm::sys::path::filename(P)); +      } + +      CmdArgs.push_back("-MT"); +      SmallString<128> Quoted; +      QuoteTarget(DepTarget, Quoted); +      CmdArgs.push_back(Args.MakeArgString(Quoted)); +    } + +    if (ArgM->getOption().matches(options::OPT_M) || +        ArgM->getOption().matches(options::OPT_MD)) +      CmdArgs.push_back("-sys-header-deps"); +    if ((isa<PrecompileJobAction>(JA) && +         !Args.hasArg(options::OPT_fno_module_file_deps)) || +        Args.hasArg(options::OPT_fmodule_file_deps)) +      CmdArgs.push_back("-module-file-deps"); +  } + +  if (Args.hasArg(options::OPT_MG)) { +    if (!ArgM || ArgM->getOption().matches(options::OPT_MD) || +        ArgM->getOption().matches(options::OPT_MMD)) +      D.Diag(diag::err_drv_mg_requires_m_or_mm); +    CmdArgs.push_back("-MG"); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_MP); +  Args.AddLastArg(CmdArgs, options::OPT_MV); + +  // Add offload include arguments specific for CUDA.  This must happen before +  // we -I or -include anything else, because we must pick up the CUDA headers +  // from the particular CUDA installation, rather than from e.g. +  // /usr/local/include. +  if (JA.isOffloading(Action::OFK_Cuda)) +    getToolChain().AddCudaIncludeArgs(Args, CmdArgs); + +  // If we are offloading to a target via OpenMP we need to include the +  // openmp_wrappers folder which contains alternative system headers. +  if (JA.isDeviceOffloading(Action::OFK_OpenMP) && +      getToolChain().getTriple().isNVPTX()){ +    if (!Args.hasArg(options::OPT_nobuiltininc)) { +      // Add openmp_wrappers/* to our system include path.  This lets us wrap +      // standard library headers. +      SmallString<128> P(D.ResourceDir); +      llvm::sys::path::append(P, "include"); +      llvm::sys::path::append(P, "openmp_wrappers"); +      CmdArgs.push_back("-internal-isystem"); +      CmdArgs.push_back(Args.MakeArgString(P)); +    } + +    CmdArgs.push_back("-include"); +    CmdArgs.push_back("__clang_openmp_math_declares.h"); +  } + +  // Add -i* options, and automatically translate to +  // -include-pch/-include-pth for transparent PCH support. It's +  // wonky, but we include looking for .gch so we can support seamless +  // replacement into a build system already set up to be generating +  // .gch files. + +  if (getToolChain().getDriver().IsCLMode()) { +    const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); +    const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); +    if (YcArg && JA.getKind() >= Action::PrecompileJobClass && +        JA.getKind() <= Action::AssembleJobClass) { +      CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); +    } +    if (YcArg || YuArg) { +      StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue(); +      if (!isa<PrecompileJobAction>(JA)) { +        CmdArgs.push_back("-include-pch"); +        CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath( +            C, !ThroughHeader.empty() +                   ? ThroughHeader +                   : llvm::sys::path::filename(Inputs[0].getBaseInput())))); +      } + +      if (ThroughHeader.empty()) { +        CmdArgs.push_back(Args.MakeArgString( +            Twine("-pch-through-hdrstop-") + (YcArg ? "create" : "use"))); +      } else { +        CmdArgs.push_back( +            Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader)); +      } +    } +  } + +  bool RenderedImplicitInclude = false; +  for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { +    if (A->getOption().matches(options::OPT_include)) { +      // Handling of gcc-style gch precompiled headers. +      bool IsFirstImplicitInclude = !RenderedImplicitInclude; +      RenderedImplicitInclude = true; + +      bool FoundPCH = false; +      SmallString<128> P(A->getValue()); +      // We want the files to have a name like foo.h.pch. Add a dummy extension +      // so that replace_extension does the right thing. +      P += ".dummy"; +      llvm::sys::path::replace_extension(P, "pch"); +      if (llvm::sys::fs::exists(P)) +        FoundPCH = true; + +      if (!FoundPCH) { +        llvm::sys::path::replace_extension(P, "gch"); +        if (llvm::sys::fs::exists(P)) { +          FoundPCH = true; +        } +      } + +      if (FoundPCH) { +        if (IsFirstImplicitInclude) { +          A->claim(); +          CmdArgs.push_back("-include-pch"); +          CmdArgs.push_back(Args.MakeArgString(P)); +          continue; +        } else { +          // Ignore the PCH if not first on command line and emit warning. +          D.Diag(diag::warn_drv_pch_not_first_include) << P +                                                       << A->getAsString(Args); +        } +      } +    } else if (A->getOption().matches(options::OPT_isystem_after)) { +      // Handling of paths which must come late.  These entries are handled by +      // the toolchain itself after the resource dir is inserted in the right +      // search order. +      // Do not claim the argument so that the use of the argument does not +      // silently go unnoticed on toolchains which do not honour the option. +      continue; +    } else if (A->getOption().matches(options::OPT_stdlibxx_isystem)) { +      // Translated to -internal-isystem by the driver, no need to pass to cc1. +      continue; +    } + +    // Not translated, render as usual. +    A->claim(); +    A->render(Args, CmdArgs); +  } + +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_D, options::OPT_U, options::OPT_I_Group, +                   options::OPT_F, options::OPT_index_header_map}); + +  // Add -Wp, and -Xpreprocessor if using the preprocessor. + +  // FIXME: There is a very unfortunate problem here, some troubled +  // souls abuse -Wp, to pass preprocessor options in gcc syntax. To +  // really support that we would have to parse and then translate +  // those options. :( +  Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, +                       options::OPT_Xpreprocessor); + +  // -I- is a deprecated GCC feature, reject it. +  if (Arg *A = Args.getLastArg(options::OPT_I_)) +    D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args); + +  // If we have a --sysroot, and don't have an explicit -isysroot flag, add an +  // -isysroot to the CC1 invocation. +  StringRef sysroot = C.getSysRoot(); +  if (sysroot != "") { +    if (!Args.hasArg(options::OPT_isysroot)) { +      CmdArgs.push_back("-isysroot"); +      CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); +    } +  } + +  // 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. +  // CPATH - included following the user specified includes (but prior to +  // builtin and standard includes). +  addDirectoryList(Args, CmdArgs, "-I", "CPATH"); +  // C_INCLUDE_PATH - system includes enabled when compiling C. +  addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH"); +  // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++. +  addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH"); +  // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC. +  addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH"); +  // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. +  addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH"); + +  // While adding the include arguments, we also attempt to retrieve the +  // arguments of related offloading toolchains or arguments that are specific +  // of an offloading programming model. + +  // Add C++ include arguments, if needed. +  if (types::isCXX(Inputs[0].getType())) { +    bool HasStdlibxxIsystem = Args.hasArg(options::OPT_stdlibxx_isystem); +    forAllAssociatedToolChains( +        C, JA, getToolChain(), +        [&Args, &CmdArgs, HasStdlibxxIsystem](const ToolChain &TC) { +          HasStdlibxxIsystem ? TC.AddClangCXXStdlibIsystemArgs(Args, CmdArgs) +                             : TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs); +        }); +  } + +  // Add system include arguments for all targets but IAMCU. +  if (!IsIAMCU) +    forAllAssociatedToolChains(C, JA, getToolChain(), +                               [&Args, &CmdArgs](const ToolChain &TC) { +                                 TC.AddClangSystemIncludeArgs(Args, CmdArgs); +                               }); +  else { +    // For IAMCU add special include arguments. +    getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); +  } +} + +// FIXME: Move to target hook. +static bool isSignedCharDefault(const llvm::Triple &Triple) { +  switch (Triple.getArch()) { +  default: +    return true; + +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +    if (Triple.isOSDarwin() || Triple.isOSWindows()) +      return true; +    return false; + +  case llvm::Triple::ppc: +  case llvm::Triple::ppc64: +    if (Triple.isOSDarwin()) +      return true; +    return false; + +  case llvm::Triple::hexagon: +  case llvm::Triple::ppc64le: +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +  case llvm::Triple::systemz: +  case llvm::Triple::xcore: +    return false; +  } +} + +static bool isNoCommonDefault(const llvm::Triple &Triple) { +  switch (Triple.getArch()) { +  default: +    if (Triple.isOSFuchsia()) +      return true; +    return false; + +  case llvm::Triple::xcore: +  case llvm::Triple::wasm32: +  case llvm::Triple::wasm64: +    return true; +  } +} + +namespace { +void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, +                  ArgStringList &CmdArgs) { +  // Select the ABI to use. +  // FIXME: Support -meabi. +  // FIXME: Parts of this are duplicated in the backend, unify this somehow. +  const char *ABIName = nullptr; +  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { +    ABIName = A->getValue(); +  } else { +    std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); +    ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data(); +  } + +  CmdArgs.push_back("-target-abi"); +  CmdArgs.push_back(ABIName); +} +} + +void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, +                             ArgStringList &CmdArgs, bool KernelOrKext) const { +  RenderARMABI(Triple, Args, CmdArgs); + +  // Determine floating point ABI from the options & target defaults. +  arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); +  if (ABI == arm::FloatABI::Soft) { +    // Floating point operations and argument passing are soft. +    // FIXME: This changes CPP defines, we need -target-soft-float. +    CmdArgs.push_back("-msoft-float"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("soft"); +  } else if (ABI == arm::FloatABI::SoftFP) { +    // Floating point operations are hard, but argument passing is soft. +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("soft"); +  } else { +    // Floating point operations and argument passing are hard. +    assert(ABI == arm::FloatABI::Hard && "Invalid float abi!"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("hard"); +  } + +  // Forward the -mglobal-merge option for explicit control over the pass. +  if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, +                               options::OPT_mno_global_merge)) { +    CmdArgs.push_back("-mllvm"); +    if (A->getOption().matches(options::OPT_mno_global_merge)) +      CmdArgs.push_back("-arm-global-merge=false"); +    else +      CmdArgs.push_back("-arm-global-merge=true"); +  } + +  if (!Args.hasFlag(options::OPT_mimplicit_float, +                    options::OPT_mno_implicit_float, true)) +    CmdArgs.push_back("-no-implicit-float"); + +  if (Args.getLastArg(options::OPT_mcmse)) +    CmdArgs.push_back("-mcmse"); +} + +void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, +                                const ArgList &Args, bool KernelOrKext, +                                ArgStringList &CmdArgs) const { +  const ToolChain &TC = getToolChain(); + +  // Add the target features +  getTargetFeatures(TC, EffectiveTriple, Args, CmdArgs, false); + +  // Add target specific flags. +  switch (TC.getArch()) { +  default: +    break; + +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +    // Use the effective triple, which takes into account the deployment target. +    AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext); +    CmdArgs.push_back("-fallow-half-arguments-and-returns"); +    break; + +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: +    AddAArch64TargetArgs(Args, CmdArgs); +    CmdArgs.push_back("-fallow-half-arguments-and-returns"); +    break; + +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: +    AddMIPSTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::ppc: +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: +    AddPPCTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +    AddRISCVTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +  case llvm::Triple::sparcv9: +    AddSparcTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::systemz: +    AddSystemZTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::x86: +  case llvm::Triple::x86_64: +    AddX86TargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::lanai: +    AddLanaiTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::hexagon: +    AddHexagonTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::wasm32: +  case llvm::Triple::wasm64: +    AddWebAssemblyTargetArgs(Args, CmdArgs); +    break; +  } +} + +// Parse -mbranch-protection=<protection>[+<protection>]* where +//   <protection> ::= standard | none | [bti,pac-ret[+b-key,+leaf]*] +// Returns a triple of (return address signing Scope, signing key, require +// landing pads) +static std::tuple<StringRef, StringRef, bool> +ParseAArch64BranchProtection(const Driver &D, const ArgList &Args, +                             const Arg *A) { +  StringRef Scope = "none"; +  StringRef Key = "a_key"; +  bool IndirectBranches = false; + +  StringRef Value = A->getValue(); +  // This maps onto -mbranch-protection=<scope>+<key> + +  if (Value.equals("standard")) { +    Scope = "non-leaf"; +    Key = "a_key"; +    IndirectBranches = true; + +  } else if (!Value.equals("none")) { +    SmallVector<StringRef, 4> BranchProtection; +    StringRef(A->getValue()).split(BranchProtection, '+'); + +    auto Protection = BranchProtection.begin(); +    while (Protection != BranchProtection.end()) { +      if (Protection->equals("bti")) +        IndirectBranches = true; +      else if (Protection->equals("pac-ret")) { +        Scope = "non-leaf"; +        while (++Protection != BranchProtection.end()) { +          // Inner loop as "leaf" and "b-key" options must only appear attached +          // to pac-ret. +          if (Protection->equals("leaf")) +            Scope = "all"; +          else if (Protection->equals("b-key")) +            Key = "b_key"; +          else +            break; +        } +        Protection--; +      } else +        D.Diag(diag::err_invalid_branch_protection) +            << *Protection << A->getAsString(Args); +      Protection++; +    } +  } + +  return std::make_tuple(Scope, Key, IndirectBranches); +} + +namespace { +void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args, +                      ArgStringList &CmdArgs) { +  const char *ABIName = nullptr; +  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) +    ABIName = A->getValue(); +  else if (Triple.isOSDarwin()) +    ABIName = "darwinpcs"; +  else +    ABIName = "aapcs"; + +  CmdArgs.push_back("-target-abi"); +  CmdArgs.push_back(ABIName); +} +} + +void Clang::AddAArch64TargetArgs(const ArgList &Args, +                                 ArgStringList &CmdArgs) const { +  const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + +  if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || +      Args.hasArg(options::OPT_mkernel) || +      Args.hasArg(options::OPT_fapple_kext)) +    CmdArgs.push_back("-disable-red-zone"); + +  if (!Args.hasFlag(options::OPT_mimplicit_float, +                    options::OPT_mno_implicit_float, true)) +    CmdArgs.push_back("-no-implicit-float"); + +  RenderAArch64ABI(Triple, Args, CmdArgs); + +  if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, +                               options::OPT_mno_fix_cortex_a53_835769)) { +    CmdArgs.push_back("-mllvm"); +    if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) +      CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); +    else +      CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); +  } else if (Triple.isAndroid()) { +    // Enabled A53 errata (835769) workaround by default on android +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); +  } + +  // Forward the -mglobal-merge option for explicit control over the pass. +  if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, +                               options::OPT_mno_global_merge)) { +    CmdArgs.push_back("-mllvm"); +    if (A->getOption().matches(options::OPT_mno_global_merge)) +      CmdArgs.push_back("-aarch64-enable-global-merge=false"); +    else +      CmdArgs.push_back("-aarch64-enable-global-merge=true"); +  } + +  // Enable/disable return address signing and indirect branch targets. +  if (Arg *A = Args.getLastArg(options::OPT_msign_return_address_EQ, +                               options::OPT_mbranch_protection_EQ)) { + +    const Driver &D = getToolChain().getDriver(); + +    StringRef Scope, Key; +    bool IndirectBranches; + +    if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { +      Scope = A->getValue(); +      if (!Scope.equals("none") && !Scope.equals("non-leaf") && +          !Scope.equals("all")) +        D.Diag(diag::err_invalid_branch_protection) +            << Scope << A->getAsString(Args); +      Key = "a_key"; +      IndirectBranches = false; +    } else +      std::tie(Scope, Key, IndirectBranches) = +          ParseAArch64BranchProtection(D, Args, A); + +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-msign-return-address=") + Scope)); +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); +    if (IndirectBranches) +      CmdArgs.push_back("-mbranch-target-enforce"); +  } +} + +void Clang::AddMIPSTargetArgs(const ArgList &Args, +                              ArgStringList &CmdArgs) const { +  const Driver &D = getToolChain().getDriver(); +  StringRef CPUName; +  StringRef ABIName; +  const llvm::Triple &Triple = getToolChain().getTriple(); +  mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + +  CmdArgs.push_back("-target-abi"); +  CmdArgs.push_back(ABIName.data()); + +  mips::FloatABI ABI = mips::getMipsFloatABI(D, Args, Triple); +  if (ABI == mips::FloatABI::Soft) { +    // Floating point operations and argument passing are soft. +    CmdArgs.push_back("-msoft-float"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("soft"); +  } else { +    // Floating point operations and argument passing are hard. +    assert(ABI == mips::FloatABI::Hard && "Invalid float abi!"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("hard"); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1, +                               options::OPT_mno_ldc1_sdc1)) { +    if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-mno-ldc1-sdc1"); +    } +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division, +                               options::OPT_mno_check_zero_division)) { +    if (A->getOption().matches(options::OPT_mno_check_zero_division)) { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-mno-check-zero-division"); +    } +  } + +  if (Arg *A = Args.getLastArg(options::OPT_G)) { +    StringRef v = A->getValue(); +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v)); +    A->claim(); +  } + +  Arg *GPOpt = Args.getLastArg(options::OPT_mgpopt, options::OPT_mno_gpopt); +  Arg *ABICalls = +      Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); + +  // -mabicalls is the default for many MIPS environments, even with -fno-pic. +  // -mgpopt is the default for static, -fno-pic environments but these two +  // options conflict. We want to be certain that -mno-abicalls -mgpopt is +  // the only case where -mllvm -mgpopt is passed. +  // NOTE: We need a warning here or in the backend to warn when -mgpopt is +  //       passed explicitly when compiling something with -mabicalls +  //       (implictly) in affect. Currently the warning is in the backend. +  // +  // When the ABI in use is  N64, we also need to determine the PIC mode that +  // is in use, as -fno-pic for N64 implies -mno-abicalls. +  bool NoABICalls = +      ABICalls && ABICalls->getOption().matches(options::OPT_mno_abicalls); + +  llvm::Reloc::Model RelocationModel; +  unsigned PICLevel; +  bool IsPIE; +  std::tie(RelocationModel, PICLevel, IsPIE) = +      ParsePICArgs(getToolChain(), Args); + +  NoABICalls = NoABICalls || +               (RelocationModel == llvm::Reloc::Static && ABIName == "n64"); + +  bool WantGPOpt = GPOpt && GPOpt->getOption().matches(options::OPT_mgpopt); +  // We quietly ignore -mno-gpopt as the backend defaults to -mno-gpopt. +  if (NoABICalls && (!GPOpt || WantGPOpt)) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-mgpopt"); + +    Arg *LocalSData = Args.getLastArg(options::OPT_mlocal_sdata, +                                      options::OPT_mno_local_sdata); +    Arg *ExternSData = Args.getLastArg(options::OPT_mextern_sdata, +                                       options::OPT_mno_extern_sdata); +    Arg *EmbeddedData = Args.getLastArg(options::OPT_membedded_data, +                                        options::OPT_mno_embedded_data); +    if (LocalSData) { +      CmdArgs.push_back("-mllvm"); +      if (LocalSData->getOption().matches(options::OPT_mlocal_sdata)) { +        CmdArgs.push_back("-mlocal-sdata=1"); +      } else { +        CmdArgs.push_back("-mlocal-sdata=0"); +      } +      LocalSData->claim(); +    } + +    if (ExternSData) { +      CmdArgs.push_back("-mllvm"); +      if (ExternSData->getOption().matches(options::OPT_mextern_sdata)) { +        CmdArgs.push_back("-mextern-sdata=1"); +      } else { +        CmdArgs.push_back("-mextern-sdata=0"); +      } +      ExternSData->claim(); +    } + +    if (EmbeddedData) { +      CmdArgs.push_back("-mllvm"); +      if (EmbeddedData->getOption().matches(options::OPT_membedded_data)) { +        CmdArgs.push_back("-membedded-data=1"); +      } else { +        CmdArgs.push_back("-membedded-data=0"); +      } +      EmbeddedData->claim(); +    } + +  } else if ((!ABICalls || (!NoABICalls && ABICalls)) && WantGPOpt) +    D.Diag(diag::warn_drv_unsupported_gpopt) << (ABICalls ? 0 : 1); + +  if (GPOpt) +    GPOpt->claim(); + +  if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) { +    StringRef Val = StringRef(A->getValue()); +    if (mips::hasCompactBranches(CPUName)) { +      if (Val == "never" || Val == "always" || Val == "optimal") { +        CmdArgs.push_back("-mllvm"); +        CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val)); +      } else +        D.Diag(diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Val; +    } else +      D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName; +  } + +  if (Arg *A = Args.getLastArg(options::OPT_mrelax_pic_calls, +                               options::OPT_mno_relax_pic_calls)) { +    if (A->getOption().matches(options::OPT_mno_relax_pic_calls)) { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-mips-jalr-reloc=0"); +    } +  } +} + +void Clang::AddPPCTargetArgs(const ArgList &Args, +                             ArgStringList &CmdArgs) const { +  // Select the ABI to use. +  const char *ABIName = nullptr; +  if (getToolChain().getTriple().isOSLinux()) +    switch (getToolChain().getArch()) { +    case llvm::Triple::ppc64: { +      // When targeting a processor that supports QPX, or if QPX is +      // specifically enabled, default to using the ABI that supports QPX (so +      // long as it is not specifically disabled). +      bool HasQPX = false; +      if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) +        HasQPX = A->getValue() == StringRef("a2q"); +      HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX); +      if (HasQPX) { +        ABIName = "elfv1-qpx"; +        break; +      } + +      ABIName = "elfv1"; +      break; +    } +    case llvm::Triple::ppc64le: +      ABIName = "elfv2"; +      break; +    default: +      break; +    } + +  bool IEEELongDouble = false; +  for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) { +    StringRef V = A->getValue(); +    if (V == "ieeelongdouble") +      IEEELongDouble = true; +    else if (V == "ibmlongdouble") +      IEEELongDouble = false; +    else if (V != "altivec") +      // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore +      // the option if given as we don't have backend support for any targets +      // that don't use the altivec abi. +      ABIName = A->getValue(); +  } +  if (IEEELongDouble) +    CmdArgs.push_back("-mabi=ieeelongdouble"); + +  ppc::FloatABI FloatABI = +      ppc::getPPCFloatABI(getToolChain().getDriver(), Args); + +  if (FloatABI == ppc::FloatABI::Soft) { +    // Floating point operations and argument passing are soft. +    CmdArgs.push_back("-msoft-float"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("soft"); +  } else { +    // Floating point operations and argument passing are hard. +    assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("hard"); +  } + +  if (ABIName) { +    CmdArgs.push_back("-target-abi"); +    CmdArgs.push_back(ABIName); +  } +} + +void Clang::AddRISCVTargetArgs(const ArgList &Args, +                               ArgStringList &CmdArgs) const { +  const llvm::Triple &Triple = getToolChain().getTriple(); +  StringRef ABIName = riscv::getRISCVABI(Args, Triple); + +  CmdArgs.push_back("-target-abi"); +  CmdArgs.push_back(ABIName.data()); +} + +void Clang::AddSparcTargetArgs(const ArgList &Args, +                               ArgStringList &CmdArgs) const { +  sparc::FloatABI FloatABI = +      sparc::getSparcFloatABI(getToolChain().getDriver(), Args); + +  if (FloatABI == sparc::FloatABI::Soft) { +    // Floating point operations and argument passing are soft. +    CmdArgs.push_back("-msoft-float"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("soft"); +  } else { +    // Floating point operations and argument passing are hard. +    assert(FloatABI == sparc::FloatABI::Hard && "Invalid float abi!"); +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("hard"); +  } +} + +void Clang::AddSystemZTargetArgs(const ArgList &Args, +                                 ArgStringList &CmdArgs) const { +  if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false)) +    CmdArgs.push_back("-mbackchain"); +} + +void Clang::AddX86TargetArgs(const ArgList &Args, +                             ArgStringList &CmdArgs) const { +  if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || +      Args.hasArg(options::OPT_mkernel) || +      Args.hasArg(options::OPT_fapple_kext)) +    CmdArgs.push_back("-disable-red-zone"); + +  if (!Args.hasFlag(options::OPT_mtls_direct_seg_refs, +                    options::OPT_mno_tls_direct_seg_refs, true)) +    CmdArgs.push_back("-mno-tls-direct-seg-refs"); + +  // 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_mimplicit_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 (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { +    StringRef Value = A->getValue(); +    if (Value == "intel" || Value == "att") { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); +    } else { +      getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Value; +    } +  } else if (getToolChain().getDriver().IsCLMode()) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-x86-asm-syntax=intel"); +  } + +  // Set flags to support MCU ABI. +  if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { +    CmdArgs.push_back("-mfloat-abi"); +    CmdArgs.push_back("soft"); +    CmdArgs.push_back("-mstack-alignment=4"); +  } +} + +void Clang::AddHexagonTargetArgs(const ArgList &Args, +                                 ArgStringList &CmdArgs) const { +  CmdArgs.push_back("-mqdsp6-compat"); +  CmdArgs.push_back("-Wreturn-type"); + +  if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" + +                                         Twine(G.getValue()))); +  } + +  if (!Args.hasArg(options::OPT_fno_short_enums)) +    CmdArgs.push_back("-fshort-enums"); +  if (Args.getLastArg(options::OPT_mieee_rnd_near)) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-enable-hexagon-ieee-rnd-near"); +  } +  CmdArgs.push_back("-mllvm"); +  CmdArgs.push_back("-machine-sink-split=0"); +} + +void Clang::AddLanaiTargetArgs(const ArgList &Args, +                               ArgStringList &CmdArgs) const { +  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { +    StringRef CPUName = A->getValue(); + +    CmdArgs.push_back("-target-cpu"); +    CmdArgs.push_back(Args.MakeArgString(CPUName)); +  } +  if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { +    StringRef Value = A->getValue(); +    // Only support mregparm=4 to support old usage. Report error for all other +    // cases. +    int Mregparm; +    if (Value.getAsInteger(10, Mregparm)) { +      if (Mregparm != 4) { +        getToolChain().getDriver().Diag( +            diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Value; +      } +    } +  } +} + +void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, +                                     ArgStringList &CmdArgs) const { +  // Default to "hidden" visibility. +  if (!Args.hasArg(options::OPT_fvisibility_EQ, +                   options::OPT_fvisibility_ms_compat)) { +    CmdArgs.push_back("-fvisibility"); +    CmdArgs.push_back("hidden"); +  } +} + +void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, +                                    StringRef Target, const InputInfo &Output, +                                    const InputInfo &Input, const ArgList &Args) const { +  // If this is a dry run, do not create the compilation database file. +  if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) +    return; + +  using llvm::yaml::escape; +  const Driver &D = getToolChain().getDriver(); + +  if (!CompilationDatabase) { +    std::error_code EC; +    auto File = std::make_unique<llvm::raw_fd_ostream>(Filename, EC, +                                                        llvm::sys::fs::OF_Text); +    if (EC) { +      D.Diag(clang::diag::err_drv_compilationdatabase) << Filename +                                                       << EC.message(); +      return; +    } +    CompilationDatabase = std::move(File); +  } +  auto &CDB = *CompilationDatabase; +  auto CWD = D.getVFS().getCurrentWorkingDirectory(); +  if (!CWD) +    CWD = "."; +  CDB << "{ \"directory\": \"" << escape(*CWD) << "\""; +  CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; +  CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; +  CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; +  SmallString<128> Buf; +  Buf = "-x"; +  Buf += types::getTypeName(Input.getType()); +  CDB << ", \"" << escape(Buf) << "\""; +  if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) { +    Buf = "--sysroot="; +    Buf += D.SysRoot; +    CDB << ", \"" << escape(Buf) << "\""; +  } +  CDB << ", \"" << escape(Input.getFilename()) << "\""; +  for (auto &A: Args) { +    auto &O = A->getOption(); +    // Skip language selection, which is positional. +    if (O.getID() == options::OPT_x) +      continue; +    // Skip writing dependency output and the compilation database itself. +    if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group) +      continue; +    if (O.getID() == options::OPT_gen_cdb_fragment_path) +      continue; +    // Skip inputs. +    if (O.getKind() == Option::InputClass) +      continue; +    // All other arguments are quoted and appended. +    ArgStringList ASL; +    A->render(Args, ASL); +    for (auto &it: ASL) +      CDB << ", \"" << escape(it) << "\""; +  } +  Buf = "--target="; +  Buf += Target; +  CDB << ", \"" << escape(Buf) << "\"]},\n"; +} + +void Clang::DumpCompilationDatabaseFragmentToDir( +    StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output, +    const InputInfo &Input, const llvm::opt::ArgList &Args) const { +  // If this is a dry run, do not create the compilation database file. +  if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) +    return; + +  if (CompilationDatabase) +    DumpCompilationDatabase(C, "", Target, Output, Input, Args); + +  SmallString<256> Path = Dir; +  const auto &Driver = C.getDriver(); +  Driver.getVFS().makeAbsolute(Path); +  auto Err = llvm::sys::fs::create_directory(Path, /*IgnoreExisting=*/true); +  if (Err) { +    Driver.Diag(diag::err_drv_compilationdatabase) << Dir << Err.message(); +    return; +  } + +  llvm::sys::path::append( +      Path, +      Twine(llvm::sys::path::filename(Input.getFilename())) + ".%%%%.json"); +  int FD; +  SmallString<256> TempPath; +  Err = llvm::sys::fs::createUniqueFile(Path, FD, TempPath); +  if (Err) { +    Driver.Diag(diag::err_drv_compilationdatabase) << Path << Err.message(); +    return; +  } +  CompilationDatabase = +      std::make_unique<llvm::raw_fd_ostream>(FD, /*shouldClose=*/true); +  DumpCompilationDatabase(C, "", Target, Output, Input, Args); +} + +static void CollectArgsForIntegratedAssembler(Compilation &C, +                                              const ArgList &Args, +                                              ArgStringList &CmdArgs, +                                              const Driver &D) { +  if (UseRelaxAll(C, Args)) +    CmdArgs.push_back("-mrelax-all"); + +  // Only default to -mincremental-linker-compatible if we think we are +  // targeting the MSVC linker. +  bool DefaultIncrementalLinkerCompatible = +      C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); +  if (Args.hasFlag(options::OPT_mincremental_linker_compatible, +                   options::OPT_mno_incremental_linker_compatible, +                   DefaultIncrementalLinkerCompatible)) +    CmdArgs.push_back("-mincremental-linker-compatible"); + +  switch (C.getDefaultToolChain().getArch()) { +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +    if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) { +      StringRef Value = A->getValue(); +      if (Value == "always" || Value == "never" || Value == "arm" || +          Value == "thumb") { +        CmdArgs.push_back("-mllvm"); +        CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value)); +      } else { +        D.Diag(diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Value; +      } +    } +    break; +  default: +    break; +  } + +  // If you add more args here, also add them to the block below that +  // starts with "// If CollectArgsForIntegratedAssembler() isn't called below". + +  // When passing -I arguments to the assembler we sometimes need to +  // unconditionally take the next argument.  For example, when parsing +  // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the +  // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo' +  // arg after parsing the '-I' arg. +  bool TakeNextArg = false; + +  bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); +  bool UseNoExecStack = C.getDefaultToolChain().isNoExecStackDefault(); +  const char *MipsTargetFeature = nullptr; +  for (const Arg *A : +       Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { +    A->claim(); + +    for (StringRef Value : A->getValues()) { +      if (TakeNextArg) { +        CmdArgs.push_back(Value.data()); +        TakeNextArg = false; +        continue; +      } + +      if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() && +          Value == "-mbig-obj") +        continue; // LLVM handles bigobj automatically + +      switch (C.getDefaultToolChain().getArch()) { +      default: +        break; +      case llvm::Triple::thumb: +      case llvm::Triple::thumbeb: +      case llvm::Triple::arm: +      case llvm::Triple::armeb: +        if (Value == "-mthumb") +          // -mthumb has already been processed in ComputeLLVMTriple() +          // recognize but skip over here. +          continue; +        break; +      case llvm::Triple::mips: +      case llvm::Triple::mipsel: +      case llvm::Triple::mips64: +      case llvm::Triple::mips64el: +        if (Value == "--trap") { +          CmdArgs.push_back("-target-feature"); +          CmdArgs.push_back("+use-tcc-in-div"); +          continue; +        } +        if (Value == "--break") { +          CmdArgs.push_back("-target-feature"); +          CmdArgs.push_back("-use-tcc-in-div"); +          continue; +        } +        if (Value.startswith("-msoft-float")) { +          CmdArgs.push_back("-target-feature"); +          CmdArgs.push_back("+soft-float"); +          continue; +        } +        if (Value.startswith("-mhard-float")) { +          CmdArgs.push_back("-target-feature"); +          CmdArgs.push_back("-soft-float"); +          continue; +        } + +        MipsTargetFeature = llvm::StringSwitch<const char *>(Value) +                                .Case("-mips1", "+mips1") +                                .Case("-mips2", "+mips2") +                                .Case("-mips3", "+mips3") +                                .Case("-mips4", "+mips4") +                                .Case("-mips5", "+mips5") +                                .Case("-mips32", "+mips32") +                                .Case("-mips32r2", "+mips32r2") +                                .Case("-mips32r3", "+mips32r3") +                                .Case("-mips32r5", "+mips32r5") +                                .Case("-mips32r6", "+mips32r6") +                                .Case("-mips64", "+mips64") +                                .Case("-mips64r2", "+mips64r2") +                                .Case("-mips64r3", "+mips64r3") +                                .Case("-mips64r5", "+mips64r5") +                                .Case("-mips64r6", "+mips64r6") +                                .Default(nullptr); +        if (MipsTargetFeature) +          continue; +      } + +      if (Value == "-force_cpusubtype_ALL") { +        // Do nothing, this is the default and we don't support anything else. +      } else if (Value == "-L") { +        CmdArgs.push_back("-msave-temp-labels"); +      } else if (Value == "--fatal-warnings") { +        CmdArgs.push_back("-massembler-fatal-warnings"); +      } else if (Value == "--no-warn" || Value == "-W") { +        CmdArgs.push_back("-massembler-no-warn"); +      } else if (Value == "--noexecstack") { +        UseNoExecStack = true; +      } else if (Value.startswith("-compress-debug-sections") || +                 Value.startswith("--compress-debug-sections") || +                 Value == "-nocompress-debug-sections" || +                 Value == "--nocompress-debug-sections") { +        CmdArgs.push_back(Value.data()); +      } else if (Value == "-mrelax-relocations=yes" || +                 Value == "--mrelax-relocations=yes") { +        UseRelaxRelocations = true; +      } else if (Value == "-mrelax-relocations=no" || +                 Value == "--mrelax-relocations=no") { +        UseRelaxRelocations = false; +      } else if (Value.startswith("-I")) { +        CmdArgs.push_back(Value.data()); +        // We need to consume the next argument if the current arg is a plain +        // -I. The next arg will be the include directory. +        if (Value == "-I") +          TakeNextArg = true; +      } else if (Value.startswith("-gdwarf-")) { +        // "-gdwarf-N" options are not cc1as options. +        unsigned DwarfVersion = DwarfVersionNum(Value); +        if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. +          CmdArgs.push_back(Value.data()); +        } else { +          RenderDebugEnablingArgs(Args, CmdArgs, +                                  codegenoptions::LimitedDebugInfo, +                                  DwarfVersion, llvm::DebuggerKind::Default); +        } +      } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || +                 Value.startswith("-mhwdiv") || Value.startswith("-march")) { +        // Do nothing, we'll validate it later. +      } else if (Value == "-defsym") { +          if (A->getNumValues() != 2) { +            D.Diag(diag::err_drv_defsym_invalid_format) << Value; +            break; +          } +          const char *S = A->getValue(1); +          auto Pair = StringRef(S).split('='); +          auto Sym = Pair.first; +          auto SVal = Pair.second; + +          if (Sym.empty() || SVal.empty()) { +            D.Diag(diag::err_drv_defsym_invalid_format) << S; +            break; +          } +          int64_t IVal; +          if (SVal.getAsInteger(0, IVal)) { +            D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; +            break; +          } +          CmdArgs.push_back(Value.data()); +          TakeNextArg = true; +      } else if (Value == "-fdebug-compilation-dir") { +        CmdArgs.push_back("-fdebug-compilation-dir"); +        TakeNextArg = true; +      } else { +        D.Diag(diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Value; +      } +    } +  } +  if (UseRelaxRelocations) +    CmdArgs.push_back("--mrelax-relocations"); +  if (UseNoExecStack) +    CmdArgs.push_back("-mnoexecstack"); +  if (MipsTargetFeature != nullptr) { +    CmdArgs.push_back("-target-feature"); +    CmdArgs.push_back(MipsTargetFeature); +  } + +  // forward -fembed-bitcode to assmebler +  if (C.getDriver().embedBitcodeEnabled() || +      C.getDriver().embedBitcodeMarkerOnly()) +    Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); +} + +static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, +                                       bool OFastEnabled, const ArgList &Args, +                                       ArgStringList &CmdArgs) { +  // Handle various floating point optimization flags, mapping them to the +  // appropriate LLVM code generation flags. This is complicated by several +  // "umbrella" flags, so we do this by stepping through the flags incrementally +  // adjusting what we think is enabled/disabled, then at the end setting the +  // LLVM flags based on the final state. +  bool HonorINFs = true; +  bool HonorNaNs = true; +  // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. +  bool MathErrno = TC.IsMathErrnoDefault(); +  bool AssociativeMath = false; +  bool ReciprocalMath = false; +  bool SignedZeros = true; +  bool TrappingMath = true; +  StringRef DenormalFPMath = ""; +  StringRef FPContract = ""; + +  if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { +    CmdArgs.push_back("-mlimit-float-precision"); +    CmdArgs.push_back(A->getValue()); +  } + +  for (const Arg *A : Args) { +    switch (A->getOption().getID()) { +    // If this isn't an FP option skip the claim below +    default: continue; + +    // Options controlling individual features +    case options::OPT_fhonor_infinities:    HonorINFs = true;         break; +    case options::OPT_fno_honor_infinities: HonorINFs = false;        break; +    case options::OPT_fhonor_nans:          HonorNaNs = true;         break; +    case options::OPT_fno_honor_nans:       HonorNaNs = false;        break; +    case options::OPT_fmath_errno:          MathErrno = true;         break; +    case options::OPT_fno_math_errno:       MathErrno = false;        break; +    case options::OPT_fassociative_math:    AssociativeMath = true;   break; +    case options::OPT_fno_associative_math: AssociativeMath = false;  break; +    case options::OPT_freciprocal_math:     ReciprocalMath = true;    break; +    case options::OPT_fno_reciprocal_math:  ReciprocalMath = false;   break; +    case options::OPT_fsigned_zeros:        SignedZeros = true;       break; +    case options::OPT_fno_signed_zeros:     SignedZeros = false;      break; +    case options::OPT_ftrapping_math:       TrappingMath = true;      break; +    case options::OPT_fno_trapping_math:    TrappingMath = false;     break; + +    case options::OPT_fdenormal_fp_math_EQ: +      DenormalFPMath = A->getValue(); +      break; + +    // Validate and pass through -fp-contract option. +    case options::OPT_ffp_contract: { +      StringRef Val = A->getValue(); +      if (Val == "fast" || Val == "on" || Val == "off") +        FPContract = Val; +      else +        D.Diag(diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Val; +      break; +    } + +    case options::OPT_ffinite_math_only: +      HonorINFs = false; +      HonorNaNs = false; +      break; +    case options::OPT_fno_finite_math_only: +      HonorINFs = true; +      HonorNaNs = true; +      break; + +    case options::OPT_funsafe_math_optimizations: +      AssociativeMath = true; +      ReciprocalMath = true; +      SignedZeros = false; +      TrappingMath = false; +      break; +    case options::OPT_fno_unsafe_math_optimizations: +      AssociativeMath = false; +      ReciprocalMath = false; +      SignedZeros = true; +      TrappingMath = true; +      // -fno_unsafe_math_optimizations restores default denormal handling +      DenormalFPMath = ""; +      break; + +    case options::OPT_Ofast: +      // If -Ofast is the optimization level, then -ffast-math should be enabled +      if (!OFastEnabled) +        continue; +      LLVM_FALLTHROUGH; +    case options::OPT_ffast_math: +      HonorINFs = false; +      HonorNaNs = false; +      MathErrno = false; +      AssociativeMath = true; +      ReciprocalMath = true; +      SignedZeros = false; +      TrappingMath = false; +      // If fast-math is set then set the fp-contract mode to fast. +      FPContract = "fast"; +      break; +    case options::OPT_fno_fast_math: +      HonorINFs = true; +      HonorNaNs = true; +      // Turning on -ffast-math (with either flag) removes the need for +      // MathErrno. However, turning *off* -ffast-math merely restores the +      // toolchain default (which may be false). +      MathErrno = TC.IsMathErrnoDefault(); +      AssociativeMath = false; +      ReciprocalMath = false; +      SignedZeros = true; +      TrappingMath = true; +      // -fno_fast_math restores default denormal and fpcontract handling +      DenormalFPMath = ""; +      FPContract = ""; +      break; +    } + +    // If we handled this option claim it +    A->claim(); +  } + +  if (!HonorINFs) +    CmdArgs.push_back("-menable-no-infs"); + +  if (!HonorNaNs) +    CmdArgs.push_back("-menable-no-nans"); + +  if (MathErrno) +    CmdArgs.push_back("-fmath-errno"); + +  if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && +      !TrappingMath) +    CmdArgs.push_back("-menable-unsafe-fp-math"); + +  if (!SignedZeros) +    CmdArgs.push_back("-fno-signed-zeros"); + +  if (AssociativeMath && !SignedZeros && !TrappingMath) +    CmdArgs.push_back("-mreassociate"); + +  if (ReciprocalMath) +    CmdArgs.push_back("-freciprocal-math"); + +  if (!TrappingMath) +    CmdArgs.push_back("-fno-trapping-math"); + +  if (!DenormalFPMath.empty()) +    CmdArgs.push_back( +        Args.MakeArgString("-fdenormal-fp-math=" + DenormalFPMath)); + +  if (!FPContract.empty()) +    CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + +  ParseMRecip(D, Args, CmdArgs); + +  // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the +  // individual features enabled by -ffast-math instead of the option itself as +  // that's consistent with gcc's behaviour. +  if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && +      ReciprocalMath && !SignedZeros && !TrappingMath) +    CmdArgs.push_back("-ffast-math"); + +  // Handle __FINITE_MATH_ONLY__ similarly. +  if (!HonorINFs && !HonorNaNs) +    CmdArgs.push_back("-ffinite-math-only"); + +  if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { +    CmdArgs.push_back("-mfpmath"); +    CmdArgs.push_back(A->getValue()); +  } + +  // Disable a codegen optimization for floating-point casts. +  if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow, +                   options::OPT_fstrict_float_cast_overflow, false)) +    CmdArgs.push_back("-fno-strict-float-cast-overflow"); +} + +static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, +                                  const llvm::Triple &Triple, +                                  const InputInfo &Input) { +  // Enable region store model by default. +  CmdArgs.push_back("-analyzer-store=region"); + +  // Treat blocks as analysis entry points. +  CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); + +  // Add default argument set. +  if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { +    CmdArgs.push_back("-analyzer-checker=core"); +    CmdArgs.push_back("-analyzer-checker=apiModeling"); + +    if (!Triple.isWindowsMSVCEnvironment()) { +      CmdArgs.push_back("-analyzer-checker=unix"); +    } else { +      // Enable "unix" checkers that also work on Windows. +      CmdArgs.push_back("-analyzer-checker=unix.API"); +      CmdArgs.push_back("-analyzer-checker=unix.Malloc"); +      CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof"); +      CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator"); +      CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg"); +      CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); +    } + +    // Disable some unix checkers for PS4. +    if (Triple.isPS4CPU()) { +      CmdArgs.push_back("-analyzer-disable-checker=unix.API"); +      CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); +    } + +    if (Triple.isOSDarwin()) +      CmdArgs.push_back("-analyzer-checker=osx"); + +    CmdArgs.push_back("-analyzer-checker=deadcode"); + +    if (types::isCXX(Input.getType())) +      CmdArgs.push_back("-analyzer-checker=cplusplus"); + +    if (!Triple.isPS4CPU()) { +      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); +      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); +      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); +      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); +      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); +      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); +    } + +    // Default nullability checks. +    CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull"); +    CmdArgs.push_back("-analyzer-checker=nullability.NullReturnedFromNonnull"); +  } + +  // Set the output format. The default is plist, for (lame) historical reasons. +  CmdArgs.push_back("-analyzer-output"); +  if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) +    CmdArgs.push_back(A->getValue()); +  else +    CmdArgs.push_back("plist"); + +  // Disable the presentation of standard compiler warnings when using +  // --analyze.  We only want to show static analyzer diagnostics or frontend +  // errors. +  CmdArgs.push_back("-w"); + +  // Add -Xanalyzer arguments when running as analyzer. +  Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); +} + +static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args, +                             ArgStringList &CmdArgs, bool KernelOrKext) { +  const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); + +  // NVPTX doesn't support stack protectors; from the compiler's perspective, it +  // doesn't even have a stack! +  if (EffectiveTriple.isNVPTX()) +    return; + +  // -stack-protector=0 is default. +  unsigned StackProtectorLevel = 0; +  unsigned DefaultStackProtectorLevel = +      TC.GetDefaultStackProtectorLevel(KernelOrKext); + +  if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, +                               options::OPT_fstack_protector_all, +                               options::OPT_fstack_protector_strong, +                               options::OPT_fstack_protector)) { +    if (A->getOption().matches(options::OPT_fstack_protector)) +      StackProtectorLevel = +          std::max<unsigned>(LangOptions::SSPOn, DefaultStackProtectorLevel); +    else if (A->getOption().matches(options::OPT_fstack_protector_strong)) +      StackProtectorLevel = LangOptions::SSPStrong; +    else if (A->getOption().matches(options::OPT_fstack_protector_all)) +      StackProtectorLevel = LangOptions::SSPReq; +  } else { +    StackProtectorLevel = DefaultStackProtectorLevel; +  } + +  if (StackProtectorLevel) { +    CmdArgs.push_back("-stack-protector"); +    CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); +  } + +  // --param ssp-buffer-size= +  for (const Arg *A : Args.filtered(options::OPT__param)) { +    StringRef Str(A->getValue()); +    if (Str.startswith("ssp-buffer-size=")) { +      if (StackProtectorLevel) { +        CmdArgs.push_back("-stack-protector-buffer-size"); +        // FIXME: Verify the argument is a valid integer. +        CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); +      } +      A->claim(); +    } +  } +} + +static void RenderTrivialAutoVarInitOptions(const Driver &D, +                                            const ToolChain &TC, +                                            const ArgList &Args, +                                            ArgStringList &CmdArgs) { +  auto DefaultTrivialAutoVarInit = TC.GetDefaultTrivialAutoVarInit(); +  StringRef TrivialAutoVarInit = ""; + +  for (const Arg *A : Args) { +    switch (A->getOption().getID()) { +    default: +      continue; +    case options::OPT_ftrivial_auto_var_init: { +      A->claim(); +      StringRef Val = A->getValue(); +      if (Val == "uninitialized" || Val == "zero" || Val == "pattern") +        TrivialAutoVarInit = Val; +      else +        D.Diag(diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Val; +      break; +    } +    } +  } + +  if (TrivialAutoVarInit.empty()) +    switch (DefaultTrivialAutoVarInit) { +    case LangOptions::TrivialAutoVarInitKind::Uninitialized: +      break; +    case LangOptions::TrivialAutoVarInitKind::Pattern: +      TrivialAutoVarInit = "pattern"; +      break; +    case LangOptions::TrivialAutoVarInitKind::Zero: +      TrivialAutoVarInit = "zero"; +      break; +    } + +  if (!TrivialAutoVarInit.empty()) { +    if (TrivialAutoVarInit == "zero" && !Args.hasArg(options::OPT_enable_trivial_var_init_zero)) +      D.Diag(diag::err_drv_trivial_auto_var_init_zero_disabled); +    CmdArgs.push_back( +        Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit)); +  } +} + +static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { +  const unsigned ForwardedArguments[] = { +      options::OPT_cl_opt_disable, +      options::OPT_cl_strict_aliasing, +      options::OPT_cl_single_precision_constant, +      options::OPT_cl_finite_math_only, +      options::OPT_cl_kernel_arg_info, +      options::OPT_cl_unsafe_math_optimizations, +      options::OPT_cl_fast_relaxed_math, +      options::OPT_cl_mad_enable, +      options::OPT_cl_no_signed_zeros, +      options::OPT_cl_denorms_are_zero, +      options::OPT_cl_fp32_correctly_rounded_divide_sqrt, +      options::OPT_cl_uniform_work_group_size +  }; + +  if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { +    std::string CLStdStr = std::string("-cl-std=") + A->getValue(); +    CmdArgs.push_back(Args.MakeArgString(CLStdStr)); +  } + +  for (const auto &Arg : ForwardedArguments) +    if (const auto *A = Args.getLastArg(Arg)) +      CmdArgs.push_back(Args.MakeArgString(A->getOption().getPrefixedName())); +} + +static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, +                                        ArgStringList &CmdArgs) { +  bool ARCMTEnabled = false; +  if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { +    if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, +                                       options::OPT_ccc_arcmt_modify, +                                       options::OPT_ccc_arcmt_migrate)) { +      ARCMTEnabled = true; +      switch (A->getOption().getID()) { +      default: llvm_unreachable("missed a case"); +      case options::OPT_ccc_arcmt_check: +        CmdArgs.push_back("-arcmt-check"); +        break; +      case options::OPT_ccc_arcmt_modify: +        CmdArgs.push_back("-arcmt-modify"); +        break; +      case options::OPT_ccc_arcmt_migrate: +        CmdArgs.push_back("-arcmt-migrate"); +        CmdArgs.push_back("-mt-migrate-directory"); +        CmdArgs.push_back(A->getValue()); + +        Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); +        Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); +        break; +      } +    } +  } else { +    Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); +    Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); +    Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); +  } + +  if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { +    if (ARCMTEnabled) +      D.Diag(diag::err_drv_argument_not_allowed_with) +          << A->getAsString(Args) << "-ccc-arcmt-migrate"; + +    CmdArgs.push_back("-mt-migrate-directory"); +    CmdArgs.push_back(A->getValue()); + +    if (!Args.hasArg(options::OPT_objcmt_migrate_literals, +                     options::OPT_objcmt_migrate_subscripting, +                     options::OPT_objcmt_migrate_property)) { +      // None specified, means enable them all. +      CmdArgs.push_back("-objcmt-migrate-literals"); +      CmdArgs.push_back("-objcmt-migrate-subscripting"); +      CmdArgs.push_back("-objcmt-migrate-property"); +    } else { +      Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); +      Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); +      Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); +    } +  } else { +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); +    Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); +  } +} + +static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, +                                 const ArgList &Args, ArgStringList &CmdArgs) { +  // -fbuiltin is default unless -mkernel is used. +  bool UseBuiltins = +      Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, +                   !Args.hasArg(options::OPT_mkernel)); +  if (!UseBuiltins) +    CmdArgs.push_back("-fno-builtin"); + +  // -ffreestanding implies -fno-builtin. +  if (Args.hasArg(options::OPT_ffreestanding)) +    UseBuiltins = false; + +  // Process the -fno-builtin-* options. +  for (const auto &Arg : Args) { +    const Option &O = Arg->getOption(); +    if (!O.matches(options::OPT_fno_builtin_)) +      continue; + +    Arg->claim(); + +    // If -fno-builtin is specified, then there's no need to pass the option to +    // the frontend. +    if (!UseBuiltins) +      continue; + +    StringRef FuncName = Arg->getValue(); +    CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); +  } + +  // le32-specific flags: +  //  -fno-math-builtin: clang should not convert math builtins to intrinsics +  //                     by default. +  if (TC.getArch() == llvm::Triple::le32) +    CmdArgs.push_back("-fno-math-builtin"); +} + +void Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { +  llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Result); +  llvm::sys::path::append(Result, "org.llvm.clang."); +  appendUserToPath(Result); +  llvm::sys::path::append(Result, "ModuleCache"); +} + +static void RenderModulesOptions(Compilation &C, const Driver &D, +                                 const ArgList &Args, const InputInfo &Input, +                                 const InputInfo &Output, +                                 ArgStringList &CmdArgs, bool &HaveModules) { +  // -fmodules enables the use of precompiled modules (off by default). +  // Users can pass -fno-cxx-modules to turn off modules support for +  // C++/Objective-C++ programs. +  bool HaveClangModules = 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, true); +    if (AllowedInCXX || !types::isCXX(Input.getType())) { +      CmdArgs.push_back("-fmodules"); +      HaveClangModules = true; +    } +  } + +  HaveModules |= HaveClangModules; +  if (Args.hasArg(options::OPT_fmodules_ts)) { +    CmdArgs.push_back("-fmodules-ts"); +    HaveModules = true; +  } + +  // -fmodule-maps enables implicit reading of module map files. By default, +  // this is enabled if we are using Clang's flavor of precompiled modules. +  if (Args.hasFlag(options::OPT_fimplicit_module_maps, +                   options::OPT_fno_implicit_module_maps, HaveClangModules)) +    CmdArgs.push_back("-fimplicit-module-maps"); + +  // -fmodules-decluse checks that modules used are declared so (off by default) +  if (Args.hasFlag(options::OPT_fmodules_decluse, +                   options::OPT_fno_modules_decluse, false)) +    CmdArgs.push_back("-fmodules-decluse"); + +  // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that +  // all #included headers are part of modules. +  if (Args.hasFlag(options::OPT_fmodules_strict_decluse, +                   options::OPT_fno_modules_strict_decluse, false)) +    CmdArgs.push_back("-fmodules-strict-decluse"); + +  // -fno-implicit-modules turns off implicitly compiling modules on demand. +  bool ImplicitModules = false; +  if (!Args.hasFlag(options::OPT_fimplicit_modules, +                    options::OPT_fno_implicit_modules, HaveClangModules)) { +    if (HaveModules) +      CmdArgs.push_back("-fno-implicit-modules"); +  } else if (HaveModules) { +    ImplicitModules = true; +    // -fmodule-cache-path specifies where our implicitly-built module files +    // should be written. +    SmallString<128> Path; +    if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) +      Path = A->getValue(); + +    if (C.isForDiagnostics()) { +      // When generating crash reports, we want to emit the modules along with +      // the reproduction sources, so we ignore any provided module path. +      Path = Output.getFilename(); +      llvm::sys::path::replace_extension(Path, ".cache"); +      llvm::sys::path::append(Path, "modules"); +    } else if (Path.empty()) { +      // No module path was provided: use the default. +      Driver::getDefaultModuleCachePath(Path); +    } + +    const char Arg[] = "-fmodules-cache-path="; +    Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); +    CmdArgs.push_back(Args.MakeArgString(Path)); +  } + +  if (HaveModules) { +    // -fprebuilt-module-path specifies where to load the prebuilt module files. +    for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { +      CmdArgs.push_back(Args.MakeArgString( +          std::string("-fprebuilt-module-path=") + A->getValue())); +      A->claim(); +    } +    if (Args.hasFlag(options::OPT_fmodules_validate_input_files_content, +                     options::OPT_fno_modules_validate_input_files_content, +                     false)) +      CmdArgs.push_back("-fvalidate-ast-input-files-content"); +  } + +  // -fmodule-name specifies the module that is currently being built (or +  // used for header checking by -fmodule-maps). +  Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ); + +  // -fmodule-map-file can be used to specify files containing module +  // definitions. +  Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); + +  // -fbuiltin-module-map can be used to load the clang +  // builtin headers modulemap file. +  if (Args.hasArg(options::OPT_fbuiltin_module_map)) { +    SmallString<128> BuiltinModuleMap(D.ResourceDir); +    llvm::sys::path::append(BuiltinModuleMap, "include"); +    llvm::sys::path::append(BuiltinModuleMap, "module.modulemap"); +    if (llvm::sys::fs::exists(BuiltinModuleMap)) +      CmdArgs.push_back( +          Args.MakeArgString("-fmodule-map-file=" + BuiltinModuleMap)); +  } + +  // The -fmodule-file=<name>=<file> form specifies the mapping of module +  // names to precompiled module files (the module is loaded only if used). +  // The -fmodule-file=<file> form can be used to unconditionally load +  // precompiled module files (whether used or not). +  if (HaveModules) +    Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); +  else +    Args.ClaimAllArgs(options::OPT_fmodule_file); + +  // When building modules and generating crashdumps, we need to dump a module +  // dependency VFS alongside the output. +  if (HaveClangModules && C.isForDiagnostics()) { +    SmallString<128> VFSDir(Output.getFilename()); +    llvm::sys::path::replace_extension(VFSDir, ".cache"); +    // Add the cache directory as a temp so the crash diagnostics pick it up. +    C.addTempFile(Args.MakeArgString(VFSDir)); + +    llvm::sys::path::append(VFSDir, "vfs"); +    CmdArgs.push_back("-module-dependency-dir"); +    CmdArgs.push_back(Args.MakeArgString(VFSDir)); +  } + +  if (HaveClangModules) +    Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); + +  // 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); + +  Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); + +  if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { +    if (Args.hasArg(options::OPT_fbuild_session_timestamp)) +      D.Diag(diag::err_drv_argument_not_allowed_with) +          << A->getAsString(Args) << "-fbuild-session-timestamp"; + +    llvm::sys::fs::file_status Status; +    if (llvm::sys::fs::status(A->getValue(), Status)) +      D.Diag(diag::err_drv_no_such_file) << A->getValue(); +    CmdArgs.push_back( +        Args.MakeArgString("-fbuild-session-timestamp=" + +                           Twine((uint64_t)Status.getLastModificationTime() +                                     .time_since_epoch() +                                     .count()))); +  } + +  if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { +    if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, +                         options::OPT_fbuild_session_file)) +      D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); + +    Args.AddLastArg(CmdArgs, +                    options::OPT_fmodules_validate_once_per_build_session); +  } + +  if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, +                   options::OPT_fno_modules_validate_system_headers, +                   ImplicitModules)) +    CmdArgs.push_back("-fmodules-validate-system-headers"); + +  Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); +} + +static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, +                                   ArgStringList &CmdArgs) { +  // -fsigned-char is default. +  if (const Arg *A = Args.getLastArg(options::OPT_fsigned_char, +                                     options::OPT_fno_signed_char, +                                     options::OPT_funsigned_char, +                                     options::OPT_fno_unsigned_char)) { +    if (A->getOption().matches(options::OPT_funsigned_char) || +        A->getOption().matches(options::OPT_fno_signed_char)) { +      CmdArgs.push_back("-fno-signed-char"); +    } +  } else if (!isSignedCharDefault(T)) { +    CmdArgs.push_back("-fno-signed-char"); +  } + +  // The default depends on the language standard. +  Args.AddLastArg(CmdArgs, options::OPT_fchar8__t, options::OPT_fno_char8__t); + +  if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar, +                                     options::OPT_fno_short_wchar)) { +    if (A->getOption().matches(options::OPT_fshort_wchar)) { +      CmdArgs.push_back("-fwchar-type=short"); +      CmdArgs.push_back("-fno-signed-wchar"); +    } else { +      bool IsARM = T.isARM() || T.isThumb() || T.isAArch64(); +      CmdArgs.push_back("-fwchar-type=int"); +      if (IsARM && !(T.isOSWindows() || T.isOSNetBSD() || +                     T.isOSOpenBSD())) +        CmdArgs.push_back("-fno-signed-wchar"); +      else +        CmdArgs.push_back("-fsigned-wchar"); +    } +  } +} + +static void RenderObjCOptions(const ToolChain &TC, const Driver &D, +                              const llvm::Triple &T, const ArgList &Args, +                              ObjCRuntime &Runtime, bool InferCovariantReturns, +                              const InputInfo &Input, ArgStringList &CmdArgs) { +  const llvm::Triple::ArchType Arch = TC.getArch(); + +  // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and legacy +  // is the default. Except for deployment target of 10.5, next runtime is +  // always legacy dispatch and -fno-objc-legacy-dispatch gets ignored silently. +  if (Runtime.isNonFragile()) { +    if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, +                      options::OPT_fno_objc_legacy_dispatch, +                      Runtime.isLegacyDispatchDefaultForArch(Arch))) { +      if (TC.UseObjCMixedDispatch()) +        CmdArgs.push_back("-fobjc-dispatch-method=mixed"); +      else +        CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); +    } +  } + +  // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option +  // to do Array/Dictionary subscripting by default. +  if (Arch == llvm::Triple::x86 && T.isMacOSX() && +      Runtime.getKind() == ObjCRuntime::FragileMacOSX && Runtime.isNeXTFamily()) +    CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); + +  // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. +  // NOTE: This logic is duplicated in ToolChains.cpp. +  if (isObjCAutoRefCount(Args)) { +    TC.CheckObjCARC(); + +    CmdArgs.push_back("-fobjc-arc"); + +    // FIXME: It seems like this entire block, and several around it should be +    // wrapped in isObjC, but for now we just use it here as this is where it +    // was being used previously. +    if (types::isCXX(Input.getType()) && types::isObjC(Input.getType())) { +      if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) +        CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); +      else +        CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); +    } + +    // Allow the user to enable full exceptions code emission. +    // We default off for Objective-C, on for Objective-C++. +    if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, +                     options::OPT_fno_objc_arc_exceptions, +                     /*Default=*/types::isCXX(Input.getType()))) +      CmdArgs.push_back("-fobjc-arc-exceptions"); +  } + +  // Silence warning for full exception code emission options when explicitly +  // set to use no ARC. +  if (Args.hasArg(options::OPT_fno_objc_arc)) { +    Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions); +    Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions); +  } + +  // Allow the user to control whether messages can be converted to runtime +  // functions. +  if (types::isObjC(Input.getType())) { +    auto *Arg = Args.getLastArg( +        options::OPT_fobjc_convert_messages_to_runtime_calls, +        options::OPT_fno_objc_convert_messages_to_runtime_calls); +    if (Arg && +        Arg->getOption().matches( +            options::OPT_fno_objc_convert_messages_to_runtime_calls)) +      CmdArgs.push_back("-fno-objc-convert-messages-to-runtime-calls"); +  } + +  // -fobjc-infer-related-result-type is the default, except in the Objective-C +  // rewriter. +  if (InferCovariantReturns) +    CmdArgs.push_back("-fno-objc-infer-related-result-type"); + +  // Pass down -fobjc-weak or -fno-objc-weak if present. +  if (types::isObjC(Input.getType())) { +    auto WeakArg = +        Args.getLastArg(options::OPT_fobjc_weak, options::OPT_fno_objc_weak); +    if (!WeakArg) { +      // nothing to do +    } else if (!Runtime.allowsWeak()) { +      if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) +        D.Diag(diag::err_objc_weak_unsupported); +    } else { +      WeakArg->render(Args, CmdArgs); +    } +  } +} + +static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, +                                     ArgStringList &CmdArgs) { +  bool CaretDefault = true; +  bool ColumnDefault = true; + +  if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diagnostics_classic, +                                     options::OPT__SLASH_diagnostics_column, +                                     options::OPT__SLASH_diagnostics_caret)) { +    switch (A->getOption().getID()) { +    case options::OPT__SLASH_diagnostics_caret: +      CaretDefault = true; +      ColumnDefault = true; +      break; +    case options::OPT__SLASH_diagnostics_column: +      CaretDefault = false; +      ColumnDefault = true; +      break; +    case options::OPT__SLASH_diagnostics_classic: +      CaretDefault = false; +      ColumnDefault = false; +      break; +    } +  } + +  // -fcaret-diagnostics is default. +  if (!Args.hasFlag(options::OPT_fcaret_diagnostics, +                    options::OPT_fno_caret_diagnostics, CaretDefault)) +    CmdArgs.push_back("-fno-caret-diagnostics"); + +  // -fdiagnostics-fixit-info is default, only pass non-default. +  if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, +                    options::OPT_fno_diagnostics_fixit_info)) +    CmdArgs.push_back("-fno-diagnostics-fixit-info"); + +  // Enable -fdiagnostics-show-option by default. +  if (Args.hasFlag(options::OPT_fdiagnostics_show_option, +                   options::OPT_fno_diagnostics_show_option)) +    CmdArgs.push_back("-fdiagnostics-show-option"); + +  if (const Arg *A = +          Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { +    CmdArgs.push_back("-fdiagnostics-show-category"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, +                   options::OPT_fno_diagnostics_show_hotness, false)) +    CmdArgs.push_back("-fdiagnostics-show-hotness"); + +  if (const Arg *A = +          Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { +    std::string Opt = +        std::string("-fdiagnostics-hotness-threshold=") + A->getValue(); +    CmdArgs.push_back(Args.MakeArgString(Opt)); +  } + +  if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { +    CmdArgs.push_back("-fdiagnostics-format"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (const Arg *A = Args.getLastArg( +          options::OPT_fdiagnostics_show_note_include_stack, +          options::OPT_fno_diagnostics_show_note_include_stack)) { +    const Option &O = A->getOption(); +    if (O.matches(options::OPT_fdiagnostics_show_note_include_stack)) +      CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); +    else +      CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); +  } + +  // Color diagnostics are parsed by the driver directly from argv and later +  // re-parsed to construct this job; claim any possible color diagnostic here +  // to avoid warn_drv_unused_argument and diagnose bad +  // OPT_fdiagnostics_color_EQ values. +  for (const Arg *A : Args) { +    const Option &O = A->getOption(); +    if (!O.matches(options::OPT_fcolor_diagnostics) && +        !O.matches(options::OPT_fdiagnostics_color) && +        !O.matches(options::OPT_fno_color_diagnostics) && +        !O.matches(options::OPT_fno_diagnostics_color) && +        !O.matches(options::OPT_fdiagnostics_color_EQ)) +      continue; + +    if (O.matches(options::OPT_fdiagnostics_color_EQ)) { +      StringRef Value(A->getValue()); +      if (Value != "always" && Value != "never" && Value != "auto") +        D.Diag(diag::err_drv_clang_unsupported) +            << ("-fdiagnostics-color=" + Value).str(); +    } +    A->claim(); +  } + +  if (D.getDiags().getDiagnosticOptions().ShowColors) +    CmdArgs.push_back("-fcolor-diagnostics"); + +  if (Args.hasArg(options::OPT_fansi_escape_codes)) +    CmdArgs.push_back("-fansi-escape-codes"); + +  if (!Args.hasFlag(options::OPT_fshow_source_location, +                    options::OPT_fno_show_source_location)) +    CmdArgs.push_back("-fno-show-source-location"); + +  if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) +    CmdArgs.push_back("-fdiagnostics-absolute-paths"); + +  if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, +                    ColumnDefault)) +    CmdArgs.push_back("-fno-show-column"); + +  if (!Args.hasFlag(options::OPT_fspell_checking, +                    options::OPT_fno_spell_checking)) +    CmdArgs.push_back("-fno-spell-checking"); +} + +enum class DwarfFissionKind { None, Split, Single }; + +static DwarfFissionKind getDebugFissionKind(const Driver &D, +                                            const ArgList &Args, Arg *&Arg) { +  Arg = +      Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ); +  if (!Arg) +    return DwarfFissionKind::None; + +  if (Arg->getOption().matches(options::OPT_gsplit_dwarf)) +    return DwarfFissionKind::Split; + +  StringRef Value = Arg->getValue(); +  if (Value == "split") +    return DwarfFissionKind::Split; +  if (Value == "single") +    return DwarfFissionKind::Single; + +  D.Diag(diag::err_drv_unsupported_option_argument) +      << Arg->getOption().getName() << Arg->getValue(); +  return DwarfFissionKind::None; +} + +static void RenderDebugOptions(const ToolChain &TC, const Driver &D, +                               const llvm::Triple &T, const ArgList &Args, +                               bool EmitCodeView, bool IsWindowsMSVC, +                               ArgStringList &CmdArgs, +                               codegenoptions::DebugInfoKind &DebugInfoKind, +                               DwarfFissionKind &DwarfFission) { +  if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, +                   options::OPT_fno_debug_info_for_profiling, false) && +      checkDebugInfoOption( +          Args.getLastArg(options::OPT_fdebug_info_for_profiling), Args, D, TC)) +    CmdArgs.push_back("-fdebug-info-for-profiling"); + +  // The 'g' groups options involve a somewhat intricate sequence of decisions +  // about what to pass from the driver to the frontend, but by the time they +  // reach cc1 they've been factored into three well-defined orthogonal choices: +  //  * what level of debug info to generate +  //  * what dwarf version to write +  //  * what debugger tuning to use +  // This avoids having to monkey around further in cc1 other than to disable +  // codeview if not running in a Windows environment. Perhaps even that +  // decision should be made in the driver as well though. +  unsigned DWARFVersion = 0; +  llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning(); + +  bool SplitDWARFInlining = +      Args.hasFlag(options::OPT_fsplit_dwarf_inlining, +                   options::OPT_fno_split_dwarf_inlining, true); + +  Args.ClaimAllArgs(options::OPT_g_Group); + +  Arg* SplitDWARFArg; +  DwarfFission = getDebugFissionKind(D, Args, SplitDWARFArg); + +  if (DwarfFission != DwarfFissionKind::None && +      !checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) { +    DwarfFission = DwarfFissionKind::None; +    SplitDWARFInlining = false; +  } + +  if (const Arg *A = +          Args.getLastArg(options::OPT_g_Group, options::OPT_gsplit_dwarf, +                          options::OPT_gsplit_dwarf_EQ)) { +    DebugInfoKind = codegenoptions::LimitedDebugInfo; + +    // If the last option explicitly specified a debug-info level, use it. +    if (checkDebugInfoOption(A, Args, D, TC) && +        A->getOption().matches(options::OPT_gN_Group)) { +      DebugInfoKind = DebugLevelToInfoKind(*A); +      // For -g0 or -gline-tables-only, drop -gsplit-dwarf. This gets a bit more +      // complicated if you've disabled inline info in the skeleton CUs +      // (SplitDWARFInlining) - then there's value in composing split-dwarf and +      // line-tables-only, so let those compose naturally in that case. +      if (DebugInfoKind == codegenoptions::NoDebugInfo || +          DebugInfoKind == codegenoptions::DebugDirectivesOnly || +          (DebugInfoKind == codegenoptions::DebugLineTablesOnly && +           SplitDWARFInlining)) +        DwarfFission = DwarfFissionKind::None; +    } +  } + +  // If a debugger tuning argument appeared, remember it. +  if (const Arg *A = +          Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { +    if (checkDebugInfoOption(A, Args, D, TC)) { +      if (A->getOption().matches(options::OPT_glldb)) +        DebuggerTuning = llvm::DebuggerKind::LLDB; +      else if (A->getOption().matches(options::OPT_gsce)) +        DebuggerTuning = llvm::DebuggerKind::SCE; +      else +        DebuggerTuning = llvm::DebuggerKind::GDB; +    } +  } + +  // If a -gdwarf argument appeared, remember it. +  if (const Arg *A = +          Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, +                          options::OPT_gdwarf_4, options::OPT_gdwarf_5)) +    if (checkDebugInfoOption(A, Args, D, TC)) +      DWARFVersion = DwarfVersionNum(A->getSpelling()); + +  if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { +    if (checkDebugInfoOption(A, Args, D, TC)) +      EmitCodeView = true; +  } + +  // If the user asked for debug info but did not explicitly specify -gcodeview +  // or -gdwarf, ask the toolchain for the default format. +  if (!EmitCodeView && DWARFVersion == 0 && +      DebugInfoKind != codegenoptions::NoDebugInfo) { +    switch (TC.getDefaultDebugFormat()) { +    case codegenoptions::DIF_CodeView: +      EmitCodeView = true; +      break; +    case codegenoptions::DIF_DWARF: +      DWARFVersion = TC.GetDefaultDwarfVersion(); +      break; +    } +  } + +  // -gline-directives-only supported only for the DWARF debug info. +  if (DWARFVersion == 0 && DebugInfoKind == codegenoptions::DebugDirectivesOnly) +    DebugInfoKind = codegenoptions::NoDebugInfo; + +  // We ignore flag -gstrict-dwarf for now. +  // And we handle flag -grecord-gcc-switches later with DWARFDebugFlags. +  Args.ClaimAllArgs(options::OPT_g_flags_Group); + +  // Column info is included by default for everything except SCE and +  // CodeView. Clang doesn't track end columns, just starting columns, which, +  // in theory, is fine for CodeView (and PDB).  In practice, however, the +  // Microsoft debuggers don't handle missing end columns well, so it's better +  // not to include any column info. +  if (const Arg *A = Args.getLastArg(options::OPT_gcolumn_info)) +    (void)checkDebugInfoOption(A, Args, D, TC); +  if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, +                   /*Default=*/!EmitCodeView && +                       DebuggerTuning != llvm::DebuggerKind::SCE)) +    CmdArgs.push_back("-dwarf-column-info"); + +  // FIXME: Move backend command line options to the module. +  // If -gline-tables-only or -gline-directives-only is the last option it wins. +  if (const Arg *A = Args.getLastArg(options::OPT_gmodules)) +    if (checkDebugInfoOption(A, Args, D, TC)) { +      if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && +          DebugInfoKind != codegenoptions::DebugDirectivesOnly) { +        DebugInfoKind = codegenoptions::LimitedDebugInfo; +        CmdArgs.push_back("-dwarf-ext-refs"); +        CmdArgs.push_back("-fmodule-format=obj"); +      } +    } + +  if (T.isOSBinFormatELF() && !SplitDWARFInlining) +    CmdArgs.push_back("-fno-split-dwarf-inlining"); + +  // After we've dealt with all combinations of things that could +  // make DebugInfoKind be other than None or DebugLineTablesOnly, +  // figure out if we need to "upgrade" it to standalone debug info. +  // We parse these two '-f' options whether or not they will be used, +  // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" +  bool NeedFullDebug = Args.hasFlag( +      options::OPT_fstandalone_debug, options::OPT_fno_standalone_debug, +      DebuggerTuning == llvm::DebuggerKind::LLDB || +          TC.GetDefaultStandaloneDebug()); +  if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug)) +    (void)checkDebugInfoOption(A, Args, D, TC); +  if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) +    DebugInfoKind = codegenoptions::FullDebugInfo; + +  if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source, +                   false)) { +    // Source embedding is a vendor extension to DWARF v5. By now we have +    // checked if a DWARF version was stated explicitly, and have otherwise +    // fallen back to the target default, so if this is still not at least 5 +    // we emit an error. +    const Arg *A = Args.getLastArg(options::OPT_gembed_source); +    if (DWARFVersion < 5) +      D.Diag(diag::err_drv_argument_only_allowed_with) +          << A->getAsString(Args) << "-gdwarf-5"; +    else if (checkDebugInfoOption(A, Args, D, TC)) +      CmdArgs.push_back("-gembed-source"); +  } + +  if (EmitCodeView) { +    CmdArgs.push_back("-gcodeview"); + +    // Emit codeview type hashes if requested. +    if (Args.hasFlag(options::OPT_gcodeview_ghash, +                     options::OPT_gno_codeview_ghash, false)) { +      CmdArgs.push_back("-gcodeview-ghash"); +    } +  } + +  // Adjust the debug info kind for the given toolchain. +  TC.adjustDebugInfoKind(DebugInfoKind, Args); + +  RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, +                          DebuggerTuning); + +  // -fdebug-macro turns on macro debug info generation. +  if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, +                   false)) +    if (checkDebugInfoOption(Args.getLastArg(options::OPT_fdebug_macro), Args, +                             D, TC)) +      CmdArgs.push_back("-debug-info-macro"); + +  // -ggnu-pubnames turns on gnu style pubnames in the backend. +  const auto *PubnamesArg = +      Args.getLastArg(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames, +                      options::OPT_gpubnames, options::OPT_gno_pubnames); +  if (DwarfFission != DwarfFissionKind::None || +      (PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC))) +    if (!PubnamesArg || +        (!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) && +         !PubnamesArg->getOption().matches(options::OPT_gno_pubnames))) +      CmdArgs.push_back(PubnamesArg && PubnamesArg->getOption().matches( +                                           options::OPT_gpubnames) +                            ? "-gpubnames" +                            : "-ggnu-pubnames"); + +  if (Args.hasFlag(options::OPT_fdebug_ranges_base_address, +                   options::OPT_fno_debug_ranges_base_address, false)) { +    CmdArgs.push_back("-fdebug-ranges-base-address"); +  } + +  // -gdwarf-aranges turns on the emission of the aranges section in the +  // backend. +  // Always enabled for SCE tuning. +  bool NeedAranges = DebuggerTuning == llvm::DebuggerKind::SCE; +  if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_aranges)) +    NeedAranges = checkDebugInfoOption(A, Args, D, TC) || NeedAranges; +  if (NeedAranges) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-generate-arange-section"); +  } + +  if (Args.hasFlag(options::OPT_fdebug_types_section, +                   options::OPT_fno_debug_types_section, false)) { +    if (!T.isOSBinFormatELF()) { +      D.Diag(diag::err_drv_unsupported_opt_for_target) +          << Args.getLastArg(options::OPT_fdebug_types_section) +                 ->getAsString(Args) +          << T.getTriple(); +    } else if (checkDebugInfoOption( +                   Args.getLastArg(options::OPT_fdebug_types_section), Args, D, +                   TC)) { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-generate-type-units"); +    } +  } + +  // Decide how to render forward declarations of template instantiations. +  // SCE wants full descriptions, others just get them in the name. +  if (DebuggerTuning == llvm::DebuggerKind::SCE) +    CmdArgs.push_back("-debug-forward-template-params"); + +  // Do we need to explicitly import anonymous namespaces into the parent +  // scope? +  if (DebuggerTuning == llvm::DebuggerKind::SCE) +    CmdArgs.push_back("-dwarf-explicit-import"); + +  RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); +} + +void Clang::ConstructJob(Compilation &C, const JobAction &JA, +                         const InputInfo &Output, const InputInfoList &Inputs, +                         const ArgList &Args, const char *LinkingOutput) const { +  const auto &TC = getToolChain(); +  const llvm::Triple &RawTriple = TC.getTriple(); +  const llvm::Triple &Triple = TC.getEffectiveTriple(); +  const std::string &TripleStr = Triple.getTriple(); + +  bool KernelOrKext = +      Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); +  const Driver &D = TC.getDriver(); +  ArgStringList CmdArgs; + +  // Check number of inputs for sanity. We need at least one input. +  assert(Inputs.size() >= 1 && "Must have at least one input."); +  // CUDA/HIP compilation may have multiple inputs (source file + results of +  // device-side compilations). OpenMP device jobs also take the host IR as a +  // second input. Module precompilation accepts a list of header files to +  // include as part of the module. All other jobs are expected to have exactly +  // one input. +  bool IsCuda = JA.isOffloading(Action::OFK_Cuda); +  bool IsHIP = JA.isOffloading(Action::OFK_HIP); +  bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); +  bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA); + +  // A header module compilation doesn't have a main input file, so invent a +  // fake one as a placeholder. +  const char *ModuleName = [&]{ +    auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ); +    return ModuleNameArg ? ModuleNameArg->getValue() : ""; +  }(); +  InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName); + +  const InputInfo &Input = +      IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0]; + +  InputInfoList ModuleHeaderInputs; +  const InputInfo *CudaDeviceInput = nullptr; +  const InputInfo *OpenMPDeviceInput = nullptr; +  for (const InputInfo &I : Inputs) { +    if (&I == &Input) { +      // This is the primary input. +    } else if (IsHeaderModulePrecompile && +               types::getPrecompiledType(I.getType()) == types::TY_PCH) { +      types::ID Expected = HeaderModuleInput.getType(); +      if (I.getType() != Expected) { +        D.Diag(diag::err_drv_module_header_wrong_kind) +            << I.getFilename() << types::getTypeName(I.getType()) +            << types::getTypeName(Expected); +      } +      ModuleHeaderInputs.push_back(I); +    } else if ((IsCuda || IsHIP) && !CudaDeviceInput) { +      CudaDeviceInput = &I; +    } else if (IsOpenMPDevice && !OpenMPDeviceInput) { +      OpenMPDeviceInput = &I; +    } else { +      llvm_unreachable("unexpectedly given multiple inputs"); +    } +  } + +  const llvm::Triple *AuxTriple = IsCuda ? TC.getAuxTriple() : nullptr; +  bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); +  bool IsIAMCU = RawTriple.isOSIAMCU(); + +  // Adjust IsWindowsXYZ for CUDA/HIP compilations.  Even when compiling in +  // device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not +  // Windows), we need to pass Windows-specific flags to cc1. +  if (IsCuda || IsHIP) +    IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); + +  // C++ is not supported for IAMCU. +  if (IsIAMCU && types::isCXX(Input.getType())) +    D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU"; + +  // Invoke ourselves in -cc1 mode. +  // +  // FIXME: Implement custom jobs for internal actions. +  CmdArgs.push_back("-cc1"); + +  // Add the "effective" target triple. +  CmdArgs.push_back("-triple"); +  CmdArgs.push_back(Args.MakeArgString(TripleStr)); + +  if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) { +    DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args); +    Args.ClaimAllArgs(options::OPT_MJ); +  } else if (const Arg *GenCDBFragment = +                 Args.getLastArg(options::OPT_gen_cdb_fragment_path)) { +    DumpCompilationDatabaseFragmentToDir(GenCDBFragment->getValue(), C, +                                         TripleStr, Output, Input, Args); +    Args.ClaimAllArgs(options::OPT_gen_cdb_fragment_path); +  } + +  if (IsCuda || IsHIP) { +    // We have to pass the triple of the host if compiling for a CUDA/HIP device +    // and vice-versa. +    std::string NormalizedTriple; +    if (JA.isDeviceOffloading(Action::OFK_Cuda) || +        JA.isDeviceOffloading(Action::OFK_HIP)) +      NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>() +                             ->getTriple() +                             .normalize(); +    else { +      // Host-side compilation. +      NormalizedTriple = +          (IsCuda ? C.getSingleOffloadToolChain<Action::OFK_Cuda>() +                  : C.getSingleOffloadToolChain<Action::OFK_HIP>()) +              ->getTriple() +              .normalize(); +      if (IsCuda) { +        // We need to figure out which CUDA version we're compiling for, as that +        // determines how we load and launch GPU kernels. +        auto *CTC = static_cast<const toolchains::CudaToolChain *>( +            C.getSingleOffloadToolChain<Action::OFK_Cuda>()); +        assert(CTC && "Expected valid CUDA Toolchain."); +        if (CTC && CTC->CudaInstallation.version() != CudaVersion::UNKNOWN) +          CmdArgs.push_back(Args.MakeArgString( +              Twine("-target-sdk-version=") + +              CudaVersionToString(CTC->CudaInstallation.version()))); +      } +    } +    CmdArgs.push_back("-aux-triple"); +    CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); +  } + +  if (IsOpenMPDevice) { +    // We have to pass the triple of the host if compiling for an OpenMP device. +    std::string NormalizedTriple = +        C.getSingleOffloadToolChain<Action::OFK_Host>() +            ->getTriple() +            .normalize(); +    CmdArgs.push_back("-aux-triple"); +    CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); +  } + +  if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || +                               Triple.getArch() == llvm::Triple::thumb)) { +    unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; +    unsigned Version; +    Triple.getArchName().substr(Offset).getAsInteger(10, Version); +    if (Version < 7) +      D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() +                                                << TripleStr; +  } + +  // Push all default warning arguments that are specific to +  // the given target.  These come before user provided warning options +  // are provided. +  TC.addClangWarningOptions(CmdArgs); + +  // Select the appropriate action. +  RewriteKind rewriteKind = RK_None; + +  // If CollectArgsForIntegratedAssembler() isn't called below, claim the args +  // it claims when not running an assembler. Otherwise, clang would emit +  // "argument unused" warnings for assembler flags when e.g. adding "-E" to +  // flags while debugging something. That'd be somewhat inconvenient, and it's +  // also inconsistent with most other flags -- we don't warn on +  // -ffunction-sections not being used in -E mode either for example, even +  // though it's not really used either. +  if (!isa<AssembleJobAction>(JA)) { +    // The args claimed here should match the args used in +    // CollectArgsForIntegratedAssembler(). +    if (TC.useIntegratedAs()) { +      Args.ClaimAllArgs(options::OPT_mrelax_all); +      Args.ClaimAllArgs(options::OPT_mno_relax_all); +      Args.ClaimAllArgs(options::OPT_mincremental_linker_compatible); +      Args.ClaimAllArgs(options::OPT_mno_incremental_linker_compatible); +      switch (C.getDefaultToolChain().getArch()) { +      case llvm::Triple::arm: +      case llvm::Triple::armeb: +      case llvm::Triple::thumb: +      case llvm::Triple::thumbeb: +        Args.ClaimAllArgs(options::OPT_mimplicit_it_EQ); +        break; +      default: +        break; +      } +    } +    Args.ClaimAllArgs(options::OPT_Wa_COMMA); +    Args.ClaimAllArgs(options::OPT_Xassembler); +  } + +  if (isa<AnalyzeJobAction>(JA)) { +    assert(JA.getType() == types::TY_Plist && "Invalid output type."); +    CmdArgs.push_back("-analyze"); +  } else if (isa<MigrateJobAction>(JA)) { +    CmdArgs.push_back("-migrate"); +  } else if (isa<PreprocessJobAction>(JA)) { +    if (Output.getType() == types::TY_Dependencies) +      CmdArgs.push_back("-Eonly"); +    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"); + +    CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D); + +    // Also ignore explicit -force_cpusubtype_ALL option. +    (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); +  } else if (isa<PrecompileJobAction>(JA)) { +    if (JA.getType() == types::TY_Nothing) +      CmdArgs.push_back("-fsyntax-only"); +    else if (JA.getType() == types::TY_ModuleFile) +      CmdArgs.push_back(IsHeaderModulePrecompile +                            ? "-emit-header-module" +                            : "-emit-module-interface"); +    else +      CmdArgs.push_back("-emit-pch"); +  } else if (isa<VerifyPCHJobAction>(JA)) { +    CmdArgs.push_back("-verify-pch"); +  } else { +    assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && +           "Invalid action for clang tool."); +    if (JA.getType() == types::TY_Nothing) { +      CmdArgs.push_back("-fsyntax-only"); +    } else 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 (JA.getType() == types::TY_IFS || +               JA.getType() == types::TY_IFS_CPP) { +      StringRef ArgStr = +          Args.hasArg(options::OPT_interface_stub_version_EQ) +              ? Args.getLastArgValue(options::OPT_interface_stub_version_EQ) +              : "experimental-ifs-v1"; +      CmdArgs.push_back("-emit-interface-stubs"); +      CmdArgs.push_back( +          Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str())); +    } else if (JA.getType() == types::TY_PP_Asm) { +      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; +    } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { +      CmdArgs.push_back("-rewrite-objc"); +      rewriteKind = RK_Fragile; +    } else { +      assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); +    } + +    // Preserve use-list order by default when emitting bitcode, so that +    // loading the bitcode up in 'opt' or 'llc' and running passes gives the +    // same result as running passes here.  For LTO, we don't need to preserve +    // the use-list order, since serialization to bitcode is part of the flow. +    if (JA.getType() == types::TY_LLVM_BC) +      CmdArgs.push_back("-emit-llvm-uselists"); + +    // Device-side jobs do not support LTO. +    bool isDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) || +                                   JA.isDeviceOffloading(Action::OFK_Host)); + +    if (D.isUsingLTO() && !isDeviceOffloadAction) { +      Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); +      CmdArgs.push_back("-flto-unit"); +    } +  } + +  if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { +    if (!types::isLLVMIR(Input.getType())) +      D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args); +    Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); +  } + +  if (Args.getLastArg(options::OPT_save_temps_EQ)) +    Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); + +  // Embed-bitcode option. +  // Only white-listed flags below are allowed to be embedded. +  if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() && +      (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { +    // Add flags implied by -fembed-bitcode. +    Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); +    // Disable all llvm IR level optimizations. +    CmdArgs.push_back("-disable-llvm-passes"); + +    // Render target options such as -fuse-init-array on modern ELF platforms. +    TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); + +    // reject options that shouldn't be supported in bitcode +    // also reject kernel/kext +    static const constexpr unsigned kBitcodeOptionBlacklist[] = { +        options::OPT_mkernel, +        options::OPT_fapple_kext, +        options::OPT_ffunction_sections, +        options::OPT_fno_function_sections, +        options::OPT_fdata_sections, +        options::OPT_fno_data_sections, +        options::OPT_funique_section_names, +        options::OPT_fno_unique_section_names, +        options::OPT_mrestrict_it, +        options::OPT_mno_restrict_it, +        options::OPT_mstackrealign, +        options::OPT_mno_stackrealign, +        options::OPT_mstack_alignment, +        options::OPT_mcmodel_EQ, +        options::OPT_mlong_calls, +        options::OPT_mno_long_calls, +        options::OPT_ggnu_pubnames, +        options::OPT_gdwarf_aranges, +        options::OPT_fdebug_types_section, +        options::OPT_fno_debug_types_section, +        options::OPT_fdwarf_directory_asm, +        options::OPT_fno_dwarf_directory_asm, +        options::OPT_mrelax_all, +        options::OPT_mno_relax_all, +        options::OPT_ftrap_function_EQ, +        options::OPT_ffixed_r9, +        options::OPT_mfix_cortex_a53_835769, +        options::OPT_mno_fix_cortex_a53_835769, +        options::OPT_ffixed_x18, +        options::OPT_mglobal_merge, +        options::OPT_mno_global_merge, +        options::OPT_mred_zone, +        options::OPT_mno_red_zone, +        options::OPT_Wa_COMMA, +        options::OPT_Xassembler, +        options::OPT_mllvm, +    }; +    for (const auto &A : Args) +      if (llvm::find(kBitcodeOptionBlacklist, A->getOption().getID()) != +          std::end(kBitcodeOptionBlacklist)) +        D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling(); + +    // Render the CodeGen options that need to be passed. +    if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, +                      options::OPT_fno_optimize_sibling_calls)) +      CmdArgs.push_back("-mdisable-tail-calls"); + +    RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args, +                               CmdArgs); + +    // Render ABI arguments +    switch (TC.getArch()) { +    default: break; +    case llvm::Triple::arm: +    case llvm::Triple::armeb: +    case llvm::Triple::thumbeb: +      RenderARMABI(Triple, Args, CmdArgs); +      break; +    case llvm::Triple::aarch64: +    case llvm::Triple::aarch64_be: +      RenderAArch64ABI(Triple, Args, CmdArgs); +      break; +    } + +    // Optimization level for CodeGen. +    if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { +      if (A->getOption().matches(options::OPT_O4)) { +        CmdArgs.push_back("-O3"); +        D.Diag(diag::warn_O4_is_O3); +      } else { +        A->render(Args, CmdArgs); +      } +    } + +    // Input/Output file. +    if (Output.getType() == types::TY_Dependencies) { +      // Handled with other dependency code. +    } else if (Output.isFilename()) { +      CmdArgs.push_back("-o"); +      CmdArgs.push_back(Output.getFilename()); +    } else { +      assert(Output.isNothing() && "Input output."); +    } + +    for (const auto &II : Inputs) { +      addDashXForInput(Args, II, CmdArgs); +      if (II.isFilename()) +        CmdArgs.push_back(II.getFilename()); +      else +        II.getInputArg().renderAsInput(Args, CmdArgs); +    } + +    C.addCommand(std::make_unique<Command>(JA, *this, D.getClangProgramPath(), +                                            CmdArgs, Inputs)); +    return; +  } + +  if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO()) +    CmdArgs.push_back("-fembed-bitcode=marker"); + +  // We normally speed up the clang process a bit by skipping destructors at +  // exit, but when we're generating diagnostics we can rely on some of the +  // cleanup. +  if (!C.isForDiagnostics()) +    CmdArgs.push_back("-disable-free"); + +#ifdef NDEBUG +  const bool IsAssertBuild = false; +#else +  const bool IsAssertBuild = true; +#endif + +  // Disable the verification pass in -asserts builds. +  if (!IsAssertBuild) +    CmdArgs.push_back("-disable-llvm-verifier"); + +  // Discard value names in assert builds unless otherwise specified. +  if (Args.hasFlag(options::OPT_fdiscard_value_names, +                   options::OPT_fno_discard_value_names, !IsAssertBuild)) +    CmdArgs.push_back("-discard-value-names"); + +  // Set the main file name, so that debug info works even with +  // -save-temps. +  CmdArgs.push_back("-main-file-name"); +  CmdArgs.push_back(getBaseInputName(Args, Input)); + +  // Some flags which affect the language (via preprocessor +  // defines). +  if (Args.hasArg(options::OPT_static)) +    CmdArgs.push_back("-static-define"); + +  if (Args.hasArg(options::OPT_municode)) +    CmdArgs.push_back("-DUNICODE"); + +  if (isa<AnalyzeJobAction>(JA)) +    RenderAnalyzerOptions(Args, CmdArgs, Triple, Input); + +  if (isa<AnalyzeJobAction>(JA) || +      (isa<PreprocessJobAction>(JA) && Args.hasArg(options::OPT__analyze))) +    CmdArgs.push_back("-setup-static-analyzer"); + +  // Enable compatilibily mode to avoid analyzer-config related errors. +  // Since we can't access frontend flags through hasArg, let's manually iterate +  // through them. +  bool FoundAnalyzerConfig = false; +  for (auto Arg : Args.filtered(options::OPT_Xclang)) +    if (StringRef(Arg->getValue()) == "-analyzer-config") { +      FoundAnalyzerConfig = true; +      break; +    } +  if (!FoundAnalyzerConfig) +    for (auto Arg : Args.filtered(options::OPT_Xanalyzer)) +      if (StringRef(Arg->getValue()) == "-analyzer-config") { +        FoundAnalyzerConfig = true; +        break; +      } +  if (FoundAnalyzerConfig) +    CmdArgs.push_back("-analyzer-config-compatibility-mode=true"); + +  CheckCodeGenerationOptions(D, Args); + +  unsigned FunctionAlignment = ParseFunctionAlignment(TC, Args); +  assert(FunctionAlignment <= 31 && "function alignment will be truncated!"); +  if (FunctionAlignment) { +    CmdArgs.push_back("-function-alignment"); +    CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment))); +  } + +  llvm::Reloc::Model RelocationModel; +  unsigned PICLevel; +  bool IsPIE; +  std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args); + +  const char *RMName = RelocationModelName(RelocationModel); + +  if ((RelocationModel == llvm::Reloc::ROPI || +       RelocationModel == llvm::Reloc::ROPI_RWPI) && +      types::isCXX(Input.getType()) && +      !Args.hasArg(options::OPT_fallow_unsupported)) +    D.Diag(diag::err_drv_ropi_incompatible_with_cxx); + +  if (RMName) { +    CmdArgs.push_back("-mrelocation-model"); +    CmdArgs.push_back(RMName); +  } +  if (PICLevel > 0) { +    CmdArgs.push_back("-pic-level"); +    CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); +    if (IsPIE) +      CmdArgs.push_back("-pic-is-pie"); +  } + +  if (RelocationModel == llvm::Reloc::ROPI || +      RelocationModel == llvm::Reloc::ROPI_RWPI) +    CmdArgs.push_back("-fropi"); +  if (RelocationModel == llvm::Reloc::RWPI || +      RelocationModel == llvm::Reloc::ROPI_RWPI) +    CmdArgs.push_back("-frwpi"); + +  if (Arg *A = Args.getLastArg(options::OPT_meabi)) { +    CmdArgs.push_back("-meabi"); +    CmdArgs.push_back(A->getValue()); +  } + +  CmdArgs.push_back("-mthread-model"); +  if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) { +    if (!TC.isThreadModelSupported(A->getValue())) +      D.Diag(diag::err_drv_invalid_thread_model_for_target) +          << A->getValue() << A->getAsString(Args); +    CmdArgs.push_back(A->getValue()); +  } +  else +    CmdArgs.push_back(Args.MakeArgString(TC.getThreadModel())); + +  Args.AddLastArg(CmdArgs, options::OPT_fveclib); + +  if (Args.hasFlag(options::OPT_fmerge_all_constants, +                   options::OPT_fno_merge_all_constants, false)) +    CmdArgs.push_back("-fmerge-all-constants"); + +  if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks, +                   options::OPT_fdelete_null_pointer_checks, false)) +    CmdArgs.push_back("-fno-delete-null-pointer-checks"); + +  // LLVM Code Generator Options. + +  if (Args.hasArg(options::OPT_frewrite_map_file) || +      Args.hasArg(options::OPT_frewrite_map_file_EQ)) { +    for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file, +                                      options::OPT_frewrite_map_file_EQ)) { +      StringRef Map = A->getValue(); +      if (!llvm::sys::fs::exists(Map)) { +        D.Diag(diag::err_drv_no_such_file) << Map; +      } else { +        CmdArgs.push_back("-frewrite-map-file"); +        CmdArgs.push_back(A->getValue()); +        A->claim(); +      } +    } +  } + +  if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { +    StringRef v = A->getValue(); +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v)); +    A->claim(); +  } + +  if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables, +                    true)) +    CmdArgs.push_back("-fno-jump-tables"); + +  if (Args.hasFlag(options::OPT_fprofile_sample_accurate, +                   options::OPT_fno_profile_sample_accurate, false)) +    CmdArgs.push_back("-fprofile-sample-accurate"); + +  if (!Args.hasFlag(options::OPT_fpreserve_as_comments, +                    options::OPT_fno_preserve_as_comments, true)) +    CmdArgs.push_back("-fno-preserve-as-comments"); + +  if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { +    CmdArgs.push_back("-mregparm"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, +                               options::OPT_freg_struct_return)) { +    if (TC.getArch() != llvm::Triple::x86) { +      D.Diag(diag::err_drv_unsupported_opt_for_target) +          << A->getSpelling() << RawTriple.str(); +    } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { +      CmdArgs.push_back("-fpcc-struct-return"); +    } else { +      assert(A->getOption().matches(options::OPT_freg_struct_return)); +      CmdArgs.push_back("-freg-struct-return"); +    } +  } + +  if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) +    CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + +  CodeGenOptions::FramePointerKind FPKeepKind = +                  getFramePointerKind(Args, RawTriple); +  const char *FPKeepKindStr = nullptr; +  switch (FPKeepKind) { +  case CodeGenOptions::FramePointerKind::None: +    FPKeepKindStr = "-mframe-pointer=none"; +    break; +  case CodeGenOptions::FramePointerKind::NonLeaf: +    FPKeepKindStr = "-mframe-pointer=non-leaf"; +    break; +  case CodeGenOptions::FramePointerKind::All: +    FPKeepKindStr = "-mframe-pointer=all"; +    break; +  } +  assert(FPKeepKindStr && "unknown FramePointerKind"); +  CmdArgs.push_back(FPKeepKindStr); + +  if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, +                    options::OPT_fno_zero_initialized_in_bss)) +    CmdArgs.push_back("-mno-zero-initialized-in-bss"); + +  bool OFastEnabled = isOptimizationLevelFast(Args); +  // If -Ofast is the optimization level, then -fstrict-aliasing should be +  // enabled.  This alias option is being used to simplify the hasFlag logic. +  OptSpecifier StrictAliasingAliasOption = +      OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing; +  // We turn strict aliasing off by default if we're in CL mode, since MSVC +  // doesn't do any TBAA. +  bool TBAAOnByDefault = !D.IsCLMode(); +  if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, +                    options::OPT_fno_strict_aliasing, TBAAOnByDefault)) +    CmdArgs.push_back("-relaxed-aliasing"); +  if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, +                    options::OPT_fno_struct_path_tbaa)) +    CmdArgs.push_back("-no-struct-path-tbaa"); +  if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, +                   false)) +    CmdArgs.push_back("-fstrict-enums"); +  if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, +                    true)) +    CmdArgs.push_back("-fno-strict-return"); +  if (Args.hasFlag(options::OPT_fallow_editor_placeholders, +                   options::OPT_fno_allow_editor_placeholders, false)) +    CmdArgs.push_back("-fallow-editor-placeholders"); +  if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, +                   options::OPT_fno_strict_vtable_pointers, +                   false)) +    CmdArgs.push_back("-fstrict-vtable-pointers"); +  if (Args.hasFlag(options::OPT_fforce_emit_vtables, +                   options::OPT_fno_force_emit_vtables, +                   false)) +    CmdArgs.push_back("-fforce-emit-vtables"); +  if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, +                    options::OPT_fno_optimize_sibling_calls)) +    CmdArgs.push_back("-mdisable-tail-calls"); +  if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls, +                   options::OPT_fescaping_block_tail_calls, false)) +    CmdArgs.push_back("-fno-escaping-block-tail-calls"); + +  Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, +                  options::OPT_fno_fine_grained_bitfield_accesses); + +  // Handle segmented stacks. +  if (Args.hasArg(options::OPT_fsplit_stack)) +    CmdArgs.push_back("-split-stacks"); + +  RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs); + +  if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) { +    if (TC.getArch() == llvm::Triple::x86 || +        TC.getArch() == llvm::Triple::x86_64) +      A->render(Args, CmdArgs); +    else if ((TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) && +             (A->getOption().getID() != options::OPT_mlong_double_80)) +      A->render(Args, CmdArgs); +    else +      D.Diag(diag::err_drv_unsupported_opt_for_target) +          << A->getAsString(Args) << TripleStr; +  } + +  // Decide whether to use verbose asm. Verbose assembly is the default on +  // toolchains which have the integrated assembler on by default. +  bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault(); +  if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, +                   IsIntegratedAssemblerDefault)) +    CmdArgs.push_back("-masm-verbose"); + +  if (!TC.useIntegratedAs()) +    CmdArgs.push_back("-no-integrated-as"); + +  if (Args.hasArg(options::OPT_fdebug_pass_structure)) { +    CmdArgs.push_back("-mdebug-pass"); +    CmdArgs.push_back("Structure"); +  } +  if (Args.hasArg(options::OPT_fdebug_pass_arguments)) { +    CmdArgs.push_back("-mdebug-pass"); +    CmdArgs.push_back("Arguments"); +  } + +  // Enable -mconstructor-aliases except on darwin, where we have to work around +  // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where +  // aliases aren't supported. +  if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) +    CmdArgs.push_back("-mconstructor-aliases"); + +  // Darwin's kernel doesn't support guard variables; just die if we +  // try to use them. +  if (KernelOrKext && RawTriple.isOSDarwin()) +    CmdArgs.push_back("-fforbid-guard-variables"); + +  if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, +                   false)) { +    CmdArgs.push_back("-mms-bitfields"); +  } + +  if (Args.hasFlag(options::OPT_mpie_copy_relocations, +                   options::OPT_mno_pie_copy_relocations, +                   false)) { +    CmdArgs.push_back("-mpie-copy-relocations"); +  } + +  if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) { +    CmdArgs.push_back("-fno-plt"); +  } + +  // -fhosted is default. +  // TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to +  // use Freestanding. +  bool Freestanding = +      Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || +      KernelOrKext; +  if (Freestanding) +    CmdArgs.push_back("-ffreestanding"); + +  // This is a coarse approximation of what llvm-gcc actually does, both +  // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more +  // complicated ways. +  bool AsynchronousUnwindTables = +      Args.hasFlag(options::OPT_fasynchronous_unwind_tables, +                   options::OPT_fno_asynchronous_unwind_tables, +                   (TC.IsUnwindTablesDefault(Args) || +                    TC.getSanitizerArgs().needsUnwindTables()) && +                       !Freestanding); +  if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, +                   AsynchronousUnwindTables)) +    CmdArgs.push_back("-munwind-tables"); + +  TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); + +  // FIXME: Handle -mtune=. +  (void)Args.hasArg(options::OPT_mtune_EQ); + +  if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { +    CmdArgs.push_back("-mcode-model"); +    CmdArgs.push_back(A->getValue()); +  } + +  // Add the target cpu +  std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); +  if (!CPU.empty()) { +    CmdArgs.push_back("-target-cpu"); +    CmdArgs.push_back(Args.MakeArgString(CPU)); +  } + +  RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs); + +  // These two are potentially updated by AddClangCLArgs. +  codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; +  bool EmitCodeView = false; + +  // Add clang-cl arguments. +  types::ID InputType = Input.getType(); +  if (D.IsCLMode()) +    AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + +  DwarfFissionKind DwarfFission; +  RenderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, IsWindowsMSVC, +                     CmdArgs, DebugInfoKind, DwarfFission); + +  // Add the split debug info name to the command lines here so we +  // can propagate it to the backend. +  bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) && +                    TC.getTriple().isOSBinFormatELF() && +                    (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || +                     isa<BackendJobAction>(JA)); +  if (SplitDWARF) { +    const char *SplitDWARFOut = SplitDebugName(Args, Input, Output); +    CmdArgs.push_back("-split-dwarf-file"); +    CmdArgs.push_back(SplitDWARFOut); +    if (DwarfFission == DwarfFissionKind::Split) { +      CmdArgs.push_back("-split-dwarf-output"); +      CmdArgs.push_back(SplitDWARFOut); +    } +  } + +  // Pass the linker version in use. +  if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { +    CmdArgs.push_back("-target-linker-version"); +    CmdArgs.push_back(A->getValue()); +  } + +  // Explicitly error on some things we know we don't support and can't just +  // ignore. +  if (!Args.hasArg(options::OPT_fallow_unsupported)) { +    Arg *Unsupported; +    if (types::isCXX(InputType) && RawTriple.isOSDarwin() && +        TC.getArch() == llvm::Triple::x86) { +      if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || +          (Unsupported = Args.getLastArg(options::OPT_mkernel))) +        D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) +            << Unsupported->getOption().getName(); +    } +    // The faltivec option has been superseded by the maltivec option. +    if ((Unsupported = Args.getLastArg(options::OPT_faltivec))) +      D.Diag(diag::err_drv_clang_unsupported_opt_faltivec) +          << Unsupported->getOption().getName() +          << "please use -maltivec and include altivec.h explicitly"; +    if ((Unsupported = Args.getLastArg(options::OPT_fno_altivec))) +      D.Diag(diag::err_drv_clang_unsupported_opt_faltivec) +          << Unsupported->getOption().getName() << "please use -mno-altivec"; +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_v); +  Args.AddLastArg(CmdArgs, options::OPT_H); +  if (D.CCPrintHeaders && !D.CCGenDiagnostics) { +    CmdArgs.push_back("-header-include-file"); +    CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename +                                               : "-"); +  } +  Args.AddLastArg(CmdArgs, options::OPT_P); +  Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); + +  if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { +    CmdArgs.push_back("-diagnostic-log-file"); +    CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename +                                                 : "-"); +  } + +  bool UseSeparateSections = isUseSeparateSections(Triple); + +  if (Args.hasFlag(options::OPT_ffunction_sections, +                   options::OPT_fno_function_sections, UseSeparateSections)) { +    CmdArgs.push_back("-ffunction-sections"); +  } + +  if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, +                   UseSeparateSections)) { +    CmdArgs.push_back("-fdata-sections"); +  } + +  if (!Args.hasFlag(options::OPT_funique_section_names, +                    options::OPT_fno_unique_section_names, true)) +    CmdArgs.push_back("-fno-unique-section-names"); + +  Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions, +                  options::OPT_finstrument_functions_after_inlining, +                  options::OPT_finstrument_function_entry_bare); + +  // NVPTX doesn't support PGO or coverage. There's no runtime support for +  // sampling, overhead of call arc collection is way too high and there's no +  // way to collect the output. +  if (!Triple.isNVPTX()) +    addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs); + +  Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); + +  // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled. +  if (RawTriple.isPS4CPU() && +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    PS4cpu::addProfileRTArgs(TC, Args, CmdArgs); +    PS4cpu::addSanitizerArgs(TC, CmdArgs); +  } + +  // Pass options for controlling the default header search paths. +  if (Args.hasArg(options::OPT_nostdinc)) { +    CmdArgs.push_back("-nostdsysteminc"); +    CmdArgs.push_back("-nobuiltininc"); +  } else { +    if (Args.hasArg(options::OPT_nostdlibinc)) +      CmdArgs.push_back("-nostdsysteminc"); +    Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); +    Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); +  } + +  // Pass the path to compiler resource files. +  CmdArgs.push_back("-resource-dir"); +  CmdArgs.push_back(D.ResourceDir.c_str()); + +  Args.AddLastArg(CmdArgs, options::OPT_working_directory); + +  RenderARCMigrateToolOptions(D, Args, CmdArgs); + +  // Add preprocessing options like -I, -D, etc. if we are using the +  // preprocessor. +  // +  // FIXME: Support -fpreprocessed +  if (types::getPreprocessedType(InputType) != types::TY_INVALID) +    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". +  // When building with ccache, it will pass -D options to clang even on +  // preprocessed inputs and configure concludes that -fPIC is not supported. +  Args.ClaimAllArgs(options::OPT_D); + +  // Manually translate -O4 to -O3; let clang reject others. +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { +    if (A->getOption().matches(options::OPT_O4)) { +      CmdArgs.push_back("-O3"); +      D.Diag(diag::warn_O4_is_O3); +    } else { +      A->render(Args, CmdArgs); +    } +  } + +  // Warn about ignored options to clang. +  for (const Arg *A : +       Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) { +    D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args); +    A->claim(); +  } + +  for (const Arg *A : +       Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) { +    D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args); +    A->claim(); +  } + +  claimNoWarnArgs(Args); + +  Args.AddAllArgs(CmdArgs, options::OPT_R_Group); + +  Args.AddAllArgs(CmdArgs, options::OPT_W_Group); +  if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) +    CmdArgs.push_back("-pedantic"); +  Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); +  Args.AddLastArg(CmdArgs, options::OPT_w); + +  // Fixed point flags +  if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point, +                   /*Default=*/false)) +    Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + +  // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} +  // (-ansi is equivalent to -std=c89 or -std=c++98). +  // +  // If a std is supplied, only add -trigraphs if it follows the +  // option. +  bool ImplyVCPPCXXVer = false; +  const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi); +  if (Std) { +    if (Std->getOption().matches(options::OPT_ansi)) +      if (types::isCXX(InputType)) +        CmdArgs.push_back("-std=c++98"); +      else +        CmdArgs.push_back("-std=c89"); +    else +      Std->render(Args, CmdArgs); + +    // If -f(no-)trigraphs appears after the language standard flag, honor it. +    if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi, +                                 options::OPT_ftrigraphs, +                                 options::OPT_fno_trigraphs)) +      if (A != Std) +        A->render(Args, CmdArgs); +  } else { +    // Honor -std-default. +    // +    // FIXME: Clang doesn't correctly handle -std= when the input language +    // doesn't match. For the time being just ignore this for C++ inputs; +    // eventually we want to do all the standard defaulting here instead of +    // splitting it between the driver and clang -cc1. +    if (!types::isCXX(InputType)) +      Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", +                                /*Joined=*/true); +    else if (IsWindowsMSVC) +      ImplyVCPPCXXVer = true; + +    Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, +                    options::OPT_fno_trigraphs); +  } + +  // GCC's behavior for -Wwrite-strings is a bit strange: +  //  * In C, this "warning flag" changes the types of string literals from +  //    'char[N]' to 'const char[N]', and thus triggers an unrelated warning +  //    for the discarded qualifier. +  //  * In C++, this is just a normal warning flag. +  // +  // Implementing this warning correctly in C is hard, so we follow GCC's +  // behavior for now. FIXME: Directly diagnose uses of a string literal as +  // a non-const char* in C, rather than using this crude hack. +  if (!types::isCXX(InputType)) { +    // FIXME: This should behave just like a warning flag, and thus should also +    // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on. +    Arg *WriteStrings = +        Args.getLastArg(options::OPT_Wwrite_strings, +                        options::OPT_Wno_write_strings, options::OPT_w); +    if (WriteStrings && +        WriteStrings->getOption().matches(options::OPT_Wwrite_strings)) +      CmdArgs.push_back("-fconst-strings"); +  } + +  // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active +  // during C++ compilation, which it is by default. GCC keeps this define even +  // in the presence of '-w', match this behavior bug-for-bug. +  if (types::isCXX(InputType) && +      Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated, +                   true)) { +    CmdArgs.push_back("-fdeprecated-macro"); +  } + +  // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. +  if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { +    if (Asm->getOption().matches(options::OPT_fasm)) +      CmdArgs.push_back("-fgnu-keywords"); +    else +      CmdArgs.push_back("-fno-gnu-keywords"); +  } + +  if (ShouldDisableDwarfDirectory(Args, TC)) +    CmdArgs.push_back("-fno-dwarf-directory-asm"); + +  if (ShouldDisableAutolink(Args, TC)) +    CmdArgs.push_back("-fno-autolink"); + +  // Add in -fdebug-compilation-dir if necessary. +  addDebugCompDirArg(Args, CmdArgs, D.getVFS()); + +  addDebugPrefixMapArg(D, Args, CmdArgs); + +  if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, +                               options::OPT_ftemplate_depth_EQ)) { +    CmdArgs.push_back("-ftemplate-depth"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { +    CmdArgs.push_back("-foperator-arrow-depth"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { +    CmdArgs.push_back("-fconstexpr-depth"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { +    CmdArgs.push_back("-fconstexpr-steps"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) +    CmdArgs.push_back("-fexperimental-new-constant-interpreter"); + +  if (Args.hasArg(options::OPT_fforce_experimental_new_constant_interpreter)) +    CmdArgs.push_back("-fforce-experimental-new-constant-interpreter"); + +  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()) { +      StringRef bytes = A->getValue(); +      CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes)); +    } else +      CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value +  } + +  if (Args.hasArg(options::OPT_relocatable_pch)) +    CmdArgs.push_back("-relocatable-pch"); + +  if (const Arg *A = Args.getLastArg(options::OPT_fcf_runtime_abi_EQ)) { +    static const char *kCFABIs[] = { +      "standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1", +    }; + +    if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs)) +      D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue(); +    else +      A->render(Args, CmdArgs); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { +    CmdArgs.push_back("-fconstant-string-class"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { +    CmdArgs.push_back("-ftabstop"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Args.hasFlag(options::OPT_fstack_size_section, +                   options::OPT_fno_stack_size_section, RawTriple.isPS4())) +    CmdArgs.push_back("-fstack-size-section"); + +  CmdArgs.push_back("-ferror-limit"); +  if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) +    CmdArgs.push_back(A->getValue()); +  else +    CmdArgs.push_back("19"); + +  if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { +    CmdArgs.push_back("-fmacro-backtrace-limit"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { +    CmdArgs.push_back("-ftemplate-backtrace-limit"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { +    CmdArgs.push_back("-fconstexpr-backtrace-limit"); +    CmdArgs.push_back(A->getValue()); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) { +    CmdArgs.push_back("-fspell-checking-limit"); +    CmdArgs.push_back(A->getValue()); +  } + +  // Pass -fmessage-length=. +  CmdArgs.push_back("-fmessage-length"); +  if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { +    CmdArgs.push_back(A->getValue()); +  } else { +    // If -fmessage-length=N was not specified, determine whether this is a +    // terminal and, if so, implicitly define -fmessage-length appropriately. +    unsigned N = llvm::sys::Process::StandardErrColumns(); +    CmdArgs.push_back(Args.MakeArgString(Twine(N))); +  } + +  // -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); +  Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden); + +  Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); + +  // Forward -f (flag) options which we can pass directly. +  Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); +  Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); +  Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs); +  Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); +  Args.AddLastArg(CmdArgs, options::OPT_femulated_tls, +                  options::OPT_fno_emulated_tls); +  Args.AddLastArg(CmdArgs, options::OPT_fkeep_static_consts); + +  // AltiVec-like language extensions aren't relevant for assembling. +  if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) +    Args.AddLastArg(CmdArgs, options::OPT_fzvector); + +  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); +  Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); + +  // Forward flags for OpenMP. We don't do this if the current action is an +  // device offloading action other than OpenMP. +  if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, +                   options::OPT_fno_openmp, false) && +      (JA.isDeviceOffloading(Action::OFK_None) || +       JA.isDeviceOffloading(Action::OFK_OpenMP))) { +    switch (D.getOpenMPRuntime(Args)) { +    case Driver::OMPRT_OMP: +    case Driver::OMPRT_IOMP5: +      // Clang can generate useful OpenMP code for these two runtime libraries. +      CmdArgs.push_back("-fopenmp"); + +      // If no option regarding the use of TLS in OpenMP codegeneration is +      // given, decide a default based on the target. Otherwise rely on the +      // options and pass the right information to the frontend. +      if (!Args.hasFlag(options::OPT_fopenmp_use_tls, +                        options::OPT_fnoopenmp_use_tls, /*Default=*/true)) +        CmdArgs.push_back("-fnoopenmp-use-tls"); +      Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, +                      options::OPT_fno_openmp_simd); +      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); +      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ); +      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ); +      Args.AddAllArgs(CmdArgs, +                      options::OPT_fopenmp_cuda_teams_reduction_recs_num_EQ); +      if (Args.hasFlag(options::OPT_fopenmp_optimistic_collapse, +                       options::OPT_fno_openmp_optimistic_collapse, +                       /*Default=*/false)) +        CmdArgs.push_back("-fopenmp-optimistic-collapse"); + +      // When in OpenMP offloading mode with NVPTX target, forward +      // cuda-mode flag +      if (Args.hasFlag(options::OPT_fopenmp_cuda_mode, +                       options::OPT_fno_openmp_cuda_mode, /*Default=*/false)) +        CmdArgs.push_back("-fopenmp-cuda-mode"); + +      // When in OpenMP offloading mode with NVPTX target, check if full runtime +      // is required. +      if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime, +                       options::OPT_fno_openmp_cuda_force_full_runtime, +                       /*Default=*/false)) +        CmdArgs.push_back("-fopenmp-cuda-force-full-runtime"); +      break; +    default: +      // By default, if Clang doesn't know how to generate useful OpenMP code +      // for a specific runtime library, we just don't pass the '-fopenmp' flag +      // down to the actual compilation. +      // FIXME: It would be better to have a mode which *only* omits IR +      // generation based on the OpenMP support so that we get consistent +      // semantic analysis, etc. +      break; +    } +  } else { +    Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, +                    options::OPT_fno_openmp_simd); +    Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); +  } + +  const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); +  Sanitize.addArgs(TC, Args, CmdArgs, InputType); + +  const XRayArgs &XRay = TC.getXRayArgs(); +  XRay.addArgs(TC, Args, CmdArgs, InputType); + +  if (TC.SupportsProfiling()) +    Args.AddLastArg(CmdArgs, options::OPT_pg); + +  if (TC.SupportsProfiling()) +    Args.AddLastArg(CmdArgs, options::OPT_mfentry); + +  if (Args.getLastArg(options::OPT_fapple_kext) || +      (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) +    CmdArgs.push_back("-fapple-kext"); + +  Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions_EQ); +  Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); +  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); +  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); +  Args.AddLastArg(CmdArgs, options::OPT_ftime_report); +  Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); +  Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); +  Args.AddLastArg(CmdArgs, options::OPT_ftrapv); +  Args.AddLastArg(CmdArgs, options::OPT_malign_double); + +  if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { +    CmdArgs.push_back("-ftrapv-handler"); +    CmdArgs.push_back(A->getValue()); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ); + +  // -fno-strict-overflow implies -fwrapv if it isn't disabled, but +  // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. +  if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) { +    if (A->getOption().matches(options::OPT_fwrapv)) +      CmdArgs.push_back("-fwrapv"); +  } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow, +                                      options::OPT_fno_strict_overflow)) { +    if (A->getOption().matches(options::OPT_fno_strict_overflow)) +      CmdArgs.push_back("-fwrapv"); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_freroll_loops, +                               options::OPT_fno_reroll_loops)) +    if (A->getOption().matches(options::OPT_freroll_loops)) +      CmdArgs.push_back("-freroll-loops"); + +  Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); +  Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, +                  options::OPT_fno_unroll_loops); + +  Args.AddLastArg(CmdArgs, options::OPT_pthread); + +  if (Args.hasFlag(options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening, +                   false)) +    CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening")); + +  RenderSSPOptions(TC, Args, CmdArgs, KernelOrKext); +  RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs); + +  // Translate -mstackrealign +  if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, +                   false)) +    CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); + +  if (Args.hasArg(options::OPT_mstack_alignment)) { +    StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); +    CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); +  } + +  if (Args.hasArg(options::OPT_mstack_probe_size)) { +    StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size); + +    if (!Size.empty()) +      CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size)); +    else +      CmdArgs.push_back("-mstack-probe-size=0"); +  } + +  if (!Args.hasFlag(options::OPT_mstack_arg_probe, +                    options::OPT_mno_stack_arg_probe, true)) +    CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe")); + +  if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, +                               options::OPT_mno_restrict_it)) { +    if (A->getOption().matches(options::OPT_mrestrict_it)) { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-arm-restrict-it"); +    } else { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-arm-no-restrict-it"); +    } +  } else if (Triple.isOSWindows() && +             (Triple.getArch() == llvm::Triple::arm || +              Triple.getArch() == llvm::Triple::thumb)) { +    // Windows on ARM expects restricted IT blocks +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-arm-restrict-it"); +  } + +  // Forward -cl options to -cc1 +  RenderOpenCLOptions(Args, CmdArgs); + +  if (Args.hasFlag(options::OPT_fhip_new_launch_api, +                   options::OPT_fno_hip_new_launch_api, false)) +    CmdArgs.push_back("-fhip-new-launch-api"); + +  if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); +  } + +  // Forward -f options with positive and negative forms; we translate +  // these by hand. +  if (Arg *A = getLastProfileSampleUseArg(Args)) { +    auto *PGOArg = Args.getLastArg( +        options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ, +        options::OPT_fcs_profile_generate, options::OPT_fcs_profile_generate_EQ, +        options::OPT_fprofile_use, options::OPT_fprofile_use_EQ); +    if (PGOArg) +      D.Diag(diag::err_drv_argument_not_allowed_with) +          << "SampleUse with PGO options"; + +    StringRef fname = A->getValue(); +    if (!llvm::sys::fs::exists(fname)) +      D.Diag(diag::err_drv_no_such_file) << fname; +    else +      A->render(Args, CmdArgs); +  } +  Args.AddLastArg(CmdArgs, options::OPT_fprofile_remapping_file_EQ); + +  RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs); + +  if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, +                    options::OPT_fno_assume_sane_operator_new)) +    CmdArgs.push_back("-fno-assume-sane-operator-new"); + +  // -fblocks=0 is default. +  if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, +                   TC.IsBlocksDefault()) || +      (Args.hasArg(options::OPT_fgnu_runtime) && +       Args.hasArg(options::OPT_fobjc_nonfragile_abi) && +       !Args.hasArg(options::OPT_fno_blocks))) { +    CmdArgs.push_back("-fblocks"); + +    if (!Args.hasArg(options::OPT_fgnu_runtime) && !TC.hasBlocksRuntime()) +      CmdArgs.push_back("-fblocks-runtime-optional"); +  } + +  // -fencode-extended-block-signature=1 is default. +  if (TC.IsEncodeExtendedBlockSignatureDefault()) +    CmdArgs.push_back("-fencode-extended-block-signature"); + +  if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, +                   false) && +      types::isCXX(InputType)) { +    CmdArgs.push_back("-fcoroutines-ts"); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes, +                  options::OPT_fno_double_square_bracket_attributes); + +  // -faccess-control is default. +  if (Args.hasFlag(options::OPT_fno_access_control, +                   options::OPT_faccess_control, false)) +    CmdArgs.push_back("-fno-access-control"); + +  // -felide-constructors is the default. +  if (Args.hasFlag(options::OPT_fno_elide_constructors, +                   options::OPT_felide_constructors, false)) +    CmdArgs.push_back("-fno-elide-constructors"); + +  ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); + +  if (KernelOrKext || (types::isCXX(InputType) && +                       (RTTIMode == ToolChain::RM_Disabled))) +    CmdArgs.push_back("-fno-rtti"); + +  // -fshort-enums=0 is default for all architectures except Hexagon. +  if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, +                   TC.getArch() == llvm::Triple::hexagon)) +    CmdArgs.push_back("-fshort-enums"); + +  RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs); + +  // -fuse-cxa-atexit is default. +  if (!Args.hasFlag( +          options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, +          !RawTriple.isOSWindows() && +              TC.getArch() != llvm::Triple::xcore && +              ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) || +               RawTriple.hasEnvironment())) || +      KernelOrKext) +    CmdArgs.push_back("-fno-use-cxa-atexit"); + +  if (Args.hasFlag(options::OPT_fregister_global_dtors_with_atexit, +                   options::OPT_fno_register_global_dtors_with_atexit, +                   RawTriple.isOSDarwin() && !KernelOrKext)) +    CmdArgs.push_back("-fregister-global-dtors-with-atexit"); + +  // -fms-extensions=0 is default. +  if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, +                   IsWindowsMSVC)) +    CmdArgs.push_back("-fms-extensions"); + +  // -fno-use-line-directives is default. +  if (Args.hasFlag(options::OPT_fuse_line_directives, +                   options::OPT_fno_use_line_directives, false)) +    CmdArgs.push_back("-fuse-line-directives"); + +  // -fms-compatibility=0 is default. +  bool IsMSVCCompat = Args.hasFlag( +      options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, +      (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions, +                                     options::OPT_fno_ms_extensions, true))); +  if (IsMSVCCompat) +    CmdArgs.push_back("-fms-compatibility"); + +  // Handle -fgcc-version, if present. +  VersionTuple GNUCVer; +  if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) { +    // Check that the version has 1 to 3 components and the minor and patch +    // versions fit in two decimal digits. +    StringRef Val = A->getValue(); +    Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable. +    bool Invalid = GNUCVer.tryParse(Val); +    unsigned Minor = GNUCVer.getMinor().getValueOr(0); +    unsigned Patch = GNUCVer.getSubminor().getValueOr(0); +    if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) { +      D.Diag(diag::err_drv_invalid_value) +          << A->getAsString(Args) << A->getValue(); +    } +  } else if (!IsMSVCCompat) { +    // Imitate GCC 4.2.1 by default if -fms-compatibility is not in effect. +    GNUCVer = VersionTuple(4, 2, 1); +  } +  if (!GNUCVer.empty()) { +    CmdArgs.push_back( +        Args.MakeArgString("-fgnuc-version=" + GNUCVer.getAsString())); +  } + +  VersionTuple MSVT = TC.computeMSVCVersion(&D, Args); +  if (!MSVT.empty()) +    CmdArgs.push_back( +        Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); + +  bool IsMSVC2015Compatible = MSVT.getMajor() >= 19; +  if (ImplyVCPPCXXVer) { +    StringRef LanguageStandard; +    if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) { +      Std = StdArg; +      LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue()) +                             .Case("c++14", "-std=c++14") +                             .Case("c++17", "-std=c++17") +                             .Case("c++latest", "-std=c++2a") +                             .Default(""); +      if (LanguageStandard.empty()) +        D.Diag(clang::diag::warn_drv_unused_argument) +            << StdArg->getAsString(Args); +    } + +    if (LanguageStandard.empty()) { +      if (IsMSVC2015Compatible) +        LanguageStandard = "-std=c++14"; +      else +        LanguageStandard = "-std=c++11"; +    } + +    CmdArgs.push_back(LanguageStandard.data()); +  } + +  // -fno-borland-extensions is default. +  if (Args.hasFlag(options::OPT_fborland_extensions, +                   options::OPT_fno_borland_extensions, false)) +    CmdArgs.push_back("-fborland-extensions"); + +  // -fno-declspec is default, except for PS4. +  if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, +                   RawTriple.isPS4())) +    CmdArgs.push_back("-fdeclspec"); +  else if (Args.hasArg(options::OPT_fno_declspec)) +    CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. + +  // -fthreadsafe-static is default, except for MSVC compatibility versions less +  // than 19. +  if (!Args.hasFlag(options::OPT_fthreadsafe_statics, +                    options::OPT_fno_threadsafe_statics, +                    !IsWindowsMSVC || IsMSVC2015Compatible)) +    CmdArgs.push_back("-fno-threadsafe-statics"); + +  // -fno-delayed-template-parsing is default, except when targeting MSVC. +  // Many old Windows SDK versions require this to parse. +  // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their +  // compiler. We should be able to disable this by default at some point. +  if (Args.hasFlag(options::OPT_fdelayed_template_parsing, +                   options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) +    CmdArgs.push_back("-fdelayed-template-parsing"); + +  // -fgnu-keywords default varies depending on language; only pass if +  // specified. +  Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords, +                  options::OPT_fno_gnu_keywords); + +  if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, +                   false)) +    CmdArgs.push_back("-fgnu89-inline"); + +  if (Args.hasArg(options::OPT_fno_inline)) +    CmdArgs.push_back("-fno-inline"); + +  Args.AddLastArg(CmdArgs, options::OPT_finline_functions, +                  options::OPT_finline_hint_functions, +                  options::OPT_fno_inline_functions); + +  // FIXME: Find a better way to determine whether the language has modules +  // support by default, or just assume that all languages do. +  bool HaveModules = +      Std && (Std->containsValue("c++2a") || Std->containsValue("c++latest")); +  RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules); + +  if (Args.hasFlag(options::OPT_fpch_validate_input_files_content, +                   options::OPT_fno_pch_validate_input_files_content, false)) +    CmdArgs.push_back("-fvalidate-ast-input-files-content"); + +  Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager, +                  options::OPT_fno_experimental_new_pass_manager); + +  ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); +  RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None, +                    Input, CmdArgs); + +  if (Args.hasFlag(options::OPT_fapplication_extension, +                   options::OPT_fno_application_extension, false)) +    CmdArgs.push_back("-fapplication-extension"); + +  // Handle GCC-style exception args. +  if (!C.getDriver().IsCLMode()) +    addExceptionArgs(Args, InputType, TC, KernelOrKext, Runtime, CmdArgs); + +  // Handle exception personalities +  Arg *A = Args.getLastArg( +      options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, +      options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions); +  if (A) { +    const Option &Opt = A->getOption(); +    if (Opt.matches(options::OPT_fsjlj_exceptions)) +      CmdArgs.push_back("-fsjlj-exceptions"); +    if (Opt.matches(options::OPT_fseh_exceptions)) +      CmdArgs.push_back("-fseh-exceptions"); +    if (Opt.matches(options::OPT_fdwarf_exceptions)) +      CmdArgs.push_back("-fdwarf-exceptions"); +    if (Opt.matches(options::OPT_fwasm_exceptions)) +      CmdArgs.push_back("-fwasm-exceptions"); +  } else { +    switch (TC.GetExceptionModel(Args)) { +    default: +      break; +    case llvm::ExceptionHandling::DwarfCFI: +      CmdArgs.push_back("-fdwarf-exceptions"); +      break; +    case llvm::ExceptionHandling::SjLj: +      CmdArgs.push_back("-fsjlj-exceptions"); +      break; +    case llvm::ExceptionHandling::WinEH: +      CmdArgs.push_back("-fseh-exceptions"); +      break; +    } +  } + +  // C++ "sane" operator new. +  if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, +                    options::OPT_fno_assume_sane_operator_new)) +    CmdArgs.push_back("-fno-assume-sane-operator-new"); + +  // -frelaxed-template-template-args is off by default, as it is a severe +  // breaking change until a corresponding change to template partial ordering +  // is provided. +  if (Args.hasFlag(options::OPT_frelaxed_template_template_args, +                   options::OPT_fno_relaxed_template_template_args, false)) +    CmdArgs.push_back("-frelaxed-template-template-args"); + +  // -fsized-deallocation is off by default, as it is an ABI-breaking change for +  // most platforms. +  if (Args.hasFlag(options::OPT_fsized_deallocation, +                   options::OPT_fno_sized_deallocation, false)) +    CmdArgs.push_back("-fsized-deallocation"); + +  // -faligned-allocation is on by default in C++17 onwards and otherwise off +  // by default. +  if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation, +                               options::OPT_fno_aligned_allocation, +                               options::OPT_faligned_new_EQ)) { +    if (A->getOption().matches(options::OPT_fno_aligned_allocation)) +      CmdArgs.push_back("-fno-aligned-allocation"); +    else +      CmdArgs.push_back("-faligned-allocation"); +  } + +  // The default new alignment can be specified using a dedicated option or via +  // a GCC-compatible option that also turns on aligned allocation. +  if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ, +                               options::OPT_faligned_new_EQ)) +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue())); + +  // -fconstant-cfstrings is default, and may be subject to argument translation +  // on Darwin. +  if (!Args.hasFlag(options::OPT_fconstant_cfstrings, +                    options::OPT_fno_constant_cfstrings) || +      !Args.hasFlag(options::OPT_mconstant_cfstrings, +                    options::OPT_mno_constant_cfstrings)) +    CmdArgs.push_back("-fno-constant-cfstrings"); + +  // -fno-pascal-strings is default, only pass non-default. +  if (Args.hasFlag(options::OPT_fpascal_strings, +                   options::OPT_fno_pascal_strings, false)) +    CmdArgs.push_back("-fpascal-strings"); + +  // Honor -fpack-struct= and -fpack-struct, if given. Note that +  // -fno-pack-struct doesn't apply to -fpack-struct=. +  if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { +    std::string PackStructStr = "-fpack-struct="; +    PackStructStr += A->getValue(); +    CmdArgs.push_back(Args.MakeArgString(PackStructStr)); +  } else if (Args.hasFlag(options::OPT_fpack_struct, +                          options::OPT_fno_pack_struct, false)) { +    CmdArgs.push_back("-fpack-struct=1"); +  } + +  // Handle -fmax-type-align=N and -fno-type-align +  bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align); +  if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) { +    if (!SkipMaxTypeAlign) { +      std::string MaxTypeAlignStr = "-fmax-type-align="; +      MaxTypeAlignStr += A->getValue(); +      CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); +    } +  } else if (RawTriple.isOSDarwin()) { +    if (!SkipMaxTypeAlign) { +      std::string MaxTypeAlignStr = "-fmax-type-align=16"; +      CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); +    } +  } + +  if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true)) +    CmdArgs.push_back("-Qn"); + +  // -fcommon is the default unless compiling kernel code or the target says so +  bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple); +  if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, +                    !NoCommonDefault)) +    CmdArgs.push_back("-fno-common"); + +  // -fsigned-bitfields is default, and clang doesn't yet support +  // -funsigned-bitfields. +  if (!Args.hasFlag(options::OPT_fsigned_bitfields, +                    options::OPT_funsigned_bitfields)) +    D.Diag(diag::warn_drv_clang_unsupported) +        << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); + +  // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. +  if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) +    D.Diag(diag::err_drv_clang_unsupported) +        << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); + +  // -finput_charset=UTF-8 is default. Reject others +  if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) { +    StringRef value = inputCharset->getValue(); +    if (!value.equals_lower("utf-8")) +      D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) +                                          << value; +  } + +  // -fexec_charset=UTF-8 is default. Reject others +  if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) { +    StringRef value = execCharset->getValue(); +    if (!value.equals_lower("utf-8")) +      D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args) +                                          << value; +  } + +  RenderDiagnosticsOptions(D, Args, CmdArgs); + +  // -fno-asm-blocks is default. +  if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, +                   false)) +    CmdArgs.push_back("-fasm-blocks"); + +  // -fgnu-inline-asm is default. +  if (!Args.hasFlag(options::OPT_fgnu_inline_asm, +                    options::OPT_fno_gnu_inline_asm, true)) +    CmdArgs.push_back("-fno-gnu-inline-asm"); + +  // Enable vectorization per default according to the optimization level +  // selected. For optimization levels that want vectorization we use the alias +  // option to simplify the hasFlag logic. +  bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false); +  OptSpecifier VectorizeAliasOption = +      EnableVec ? options::OPT_O_Group : options::OPT_fvectorize; +  if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, +                   options::OPT_fno_vectorize, EnableVec)) +    CmdArgs.push_back("-vectorize-loops"); + +  // -fslp-vectorize is enabled based on the optimization level selected. +  bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true); +  OptSpecifier SLPVectAliasOption = +      EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize; +  if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption, +                   options::OPT_fno_slp_vectorize, EnableSLPVec)) +    CmdArgs.push_back("-vectorize-slp"); + +  ParseMPreferVectorWidth(D, Args, CmdArgs); + +  Args.AddLastArg(CmdArgs, options::OPT_fshow_overloads_EQ); +  Args.AddLastArg(CmdArgs, +                  options::OPT_fsanitize_undefined_strip_path_components_EQ); + +  // -fdollars-in-identifiers default varies depending on platform and +  // language; only pass if specified. +  if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, +                               options::OPT_fno_dollars_in_identifiers)) { +    if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) +      CmdArgs.push_back("-fdollars-in-identifiers"); +    else +      CmdArgs.push_back("-fno-dollars-in-identifiers"); +  } + +  // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for +  // practical purposes. +  if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, +                               options::OPT_fno_unit_at_a_time)) { +    if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) +      D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); +  } + +  if (Args.hasFlag(options::OPT_fapple_pragma_pack, +                   options::OPT_fno_apple_pragma_pack, false)) +    CmdArgs.push_back("-fapple-pragma-pack"); + +  // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. +  if (Args.hasFlag(options::OPT_fsave_optimization_record, +                   options::OPT_foptimization_record_file_EQ, +                   options::OPT_fno_save_optimization_record, false) || +      Args.hasFlag(options::OPT_fsave_optimization_record_EQ, +                   options::OPT_fno_save_optimization_record, false) || +      Args.hasFlag(options::OPT_foptimization_record_passes_EQ, +                   options::OPT_fno_save_optimization_record, false)) { +    CmdArgs.push_back("-opt-record-file"); + +    const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); +    if (A) { +      CmdArgs.push_back(A->getValue()); +    } else { +      SmallString<128> F; + +      if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { +        if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) +          F = FinalOutput->getValue(); +      } + +      if (F.empty()) { +        // Use the input filename. +        F = llvm::sys::path::stem(Input.getBaseInput()); + +        // If we're compiling for an offload architecture (i.e. a CUDA device), +        // we need to make the file name for the device compilation different +        // from the host compilation. +        if (!JA.isDeviceOffloading(Action::OFK_None) && +            !JA.isDeviceOffloading(Action::OFK_Host)) { +          llvm::sys::path::replace_extension(F, ""); +          F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), +                                                   Triple.normalize()); +          F += "-"; +          F += JA.getOffloadingArch(); +        } +      } + +      std::string Extension = "opt."; +      if (const Arg *A = +              Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) +        Extension += A->getValue(); +      else +        Extension += "yaml"; + +      llvm::sys::path::replace_extension(F, Extension); +      CmdArgs.push_back(Args.MakeArgString(F)); +    } + +    if (const Arg *A = +            Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { +      CmdArgs.push_back("-opt-record-passes"); +      CmdArgs.push_back(A->getValue()); +    } + +    if (const Arg *A = +            Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { +      CmdArgs.push_back("-opt-record-format"); +      CmdArgs.push_back(A->getValue()); +    } +  } + +  bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports, +                                     options::OPT_fno_rewrite_imports, false); +  if (RewriteImports) +    CmdArgs.push_back("-frewrite-imports"); + +  // Enable rewrite includes if the user's asked for it or if we're generating +  // diagnostics. +  // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be +  // nice to enable this when doing a crashdump for modules as well. +  if (Args.hasFlag(options::OPT_frewrite_includes, +                   options::OPT_fno_rewrite_includes, false) || +      (C.isForDiagnostics() && !HaveModules)) +    CmdArgs.push_back("-frewrite-includes"); + +  // Only allow -traditional or -traditional-cpp outside in preprocessing modes. +  if (Arg *A = Args.getLastArg(options::OPT_traditional, +                               options::OPT_traditional_cpp)) { +    if (isa<PreprocessJobAction>(JA)) +      CmdArgs.push_back("-traditional-cpp"); +    else +      D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_dM); +  Args.AddLastArg(CmdArgs, options::OPT_dD); + +  // Handle serialized diagnostics. +  if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) { +    CmdArgs.push_back("-serialize-diagnostic-file"); +    CmdArgs.push_back(Args.MakeArgString(A->getValue())); +  } + +  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 -fparse-all-comments to -cc1. +  Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); + +  // Turn -fplugin=name.so into -load name.so +  for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) { +    CmdArgs.push_back("-load"); +    CmdArgs.push_back(A->getValue()); +    A->claim(); +  } + +  // Forward -fpass-plugin=name.so to -cc1. +  for (const Arg *A : Args.filtered(options::OPT_fpass_plugin_EQ)) { +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-fpass-plugin=") + A->getValue())); +    A->claim(); +  } + +  // Setup statistics file output. +  SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); +  if (!StatsFile.empty()) +    CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile)); + +  // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option +  // parser. +  // -finclude-default-header flag is for preprocessor, +  // do not pass it to other cc1 commands when save-temps is enabled +  if (C.getDriver().isSaveTempsEnabled() && +      !isa<PreprocessJobAction>(JA)) { +    for (auto Arg : Args.filtered(options::OPT_Xclang)) { +      Arg->claim(); +      if (StringRef(Arg->getValue()) != "-finclude-default-header") +        CmdArgs.push_back(Arg->getValue()); +    } +  } +  else { +    Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); +  } +  for (const Arg *A : Args.filtered(options::OPT_mllvm)) { +    A->claim(); + +    // We translate this by hand to the -cc1 argument, since nightly test uses +    // it and developers have been trained to spell it with -mllvm. Both +    // spellings are now deprecated and should be removed. +    if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") { +      CmdArgs.push_back("-disable-llvm-optzns"); +    } else { +      A->render(Args, CmdArgs); +    } +  } + +  // With -save-temps, we want to save the unoptimized bitcode output from the +  // CompileJobAction, use -disable-llvm-passes to get pristine IR generated +  // by the frontend. +  // When -fembed-bitcode is enabled, optimized bitcode is emitted because it +  // has slightly different breakdown between stages. +  // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of +  // pristine IR generated by the frontend. Ideally, a new compile action should +  // be added so both IR can be captured. +  if (C.getDriver().isSaveTempsEnabled() && +      !(C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO()) && +      isa<CompileJobAction>(JA)) +    CmdArgs.push_back("-disable-llvm-passes"); + +  Args.AddAllArgs(CmdArgs, options::OPT_undef); + +  const char *Exec = D.getClangProgramPath(); + +  // Optionally embed the -cc1 level arguments into the debug info or a +  // section, for build analysis. +  // Also record command line arguments into the debug info if +  // -grecord-gcc-switches options is set on. +  // By default, -gno-record-gcc-switches is set on and no recording. +  auto GRecordSwitches = +      Args.hasFlag(options::OPT_grecord_command_line, +                   options::OPT_gno_record_command_line, false); +  auto FRecordSwitches = +      Args.hasFlag(options::OPT_frecord_command_line, +                   options::OPT_fno_record_command_line, false); +  if (FRecordSwitches && !Triple.isOSBinFormatELF()) +    D.Diag(diag::err_drv_unsupported_opt_for_target) +        << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args) +        << TripleStr; +  if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) { +    ArgStringList OriginalArgs; +    for (const auto &Arg : Args) +      Arg->render(Args, OriginalArgs); + +    SmallString<256> Flags; +    Flags += Exec; +    for (const char *OriginalArg : OriginalArgs) { +      SmallString<128> EscapedArg; +      EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); +      Flags += " "; +      Flags += EscapedArg; +    } +    auto FlagsArgString = Args.MakeArgString(Flags); +    if (TC.UseDwarfDebugFlags() || GRecordSwitches) { +      CmdArgs.push_back("-dwarf-debug-flags"); +      CmdArgs.push_back(FlagsArgString); +    } +    if (FRecordSwitches) { +      CmdArgs.push_back("-record-command-line"); +      CmdArgs.push_back(FlagsArgString); +    } +  } + +  // Host-side cuda compilation receives all device-side outputs in a single +  // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary. +  if ((IsCuda || IsHIP) && CudaDeviceInput) { +      CmdArgs.push_back("-fcuda-include-gpubinary"); +      CmdArgs.push_back(CudaDeviceInput->getFilename()); +      if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) +        CmdArgs.push_back("-fgpu-rdc"); +  } + +  if (IsCuda) { +    if (Args.hasFlag(options::OPT_fcuda_short_ptr, +                     options::OPT_fno_cuda_short_ptr, false)) +      CmdArgs.push_back("-fcuda-short-ptr"); +  } + +  // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path +  // to specify the result of the compile phase on the host, so the meaningful +  // device declarations can be identified. Also, -fopenmp-is-device is passed +  // along to tell the frontend that it is generating code for a device, so that +  // only the relevant declarations are emitted. +  if (IsOpenMPDevice) { +    CmdArgs.push_back("-fopenmp-is-device"); +    if (OpenMPDeviceInput) { +      CmdArgs.push_back("-fopenmp-host-ir-file-path"); +      CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename())); +    } +  } + +  // For all the host OpenMP offloading compile jobs we need to pass the targets +  // information using -fopenmp-targets= option. +  if (JA.isHostOffloading(Action::OFK_OpenMP)) { +    SmallString<128> TargetInfo("-fopenmp-targets="); + +    Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); +    assert(Tgts && Tgts->getNumValues() && +           "OpenMP offloading has to have targets specified."); +    for (unsigned i = 0; i < Tgts->getNumValues(); ++i) { +      if (i) +        TargetInfo += ','; +      // We need to get the string from the triple because it may be not exactly +      // the same as the one we get directly from the arguments. +      llvm::Triple T(Tgts->getValue(i)); +      TargetInfo += T.getTriple(); +    } +    CmdArgs.push_back(Args.MakeArgString(TargetInfo.str())); +  } + +  bool VirtualFunctionElimination = +      Args.hasFlag(options::OPT_fvirtual_function_elimination, +                   options::OPT_fno_virtual_function_elimination, false); +  if (VirtualFunctionElimination) { +    // VFE requires full LTO (currently, this might be relaxed to allow ThinLTO +    // in the future). +    if (D.getLTOMode() != LTOK_Full) +      D.Diag(diag::err_drv_argument_only_allowed_with) +          << "-fvirtual-function-elimination" +          << "-flto=full"; + +    CmdArgs.push_back("-fvirtual-function-elimination"); +  } + +  // VFE requires whole-program-vtables, and enables it by default. +  bool WholeProgramVTables = Args.hasFlag( +      options::OPT_fwhole_program_vtables, +      options::OPT_fno_whole_program_vtables, VirtualFunctionElimination); +  if (VirtualFunctionElimination && !WholeProgramVTables) { +    D.Diag(diag::err_drv_argument_not_allowed_with) +        << "-fno-whole-program-vtables" +        << "-fvirtual-function-elimination"; +  } + +  if (WholeProgramVTables) { +    if (!D.isUsingLTO()) +      D.Diag(diag::err_drv_argument_only_allowed_with) +          << "-fwhole-program-vtables" +          << "-flto"; +    CmdArgs.push_back("-fwhole-program-vtables"); +  } + +  bool DefaultsSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO(); +  bool SplitLTOUnit = +      Args.hasFlag(options::OPT_fsplit_lto_unit, +                   options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit); +  if (Sanitize.needsLTO() && !SplitLTOUnit) +    D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit" +                                                    << "-fsanitize=cfi"; +  if (SplitLTOUnit) +    CmdArgs.push_back("-fsplit-lto-unit"); + +  if (Arg *A = Args.getLastArg(options::OPT_fexperimental_isel, +                               options::OPT_fno_experimental_isel)) { +    CmdArgs.push_back("-mllvm"); +    if (A->getOption().matches(options::OPT_fexperimental_isel)) { +      CmdArgs.push_back("-global-isel=1"); + +      // GISel is on by default on AArch64 -O0, so don't bother adding +      // the fallback remarks for it. Other combinations will add a warning of +      // some kind. +      bool IsArchSupported = Triple.getArch() == llvm::Triple::aarch64; +      bool IsOptLevelSupported = false; + +      Arg *A = Args.getLastArg(options::OPT_O_Group); +      if (Triple.getArch() == llvm::Triple::aarch64) { +        if (!A || A->getOption().matches(options::OPT_O0)) +          IsOptLevelSupported = true; +      } +      if (!IsArchSupported || !IsOptLevelSupported) { +        CmdArgs.push_back("-mllvm"); +        CmdArgs.push_back("-global-isel-abort=2"); + +        if (!IsArchSupported) +          D.Diag(diag::warn_drv_experimental_isel_incomplete) << Triple.getArchName(); +        else +          D.Diag(diag::warn_drv_experimental_isel_incomplete_opt); +      } +    } else { +      CmdArgs.push_back("-global-isel=0"); +    } +  } + +  if (Args.hasArg(options::OPT_forder_file_instrumentation)) { +     CmdArgs.push_back("-forder-file-instrumentation"); +     // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is +     // on, we need to pass these flags as linker flags and that will be handled +     // outside of the compiler. +     if (!D.isUsingLTO()) { +       CmdArgs.push_back("-mllvm"); +       CmdArgs.push_back("-enable-order-file-instrumentation"); +     } +  } + +  if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128, +                               options::OPT_fno_force_enable_int128)) { +    if (A->getOption().matches(options::OPT_fforce_enable_int128)) +      CmdArgs.push_back("-fforce-enable-int128"); +  } + +  if (Args.hasFlag(options::OPT_fcomplete_member_pointers, +                   options::OPT_fno_complete_member_pointers, false)) +    CmdArgs.push_back("-fcomplete-member-pointers"); + +  if (!Args.hasFlag(options::OPT_fcxx_static_destructors, +                    options::OPT_fno_cxx_static_destructors, true)) +    CmdArgs.push_back("-fno-c++-static-destructors"); + +  if (Arg *A = Args.getLastArg(options::OPT_moutline, +                               options::OPT_mno_outline)) { +    if (A->getOption().matches(options::OPT_moutline)) { +      // We only support -moutline in AArch64 right now. If we're not compiling +      // for AArch64, emit a warning and ignore the flag. Otherwise, add the +      // proper mllvm flags. +      if (Triple.getArch() != llvm::Triple::aarch64) { +        D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); +      } else { +          CmdArgs.push_back("-mllvm"); +          CmdArgs.push_back("-enable-machine-outliner"); +      } +    } else { +      // Disable all outlining behaviour. +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-enable-machine-outliner=never"); +    } +  } + +  if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig, +                   (TC.getTriple().isOSBinFormatELF() || +                    TC.getTriple().isOSBinFormatCOFF()) && +                      !TC.getTriple().isPS4() && +                      !TC.getTriple().isOSNetBSD() && +                      !Distro(D.getVFS()).IsGentoo() && +                      !TC.getTriple().isAndroid() && +                       TC.useIntegratedAs())) +    CmdArgs.push_back("-faddrsig"); + +  if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) { +    std::string Str = A->getAsString(Args); +    if (!TC.getTriple().isOSBinFormatELF()) +      D.Diag(diag::err_drv_unsupported_opt_for_target) +          << Str << TC.getTripleString(); +    CmdArgs.push_back(Args.MakeArgString(Str)); +  } + +  // Add the "-o out -x type src.c" flags last. This is done primarily to make +  // the -cc1 command easier to edit when reproducing compiler crashes. +  if (Output.getType() == types::TY_Dependencies) { +    // Handled with other dependency code. +  } else if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  addDashXForInput(Args, Input, CmdArgs); + +  ArrayRef<InputInfo> FrontendInputs = Input; +  if (IsHeaderModulePrecompile) +    FrontendInputs = ModuleHeaderInputs; +  else if (Input.isNothing()) +    FrontendInputs = {}; + +  for (const InputInfo &Input : FrontendInputs) { +    if (Input.isFilename()) +      CmdArgs.push_back(Input.getFilename()); +    else +      Input.getInputArg().renderAsInput(Args, CmdArgs); +  } + +  // Finally add the compile command to the compilation. +  if (Args.hasArg(options::OPT__SLASH_fallback) && +      Output.getType() == types::TY_Object && +      (InputType == types::TY_C || InputType == types::TY_CXX)) { +    auto CLCommand = +        getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); +    C.addCommand(std::make_unique<FallbackCommand>( +        JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand))); +  } else if (Args.hasArg(options::OPT__SLASH_fallback) && +             isa<PrecompileJobAction>(JA)) { +    // In /fallback builds, run the main compilation even if the pch generation +    // fails, so that the main compilation's fallback to cl.exe runs. +    C.addCommand(std::make_unique<ForceSuccessCommand>(JA, *this, Exec, +                                                        CmdArgs, Inputs)); +  } else { +    C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +  } + +  // Make the compile command echo its inputs for /showFilenames. +  if (Output.getType() == types::TY_Object && +      Args.hasFlag(options::OPT__SLASH_showFilenames, +                   options::OPT__SLASH_showFilenames_, false)) { +    C.getJobs().getJobs().back()->setPrintInputFilenames(true); +  } + +  if (Arg *A = Args.getLastArg(options::OPT_pg)) +    if (FPKeepKind == CodeGenOptions::FramePointerKind::None) +      D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" +                                                      << A->getAsString(Args); + +  // Claim some arguments which clang supports automatically. + +  // -fpch-preprocess is used with gcc to add a special marker in the output to +  // include the PCH file. +  Args.ClaimAllArgs(options::OPT_fpch_preprocess); + +  // Claim some arguments which clang doesn't support, but we don't +  // care to warn the user about. +  Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); +  Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); + +  // Disable warnings for clang -E -emit-llvm foo.c +  Args.ClaimAllArgs(options::OPT_emit_llvm); +} + +Clang::Clang(const ToolChain &TC) +    // CAUTION! The first constructor argument ("clang") is not arbitrary, +    // as it is for other tools. Some operations on a Tool actually test +    // whether that tool is Clang based on the Tool's Name as a string. +    : Tool("clang", "clang frontend", TC, RF_Full) {} + +Clang::~Clang() {} + +/// Add options related to the Objective-C runtime/ABI. +/// +/// Returns true if the runtime is non-fragile. +ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, +                                      ArgStringList &cmdArgs, +                                      RewriteKind rewriteKind) const { +  // Look for the controlling runtime option. +  Arg *runtimeArg = +      args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, +                      options::OPT_fobjc_runtime_EQ); + +  // Just forward -fobjc-runtime= to the frontend.  This supercedes +  // options about fragility. +  if (runtimeArg && +      runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) { +    ObjCRuntime runtime; +    StringRef value = runtimeArg->getValue(); +    if (runtime.tryParse(value)) { +      getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) +          << value; +    } +    if ((runtime.getKind() == ObjCRuntime::GNUstep) && +        (runtime.getVersion() >= VersionTuple(2, 0))) +      if (!getToolChain().getTriple().isOSBinFormatELF() && +          !getToolChain().getTriple().isOSBinFormatCOFF()) { +        getToolChain().getDriver().Diag( +            diag::err_drv_gnustep_objc_runtime_incompatible_binary) +          << runtime.getVersion().getMajor(); +      } + +    runtimeArg->render(args, cmdArgs); +    return runtime; +  } + +  // Otherwise, we'll need the ABI "version".  Version numbers are +  // slightly confusing for historical reasons: +  //   1 - Traditional "fragile" ABI +  //   2 - Non-fragile ABI, version 1 +  //   3 - Non-fragile ABI, version 2 +  unsigned objcABIVersion = 1; +  // If -fobjc-abi-version= is present, use that to set the version. +  if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { +    StringRef value = abiArg->getValue(); +    if (value == "1") +      objcABIVersion = 1; +    else if (value == "2") +      objcABIVersion = 2; +    else if (value == "3") +      objcABIVersion = 3; +    else +      getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value; +  } else { +    // Otherwise, determine if we are using the non-fragile ABI. +    bool nonFragileABIIsDefault = +        (rewriteKind == RK_NonFragile || +         (rewriteKind == RK_None && +          getToolChain().IsObjCNonFragileABIDefault())); +    if (args.hasFlag(options::OPT_fobjc_nonfragile_abi, +                     options::OPT_fno_objc_nonfragile_abi, +                     nonFragileABIIsDefault)) { +// Determine the non-fragile ABI version to use. +#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO +      unsigned nonFragileABIVersion = 1; +#else +      unsigned nonFragileABIVersion = 2; +#endif + +      if (Arg *abiArg = +              args.getLastArg(options::OPT_fobjc_nonfragile_abi_version_EQ)) { +        StringRef value = abiArg->getValue(); +        if (value == "1") +          nonFragileABIVersion = 1; +        else if (value == "2") +          nonFragileABIVersion = 2; +        else +          getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) +              << value; +      } + +      objcABIVersion = 1 + nonFragileABIVersion; +    } else { +      objcABIVersion = 1; +    } +  } + +  // We don't actually care about the ABI version other than whether +  // it's non-fragile. +  bool isNonFragile = objcABIVersion != 1; + +  // If we have no runtime argument, ask the toolchain for its default runtime. +  // However, the rewriter only really supports the Mac runtime, so assume that. +  ObjCRuntime runtime; +  if (!runtimeArg) { +    switch (rewriteKind) { +    case RK_None: +      runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); +      break; +    case RK_Fragile: +      runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple()); +      break; +    case RK_NonFragile: +      runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); +      break; +    } + +    // -fnext-runtime +  } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) { +    // On Darwin, make this use the default behavior for the toolchain. +    if (getToolChain().getTriple().isOSDarwin()) { +      runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); + +      // Otherwise, build for a generic macosx port. +    } else { +      runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); +    } + +    // -fgnu-runtime +  } else { +    assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime)); +    // Legacy behaviour is to target the gnustep runtime if we are in +    // non-fragile mode or the GCC runtime in fragile mode. +    if (isNonFragile) +      runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(2, 0)); +    else +      runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); +  } + +  cmdArgs.push_back( +      args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); +  return runtime; +} + +static bool maybeConsumeDash(const std::string &EH, size_t &I) { +  bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-'); +  I += HaveDash; +  return !HaveDash; +} + +namespace { +struct EHFlags { +  bool Synch = false; +  bool Asynch = false; +  bool NoUnwindC = false; +}; +} // end anonymous namespace + +/// /EH controls whether to run destructor cleanups when exceptions are +/// thrown.  There are three modifiers: +/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions. +/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions. +///      The 'a' modifier is unimplemented and fundamentally hard in LLVM IR. +/// - c: Assume that extern "C" functions are implicitly nounwind. +/// The default is /EHs-c-, meaning cleanups are disabled. +static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { +  EHFlags EH; + +  std::vector<std::string> EHArgs = +      Args.getAllArgValues(options::OPT__SLASH_EH); +  for (auto EHVal : EHArgs) { +    for (size_t I = 0, E = EHVal.size(); I != E; ++I) { +      switch (EHVal[I]) { +      case 'a': +        EH.Asynch = maybeConsumeDash(EHVal, I); +        if (EH.Asynch) +          EH.Synch = false; +        continue; +      case 'c': +        EH.NoUnwindC = maybeConsumeDash(EHVal, I); +        continue; +      case 's': +        EH.Synch = maybeConsumeDash(EHVal, I); +        if (EH.Synch) +          EH.Asynch = false; +        continue; +      default: +        break; +      } +      D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal; +      break; +    } +  } +  // The /GX, /GX- flags are only processed if there are not /EH flags. +  // The default is that /GX is not specified. +  if (EHArgs.empty() && +      Args.hasFlag(options::OPT__SLASH_GX, options::OPT__SLASH_GX_, +                   /*Default=*/false)) { +    EH.Synch = true; +    EH.NoUnwindC = true; +  } + +  return EH; +} + +void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, +                           ArgStringList &CmdArgs, +                           codegenoptions::DebugInfoKind *DebugInfoKind, +                           bool *EmitCodeView) const { +  unsigned RTOptionID = options::OPT__SLASH_MT; + +  if (Args.hasArg(options::OPT__SLASH_LDd)) +    // The /LDd option implies /MTd. The dependent lib part can be overridden, +    // but defining _DEBUG is sticky. +    RTOptionID = options::OPT__SLASH_MTd; + +  if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) +    RTOptionID = A->getOption().getID(); + +  StringRef FlagForCRT; +  switch (RTOptionID) { +  case options::OPT__SLASH_MD: +    if (Args.hasArg(options::OPT__SLASH_LDd)) +      CmdArgs.push_back("-D_DEBUG"); +    CmdArgs.push_back("-D_MT"); +    CmdArgs.push_back("-D_DLL"); +    FlagForCRT = "--dependent-lib=msvcrt"; +    break; +  case options::OPT__SLASH_MDd: +    CmdArgs.push_back("-D_DEBUG"); +    CmdArgs.push_back("-D_MT"); +    CmdArgs.push_back("-D_DLL"); +    FlagForCRT = "--dependent-lib=msvcrtd"; +    break; +  case options::OPT__SLASH_MT: +    if (Args.hasArg(options::OPT__SLASH_LDd)) +      CmdArgs.push_back("-D_DEBUG"); +    CmdArgs.push_back("-D_MT"); +    CmdArgs.push_back("-flto-visibility-public-std"); +    FlagForCRT = "--dependent-lib=libcmt"; +    break; +  case options::OPT__SLASH_MTd: +    CmdArgs.push_back("-D_DEBUG"); +    CmdArgs.push_back("-D_MT"); +    CmdArgs.push_back("-flto-visibility-public-std"); +    FlagForCRT = "--dependent-lib=libcmtd"; +    break; +  default: +    llvm_unreachable("Unexpected option ID."); +  } + +  if (Args.hasArg(options::OPT__SLASH_Zl)) { +    CmdArgs.push_back("-D_VC_NODEFAULTLIB"); +  } else { +    CmdArgs.push_back(FlagForCRT.data()); + +    // This provides POSIX compatibility (maps 'open' to '_open'), which most +    // users want.  The /Za flag to cl.exe turns this off, but it's not +    // implemented in clang. +    CmdArgs.push_back("--dependent-lib=oldnames"); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_show_includes); + +  // This controls whether or not we emit RTTI data for polymorphic types. +  if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, +                   /*Default=*/false)) +    CmdArgs.push_back("-fno-rtti-data"); + +  // This controls whether or not we emit stack-protector instrumentation. +  // In MSVC, Buffer Security Check (/GS) is on by default. +  if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_, +                   /*Default=*/true)) { +    CmdArgs.push_back("-stack-protector"); +    CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong))); +  } + +  // Emit CodeView if -Z7, -Zd, or -gline-tables-only are present. +  if (Arg *DebugInfoArg = +          Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd, +                          options::OPT_gline_tables_only)) { +    *EmitCodeView = true; +    if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) +      *DebugInfoKind = codegenoptions::LimitedDebugInfo; +    else +      *DebugInfoKind = codegenoptions::DebugLineTablesOnly; +  } else { +    *EmitCodeView = false; +  } + +  const Driver &D = getToolChain().getDriver(); +  EHFlags EH = parseClangCLEHFlags(D, Args); +  if (EH.Synch || EH.Asynch) { +    if (types::isCXX(InputType)) +      CmdArgs.push_back("-fcxx-exceptions"); +    CmdArgs.push_back("-fexceptions"); +  } +  if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) +    CmdArgs.push_back("-fexternc-nounwind"); + +  // /EP should expand to -E -P. +  if (Args.hasArg(options::OPT__SLASH_EP)) { +    CmdArgs.push_back("-E"); +    CmdArgs.push_back("-P"); +  } + +  unsigned VolatileOptionID; +  if (getToolChain().getArch() == llvm::Triple::x86_64 || +      getToolChain().getArch() == llvm::Triple::x86) +    VolatileOptionID = options::OPT__SLASH_volatile_ms; +  else +    VolatileOptionID = options::OPT__SLASH_volatile_iso; + +  if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group)) +    VolatileOptionID = A->getOption().getID(); + +  if (VolatileOptionID == options::OPT__SLASH_volatile_ms) +    CmdArgs.push_back("-fms-volatile"); + + if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_, +                  options::OPT__SLASH_Zc_dllexportInlines, +                  false)) { +   if (Args.hasArg(options::OPT__SLASH_fallback)) { +     D.Diag(clang::diag::err_drv_dllexport_inlines_and_fallback); +   } else { +    CmdArgs.push_back("-fno-dllexport-inlines"); +   } + } + +  Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); +  Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); +  if (MostGeneralArg && BestCaseArg) +    D.Diag(clang::diag::err_drv_argument_not_allowed_with) +        << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args); + +  if (MostGeneralArg) { +    Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms); +    Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm); +    Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv); + +    Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg; +    Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg; +    if (FirstConflict && SecondConflict && FirstConflict != SecondConflict) +      D.Diag(clang::diag::err_drv_argument_not_allowed_with) +          << FirstConflict->getAsString(Args) +          << SecondConflict->getAsString(Args); + +    if (SingleArg) +      CmdArgs.push_back("-fms-memptr-rep=single"); +    else if (MultipleArg) +      CmdArgs.push_back("-fms-memptr-rep=multiple"); +    else +      CmdArgs.push_back("-fms-memptr-rep=virtual"); +  } + +  // Parse the default calling convention options. +  if (Arg *CCArg = +          Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr, +                          options::OPT__SLASH_Gz, options::OPT__SLASH_Gv, +                          options::OPT__SLASH_Gregcall)) { +    unsigned DCCOptId = CCArg->getOption().getID(); +    const char *DCCFlag = nullptr; +    bool ArchSupported = true; +    llvm::Triple::ArchType Arch = getToolChain().getArch(); +    switch (DCCOptId) { +    case options::OPT__SLASH_Gd: +      DCCFlag = "-fdefault-calling-conv=cdecl"; +      break; +    case options::OPT__SLASH_Gr: +      ArchSupported = Arch == llvm::Triple::x86; +      DCCFlag = "-fdefault-calling-conv=fastcall"; +      break; +    case options::OPT__SLASH_Gz: +      ArchSupported = Arch == llvm::Triple::x86; +      DCCFlag = "-fdefault-calling-conv=stdcall"; +      break; +    case options::OPT__SLASH_Gv: +      ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64; +      DCCFlag = "-fdefault-calling-conv=vectorcall"; +      break; +    case options::OPT__SLASH_Gregcall: +      ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64; +      DCCFlag = "-fdefault-calling-conv=regcall"; +      break; +    } + +    // MSVC doesn't warn if /Gr or /Gz is used on x64, so we don't either. +    if (ArchSupported && DCCFlag) +      CmdArgs.push_back(DCCFlag); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_vtordisp_mode_EQ); + +  if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { +    CmdArgs.push_back("-fdiagnostics-format"); +    if (Args.hasArg(options::OPT__SLASH_fallback)) +      CmdArgs.push_back("msvc-fallback"); +    else +      CmdArgs.push_back("msvc"); +  } + +  if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { +    SmallVector<StringRef, 1> SplitArgs; +    StringRef(A->getValue()).split(SplitArgs, ","); +    bool Instrument = false; +    bool NoChecks = false; +    for (StringRef Arg : SplitArgs) { +      if (Arg.equals_lower("cf")) +        Instrument = true; +      else if (Arg.equals_lower("cf-")) +        Instrument = false; +      else if (Arg.equals_lower("nochecks")) +        NoChecks = true; +      else if (Arg.equals_lower("nochecks-")) +        NoChecks = false; +      else +        D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg; +    } +    // Currently there's no support emitting CFG instrumentation; the flag only +    // emits the table of address-taken functions. +    if (Instrument || NoChecks) +      CmdArgs.push_back("-cfguard"); +  } +} + +visualstudio::Compiler *Clang::getCLFallback() const { +  if (!CLFallback) +    CLFallback.reset(new visualstudio::Compiler(getToolChain())); +  return CLFallback.get(); +} + + +const char *Clang::getBaseInputName(const ArgList &Args, +                                    const InputInfo &Input) { +  return Args.MakeArgString(llvm::sys::path::filename(Input.getBaseInput())); +} + +const char *Clang::getBaseInputStem(const ArgList &Args, +                                    const InputInfoList &Inputs) { +  const char *Str = getBaseInputName(Args, Inputs[0]); + +  if (const char *End = strrchr(Str, '.')) +    return Args.MakeArgString(std::string(Str, End)); + +  return Str; +} + +const char *Clang::getDependencyFileName(const ArgList &Args, +                                         const InputInfoList &Inputs) { +  // FIXME: Think about this more. + +  if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { +    SmallString<128> OutputFilename(OutputOpt->getValue()); +    llvm::sys::path::replace_extension(OutputFilename, llvm::Twine('d')); +    return Args.MakeArgString(OutputFilename); +  } + +  return Args.MakeArgString(Twine(getBaseInputStem(Args, Inputs)) + ".d"); +} + +// Begin ClangAs + +void ClangAs::AddMIPSTargetArgs(const ArgList &Args, +                                ArgStringList &CmdArgs) const { +  StringRef CPUName; +  StringRef ABIName; +  const llvm::Triple &Triple = getToolChain().getTriple(); +  mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + +  CmdArgs.push_back("-target-abi"); +  CmdArgs.push_back(ABIName.data()); +} + +void ClangAs::AddX86TargetArgs(const ArgList &Args, +                               ArgStringList &CmdArgs) const { +  if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { +    StringRef Value = A->getValue(); +    if (Value == "intel" || Value == "att") { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); +    } else { +      getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Value; +    } +  } +} + +void ClangAs::AddRISCVTargetArgs(const ArgList &Args, +                               ArgStringList &CmdArgs) const { +  const llvm::Triple &Triple = getToolChain().getTriple(); +  StringRef ABIName = riscv::getRISCVABI(Args, Triple); + +  CmdArgs.push_back("-target-abi"); +  CmdArgs.push_back(ABIName.data()); +} + +void ClangAs::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."); +  const InputInfo &Input = Inputs[0]; + +  const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); +  const std::string &TripleStr = Triple.getTriple(); +  const auto &D = getToolChain().getDriver(); + +  // Don't warn about "clang -w -c foo.s" +  Args.ClaimAllArgs(options::OPT_w); +  // and "clang -emit-llvm -c foo.s" +  Args.ClaimAllArgs(options::OPT_emit_llvm); + +  claimNoWarnArgs(Args); + +  // Invoke ourselves in -cc1as mode. +  // +  // FIXME: Implement custom jobs for internal actions. +  CmdArgs.push_back("-cc1as"); + +  // Add the "effective" target triple. +  CmdArgs.push_back("-triple"); +  CmdArgs.push_back(Args.MakeArgString(TripleStr)); + +  // Set the output mode, we currently only expect to be used as a real +  // assembler. +  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, Input)); + +  // Add the target cpu +  std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); +  if (!CPU.empty()) { +    CmdArgs.push_back("-target-cpu"); +    CmdArgs.push_back(Args.MakeArgString(CPU)); +  } + +  // Add the target features +  getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true); + +  // Ignore explicit -force_cpusubtype_ALL option. +  (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); + +  // Pass along any -I options so we get proper .include search paths. +  Args.AddAllArgs(CmdArgs, options::OPT_I_Group); + +  // Determine the original source input. +  const Action *SourceAction = &JA; +  while (SourceAction->getKind() != Action::InputClass) { +    assert(!SourceAction->getInputs().empty() && "unexpected root action!"); +    SourceAction = SourceAction->getInputs()[0]; +  } + +  // Forward -g and handle debug info related flags, assuming we are dealing +  // with an actual assembly file. +  bool WantDebug = false; +  unsigned DwarfVersion = 0; +  Args.ClaimAllArgs(options::OPT_g_Group); +  if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { +    WantDebug = !A->getOption().matches(options::OPT_g0) && +                !A->getOption().matches(options::OPT_ggdb0); +    if (WantDebug) +      DwarfVersion = DwarfVersionNum(A->getSpelling()); +  } +  if (DwarfVersion == 0) +    DwarfVersion = getToolChain().GetDefaultDwarfVersion(); + +  codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; + +  if (SourceAction->getType() == types::TY_Asm || +      SourceAction->getType() == types::TY_PP_Asm) { +    // You might think that it would be ok to set DebugInfoKind outside of +    // the guard for source type, however there is a test which asserts +    // that some assembler invocation receives no -debug-info-kind, +    // and it's not clear whether that test is just overly restrictive. +    DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo +                               : codegenoptions::NoDebugInfo); +    // Add the -fdebug-compilation-dir flag if needed. +    addDebugCompDirArg(Args, CmdArgs, C.getDriver().getVFS()); + +    addDebugPrefixMapArg(getToolChain().getDriver(), 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())); + +    // And pass along -I options +    Args.AddAllArgs(CmdArgs, options::OPT_I); +  } +  RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, +                          llvm::DebuggerKind::Default); +  RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); + + +  // Handle -fPIC et al -- the relocation-model affects the assembler +  // for some targets. +  llvm::Reloc::Model RelocationModel; +  unsigned PICLevel; +  bool IsPIE; +  std::tie(RelocationModel, PICLevel, IsPIE) = +      ParsePICArgs(getToolChain(), Args); + +  const char *RMName = RelocationModelName(RelocationModel); +  if (RMName) { +    CmdArgs.push_back("-mrelocation-model"); +    CmdArgs.push_back(RMName); +  } + +  // Optionally embed the -cc1as level arguments into the debug info, for build +  // analysis. +  if (getToolChain().UseDwarfDebugFlags()) { +    ArgStringList OriginalArgs; +    for (const auto &Arg : Args) +      Arg->render(Args, OriginalArgs); + +    SmallString<256> Flags; +    const char *Exec = getToolChain().getDriver().getClangProgramPath(); +    Flags += Exec; +    for (const char *OriginalArg : OriginalArgs) { +      SmallString<128> EscapedArg; +      EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); +      Flags += " "; +      Flags += EscapedArg; +    } +    CmdArgs.push_back("-dwarf-debug-flags"); +    CmdArgs.push_back(Args.MakeArgString(Flags)); +  } + +  // FIXME: Add -static support, once we have it. + +  // Add target specific flags. +  switch (getToolChain().getArch()) { +  default: +    break; + +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: +    AddMIPSTargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::x86: +  case llvm::Triple::x86_64: +    AddX86TargetArgs(Args, CmdArgs); +    break; + +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +    // This isn't in AddARMTargetArgs because we want to do this for assembly +    // only, not C/C++. +    if (Args.hasFlag(options::OPT_mdefault_build_attributes, +                     options::OPT_mno_default_build_attributes, true)) { +        CmdArgs.push_back("-mllvm"); +        CmdArgs.push_back("-arm-add-build-attributes"); +    } +    break; + +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +    AddRISCVTargetArgs(Args, CmdArgs); +    break; +  } + +  // Consume all the warning flags. Usually this would be handled more +  // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as +  // doesn't handle that so rather than warning about unused flags that are +  // actually used, we'll lie by omission instead. +  // FIXME: Stop lying and consume only the appropriate driver flags +  Args.ClaimAllArgs(options::OPT_W_Group); + +  CollectArgsForIntegratedAssembler(C, Args, CmdArgs, +                                    getToolChain().getDriver()); + +  Args.AddAllArgs(CmdArgs, options::OPT_mllvm); + +  assert(Output.isFilename() && "Unexpected lipo output."); +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  const llvm::Triple &T = getToolChain().getTriple(); +  Arg *A; +  if (getDebugFissionKind(D, Args, A) == DwarfFissionKind::Split && +      T.isOSBinFormatELF()) { +    CmdArgs.push_back("-split-dwarf-output"); +    CmdArgs.push_back(SplitDebugName(Args, Input, Output)); +  } + +  assert(Input.isFilename() && "Invalid input."); +  CmdArgs.push_back(Input.getFilename()); + +  const char *Exec = getToolChain().getDriver().getClangProgramPath(); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// Begin OffloadBundler + +void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const llvm::opt::ArgList &TCArgs, +                                  const char *LinkingOutput) const { +  // The version with only one output is expected to refer to a bundling job. +  assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!"); + +  // The bundling command looks like this: +  // clang-offload-bundler -type=bc +  //   -targets=host-triple,openmp-triple1,openmp-triple2 +  //   -outputs=input_file +  //   -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + +  ArgStringList CmdArgs; + +  // Get the type. +  CmdArgs.push_back(TCArgs.MakeArgString( +      Twine("-type=") + types::getTypeTempSuffix(Output.getType()))); + +  assert(JA.getInputs().size() == Inputs.size() && +         "Not have inputs for all dependence actions??"); + +  // Get the targets. +  SmallString<128> Triples; +  Triples += "-targets="; +  for (unsigned I = 0; I < Inputs.size(); ++I) { +    if (I) +      Triples += ','; + +    // Find ToolChain for this input. +    Action::OffloadKind CurKind = Action::OFK_Host; +    const ToolChain *CurTC = &getToolChain(); +    const Action *CurDep = JA.getInputs()[I]; + +    if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) { +      CurTC = nullptr; +      OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) { +        assert(CurTC == nullptr && "Expected one dependence!"); +        CurKind = A->getOffloadingDeviceKind(); +        CurTC = TC; +      }); +    } +    Triples += Action::GetOffloadKindName(CurKind); +    Triples += '-'; +    Triples += CurTC->getTriple().normalize(); +    if (CurKind == Action::OFK_HIP && CurDep->getOffloadingArch()) { +      Triples += '-'; +      Triples += CurDep->getOffloadingArch(); +    } +  } +  CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + +  // Get bundled file command. +  CmdArgs.push_back( +      TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename())); + +  // Get unbundled files command. +  SmallString<128> UB; +  UB += "-inputs="; +  for (unsigned I = 0; I < Inputs.size(); ++I) { +    if (I) +      UB += ','; + +    // Find ToolChain for this input. +    const ToolChain *CurTC = &getToolChain(); +    if (const auto *OA = dyn_cast<OffloadAction>(JA.getInputs()[I])) { +      CurTC = nullptr; +      OA->doOnEachDependence([&](Action *, const ToolChain *TC, const char *) { +        assert(CurTC == nullptr && "Expected one dependence!"); +        CurTC = TC; +      }); +    } +    UB += CurTC->getInputFilename(Inputs[I]); +  } +  CmdArgs.push_back(TCArgs.MakeArgString(UB)); + +  // All the inputs are encoded as commands. +  C.addCommand(std::make_unique<Command>( +      JA, *this, +      TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), +      CmdArgs, None)); +} + +void OffloadBundler::ConstructJobMultipleOutputs( +    Compilation &C, const JobAction &JA, const InputInfoList &Outputs, +    const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, +    const char *LinkingOutput) const { +  // The version with multiple outputs is expected to refer to a unbundling job. +  auto &UA = cast<OffloadUnbundlingJobAction>(JA); + +  // The unbundling command looks like this: +  // clang-offload-bundler -type=bc +  //   -targets=host-triple,openmp-triple1,openmp-triple2 +  //   -inputs=input_file +  //   -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" +  //   -unbundle + +  ArgStringList CmdArgs; + +  assert(Inputs.size() == 1 && "Expecting to unbundle a single file!"); +  InputInfo Input = Inputs.front(); + +  // Get the type. +  CmdArgs.push_back(TCArgs.MakeArgString( +      Twine("-type=") + types::getTypeTempSuffix(Input.getType()))); + +  // Get the targets. +  SmallString<128> Triples; +  Triples += "-targets="; +  auto DepInfo = UA.getDependentActionsInfo(); +  for (unsigned I = 0; I < DepInfo.size(); ++I) { +    if (I) +      Triples += ','; + +    auto &Dep = DepInfo[I]; +    Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); +    Triples += '-'; +    Triples += Dep.DependentToolChain->getTriple().normalize(); +    if (Dep.DependentOffloadKind == Action::OFK_HIP && +        !Dep.DependentBoundArch.empty()) { +      Triples += '-'; +      Triples += Dep.DependentBoundArch; +    } +  } + +  CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + +  // Get bundled file command. +  CmdArgs.push_back( +      TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); + +  // Get unbundled files command. +  SmallString<128> UB; +  UB += "-outputs="; +  for (unsigned I = 0; I < Outputs.size(); ++I) { +    if (I) +      UB += ','; +    UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]); +  } +  CmdArgs.push_back(TCArgs.MakeArgString(UB)); +  CmdArgs.push_back("-unbundle"); + +  // All the inputs are encoded as commands. +  C.addCommand(std::make_unique<Command>( +      JA, *this, +      TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), +      CmdArgs, None)); +} + +void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const ArgList &Args, +                                  const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + +  // Add the "effective" target triple. +  CmdArgs.push_back("-target"); +  CmdArgs.push_back(Args.MakeArgString(Triple.getTriple())); + +  // Add the output file name. +  assert(Output.isFilename() && "Invalid output."); +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  // Add inputs. +  for (const InputInfo &I : Inputs) { +    assert(I.isFilename() && "Invalid input."); +    CmdArgs.push_back(I.getFilename()); +  } + +  C.addCommand(std::make_unique<Command>( +      JA, *this, +      Args.MakeArgString(getToolChain().GetProgramPath(getShortName())), +      CmdArgs, Inputs)); +} diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h new file mode 100644 index 0000000000000..b345c02489d4d --- /dev/null +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -0,0 +1,174 @@ +//===--- Clang.h - Clang Tool and ToolChain Implementations ====-*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H + +#include "MSVC.h" +#include "clang/Basic/DebugInfoOptions.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/Types.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +class ObjCRuntime; +namespace driver { + +namespace tools { + +/// Clang compiler tool. +class LLVM_LIBRARY_VISIBILITY Clang : public Tool { +public: +  static const char *getBaseInputName(const llvm::opt::ArgList &Args, +                                      const InputInfo &Input); +  static const char *getBaseInputStem(const llvm::opt::ArgList &Args, +                                      const InputInfoList &Inputs); +  static const char *getDependencyFileName(const llvm::opt::ArgList &Args, +                                           const InputInfoList &Inputs); + +private: +  void AddPreprocessingOptions(Compilation &C, const JobAction &JA, +                               const Driver &D, const llvm::opt::ArgList &Args, +                               llvm::opt::ArgStringList &CmdArgs, +                               const InputInfo &Output, +                               const InputInfoList &Inputs) const; + +  void RenderTargetOptions(const llvm::Triple &EffectiveTriple, +                           const llvm::opt::ArgList &Args, bool KernelOrKext, +                           llvm::opt::ArgStringList &CmdArgs) const; + +  void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, +                            llvm::opt::ArgStringList &CmdArgs) const; +  void AddARMTargetArgs(const llvm::Triple &Triple, +                        const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs, +                        bool KernelOrKext) const; +  void AddARM64TargetArgs(const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs) const; +  void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs) const; +  void AddPPCTargetArgs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const; +  void AddR600TargetArgs(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs) const; +  void AddRISCVTargetArgs(const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs) const; +  void AddSparcTargetArgs(const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs) const; +  void AddSystemZTargetArgs(const llvm::opt::ArgList &Args, +                            llvm::opt::ArgStringList &CmdArgs) const; +  void AddX86TargetArgs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const; +  void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, +                            llvm::opt::ArgStringList &CmdArgs) const; +  void AddLanaiTargetArgs(const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs) const; +  void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args, +                                llvm::opt::ArgStringList &CmdArgs) const; + +  enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; + +  ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, +                                 llvm::opt::ArgStringList &cmdArgs, +                                 RewriteKind rewrite) const; + +  void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType, +                      llvm::opt::ArgStringList &CmdArgs, +                      codegenoptions::DebugInfoKind *DebugInfoKind, +                      bool *EmitCodeView) const; + +  visualstudio::Compiler *getCLFallback() const; + +  mutable std::unique_ptr<visualstudio::Compiler> CLFallback; + +  mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr; +  void DumpCompilationDatabase(Compilation &C, StringRef Filename, +                               StringRef Target, +                               const InputInfo &Output, const InputInfo &Input, +                               const llvm::opt::ArgList &Args) const; + +  void DumpCompilationDatabaseFragmentToDir( +      StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output, +      const InputInfo &Input, const llvm::opt::ArgList &Args) const; + +public: +  Clang(const ToolChain &TC); +  ~Clang() override; + +  bool hasGoodDiagnostics() const override { return true; } +  bool hasIntegratedAssembler() const override { return true; } +  bool hasIntegratedCPP() const override { return true; } +  bool canEmitIR() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +/// Clang integrated assembler tool. +class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { +public: +  ClangAs(const ToolChain &TC) +      : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {} +  void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs) const; +  void AddX86TargetArgs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const; +  void AddRISCVTargetArgs(const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs) const; +  bool hasGoodDiagnostics() const override { return true; } +  bool hasIntegratedAssembler() const override { return false; } +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +/// Offload bundler tool. +class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool { +public: +  OffloadBundler(const ToolChain &TC) +      : Tool("offload bundler", "clang-offload-bundler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +  void ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA, +                                   const InputInfoList &Outputs, +                                   const InputInfoList &Inputs, +                                   const llvm::opt::ArgList &TCArgs, +                                   const char *LinkingOutput) const override; +}; + +/// Offload wrapper tool. +class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool { +public: +  OffloadWrapper(const ToolChain &TC) +      : Tool("offload wrapper", "clang-offload-wrapper", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H diff --git a/clang/lib/Driver/ToolChains/CloudABI.cpp b/clang/lib/Driver/ToolChains/CloudABI.cpp new file mode 100644 index 0000000000000..cf1d0d551e570 --- /dev/null +++ b/clang/lib/Driver/ToolChains/CloudABI.cpp @@ -0,0 +1,147 @@ +//===--- CloudABI.cpp - CloudABI ToolChain Implementations ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CloudABI.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                    const InputInfo &Output, +                                    const InputInfoList &Inputs, +                                    const ArgList &Args, +                                    const char *LinkingOutput) const { +  const ToolChain &ToolChain = getToolChain(); +  const Driver &D = ToolChain.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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  // CloudABI only supports static linkage. +  CmdArgs.push_back("-Bstatic"); +  CmdArgs.push_back("--no-dynamic-linker"); + +  // Provide PIE linker flags in case PIE is default for the architecture. +  if (ToolChain.isPIEDefault()) { +    CmdArgs.push_back("-pie"); +    CmdArgs.push_back("-zrelro"); +  } + +  CmdArgs.push_back("--eh-frame-hdr"); +  CmdArgs.push_back("--gc-sections"); + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_T_Group, options::OPT_e, options::OPT_s, +                   options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + +  if (D.isUsingLTO()) { +    assert(!Inputs.empty() && "Must have at least one input."); +    AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], +                  D.getLTOMode() == LTOK_Thin); +  } + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (ToolChain.ShouldLinkCXXStdlib(Args)) +    ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    CmdArgs.push_back("-lc"); +    CmdArgs.push_back("-lcompiler_rt"); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// CloudABI - CloudABI tool chain which can call ld(1) directly. + +CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, +                   const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  SmallString<128> P(getDriver().Dir); +  llvm::sys::path::append(P, "..", getTriple().str(), "lib"); +  getFilePaths().push_back(P.str()); +} + +void CloudABI::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                     llvm::opt::ArgStringList &CC1Args) const { +  SmallString<128> P(getDriver().Dir); +  llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); +  addSystemInclude(DriverArgs, CC1Args, P.str()); +} + +void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, +                                   ArgStringList &CmdArgs) const { +  CmdArgs.push_back("-lc++"); +  CmdArgs.push_back("-lc++abi"); +  CmdArgs.push_back("-lunwind"); +} + +Tool *CloudABI::buildLinker() const { +  return new tools::cloudabi::Linker(*this); +} + +bool CloudABI::isPIEDefault() const { +  // Only enable PIE on architectures that support PC-relative +  // addressing. PC-relative addressing is required, as the process +  // startup code must be able to relocate itself. +  switch (getTriple().getArch()) { +  case llvm::Triple::aarch64: +  case llvm::Triple::x86_64: +    return true; +  default: +    return false; +  } +} + +SanitizerMask CloudABI::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::SafeStack; +  return Res; +} + +SanitizerMask CloudABI::getDefaultSanitizers() const { +  return SanitizerKind::SafeStack; +} diff --git a/clang/lib/Driver/ToolChains/CloudABI.h b/clang/lib/Driver/ToolChains/CloudABI.h new file mode 100644 index 0000000000000..cc381c2b1e1fe --- /dev/null +++ b/clang/lib/Driver/ToolChains/CloudABI.h @@ -0,0 +1,70 @@ +//===--- CloudABI.h - CloudABI ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// cloudabi -- Directly call GNU Binutils linker +namespace cloudabi { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("cloudabi::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace cloudabi +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { +public: +  CloudABI(const Driver &D, const llvm::Triple &Triple, +           const llvm::opt::ArgList &Args); +  bool HasNativeLLVMSupport() const override { return true; } + +  bool IsMathErrnoDefault() const override { return false; } +  bool IsObjCNonFragileABIDefault() const override { return true; } + +  CXXStdlibType +  GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { +    return ToolChain::CST_Libcxx; +  } +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  bool isPIEDefault() const override; +  SanitizerMask getSupportedSanitizers() const override; +  SanitizerMask getDefaultSanitizers() const override; + +protected: +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp new file mode 100644 index 0000000000000..10743559e0481 --- /dev/null +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -0,0 +1,1502 @@ +//===--- CommonArgs.cpp - Args handling for multiple toolchains -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CommonArgs.h" +#include "Arch/AArch64.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "Arch/RISCV.h" +#include "Arch/Sparc.h" +#include "Arch/SystemZ.h" +#include "Arch/X86.h" +#include "AMDGPU.h" +#include "MSP430.h" +#include "HIP.h" +#include "Hexagon.h" +#include "InputInfo.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Util.h" +#include "clang/Driver/XRayArgs.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/YAMLParser.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void tools::addPathIfExists(const Driver &D, const Twine &Path, +                            ToolChain::path_list &Paths) { +  if (D.getVFS().exists(Path)) +    Paths.push_back(Path.str()); +} + +void tools::handleTargetFeaturesGroup(const ArgList &Args, +                                      std::vector<StringRef> &Features, +                                      OptSpecifier Group) { +  for (const Arg *A : Args.filtered(Group)) { +    StringRef Name = A->getOption().getName(); +    A->claim(); + +    // Skip over "-m". +    assert(Name.startswith("m") && "Invalid feature name."); +    Name = Name.substr(1); + +    bool IsNegative = Name.startswith("no-"); +    if (IsNegative) +      Name = Name.substr(3); +    Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); +  } +} + +void tools::addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, +                             const char *ArgName, const char *EnvVar) { +  const char *DirList = ::getenv(EnvVar); +  bool CombinedArg = false; + +  if (!DirList) +    return; // Nothing to do. + +  StringRef Name(ArgName); +  if (Name.equals("-I") || Name.equals("-L")) +    CombinedArg = true; + +  StringRef Dirs(DirList); +  if (Dirs.empty()) // Empty string should not add '.'. +    return; + +  StringRef::size_type Delim; +  while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) { +    if (Delim == 0) { // Leading colon. +      if (CombinedArg) { +        CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); +      } else { +        CmdArgs.push_back(ArgName); +        CmdArgs.push_back("."); +      } +    } else { +      if (CombinedArg) { +        CmdArgs.push_back( +            Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim))); +      } else { +        CmdArgs.push_back(ArgName); +        CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); +      } +    } +    Dirs = Dirs.substr(Delim + 1); +  } + +  if (Dirs.empty()) { // Trailing colon. +    if (CombinedArg) { +      CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); +    } else { +      CmdArgs.push_back(ArgName); +      CmdArgs.push_back("."); +    } +  } else { // Add the last path. +    if (CombinedArg) { +      CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs)); +    } else { +      CmdArgs.push_back(ArgName); +      CmdArgs.push_back(Args.MakeArgString(Dirs)); +    } +  } +} + +void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, +                            const ArgList &Args, ArgStringList &CmdArgs, +                            const JobAction &JA) { +  const Driver &D = TC.getDriver(); + +  // Add extra linker input arguments which are not treated as inputs +  // (constructed via -Xarch_). +  Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); + +  // LIBRARY_PATH are included before user inputs and only supported on native +  // toolchains. +  if (!TC.isCrossCompiling()) +    addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + +  for (const auto &II : Inputs) { +    // If the current tool chain refers to an OpenMP or HIP offloading host, we +    // should ignore inputs that refer to OpenMP or HIP offloading devices - +    // they will be embedded according to a proper linker script. +    if (auto *IA = II.getAction()) +      if ((JA.isHostOffloading(Action::OFK_OpenMP) && +           IA->isDeviceOffloading(Action::OFK_OpenMP)) || +          (JA.isHostOffloading(Action::OFK_HIP) && +           IA->isDeviceOffloading(Action::OFK_HIP))) +        continue; + +    if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) +      // Don't try to pass LLVM inputs unless we have native support. +      D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); + +    // Add filenames immediately. +    if (II.isFilename()) { +      CmdArgs.push_back(II.getFilename()); +      continue; +    } + +    // Otherwise, this is a linker input argument. +    const Arg &A = II.getInputArg(); + +    // Handle reserved library options. +    if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) +      TC.AddCXXStdlibLibArgs(Args, CmdArgs); +    else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) +      TC.AddCCKextLibArgs(Args, CmdArgs); +    else if (A.getOption().matches(options::OPT_z)) { +      // Pass -z prefix for gcc linker compatibility. +      A.claim(); +      A.render(Args, CmdArgs); +    } else { +      A.renderAsInput(Args, CmdArgs); +    } +  } +} + +void tools::AddTargetFeature(const ArgList &Args, +                             std::vector<StringRef> &Features, +                             OptSpecifier OnOpt, OptSpecifier OffOpt, +                             StringRef FeatureName) { +  if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { +    if (A->getOption().matches(OnOpt)) +      Features.push_back(Args.MakeArgString("+" + FeatureName)); +    else +      Features.push_back(Args.MakeArgString("-" + FeatureName)); +  } +} + +/// 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)) { +    const char *GPUName = A->getValue(); +    return llvm::StringSwitch<const char *>(GPUName) +        .Cases("rv630", "rv635", "r600") +        .Cases("rv610", "rv620", "rs780", "rs880") +        .Case("rv740", "rv770") +        .Case("palm", "cedar") +        .Cases("sumo", "sumo2", "sumo") +        .Case("hemlock", "cypress") +        .Case("aruba", "cayman") +        .Default(GPUName); +  } +  return ""; +} + +static std::string getLanaiTargetCPU(const ArgList &Args) { +  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { +    return A->getValue(); +  } +  return ""; +} + +/// Get the (LLVM) name of the WebAssembly cpu we are targeting. +static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { +  // If we have -mcpu=, use that. +  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { +    StringRef CPU = A->getValue(); + +#ifdef __wasm__ +    // Handle "native" by examining the host. "native" isn't meaningful when +    // cross compiling, so only support this when the host is also WebAssembly. +    if (CPU == "native") +      return llvm::sys::getHostCPUName(); +#endif + +    return CPU; +  } + +  return "generic"; +} + +std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, +                              bool FromAs) { +  Arg *A; + +  switch (T.getArch()) { +  default: +    return ""; + +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: +    return aarch64::getAArch64TargetCPU(Args, T, A); + +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: { +    StringRef MArch, MCPU; +    arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs); +    return arm::getARMTargetCPU(MCPU, MArch, T); +  } + +  case llvm::Triple::avr: +    if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ)) +      return A->getValue(); +    return ""; + +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: { +    StringRef CPUName; +    StringRef ABIName; +    mips::getMipsCPUAndABI(Args, T, CPUName, ABIName); +    return CPUName; +  } + +  case llvm::Triple::nvptx: +  case llvm::Triple::nvptx64: +    if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) +      return A->getValue(); +    return ""; + +  case llvm::Triple::ppc: +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: { +    std::string TargetCPUName = ppc::getPPCTargetCPU(Args); +    // LLVM may default to generating code for the native CPU, +    // but, like gcc, we default to a more generic option for +    // each architecture. (except on Darwin) +    if (TargetCPUName.empty() && !T.isOSDarwin()) { +      if (T.getArch() == llvm::Triple::ppc64) +        TargetCPUName = "ppc64"; +      else if (T.getArch() == llvm::Triple::ppc64le) +        TargetCPUName = "ppc64le"; +      else +        TargetCPUName = "ppc"; +    } +    return TargetCPUName; +  } + +  case llvm::Triple::bpfel: +  case llvm::Triple::bpfeb: +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +  case llvm::Triple::sparcv9: +    if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) +      return A->getValue(); +    return ""; + +  case llvm::Triple::x86: +  case llvm::Triple::x86_64: +    return x86::getX86TargetCPU(Args, T); + +  case llvm::Triple::hexagon: +    return "hexagon" + +           toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + +  case llvm::Triple::lanai: +    return getLanaiTargetCPU(Args); + +  case llvm::Triple::systemz: +    return systemz::getSystemZTargetCPU(Args); + +  case llvm::Triple::r600: +  case llvm::Triple::amdgcn: +    return getR600TargetGPU(Args); + +  case llvm::Triple::wasm32: +  case llvm::Triple::wasm64: +    return getWebAssemblyTargetCPU(Args); +  } +} + +unsigned tools::getLTOParallelism(const ArgList &Args, const Driver &D) { +  unsigned Parallelism = 0; +  Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); +  if (LtoJobsArg && +      StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism)) +    D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) +                                            << LtoJobsArg->getValue(); +  return Parallelism; +} + +// CloudABI uses -ffunction-sections and -fdata-sections by default. +bool tools::isUseSeparateSections(const llvm::Triple &Triple) { +  return Triple.getOS() == llvm::Triple::CloudABI; +} + +void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, +                          ArgStringList &CmdArgs, const InputInfo &Output, +                          const InputInfo &Input, bool IsThinLTO) { +  // Tell the linker to load the plugin. This has to come before AddLinkerInputs +  // as gold requires -plugin to come before any -plugin-opt that -Wl might +  // forward. +  CmdArgs.push_back("-plugin"); + +#if defined(_WIN32) +  const char *Suffix = ".dll"; +#elif defined(__APPLE__) +  const char *Suffix = ".dylib"; +#else +  const char *Suffix = ".so"; +#endif + +  SmallString<1024> Plugin; +  llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) + +                              "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + +                              Suffix, +                          Plugin); +  CmdArgs.push_back(Args.MakeArgString(Plugin)); + +  // Try to pass driver level flags relevant to LTO code generation down to +  // the plugin. + +  // Handle flags for selecting CPU variants. +  std::string CPU = getCPUName(Args, ToolChain.getTriple()); +  if (!CPU.empty()) +    CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); + +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { +    StringRef OOpt; +    if (A->getOption().matches(options::OPT_O4) || +        A->getOption().matches(options::OPT_Ofast)) +      OOpt = "3"; +    else if (A->getOption().matches(options::OPT_O)) +      OOpt = A->getValue(); +    else if (A->getOption().matches(options::OPT_O0)) +      OOpt = "0"; +    if (!OOpt.empty()) +      CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); +  } + +  if (Args.hasArg(options::OPT_gsplit_dwarf)) { +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") + +            Output.getFilename() + "_dwo")); +  } + +  if (IsThinLTO) +    CmdArgs.push_back("-plugin-opt=thinlto"); + +  if (unsigned Parallelism = getLTOParallelism(Args, ToolChain.getDriver())) +    CmdArgs.push_back( +        Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); + +  // If an explicit debugger tuning argument appeared, pass it along. +  if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, +                               options::OPT_ggdbN_Group)) { +    if (A->getOption().matches(options::OPT_glldb)) +      CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb"); +    else if (A->getOption().matches(options::OPT_gsce)) +      CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); +    else +      CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); +  } + +  bool UseSeparateSections = +      isUseSeparateSections(ToolChain.getEffectiveTriple()); + +  if (Args.hasFlag(options::OPT_ffunction_sections, +                   options::OPT_fno_function_sections, UseSeparateSections)) { +    CmdArgs.push_back("-plugin-opt=-function-sections"); +  } + +  if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, +                   UseSeparateSections)) { +    CmdArgs.push_back("-plugin-opt=-data-sections"); +  } + +  if (Arg *A = getLastProfileSampleUseArg(Args)) { +    StringRef FName = A->getValue(); +    if (!llvm::sys::fs::exists(FName)) +      ToolChain.getDriver().Diag(diag::err_drv_no_such_file) << FName; +    else +      CmdArgs.push_back( +          Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); +  } + +  auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate, +                                           options::OPT_fcs_profile_generate_EQ, +                                           options::OPT_fno_profile_generate); +  if (CSPGOGenerateArg && +      CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) +    CSPGOGenerateArg = nullptr; + +  auto *ProfileUseArg = getLastProfileUseArg(Args); + +  if (CSPGOGenerateArg) { +    CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate")); +    if (CSPGOGenerateArg->getOption().matches( +            options::OPT_fcs_profile_generate_EQ)) { +      SmallString<128> Path(CSPGOGenerateArg->getValue()); +      llvm::sys::path::append(Path, "default_%m.profraw"); +      CmdArgs.push_back( +          Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path)); +    } else +      CmdArgs.push_back( +          Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw")); +  } else if (ProfileUseArg) { +    SmallString<128> Path( +        ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); +    if (Path.empty() || llvm::sys::fs::is_directory(Path)) +      llvm::sys::path::append(Path, "default.profdata"); +    CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + +                                         Path)); +  } + +  // Need this flag to turn on new pass manager via Gold plugin. +  if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager, +                   options::OPT_fno_experimental_new_pass_manager, +                   /* Default */ ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER)) { +    CmdArgs.push_back("-plugin-opt=new-pass-manager"); +  } + +  // Setup statistics file output. +  SmallString<128> StatsFile = +      getStatsFileName(Args, Output, Input, ToolChain.getDriver()); +  if (!StatsFile.empty()) +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); + +  getTargetFeatures(ToolChain, ToolChain.getTriple(), Args, CmdArgs, +                    /* ForAS= */ false, /* ForLTOPlugin= */ true); + +  StringRef ABIName = tools::getTargetABI(Args, ToolChain.getTriple()); +  if (!ABIName.empty()) +    CmdArgs.push_back( +        Args.MakeArgString(Twine("-plugin-opt=-target-abi=") + ABIName)); +} + +void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, +                                 ArgStringList &CmdArgs) { +  if (!Args.hasFlag(options::OPT_frtlib_add_rpath, +                    options::OPT_fno_rtlib_add_rpath, false)) +    return; + +  std::string CandidateRPath = TC.getArchSpecificLibPath(); +  if (TC.getVFS().exists(CandidateRPath)) { +    CmdArgs.push_back("-rpath"); +    CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); +  } +} + +bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, +                             const ArgList &Args, bool ForceStaticHostRuntime, +                             bool IsOffloadingHost, bool GompNeedsRT) { +  if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, +                    options::OPT_fno_openmp, false)) +    return false; + +  Driver::OpenMPRuntimeKind RTKind = TC.getDriver().getOpenMPRuntime(Args); + +  if (RTKind == Driver::OMPRT_Unknown) +    // Already diagnosed. +    return false; + +  if (ForceStaticHostRuntime) +    CmdArgs.push_back("-Bstatic"); + +  switch (RTKind) { +  case Driver::OMPRT_OMP: +    CmdArgs.push_back("-lomp"); +    break; +  case Driver::OMPRT_GOMP: +    CmdArgs.push_back("-lgomp"); +    break; +  case Driver::OMPRT_IOMP5: +    CmdArgs.push_back("-liomp5"); +    break; +  case Driver::OMPRT_Unknown: +    break; +  } + +  if (ForceStaticHostRuntime) +    CmdArgs.push_back("-Bdynamic"); + +  if (RTKind == Driver::OMPRT_GOMP && GompNeedsRT) +      CmdArgs.push_back("-lrt"); + +  if (IsOffloadingHost) +    CmdArgs.push_back("-lomptarget"); + +  addArchSpecificRPath(TC, Args, CmdArgs); + +  return true; +} + +static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, +                                ArgStringList &CmdArgs, StringRef Sanitizer, +                                bool IsShared, bool IsWhole) { +  // Wrap any static runtimes that must be forced into executable in +  // whole-archive. +  if (IsWhole) CmdArgs.push_back("--whole-archive"); +  CmdArgs.push_back(TC.getCompilerRTArgString( +      Args, Sanitizer, IsShared ? ToolChain::FT_Shared : ToolChain::FT_Static)); +  if (IsWhole) CmdArgs.push_back("--no-whole-archive"); + +  if (IsShared) { +    addArchSpecificRPath(TC, Args, CmdArgs); +  } +} + +// Tries to use a file with the list of dynamic symbols that need to be exported +// from the runtime library. Returns true if the file was found. +static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, +                                    ArgStringList &CmdArgs, +                                    StringRef Sanitizer) { +  // Solaris ld defaults to --export-dynamic behaviour but doesn't support +  // the option, so don't try to pass it. +  if (TC.getTriple().getOS() == llvm::Triple::Solaris) +    return true; +  // Myriad is static linking only.  Furthermore, some versions of its +  // linker have the bug where --export-dynamic overrides -static, so +  // don't use --export-dynamic on that platform. +  if (TC.getTriple().getVendor() == llvm::Triple::Myriad) +    return true; +  SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); +  if (llvm::sys::fs::exists(SanRT + ".syms")) { +    CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); +    return true; +  } +  return false; +} + +void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, +                                     ArgStringList &CmdArgs) { +  // Force linking against the system libraries sanitizers depends on +  // (see PR15823 why this is necessary). +  CmdArgs.push_back("--no-as-needed"); +  // There's no libpthread or librt on RTEMS & Android. +  if (TC.getTriple().getOS() != llvm::Triple::RTEMS && +      !TC.getTriple().isAndroid()) { +    CmdArgs.push_back("-lpthread"); +    if (!TC.getTriple().isOSOpenBSD()) +      CmdArgs.push_back("-lrt"); +  } +  CmdArgs.push_back("-lm"); +  // There's no libdl on all OSes. +  if (!TC.getTriple().isOSFreeBSD() && +      !TC.getTriple().isOSNetBSD() && +      !TC.getTriple().isOSOpenBSD() && +       TC.getTriple().getOS() != llvm::Triple::RTEMS) +    CmdArgs.push_back("-ldl"); +  // Required for backtrace on some OSes +  if (TC.getTriple().isOSFreeBSD() || +      TC.getTriple().isOSNetBSD()) +    CmdArgs.push_back("-lexecinfo"); +} + +static void +collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, +                         SmallVectorImpl<StringRef> &SharedRuntimes, +                         SmallVectorImpl<StringRef> &StaticRuntimes, +                         SmallVectorImpl<StringRef> &NonWholeStaticRuntimes, +                         SmallVectorImpl<StringRef> &HelperStaticRuntimes, +                         SmallVectorImpl<StringRef> &RequiredSymbols) { +  const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +  // Collect shared runtimes. +  if (SanArgs.needsSharedRt()) { +    if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { +      SharedRuntimes.push_back("asan"); +      if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) +        HelperStaticRuntimes.push_back("asan-preinit"); +    } +    if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { +      if (SanArgs.requiresMinimalRuntime()) +        SharedRuntimes.push_back("ubsan_minimal"); +      else +        SharedRuntimes.push_back("ubsan_standalone"); +    } +    if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { +      if (SanArgs.requiresMinimalRuntime()) +        SharedRuntimes.push_back("scudo_minimal"); +      else +        SharedRuntimes.push_back("scudo"); +    } +    if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) +      SharedRuntimes.push_back("hwasan"); +  } + +  // The stats_client library is also statically linked into DSOs. +  if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) +    StaticRuntimes.push_back("stats_client"); + +  // Collect static runtimes. +  if (Args.hasArg(options::OPT_shared) || SanArgs.needsSharedRt()) { +    // Don't link static runtimes into DSOs or if -shared-libasan. +    return; +  } +  if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { +    StaticRuntimes.push_back("asan"); +    if (SanArgs.linkCXXRuntimes()) +      StaticRuntimes.push_back("asan_cxx"); +  } + +  if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { +    StaticRuntimes.push_back("hwasan"); +    if (SanArgs.linkCXXRuntimes()) +      StaticRuntimes.push_back("hwasan_cxx"); +  } +  if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes()) +    StaticRuntimes.push_back("dfsan"); +  if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes()) +    StaticRuntimes.push_back("lsan"); +  if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) { +    StaticRuntimes.push_back("msan"); +    if (SanArgs.linkCXXRuntimes()) +      StaticRuntimes.push_back("msan_cxx"); +  } +  if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) { +    StaticRuntimes.push_back("tsan"); +    if (SanArgs.linkCXXRuntimes()) +      StaticRuntimes.push_back("tsan_cxx"); +  } +  if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { +    if (SanArgs.requiresMinimalRuntime()) { +      StaticRuntimes.push_back("ubsan_minimal"); +    } else { +      StaticRuntimes.push_back("ubsan_standalone"); +      if (SanArgs.linkCXXRuntimes()) +        StaticRuntimes.push_back("ubsan_standalone_cxx"); +    } +  } +  if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) { +    NonWholeStaticRuntimes.push_back("safestack"); +    RequiredSymbols.push_back("__safestack_init"); +  } +  if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes()) +    StaticRuntimes.push_back("cfi"); +  if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) { +    StaticRuntimes.push_back("cfi_diag"); +    if (SanArgs.linkCXXRuntimes()) +      StaticRuntimes.push_back("ubsan_standalone_cxx"); +  } +  if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) { +    NonWholeStaticRuntimes.push_back("stats"); +    RequiredSymbols.push_back("__sanitizer_stats_register"); +  } +  if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { +    if (SanArgs.requiresMinimalRuntime()) { +      StaticRuntimes.push_back("scudo_minimal"); +      if (SanArgs.linkCXXRuntimes()) +        StaticRuntimes.push_back("scudo_cxx_minimal"); +    } else { +      StaticRuntimes.push_back("scudo"); +      if (SanArgs.linkCXXRuntimes()) +        StaticRuntimes.push_back("scudo_cxx"); +    } +  } +} + +// Should be called before we add system libraries (C++ ABI, libstdc++/libc++, +// C runtime, etc). Returns true if sanitizer system deps need to be linked in. +bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, +                                 ArgStringList &CmdArgs) { +  SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes, +      NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; +  collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, +                           NonWholeStaticRuntimes, HelperStaticRuntimes, +                           RequiredSymbols); + +  const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +  // Inject libfuzzer dependencies. +  if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() && +      !Args.hasArg(options::OPT_shared)) { + +    addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true); +    if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx)) +      TC.AddCXXStdlibLibArgs(Args, CmdArgs); +  } + +  for (auto RT : SharedRuntimes) +    addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false); +  for (auto RT : HelperStaticRuntimes) +    addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); +  bool AddExportDynamic = false; +  for (auto RT : StaticRuntimes) { +    addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); +    AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); +  } +  for (auto RT : NonWholeStaticRuntimes) { +    addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false); +    AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); +  } +  for (auto S : RequiredSymbols) { +    CmdArgs.push_back("-u"); +    CmdArgs.push_back(Args.MakeArgString(S)); +  } +  // If there is a static runtime with no dynamic list, force all the symbols +  // to be dynamic to be sure we export sanitizer interface functions. +  if (AddExportDynamic) +    CmdArgs.push_back("--export-dynamic"); + +  if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) +    CmdArgs.push_back("-export-dynamic-symbol=__cfi_check"); + +  return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); +} + +bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringList &CmdArgs) { +  if (Args.hasArg(options::OPT_shared)) +    return false; + +  if (TC.getXRayArgs().needsXRayRt()) { +    CmdArgs.push_back("-whole-archive"); +    CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray")); +    for (const auto &Mode : TC.getXRayArgs().modeList()) +      CmdArgs.push_back(TC.getCompilerRTArgString(Args, Mode)); +    CmdArgs.push_back("-no-whole-archive"); +    return true; +  } + +  return false; +} + +void tools::linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { +  CmdArgs.push_back("--no-as-needed"); +  CmdArgs.push_back("-lpthread"); +  if (!TC.getTriple().isOSOpenBSD()) +    CmdArgs.push_back("-lrt"); +  CmdArgs.push_back("-lm"); + +  if (!TC.getTriple().isOSFreeBSD() && +      !TC.getTriple().isOSNetBSD() && +      !TC.getTriple().isOSOpenBSD()) +    CmdArgs.push_back("-ldl"); +} + +bool tools::areOptimizationsEnabled(const ArgList &Args) { +  // Find the last -O arg and see if it is non-zero. +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) +    return !A->getOption().matches(options::OPT_O0); +  // Defaults to -O0. +  return false; +} + +const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input, +                                  const InputInfo &Output) { +  if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ)) +    if (StringRef(A->getValue()) == "single") +      return Args.MakeArgString(Output.getFilename()); + +  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(Input.getBaseInput())); +    llvm::sys::path::replace_extension(F, "dwo"); +    T += F; +    return Args.MakeArgString(F); +  } +} + +void tools::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(CLANG_DEFAULT_OBJCOPY)); +  InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); + +  // First extract the dwo sections. +  C.addCommand(std::make_unique<Command>(JA, T, Exec, ExtractArgs, II)); + +  // Then remove them from the original .o file. +  C.addCommand(std::make_unique<Command>(JA, T, Exec, StripArgs, II)); +} + +// Claim options we don't want to warn if they are unused. We do this for +// options that build systems might add but are unused when assembling or only +// running the preprocessor for example. +void tools::claimNoWarnArgs(const ArgList &Args) { +  // Don't warn about unused -f(no-)?lto.  This can happen when we're +  // preprocessing, precompiling or assembling. +  Args.ClaimAllArgs(options::OPT_flto_EQ); +  Args.ClaimAllArgs(options::OPT_flto); +  Args.ClaimAllArgs(options::OPT_fno_lto); +} + +Arg *tools::getLastProfileUseArg(const ArgList &Args) { +  auto *ProfileUseArg = Args.getLastArg( +      options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, +      options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, +      options::OPT_fno_profile_instr_use); + +  if (ProfileUseArg && +      ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) +    ProfileUseArg = nullptr; + +  return ProfileUseArg; +} + +Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) { +  auto *ProfileSampleUseArg = Args.getLastArg( +      options::OPT_fprofile_sample_use, options::OPT_fprofile_sample_use_EQ, +      options::OPT_fauto_profile, options::OPT_fauto_profile_EQ, +      options::OPT_fno_profile_sample_use, options::OPT_fno_auto_profile); + +  if (ProfileSampleUseArg && +      (ProfileSampleUseArg->getOption().matches( +           options::OPT_fno_profile_sample_use) || +       ProfileSampleUseArg->getOption().matches(options::OPT_fno_auto_profile))) +    return nullptr; + +  return Args.getLastArg(options::OPT_fprofile_sample_use_EQ, +                         options::OPT_fauto_profile_EQ); +} + +/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments.  Then, +/// smooshes them together with platform defaults, to decide whether +/// this compile should be using PIC mode or not. Returns a tuple of +/// (RelocationModel, PICLevel, IsPIE). +std::tuple<llvm::Reloc::Model, unsigned, bool> +tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { +  const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); +  const llvm::Triple &Triple = ToolChain.getTriple(); + +  bool PIE = ToolChain.isPIEDefault(); +  bool PIC = PIE || ToolChain.isPICDefault(); +  // The Darwin/MachO default to use PIC does not apply when using -static. +  if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) +    PIE = PIC = false; +  bool IsPICLevelTwo = PIC; + +  bool KernelOrKext = +      Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); + +  // Android-specific defaults for PIC/PIE +  if (Triple.isAndroid()) { +    switch (Triple.getArch()) { +    case llvm::Triple::arm: +    case llvm::Triple::armeb: +    case llvm::Triple::thumb: +    case llvm::Triple::thumbeb: +    case llvm::Triple::aarch64: +    case llvm::Triple::mips: +    case llvm::Triple::mipsel: +    case llvm::Triple::mips64: +    case llvm::Triple::mips64el: +      PIC = true; // "-fpic" +      break; + +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      PIC = true; // "-fPIC" +      IsPICLevelTwo = true; +      break; + +    default: +      break; +    } +  } + +  // OpenBSD-specific defaults for PIE +  if (Triple.isOSOpenBSD()) { +    switch (ToolChain.getArch()) { +    case llvm::Triple::arm: +    case llvm::Triple::aarch64: +    case llvm::Triple::mips64: +    case llvm::Triple::mips64el: +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      IsPICLevelTwo = false; // "-fpie" +      break; + +    case llvm::Triple::ppc: +    case llvm::Triple::sparc: +    case llvm::Triple::sparcel: +    case llvm::Triple::sparcv9: +      IsPICLevelTwo = true; // "-fPIE" +      break; + +    default: +      break; +    } +  } + +  // AMDGPU-specific defaults for PIC. +  if (Triple.getArch() == llvm::Triple::amdgcn) +    PIC = true; + +  // The last argument relating to either PIC or PIE wins, and no +  // other argument is used. If the last argument is any flavor of the +  // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE +  // option implicitly enables PIC at the same level. +  Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, +                                    options::OPT_fpic, options::OPT_fno_pic, +                                    options::OPT_fPIE, options::OPT_fno_PIE, +                                    options::OPT_fpie, options::OPT_fno_pie); +  if (Triple.isOSWindows() && LastPICArg && +      LastPICArg == +          Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, +                          options::OPT_fPIE, options::OPT_fpie)) { +    ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) +        << LastPICArg->getSpelling() << Triple.str(); +    if (Triple.getArch() == llvm::Triple::x86_64) +      return std::make_tuple(llvm::Reloc::PIC_, 2U, false); +    return std::make_tuple(llvm::Reloc::Static, 0U, false); +  } + +  // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness +  // is forced, then neither PIC nor PIE flags will have no effect. +  if (!ToolChain.isPICDefaultForced()) { +    if (LastPICArg) { +      Option O = LastPICArg->getOption(); +      if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || +          O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { +        PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); +        PIC = +            PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); +        IsPICLevelTwo = +            O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); +      } else { +        PIE = PIC = false; +        if (EffectiveTriple.isPS4CPU()) { +          Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); +          StringRef Model = ModelArg ? ModelArg->getValue() : ""; +          if (Model != "kernel") { +            PIC = true; +            ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) +                << LastPICArg->getSpelling(); +          } +        } +      } +    } +  } + +  // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the +  // PIC level would've been set to level 1, force it back to level 2 PIC +  // instead. +  if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) +    IsPICLevelTwo |= ToolChain.isPICDefault(); + +  // This kernel flags are a trump-card: they will disable PIC/PIE +  // generation, independent of the argument order. +  if (KernelOrKext && +      ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && +       !EffectiveTriple.isWatchOS())) +    PIC = PIE = false; + +  if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { +    // This is a very special mode. It trumps the other modes, almost no one +    // uses it, and it isn't even valid on any OS but Darwin. +    if (!Triple.isOSDarwin()) +      ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) +          << A->getSpelling() << Triple.str(); + +    // FIXME: Warn when this flag trumps some other PIC or PIE flag. + +    // Only a forced PIC mode can cause the actual compile to have PIC defines +    // etc., no flags are sufficient. This behavior was selected to closely +    // match that of llvm-gcc and Apple GCC before that. +    PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); + +    return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false); +  } + +  bool EmbeddedPISupported; +  switch (Triple.getArch()) { +    case llvm::Triple::arm: +    case llvm::Triple::armeb: +    case llvm::Triple::thumb: +    case llvm::Triple::thumbeb: +      EmbeddedPISupported = true; +      break; +    default: +      EmbeddedPISupported = false; +      break; +  } + +  bool ROPI = false, RWPI = false; +  Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi); +  if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) { +    if (!EmbeddedPISupported) +      ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) +          << LastROPIArg->getSpelling() << Triple.str(); +    ROPI = true; +  } +  Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi); +  if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) { +    if (!EmbeddedPISupported) +      ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) +          << LastRWPIArg->getSpelling() << Triple.str(); +    RWPI = true; +  } + +  // ROPI and RWPI are not compatible with PIC or PIE. +  if ((ROPI || RWPI) && (PIC || PIE)) +    ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic); + +  if (Triple.isMIPS()) { +    StringRef CPUName; +    StringRef ABIName; +    mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); +    // When targeting the N64 ABI, PIC is the default, except in the case +    // when the -mno-abicalls option is used. In that case we exit +    // at next check regardless of PIC being set below. +    if (ABIName == "n64") +      PIC = true; +    // When targettng MIPS with -mno-abicalls, it's always static. +    if(Args.hasArg(options::OPT_mno_abicalls)) +      return std::make_tuple(llvm::Reloc::Static, 0U, false); +    // Unlike other architectures, MIPS, even with -fPIC/-mxgot/multigot, +    // does not use PIC level 2 for historical reasons. +    IsPICLevelTwo = false; +  } + +  if (PIC) +    return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE); + +  llvm::Reloc::Model RelocM = llvm::Reloc::Static; +  if (ROPI && RWPI) +    RelocM = llvm::Reloc::ROPI_RWPI; +  else if (ROPI) +    RelocM = llvm::Reloc::ROPI; +  else if (RWPI) +    RelocM = llvm::Reloc::RWPI; + +  return std::make_tuple(RelocM, 0U, false); +} + +// `-falign-functions` indicates that the functions should be aligned to a +// 16-byte boundary. +// +// `-falign-functions=1` is the same as `-fno-align-functions`. +// +// The scalar `n` in `-falign-functions=n` must be an integral value between +// [0, 65536].  If the value is not a power-of-two, it will be rounded up to +// the nearest power-of-two. +// +// If we return `0`, the frontend will default to the backend's preferred +// alignment. +// +// NOTE: icc only allows values between [0, 4096].  icc uses `-falign-functions` +// to mean `-falign-functions=16`.  GCC defaults to the backend's preferred +// alignment.  For unaligned functions, we default to the backend's preferred +// alignment. +unsigned tools::ParseFunctionAlignment(const ToolChain &TC, +                                       const ArgList &Args) { +  const Arg *A = Args.getLastArg(options::OPT_falign_functions, +                                 options::OPT_falign_functions_EQ, +                                 options::OPT_fno_align_functions); +  if (!A || A->getOption().matches(options::OPT_fno_align_functions)) +    return 0; + +  if (A->getOption().matches(options::OPT_falign_functions)) +    return 0; + +  unsigned Value = 0; +  if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536) +    TC.getDriver().Diag(diag::err_drv_invalid_int_value) +        << A->getAsString(Args) << A->getValue(); +  return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value; +} + +void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, +                             ArgStringList &CmdArgs) { +  llvm::Reloc::Model RelocationModel; +  unsigned PICLevel; +  bool IsPIE; +  std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args); + +  if (RelocationModel != llvm::Reloc::Static) +    CmdArgs.push_back("-KPIC"); +} + +/// Determine whether Objective-C automated reference counting is +/// enabled. +bool tools::isObjCAutoRefCount(const ArgList &Args) { +  return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); +} + +enum class LibGccType { UnspecifiedLibGcc, StaticLibGcc, SharedLibGcc }; + +static LibGccType getLibGccType(const Driver &D, const ArgList &Args) { +  if (Args.hasArg(options::OPT_static_libgcc) || +      Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie)) +    return LibGccType::StaticLibGcc; +  if (Args.hasArg(options::OPT_shared_libgcc) || D.CCCIsCXX()) +    return LibGccType::SharedLibGcc; +  return LibGccType::UnspecifiedLibGcc; +} + +// Gcc adds libgcc arguments in various ways: +// +// gcc <none>:     -lgcc --as-needed -lgcc_s --no-as-needed +// g++ <none>:                       -lgcc_s               -lgcc +// gcc shared:                       -lgcc_s               -lgcc +// g++ shared:                       -lgcc_s               -lgcc +// gcc static:     -lgcc             -lgcc_eh +// g++ static:     -lgcc             -lgcc_eh +// gcc static-pie: -lgcc             -lgcc_eh +// g++ static-pie: -lgcc             -lgcc_eh +// +// Also, certain targets need additional adjustments. + +static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, +                             ArgStringList &CmdArgs, const ArgList &Args) { +  ToolChain::UnwindLibType UNW = TC.GetUnwindLibType(Args); +  // Targets that don't use unwind libraries. +  if (TC.getTriple().isAndroid() || TC.getTriple().isOSIAMCU() || +      TC.getTriple().isOSBinFormatWasm() || +      UNW == ToolChain::UNW_None) +    return; + +  LibGccType LGT = getLibGccType(D, Args); +  bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc && +                  !TC.getTriple().isAndroid() && !TC.getTriple().isOSCygMing(); +  if (AsNeeded) +    CmdArgs.push_back("--as-needed"); + +  switch (UNW) { +  case ToolChain::UNW_None: +    return; +  case ToolChain::UNW_Libgcc: { +    if (LGT == LibGccType::StaticLibGcc) +      CmdArgs.push_back("-lgcc_eh"); +    else +      CmdArgs.push_back("-lgcc_s"); +    break; +  } +  case ToolChain::UNW_CompilerRT: +    CmdArgs.push_back("-lunwind"); +    break; +  } + +  if (AsNeeded) +    CmdArgs.push_back("--no-as-needed"); +} + +static void AddLibgcc(const ToolChain &TC, const Driver &D, +                      ArgStringList &CmdArgs, const ArgList &Args) { +  LibGccType LGT = getLibGccType(D, Args); +  if (LGT != LibGccType::SharedLibGcc) +    CmdArgs.push_back("-lgcc"); +  AddUnwindLibrary(TC, D, CmdArgs, Args); +  if (LGT == LibGccType::SharedLibGcc) +    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 (TC.getTriple().isAndroid() && LGT != LibGccType::StaticLibGcc) +    CmdArgs.push_back("-ldl"); +} + +void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, +                           ArgStringList &CmdArgs, const ArgList &Args) { +  // Make use of compiler-rt if --rtlib option is used +  ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args); + +  switch (RLT) { +  case ToolChain::RLT_CompilerRT: +    CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); +    AddUnwindLibrary(TC, D, CmdArgs, Args); +    break; +  case ToolChain::RLT_Libgcc: +    // Make sure libgcc is not used under MSVC environment by default +    if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { +      // Issue error diagnostic if libgcc is explicitly specified +      // through command line as --rtlib option argument. +      if (Args.hasArg(options::OPT_rtlib_EQ)) { +        TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) +            << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; +      } +    } else +      AddLibgcc(TC, D, CmdArgs, Args); +    break; +  } +} + +/// Add HIP linker script arguments at the end of the argument list so that +/// the fat binary is built by embedding the device images into the host. The +/// linker script also defines a symbol required by the code generation so that +/// the image can be retrieved at runtime. This should be used only in tool +/// chains that support linker scripts. +void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C, +                               const InputInfo &Output, +                               const InputInfoList &Inputs, const ArgList &Args, +                               ArgStringList &CmdArgs, const JobAction &JA, +                               const Tool &T) { + +  // If this is not a HIP host toolchain, we don't need to do anything. +  if (!JA.isHostOffloading(Action::OFK_HIP)) +    return; + +  InputInfoList DeviceInputs; +  for (const auto &II : Inputs) { +    const Action *A = II.getAction(); +    // Is this a device linking action? +    if (A && isa<LinkJobAction>(A) && A->isDeviceOffloading(Action::OFK_HIP)) { +      DeviceInputs.push_back(II); +    } +  } + +  if (DeviceInputs.empty()) +    return; + +  // Create temporary linker script. Keep it if save-temps is enabled. +  const char *LKS; +  std::string Name = llvm::sys::path::filename(Output.getFilename()); +  if (C.getDriver().isSaveTempsEnabled()) { +    LKS = C.getArgs().MakeArgString(Name + ".lk"); +  } else { +    auto TmpName = C.getDriver().GetTemporaryPath(Name, "lk"); +    LKS = C.addTempFile(C.getArgs().MakeArgString(TmpName)); +  } + +  // Add linker script option to the command. +  CmdArgs.push_back("-T"); +  CmdArgs.push_back(LKS); + +  // Create a buffer to write the contents of the linker script. +  std::string LksBuffer; +  llvm::raw_string_ostream LksStream(LksBuffer); + +  // Get the HIP offload tool chain. +  auto *HIPTC = static_cast<const toolchains::CudaToolChain *>( +      C.getSingleOffloadToolChain<Action::OFK_HIP>()); +  assert(HIPTC->getTriple().getArch() == llvm::Triple::amdgcn && +         "Wrong platform"); +  (void)HIPTC; + +  const char *BundleFile; +  if (C.getDriver().isSaveTempsEnabled()) { +    BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); +  } else { +    auto TmpName = C.getDriver().GetTemporaryPath(Name, "hipfb"); +    BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpName)); +  } +  AMDGCN::constructHIPFatbinCommand(C, JA, BundleFile, DeviceInputs, Args, T); + +  // Add commands to embed target binaries. We ensure that each section and +  // image is 16-byte aligned. This is not mandatory, but increases the +  // likelihood of data to be aligned with a cache block in several main host +  // machines. +  LksStream << "/*\n"; +  LksStream << "       HIP Offload Linker Script\n"; +  LksStream << " *** Automatically generated by Clang ***\n"; +  LksStream << "*/\n"; +  LksStream << "TARGET(binary)\n"; +  LksStream << "INPUT(" << BundleFile << ")\n"; +  LksStream << "SECTIONS\n"; +  LksStream << "{\n"; +  LksStream << "  .hip_fatbin :\n"; +  LksStream << "  ALIGN(0x10)\n"; +  LksStream << "  {\n"; +  LksStream << "    PROVIDE_HIDDEN(__hip_fatbin = .);\n"; +  LksStream << "    " << BundleFile << "\n"; +  LksStream << "  }\n"; +  LksStream << "  /DISCARD/ :\n"; +  LksStream << "  {\n"; +  LksStream << "    * ( __CLANG_OFFLOAD_BUNDLE__* )\n"; +  LksStream << "  }\n"; +  LksStream << "}\n"; +  LksStream << "INSERT BEFORE .data\n"; +  LksStream.flush(); + +  // Dump the contents of the linker script if the user requested that. We +  // support this option to enable testing of behavior with -###. +  if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) +    llvm::errs() << LksBuffer; + +  // If this is a dry run, do not create the linker script file. +  if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) +    return; + +  // Open script file and write the contents. +  std::error_code EC; +  llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::OF_None); + +  if (EC) { +    C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); +    return; +  } + +  Lksf << LksBuffer; +} + +SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args, +                                         const InputInfo &Output, +                                         const InputInfo &Input, +                                         const Driver &D) { +  const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ); +  if (!A) +    return {}; + +  StringRef SaveStats = A->getValue(); +  SmallString<128> StatsFile; +  if (SaveStats == "obj" && Output.isFilename()) { +    StatsFile.assign(Output.getFilename()); +    llvm::sys::path::remove_filename(StatsFile); +  } else if (SaveStats != "cwd") { +    D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; +    return {}; +  } + +  StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); +  llvm::sys::path::append(StatsFile, BaseName); +  llvm::sys::path::replace_extension(StatsFile, "stats"); +  return StatsFile; +} + +void tools::addMultilibFlag(bool Enabled, const char *const Flag, +                            Multilib::flags_list &Flags) { +  Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); +} + +static void getWebAssemblyTargetFeatures(const ArgList &Args, +                                         std::vector<StringRef> &Features) { +  handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); +} + +void tools::getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, +                       const ArgList &Args, ArgStringList &CmdArgs, bool ForAS, +                       bool ForLTOPlugin) { + +  const Driver &D = TC.getDriver(); +  std::vector<StringRef> Features; +  switch (Triple.getArch()) { +  default: +    break; +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: +    mips::getMIPSTargetFeatures(D, Triple, Args, Features); +    break; + +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +    arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); +    break; + +  case llvm::Triple::ppc: +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: +    ppc::getPPCTargetFeatures(D, Triple, Args, Features); +    break; +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +    riscv::getRISCVTargetFeatures(D, Triple, Args, Features); +    break; +  case llvm::Triple::systemz: +    systemz::getSystemZTargetFeatures(Args, Features); +    break; +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: +    aarch64::getAArch64TargetFeatures(D, Triple, Args, Features); +    break; +  case llvm::Triple::x86: +  case llvm::Triple::x86_64: +    x86::getX86TargetFeatures(D, Triple, Args, Features); +    break; +  case llvm::Triple::hexagon: +    hexagon::getHexagonTargetFeatures(D, Args, Features); +    break; +  case llvm::Triple::wasm32: +  case llvm::Triple::wasm64: +    getWebAssemblyTargetFeatures(Args, Features); +    break; +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +  case llvm::Triple::sparcv9: +    sparc::getSparcTargetFeatures(D, Args, Features); +    break; +  case llvm::Triple::r600: +  case llvm::Triple::amdgcn: +    amdgpu::getAMDGPUTargetFeatures(D, Args, Features); +    break; +  case llvm::Triple::msp430: +    msp430::getMSP430TargetFeatures(D, Args, Features); +  } + +  // Find the last of each feature. +  llvm::StringMap<unsigned> LastOpt; +  for (unsigned I = 0, N = Features.size(); I < N; ++I) { +    StringRef Name = Features[I]; +    assert(Name[0] == '-' || Name[0] == '+'); +    LastOpt[Name.drop_front(1)] = I; +  } + +  for (unsigned I = 0, N = Features.size(); I < N; ++I) { +    // If this feature was overridden, ignore it. +    StringRef Name = Features[I]; +    llvm::StringMap<unsigned>::iterator LastI = +        LastOpt.find(Name.drop_front(1)); +    assert(LastI != LastOpt.end()); +    unsigned Last = LastI->second; +    if (Last != I) +      continue; +    if (!ForLTOPlugin) { +      CmdArgs.push_back("-target-feature"); +      CmdArgs.push_back(Name.data()); +    } else { +      CmdArgs.push_back( +          Args.MakeArgString(Twine("-plugin-opt=-mattr=") + Name)); +    } +  } +} + +StringRef tools::getTargetABI(const ArgList &Args, const llvm::Triple &Triple) { +  // TODO: Support the other target ABI +  switch (Triple.getArch()) { +  default: +    break; +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +    return tools::riscv::getRISCVABI(Args, Triple); +    break; +  } +  return StringRef(); +} diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h new file mode 100644 index 0000000000000..79468e6b89262 --- /dev/null +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -0,0 +1,133 @@ +//===--- CommonArgs.h - Args handling for multiple toolchains ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H + +#include "InputInfo.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Multilib.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/Support/CodeGen.h" + +namespace clang { +namespace driver { +namespace tools { + +void addPathIfExists(const Driver &D, const Twine &Path, +                     ToolChain::path_list &Paths); + +void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, +                     const llvm::opt::ArgList &Args, +                     llvm::opt::ArgStringList &CmdArgs, const JobAction &JA); + +void claimNoWarnArgs(const llvm::opt::ArgList &Args); + +bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs); + +void linkSanitizerRuntimeDeps(const ToolChain &TC, +                              llvm::opt::ArgStringList &CmdArgs); + +bool addXRayRuntime(const ToolChain &TC, const llvm::opt::ArgList &Args, +                    llvm::opt::ArgStringList &CmdArgs); + +void linkXRayRuntimeDeps(const ToolChain &TC, +                         llvm::opt::ArgStringList &CmdArgs); + +void AddRunTimeLibs(const ToolChain &TC, const Driver &D, +                    llvm::opt::ArgStringList &CmdArgs, +                    const llvm::opt::ArgList &Args); + +void AddHIPLinkerScript(const ToolChain &TC, Compilation &C, +                        const InputInfo &Output, const InputInfoList &Inputs, +                        const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs, const JobAction &JA, +                        const Tool &T); + +const char *SplitDebugName(const llvm::opt::ArgList &Args, +                           const InputInfo &Input, const InputInfo &Output); + +void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, +                    const JobAction &JA, const llvm::opt::ArgList &Args, +                    const InputInfo &Output, const char *OutFile); + +void AddGoldPlugin(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, +                   llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, +                   const InputInfo &Input, bool IsThinLTO); + +std::tuple<llvm::Reloc::Model, unsigned, bool> +ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); + +unsigned ParseFunctionAlignment(const ToolChain &TC, +                                const llvm::opt::ArgList &Args); + +void AddAssemblerKPIC(const ToolChain &ToolChain, +                      const llvm::opt::ArgList &Args, +                      llvm::opt::ArgStringList &CmdArgs); + +void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args, +                          llvm::opt::ArgStringList &CmdArgs); +/// Returns true, if an OpenMP runtime has been added. +bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, +                      const llvm::opt::ArgList &Args, +                      bool ForceStaticHostRuntime = false, +                      bool IsOffloadingHost = false, bool GompNeedsRT = false); + +llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); +llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); + +bool isObjCAutoRefCount(const llvm::opt::ArgList &Args); + +unsigned getLTOParallelism(const llvm::opt::ArgList &Args, const Driver &D); + +bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); + +bool isUseSeparateSections(const llvm::Triple &Triple); + +void addDirectoryList(const llvm::opt::ArgList &Args, +                      llvm::opt::ArgStringList &CmdArgs, const char *ArgName, +                      const char *EnvVar); + +void AddTargetFeature(const llvm::opt::ArgList &Args, +                      std::vector<StringRef> &Features, +                      llvm::opt::OptSpecifier OnOpt, +                      llvm::opt::OptSpecifier OffOpt, StringRef FeatureName); + +std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T, +                       bool FromAs = false); + +void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, +                               std::vector<StringRef> &Features, +                               llvm::opt::OptSpecifier Group); + +/// Handles the -save-stats option and returns the filename to save statistics +/// to. +SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, +                                  const InputInfo &Output, +                                  const InputInfo &Input, const Driver &D); + +/// \p Flag must be a flag accepted by the driver with its leading '-' removed, +//     otherwise '-print-multi-lib' will not emit them correctly. +void addMultilibFlag(bool Enabled, const char *const Flag, +                     Multilib::flags_list &Flags); + +StringRef getTargetABI(const llvm::opt::ArgList &Args, +                       const llvm::Triple &Triple); + +void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, +                       const llvm::opt::ArgList &Args, +                       llvm::opt::ArgStringList &CmdArgs, bool ForAS, +                       bool ForLTOPlugin = false); + +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H diff --git a/clang/lib/Driver/ToolChains/Contiki.cpp b/clang/lib/Driver/ToolChains/Contiki.cpp new file mode 100644 index 0000000000000..5dda1b1b09fbb --- /dev/null +++ b/clang/lib/Driver/ToolChains/Contiki.cpp @@ -0,0 +1,27 @@ +//===--- Contiki.cpp - Contiki ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Contiki.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, +                 const ArgList &Args) +    : Generic_ELF(D, Triple, Args) {} + +SanitizerMask Contiki::getSupportedSanitizers() const { +  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  if (IsX86) +    Res |= SanitizerKind::SafeStack; +  return Res; +} diff --git a/clang/lib/Driver/ToolChains/Contiki.h b/clang/lib/Driver/ToolChains/Contiki.h new file mode 100644 index 0000000000000..627d80bdda093 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Contiki.h @@ -0,0 +1,39 @@ +//===--- Contiki.h - Contiki ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF { +public: +  Contiki(const Driver &D, const llvm::Triple &Triple, +          const llvm::opt::ArgList &Args); + +  // No support for finding a C++ standard library yet. +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override {} +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override {} + +  SanitizerMask getSupportedSanitizers() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H diff --git a/clang/lib/Driver/ToolChains/CrossWindows.cpp b/clang/lib/Driver/ToolChains/CrossWindows.cpp new file mode 100644 index 0000000000000..dbf6114eb2ecc --- /dev/null +++ b/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -0,0 +1,291 @@ +//===-- CrossWindows.cpp - Cross Windows Tool Chain -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CrossWindows.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; + +using llvm::opt::ArgList; +using llvm::opt::ArgStringList; + +void tools::CrossWindows::Assembler::ConstructJob( +    Compilation &C, const JobAction &JA, const InputInfo &Output, +    const InputInfoList &Inputs, const ArgList &Args, +    const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  const auto &TC = +      static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain()); +  ArgStringList CmdArgs; +  const char *Exec; + +  switch (TC.getArch()) { +  default: +    llvm_unreachable("unsupported architecture"); +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +  case llvm::Triple::aarch64: +    break; +  case llvm::Triple::x86: +    CmdArgs.push_back("--32"); +    break; +  case llvm::Triple::x86_64: +    CmdArgs.push_back("--64"); +    break; +  } + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &Input : Inputs) +    CmdArgs.push_back(Input.getFilename()); + +  const std::string Assembler = TC.GetProgramPath("as"); +  Exec = Args.MakeArgString(Assembler); + +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::CrossWindows::Linker::ConstructJob( +    Compilation &C, const JobAction &JA, const InputInfo &Output, +    const InputInfoList &Inputs, const ArgList &Args, +    const char *LinkingOutput) const { +  const auto &TC = +      static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain()); +  const llvm::Triple &T = TC.getTriple(); +  const Driver &D = TC.getDriver(); +  SmallString<128> EntryPoint; +  ArgStringList CmdArgs; +  const char *Exec; + +  // 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" +  Args.ClaimAllArgs(options::OPT_w); +  // Other warning options are already handled somewhere else. + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_pie)) +    CmdArgs.push_back("-pie"); +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("--strip-all"); + +  CmdArgs.push_back("-m"); +  switch (TC.getArch()) { +  default: +    llvm_unreachable("unsupported architecture"); +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    // FIXME: this is incorrect for WinCE +    CmdArgs.push_back("thumb2pe"); +    break; +  case llvm::Triple::aarch64: +    CmdArgs.push_back("arm64pe"); +    break; +  case llvm::Triple::x86: +    CmdArgs.push_back("i386pe"); +    EntryPoint.append("_"); +    break; +  case llvm::Triple::x86_64: +    CmdArgs.push_back("i386pep"); +    break; +  } + +  if (Args.hasArg(options::OPT_shared)) { +    switch (T.getArch()) { +    default: +      llvm_unreachable("unsupported architecture"); +    case llvm::Triple::aarch64: +    case llvm::Triple::arm: +    case llvm::Triple::thumb: +    case llvm::Triple::x86_64: +      EntryPoint.append("_DllMainCRTStartup"); +      break; +    case llvm::Triple::x86: +      EntryPoint.append("_DllMainCRTStartup@12"); +      break; +    } + +    CmdArgs.push_back("-shared"); +    CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic" +                                                       : "-Bdynamic"); + +    CmdArgs.push_back("--enable-auto-image-base"); + +    CmdArgs.push_back("--entry"); +    CmdArgs.push_back(Args.MakeArgString(EntryPoint)); +  } else { +    EntryPoint.append("mainCRTStartup"); + +    CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic" +                                                       : "-Bdynamic"); + +    if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +      CmdArgs.push_back("--entry"); +      CmdArgs.push_back(Args.MakeArgString(EntryPoint)); +    } + +    // FIXME: handle subsystem +  } + +  // NOTE: deal with multiple definitions on Windows (e.g. COMDAT) +  CmdArgs.push_back("--allow-multiple-definition"); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) { +    SmallString<261> ImpLib(Output.getFilename()); +    llvm::sys::path::replace_extension(ImpLib, ".lib"); + +    CmdArgs.push_back("--out-implib"); +    CmdArgs.push_back(Args.MakeArgString(ImpLib)); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  TC.AddFilePathLibArgs(Args, CmdArgs); +  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + +  if (TC.ShouldLinkCXXStdlib(Args)) { +    bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && +                     !Args.hasArg(options::OPT_static); +    if (StaticCXX) +      CmdArgs.push_back("-Bstatic"); +    TC.AddCXXStdlibLibArgs(Args, CmdArgs); +    if (StaticCXX) +      CmdArgs.push_back("-Bdynamic"); +  } + +  if (!Args.hasArg(options::OPT_nostdlib)) { +    if (!Args.hasArg(options::OPT_nodefaultlibs)) { +      // TODO handle /MT[d] /MD[d] +      CmdArgs.push_back("-lmsvcrt"); +      AddRunTimeLibs(TC, D, CmdArgs, Args); +    } +  } + +  if (TC.getSanitizerArgs().needsAsanRt()) { +    // TODO handle /MT[d] /MD[d] +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); +    } else { +      for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) +        CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); +      // Make sure the dynamic runtime thunk is not optimized out at link time +      // to ensure proper SEH handling. +      CmdArgs.push_back(Args.MakeArgString("--undefined")); +      CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86 +                                               ? "___asan_seh_interceptor" +                                               : "__asan_seh_interceptor")); +    } +  } + +  Exec = Args.MakeArgString(TC.GetLinkerPath()); + +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, +                                             const llvm::Triple &T, +                                             const llvm::opt::ArgList &Args) +    : Generic_GCC(D, T, Args) {} + +bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +  // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does +  // not know how to emit them. +  return getArch() == llvm::Triple::x86_64; +} + +bool CrossWindowsToolChain::isPICDefault() const { +  return getArch() == llvm::Triple::x86_64; +} + +bool CrossWindowsToolChain::isPIEDefault() const { +  return getArch() == llvm::Triple::x86_64; +} + +bool CrossWindowsToolChain::isPICDefaultForced() const { +  return getArch() == llvm::Triple::x86_64; +} + +void CrossWindowsToolChain:: +AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); +  const std::string &SysRoot = D.SysRoot; + +  auto AddSystemAfterIncludes = [&]() { +    for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) +      addSystemInclude(DriverArgs, CC1Args, P); +  }; + +  if (DriverArgs.hasArg(options::OPT_nostdinc)) { +    AddSystemAfterIncludes(); +    return; +  } + +  addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> ResourceDir(D.ResourceDir); +    llvm::sys::path::append(ResourceDir, "include"); +    addSystemInclude(DriverArgs, CC1Args, ResourceDir); +  } +  AddSystemAfterIncludes(); +  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} + +void CrossWindowsToolChain:: +AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args) const { +  const std::string &SysRoot = getDriver().SysRoot; + +  if (DriverArgs.hasArg(options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) +    addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1"); +} + +void CrossWindowsToolChain:: +AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs, +                    llvm::opt::ArgStringList &CC1Args) const { +  if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) +    CC1Args.push_back("-lc++"); +} + +clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  return Res; +} + +Tool *CrossWindowsToolChain::buildLinker() const { +  return new tools::CrossWindows::Linker(*this); +} + +Tool *CrossWindowsToolChain::buildAssembler() const { +  return new tools::CrossWindows::Assembler(*this); +} diff --git a/clang/lib/Driver/ToolChains/CrossWindows.h b/clang/lib/Driver/ToolChains/CrossWindows.h new file mode 100644 index 0000000000000..7267a35d48b94 --- /dev/null +++ b/clang/lib/Driver/ToolChains/CrossWindows.h @@ -0,0 +1,87 @@ +//===--- CrossWindows.h - CrossWindows ToolChain Implementation -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H + +#include "Cuda.h" +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace CrossWindows { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: +  Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) +      : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace CrossWindows +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC { +public: +  CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, +                        const llvm::opt::ArgList &Args); + +  bool IsIntegratedAssemblerDefault() const override { return true; } +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; + +  unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override { +    return 0; +  } + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  SanitizerMask getSupportedSanitizers() const override; + +protected: +  Tool *buildLinker() const override; +  Tool *buildAssembler() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp new file mode 100644 index 0000000000000..8c704a3078adc --- /dev/null +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -0,0 +1,885 @@ +//===--- Cuda.cpp - Cuda Tool and ToolChain Implementations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Cuda.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Basic/Cuda.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Distro.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +// Parses the contents of version.txt in an CUDA installation.  It should +// contain one line of the from e.g. "CUDA Version 7.5.2". +static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { +  if (!V.startswith("CUDA Version ")) +    return CudaVersion::UNKNOWN; +  V = V.substr(strlen("CUDA Version ")); +  int Major = -1, Minor = -1; +  auto First = V.split('.'); +  auto Second = First.second.split('.'); +  if (First.first.getAsInteger(10, Major) || +      Second.first.getAsInteger(10, Minor)) +    return CudaVersion::UNKNOWN; + +  if (Major == 7 && Minor == 0) { +    // This doesn't appear to ever happen -- version.txt doesn't exist in the +    // CUDA 7 installs I've seen.  But no harm in checking. +    return CudaVersion::CUDA_70; +  } +  if (Major == 7 && Minor == 5) +    return CudaVersion::CUDA_75; +  if (Major == 8 && Minor == 0) +    return CudaVersion::CUDA_80; +  if (Major == 9 && Minor == 0) +    return CudaVersion::CUDA_90; +  if (Major == 9 && Minor == 1) +    return CudaVersion::CUDA_91; +  if (Major == 9 && Minor == 2) +    return CudaVersion::CUDA_92; +  if (Major == 10 && Minor == 0) +    return CudaVersion::CUDA_100; +  if (Major == 10 && Minor == 1) +    return CudaVersion::CUDA_101; +  return CudaVersion::UNKNOWN; +} + +CudaInstallationDetector::CudaInstallationDetector( +    const Driver &D, const llvm::Triple &HostTriple, +    const llvm::opt::ArgList &Args) +    : D(D) { +  struct Candidate { +    std::string Path; +    bool StrictChecking; + +    Candidate(std::string Path, bool StrictChecking = false) +        : Path(Path), StrictChecking(StrictChecking) {} +  }; +  SmallVector<Candidate, 4> Candidates; + +  // In decreasing order so we prefer newer versions to older versions. +  std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; + +  if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) { +    Candidates.emplace_back( +        Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ).str()); +  } else if (HostTriple.isOSWindows()) { +    for (const char *Ver : Versions) +      Candidates.emplace_back( +          D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + +          Ver); +  } else { +    if (!Args.hasArg(clang::driver::options::OPT_cuda_path_ignore_env)) { +      // Try to find ptxas binary. If the executable is located in a directory +      // called 'bin/', its parent directory might be a good guess for a valid +      // CUDA installation. +      // However, some distributions might installs 'ptxas' to /usr/bin. In that +      // case the candidate would be '/usr' which passes the following checks +      // because '/usr/include' exists as well. To avoid this case, we always +      // check for the directory potentially containing files for libdevice, +      // even if the user passes -nocudalib. +      if (llvm::ErrorOr<std::string> ptxas = +              llvm::sys::findProgramByName("ptxas")) { +        SmallString<256> ptxasAbsolutePath; +        llvm::sys::fs::real_path(*ptxas, ptxasAbsolutePath); + +        StringRef ptxasDir = llvm::sys::path::parent_path(ptxasAbsolutePath); +        if (llvm::sys::path::filename(ptxasDir) == "bin") +          Candidates.emplace_back(llvm::sys::path::parent_path(ptxasDir), +                                  /*StrictChecking=*/true); +      } +    } + +    Candidates.emplace_back(D.SysRoot + "/usr/local/cuda"); +    for (const char *Ver : Versions) +      Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver); + +    if (Distro(D.getVFS()).IsDebian() || Distro(D.getVFS()).IsUbuntu()) +      // Special case for Debian to have nvidia-cuda-toolkit work +      // out of the box. More info on http://bugs.debian.org/882505 +      Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda"); +  } + +  bool NoCudaLib = Args.hasArg(options::OPT_nogpulib); + +  for (const auto &Candidate : Candidates) { +    InstallPath = Candidate.Path; +    if (InstallPath.empty() || !D.getVFS().exists(InstallPath)) +      continue; + +    BinPath = InstallPath + "/bin"; +    IncludePath = InstallPath + "/include"; +    LibDevicePath = InstallPath + "/nvvm/libdevice"; + +    auto &FS = D.getVFS(); +    if (!(FS.exists(IncludePath) && FS.exists(BinPath))) +      continue; +    bool CheckLibDevice = (!NoCudaLib || Candidate.StrictChecking); +    if (CheckLibDevice && !FS.exists(LibDevicePath)) +      continue; + +    // On Linux, we have both lib and lib64 directories, and we need to choose +    // based on our triple.  On MacOS, we have only a lib directory. +    // +    // It's sufficient for our purposes to be flexible: If both lib and lib64 +    // exist, we choose whichever one matches our triple.  Otherwise, if only +    // lib exists, we use it. +    if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) +      LibPath = InstallPath + "/lib64"; +    else if (FS.exists(InstallPath + "/lib")) +      LibPath = InstallPath + "/lib"; +    else +      continue; + +    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = +        FS.getBufferForFile(InstallPath + "/version.txt"); +    if (!VersionFile) { +      // CUDA 7.0 doesn't have a version.txt, so guess that's our version if +      // version.txt isn't present. +      Version = CudaVersion::CUDA_70; +    } else { +      Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); +    } + +    if (Version >= CudaVersion::CUDA_90) { +      // CUDA-9+ uses single libdevice file for all GPU variants. +      std::string FilePath = LibDevicePath + "/libdevice.10.bc"; +      if (FS.exists(FilePath)) { +        for (const char *GpuArchName : +             {"sm_30", "sm_32", "sm_35", "sm_37", "sm_50", "sm_52", "sm_53", +              "sm_60", "sm_61", "sm_62", "sm_70", "sm_72", "sm_75"}) { +          const CudaArch GpuArch = StringToCudaArch(GpuArchName); +          if (Version >= MinVersionForCudaArch(GpuArch) && +              Version <= MaxVersionForCudaArch(GpuArch)) +            LibDeviceMap[GpuArchName] = FilePath; +        } +      } +    } else { +      std::error_code EC; +      for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; +           !EC && LI != LE; LI = LI.increment(EC)) { +        StringRef FilePath = LI->path(); +        StringRef FileName = llvm::sys::path::filename(FilePath); +        // Process all bitcode filenames that look like +        // libdevice.compute_XX.YY.bc +        const StringRef LibDeviceName = "libdevice."; +        if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) +          continue; +        StringRef GpuArch = FileName.slice( +            LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); +        LibDeviceMap[GpuArch] = FilePath.str(); +        // Insert map entries for specific devices with this compute +        // capability. NVCC's choice of the libdevice library version is +        // rather peculiar and depends on the CUDA version. +        if (GpuArch == "compute_20") { +          LibDeviceMap["sm_20"] = FilePath; +          LibDeviceMap["sm_21"] = FilePath; +          LibDeviceMap["sm_32"] = FilePath; +        } else if (GpuArch == "compute_30") { +          LibDeviceMap["sm_30"] = FilePath; +          if (Version < CudaVersion::CUDA_80) { +            LibDeviceMap["sm_50"] = FilePath; +            LibDeviceMap["sm_52"] = FilePath; +            LibDeviceMap["sm_53"] = FilePath; +          } +          LibDeviceMap["sm_60"] = FilePath; +          LibDeviceMap["sm_61"] = FilePath; +          LibDeviceMap["sm_62"] = FilePath; +        } else if (GpuArch == "compute_35") { +          LibDeviceMap["sm_35"] = FilePath; +          LibDeviceMap["sm_37"] = FilePath; +        } else if (GpuArch == "compute_50") { +          if (Version >= CudaVersion::CUDA_80) { +            LibDeviceMap["sm_50"] = FilePath; +            LibDeviceMap["sm_52"] = FilePath; +            LibDeviceMap["sm_53"] = FilePath; +          } +        } +      } +    } + +    // Check that we have found at least one libdevice that we can link in if +    // -nocudalib hasn't been specified. +    if (LibDeviceMap.empty() && !NoCudaLib) +      continue; + +    IsValid = true; +    break; +  } +} + +void CudaInstallationDetector::AddCudaIncludeArgs( +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    // Add cuda_wrappers/* to our system include path.  This lets us wrap +    // standard library headers. +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    llvm::sys::path::append(P, "cuda_wrappers"); +    CC1Args.push_back("-internal-isystem"); +    CC1Args.push_back(DriverArgs.MakeArgString(P)); +  } + +  if (DriverArgs.hasArg(options::OPT_nocudainc)) +    return; + +  if (!isValid()) { +    D.Diag(diag::err_drv_no_cuda_installation); +    return; +  } + +  CC1Args.push_back("-internal-isystem"); +  CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); +  CC1Args.push_back("-include"); +  CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); +} + +void CudaInstallationDetector::CheckCudaVersionSupportsArch( +    CudaArch Arch) const { +  if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || +      ArchsWithBadVersion.count(Arch) > 0) +    return; + +  auto MinVersion = MinVersionForCudaArch(Arch); +  auto MaxVersion = MaxVersionForCudaArch(Arch); +  if (Version < MinVersion || Version > MaxVersion) { +    ArchsWithBadVersion.insert(Arch); +    D.Diag(diag::err_drv_cuda_version_unsupported) +        << CudaArchToString(Arch) << CudaVersionToString(MinVersion) +        << CudaVersionToString(MaxVersion) << InstallPath +        << CudaVersionToString(Version); +  } +} + +void CudaInstallationDetector::print(raw_ostream &OS) const { +  if (isValid()) +    OS << "Found CUDA installation: " << InstallPath << ", version " +       << CudaVersionToString(Version) << "\n"; +} + +namespace { +/// Debug info level for the NVPTX devices. We may need to emit different debug +/// info level for the host and for the device itselfi. This type controls +/// emission of the debug info for the devices. It either prohibits disable info +/// emission completely, or emits debug directives only, or emits same debug +/// info as for the host. +enum DeviceDebugInfoLevel { +  DisableDebugInfo,        /// Do not emit debug info for the devices. +  DebugDirectivesOnly,     /// Emit only debug directives. +  EmitSameDebugInfoAsHost, /// Use the same debug info level just like for the +                           /// host. +}; +} // anonymous namespace + +/// Define debug info level for the NVPTX devices. If the debug info for both +/// the host and device are disabled (-g0/-ggdb0 or no debug options at all). If +/// only debug directives are requested for the both host and device +/// (-gline-directvies-only), or the debug info only for the device is disabled +/// (optimization is on and --cuda-noopt-device-debug was not specified), the +/// debug directves only must be emitted for the device. Otherwise, use the same +/// debug info level just like for the host (with the limitations of only +/// supported DWARF2 standard). +static DeviceDebugInfoLevel mustEmitDebugInfo(const ArgList &Args) { +  const Arg *A = Args.getLastArg(options::OPT_O_Group); +  bool IsDebugEnabled = !A || A->getOption().matches(options::OPT_O0) || +                        Args.hasFlag(options::OPT_cuda_noopt_device_debug, +                                     options::OPT_no_cuda_noopt_device_debug, +                                     /*Default=*/false); +  if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { +    const Option &Opt = A->getOption(); +    if (Opt.matches(options::OPT_gN_Group)) { +      if (Opt.matches(options::OPT_g0) || Opt.matches(options::OPT_ggdb0)) +        return DisableDebugInfo; +      if (Opt.matches(options::OPT_gline_directives_only)) +        return DebugDirectivesOnly; +    } +    return IsDebugEnabled ? EmitSameDebugInfoAsHost : DebugDirectivesOnly; +  } +  return DisableDebugInfo; +} + +void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                    const InputInfo &Output, +                                    const InputInfoList &Inputs, +                                    const ArgList &Args, +                                    const char *LinkingOutput) const { +  const auto &TC = +      static_cast<const toolchains::CudaToolChain &>(getToolChain()); +  assert(TC.getTriple().isNVPTX() && "Wrong platform"); + +  StringRef GPUArchName; +  // If this is an OpenMP action we need to extract the device architecture +  // from the -march=arch option. This option may come from -Xopenmp-target +  // flag or the default value. +  if (JA.isDeviceOffloading(Action::OFK_OpenMP)) { +    GPUArchName = Args.getLastArgValue(options::OPT_march_EQ); +    assert(!GPUArchName.empty() && "Must have an architecture passed in."); +  } else +    GPUArchName = JA.getOffloadingArch(); + +  // Obtain architecture from the action. +  CudaArch gpu_arch = StringToCudaArch(GPUArchName); +  assert(gpu_arch != CudaArch::UNKNOWN && +         "Device action expected to have an architecture."); + +  // Check that our installation's ptxas supports gpu_arch. +  if (!Args.hasArg(options::OPT_no_cuda_version_check)) { +    TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch); +  } + +  ArgStringList CmdArgs; +  CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32"); +  DeviceDebugInfoLevel DIKind = mustEmitDebugInfo(Args); +  if (DIKind == EmitSameDebugInfoAsHost) { +    // ptxas does not accept -g option if optimization is enabled, so +    // we ignore the compiler's -O* options if we want debug info. +    CmdArgs.push_back("-g"); +    CmdArgs.push_back("--dont-merge-basicblocks"); +    CmdArgs.push_back("--return-at-end"); +  } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { +    // Map the -O we received to -O{0,1,2,3}. +    // +    // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's +    // default, so it may correspond more closely to the spirit of clang -O2. + +    // -O3 seems like the least-bad option when -Osomething is specified to +    // clang but it isn't handled below. +    StringRef OOpt = "3"; +    if (A->getOption().matches(options::OPT_O4) || +        A->getOption().matches(options::OPT_Ofast)) +      OOpt = "3"; +    else if (A->getOption().matches(options::OPT_O0)) +      OOpt = "0"; +    else if (A->getOption().matches(options::OPT_O)) { +      // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options. +      OOpt = llvm::StringSwitch<const char *>(A->getValue()) +                 .Case("1", "1") +                 .Case("2", "2") +                 .Case("3", "3") +                 .Case("s", "2") +                 .Case("z", "2") +                 .Default("2"); +    } +    CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); +  } else { +    // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond +    // to no optimizations, but ptxas's default is -O3. +    CmdArgs.push_back("-O0"); +  } +  if (DIKind == DebugDirectivesOnly) +    CmdArgs.push_back("-lineinfo"); + +  // Pass -v to ptxas if it was passed to the driver. +  if (Args.hasArg(options::OPT_v)) +    CmdArgs.push_back("-v"); + +  CmdArgs.push_back("--gpu-name"); +  CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); +  CmdArgs.push_back("--output-file"); +  CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output))); +  for (const auto& II : Inputs) +    CmdArgs.push_back(Args.MakeArgString(II.getFilename())); + +  for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) +    CmdArgs.push_back(Args.MakeArgString(A)); + +  bool Relocatable = false; +  if (JA.isOffloading(Action::OFK_OpenMP)) +    // In OpenMP we need to generate relocatable code. +    Relocatable = Args.hasFlag(options::OPT_fopenmp_relocatable_target, +                               options::OPT_fnoopenmp_relocatable_target, +                               /*Default=*/true); +  else if (JA.isOffloading(Action::OFK_Cuda)) +    Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, +                               options::OPT_fno_gpu_rdc, /*Default=*/false); + +  if (Relocatable) +    CmdArgs.push_back("-c"); + +  const char *Exec; +  if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) +    Exec = A->getValue(); +  else +    Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) { +  bool includePTX = true; +  for (Arg *A : Args) { +    if (!(A->getOption().matches(options::OPT_cuda_include_ptx_EQ) || +          A->getOption().matches(options::OPT_no_cuda_include_ptx_EQ))) +      continue; +    A->claim(); +    const StringRef ArchStr = A->getValue(); +    if (ArchStr == "all" || ArchStr == gpu_arch) { +      includePTX = A->getOption().matches(options::OPT_cuda_include_ptx_EQ); +      continue; +    } +  } +  return includePTX; +} + +// All inputs to this linker must be from CudaDeviceActions, as we need to look +// at the Inputs' Actions in order to figure out which GPU architecture they +// correspond to. +void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                 const InputInfo &Output, +                                 const InputInfoList &Inputs, +                                 const ArgList &Args, +                                 const char *LinkingOutput) const { +  const auto &TC = +      static_cast<const toolchains::CudaToolChain &>(getToolChain()); +  assert(TC.getTriple().isNVPTX() && "Wrong platform"); + +  ArgStringList CmdArgs; +  if (TC.CudaInstallation.version() <= CudaVersion::CUDA_100) +    CmdArgs.push_back("--cuda"); +  CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32"); +  CmdArgs.push_back(Args.MakeArgString("--create")); +  CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); +  if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost) +    CmdArgs.push_back("-g"); + +  for (const auto& II : Inputs) { +    auto *A = II.getAction(); +    assert(A->getInputs().size() == 1 && +           "Device offload action is expected to have a single input"); +    const char *gpu_arch_str = A->getOffloadingArch(); +    assert(gpu_arch_str && +           "Device action expected to have associated a GPU architecture!"); +    CudaArch gpu_arch = StringToCudaArch(gpu_arch_str); + +    if (II.getType() == types::TY_PP_Asm && +        !shouldIncludePTX(Args, gpu_arch_str)) +      continue; +    // We need to pass an Arch of the form "sm_XX" for cubin files and +    // "compute_XX" for ptx. +    const char *Arch = +        (II.getType() == types::TY_PP_Asm) +            ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch)) +            : gpu_arch_str; +    CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + +                                         Arch + ",file=" + II.getFilename())); +  } + +  for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) +    CmdArgs.push_back(Args.MakeArgString(A)); + +  const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, +                                       const InputInfo &Output, +                                       const InputInfoList &Inputs, +                                       const ArgList &Args, +                                       const char *LinkingOutput) const { +  const auto &TC = +      static_cast<const toolchains::CudaToolChain &>(getToolChain()); +  assert(TC.getTriple().isNVPTX() && "Wrong platform"); + +  ArgStringList CmdArgs; + +  // OpenMP uses nvlink to link cubin files. The result will be embedded in the +  // host binary by the host linker. +  assert(!JA.isHostOffloading(Action::OFK_OpenMP) && +         "CUDA toolchain not expected for an OpenMP host device."); + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else +    assert(Output.isNothing() && "Invalid output."); +  if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost) +    CmdArgs.push_back("-g"); + +  if (Args.hasArg(options::OPT_v)) +    CmdArgs.push_back("-v"); + +  StringRef GPUArch = +      Args.getLastArgValue(options::OPT_march_EQ); +  assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas."); + +  CmdArgs.push_back("-arch"); +  CmdArgs.push_back(Args.MakeArgString(GPUArch)); + +  // Assume that the directory specified with --libomptarget_nvptx_path +  // contains the static library libomptarget-nvptx.a. +  if (const Arg *A = Args.getLastArg(options::OPT_libomptarget_nvptx_path_EQ)) +    CmdArgs.push_back(Args.MakeArgString(Twine("-L") + A->getValue())); + +  // Add paths specified in LIBRARY_PATH environment variable as -L options. +  addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + +  // Add paths for the default clang library path. +  SmallString<256> DefaultLibPath = +      llvm::sys::path::parent_path(TC.getDriver().Dir); +  llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX); +  CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); + +  // Add linking against library implementing OpenMP calls on NVPTX target. +  CmdArgs.push_back("-lomptarget-nvptx"); + +  for (const auto &II : Inputs) { +    if (II.getType() == types::TY_LLVM_IR || +        II.getType() == types::TY_LTO_IR || +        II.getType() == types::TY_LTO_BC || +        II.getType() == types::TY_LLVM_BC) { +      C.getDriver().Diag(diag::err_drv_no_linker_llvm_support) +          << getToolChain().getTripleString(); +      continue; +    } + +    // Currently, we only pass the input files to the linker, we do not pass +    // any libraries that may be valid only for the host. +    if (!II.isFilename()) +      continue; + +    const char *CubinF = C.addTempFile( +        C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); + +    CmdArgs.push_back(CubinF); +  } + +  const char *Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// CUDA toolchain.  Our assembler is ptxas, and our "linker" is fatbinary, +/// which isn't properly a linker but nonetheless performs the step of stitching +/// together object files from the assembler into a single blob. + +CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, +                             const ToolChain &HostTC, const ArgList &Args, +                             const Action::OffloadKind OK) +    : ToolChain(D, Triple, Args), HostTC(HostTC), +      CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { +  if (CudaInstallation.isValid()) +    getProgramPaths().push_back(CudaInstallation.getBinPath()); +  // Lookup binaries into the driver directory, this is used to +  // discover the clang-offload-bundler executable. +  getProgramPaths().push_back(getDriver().Dir); +} + +std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { +  // Only object files are changed, for example assembly files keep their .s +  // extensions. CUDA also continues to use .o as they don't use nvlink but +  // fatbinary. +  if (!(OK == Action::OFK_OpenMP && Input.getType() == types::TY_Object)) +    return ToolChain::getInputFilename(Input); + +  // Replace extension for object files with cubin because nvlink relies on +  // these particular file names. +  SmallString<256> Filename(ToolChain::getInputFilename(Input)); +  llvm::sys::path::replace_extension(Filename, "cubin"); +  return Filename.str(); +} + +void CudaToolChain::addClangTargetOptions( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args, +    Action::OffloadKind DeviceOffloadingKind) const { +  HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); + +  StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); +  assert(!GpuArch.empty() && "Must have an explicit GPU arch."); +  assert((DeviceOffloadingKind == Action::OFK_OpenMP || +          DeviceOffloadingKind == Action::OFK_Cuda) && +         "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs."); + +  if (DeviceOffloadingKind == Action::OFK_Cuda) { +    CC1Args.push_back("-fcuda-is-device"); + +    if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, +                           options::OPT_fno_cuda_flush_denormals_to_zero, false)) +      CC1Args.push_back("-fcuda-flush-denormals-to-zero"); + +    if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, +                           options::OPT_fno_cuda_approx_transcendentals, false)) +      CC1Args.push_back("-fcuda-approx-transcendentals"); + +    if (DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, +                           false)) +      CC1Args.push_back("-fgpu-rdc"); +  } + +  if (DriverArgs.hasArg(options::OPT_nogpulib)) +    return; + +  std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); + +  if (LibDeviceFile.empty()) { +    if (DeviceOffloadingKind == Action::OFK_OpenMP && +        DriverArgs.hasArg(options::OPT_S)) +      return; + +    getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; +    return; +  } + +  CC1Args.push_back("-mlink-builtin-bitcode"); +  CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); + +  // New CUDA versions often introduce new instructions that are only supported +  // by new PTX version, so we need to raise PTX level to enable them in NVPTX +  // back-end. +  const char *PtxFeature = nullptr; +  switch(CudaInstallation.version()) { +    case CudaVersion::CUDA_101: +      PtxFeature = "+ptx64"; +      break; +    case CudaVersion::CUDA_100: +      PtxFeature = "+ptx63"; +      break; +    case CudaVersion::CUDA_92: +      PtxFeature = "+ptx61"; +      break; +    case CudaVersion::CUDA_91: +      PtxFeature = "+ptx61"; +      break; +    case CudaVersion::CUDA_90: +      PtxFeature = "+ptx60"; +      break; +    default: +      PtxFeature = "+ptx42"; +  } +  CC1Args.append({"-target-feature", PtxFeature}); +  if (DriverArgs.hasFlag(options::OPT_fcuda_short_ptr, +                         options::OPT_fno_cuda_short_ptr, false)) +    CC1Args.append({"-mllvm", "--nvptx-short-ptr"}); + +  if (CudaInstallation.version() >= CudaVersion::UNKNOWN) +    CC1Args.push_back(DriverArgs.MakeArgString( +        Twine("-target-sdk-version=") + +        CudaVersionToString(CudaInstallation.version()))); + +  if (DeviceOffloadingKind == Action::OFK_OpenMP) { +    SmallVector<StringRef, 8> LibraryPaths; +    if (const Arg *A = DriverArgs.getLastArg(options::OPT_libomptarget_nvptx_path_EQ)) +      LibraryPaths.push_back(A->getValue()); + +    // Add user defined library paths from LIBRARY_PATH. +    llvm::Optional<std::string> LibPath = +        llvm::sys::Process::GetEnv("LIBRARY_PATH"); +    if (LibPath) { +      SmallVector<StringRef, 8> Frags; +      const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; +      llvm::SplitString(*LibPath, Frags, EnvPathSeparatorStr); +      for (StringRef Path : Frags) +        LibraryPaths.emplace_back(Path.trim()); +    } + +    // Add path to lib / lib64 folder. +    SmallString<256> DefaultLibPath = +        llvm::sys::path::parent_path(getDriver().Dir); +    llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); +    LibraryPaths.emplace_back(DefaultLibPath.c_str()); + +    std::string LibOmpTargetName = +      "libomptarget-nvptx-" + GpuArch.str() + ".bc"; +    bool FoundBCLibrary = false; +    for (StringRef LibraryPath : LibraryPaths) { +      SmallString<128> LibOmpTargetFile(LibraryPath); +      llvm::sys::path::append(LibOmpTargetFile, LibOmpTargetName); +      if (llvm::sys::fs::exists(LibOmpTargetFile)) { +        CC1Args.push_back("-mlink-builtin-bitcode"); +        CC1Args.push_back(DriverArgs.MakeArgString(LibOmpTargetFile)); +        FoundBCLibrary = true; +        break; +      } +    } +    if (!FoundBCLibrary) +      getDriver().Diag(diag::warn_drv_omp_offload_target_missingbcruntime) +          << LibOmpTargetName; +  } +} + +bool CudaToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const { +  const Option &O = A->getOption(); +  return (O.matches(options::OPT_gN_Group) && +          !O.matches(options::OPT_gmodules)) || +         O.matches(options::OPT_g_Flag) || +         O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) || +         O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) || +         O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) || +         O.matches(options::OPT_gdwarf_5) || +         O.matches(options::OPT_gcolumn_info); +} + +void CudaToolChain::adjustDebugInfoKind( +    codegenoptions::DebugInfoKind &DebugInfoKind, const ArgList &Args) const { +  switch (mustEmitDebugInfo(Args)) { +  case DisableDebugInfo: +    DebugInfoKind = codegenoptions::NoDebugInfo; +    break; +  case DebugDirectivesOnly: +    DebugInfoKind = codegenoptions::DebugDirectivesOnly; +    break; +  case EmitSameDebugInfoAsHost: +    // Use same debug info level as the host. +    break; +  } +} + +void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, +                                       ArgStringList &CC1Args) const { +  // Check our CUDA version if we're going to include the CUDA headers. +  if (!DriverArgs.hasArg(options::OPT_nocudainc) && +      !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { +    StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); +    assert(!Arch.empty() && "Must have an explicit GPU arch."); +    CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch)); +  } +  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +llvm::opt::DerivedArgList * +CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, +                             StringRef BoundArch, +                             Action::OffloadKind DeviceOffloadKind) const { +  DerivedArgList *DAL = +      HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); +  if (!DAL) +    DAL = new DerivedArgList(Args.getBaseArgs()); + +  const OptTable &Opts = getDriver().getOpts(); + +  // For OpenMP device offloading, append derived arguments. Make sure +  // flags are not duplicated. +  // Also append the compute capability. +  if (DeviceOffloadKind == Action::OFK_OpenMP) { +    for (Arg *A : Args) { +      bool IsDuplicate = false; +      for (Arg *DALArg : *DAL) { +        if (A == DALArg) { +          IsDuplicate = true; +          break; +        } +      } +      if (!IsDuplicate) +        DAL->append(A); +    } + +    StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); +    if (Arch.empty()) +      DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), +                        CLANG_OPENMP_NVPTX_DEFAULT_ARCH); + +    return DAL; +  } + +  for (Arg *A : Args) { +    if (A->getOption().matches(options::OPT_Xarch__)) { +      // Skip this argument unless the architecture matches BoundArch +      if (BoundArch.empty() || A->getValue(0) != BoundArch) +        continue; + +      unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); +      unsigned Prev = Index; +      std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + +      // If the argument parsing failed or more than one argument was +      // consumed, the -Xarch_ argument's parameter tried to consume +      // extra arguments. Emit an error and ignore. +      // +      // We also want to disallow any options which would alter the +      // driver behavior; that isn't going to work in our model. We +      // use isDriverOption() as an approximation, although things +      // like -O4 are going to slip through. +      if (!XarchArg || Index > Prev + 1) { +        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) +            << A->getAsString(Args); +        continue; +      } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { +        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) +            << A->getAsString(Args); +        continue; +      } +      XarchArg->setBaseArg(A); +      A = XarchArg.release(); +      DAL->AddSynthesizedArg(A); +    } +    DAL->append(A); +  } + +  if (!BoundArch.empty()) { +    DAL->eraseArg(options::OPT_march_EQ); +    DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); +  } +  return DAL; +} + +Tool *CudaToolChain::buildAssembler() const { +  return new tools::NVPTX::Assembler(*this); +} + +Tool *CudaToolChain::buildLinker() const { +  if (OK == Action::OFK_OpenMP) +    return new tools::NVPTX::OpenMPLinker(*this); +  return new tools::NVPTX::Linker(*this); +} + +void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { +  HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { +  return HostTC.GetCXXStdlibType(Args); +} + +void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                              ArgStringList &CC1Args) const { +  HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, +                                                 ArgStringList &CC1Args) const { +  HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args, +                                        ArgStringList &CC1Args) const { +  HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +SanitizerMask CudaToolChain::getSupportedSanitizers() const { +  // The CudaToolChain only supports sanitizers in the sense that it allows +  // sanitizer arguments on the command line if they are supported by the host +  // toolchain. The CudaToolChain will actually ignore any command line +  // arguments for any of these "supported" sanitizers. That means that no +  // sanitization of device code is actually supported at this time. +  // +  // This behavior is necessary because the host and device toolchains +  // invocations often share the command line, so the device toolchain must +  // tolerate flags meant only for the host toolchain. +  return HostTC.getSupportedSanitizers(); +} + +VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D, +                                               const ArgList &Args) const { +  return HostTC.computeMSVCVersion(D, Args); +} diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h new file mode 100644 index 0000000000000..4ee8b6f1fea99 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -0,0 +1,202 @@ +//===--- Cuda.h - Cuda ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H + +#include "clang/Basic/Cuda.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Multilib.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/VersionTuple.h" +#include <set> +#include <vector> + +namespace clang { +namespace driver { + +/// A class to find a viable CUDA installation +class CudaInstallationDetector { +private: +  const Driver &D; +  bool IsValid = false; +  CudaVersion Version = CudaVersion::UNKNOWN; +  std::string InstallPath; +  std::string BinPath; +  std::string LibPath; +  std::string LibDevicePath; +  std::string IncludePath; +  llvm::StringMap<std::string> LibDeviceMap; + +  // CUDA architectures for which we have raised an error in +  // CheckCudaVersionSupportsArch. +  mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion; + +public: +  CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, +                           const llvm::opt::ArgList &Args); + +  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const; + +  /// Emit an error if Version does not support the given Arch. +  /// +  /// If either Version or Arch is unknown, does not emit an error.  Emits at +  /// most one error per Arch. +  void CheckCudaVersionSupportsArch(CudaArch Arch) const; + +  /// Check whether we detected a valid Cuda install. +  bool isValid() const { return IsValid; } +  /// Print information about the detected CUDA installation. +  void print(raw_ostream &OS) const; + +  /// Get the detected Cuda install's version. +  CudaVersion version() const { return Version; } +  /// Get the detected Cuda installation path. +  StringRef getInstallPath() const { return InstallPath; } +  /// Get the detected path to Cuda's bin directory. +  StringRef getBinPath() const { return BinPath; } +  /// Get the detected Cuda Include path. +  StringRef getIncludePath() const { return IncludePath; } +  /// Get the detected Cuda library path. +  StringRef getLibPath() const { return LibPath; } +  /// Get the detected Cuda device library path. +  StringRef getLibDevicePath() const { return LibDevicePath; } +  /// Get libdevice file for given architecture +  std::string getLibDeviceFile(StringRef Gpu) const { +    return LibDeviceMap.lookup(Gpu); +  } +}; + +namespace tools { +namespace NVPTX { + +// Run ptxas, the NVPTX assembler. +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { + public: +   Assembler(const ToolChain &TC) +       : Tool("NVPTX::Assembler", "ptxas", TC, RF_Full, llvm::sys::WEM_UTF8, +              "--options-file") {} + +   bool hasIntegratedCPP() const override { return false; } + +   void ConstructJob(Compilation &C, const JobAction &JA, +                     const InputInfo &Output, const InputInfoList &Inputs, +                     const llvm::opt::ArgList &TCArgs, +                     const char *LinkingOutput) const override; +}; + +// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX +// assembly into a single output file. +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { + public: +   Linker(const ToolChain &TC) +       : Tool("NVPTX::Linker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8, +              "--options-file") {} + +   bool hasIntegratedCPP() const override { return false; } + +   void ConstructJob(Compilation &C, const JobAction &JA, +                     const InputInfo &Output, const InputInfoList &Inputs, +                     const llvm::opt::ArgList &TCArgs, +                     const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { + public: +   OpenMPLinker(const ToolChain &TC) +       : Tool("NVPTX::OpenMPLinker", "nvlink", TC, RF_Full, llvm::sys::WEM_UTF8, +              "--options-file") {} + +   bool hasIntegratedCPP() const override { return false; } + +   void ConstructJob(Compilation &C, const JobAction &JA, +                     const InputInfo &Output, const InputInfoList &Inputs, +                     const llvm::opt::ArgList &TCArgs, +                     const char *LinkingOutput) const override; +}; + +} // end namespace NVPTX +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { +public: +  CudaToolChain(const Driver &D, const llvm::Triple &Triple, +                const ToolChain &HostTC, const llvm::opt::ArgList &Args, +                const Action::OffloadKind OK); + +  const llvm::Triple *getAuxTriple() const override { +    return &HostTC.getTriple(); +  } + +  std::string getInputFilename(const InputInfo &Input) const override; + +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; + +  // Never try to use the integrated assembler with CUDA; always fork out to +  // ptxas. +  bool useIntegratedAs() const override { return false; } +  bool isCrossCompiling() const override { return true; } +  bool isPICDefault() const override { return false; } +  bool isPIEDefault() const override { return false; } +  bool isPICDefaultForced() const override { return false; } +  bool SupportsProfiling() const override { return false; } +  bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override; +  void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind, +                           const llvm::opt::ArgList &Args) const override; +  bool IsMathErrnoDefault() const override { return false; } + +  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const override; + +  void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; +  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &Args, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                           llvm::opt::ArgStringList &CC1Args) const override; + +  SanitizerMask getSupportedSanitizers() const override; + +  VersionTuple +  computeMSVCVersion(const Driver *D, +                     const llvm::opt::ArgList &Args) const override; + +  unsigned GetDefaultDwarfVersion() const override { return 2; } + +  const ToolChain &HostTC; +  CudaInstallationDetector CudaInstallation; + +protected: +  Tool *buildAssembler() const override;  // ptxas +  Tool *buildLinker() const override;     // fatbinary (ok, not really a linker) + +private: +  const Action::OffloadKind OK; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp new file mode 100644 index 0000000000000..ee08b8208d939 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -0,0 +1,2615 @@ +//===--- Darwin.cpp - Darwin Tool and ToolChain Implementations -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Darwin.h" +#include "Arch/ARM.h" +#include "CommonArgs.h" +#include "clang/Basic/AlignedAllocation.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { +  // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for +  // archs which Darwin doesn't use. + +  // The matching this routine does is fairly pointless, since it is neither the +  // complete architecture list, nor a reasonable subset. The problem is that +  // historically the driver driver accepts this and also ties its -march= +  // handling to the architecture name, so we need to be careful before removing +  // support for it. + +  // This code must be kept in sync with Clang's Darwin specific argument +  // translation. + +  return llvm::StringSwitch<llvm::Triple::ArchType>(Str) +      .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) +      .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) +      .Case("ppc64", llvm::Triple::ppc64) +      .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) +      .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", +             llvm::Triple::x86) +      .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) +      // This is derived from the driver driver. +      .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) +      .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) +      .Cases("armv7s", "xscale", llvm::Triple::arm) +      .Case("arm64", llvm::Triple::aarch64) +      .Case("r600", llvm::Triple::r600) +      .Case("amdgcn", llvm::Triple::amdgcn) +      .Case("nvptx", llvm::Triple::nvptx) +      .Case("nvptx64", llvm::Triple::nvptx64) +      .Case("amdil", llvm::Triple::amdil) +      .Case("spir", llvm::Triple::spir) +      .Default(llvm::Triple::UnknownArch); +} + +void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { +  const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); +  llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Str); +  T.setArch(Arch); + +  if (Str == "x86_64h") +    T.setArchName(Str); +  else if (ArchKind == llvm::ARM::ArchKind::ARMV6M || +           ArchKind == llvm::ARM::ArchKind::ARMV7M || +           ArchKind == llvm::ARM::ArchKind::ARMV7EM) { +    T.setOS(llvm::Triple::UnknownOS); +    T.setObjectFormat(llvm::Triple::MachO); +  } +} + +void darwin::Assembler::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."); +  const InputInfo &Input = Inputs[0]; + +  // Determine the original source input. +  const Action *SourceAction = &JA; +  while (SourceAction->getKind() != Action::InputClass) { +    assert(!SourceAction->getInputs().empty() && "unexpected root action!"); +    SourceAction = SourceAction->getInputs()[0]; +  } + +  // If -fno-integrated-as is used add -Q to the darwin assembler driver to make +  // sure it runs its system assembler not clang's integrated assembler. +  // Applicable to darwin11+ and Xcode 4+.  darwin<10 lacked integrated-as. +  // FIXME: at run-time detect assembler capabilities or rely on version +  // information forwarded by -target-assembler-version. +  if (Args.hasArg(options::OPT_fno_integrated_as)) { +    const llvm::Triple &T(getToolChain().getTriple()); +    if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) +      CmdArgs.push_back("-Q"); +  } + +  // Forward -g, assuming we are dealing with an actual assembly file. +  if (SourceAction->getType() == types::TY_Asm || +      SourceAction->getType() == types::TY_PP_Asm) { +    if (Args.hasArg(options::OPT_gstabs)) +      CmdArgs.push_back("--gstabs"); +    else if (Args.hasArg(options::OPT_g_Group)) +      CmdArgs.push_back("-g"); +  } + +  // Derived from asm spec. +  AddMachOArch(Args, CmdArgs); + +  // Use -force_cpusubtype_ALL on x86 by default. +  if (getToolChain().getArch() == llvm::Triple::x86 || +      getToolChain().getArch() == llvm::Triple::x86_64 || +      Args.hasArg(options::OPT_force__cpusubtype__ALL)) +    CmdArgs.push_back("-force_cpusubtype_ALL"); + +  if (getToolChain().getArch() != llvm::Triple::x86_64 && +      (((Args.hasArg(options::OPT_mkernel) || +         Args.hasArg(options::OPT_fapple_kext)) && +        getMachOToolChain().isKernelStatic()) || +       Args.hasArg(options::OPT_static))) +    CmdArgs.push_back("-static"); + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  assert(Output.isFilename() && "Unexpected lipo output."); +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  assert(Input.isFilename() && "Invalid input."); +  CmdArgs.push_back(Input.getFilename()); + +  // asm_final spec is empty. + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void darwin::MachOTool::anchor() {} + +void darwin::MachOTool::AddMachOArch(const ArgList &Args, +                                     ArgStringList &CmdArgs) const { +  StringRef ArchName = getMachOToolChain().getMachOArchName(Args); + +  // Derived from darwin_arch spec. +  CmdArgs.push_back("-arch"); +  CmdArgs.push_back(Args.MakeArgString(ArchName)); + +  // FIXME: Is this needed anymore? +  if (ArchName == "arm") +    CmdArgs.push_back("-force_cpusubtype_ALL"); +} + +bool darwin::Linker::NeedsTempPath(const InputInfoList &Inputs) const { +  // We only need to generate a temp path for LTO if we aren't compiling object +  // files. When compiling source files, we run 'dsymutil' after linking. We +  // don't run 'dsymutil' when compiling object files. +  for (const auto &Input : Inputs) +    if (Input.getType() != types::TY_Object) +      return true; + +  return false; +} + +/// Pass -no_deduplicate to ld64 under certain conditions: +/// +/// - Either -O0 or -O1 is explicitly specified +/// - No -O option is specified *and* this is a compile+link (implicit -O0) +/// +/// Also do *not* add -no_deduplicate when no -O option is specified and this +/// is just a link (we can't imply -O0) +static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { +    if (A->getOption().matches(options::OPT_O0)) +      return true; +    if (A->getOption().matches(options::OPT_O)) +      return llvm::StringSwitch<bool>(A->getValue()) +                    .Case("1", true) +                    .Default(false); +    return false; // OPT_Ofast & OPT_O4 +  } + +  if (!IsLinkerOnlyAction) // Implicit -O0 for compile+linker only. +    return true; +  return false; +} + +void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, +                                 ArgStringList &CmdArgs, +                                 const InputInfoList &Inputs) const { +  const Driver &D = getToolChain().getDriver(); +  const toolchains::MachO &MachOTC = getMachOToolChain(); + +  unsigned Version[5] = {0, 0, 0, 0, 0}; +  if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { +    if (!Driver::GetReleaseVersion(A->getValue(), Version)) +      D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); +  } + +  // Newer linkers support -demangle. Pass it if supported and not disabled by +  // the user. +  if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("-demangle"); + +  if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) +    CmdArgs.push_back("-export_dynamic"); + +  // If we are using App Extension restrictions, pass a flag to the linker +  // telling it that the compiled code has been audited. +  if (Args.hasFlag(options::OPT_fapplication_extension, +                   options::OPT_fno_application_extension, false)) +    CmdArgs.push_back("-application_extension"); + +  if (D.isUsingLTO() && Version[0] >= 116 && NeedsTempPath(Inputs)) { +    std::string TmpPathName; +    if (D.getLTOMode() == LTOK_Full) { +      // If we are using full LTO, then automatically create a temporary file +      // path for the linker to use, so that it's lifetime will extend past a +      // possible dsymutil step. +      TmpPathName = +          D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)); +    } else if (D.getLTOMode() == LTOK_Thin) +      // If we are using thin LTO, then create a directory instead. +      TmpPathName = D.GetTemporaryDirectory("thinlto"); + +    if (!TmpPathName.empty()) { +      auto *TmpPath = C.getArgs().MakeArgString(TmpPathName); +      C.addTempFile(TmpPath); +      CmdArgs.push_back("-object_path_lto"); +      CmdArgs.push_back(TmpPath); +    } +  } + +  // Use -lto_library option to specify the libLTO.dylib path. Try to find +  // it in clang installed libraries. ld64 will only look at this argument +  // when it actually uses LTO, so libLTO.dylib only needs to exist at link +  // time if ld64 decides that it needs to use LTO. +  // Since this is passed unconditionally, ld64 will never look for libLTO.dylib +  // next to it. That's ok since ld64 using a libLTO.dylib not matching the +  // clang version won't work anyways. +  if (Version[0] >= 133) { +    // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib +    StringRef P = llvm::sys::path::parent_path(D.Dir); +    SmallString<128> LibLTOPath(P); +    llvm::sys::path::append(LibLTOPath, "lib"); +    llvm::sys::path::append(LibLTOPath, "libLTO.dylib"); +    CmdArgs.push_back("-lto_library"); +    CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); +  } + +  // ld64 version 262 and above run the deduplicate pass by default. +  if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args)) +    CmdArgs.push_back("-no_deduplicate"); + +  // Derived from the "link" spec. +  Args.AddAllArgs(CmdArgs, options::OPT_static); +  if (!Args.hasArg(options::OPT_static)) +    CmdArgs.push_back("-dynamic"); +  if (Args.hasArg(options::OPT_fgnu_runtime)) { +    // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu +    // here. How do we wish to handle such things? +  } + +  if (!Args.hasArg(options::OPT_dynamiclib)) { +    AddMachOArch(Args, CmdArgs); +    // FIXME: Why do this only on this path? +    Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); + +    Args.AddLastArg(CmdArgs, options::OPT_bundle); +    Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); +    Args.AddAllArgs(CmdArgs, options::OPT_client__name); + +    Arg *A; +    if ((A = Args.getLastArg(options::OPT_compatibility__version)) || +        (A = Args.getLastArg(options::OPT_current__version)) || +        (A = Args.getLastArg(options::OPT_install__name))) +      D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) +                                                       << "-dynamiclib"; + +    Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); +    Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs); +    Args.AddLastArg(CmdArgs, options::OPT_private__bundle); +  } else { +    CmdArgs.push_back("-dylib"); + +    Arg *A; +    if ((A = Args.getLastArg(options::OPT_bundle)) || +        (A = Args.getLastArg(options::OPT_bundle__loader)) || +        (A = Args.getLastArg(options::OPT_client__name)) || +        (A = Args.getLastArg(options::OPT_force__flat__namespace)) || +        (A = Args.getLastArg(options::OPT_keep__private__externs)) || +        (A = Args.getLastArg(options::OPT_private__bundle))) +      D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) +                                                      << "-dynamiclib"; + +    Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, +                              "-dylib_compatibility_version"); +    Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, +                              "-dylib_current_version"); + +    AddMachOArch(Args, CmdArgs); + +    Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, +                              "-dylib_install_name"); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_all__load); +  Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); +  Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); +  if (MachOTC.isTargetIOSBased()) +    Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); +  Args.AddLastArg(CmdArgs, options::OPT_dead__strip); +  Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); +  Args.AddAllArgs(CmdArgs, options::OPT_dylib__file); +  Args.AddLastArg(CmdArgs, options::OPT_dynamic); +  Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list); +  Args.AddLastArg(CmdArgs, options::OPT_flat__namespace); +  Args.AddAllArgs(CmdArgs, options::OPT_force__load); +  Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names); +  Args.AddAllArgs(CmdArgs, options::OPT_image__base); +  Args.AddAllArgs(CmdArgs, options::OPT_init); + +  // Add the deployment target. +  MachOTC.addMinVersionArgs(Args, CmdArgs); + +  Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); +  Args.AddLastArg(CmdArgs, options::OPT_multi__module); +  Args.AddLastArg(CmdArgs, options::OPT_single__module); +  Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined); +  Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused); + +  if (const Arg *A = +          Args.getLastArg(options::OPT_fpie, options::OPT_fPIE, +                          options::OPT_fno_pie, options::OPT_fno_PIE)) { +    if (A->getOption().matches(options::OPT_fpie) || +        A->getOption().matches(options::OPT_fPIE)) +      CmdArgs.push_back("-pie"); +    else +      CmdArgs.push_back("-no_pie"); +  } + +  // for embed-bitcode, use -bitcode_bundle in linker command +  if (C.getDriver().embedBitcodeEnabled()) { +    // Check if the toolchain supports bitcode build flow. +    if (MachOTC.SupportsEmbeddedBitcode()) { +      CmdArgs.push_back("-bitcode_bundle"); +      if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) { +        CmdArgs.push_back("-bitcode_process_mode"); +        CmdArgs.push_back("marker"); +      } +    } else +      D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_prebind); +  Args.AddLastArg(CmdArgs, options::OPT_noprebind); +  Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); +  Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules); +  Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs); +  Args.AddAllArgs(CmdArgs, options::OPT_sectcreate); +  Args.AddAllArgs(CmdArgs, options::OPT_sectorder); +  Args.AddAllArgs(CmdArgs, options::OPT_seg1addr); +  Args.AddAllArgs(CmdArgs, options::OPT_segprot); +  Args.AddAllArgs(CmdArgs, options::OPT_segaddr); +  Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr); +  Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr); +  Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table); +  Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename); +  Args.AddAllArgs(CmdArgs, options::OPT_sub__library); +  Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); + +  // Give --sysroot= preference, over the Apple specific behavior to also use +  // --isysroot as the syslibroot. +  StringRef sysroot = C.getSysRoot(); +  if (sysroot != "") { +    CmdArgs.push_back("-syslibroot"); +    CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); +  } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +    CmdArgs.push_back("-syslibroot"); +    CmdArgs.push_back(A->getValue()); +  } + +  Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); +  Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints); +  Args.AddAllArgs(CmdArgs, options::OPT_umbrella); +  Args.AddAllArgs(CmdArgs, options::OPT_undefined); +  Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); +  Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); +  Args.AddLastArg(CmdArgs, options::OPT_X_Flag); +  Args.AddAllArgs(CmdArgs, options::OPT_y); +  Args.AddLastArg(CmdArgs, options::OPT_w); +  Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size); +  Args.AddAllArgs(CmdArgs, options::OPT_segs__read__); +  Args.AddLastArg(CmdArgs, options::OPT_seglinkedit); +  Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit); +  Args.AddAllArgs(CmdArgs, options::OPT_sectalign); +  Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols); +  Args.AddAllArgs(CmdArgs, options::OPT_segcreate); +  Args.AddLastArg(CmdArgs, options::OPT_whyload); +  Args.AddLastArg(CmdArgs, options::OPT_whatsloaded); +  Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); +  Args.AddLastArg(CmdArgs, options::OPT_dylinker); +  Args.AddLastArg(CmdArgs, options::OPT_Mach); +} + +/// Determine whether we are linking the ObjC runtime. +static bool isObjCRuntimeLinked(const ArgList &Args) { +  if (isObjCAutoRefCount(Args)) { +    Args.ClaimAllArgs(options::OPT_fobjc_link_runtime); +    return true; +  } +  return Args.hasArg(options::OPT_fobjc_link_runtime); +} + +void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const ArgList &Args, +                                  const char *LinkingOutput) const { +  assert(Output.getType() == types::TY_Image && "Invalid linker output type."); + +  // If the number of arguments surpasses the system limits, we will encode the +  // input files in a separate file, shortening the command line. To this end, +  // build a list of input file names that can be passed via a file with the +  // -filelist linker option. +  llvm::opt::ArgStringList InputFileList; + +  // The logic here is derived from gcc's behavior; most of which +  // comes from specs (starting with link_command). Consult gcc for +  // more information. +  ArgStringList CmdArgs; + +  /// Hack(tm) to ignore linking errors when we are doing ARC migration. +  if (Args.hasArg(options::OPT_ccc_arcmt_check, +                  options::OPT_ccc_arcmt_migrate)) { +    for (const auto &Arg : Args) +      Arg->claim(); +    const char *Exec = +        Args.MakeArgString(getToolChain().GetProgramPath("touch")); +    CmdArgs.push_back(Output.getFilename()); +    C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, None)); +    return; +  } + +  // I'm not sure why this particular decomposition exists in gcc, but +  // we follow suite for ease of comparison. +  AddLinkArgs(C, Args, CmdArgs, Inputs); + +  // For LTO, pass the name of the optimization record file and other +  // opt-remarks flags. +  if (Args.hasFlag(options::OPT_fsave_optimization_record, +                   options::OPT_fsave_optimization_record_EQ, +                   options::OPT_fno_save_optimization_record, false)) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back("-lto-pass-remarks-output"); +    CmdArgs.push_back("-mllvm"); + +    SmallString<128> F; +    F = Output.getFilename(); +    F += ".opt."; +    if (const Arg *A = +            Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) +      F += A->getValue(); +    else +      F += "yaml"; + +    CmdArgs.push_back(Args.MakeArgString(F)); + +    if (getLastProfileUseArg(Args)) { +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-lto-pass-remarks-with-hotness"); + +      if (const Arg *A = +              Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { +        CmdArgs.push_back("-mllvm"); +        std::string Opt = +            std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); +        CmdArgs.push_back(Args.MakeArgString(Opt)); +      } +    } + +    if (const Arg *A = +            Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { +      CmdArgs.push_back("-mllvm"); +      std::string Passes = +          std::string("-lto-pass-remarks-filter=") + A->getValue(); +      CmdArgs.push_back(Args.MakeArgString(Passes)); +    } + +    if (const Arg *A = +            Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { +      CmdArgs.push_back("-mllvm"); +      std::string Format = +          std::string("-lto-pass-remarks-format=") + A->getValue(); +      CmdArgs.push_back(Args.MakeArgString(Format)); +    } +  } + +  // Propagate the -moutline flag to the linker in LTO. +  if (Arg *A = +          Args.getLastArg(options::OPT_moutline, options::OPT_mno_outline)) { +    if (A->getOption().matches(options::OPT_moutline)) { +      if (getMachOToolChain().getMachOArchName(Args) == "arm64") { +        CmdArgs.push_back("-mllvm"); +        CmdArgs.push_back("-enable-machine-outliner"); + +        // Outline from linkonceodr functions by default in LTO. +        CmdArgs.push_back("-mllvm"); +        CmdArgs.push_back("-enable-linkonceodr-outlining"); +      } +    } else { +      // Disable all outlining behaviour if we have mno-outline. We need to do +      // this explicitly, because targets which support default outlining will +      // try to do work if we don't. +      CmdArgs.push_back("-mllvm"); +      CmdArgs.push_back("-enable-machine-outliner=never"); +    } +  } + +  // Setup statistics file output. +  SmallString<128> StatsFile = +      getStatsFileName(Args, Output, Inputs[0], getToolChain().getDriver()); +  if (!StatsFile.empty()) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back(Args.MakeArgString("-lto-stats-file=" + StatsFile.str())); +  } + +  // It seems that the 'e' option is completely ignored for dynamic executables +  // (the default), and with static executables, the last one wins, as expected. +  Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, +                            options::OPT_Z_Flag, options::OPT_u_Group, +                            options::OPT_e, options::OPT_r}); + +  // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading +  // members of static archive libraries which implement Objective-C classes or +  // categories. +  if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX)) +    CmdArgs.push_back("-ObjC"); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) +    getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); + +  Args.AddAllArgs(CmdArgs, options::OPT_L); + +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); +  // Build the input file for -filelist (list of linker input files) in case we +  // need it later +  for (const auto &II : Inputs) { +    if (!II.isFilename()) { +      // This is a linker input argument. +      // We cannot mix input arguments and file names in a -filelist input, thus +      // we prematurely stop our list (remaining files shall be passed as +      // arguments). +      if (InputFileList.size() > 0) +        break; + +      continue; +    } + +    InputFileList.push_back(II.getFilename()); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) +    addOpenMPRuntime(CmdArgs, getToolChain(), Args); + +  if (isObjCRuntimeLinked(Args) && +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    // We use arclite library for both ARC and subscripting support. +    getMachOToolChain().AddLinkARCArgs(Args, CmdArgs); + +    CmdArgs.push_back("-framework"); +    CmdArgs.push_back("Foundation"); +    // Link libobj. +    CmdArgs.push_back("-lobjc"); +  } + +  if (LinkingOutput) { +    CmdArgs.push_back("-arch_multiple"); +    CmdArgs.push_back("-final_output"); +    CmdArgs.push_back(LinkingOutput); +  } + +  if (Args.hasArg(options::OPT_fnested_functions)) +    CmdArgs.push_back("-allow_stack_execute"); + +  getMachOToolChain().addProfileRTLibs(Args, CmdArgs); + +  if (unsigned Parallelism = +          getLTOParallelism(Args, getToolChain().getDriver())) { +    CmdArgs.push_back("-mllvm"); +    CmdArgs.push_back(Args.MakeArgString("-threads=" + Twine(Parallelism))); +  } + +  if (getToolChain().ShouldLinkCXXStdlib(Args)) +    getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + +  bool NoStdOrDefaultLibs = +      Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); +  bool ForceLinkBuiltins = Args.hasArg(options::OPT_fapple_link_rtlib); +  if (!NoStdOrDefaultLibs || ForceLinkBuiltins) { +    // link_ssp spec is empty. + +    // If we have both -nostdlib/nodefaultlibs and -fapple-link-rtlib then +    // we just want to link the builtins, not the other libs like libSystem. +    if (NoStdOrDefaultLibs && ForceLinkBuiltins) { +      getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, "builtins"); +    } else { +      // Let the tool chain choose which runtime library to link. +      getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs, +                                                ForceLinkBuiltins); + +      // No need to do anything for pthreads. Claim argument to avoid warning. +      Args.ClaimAllArgs(options::OPT_pthread); +      Args.ClaimAllArgs(options::OPT_pthreads); +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    // endfile_spec is empty. +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_T_Group); +  Args.AddAllArgs(CmdArgs, options::OPT_F); + +  // -iframework should be forwarded as -F. +  for (const Arg *A : Args.filtered(options::OPT_iframework)) +    CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue())); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { +      if (A->getValue() == StringRef("Accelerate")) { +        CmdArgs.push_back("-framework"); +        CmdArgs.push_back("Accelerate"); +      } +    } +  } + +  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); +  std::unique_ptr<Command> Cmd = +      std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs); +  Cmd->setInputFileList(std::move(InputFileList)); +  C.addCommand(std::move(Cmd)); +} + +void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, +                                const InputInfo &Output, +                                const InputInfoList &Inputs, +                                const ArgList &Args, +                                const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  CmdArgs.push_back("-create"); +  assert(Output.isFilename() && "Unexpected lipo output."); + +  CmdArgs.push_back("-output"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) { +    assert(II.isFilename() && "Unexpected lipo input."); +    CmdArgs.push_back(II.getFilename()); +  } + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, +                                    const InputInfo &Output, +                                    const InputInfoList &Inputs, +                                    const ArgList &Args, +                                    const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); +  const InputInfo &Input = Inputs[0]; +  assert(Input.isFilename() && "Unexpected dsymutil input."); +  CmdArgs.push_back(Input.getFilename()); + +  const char *Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, +                                       const InputInfo &Output, +                                       const InputInfoList &Inputs, +                                       const ArgList &Args, +                                       const char *LinkingOutput) const { +  ArgStringList CmdArgs; +  CmdArgs.push_back("--verify"); +  CmdArgs.push_back("--debug-info"); +  CmdArgs.push_back("--eh-frame"); +  CmdArgs.push_back("--quiet"); + +  assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); +  const InputInfo &Input = Inputs[0]; +  assert(Input.isFilename() && "Unexpected verify input"); + +  // Grabbing the output of the earlier dsymutil run. +  CmdArgs.push_back(Input.getFilename()); + +  const char *Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) +    : ToolChain(D, Triple, Args) { +  // We expect 'as', 'ld', etc. to be adjacent to our install dir. +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); +} + +/// Darwin - Darwin tool chain for i386 and x86_64. +Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) +    : MachO(D, Triple, Args), TargetInitialized(false), +      CudaInstallation(D, Triple, Args) {} + +types::ID MachO::LookupTypeForExtension(StringRef Ext) const { +  types::ID Ty = types::lookupTypeForExtension(Ext); + +  // Darwin always preprocesses assembly files (unless -x is used explicitly). +  if (Ty == types::TY_PP_Asm) +    return types::TY_Asm; + +  return Ty; +} + +bool MachO::HasNativeLLVMSupport() const { return true; } + +ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const { +  // Default to use libc++ on OS X 10.9+ and iOS 7+. +  if ((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || +       (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || +       isTargetWatchOSBased()) +    return ToolChain::CST_Libcxx; + +  return ToolChain::CST_Libstdcxx; +} + +/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. +ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { +  if (isTargetWatchOSBased()) +    return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); +  if (isTargetIOSBased()) +    return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); +  if (isNonFragile) +    return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); +  return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); +} + +/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. +bool Darwin::hasBlocksRuntime() const { +  if (isTargetWatchOSBased()) +    return true; +  else if (isTargetIOSBased()) +    return !isIPhoneOSVersionLT(3, 2); +  else { +    assert(isTargetMacOS() && "unexpected darwin target"); +    return !isMacosxVersionLT(10, 6); +  } +} + +void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, +                                ArgStringList &CC1Args) const { +  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +// This is just a MachO name translation routine and there's no +// way to join this into ARMTargetParser without breaking all +// other assumptions. Maybe MachO should consider standardising +// their nomenclature. +static const char *ArmMachOArchName(StringRef Arch) { +  return llvm::StringSwitch<const char *>(Arch) +      .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("armv7em", "armv7e-m", "armv7em") +      .Cases("armv7k", "armv7-k", "armv7k") +      .Cases("armv7m", "armv7-m", "armv7m") +      .Cases("armv7s", "armv7-s", "armv7s") +      .Default(nullptr); +} + +static const char *ArmMachOArchNameCPU(StringRef CPU) { +  llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); +  if (ArchKind == llvm::ARM::ArchKind::INVALID) +    return nullptr; +  StringRef Arch = llvm::ARM::getArchName(ArchKind); + +  // FIXME: Make sure this MachO triple mangling is really necessary. +  // ARMv5* normalises to ARMv5. +  if (Arch.startswith("armv5")) +    Arch = Arch.substr(0, 5); +  // ARMv6*, except ARMv6M, normalises to ARMv6. +  else if (Arch.startswith("armv6") && !Arch.endswith("6m")) +    Arch = Arch.substr(0, 5); +  // ARMv7A normalises to ARMv7. +  else if (Arch.endswith("v7a")) +    Arch = Arch.substr(0, 5); +  return Arch.data(); +} + +StringRef MachO::getMachOArchName(const ArgList &Args) const { +  switch (getTriple().getArch()) { +  default: +    return getDefaultUniversalArchName(); + +  case llvm::Triple::aarch64: +    return "arm64"; + +  case llvm::Triple::thumb: +  case llvm::Triple::arm: +    if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) +      if (const char *Arch = ArmMachOArchName(A->getValue())) +        return Arch; + +    if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) +      if (const char *Arch = ArmMachOArchNameCPU(A->getValue())) +        return Arch; + +    return "arm"; +  } +} + +Darwin::~Darwin() {} + +MachO::~MachO() {} + +std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, +                                                types::ID InputType) const { +  llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); + +  // If the target isn't initialized (e.g., an unknown Darwin platform, return +  // the default triple). +  if (!isTargetInitialized()) +    return Triple.getTriple(); + +  SmallString<16> Str; +  if (isTargetWatchOSBased()) +    Str += "watchos"; +  else if (isTargetTvOSBased()) +    Str += "tvos"; +  else if (isTargetIOSBased()) +    Str += "ios"; +  else +    Str += "macosx"; +  Str += getTargetVersion().getAsString(); +  Triple.setOSName(Str); + +  return Triple.getTriple(); +} + +Tool *MachO::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::VerifyDebugInfoJobClass: +    if (!VerifyDebug) +      VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); +    return VerifyDebug.get(); +  default: +    return ToolChain::getTool(AC); +  } +} + +Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } + +Tool *MachO::buildAssembler() const { +  return new tools::darwin::Assembler(*this); +} + +DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple, +                         const ArgList &Args) +    : Darwin(D, Triple, Args) {} + +void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { +  // For modern targets, promote certain warnings to errors. +  if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { +    // Always enable -Wdeprecated-objc-isa-usage and promote it +    // to an error. +    CC1Args.push_back("-Wdeprecated-objc-isa-usage"); +    CC1Args.push_back("-Werror=deprecated-objc-isa-usage"); + +    // For iOS and watchOS, also error about implicit function declarations, +    // as that can impact calling conventions. +    if (!isTargetMacOS()) +      CC1Args.push_back("-Werror=implicit-function-declaration"); +  } +} + +/// Take a path that speculatively points into Xcode and return the +/// `XCODE/Contents/Developer` path if it is an Xcode path, or an empty path +/// otherwise. +static StringRef getXcodeDeveloperPath(StringRef PathIntoXcode) { +  static constexpr llvm::StringLiteral XcodeAppSuffix( +      ".app/Contents/Developer"); +  size_t Index = PathIntoXcode.find(XcodeAppSuffix); +  if (Index == StringRef::npos) +    return ""; +  return PathIntoXcode.take_front(Index + XcodeAppSuffix.size()); +} + +void DarwinClang::AddLinkARCArgs(const ArgList &Args, +                                 ArgStringList &CmdArgs) const { +  // Avoid linking compatibility stubs on i386 mac. +  if (isTargetMacOS() && getArch() == llvm::Triple::x86) +    return; + +  ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); + +  if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) && +      runtime.hasSubscripting()) +    return; + +  SmallString<128> P(getDriver().ClangExecutable); +  llvm::sys::path::remove_filename(P); // 'clang' +  llvm::sys::path::remove_filename(P); // 'bin' + +  // 'libarclite' usually lives in the same toolchain as 'clang'. However, the +  // Swift open source toolchains for macOS distribute Clang without libarclite. +  // In that case, to allow the linker to find 'libarclite', we point to the +  // 'libarclite' in the XcodeDefault toolchain instead. +  if (getXcodeDeveloperPath(P).empty()) { +    if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +      // Try to infer the path to 'libarclite' in the toolchain from the +      // specified SDK path. +      StringRef XcodePathForSDK = getXcodeDeveloperPath(A->getValue()); +      if (!XcodePathForSDK.empty()) { +        P = XcodePathForSDK; +        llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr"); +      } +    } +  } + +  CmdArgs.push_back("-force_load"); +  llvm::sys::path::append(P, "lib", "arc", "libarclite_"); +  // Mash in the platform. +  if (isTargetWatchOSSimulator()) +    P += "watchsimulator"; +  else if (isTargetWatchOS()) +    P += "watchos"; +  else if (isTargetTvOSSimulator()) +    P += "appletvsimulator"; +  else if (isTargetTvOS()) +    P += "appletvos"; +  else if (isTargetIOSSimulator()) +    P += "iphonesimulator"; +  else if (isTargetIPhoneOS()) +    P += "iphoneos"; +  else +    P += "macosx"; +  P += ".a"; + +  CmdArgs.push_back(Args.MakeArgString(P)); +} + +unsigned DarwinClang::GetDefaultDwarfVersion() const { +  // Default to use DWARF 2 on OS X 10.10 / iOS 8 and lower. +  if ((isTargetMacOS() && isMacosxVersionLT(10, 11)) || +      (isTargetIOSBased() && isIPhoneOSVersionLT(9))) +    return 2; +  return 4; +} + +void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, +                              StringRef Component, RuntimeLinkOptions Opts, +                              bool IsShared) const { +  SmallString<64> DarwinLibName = StringRef("libclang_rt."); +  // an Darwin the builtins compomnent is not in the library name +  if (Component != "builtins") { +    DarwinLibName += Component; +    if (!(Opts & RLO_IsEmbedded)) +      DarwinLibName += "_"; +    DarwinLibName += getOSLibraryNameSuffix(); +  } else +    DarwinLibName += getOSLibraryNameSuffix(true); + +  DarwinLibName += IsShared ? "_dynamic.dylib" : ".a"; +  SmallString<128> Dir(getDriver().ResourceDir); +  llvm::sys::path::append( +      Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin"); + +  SmallString<128> P(Dir); +  llvm::sys::path::append(P, DarwinLibName); + +  // For now, allow missing resource libraries to support developers who may +  // not have compiler-rt checked out or integrated into their build (unless +  // we explicitly force linking with this library). +  if ((Opts & RLO_AlwaysLink) || getVFS().exists(P)) { +    const char *LibArg = Args.MakeArgString(P); +    if (Opts & RLO_FirstLink) +      CmdArgs.insert(CmdArgs.begin(), LibArg); +    else +      CmdArgs.push_back(LibArg); +  } + +  // Adding the rpaths might negatively interact when other rpaths are involved, +  // so we should make sure we add the rpaths last, after all user-specified +  // rpaths. This is currently true from this place, but we need to be +  // careful if this function is ever called before user's rpaths are emitted. +  if (Opts & RLO_AddRPath) { +    assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); + +    // Add @executable_path to rpath to support having the dylib copied with +    // the executable. +    CmdArgs.push_back("-rpath"); +    CmdArgs.push_back("@executable_path"); + +    // Add the path to the resource dir to rpath to support using the dylib +    // from the default location without copying. +    CmdArgs.push_back("-rpath"); +    CmdArgs.push_back(Args.MakeArgString(Dir)); +  } +} + +StringRef Darwin::getPlatformFamily() const { +  switch (TargetPlatform) { +    case DarwinPlatformKind::MacOS: +      return "MacOSX"; +    case DarwinPlatformKind::IPhoneOS: +      return "iPhone"; +    case DarwinPlatformKind::TvOS: +      return "AppleTV"; +    case DarwinPlatformKind::WatchOS: +      return "Watch"; +  } +  llvm_unreachable("Unsupported platform"); +} + +StringRef Darwin::getSDKName(StringRef isysroot) { +  // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk +  llvm::sys::path::const_iterator SDKDir; +  auto BeginSDK = llvm::sys::path::begin(isysroot); +  auto EndSDK = llvm::sys::path::end(isysroot); +  for (auto IT = BeginSDK; IT != EndSDK; ++IT) { +    StringRef SDK = *IT; +    if (SDK.endswith(".sdk")) +      return SDK.slice(0, SDK.size() - 4); +  } +  return ""; +} + +StringRef Darwin::getOSLibraryNameSuffix(bool IgnoreSim) const { +  switch (TargetPlatform) { +  case DarwinPlatformKind::MacOS: +    return "osx"; +  case DarwinPlatformKind::IPhoneOS: +    return TargetEnvironment == NativeEnvironment || IgnoreSim ? "ios" +                                                               : "iossim"; +  case DarwinPlatformKind::TvOS: +    return TargetEnvironment == NativeEnvironment || IgnoreSim ? "tvos" +                                                               : "tvossim"; +  case DarwinPlatformKind::WatchOS: +    return TargetEnvironment == NativeEnvironment || IgnoreSim ? "watchos" +                                                               : "watchossim"; +  } +  llvm_unreachable("Unsupported platform"); +} + +/// Check if the link command contains a symbol export directive. +static bool hasExportSymbolDirective(const ArgList &Args) { +  for (Arg *A : Args) { +    if (A->getOption().matches(options::OPT_exported__symbols__list)) +      return true; +    if (!A->getOption().matches(options::OPT_Wl_COMMA) && +        !A->getOption().matches(options::OPT_Xlinker)) +      continue; +    if (A->containsValue("-exported_symbols_list") || +        A->containsValue("-exported_symbol")) +      return true; +  } +  return false; +} + +/// Add an export directive for \p Symbol to the link command. +static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) { +  CmdArgs.push_back("-exported_symbol"); +  CmdArgs.push_back(Symbol); +} + +void Darwin::addProfileRTLibs(const ArgList &Args, +                              ArgStringList &CmdArgs) const { +  if (!needsProfileRT(Args)) return; + +  AddLinkRuntimeLib(Args, CmdArgs, "profile", +                    RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink)); + +  // If we have a symbol export directive and we're linking in the profile +  // runtime, automatically export symbols necessary to implement some of the +  // runtime's functionality. +  if (hasExportSymbolDirective(Args)) { +    if (needsGCovInstrumentation(Args)) { +      addExportedSymbol(CmdArgs, "___gcov_flush"); +      addExportedSymbol(CmdArgs, "_flush_fn_list"); +      addExportedSymbol(CmdArgs, "_writeout_fn_list"); +    } else { +      addExportedSymbol(CmdArgs, "___llvm_profile_filename"); +      addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); +    } +    addExportedSymbol(CmdArgs, "_lprofDirMode"); +  } +} + +void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, +                                          ArgStringList &CmdArgs, +                                          StringRef Sanitizer, +                                          bool Shared) const { +  auto RLO = RuntimeLinkOptions(RLO_AlwaysLink | (Shared ? RLO_AddRPath : 0U)); +  AddLinkRuntimeLib(Args, CmdArgs, Sanitizer, RLO, Shared); +} + +ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( +    const ArgList &Args) const { +  if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { +    StringRef Value = A->getValue(); +    if (Value != "compiler-rt") +      getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform) +          << Value << "darwin"; +  } + +  return ToolChain::RLT_CompilerRT; +} + +void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, +                                        ArgStringList &CmdArgs, +                                        bool ForceLinkBuiltinRT) const { +  // Call once to ensure diagnostic is printed if wrong value was specified +  GetRuntimeLibType(Args); + +  // Darwin doesn't support real static executables, don't link any runtime +  // libraries with -static. +  if (Args.hasArg(options::OPT_static) || +      Args.hasArg(options::OPT_fapple_kext) || +      Args.hasArg(options::OPT_mkernel)) { +    if (ForceLinkBuiltinRT) +      AddLinkRuntimeLib(Args, CmdArgs, "builtins"); +    return; +  } + +  // Reject -static-libgcc for now, we can deal with this when and if someone +  // cares. This is useful in situations where someone wants to statically link +  // something like libstdc++, and needs its runtime support routines. +  if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { +    getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); +    return; +  } + +  const SanitizerArgs &Sanitize = getSanitizerArgs(); +  if (Sanitize.needsAsanRt()) +    AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); +  if (Sanitize.needsLsanRt()) +    AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); +  if (Sanitize.needsUbsanRt()) +    AddLinkSanitizerLibArgs(Args, CmdArgs, +                            Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" +                                                              : "ubsan", +                            Sanitize.needsSharedRt()); +  if (Sanitize.needsTsanRt()) +    AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); +  if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { +    AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); + +    // Libfuzzer is written in C++ and requires libcxx. +    AddCXXStdlibLibArgs(Args, CmdArgs); +  } +  if (Sanitize.needsStatsRt()) { +    AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink); +    AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); +  } + +  const XRayArgs &XRay = getXRayArgs(); +  if (XRay.needsXRayRt()) { +    AddLinkRuntimeLib(Args, CmdArgs, "xray"); +    AddLinkRuntimeLib(Args, CmdArgs, "xray-basic"); +    AddLinkRuntimeLib(Args, CmdArgs, "xray-fdr"); +  } + +  // Otherwise link libSystem, then the dynamic runtime library, and finally any +  // target specific static runtime library. +  CmdArgs.push_back("-lSystem"); + +  // Select the dynamic runtime library and the target specific static library. +  if (isTargetIOSBased()) { +    // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, +    // it never went into the SDK. +    // Linking against libgcc_s.1 isn't needed for iOS 5.0+ +    if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() && +        getTriple().getArch() != llvm::Triple::aarch64) +      CmdArgs.push_back("-lgcc_s.1"); +  } +  AddLinkRuntimeLib(Args, CmdArgs, "builtins"); +} + +/// Returns the most appropriate macOS target version for the current process. +/// +/// If the macOS SDK version is the same or earlier than the system version, +/// then the SDK version is returned. Otherwise the system version is returned. +static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { +  unsigned Major, Minor, Micro; +  llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); +  if (!SystemTriple.isMacOSX()) +    return MacOSSDKVersion; +  SystemTriple.getMacOSXVersion(Major, Minor, Micro); +  VersionTuple SystemVersion(Major, Minor, Micro); +  bool HadExtra; +  if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro, +                                 HadExtra)) +    return MacOSSDKVersion; +  VersionTuple SDKVersion(Major, Minor, Micro); +  if (SDKVersion > SystemVersion) +    return SystemVersion.getAsString(); +  return MacOSSDKVersion; +} + +namespace { + +/// The Darwin OS that was selected or inferred from arguments / environment. +struct DarwinPlatform { +  enum SourceKind { +    /// The OS was specified using the -target argument. +    TargetArg, +    /// The OS was specified using the -m<os>-version-min argument. +    OSVersionArg, +    /// The OS was specified using the OS_DEPLOYMENT_TARGET environment. +    DeploymentTargetEnv, +    /// The OS was inferred from the SDK. +    InferredFromSDK, +    /// The OS was inferred from the -arch. +    InferredFromArch +  }; + +  using DarwinPlatformKind = Darwin::DarwinPlatformKind; +  using DarwinEnvironmentKind = Darwin::DarwinEnvironmentKind; + +  DarwinPlatformKind getPlatform() const { return Platform; } + +  DarwinEnvironmentKind getEnvironment() const { return Environment; } + +  void setEnvironment(DarwinEnvironmentKind Kind) { +    Environment = Kind; +    InferSimulatorFromArch = false; +  } + +  StringRef getOSVersion() const { +    if (Kind == OSVersionArg) +      return Argument->getValue(); +    return OSVersion; +  } + +  void setOSVersion(StringRef S) { +    assert(Kind == TargetArg && "Unexpected kind!"); +    OSVersion = S; +  } + +  bool hasOSVersion() const { return HasOSVersion; } + +  /// Returns true if the target OS was explicitly specified. +  bool isExplicitlySpecified() const { return Kind <= DeploymentTargetEnv; } + +  /// Returns true if the simulator environment can be inferred from the arch. +  bool canInferSimulatorFromArch() const { return InferSimulatorFromArch; } + +  /// Adds the -m<os>-version-min argument to the compiler invocation. +  void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) { +    if (Argument) +      return; +    assert(Kind != TargetArg && Kind != OSVersionArg && "Invalid kind"); +    options::ID Opt; +    switch (Platform) { +    case DarwinPlatformKind::MacOS: +      Opt = options::OPT_mmacosx_version_min_EQ; +      break; +    case DarwinPlatformKind::IPhoneOS: +      Opt = options::OPT_miphoneos_version_min_EQ; +      break; +    case DarwinPlatformKind::TvOS: +      Opt = options::OPT_mtvos_version_min_EQ; +      break; +    case DarwinPlatformKind::WatchOS: +      Opt = options::OPT_mwatchos_version_min_EQ; +      break; +    } +    Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion); +    Args.append(Argument); +  } + +  /// Returns the OS version with the argument / environment variable that +  /// specified it. +  std::string getAsString(DerivedArgList &Args, const OptTable &Opts) { +    switch (Kind) { +    case TargetArg: +    case OSVersionArg: +    case InferredFromSDK: +    case InferredFromArch: +      assert(Argument && "OS version argument not yet inferred"); +      return Argument->getAsString(Args); +    case DeploymentTargetEnv: +      return (llvm::Twine(EnvVarName) + "=" + OSVersion).str(); +    } +    llvm_unreachable("Unsupported Darwin Source Kind"); +  } + +  static DarwinPlatform createFromTarget(const llvm::Triple &TT, +                                         StringRef OSVersion, Arg *A) { +    DarwinPlatform Result(TargetArg, getPlatformFromOS(TT.getOS()), OSVersion, +                          A); +    switch (TT.getEnvironment()) { +    case llvm::Triple::Simulator: +      Result.Environment = DarwinEnvironmentKind::Simulator; +      break; +    default: +      break; +    } +    unsigned Major, Minor, Micro; +    TT.getOSVersion(Major, Minor, Micro); +    if (Major == 0) +      Result.HasOSVersion = false; +    return Result; +  } +  static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, +                                           Arg *A) { +    return DarwinPlatform(OSVersionArg, Platform, A); +  } +  static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform, +                                                  StringRef EnvVarName, +                                                  StringRef Value) { +    DarwinPlatform Result(DeploymentTargetEnv, Platform, Value); +    Result.EnvVarName = EnvVarName; +    return Result; +  } +  static DarwinPlatform createFromSDK(DarwinPlatformKind Platform, +                                      StringRef Value, +                                      bool IsSimulator = false) { +    DarwinPlatform Result(InferredFromSDK, Platform, Value); +    if (IsSimulator) +      Result.Environment = DarwinEnvironmentKind::Simulator; +    Result.InferSimulatorFromArch = false; +    return Result; +  } +  static DarwinPlatform createFromArch(llvm::Triple::OSType OS, +                                       StringRef Value) { +    return DarwinPlatform(InferredFromArch, getPlatformFromOS(OS), Value); +  } + +  /// Constructs an inferred SDKInfo value based on the version inferred from +  /// the SDK path itself. Only works for values that were created by inferring +  /// the platform from the SDKPath. +  DarwinSDKInfo inferSDKInfo() { +    assert(Kind == InferredFromSDK && "can infer SDK info only"); +    llvm::VersionTuple Version; +    bool IsValid = !Version.tryParse(OSVersion); +    (void)IsValid; +    assert(IsValid && "invalid SDK version"); +    return DarwinSDKInfo(Version); +  } + +private: +  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg *Argument) +      : Kind(Kind), Platform(Platform), Argument(Argument) {} +  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef Value, +                 Arg *Argument = nullptr) +      : Kind(Kind), Platform(Platform), OSVersion(Value), Argument(Argument) {} + +  static DarwinPlatformKind getPlatformFromOS(llvm::Triple::OSType OS) { +    switch (OS) { +    case llvm::Triple::Darwin: +    case llvm::Triple::MacOSX: +      return DarwinPlatformKind::MacOS; +    case llvm::Triple::IOS: +      return DarwinPlatformKind::IPhoneOS; +    case llvm::Triple::TvOS: +      return DarwinPlatformKind::TvOS; +    case llvm::Triple::WatchOS: +      return DarwinPlatformKind::WatchOS; +    default: +      llvm_unreachable("Unable to infer Darwin variant"); +    } +  } + +  SourceKind Kind; +  DarwinPlatformKind Platform; +  DarwinEnvironmentKind Environment = DarwinEnvironmentKind::NativeEnvironment; +  std::string OSVersion; +  bool HasOSVersion = true, InferSimulatorFromArch = true; +  Arg *Argument; +  StringRef EnvVarName; +}; + +/// Returns the deployment target that's specified using the -m<os>-version-min +/// argument. +Optional<DarwinPlatform> +getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, +                                    const Driver &TheDriver) { +  Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); +  Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ, +                                    options::OPT_mios_simulator_version_min_EQ); +  Arg *TvOSVersion = +      Args.getLastArg(options::OPT_mtvos_version_min_EQ, +                      options::OPT_mtvos_simulator_version_min_EQ); +  Arg *WatchOSVersion = +      Args.getLastArg(options::OPT_mwatchos_version_min_EQ, +                      options::OPT_mwatchos_simulator_version_min_EQ); +  if (OSXVersion) { +    if (iOSVersion || TvOSVersion || WatchOSVersion) { +      TheDriver.Diag(diag::err_drv_argument_not_allowed_with) +          << OSXVersion->getAsString(Args) +          << (iOSVersion ? iOSVersion +                         : TvOSVersion ? TvOSVersion : WatchOSVersion) +                 ->getAsString(Args); +    } +    return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion); +  } else if (iOSVersion) { +    if (TvOSVersion || WatchOSVersion) { +      TheDriver.Diag(diag::err_drv_argument_not_allowed_with) +          << iOSVersion->getAsString(Args) +          << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); +    } +    return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion); +  } else if (TvOSVersion) { +    if (WatchOSVersion) { +      TheDriver.Diag(diag::err_drv_argument_not_allowed_with) +          << TvOSVersion->getAsString(Args) +          << WatchOSVersion->getAsString(Args); +    } +    return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion); +  } else if (WatchOSVersion) +    return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion); +  return None; +} + +/// Returns the deployment target that's specified using the +/// OS_DEPLOYMENT_TARGET environment variable. +Optional<DarwinPlatform> +getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, +                                            const llvm::Triple &Triple) { +  std::string Targets[Darwin::LastDarwinPlatform + 1]; +  const char *EnvVars[] = { +      "MACOSX_DEPLOYMENT_TARGET", +      "IPHONEOS_DEPLOYMENT_TARGET", +      "TVOS_DEPLOYMENT_TARGET", +      "WATCHOS_DEPLOYMENT_TARGET", +  }; +  static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1, +                "Missing platform"); +  for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) { +    if (char *Env = ::getenv(I.value())) +      Targets[I.index()] = Env; +  } + +  // Allow conflicts among OSX and iOS for historical reasons, but choose the +  // default platform. +  if (!Targets[Darwin::MacOS].empty() && +      (!Targets[Darwin::IPhoneOS].empty() || +       !Targets[Darwin::WatchOS].empty() || !Targets[Darwin::TvOS].empty())) { +    if (Triple.getArch() == llvm::Triple::arm || +        Triple.getArch() == llvm::Triple::aarch64 || +        Triple.getArch() == llvm::Triple::thumb) +      Targets[Darwin::MacOS] = ""; +    else +      Targets[Darwin::IPhoneOS] = Targets[Darwin::WatchOS] = +          Targets[Darwin::TvOS] = ""; +  } else { +    // Don't allow conflicts in any other platform. +    int FirstTarget = llvm::array_lengthof(Targets); +    for (int I = 0; I != llvm::array_lengthof(Targets); ++I) { +      if (Targets[I].empty()) +        continue; +      if (FirstTarget == llvm::array_lengthof(Targets)) +        FirstTarget = I; +      else +        TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) +            << Targets[FirstTarget] << Targets[I]; +    } +  } + +  for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) { +    if (!Target.value().empty()) +      return DarwinPlatform::createDeploymentTargetEnv( +          (Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()], +          Target.value()); +  } +  return None; +} + +/// Tries to infer the deployment target from the SDK specified by -isysroot +/// (or SDKROOT). Uses the version specified in the SDKSettings.json file if +/// it's available. +Optional<DarwinPlatform> +inferDeploymentTargetFromSDK(DerivedArgList &Args, +                             const Optional<DarwinSDKInfo> &SDKInfo) { +  const Arg *A = Args.getLastArg(options::OPT_isysroot); +  if (!A) +    return None; +  StringRef isysroot = A->getValue(); +  StringRef SDK = Darwin::getSDKName(isysroot); +  if (!SDK.size()) +    return None; + +  std::string Version; +  if (SDKInfo) { +    // Get the version from the SDKSettings.json if it's available. +    Version = SDKInfo->getVersion().getAsString(); +  } else { +    // Slice the version number out. +    // Version number is between the first and the last number. +    size_t StartVer = SDK.find_first_of("0123456789"); +    size_t EndVer = SDK.find_last_of("0123456789"); +    if (StartVer != StringRef::npos && EndVer > StartVer) +      Version = SDK.slice(StartVer, EndVer + 1); +  } +  if (Version.empty()) +    return None; + +  if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) +    return DarwinPlatform::createFromSDK( +        Darwin::IPhoneOS, Version, +        /*IsSimulator=*/SDK.startswith("iPhoneSimulator")); +  else if (SDK.startswith("MacOSX")) +    return DarwinPlatform::createFromSDK(Darwin::MacOS, +                                         getSystemOrSDKMacOSVersion(Version)); +  else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) +    return DarwinPlatform::createFromSDK( +        Darwin::WatchOS, Version, +        /*IsSimulator=*/SDK.startswith("WatchSimulator")); +  else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) +    return DarwinPlatform::createFromSDK( +        Darwin::TvOS, Version, +        /*IsSimulator=*/SDK.startswith("AppleTVSimulator")); +  return None; +} + +std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, +                         const Driver &TheDriver) { +  unsigned Major, Minor, Micro; +  llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); +  switch (OS) { +  case llvm::Triple::Darwin: +  case llvm::Triple::MacOSX: +    // If there is no version specified on triple, and both host and target are +    // macos, use the host triple to infer OS version. +    if (Triple.isMacOSX() && SystemTriple.isMacOSX() && +        !Triple.getOSMajorVersion()) +      SystemTriple.getMacOSXVersion(Major, Minor, Micro); +    else if (!Triple.getMacOSXVersion(Major, Minor, Micro)) +      TheDriver.Diag(diag::err_drv_invalid_darwin_version) +          << Triple.getOSName(); +    break; +  case llvm::Triple::IOS: +    Triple.getiOSVersion(Major, Minor, Micro); +    break; +  case llvm::Triple::TvOS: +    Triple.getOSVersion(Major, Minor, Micro); +    break; +  case llvm::Triple::WatchOS: +    Triple.getWatchOSVersion(Major, Minor, Micro); +    break; +  default: +    llvm_unreachable("Unexpected OS type"); +    break; +  } + +  std::string OSVersion; +  llvm::raw_string_ostream(OSVersion) << Major << '.' << Minor << '.' << Micro; +  return OSVersion; +} + +/// Tries to infer the target OS from the -arch. +Optional<DarwinPlatform> +inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, +                              const llvm::Triple &Triple, +                              const Driver &TheDriver) { +  llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; + +  StringRef MachOArchName = Toolchain.getMachOArchName(Args); +  if (MachOArchName == "armv7" || MachOArchName == "armv7s" || +      MachOArchName == "arm64") +    OSTy = llvm::Triple::IOS; +  else if (MachOArchName == "armv7k") +    OSTy = llvm::Triple::WatchOS; +  else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && +           MachOArchName != "armv7em") +    OSTy = llvm::Triple::MacOSX; + +  if (OSTy == llvm::Triple::UnknownOS) +    return None; +  return DarwinPlatform::createFromArch(OSTy, +                                        getOSVersion(OSTy, Triple, TheDriver)); +} + +/// Returns the deployment target that's specified using the -target option. +Optional<DarwinPlatform> getDeploymentTargetFromTargetArg( +    DerivedArgList &Args, const llvm::Triple &Triple, const Driver &TheDriver) { +  if (!Args.hasArg(options::OPT_target)) +    return None; +  if (Triple.getOS() == llvm::Triple::Darwin || +      Triple.getOS() == llvm::Triple::UnknownOS) +    return None; +  std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver); +  return DarwinPlatform::createFromTarget(Triple, OSVersion, +                                          Args.getLastArg(options::OPT_target)); +} + +Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS, +                                         const ArgList &Args, +                                         const Driver &TheDriver) { +  const Arg *A = Args.getLastArg(options::OPT_isysroot); +  if (!A) +    return None; +  StringRef isysroot = A->getValue(); +  auto SDKInfoOrErr = driver::parseDarwinSDKInfo(VFS, isysroot); +  if (!SDKInfoOrErr) { +    llvm::consumeError(SDKInfoOrErr.takeError()); +    TheDriver.Diag(diag::warn_drv_darwin_sdk_invalid_settings); +    return None; +  } +  return *SDKInfoOrErr; +} + +} // namespace + +void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { +  const OptTable &Opts = getDriver().getOpts(); + +  // 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 (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +    // Warn if the path does not exist. +    if (!getVFS().exists(A->getValue())) +      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, +      // exists, and it is not the root path. +      if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && +          StringRef(env) != "/") { +        Args.append(Args.MakeSeparateArg( +            nullptr, Opts.getOption(options::OPT_isysroot), env)); +      } +    } +  } + +  // Read the SDKSettings.json file for more information, like the SDK version +  // that we can pass down to the compiler. +  SDKInfo = parseSDKSettings(getVFS(), Args, getDriver()); + +  // The OS and the version can be specified using the -target argument. +  Optional<DarwinPlatform> OSTarget = +      getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver()); +  if (OSTarget) { +    Optional<DarwinPlatform> OSVersionArgTarget = +        getDeploymentTargetFromOSVersionArg(Args, getDriver()); +    if (OSVersionArgTarget) { +      unsigned TargetMajor, TargetMinor, TargetMicro; +      bool TargetExtra; +      unsigned ArgMajor, ArgMinor, ArgMicro; +      bool ArgExtra; +      if (OSTarget->getPlatform() != OSVersionArgTarget->getPlatform() || +          (Driver::GetReleaseVersion(OSTarget->getOSVersion(), TargetMajor, +                                     TargetMinor, TargetMicro, TargetExtra) && +           Driver::GetReleaseVersion(OSVersionArgTarget->getOSVersion(), +                                     ArgMajor, ArgMinor, ArgMicro, ArgExtra) && +           (VersionTuple(TargetMajor, TargetMinor, TargetMicro) != +                VersionTuple(ArgMajor, ArgMinor, ArgMicro) || +            TargetExtra != ArgExtra))) { +        // Select the OS version from the -m<os>-version-min argument when +        // the -target does not include an OS version. +        if (OSTarget->getPlatform() == OSVersionArgTarget->getPlatform() && +            !OSTarget->hasOSVersion()) { +          OSTarget->setOSVersion(OSVersionArgTarget->getOSVersion()); +        } else { +          // Warn about -m<os>-version-min that doesn't match the OS version +          // that's specified in the target. +          std::string OSVersionArg = +              OSVersionArgTarget->getAsString(Args, Opts); +          std::string TargetArg = OSTarget->getAsString(Args, Opts); +          getDriver().Diag(clang::diag::warn_drv_overriding_flag_option) +              << OSVersionArg << TargetArg; +        } +      } +    } +  } else { +    // The OS target can be specified using the -m<os>version-min argument. +    OSTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); +    // If no deployment target was specified on the command line, check for +    // environment defines. +    if (!OSTarget) { +      OSTarget = +          getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple()); +      if (OSTarget) { +        // Don't infer simulator from the arch when the SDK is also specified. +        Optional<DarwinPlatform> SDKTarget = +            inferDeploymentTargetFromSDK(Args, SDKInfo); +        if (SDKTarget) +          OSTarget->setEnvironment(SDKTarget->getEnvironment()); +      } +    } +    // If there is no command-line argument to specify the Target version and +    // no environment variable defined, see if we can set the default based +    // on -isysroot using SDKSettings.json if it exists. +    if (!OSTarget) { +      OSTarget = inferDeploymentTargetFromSDK(Args, SDKInfo); +      /// If the target was successfully constructed from the SDK path, try to +      /// infer the SDK info if the SDK doesn't have it. +      if (OSTarget && !SDKInfo) +        SDKInfo = OSTarget->inferSDKInfo(); +    } +    // If no OS targets have been specified, try to guess platform from -target +    // or arch name and compute the version from the triple. +    if (!OSTarget) +      OSTarget = +          inferDeploymentTargetFromArch(Args, *this, getTriple(), getDriver()); +  } + +  assert(OSTarget && "Unable to infer Darwin variant"); +  OSTarget->addOSVersionMinArgument(Args, Opts); +  DarwinPlatformKind Platform = OSTarget->getPlatform(); + +  unsigned Major, Minor, Micro; +  bool HadExtra; +  // Set the tool chain target information. +  if (Platform == MacOS) { +    if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, +                                   Micro, HadExtra) || +        HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) +      getDriver().Diag(diag::err_drv_invalid_version_number) +          << OSTarget->getAsString(Args, Opts); +  } else if (Platform == IPhoneOS) { +    if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, +                                   Micro, HadExtra) || +        HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) +      getDriver().Diag(diag::err_drv_invalid_version_number) +          << OSTarget->getAsString(Args, Opts); +    ; +    // For 32-bit targets, the deployment target for iOS has to be earlier than +    // iOS 11. +    if (getTriple().isArch32Bit() && Major >= 11) { +      // If the deployment target is explicitly specified, print a diagnostic. +      if (OSTarget->isExplicitlySpecified()) { +        getDriver().Diag(diag::warn_invalid_ios_deployment_target) +            << OSTarget->getAsString(Args, Opts); +        // Otherwise, set it to 10.99.99. +      } else { +        Major = 10; +        Minor = 99; +        Micro = 99; +      } +    } +  } else if (Platform == TvOS) { +    if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, +                                   Micro, HadExtra) || +        HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) +      getDriver().Diag(diag::err_drv_invalid_version_number) +          << OSTarget->getAsString(Args, Opts); +  } else if (Platform == WatchOS) { +    if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, +                                   Micro, HadExtra) || +        HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) +      getDriver().Diag(diag::err_drv_invalid_version_number) +          << OSTarget->getAsString(Args, Opts); +  } else +    llvm_unreachable("unknown kind of Darwin platform"); + +  DarwinEnvironmentKind Environment = OSTarget->getEnvironment(); +  // Recognize iOS targets with an x86 architecture as the iOS simulator. +  if (Environment == NativeEnvironment && Platform != MacOS && +      OSTarget->canInferSimulatorFromArch() && +      (getTriple().getArch() == llvm::Triple::x86 || +       getTriple().getArch() == llvm::Triple::x86_64)) +    Environment = Simulator; + +  setTarget(Platform, Environment, Major, Minor, Micro); + +  if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +    StringRef SDK = getSDKName(A->getValue()); +    if (SDK.size() > 0) { +      size_t StartVer = SDK.find_first_of("0123456789"); +      StringRef SDKName = SDK.slice(0, StartVer); +      if (!SDKName.startswith(getPlatformFamily())) +        getDriver().Diag(diag::warn_incompatible_sysroot) +            << SDKName << getPlatformFamily(); +    } +  } +} + +// Returns the effective header sysroot path to use. This comes either from +// -isysroot or --sysroot. +llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const { +  if(DriverArgs.hasArg(options::OPT_isysroot)) +    return DriverArgs.getLastArgValue(options::OPT_isysroot); +  if (!getDriver().SysRoot.empty()) +    return getDriver().SysRoot; +  return "/"; +} + +void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                                            llvm::opt::ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); + +  llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + +  bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc); +  bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc); +  bool NoBuiltinInc = DriverArgs.hasArg(options::OPT_nobuiltininc); + +  // Add <sysroot>/usr/local/include +  if (!NoStdInc && !NoStdlibInc) { +      SmallString<128> P(Sysroot); +      llvm::sys::path::append(P, "usr", "local", "include"); +      addSystemInclude(DriverArgs, CC1Args, P); +  } + +  // Add the Clang builtin headers (<resource>/include) +  if (!NoStdInc && !NoBuiltinInc) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  if (NoStdInc || NoStdlibInc) +    return; + +  // Check for configure-time C include directories. +  llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); +  if (!CIncludeDirs.empty()) { +    llvm::SmallVector<llvm::StringRef, 5> dirs; +    CIncludeDirs.split(dirs, ":"); +    for (llvm::StringRef dir : dirs) { +      llvm::StringRef Prefix = +          llvm::sys::path::is_absolute(dir) ? llvm::StringRef(Sysroot) : ""; +      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); +    } +  } else { +    // Otherwise, add <sysroot>/usr/include. +    SmallString<128> P(Sysroot); +    llvm::sys::path::append(P, "usr", "include"); +    addExternCSystemInclude(DriverArgs, CC1Args, P.str()); +  } +} + +bool DarwinClang::AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                              llvm::opt::ArgStringList &CC1Args, +                                              llvm::SmallString<128> Base, +                                              llvm::StringRef Version, +                                              llvm::StringRef ArchDir, +                                              llvm::StringRef BitDir) const { +  llvm::sys::path::append(Base, Version); + +  // Add the base dir +  addSystemInclude(DriverArgs, CC1Args, Base); + +  // Add the multilib dirs +  { +    llvm::SmallString<128> P = Base; +    if (!ArchDir.empty()) +      llvm::sys::path::append(P, ArchDir); +    if (!BitDir.empty()) +      llvm::sys::path::append(P, BitDir); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  // Add the backward dir +  { +    llvm::SmallString<128> P = Base; +    llvm::sys::path::append(P, "backward"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  return getVFS().exists(Base); +} + +void DarwinClang::AddClangCXXStdlibIncludeArgs( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  // The implementation from a base class will pass through the -stdlib to +  // CC1Args. +  // FIXME: this should not be necessary, remove usages in the frontend +  //        (e.g. HeaderSearchOptions::UseLibcxx) and don't pipe -stdlib. +  //        Also check whether this is used for setting library search paths. +  ToolChain::AddClangCXXStdlibIncludeArgs(DriverArgs, CC1Args); + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + +  switch (GetCXXStdlibType(DriverArgs)) { +  case ToolChain::CST_Libcxx: { +    // On Darwin, libc++ is installed alongside the compiler in +    // include/c++/v1, so get from '<install>/bin' to '<install>/include/c++/v1'. +    { +      llvm::SmallString<128> P = llvm::StringRef(getDriver().getInstalledDir()); +      // Note that P can be relative, so we have to '..' and not parent_path. +      llvm::sys::path::append(P, "..", "include", "c++", "v1"); +      addSystemInclude(DriverArgs, CC1Args, P); +    } +    // Also add <sysroot>/usr/include/c++/v1 unless -nostdinc is used, +    // to match the legacy behavior in CC1. +    if (!DriverArgs.hasArg(options::OPT_nostdinc)) { +      llvm::SmallString<128> P = Sysroot; +      llvm::sys::path::append(P, "usr", "include", "c++", "v1"); +      addSystemInclude(DriverArgs, CC1Args, P); +    } +    break; +  } + +  case ToolChain::CST_Libstdcxx: +    llvm::SmallString<128> UsrIncludeCxx = Sysroot; +    llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++"); + +    llvm::Triple::ArchType arch = getTriple().getArch(); +    bool IsBaseFound = true; +    switch (arch) { +    default: break; + +    case llvm::Triple::ppc: +    case llvm::Triple::ppc64: +      IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.2.1", +                                                "powerpc-apple-darwin10", +                                                arch == llvm::Triple::ppc64 ? "ppc64" : ""); +      IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.0.0", "powerpc-apple-darwin10", +                                                 arch == llvm::Triple::ppc64 ? "ppc64" : ""); +      break; + +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.2.1", +                                                "i686-apple-darwin10", +                                                arch == llvm::Triple::x86_64 ? "x86_64" : ""); +      IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.0.0", "i686-apple-darwin8", +                                                 ""); +      break; + +    case llvm::Triple::arm: +    case llvm::Triple::thumb: +      IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.2.1", +                                                "arm-apple-darwin10", +                                                "v7"); +      IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.2.1", +                                                "arm-apple-darwin10", +                                                 "v6"); +      break; + +    case llvm::Triple::aarch64: +      IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, +                                                "4.2.1", +                                                "arm64-apple-darwin10", +                                                ""); +      break; +    } + +    if (!IsBaseFound) { +      getDriver().Diag(diag::warn_drv_libstdcxx_not_found); +    } + +    break; +  } +} +void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, +                                      ArgStringList &CmdArgs) const { +  CXXStdlibType Type = GetCXXStdlibType(Args); + +  switch (Type) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    break; + +  case ToolChain::CST_Libstdcxx: +    // Unfortunately, -lstdc++ doesn't always exist in the standard search path; +    // it was previously found in the gcc lib dir. However, for all the Darwin +    // platforms we care about it was -lstdc++.6, so we search for that +    // explicitly if we can't see an obvious -lstdc++ candidate. + +    // Check in the sysroot first. +    if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +      SmallString<128> P(A->getValue()); +      llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); + +      if (!getVFS().exists(P)) { +        llvm::sys::path::remove_filename(P); +        llvm::sys::path::append(P, "libstdc++.6.dylib"); +        if (getVFS().exists(P)) { +          CmdArgs.push_back(Args.MakeArgString(P)); +          return; +        } +      } +    } + +    // Otherwise, look in the root. +    // FIXME: This should be removed someday when we don't have to care about +    // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. +    if (!getVFS().exists("/usr/lib/libstdc++.dylib") && +        getVFS().exists("/usr/lib/libstdc++.6.dylib")) { +      CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); +      return; +    } + +    // Otherwise, let the linker search. +    CmdArgs.push_back("-lstdc++"); +    break; +  } +} + +void DarwinClang::AddCCKextLibArgs(const ArgList &Args, +                                   ArgStringList &CmdArgs) const { +  // For Darwin platforms, use the compiler-rt-based support library +  // instead of the gcc-provided one (which is also incidentally +  // only present in the gcc lib dir, which makes it hard to find). + +  SmallString<128> P(getDriver().ResourceDir); +  llvm::sys::path::append(P, "lib", "darwin"); + +  // Use the newer cc_kext for iOS ARM after 6.0. +  if (isTargetWatchOS()) { +    llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a"); +  } else if (isTargetTvOS()) { +    llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); +  } else if (isTargetIPhoneOS()) { +    llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); +  } else { +    llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); +  } + +  // For now, allow missing resource libraries to support developers who may +  // not have compiler-rt checked out or integrated into their build. +  if (getVFS().exists(P)) +    CmdArgs.push_back(Args.MakeArgString(P)); +} + +DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, +                                     StringRef BoundArch, +                                     Action::OffloadKind) const { +  DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); +  const OptTable &Opts = getDriver().getOpts(); + +  // FIXME: We really want to get out of the tool chain level argument +  // translation business, as it makes the driver functionality much +  // more opaque. For now, we follow gcc closely solely for the +  // purpose of easily achieving feature parity & testability. Once we +  // have something that works, we should reevaluate each translation +  // and try to push it down into tool specific logic. + +  for (Arg *A : Args) { +    if (A->getOption().matches(options::OPT_Xarch__)) { +      // Skip this argument unless the architecture matches either the toolchain +      // triple arch, or the arch being bound. +      llvm::Triple::ArchType XarchArch = +          tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); +      if (!(XarchArch == getArch() || +            (!BoundArch.empty() && +             XarchArch == +                 tools::darwin::getArchTypeForMachOArchName(BoundArch)))) +        continue; + +      Arg *OriginalArg = A; +      unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); +      unsigned Prev = Index; +      std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + +      // If the argument parsing failed or more than one argument was +      // consumed, the -Xarch_ argument's parameter tried to consume +      // extra arguments. Emit an error and ignore. +      // +      // We also want to disallow any options which would alter the +      // driver behavior; that isn't going to work in our model. We +      // use isDriverOption() as an approximation, although things +      // like -O4 are going to slip through. +      if (!XarchArg || Index > Prev + 1) { +        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) +            << A->getAsString(Args); +        continue; +      } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { +        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) +            << A->getAsString(Args); +        continue; +      } + +      XarchArg->setBaseArg(A); + +      A = XarchArg.release(); +      DAL->AddSynthesizedArg(A); + +      // Linker input arguments require custom handling. The problem is that we +      // have already constructed the phase actions, so we can not treat them as +      // "input arguments". +      if (A->getOption().hasFlag(options::LinkerInput)) { +        // Convert the argument into individual Zlinker_input_args. +        for (const char *Value : A->getValues()) { +          DAL->AddSeparateArg( +              OriginalArg, Opts.getOption(options::OPT_Zlinker_input), Value); +        } +        continue; +      } +    } + +    // Sob. These is strictly gcc compatible for the time being. Apple +    // gcc translates options twice, which means that self-expanding +    // options add duplicates. +    switch ((options::ID)A->getOption().getID()) { +    default: +      DAL->append(A); +      break; + +    case options::OPT_mkernel: +    case options::OPT_fapple_kext: +      DAL->append(A); +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); +      break; + +    case options::OPT_dependency_file: +      DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue()); +      break; + +    case options::OPT_gfull: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); +      DAL->AddFlagArg( +          A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)); +      break; + +    case options::OPT_gused: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); +      DAL->AddFlagArg( +          A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); +      break; + +    case options::OPT_shared: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); +      break; + +    case options::OPT_fconstant_cfstrings: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings)); +      break; + +    case options::OPT_fno_constant_cfstrings: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings)); +      break; + +    case options::OPT_Wnonportable_cfstrings: +      DAL->AddFlagArg(A, +                      Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)); +      break; + +    case options::OPT_Wno_nonportable_cfstrings: +      DAL->AddFlagArg( +          A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); +      break; + +    case options::OPT_fpascal_strings: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); +      break; + +    case options::OPT_fno_pascal_strings: +      DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); +      break; +    } +  } + +  if (getTriple().getArch() == llvm::Triple::x86 || +      getTriple().getArch() == llvm::Triple::x86_64) +    if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) +      DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), +                        "core2"); + +  // Add the arch options based on the particular spelling of -arch, to match +  // how the driver driver works. +  if (!BoundArch.empty()) { +    StringRef Name = BoundArch; +    const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); +    const Option MArch = Opts.getOption(clang::driver::options::OPT_march_EQ); + +    // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, +    // which defines the list of which architectures we accept. +    if (Name == "ppc") +      ; +    else if (Name == "ppc601") +      DAL->AddJoinedArg(nullptr, MCpu, "601"); +    else if (Name == "ppc603") +      DAL->AddJoinedArg(nullptr, MCpu, "603"); +    else if (Name == "ppc604") +      DAL->AddJoinedArg(nullptr, MCpu, "604"); +    else if (Name == "ppc604e") +      DAL->AddJoinedArg(nullptr, MCpu, "604e"); +    else if (Name == "ppc750") +      DAL->AddJoinedArg(nullptr, MCpu, "750"); +    else if (Name == "ppc7400") +      DAL->AddJoinedArg(nullptr, MCpu, "7400"); +    else if (Name == "ppc7450") +      DAL->AddJoinedArg(nullptr, MCpu, "7450"); +    else if (Name == "ppc970") +      DAL->AddJoinedArg(nullptr, MCpu, "970"); + +    else if (Name == "ppc64" || Name == "ppc64le") +      DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); + +    else if (Name == "i386") +      ; +    else if (Name == "i486") +      DAL->AddJoinedArg(nullptr, MArch, "i486"); +    else if (Name == "i586") +      DAL->AddJoinedArg(nullptr, MArch, "i586"); +    else if (Name == "i686") +      DAL->AddJoinedArg(nullptr, MArch, "i686"); +    else if (Name == "pentium") +      DAL->AddJoinedArg(nullptr, MArch, "pentium"); +    else if (Name == "pentium2") +      DAL->AddJoinedArg(nullptr, MArch, "pentium2"); +    else if (Name == "pentpro") +      DAL->AddJoinedArg(nullptr, MArch, "pentiumpro"); +    else if (Name == "pentIIm3") +      DAL->AddJoinedArg(nullptr, MArch, "pentium2"); + +    else if (Name == "x86_64" || Name == "x86_64h") +      DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); + +    else if (Name == "arm") +      DAL->AddJoinedArg(nullptr, MArch, "armv4t"); +    else if (Name == "armv4t") +      DAL->AddJoinedArg(nullptr, MArch, "armv4t"); +    else if (Name == "armv5") +      DAL->AddJoinedArg(nullptr, MArch, "armv5tej"); +    else if (Name == "xscale") +      DAL->AddJoinedArg(nullptr, MArch, "xscale"); +    else if (Name == "armv6") +      DAL->AddJoinedArg(nullptr, MArch, "armv6k"); +    else if (Name == "armv6m") +      DAL->AddJoinedArg(nullptr, MArch, "armv6m"); +    else if (Name == "armv7") +      DAL->AddJoinedArg(nullptr, MArch, "armv7a"); +    else if (Name == "armv7em") +      DAL->AddJoinedArg(nullptr, MArch, "armv7em"); +    else if (Name == "armv7k") +      DAL->AddJoinedArg(nullptr, MArch, "armv7k"); +    else if (Name == "armv7m") +      DAL->AddJoinedArg(nullptr, MArch, "armv7m"); +    else if (Name == "armv7s") +      DAL->AddJoinedArg(nullptr, MArch, "armv7s"); +  } + +  return DAL; +} + +void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, +                                  ArgStringList &CmdArgs, +                                  bool ForceLinkBuiltinRT) const { +  // Embedded targets are simple at the moment, not supporting sanitizers and +  // with different libraries for each member of the product { static, PIC } x +  // { hard-float, soft-float } +  llvm::SmallString<32> CompilerRT = StringRef(""); +  CompilerRT += +      (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard) +          ? "hard" +          : "soft"; +  CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic" : "_static"; + +  AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, RLO_IsEmbedded); +} + +bool Darwin::isAlignedAllocationUnavailable() const { +  llvm::Triple::OSType OS; + +  switch (TargetPlatform) { +  case MacOS: // Earlier than 10.13. +    OS = llvm::Triple::MacOSX; +    break; +  case IPhoneOS: +    OS = llvm::Triple::IOS; +    break; +  case TvOS: // Earlier than 11.0. +    OS = llvm::Triple::TvOS; +    break; +  case WatchOS: // Earlier than 4.0. +    OS = llvm::Triple::WatchOS; +    break; +  } + +  return TargetVersion < alignedAllocMinVersion(OS); +} + +void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                                   llvm::opt::ArgStringList &CC1Args, +                                   Action::OffloadKind DeviceOffloadKind) const { +  // Pass "-faligned-alloc-unavailable" only when the user hasn't manually +  // enabled or disabled aligned allocations. +  if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation, +                                options::OPT_fno_aligned_allocation) && +      isAlignedAllocationUnavailable()) +    CC1Args.push_back("-faligned-alloc-unavailable"); + +  if (SDKInfo) { +    /// Pass the SDK version to the compiler when the SDK information is +    /// available. +    std::string Arg; +    llvm::raw_string_ostream OS(Arg); +    OS << "-target-sdk-version=" << SDKInfo->getVersion(); +    CC1Args.push_back(DriverArgs.MakeArgString(OS.str())); +  } +} + +DerivedArgList * +Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, +                      Action::OffloadKind DeviceOffloadKind) const { +  // First get the generic Apple args, before moving onto Darwin-specific ones. +  DerivedArgList *DAL = +      MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind); +  const OptTable &Opts = getDriver().getOpts(); + +  // If no architecture is bound, none of the translations here are relevant. +  if (BoundArch.empty()) +    return DAL; + +  // Add an explicit version min argument for the deployment target. We do this +  // after argument translation because -Xarch_ arguments may add a version min +  // argument. +  AddDeploymentTarget(*DAL); + +  // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext. +  // FIXME: It would be far better to avoid inserting those -static arguments, +  // but we can't check the deployment target in the translation code until +  // it is set here. +  if (isTargetWatchOSBased() || +      (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { +    for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { +      Arg *A = *it; +      ++it; +      if (A->getOption().getID() != options::OPT_mkernel && +          A->getOption().getID() != options::OPT_fapple_kext) +        continue; +      assert(it != ie && "unexpected argument translation"); +      A = *it; +      assert(A->getOption().getID() == options::OPT_static && +             "missing expected -static argument"); +      *it = nullptr; +      ++it; +    } +  } + +  if (!Args.getLastArg(options::OPT_stdlib_EQ) && +      GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) +    DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), +                      "libc++"); + +  // Validate the C++ standard library choice. +  CXXStdlibType Type = GetCXXStdlibType(*DAL); +  if (Type == ToolChain::CST_Libcxx) { +    // Check whether the target provides libc++. +    StringRef where; + +    // Complain about targeting iOS < 5.0 in any way. +    if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) +      where = "iOS 5.0"; + +    if (where != StringRef()) { +      getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where; +    } +  } + +  auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch); +  if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) { +    if (Args.hasFlag(options::OPT_fomit_frame_pointer, +                     options::OPT_fno_omit_frame_pointer, false)) +      getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target) +          << "-fomit-frame-pointer" << BoundArch; +  } + +  return DAL; +} + +bool MachO::IsUnwindTablesDefault(const ArgList &Args) const { +  // Unwind tables are not emitted if -fno-exceptions is supplied (except when +  // targeting x86_64). +  return getArch() == llvm::Triple::x86_64 || +         (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && +          Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, +                       true)); +} + +bool MachO::UseDwarfDebugFlags() const { +  if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) +    return S[0] != '\0'; +  return false; +} + +llvm::ExceptionHandling Darwin::GetExceptionModel(const ArgList &Args) const { +  // Darwin uses SjLj exceptions on ARM. +  if (getTriple().getArch() != llvm::Triple::arm && +      getTriple().getArch() != llvm::Triple::thumb) +    return llvm::ExceptionHandling::None; + +  // Only watchOS uses the new DWARF/Compact unwinding method. +  llvm::Triple Triple(ComputeLLVMTriple(Args)); +  if (Triple.isWatchABI()) +    return llvm::ExceptionHandling::DwarfCFI; + +  return llvm::ExceptionHandling::SjLj; +} + +bool Darwin::SupportsEmbeddedBitcode() const { +  assert(TargetInitialized && "Target not initialized!"); +  if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0)) +    return false; +  return true; +} + +bool MachO::isPICDefault() const { return true; } + +bool MachO::isPIEDefault() const { return false; } + +bool MachO::isPICDefaultForced() const { +  return (getArch() == llvm::Triple::x86_64 || +          getArch() == llvm::Triple::aarch64); +} + +bool MachO::SupportsProfiling() const { +  // Profiling instrumentation is only supported on x86. +  return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; +} + +void Darwin::addMinVersionArgs(const ArgList &Args, +                               ArgStringList &CmdArgs) const { +  VersionTuple TargetVersion = getTargetVersion(); + +  if (isTargetWatchOS()) +    CmdArgs.push_back("-watchos_version_min"); +  else if (isTargetWatchOSSimulator()) +    CmdArgs.push_back("-watchos_simulator_version_min"); +  else if (isTargetTvOS()) +    CmdArgs.push_back("-tvos_version_min"); +  else if (isTargetTvOSSimulator()) +    CmdArgs.push_back("-tvos_simulator_version_min"); +  else if (isTargetIOSSimulator()) +    CmdArgs.push_back("-ios_simulator_version_min"); +  else if (isTargetIOSBased()) +    CmdArgs.push_back("-iphoneos_version_min"); +  else { +    assert(isTargetMacOS() && "unexpected target"); +    CmdArgs.push_back("-macosx_version_min"); +  } + +  CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); +} + +void Darwin::addStartObjectFileArgs(const ArgList &Args, +                                    ArgStringList &CmdArgs) const { +  // Derived from startfile spec. +  if (Args.hasArg(options::OPT_dynamiclib)) { +    // Derived from darwin_dylib1 spec. +    if (isTargetWatchOSBased()) { +      ; // watchOS does not need dylib1.o. +    } else if (isTargetIOSSimulator()) { +      ; // iOS simulator does not need dylib1.o. +    } else if (isTargetIPhoneOS()) { +      if (isIPhoneOSVersionLT(3, 1)) +        CmdArgs.push_back("-ldylib1.o"); +    } else { +      if (isMacosxVersionLT(10, 5)) +        CmdArgs.push_back("-ldylib1.o"); +      else if (isMacosxVersionLT(10, 6)) +        CmdArgs.push_back("-ldylib1.10.5.o"); +    } +  } else { +    if (Args.hasArg(options::OPT_bundle)) { +      if (!Args.hasArg(options::OPT_static)) { +        // Derived from darwin_bundle1 spec. +        if (isTargetWatchOSBased()) { +          ; // watchOS does not need bundle1.o. +        } else if (isTargetIOSSimulator()) { +          ; // iOS simulator does not need bundle1.o. +        } else if (isTargetIPhoneOS()) { +          if (isIPhoneOSVersionLT(3, 1)) +            CmdArgs.push_back("-lbundle1.o"); +        } else { +          if (isMacosxVersionLT(10, 6)) +            CmdArgs.push_back("-lbundle1.o"); +        } +      } +    } else { +      if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) { +        if (isTargetMacOS() && isMacosxVersionLT(10, 9)) { +          if (Args.hasArg(options::OPT_static) || +              Args.hasArg(options::OPT_object) || +              Args.hasArg(options::OPT_preload)) { +            CmdArgs.push_back("-lgcrt0.o"); +          } else { +            CmdArgs.push_back("-lgcrt1.o"); + +            // darwin_crt2 spec is empty. +          } +          // By default on OS X 10.8 and later, we don't link with a crt1.o +          // file and the linker knows to use _main as the entry point.  But, +          // when compiling with -pg, we need to link with the gcrt1.o file, +          // so pass the -no_new_main option to tell the linker to use the +          // "start" symbol as the entry point. +          if (isTargetMacOS() && !isMacosxVersionLT(10, 8)) +            CmdArgs.push_back("-no_new_main"); +        } else { +          getDriver().Diag(diag::err_drv_clang_unsupported_opt_pg_darwin) +              << isTargetMacOS(); +        } +      } else { +        if (Args.hasArg(options::OPT_static) || +            Args.hasArg(options::OPT_object) || +            Args.hasArg(options::OPT_preload)) { +          CmdArgs.push_back("-lcrt0.o"); +        } else { +          // Derived from darwin_crt1 spec. +          if (isTargetWatchOSBased()) { +            ; // watchOS does not need crt1.o. +          } else if (isTargetIOSSimulator()) { +            ; // iOS simulator does not need crt1.o. +          } else if (isTargetIPhoneOS()) { +            if (getArch() == llvm::Triple::aarch64) +              ; // iOS does not need any crt1 files for arm64 +            else if (isIPhoneOSVersionLT(3, 1)) +              CmdArgs.push_back("-lcrt1.o"); +            else if (isIPhoneOSVersionLT(6, 0)) +              CmdArgs.push_back("-lcrt1.3.1.o"); +          } else { +            if (isMacosxVersionLT(10, 5)) +              CmdArgs.push_back("-lcrt1.o"); +            else if (isMacosxVersionLT(10, 6)) +              CmdArgs.push_back("-lcrt1.10.5.o"); +            else if (isMacosxVersionLT(10, 8)) +              CmdArgs.push_back("-lcrt1.10.6.o"); + +            // darwin_crt2 spec is empty. +          } +        } +      } +    } +  } + +  if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && +      !isTargetWatchOS() && isMacosxVersionLT(10, 5)) { +    const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); +    CmdArgs.push_back(Str); +  } +} + +void Darwin::CheckObjCARC() const { +  if (isTargetIOSBased() || isTargetWatchOSBased() || +      (isTargetMacOS() && !isMacosxVersionLT(10, 6))) +    return; +  getDriver().Diag(diag::err_arc_unsupported_on_toolchain); +} + +SanitizerMask Darwin::getSupportedSanitizers() const { +  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Leak; +  Res |= SanitizerKind::Fuzzer; +  Res |= SanitizerKind::FuzzerNoLink; +  Res |= SanitizerKind::Function; + +  // Prior to 10.9, macOS shipped a version of the C++ standard library without +  // C++11 support. The same is true of iOS prior to version 5. These OS'es are +  // incompatible with -fsanitize=vptr. +  if (!(isTargetMacOS() && isMacosxVersionLT(10, 9)) +      && !(isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))) +    Res |= SanitizerKind::Vptr; + +  if (isTargetMacOS()) { +    if (IsX86_64) +      Res |= SanitizerKind::Thread; +  } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) { +    if (IsX86_64) +      Res |= SanitizerKind::Thread; +  } +  return Res; +} + +void Darwin::printVerboseInfo(raw_ostream &OS) const { +  CudaInstallation.print(OS); +} diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h new file mode 100644 index 0000000000000..2dc7c85880f73 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -0,0 +1,550 @@ +//===--- Darwin.h - Darwin ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H + +#include "Cuda.h" +#include "clang/Driver/DarwinSDKInfo.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/XRayArgs.h" + +namespace clang { +namespace driver { + +namespace toolchains { +class MachO; +} // end namespace toolchains + +namespace tools { + +namespace darwin { +llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); +void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); + +class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { +  virtual void anchor(); + +protected: +  void AddMachOArch(const llvm::opt::ArgList &Args, +                    llvm::opt::ArgStringList &CmdArgs) const; + +  const toolchains::MachO &getMachOToolChain() const { +    return reinterpret_cast<const toolchains::MachO &>(getToolChain()); +  } + +public: +  MachOTool( +      const char *Name, const char *ShortName, const ToolChain &TC, +      ResponseFileSupport ResponseSupport = RF_None, +      llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, +      const char *ResponseFlag = "@") +      : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding, +             ResponseFlag) {} +}; + +class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool { +public: +  Assembler(const ToolChain &TC) +      : MachOTool("darwin::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool { +  bool NeedsTempPath(const InputInfoList &Inputs) const; +  void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, +                   llvm::opt::ArgStringList &CmdArgs, +                   const InputInfoList &Inputs) const; + +public: +  Linker(const ToolChain &TC) +      : MachOTool("darwin::Linker", "linker", TC, RF_FileList, +                  llvm::sys::WEM_UTF8, "-filelist") {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { +public: +  Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Dsymutil : public MachOTool { +public: +  Dsymutil(const ToolChain &TC) +      : MachOTool("darwin::Dsymutil", "dsymutil", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isDsymutilJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool { +public: +  VerifyDebug(const ToolChain &TC) +      : MachOTool("darwin::VerifyDebug", "dwarfdump", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace darwin +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain { +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +  Tool *getTool(Action::ActionClass AC) const override; + +private: +  mutable std::unique_ptr<tools::darwin::Lipo> Lipo; +  mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil; +  mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug; + +public: +  MachO(const Driver &D, const llvm::Triple &Triple, +        const llvm::opt::ArgList &Args); +  ~MachO() override; + +  /// @name MachO specific toolchain API +  /// { + +  /// Get the "MachO" arch name for a particular compiler invocation. For +  /// example, Apple treats different ARM variations as distinct architectures. +  StringRef getMachOArchName(const llvm::opt::ArgList &Args) const; + +  /// Add the linker arguments to link the ARC runtime library. +  virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, +                              llvm::opt::ArgStringList &CmdArgs) const {} + +  /// Add the linker arguments to link the compiler runtime library. +  /// +  /// FIXME: This API is intended for use with embedded libraries only, and is +  /// misleadingly named. +  virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, +                                     llvm::opt::ArgStringList &CmdArgs, +                                     bool ForceLinkBuiltinRT = false) const; + +  virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, +                                      llvm::opt::ArgStringList &CmdArgs) const { +  } + +  virtual void addMinVersionArgs(const llvm::opt::ArgList &Args, +                                 llvm::opt::ArgStringList &CmdArgs) const {} + +  /// On some iOS platforms, kernel and kernel modules were built statically. Is +  /// this such a target? +  virtual bool isKernelStatic() const { return false; } + +  /// Is the target either iOS or an iOS simulator? +  bool isTargetIOSBased() const { return false; } + +  /// Options to control how a runtime library is linked. +  enum RuntimeLinkOptions : unsigned { +    /// Link the library in even if it can't be found in the VFS. +    RLO_AlwaysLink = 1 << 0, + +    /// Use the embedded runtime from the macho_embedded directory. +    RLO_IsEmbedded = 1 << 1, + +    /// Emit rpaths for @executable_path as well as the resource directory. +    RLO_AddRPath = 1 << 2, + +    /// Link the library in before any others. +    RLO_FirstLink = 1 << 3, +  }; + +  /// Add a runtime library to the list of items to link. +  void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs, StringRef Component, +                         RuntimeLinkOptions Opts = RuntimeLinkOptions(), +                         bool IsShared = false) const; + +  /// Add any profiling runtime libraries that are needed. This is essentially a +  /// MachO specific version of addProfileRT in Tools.cpp. +  void addProfileRTLibs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const override { +    // There aren't any profiling libs for embedded targets currently. +  } + +  /// } +  /// @name ToolChain Implementation +  /// { + +  types::ID LookupTypeForExtension(StringRef Ext) const override; + +  bool HasNativeLLVMSupport() const override; + +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; + +  bool IsBlocksDefault() const override { +    // Always allow blocks on Apple; users interested in versioning are +    // expected to use /usr/include/Block.h. +    return true; +  } +  bool IsIntegratedAssemblerDefault() const override { +    // Default integrated assembler to on for Apple's MachO targets. +    return true; +  } + +  bool IsMathErrnoDefault() const override { return false; } + +  bool IsEncodeExtendedBlockSignatureDefault() const override { return true; } + +  bool IsObjCNonFragileABIDefault() const override { +    // Non-fragile ABI is default for everything but i386. +    return getTriple().getArch() != llvm::Triple::x86; +  } + +  bool UseObjCMixedDispatch() const override { return true; } + +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + +  RuntimeLibType GetDefaultRuntimeLibType() const override { +    return ToolChain::RLT_CompilerRT; +  } + +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; + +  bool SupportsProfiling() const override; + +  bool UseDwarfDebugFlags() const override; + +  llvm::ExceptionHandling +  GetExceptionModel(const llvm::opt::ArgList &Args) const override { +    return llvm::ExceptionHandling::None; +  } + +  virtual StringRef getOSLibraryNameSuffix(bool IgnoreSim = false) const { +    return ""; +  } + +  /// } +}; + +/// Darwin - The base Darwin tool chain. +class LLVM_LIBRARY_VISIBILITY Darwin : public MachO { +public: +  /// Whether the information on the target has been initialized. +  // +  // FIXME: This should be eliminated. What we want to do is make this part of +  // the "default target for arguments" selection process, once we get out of +  // the argument translation business. +  mutable bool TargetInitialized; + +  enum DarwinPlatformKind { +    MacOS, +    IPhoneOS, +    TvOS, +    WatchOS, +    LastDarwinPlatform = WatchOS +  }; +  enum DarwinEnvironmentKind { +    NativeEnvironment, +    Simulator, +  }; + +  mutable DarwinPlatformKind TargetPlatform; +  mutable DarwinEnvironmentKind TargetEnvironment; + +  /// The OS version we are targeting. +  mutable VersionTuple TargetVersion; + +  /// The information about the darwin SDK that was used. +  mutable Optional<DarwinSDKInfo> SDKInfo; + +  CudaInstallationDetector CudaInstallation; + +private: +  void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; + +public: +  Darwin(const Driver &D, const llvm::Triple &Triple, +         const llvm::opt::ArgList &Args); +  ~Darwin() override; + +  std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, +                                          types::ID InputType) const override; + +  /// @name Apple Specific Toolchain Implementation +  /// { + +  void addMinVersionArgs(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs) const override; + +  void addStartObjectFileArgs(const llvm::opt::ArgList &Args, +                              llvm::opt::ArgStringList &CmdArgs) const override; + +  bool isKernelStatic() const override { +    return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && +            !isTargetWatchOS()); +  } + +  void addProfileRTLibs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const override; + +protected: +  /// } +  /// @name Darwin specific Toolchain functions +  /// { + +  // FIXME: Eliminate these ...Target functions and derive separate tool chains +  // for these targets and put version in constructor. +  void setTarget(DarwinPlatformKind Platform, DarwinEnvironmentKind Environment, +                 unsigned Major, unsigned Minor, unsigned Micro) const { +    // FIXME: For now, allow reinitialization as long as values don't +    // change. This will go away when we move away from argument translation. +    if (TargetInitialized && TargetPlatform == Platform && +        TargetEnvironment == Environment && +        TargetVersion == VersionTuple(Major, Minor, Micro)) +      return; + +    assert(!TargetInitialized && "Target already initialized!"); +    TargetInitialized = true; +    TargetPlatform = Platform; +    TargetEnvironment = Environment; +    TargetVersion = VersionTuple(Major, Minor, Micro); +    if (Environment == Simulator) +      const_cast<Darwin *>(this)->setTripleEnvironment(llvm::Triple::Simulator); +  } + +  bool isTargetIPhoneOS() const { +    assert(TargetInitialized && "Target not initialized!"); +    return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && +           TargetEnvironment == NativeEnvironment; +  } + +  bool isTargetIOSSimulator() const { +    assert(TargetInitialized && "Target not initialized!"); +    return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && +           TargetEnvironment == Simulator; +  } + +  bool isTargetIOSBased() const { +    assert(TargetInitialized && "Target not initialized!"); +    return isTargetIPhoneOS() || isTargetIOSSimulator(); +  } + +  bool isTargetTvOS() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == TvOS && TargetEnvironment == NativeEnvironment; +  } + +  bool isTargetTvOSSimulator() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == TvOS && TargetEnvironment == Simulator; +  } + +  bool isTargetTvOSBased() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == TvOS; +  } + +  bool isTargetWatchOS() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == WatchOS && TargetEnvironment == NativeEnvironment; +  } + +  bool isTargetWatchOSSimulator() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == WatchOS && TargetEnvironment == Simulator; +  } + +  bool isTargetWatchOSBased() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == WatchOS; +  } + +  bool isTargetMacOS() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetPlatform == MacOS; +  } + +  bool isTargetInitialized() const { return TargetInitialized; } + +  VersionTuple getTargetVersion() const { +    assert(TargetInitialized && "Target not initialized!"); +    return TargetVersion; +  } + +  bool isIPhoneOSVersionLT(unsigned V0, unsigned V1 = 0, +                           unsigned V2 = 0) const { +    assert(isTargetIOSBased() && "Unexpected call for non iOS target!"); +    return TargetVersion < VersionTuple(V0, V1, V2); +  } + +  bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const { +    assert(isTargetMacOS() && "Unexpected call for non OS X target!"); +    return TargetVersion < VersionTuple(V0, V1, V2); +  } + +  /// Return true if c++17 aligned allocation/deallocation functions are not +  /// implemented in the c++ standard library of the deployment target we are +  /// targeting. +  bool isAlignedAllocationUnavailable() const; + +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; + +  StringRef getPlatformFamily() const; +  StringRef getOSLibraryNameSuffix(bool IgnoreSim = false) const override; + +public: +  static StringRef getSDKName(StringRef isysroot); + +  /// } +  /// @name ToolChain Implementation +  /// { + +  // Darwin tools support multiple architecture (e.g., i386 and x86_64) and +  // most development is done against SDKs, so compiling for a different +  // architecture should not get any special treatment. +  bool isCrossCompiling() const override { return false; } + +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; + +  CXXStdlibType GetDefaultCXXStdlibType() const override; +  ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; +  bool hasBlocksRuntime() const override; + +  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const override; + +  bool UseObjCMixedDispatch() const override { +    // This is only used with the non-fragile ABI and non-legacy dispatch. + +    // Mixed dispatch is used everywhere except OS X before 10.6. +    return !(isTargetMacOS() && isMacosxVersionLT(10, 6)); +  } + +  unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { +    // Stack protectors default to on for user code on 10.5, +    // and for everything in 10.6 and beyond +    if (isTargetIOSBased() || isTargetWatchOSBased()) +      return 1; +    else if (isTargetMacOS() && !isMacosxVersionLT(10, 6)) +      return 1; +    else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext) +      return 1; + +    return 0; +  } + +  void CheckObjCARC() const override; + +  llvm::ExceptionHandling GetExceptionModel( +      const llvm::opt::ArgList &Args) const override; + +  bool SupportsEmbeddedBitcode() const override; + +  SanitizerMask getSupportedSanitizers() const override; + +  void printVerboseInfo(raw_ostream &OS) const override; +}; + +/// DarwinClang - The Darwin toolchain used by Clang. +class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { +public: +  DarwinClang(const Driver &D, const llvm::Triple &Triple, +              const llvm::opt::ArgList &Args); + +  /// @name Apple ToolChain Implementation +  /// { + +  RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + +  void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, +                             llvm::opt::ArgStringList &CmdArgs, +                             bool ForceLinkBuiltinRT = false) const override; + +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                                 llvm::opt::ArgStringList &CC1Args) const override; + +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  void AddCCKextLibArgs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const override; + +  void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + +  void AddLinkARCArgs(const llvm::opt::ArgList &Args, +                      llvm::opt::ArgStringList &CmdArgs) const override; + +  unsigned GetDefaultDwarfVersion() const override; +  // Until dtrace (via CTF) and LLDB can deal with distributed debug info, +  // Darwin defaults to standalone/full debug info. +  bool GetDefaultStandaloneDebug() const override { return true; } +  llvm::DebuggerKind getDefaultDebuggerTuning() const override { +    return llvm::DebuggerKind::LLDB; +  } + +  /// } + +private: +  void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, +                               llvm::opt::ArgStringList &CmdArgs, +                               StringRef Sanitizer, +                               bool shared = true) const; + +  bool AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                   llvm::opt::ArgStringList &CC1Args, +                                   llvm::SmallString<128> Base, +                                   llvm::StringRef Version, +                                   llvm::StringRef ArchDir, +                                   llvm::StringRef BitDir) const; + +  llvm::StringRef GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H diff --git a/clang/lib/Driver/ToolChains/DragonFly.cpp b/clang/lib/Driver/ToolChains/DragonFly.cpp new file mode 100644 index 0000000000000..424331fbc6fe0 --- /dev/null +++ b/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -0,0 +1,197 @@ +//===--- DragonFly.cpp - DragonFly ToolChain Implementations ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DragonFly.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// DragonFly Tools + +// For now, DragonFly Assemble does just about the same as for +// FreeBSD, but this may change soon. +void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                        const InputInfo &Output, +                                        const InputInfoList &Inputs, +                                        const ArgList &Args, +                                        const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  // When building 32-bit code on DragonFly/pc64, we have to explicitly +  // instruct as in the base system to assemble 32-bit code. +  if (getToolChain().getArch() == llvm::Triple::x86) +    CmdArgs.push_back("--32"); + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void dragonfly::Linker::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; + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  CmdArgs.push_back("--eh-frame-hdr"); +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    if (Args.hasArg(options::OPT_shared)) +      CmdArgs.push_back("-Bshareable"); +    else { +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); +    } +    CmdArgs.push_back("--hash-style=gnu"); +    CmdArgs.push_back("--enable-new-dtags"); +  } + +  // When building 32-bit code on DragonFly/pc64, we have to explicitly +  // instruct ld in the base system to link 32-bit code. +  if (getToolChain().getArch() == llvm::Triple::x86) { +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf_i386"); +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) { +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back( +            Args.MakeArgString(getToolChain().GetFilePath("gcrt1.o"))); +      else { +        if (Args.hasArg(options::OPT_pie)) +          CmdArgs.push_back( +              Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o"))); +        else +          CmdArgs.push_back( +              Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); +      } +    } +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      CmdArgs.push_back( +          Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); +    else +      CmdArgs.push_back( +          Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); +  } + +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_L, options::OPT_T_Group, options::OPT_e}); + +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    CmdArgs.push_back("-L/usr/lib/gcc50"); + +    if (!Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-rpath"); +      CmdArgs.push_back("/usr/lib/gcc50"); +    } + +    if (D.CCCIsCXX()) { +      if (getToolChain().ShouldLinkCXXStdlib(Args)) +        getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); +      CmdArgs.push_back("-lm"); +    } + +    if (Args.hasArg(options::OPT_pthread)) +      CmdArgs.push_back("-lpthread"); + +    if (!Args.hasArg(options::OPT_nolibc)) { +      CmdArgs.push_back("-lc"); +    } + +    if (Args.hasArg(options::OPT_static) || +        Args.hasArg(options::OPT_static_libgcc)) { +        CmdArgs.push_back("-lgcc"); +        CmdArgs.push_back("-lgcc_eh"); +    } else { +      if (Args.hasArg(options::OPT_shared_libgcc)) { +          CmdArgs.push_back("-lgcc_pic"); +          if (!Args.hasArg(options::OPT_shared)) +            CmdArgs.push_back("-lgcc"); +      } else { +          CmdArgs.push_back("-lgcc"); +          CmdArgs.push_back("--as-needed"); +          CmdArgs.push_back("-lgcc_pic"); +          CmdArgs.push_back("--no-as-needed"); +      } +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      CmdArgs.push_back( +          Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); +    else +      CmdArgs.push_back( +          Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); +  } + +  getToolChain().addProfileRTLibs(Args, CmdArgs); + +  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. + +DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, +                     const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { + +  // Path mangling to find libexec +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); + +  getFilePaths().push_back(getDriver().Dir + "/../lib"); +  getFilePaths().push_back("/usr/lib"); +  getFilePaths().push_back("/usr/lib/gcc50"); +} + +Tool *DragonFly::buildAssembler() const { +  return new tools::dragonfly::Assembler(*this); +} + +Tool *DragonFly::buildLinker() const { +  return new tools::dragonfly::Linker(*this); +} diff --git a/clang/lib/Driver/ToolChains/DragonFly.h b/clang/lib/Driver/ToolChains/DragonFly.h new file mode 100644 index 0000000000000..7e76904f10558 --- /dev/null +++ b/clang/lib/Driver/ToolChains/DragonFly.h @@ -0,0 +1,67 @@ +//===--- DragonFly.h - DragonFly ToolChain Implementations ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +/// dragonfly -- Directly call GNU Binutils assembler and linker +namespace dragonfly { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("dragonfly::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("dragonfly::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace dragonfly +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { +public: +  DragonFly(const Driver &D, const llvm::Triple &Triple, +            const llvm::opt::ArgList &Args); + +  bool IsMathErrnoDefault() const override { return false; } + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp new file mode 100644 index 0000000000000..7c891a24ba304 --- /dev/null +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -0,0 +1,447 @@ +//===--- FreeBSD.cpp - FreeBSD ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FreeBSD.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                      const InputInfo &Output, +                                      const InputInfoList &Inputs, +                                      const ArgList &Args, +                                      const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  // When building 32-bit code on FreeBSD/amd64, we have to explicitly +  // instruct as in the base system to assemble 32-bit code. +  switch (getToolChain().getArch()) { +  default: +    break; +  case llvm::Triple::x86: +    CmdArgs.push_back("--32"); +    break; +  case llvm::Triple::ppc: +    CmdArgs.push_back("-a32"); +    break; +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: { +    StringRef CPUName; +    StringRef ABIName; +    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + +    CmdArgs.push_back("-march"); +    CmdArgs.push_back(CPUName.data()); + +    CmdArgs.push_back("-mabi"); +    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); + +    if (getToolChain().getTriple().isLittleEndian()) +      CmdArgs.push_back("-EL"); +    else +      CmdArgs.push_back("-EB"); + +    if (Arg *A = Args.getLastArg(options::OPT_G)) { +      StringRef v = A->getValue(); +      CmdArgs.push_back(Args.MakeArgString("-G" + v)); +      A->claim(); +    } + +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: { +    arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); + +    if (ABI == arm::FloatABI::Hard) +      CmdArgs.push_back("-mfpu=vfp"); +    else +      CmdArgs.push_back("-mfpu=softvfp"); + +    switch (getToolChain().getTriple().getEnvironment()) { +    case llvm::Triple::GNUEABIHF: +    case llvm::Triple::GNUEABI: +    case llvm::Triple::EABI: +      CmdArgs.push_back("-meabi=5"); +      break; + +    default: +      CmdArgs.push_back("-matpcs"); +    } +    break; +  } +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +  case llvm::Triple::sparcv9: { +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } +  } + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                   const InputInfo &Output, +                                   const InputInfoList &Inputs, +                                   const ArgList &Args, +                                   const char *LinkingOutput) const { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  const llvm::Triple::ArchType Arch = ToolChain.getArch(); +  const bool IsPIE = +      !Args.hasArg(options::OPT_shared) && +      (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); +  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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (IsPIE) +    CmdArgs.push_back("-pie"); + +  CmdArgs.push_back("--eh-frame-hdr"); +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-Bshareable"); +    } else { +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/libexec/ld-elf.so.1"); +    } +    if (ToolChain.getTriple().getOSMajorVersion() >= 9) { +      if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || +          Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { +        CmdArgs.push_back("--hash-style=both"); +      } +    } +    CmdArgs.push_back("--enable-new-dtags"); +  } + +  // Explicitly set the linker emulation for platforms that might not +  // be the default emulation for the linker. +  switch (Arch) { +  case llvm::Triple::x86: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf_i386_fbsd"); +    break; +  case llvm::Triple::ppc: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf32ppc_fbsd"); +    break; +  case llvm::Triple::mips: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf32btsmip_fbsd"); +    break; +  case llvm::Triple::mipsel: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf32ltsmip_fbsd"); +    break; +  case llvm::Triple::mips64: +    CmdArgs.push_back("-m"); +    if (tools::mips::hasMipsAbiArg(Args, "n32")) +      CmdArgs.push_back("elf32btsmipn32_fbsd"); +    else +      CmdArgs.push_back("elf64btsmip_fbsd"); +    break; +  case llvm::Triple::mips64el: +    CmdArgs.push_back("-m"); +    if (tools::mips::hasMipsAbiArg(Args, "n32")) +      CmdArgs.push_back("elf32ltsmipn32_fbsd"); +    else +      CmdArgs.push_back("elf64ltsmip_fbsd"); +    break; +  case llvm::Triple::riscv32: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf32lriscv"); +    break; +  case llvm::Triple::riscv64: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf64lriscv"); +    break; +  default: +    break; +  } + +  if (Arg *A = Args.getLastArg(options::OPT_G)) { +    if (ToolChain.getTriple().isMIPS()) { +      StringRef v = A->getValue(); +      CmdArgs.push_back(Args.MakeArgString("-G" + v)); +      A->claim(); +    } +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    const char *crt1 = nullptr; +    if (!Args.hasArg(options::OPT_shared)) { +      if (Args.hasArg(options::OPT_pg)) +        crt1 = "gcrt1.o"; +      else if (IsPIE) +        crt1 = "Scrt1.o"; +      else +        crt1 = "crt1.o"; +    } +    if (crt1) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + +    const char *crtbegin = nullptr; +    if (Args.hasArg(options::OPT_static)) +      crtbegin = "crtbeginT.o"; +    else if (Args.hasArg(options::OPT_shared) || IsPIE) +      crtbegin = "crtbeginS.o"; +    else +      crtbegin = "crtbegin.o"; + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  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); + +  if (D.isUsingLTO()) { +    assert(!Inputs.empty() && "Must have at least one input."); +    AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], +                  D.getLTOMode() == LTOK_Thin); +  } + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); +  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    // Use the static OpenMP runtime with -static-openmp +    bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && +                        !Args.hasArg(options::OPT_static); +    addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + +    if (D.CCCIsCXX()) { +      if (ToolChain.ShouldLinkCXXStdlib(Args)) +        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lm_p"); +      else +        CmdArgs.push_back("-lm"); +    } +    if (NeedsSanitizerDeps) +      linkSanitizerRuntimeDeps(ToolChain, CmdArgs); +    if (NeedsXRayDeps) +      linkXRayRuntimeDeps(ToolChain, CmdArgs); +    // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding +    // the default system libraries. Just mimic this for now. +    if (Args.hasArg(options::OPT_pg)) +      CmdArgs.push_back("-lgcc_p"); +    else +      CmdArgs.push_back("-lgcc"); +    if (Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-lgcc_eh"); +    } else if (Args.hasArg(options::OPT_pg)) { +      CmdArgs.push_back("-lgcc_eh_p"); +    } else { +      CmdArgs.push_back("--as-needed"); +      CmdArgs.push_back("-lgcc_s"); +      CmdArgs.push_back("--no-as-needed"); +    } + +    if (Args.hasArg(options::OPT_pthread)) { +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lpthread_p"); +      else +        CmdArgs.push_back("-lpthread"); +    } + +    if (Args.hasArg(options::OPT_pg)) { +      if (Args.hasArg(options::OPT_shared)) +        CmdArgs.push_back("-lc"); +      else +        CmdArgs.push_back("-lc_p"); +      CmdArgs.push_back("-lgcc_p"); +    } else { +      CmdArgs.push_back("-lc"); +      CmdArgs.push_back("-lgcc"); +    } + +    if (Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-lgcc_eh"); +    } else if (Args.hasArg(options::OPT_pg)) { +      CmdArgs.push_back("-lgcc_eh_p"); +    } else { +      CmdArgs.push_back("--as-needed"); +      CmdArgs.push_back("-lgcc_s"); +      CmdArgs.push_back("--no-as-needed"); +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || IsPIE) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); +    else +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +  } + +  ToolChain.addProfileRTLibs(Args, CmdArgs); + +  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. + +FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, +                 const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { + +  // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall +  // back to '/usr/lib' if it doesn't exist. +  if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || +       Triple.getArch() == llvm::Triple::ppc) && +      D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) +    getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); +  else +    getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { +  if (getTriple().getOSMajorVersion() >= 10) +    return ToolChain::CST_Libcxx; +  return ToolChain::CST_Libstdcxx; +} + +unsigned FreeBSD::GetDefaultDwarfVersion() const { +  if (getTriple().getOSMajorVersion() < 12) +    return 2; +  return 4; +} + +void FreeBSD::addLibStdCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "", +                           "", "", DriverArgs, CC1Args); +} + +void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, +                                  ArgStringList &CmdArgs) const { +  CXXStdlibType Type = GetCXXStdlibType(Args); +  bool Profiling = Args.hasArg(options::OPT_pg); + +  switch (Type) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); +    break; + +  case ToolChain::CST_Libstdcxx: +    CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); +    break; +  } +} + +Tool *FreeBSD::buildAssembler() const { +  return new tools::freebsd::Assembler(*this); +} + +Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } + +llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { +  // FreeBSD uses SjLj exceptions on ARM oabi. +  switch (getTriple().getEnvironment()) { +  case llvm::Triple::GNUEABIHF: +  case llvm::Triple::GNUEABI: +  case llvm::Triple::EABI: +    return llvm::ExceptionHandling::None; +  default: +    if (getTriple().getArch() == llvm::Triple::arm || +        getTriple().getArch() == llvm::Triple::thumb) +      return llvm::ExceptionHandling::SjLj; +    return llvm::ExceptionHandling::None; +  } +} + +bool FreeBSD::HasNativeLLVMSupport() const { return true; } + +bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } + +SanitizerMask FreeBSD::getSupportedSanitizers() const { +  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; +  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; +  const bool IsMIPS64 = getTriple().isMIPS64(); +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Vptr; +  if (IsX86_64 || IsMIPS64) { +    Res |= SanitizerKind::Leak; +    Res |= SanitizerKind::Thread; +  } +  if (IsX86 || IsX86_64) { +    Res |= SanitizerKind::Function; +    Res |= SanitizerKind::SafeStack; +    Res |= SanitizerKind::Fuzzer; +    Res |= SanitizerKind::FuzzerNoLink; +  } +  if (IsX86_64) +    Res |= SanitizerKind::Memory; +  return Res; +} diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h new file mode 100644 index 0000000000000..d17b3808ffacc --- /dev/null +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -0,0 +1,86 @@ +//===--- FreeBSD.h - FreeBSD ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H + +#include "Gnu.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// freebsd -- Directly call GNU Binutils assembler and linker +namespace freebsd { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("freebsd::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("freebsd::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace freebsd +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { +public: +  FreeBSD(const Driver &D, const llvm::Triple &Triple, +          const llvm::opt::ArgList &Args); +  bool HasNativeLLVMSupport() const override; + +  bool IsMathErrnoDefault() const override { return false; } +  bool IsObjCNonFragileABIDefault() const override { return true; } + +  CXXStdlibType GetDefaultCXXStdlibType() const override; +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  llvm::ExceptionHandling GetExceptionModel( +      const llvm::opt::ArgList &Args) const override; +  bool isPIEDefault() const override; +  SanitizerMask getSupportedSanitizers() const override; +  unsigned GetDefaultDwarfVersion() const override; +  // Until dtrace (via CTF) and LLDB can deal with distributed debug info, +  // FreeBSD defaults to standalone/full debug info. +  bool GetDefaultStandaloneDebug() const override { return true; } + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp new file mode 100644 index 0000000000000..e7d38ff9f227b --- /dev/null +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -0,0 +1,347 @@ +//===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Fuchsia.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +using tools::addMultilibFlag; + +void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                   const InputInfo &Output, +                                   const InputInfoList &Inputs, +                                   const ArgList &Args, +                                   const char *LinkingOutput) const { +  const toolchains::Fuchsia &ToolChain = +      static_cast<const toolchains::Fuchsia &>(getToolChain()); +  const Driver &D = ToolChain.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); + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || +      llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { +    CmdArgs.push_back("-z"); +    CmdArgs.push_back("rodynamic"); +    CmdArgs.push_back("-z"); +    CmdArgs.push_back("separate-loadable-segments"); +  } + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) +    CmdArgs.push_back("-pie"); + +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); + +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("-s"); + +  if (Args.hasArg(options::OPT_r)) { +    CmdArgs.push_back("-r"); +  } else { +    CmdArgs.push_back("--build-id"); +    CmdArgs.push_back("--hash-style=gnu"); +  } + +  CmdArgs.push_back("--eh-frame-hdr"); + +  if (Args.hasArg(options::OPT_static)) +    CmdArgs.push_back("-Bstatic"); +  else if (Args.hasArg(options::OPT_shared)) +    CmdArgs.push_back("-shared"); + +  const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); + +  if (!Args.hasArg(options::OPT_shared)) { +    std::string Dyld = D.DyldPrefix; +    if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt()) +      Dyld += "asan/"; +    Dyld += "ld.so.1"; +    CmdArgs.push_back("-dynamic-linker"); +    CmdArgs.push_back(Args.MakeArgString(Dyld)); +  } + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); +    } +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  Args.AddAllArgs(CmdArgs, options::OPT_u); + +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); + +  if (D.isUsingLTO()) { +    assert(!Inputs.empty() && "Must have at least one input."); +    AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], +                  D.getLTOMode() == LTOK_Thin); +  } + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); +  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); +  ToolChain.addProfileRTLibs(Args, CmdArgs); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (Args.hasArg(options::OPT_static)) +      CmdArgs.push_back("-Bdynamic"); + +    if (D.CCCIsCXX()) { +      if (ToolChain.ShouldLinkCXXStdlib(Args)) { +        bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && +                                   !Args.hasArg(options::OPT_static); +        CmdArgs.push_back("--push-state"); +        CmdArgs.push_back("--as-needed"); +        if (OnlyLibstdcxxStatic) +          CmdArgs.push_back("-Bstatic"); +        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +        if (OnlyLibstdcxxStatic) +          CmdArgs.push_back("-Bdynamic"); +        CmdArgs.push_back("-lm"); +        CmdArgs.push_back("--pop-state"); +      } +    } + +    if (NeedsSanitizerDeps) +      linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + +    if (NeedsXRayDeps) +      linkXRayRuntimeDeps(ToolChain, CmdArgs); + +    AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + +    if (Args.hasArg(options::OPT_pthread) || +        Args.hasArg(options::OPT_pthreads)) +      CmdArgs.push_back("-lpthread"); + +    if (Args.hasArg(options::OPT_fsplit_stack)) +      CmdArgs.push_back("--wrap=pthread_create"); + +    if (!Args.hasArg(options::OPT_nolibc)) +      CmdArgs.push_back("-lc"); +  } + +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. + +Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, +                 const ArgList &Args) +    : ToolChain(D, Triple, Args) { +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != D.Dir) +    getProgramPaths().push_back(D.Dir); + +  if (!D.SysRoot.empty()) { +    SmallString<128> P(D.SysRoot); +    llvm::sys::path::append(P, "lib"); +    getFilePaths().push_back(P.str()); +  } + +  auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> { +    std::vector<std::string> FP; +    if (D.CCCIsCXX()) { +      if (auto CXXStdlibPath = getCXXStdlibPath()) { +        SmallString<128> P(*CXXStdlibPath); +        llvm::sys::path::append(P, M.gccSuffix()); +        FP.push_back(P.str()); +      } +    } +    return FP; +  }; + +  Multilibs.push_back(Multilib()); +  // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. +  Multilibs.push_back(Multilib("noexcept", {}, {}, 1) +                          .flag("-fexceptions") +                          .flag("+fno-exceptions")); +  // ASan has higher priority because we always want the instrumentated version. +  Multilibs.push_back(Multilib("asan", {}, {}, 2) +                          .flag("+fsanitize=address")); +  // Use the asan+noexcept variant with ASan and -fno-exceptions. +  Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3) +                          .flag("+fsanitize=address") +                          .flag("-fexceptions") +                          .flag("+fno-exceptions")); +  Multilibs.FilterOut([&](const Multilib &M) { +    std::vector<std::string> RD = FilePaths(M); +    return std::all_of(RD.begin(), RD.end(), [&](std::string P) { +      return !getVFS().exists(P); +    }); +  }); + +  Multilib::flags_list Flags; +  addMultilibFlag( +      Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), +      "fexceptions", Flags); +  addMultilibFlag(getSanitizerArgs().needsAsanRt(), "fsanitize=address", Flags); +  Multilibs.setFilePathsCallback(FilePaths); + +  if (Multilibs.select(Flags, SelectedMultilib)) +    if (!SelectedMultilib.isDefault()) +      if (const auto &PathsCallback = Multilibs.filePathsCallback()) +        for (const auto &Path : PathsCallback(SelectedMultilib)) +          // Prepend the multilib path to ensure it takes the precedence. +          getFilePaths().insert(getFilePaths().begin(), Path); +} + +std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, +                                                 types::ID InputType) const { +  llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); +  return (Triple.getArchName() + "-" + Triple.getOSName()).str(); +} + +Tool *Fuchsia::buildLinker() const { +  return new tools::fuchsia::Linker(*this); +} + +ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( +    const ArgList &Args) const { +  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { +    StringRef Value = A->getValue(); +    if (Value != "compiler-rt") +      getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name) +          << A->getAsString(Args); +  } + +  return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType +Fuchsia::GetCXXStdlibType(const ArgList &Args) const { +  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { +    StringRef Value = A->getValue(); +    if (Value != "libc++") +      getDriver().Diag(diag::err_drv_invalid_stdlib_name) +        << A->getAsString(Args); +  } + +  return ToolChain::CST_Libcxx; +} + +void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, +                                    ArgStringList &CC1Args, +                                    Action::OffloadKind) const { +  if (DriverArgs.hasFlag(options::OPT_fuse_init_array, +                         options::OPT_fno_use_init_array, true)) +    CC1Args.push_back("-fuse-init-array"); +} + +void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                        ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); + +  if (DriverArgs.hasArg(options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  // Check for configure-time C include directories. +  StringRef CIncludeDirs(C_INCLUDE_DIRS); +  if (CIncludeDirs != "") { +    SmallVector<StringRef, 5> dirs; +    CIncludeDirs.split(dirs, ":"); +    for (StringRef dir : dirs) { +      StringRef Prefix = +          llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; +      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); +    } +    return; +  } + +  if (!D.SysRoot.empty()) { +    SmallString<128> P(D.SysRoot); +    llvm::sys::path::append(P, "include"); +    addExternCSystemInclude(DriverArgs, CC1Args, P.str()); +  } +} + +void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, +                                           ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  switch (GetCXXStdlibType(DriverArgs)) { +  case ToolChain::CST_Libcxx: { +    SmallString<128> P(getDriver().Dir); +    llvm::sys::path::append(P, "..", "include", "c++", "v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  } + +  default: +    llvm_unreachable("invalid stdlib name"); +  } +} + +void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, +                                  ArgStringList &CmdArgs) const { +  switch (GetCXXStdlibType(Args)) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    break; + +  case ToolChain::CST_Libstdcxx: +    llvm_unreachable("invalid stdlib name"); +  } +} + +SanitizerMask Fuchsia::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Fuzzer; +  Res |= SanitizerKind::FuzzerNoLink; +  Res |= SanitizerKind::SafeStack; +  Res |= SanitizerKind::Scudo; +  return Res; +} + +SanitizerMask Fuchsia::getDefaultSanitizers() const { +  return SanitizerKind::SafeStack; +} diff --git a/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h new file mode 100644 index 0000000000000..fee0e018f3ce3 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -0,0 +1,101 @@ +//===--- Fuchsia.h - Fuchsia ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace fuchsia { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) : Tool("fuchsia::Linker", "ld.lld", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace fuchsia +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain { +public: +  Fuchsia(const Driver &D, const llvm::Triple &Triple, +          const llvm::opt::ArgList &Args); + +  bool HasNativeLLVMSupport() const override { return true; } +  bool IsIntegratedAssemblerDefault() const override { return true; } +  bool IsMathErrnoDefault() const override { return false; } +  bool useRelaxRelocations() const override { return true; }; +  RuntimeLibType GetDefaultRuntimeLibType() const override { +    return ToolChain::RLT_CompilerRT; +  } +  CXXStdlibType GetDefaultCXXStdlibType() const override { +    return ToolChain::CST_Libcxx; +  } +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { +    return true; +  } +  bool isPICDefault() const override { return false; } +  bool isPIEDefault() const override { return true; } +  bool isPICDefaultForced() const override { return false; } +  llvm::DebuggerKind getDefaultDebuggerTuning() const override { +    return llvm::DebuggerKind::GDB; +  } + +  unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { +    return 2; // SSPStrong +  } + +  std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, +                                          types::ID InputType) const override; + +  SanitizerMask getSupportedSanitizers() const override; +  SanitizerMask getDefaultSanitizers() const override; + +  RuntimeLibType +  GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; +  CXXStdlibType +  GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void +  AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                               llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  const char *getDefaultLinker() const override { +    return "ld.lld"; +  } + +protected: +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp new file mode 100644 index 0000000000000..c302a31cd2e10 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -0,0 +1,2734 @@ +//===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Gnu.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "Arch/RISCV.h" +#include "Arch/Sparc.h" +#include "Arch/SystemZ.h" +#include "CommonArgs.h" +#include "Linux.h" +#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addMultilibFlag; + +void tools::GnuTool::anchor() {} + +static bool forwardToGCC(const Option &O) { +  // Don't forward inputs from the original command line.  They are added from +  // InputInfoList. +  return O.getKind() != Option::InputClass && +         !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); +} + +// Switch CPU names not recognized by GNU assembler to a close CPU that it does +// recognize, instead of a lower march from being picked in the absence of a cpu +// flag. +static void normalizeCPUNamesForAssembler(const ArgList &Args, +                                          ArgStringList &CmdArgs) { +  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { +    StringRef CPUArg(A->getValue()); +    if (CPUArg.equals_lower("krait")) +      CmdArgs.push_back("-mcpu=cortex-a15"); +    else if(CPUArg.equals_lower("kryo")) +      CmdArgs.push_back("-mcpu=cortex-a57"); +    else +      Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); +  } +} + +void tools::gcc::Common::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; + +  for (const auto &A : Args) { +    if (forwardToGCC(A->getOption())) { +      // 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(); + +      // Don't forward any -g arguments to assembly steps. +      if (isa<AssembleJobAction>(JA) && +          A->getOption().matches(options::OPT_g_Group)) +        continue; + +      // Don't forward any -W arguments to assembly and link steps. +      if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && +          A->getOption().matches(options::OPT_W_Group)) +        continue; + +      // Don't forward -mno-unaligned-access since GCC doesn't understand +      // it and because it doesn't affect the assembly or link steps. +      if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && +          (A->getOption().matches(options::OPT_munaligned_access) || +           A->getOption().matches(options::OPT_mno_unaligned_access))) +        continue; + +      A->render(Args, CmdArgs); +    } +  } + +  RenderExtraToolArgs(JA, CmdArgs); + +  // If using a driver driver, force the arch. +  if (getToolChain().getTriple().isOSDarwin()) { +    CmdArgs.push_back("-arch"); +    CmdArgs.push_back( +        Args.MakeArgString(getToolChain().getDefaultUniversalArchName())); +  } + +  // Try to force gcc to match the tool chain we want, if we recognize +  // the arch. +  // +  // FIXME: The triple class should directly provide the information we want +  // here. +  switch (getToolChain().getArch()) { +  default: +    break; +  case llvm::Triple::x86: +  case llvm::Triple::ppc: +    CmdArgs.push_back("-m32"); +    break; +  case llvm::Triple::x86_64: +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: +    CmdArgs.push_back("-m64"); +    break; +  case llvm::Triple::sparcel: +    CmdArgs.push_back("-EL"); +    break; +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Unexpected output"); +    CmdArgs.push_back("-fsyntax-only"); +  } + +  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 +  // wrong in is for linker inputs if they happened to have an odd +  // suffix; really the only way to get this to happen is a command +  // like '-x foobar a.c' which will treat a.c like a linker input. +  // +  // FIXME: For the linker case specifically, can we safely convert +  // inputs into '-Wl,' options? +  for (const auto &II : Inputs) { +    // Don't try to pass LLVM or AST inputs to a generic gcc. +    if (types::isLLVMIR(II.getType())) +      D.Diag(clang::diag::err_drv_no_linker_llvm_support) +          << getToolChain().getTripleString(); +    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"); +      CmdArgs.push_back(types::getTypeName(II.getType())); +    } + +    if (II.isFilename()) +      CmdArgs.push_back(II.getFilename()); +    else { +      const Arg &A = II.getInputArg(); + +      // Reverse translate some rewritten options. +      if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { +        CmdArgs.push_back("-lstdc++"); +        continue; +      } + +      // Don't render as input, we need gcc to do the translations. +      A.render(Args, CmdArgs); +    } +  } + +  const std::string &customGCCName = D.getCCCGenericGCCName(); +  const char *GCCName; +  if (!customGCCName.empty()) +    GCCName = customGCCName.c_str(); +  else if (D.CCCIsCXX()) { +    GCCName = "g++"; +  } else +    GCCName = "gcc"; + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::gcc::Preprocessor::RenderExtraToolArgs( +    const JobAction &JA, ArgStringList &CmdArgs) const { +  CmdArgs.push_back("-E"); +} + +void tools::gcc::Compiler::RenderExtraToolArgs(const JobAction &JA, +                                               ArgStringList &CmdArgs) const { +  const Driver &D = getToolChain().getDriver(); + +  switch (JA.getType()) { +  // If -flto, etc. are present then make sure not to force assembly output. +  case types::TY_LLVM_IR: +  case types::TY_LTO_IR: +  case types::TY_LLVM_BC: +  case types::TY_LTO_BC: +    CmdArgs.push_back("-c"); +    break; +  // We assume we've got an "integrated" assembler in that gcc will produce an +  // object file itself. +  case types::TY_Object: +    CmdArgs.push_back("-c"); +    break; +  case types::TY_PP_Asm: +    CmdArgs.push_back("-S"); +    break; +  case types::TY_Nothing: +    CmdArgs.push_back("-fsyntax-only"); +    break; +  default: +    D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); +  } +} + +void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, +                                             ArgStringList &CmdArgs) const { +  // The types are (hopefully) good enough. +} + +// On Arm the endianness of the output file is determined by the target and +// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and +// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a +// normalized triple so we must handle the flag here. +static bool isArmBigEndian(const llvm::Triple &Triple, +                           const ArgList &Args) { +  bool IsBigEndian = false; +  switch (Triple.getArch()) { +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: +    IsBigEndian = true; +    LLVM_FALLTHROUGH; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, +                               options::OPT_mbig_endian)) +      IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); +    break; +  default: +    break; +  } +  return IsBigEndian; +} + +static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { +  switch (T.getArch()) { +  case llvm::Triple::x86: +    if (T.isOSIAMCU()) +      return "elf_iamcu"; +    return "elf_i386"; +  case llvm::Triple::aarch64: +    return "aarch64linux"; +  case llvm::Triple::aarch64_be: +    return "aarch64linuxb"; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: +    return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi"; +  case llvm::Triple::ppc: +    return "elf32ppclinux"; +  case llvm::Triple::ppc64: +    return "elf64ppc"; +  case llvm::Triple::ppc64le: +    return "elf64lppc"; +  case llvm::Triple::riscv32: +    return "elf32lriscv"; +  case llvm::Triple::riscv64: +    return "elf64lriscv"; +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +    return "elf32_sparc"; +  case llvm::Triple::sparcv9: +    return "elf64_sparc"; +  case llvm::Triple::mips: +    return "elf32btsmip"; +  case llvm::Triple::mipsel: +    return "elf32ltsmip"; +  case llvm::Triple::mips64: +    if (tools::mips::hasMipsAbiArg(Args, "n32") || +        T.getEnvironment() == llvm::Triple::GNUABIN32) +      return "elf32btsmipn32"; +    return "elf64btsmip"; +  case llvm::Triple::mips64el: +    if (tools::mips::hasMipsAbiArg(Args, "n32") || +        T.getEnvironment() == llvm::Triple::GNUABIN32) +      return "elf32ltsmipn32"; +    return "elf64ltsmip"; +  case llvm::Triple::systemz: +    return "elf64_s390"; +  case llvm::Triple::x86_64: +    if (T.getEnvironment() == llvm::Triple::GNUX32) +      return "elf32_x86_64"; +    return "elf_x86_64"; +  default: +    return nullptr; +  } +} + +static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { +  if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || +      Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie)) +    return false; + +  Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, +                           options::OPT_nopie); +  if (!A) +    return ToolChain.isPIEDefault(); +  return A->getOption().matches(options::OPT_pie); +} + +static bool getStaticPIE(const ArgList &Args, +                         const toolchains::Linux &ToolChain) { +  bool HasStaticPIE = Args.hasArg(options::OPT_static_pie); +  // -no-pie is an alias for -nopie. So, handling -nopie takes care of +  // -no-pie as well. +  if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) { +    const Driver &D = ToolChain.getDriver(); +    const llvm::opt::OptTable &Opts = D.getOpts(); +    const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie); +    const char *NoPIEName = Opts.getOptionName(options::OPT_nopie); +    D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName; +  } +  return HasStaticPIE; +} + +static bool getStatic(const ArgList &Args) { +  return Args.hasArg(options::OPT_static) && +      !Args.hasArg(options::OPT_static_pie); +} + +void tools::gnutools::Linker::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(); + +  const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + +  const llvm::Triple::ArchType Arch = ToolChain.getArch(); +  const bool isAndroid = ToolChain.getTriple().isAndroid(); +  const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); +  const bool IsPIE = getPIE(Args, ToolChain); +  const bool IsStaticPIE = getStaticPIE(Args, ToolChain); +  const bool IsStatic = getStatic(Args); +  const bool HasCRTBeginEndFiles = +      ToolChain.getTriple().hasEnvironment() || +      (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); + +  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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (IsPIE) +    CmdArgs.push_back("-pie"); + +  if (IsStaticPIE) { +    CmdArgs.push_back("-static"); +    CmdArgs.push_back("-pie"); +    CmdArgs.push_back("--no-dynamic-linker"); +    CmdArgs.push_back("-z"); +    CmdArgs.push_back("text"); +  } + +  if (ToolChain.isNoExecStackDefault()) { +    CmdArgs.push_back("-z"); +    CmdArgs.push_back("noexecstack"); +  } + +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); + +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("-s"); + +  if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) { +    bool IsBigEndian = isArmBigEndian(Triple, Args); +    if (IsBigEndian) +      arm::appendBE8LinkFlag(Args, CmdArgs, Triple); +    IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be; +    CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); +  } + +  // Most Android ARM64 targets should enable the linker fix for erratum +  // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. +  if (Arch == llvm::Triple::aarch64 && isAndroid) { +    std::string CPU = getCPUName(Args, Triple); +    if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") +      CmdArgs.push_back("--fix-cortex-a53-843419"); +  } + +  // Android does not allow shared text relocations. Emit a warning if the +  // user's code contains any. +  if (isAndroid) +      CmdArgs.push_back("--warn-shared-textrel"); + +  for (const auto &Opt : ToolChain.ExtraOpts) +    CmdArgs.push_back(Opt.c_str()); + +  CmdArgs.push_back("--eh-frame-hdr"); + +  if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { +    CmdArgs.push_back("-m"); +    CmdArgs.push_back(LDMOption); +  } else { +    D.Diag(diag::err_target_unknown_triple) << Triple.str(); +    return; +  } + +  if (IsStatic) { +    if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || +        Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) +      CmdArgs.push_back("-Bstatic"); +    else +      CmdArgs.push_back("-static"); +  } else if (Args.hasArg(options::OPT_shared)) { +    CmdArgs.push_back("-shared"); +  } + +  if (!IsStatic) { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); + +    if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) { +      const std::string Loader = +          D.DyldPrefix + ToolChain.getDynamicLinker(Args); +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back(Args.MakeArgString(Loader)); +    } +  } + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!isAndroid && !IsIAMCU) { +      const char *crt1 = nullptr; +      if (!Args.hasArg(options::OPT_shared)) { +        if (Args.hasArg(options::OPT_pg)) +          crt1 = "gcrt1.o"; +        else if (IsPIE) +          crt1 = "Scrt1.o"; +        else if (IsStaticPIE) +          crt1 = "rcrt1.o"; +        else +          crt1 = "crt1.o"; +      } +      if (crt1) +        CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); +    } + +    if (IsIAMCU) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); +    else if (HasCRTBeginEndFiles) { +      std::string P; +      if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT && +          !isAndroid) { +        std::string crtbegin = ToolChain.getCompilerRT(Args, "crtbegin", +                                                       ToolChain::FT_Object); +        if (ToolChain.getVFS().exists(crtbegin)) +          P = crtbegin; +      } +      if (P.empty()) { +        const char *crtbegin; +        if (IsStatic) +          crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; +        else if (Args.hasArg(options::OPT_shared)) +          crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; +        else if (IsPIE || IsStaticPIE) +          crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; +        else +          crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; +        P = ToolChain.GetFilePath(crtbegin); +      } +      CmdArgs.push_back(Args.MakeArgString(P)); +    } + +    // Add crtfastmath.o if available and fast math is enabled. +    ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  Args.AddAllArgs(CmdArgs, options::OPT_u); + +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); + +  if (D.isUsingLTO()) { +    assert(!Inputs.empty() && "Must have at least one input."); +    AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], +                  D.getLTOMode() == LTOK_Thin); +  } + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); +  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); +  // The profile runtime also needs access to system libraries. +  getToolChain().addProfileRTLibs(Args, CmdArgs); + +  if (D.CCCIsCXX() && +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (ToolChain.ShouldLinkCXXStdlib(Args)) { +      bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && +                                 !Args.hasArg(options::OPT_static); +      if (OnlyLibstdcxxStatic) +        CmdArgs.push_back("-Bstatic"); +      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (OnlyLibstdcxxStatic) +        CmdArgs.push_back("-Bdynamic"); +    } +    CmdArgs.push_back("-lm"); +  } +  // Silence warnings when linking C code with a C++ '-stdlib' argument. +  Args.ClaimAllArgs(options::OPT_stdlib_EQ); + +  if (!Args.hasArg(options::OPT_nostdlib)) { +    if (!Args.hasArg(options::OPT_nodefaultlibs)) { +      if (IsStatic || IsStaticPIE) +        CmdArgs.push_back("--start-group"); + +      if (NeedsSanitizerDeps) +        linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + +      if (NeedsXRayDeps) +        linkXRayRuntimeDeps(ToolChain, CmdArgs); + +      bool WantPthread = Args.hasArg(options::OPT_pthread) || +                         Args.hasArg(options::OPT_pthreads); + +      // Use the static OpenMP runtime with -static-openmp +      bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && +                          !Args.hasArg(options::OPT_static); + +      // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that +      // require librt. Most modern Linux platforms do, but some may not. +      if (addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP, +                           JA.isHostOffloading(Action::OFK_OpenMP), +                           /* GompNeedsRT= */ true)) +        // OpenMP runtimes implies pthreads when using the GNU toolchain. +        // FIXME: Does this really make sense for all GNU toolchains? +        WantPthread = true; + +      AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + +      if (WantPthread && !isAndroid) +        CmdArgs.push_back("-lpthread"); + +      if (Args.hasArg(options::OPT_fsplit_stack)) +        CmdArgs.push_back("--wrap=pthread_create"); + +      if (!Args.hasArg(options::OPT_nolibc)) +        CmdArgs.push_back("-lc"); + +      // Add IAMCU specific libs, if needed. +      if (IsIAMCU) +        CmdArgs.push_back("-lgloss"); + +      if (IsStatic || IsStaticPIE) +        CmdArgs.push_back("--end-group"); +      else +        AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + +      // Add IAMCU specific libs (outside the group), if needed. +      if (IsIAMCU) { +        CmdArgs.push_back("--as-needed"); +        CmdArgs.push_back("-lsoftfp"); +        CmdArgs.push_back("--no-as-needed"); +      } +    } + +    if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) { +      if (HasCRTBeginEndFiles) { +        std::string P; +        if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT && +            !isAndroid) { +          std::string crtend = ToolChain.getCompilerRT(Args, "crtend", +                                                       ToolChain::FT_Object); +          if (ToolChain.getVFS().exists(crtend)) +            P = crtend; +        } +        if (P.empty()) { +          const char *crtend; +          if (Args.hasArg(options::OPT_shared)) +            crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; +          else if (IsPIE || IsStaticPIE) +            crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; +          else +            crtend = isAndroid ? "crtend_android.o" : "crtend.o"; +          P = ToolChain.GetFilePath(crtend); +        } +        CmdArgs.push_back(Args.MakeArgString(P)); +      } +      if (!isAndroid) +        CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +    } +  } + +  // Add HIP offloading linker script args if required. +  AddHIPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA, +                     *this); + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::gnutools::Assembler::ConstructJob(Compilation &C, +                                              const JobAction &JA, +                                              const InputInfo &Output, +                                              const InputInfoList &Inputs, +                                              const ArgList &Args, +                                              const char *LinkingOutput) const { +  const auto &D = getToolChain().getDriver(); + +  claimNoWarnArgs(Args); + +  ArgStringList CmdArgs; + +  llvm::Reloc::Model RelocationModel; +  unsigned PICLevel; +  bool IsPIE; +  std::tie(RelocationModel, PICLevel, IsPIE) = +      ParsePICArgs(getToolChain(), Args); + +  if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) { +    if (A->getOption().getID() == options::OPT_gz) { +      CmdArgs.push_back("--compress-debug-sections"); +    } else { +      StringRef Value = A->getValue(); +      if (Value == "none" || Value == "zlib" || Value == "zlib-gnu") { +        CmdArgs.push_back( +            Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); +      } else { +        D.Diag(diag::err_drv_unsupported_option_argument) +            << A->getOption().getName() << Value; +      } +    } +  } + +  if (getToolChain().isNoExecStackDefault()) { +      CmdArgs.push_back("--noexecstack"); +  } + +  switch (getToolChain().getArch()) { +  default: +    break; +  // Add --32/--64 to make sure we get the format we want. +  // This is incomplete +  case llvm::Triple::x86: +    CmdArgs.push_back("--32"); +    break; +  case llvm::Triple::x86_64: +    if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) +      CmdArgs.push_back("--x32"); +    else +      CmdArgs.push_back("--64"); +    break; +  case llvm::Triple::ppc: { +    CmdArgs.push_back("-a32"); +    CmdArgs.push_back("-mppc"); +    CmdArgs.push_back( +      ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); +    break; +  } +  case llvm::Triple::ppc64: { +    CmdArgs.push_back("-a64"); +    CmdArgs.push_back("-mppc64"); +    CmdArgs.push_back( +      ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); +    break; +  } +  case llvm::Triple::ppc64le: { +    CmdArgs.push_back("-a64"); +    CmdArgs.push_back("-mppc64"); +    CmdArgs.push_back("-mlittle-endian"); +    CmdArgs.push_back( +      ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); +    break; +  } +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: { +    StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); +    CmdArgs.push_back("-mabi"); +    CmdArgs.push_back(ABIName.data()); +    if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { +      StringRef MArch = A->getValue(); +      CmdArgs.push_back("-march"); +      CmdArgs.push_back(MArch.data()); +    } +    break; +  } +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: { +    CmdArgs.push_back("-32"); +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back( +        sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } +  case llvm::Triple::sparcv9: { +    CmdArgs.push_back("-64"); +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back( +        sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: { +    const llvm::Triple &Triple2 = getToolChain().getTriple(); +    CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL"); +    switch (Triple2.getSubArch()) { +    case llvm::Triple::ARMSubArch_v7: +      CmdArgs.push_back("-mfpu=neon"); +      break; +    case llvm::Triple::ARMSubArch_v8: +      CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); +      break; +    default: +      break; +    } + +    switch (arm::getARMFloatABI(getToolChain(), Args)) { +    case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!"); +    case arm::FloatABI::Soft: +      CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft")); +      break; +    case arm::FloatABI::SoftFP: +      CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp")); +      break; +    case arm::FloatABI::Hard: +      CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard")); +      break; +    } + +    Args.AddLastArg(CmdArgs, options::OPT_march_EQ); +    normalizeCPUNamesForAssembler(Args, CmdArgs); + +    Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); +    break; +  } +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: { +    CmdArgs.push_back( +        getToolChain().getArch() == llvm::Triple::aarch64_be ? "-EB" : "-EL"); +    Args.AddLastArg(CmdArgs, options::OPT_march_EQ); +    normalizeCPUNamesForAssembler(Args, CmdArgs); + +    break; +  } +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: { +    StringRef CPUName; +    StringRef ABIName; +    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); +    ABIName = mips::getGnuCompatibleMipsABIName(ABIName); + +    CmdArgs.push_back("-march"); +    CmdArgs.push_back(CPUName.data()); + +    CmdArgs.push_back("-mabi"); +    CmdArgs.push_back(ABIName.data()); + +    // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, +    // or -mshared (not implemented) is in effect. +    if (RelocationModel == llvm::Reloc::Static) +      CmdArgs.push_back("-mno-shared"); + +    // LLVM doesn't support -mplt yet and acts as if it is always given. +    // However, -mplt has no effect with the N64 ABI. +    if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) +      CmdArgs.push_back("-call_nonpic"); + +    if (getToolChain().getTriple().isLittleEndian()) +      CmdArgs.push_back("-EL"); +    else +      CmdArgs.push_back("-EB"); + +    if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { +      if (StringRef(A->getValue()) == "2008") +        CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); +    } + +    // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. +    if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, +                                 options::OPT_mfp64)) { +      A->claim(); +      A->render(Args, CmdArgs); +    } else if (mips::shouldUseFPXX( +                   Args, getToolChain().getTriple(), CPUName, ABIName, +                   mips::getMipsFloatABI(getToolChain().getDriver(), Args, +                                         getToolChain().getTriple()))) +      CmdArgs.push_back("-mfpxx"); + +    // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of +    // -mno-mips16 is actually -no-mips16. +    if (Arg *A = +            Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) { +      if (A->getOption().matches(options::OPT_mips16)) { +        A->claim(); +        A->render(Args, CmdArgs); +      } else { +        A->claim(); +        CmdArgs.push_back("-no-mips16"); +      } +    } + +    Args.AddLastArg(CmdArgs, options::OPT_mmicromips, +                    options::OPT_mno_micromips); +    Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); +    Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); + +    if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { +      // Do not use AddLastArg because not all versions of MIPS assembler +      // support -mmsa / -mno-msa options. +      if (A->getOption().matches(options::OPT_mmsa)) +        CmdArgs.push_back(Args.MakeArgString("-mmsa")); +    } + +    Args.AddLastArg(CmdArgs, options::OPT_mhard_float, +                    options::OPT_msoft_float); + +    Args.AddLastArg(CmdArgs, options::OPT_mdouble_float, +                    options::OPT_msingle_float); + +    Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, +                    options::OPT_mno_odd_spreg); + +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } +  case llvm::Triple::systemz: { +    // Always pass an -march option, since our default of z10 is later +    // than the GNU assembler's default. +    StringRef CPUName = systemz::getSystemZTargetCPU(Args); +    CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); +    break; +  } +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_I); +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + +  // Handle the debug info splitting at object creation time if we're +  // creating an object. +  // TODO: Currently only works on linux with newer objcopy. +  if (Args.hasArg(options::OPT_gsplit_dwarf) && +      getToolChain().getTriple().isOSLinux()) +    SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, +                   SplitDebugName(Args, Inputs[0], Output)); +} + +namespace { +// Filter to remove Multilibs that don't exist as a suffix to Path +class FilterNonExistent { +  StringRef Base, File; +  llvm::vfs::FileSystem &VFS; + +public: +  FilterNonExistent(StringRef Base, StringRef File, llvm::vfs::FileSystem &VFS) +      : Base(Base), File(File), VFS(VFS) {} +  bool operator()(const Multilib &M) { +    return !VFS.exists(Base + M.gccSuffix() + File); +  } +}; +} // end anonymous namespace + +static bool isSoftFloatABI(const ArgList &Args) { +  Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, +                           options::OPT_mfloat_abi_EQ); +  if (!A) +    return false; + +  return A->getOption().matches(options::OPT_msoft_float) || +         (A->getOption().matches(options::OPT_mfloat_abi_EQ) && +          A->getValue() == StringRef("soft")); +} + +static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { +  return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; +} + +static bool isMipsEL(llvm::Triple::ArchType Arch) { +  return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; +} + +static bool isMips16(const ArgList &Args) { +  Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); +  return A && A->getOption().matches(options::OPT_mips16); +} + +static bool isMicroMips(const ArgList &Args) { +  Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); +  return A && A->getOption().matches(options::OPT_mmicromips); +} + +static bool isMSP430(llvm::Triple::ArchType Arch) { +  return Arch == llvm::Triple::msp430; +} + +static Multilib makeMultilib(StringRef commonSuffix) { +  return Multilib(commonSuffix, commonSuffix, commonSuffix); +} + +static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, +                                FilterNonExistent &NonExistent, +                                DetectedMultilibs &Result) { +  // Check for Code Sourcery toolchain multilibs +  MultilibSet CSMipsMultilibs; +  { +    auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); + +    auto MArchMicroMips = +        makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); + +    auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); + +    auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + +    auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); + +    auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + +    auto DefaultFloat = +        makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); + +    auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + +    auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + +    // Note that this one's osSuffix is "" +    auto MAbi64 = makeMultilib("") +                      .gccSuffix("/64") +                      .includeSuffix("/64") +                      .flag("+mabi=n64") +                      .flag("-mabi=n32") +                      .flag("-m32"); + +    CSMipsMultilibs = +        MultilibSet() +            .Either(MArchMips16, MArchMicroMips, MArchDefault) +            .Maybe(UCLibc) +            .Either(SoftFloat, Nan2008, DefaultFloat) +            .FilterOut("/micromips/nan2008") +            .FilterOut("/mips16/nan2008") +            .Either(BigEndian, LittleEndian) +            .Maybe(MAbi64) +            .FilterOut("/mips16.*/64") +            .FilterOut("/micromips.*/64") +            .FilterOut(NonExistent) +            .setIncludeDirsCallback([](const Multilib &M) { +              std::vector<std::string> Dirs({"/include"}); +              if (StringRef(M.includeSuffix()).startswith("/uclibc")) +                Dirs.push_back( +                    "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); +              else +                Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include"); +              return Dirs; +            }); +  } + +  MultilibSet DebianMipsMultilibs; +  { +    Multilib MAbiN32 = +        Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); + +    Multilib M64 = Multilib() +                       .gccSuffix("/64") +                       .includeSuffix("/64") +                       .flag("+m64") +                       .flag("-m32") +                       .flag("-mabi=n32"); + +    Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); + +    DebianMipsMultilibs = +        MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); +  } + +  // Sort candidates. Toolchain that best meets the directories tree goes first. +  // Then select the first toolchains matches command line flags. +  MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs}; +  if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) +    std::iter_swap(Candidates, Candidates + 1); +  for (const MultilibSet *Candidate : Candidates) { +    if (Candidate->select(Flags, Result.SelectedMultilib)) { +      if (Candidate == &DebianMipsMultilibs) +        Result.BiarchSibling = Multilib(); +      Result.Multilibs = *Candidate; +      return true; +    } +  } +  return false; +} + +static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, +                                     const Multilib::flags_list &Flags, +                                     FilterNonExistent &NonExistent, +                                     DetectedMultilibs &Result) { + +  MultilibSet AndroidMipsMultilibs = +      MultilibSet() +          .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) +          .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) +          .FilterOut(NonExistent); + +  MultilibSet AndroidMipselMultilibs = +      MultilibSet() +          .Either(Multilib().flag("+march=mips32"), +                  Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), +                  Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) +          .FilterOut(NonExistent); + +  MultilibSet AndroidMips64elMultilibs = +      MultilibSet() +          .Either( +              Multilib().flag("+march=mips64r6"), +              Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), +              Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), +              Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) +          .FilterOut(NonExistent); + +  MultilibSet *MS = &AndroidMipsMultilibs; +  if (VFS.exists(Path + "/mips-r6")) +    MS = &AndroidMipselMultilibs; +  else if (VFS.exists(Path + "/32")) +    MS = &AndroidMips64elMultilibs; +  if (MS->select(Flags, Result.SelectedMultilib)) { +    Result.Multilibs = *MS; +    return true; +  } +  return false; +} + +static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, +                                  FilterNonExistent &NonExistent, +                                  DetectedMultilibs &Result) { +  // Musl toolchain multilibs +  MultilibSet MuslMipsMultilibs; +  { +    auto MArchMipsR2 = makeMultilib("") +                           .osSuffix("/mips-r2-hard-musl") +                           .flag("+EB") +                           .flag("-EL") +                           .flag("+march=mips32r2"); + +    auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") +                             .flag("-EB") +                             .flag("+EL") +                             .flag("+march=mips32r2"); + +    MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); + +    // Specify the callback that computes the include directories. +    MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { +      return std::vector<std::string>( +          {"/../sysroot" + M.osSuffix() + "/usr/include"}); +    }); +  } +  if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { +    Result.Multilibs = MuslMipsMultilibs; +    return true; +  } +  return false; +} + +static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, +                                 FilterNonExistent &NonExistent, +                                 DetectedMultilibs &Result) { +  // CodeScape MTI toolchain v1.2 and early. +  MultilibSet MtiMipsMultilibsV1; +  { +    auto MArchMips32 = makeMultilib("/mips32") +                           .flag("+m32") +                           .flag("-m64") +                           .flag("-mmicromips") +                           .flag("+march=mips32"); + +    auto MArchMicroMips = makeMultilib("/micromips") +                              .flag("+m32") +                              .flag("-m64") +                              .flag("+mmicromips"); + +    auto MArchMips64r2 = makeMultilib("/mips64r2") +                             .flag("-m32") +                             .flag("+m64") +                             .flag("+march=mips64r2"); + +    auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( +        "-march=mips64r2"); + +    auto MArchDefault = makeMultilib("") +                            .flag("+m32") +                            .flag("-m64") +                            .flag("-mmicromips") +                            .flag("+march=mips32r2"); + +    auto Mips16 = makeMultilib("/mips16").flag("+mips16"); + +    auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + +    auto MAbi64 = +        makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + +    auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + +    auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + +    auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); + +    auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + +    MtiMipsMultilibsV1 = +        MultilibSet() +            .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, +                    MArchDefault) +            .Maybe(UCLibc) +            .Maybe(Mips16) +            .FilterOut("/mips64/mips16") +            .FilterOut("/mips64r2/mips16") +            .FilterOut("/micromips/mips16") +            .Maybe(MAbi64) +            .FilterOut("/micromips/64") +            .FilterOut("/mips32/64") +            .FilterOut("^/64") +            .FilterOut("/mips16/64") +            .Either(BigEndian, LittleEndian) +            .Maybe(SoftFloat) +            .Maybe(Nan2008) +            .FilterOut(".*sof/nan2008") +            .FilterOut(NonExistent) +            .setIncludeDirsCallback([](const Multilib &M) { +              std::vector<std::string> Dirs({"/include"}); +              if (StringRef(M.includeSuffix()).startswith("/uclibc")) +                Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); +              else +                Dirs.push_back("/../../../../sysroot/usr/include"); +              return Dirs; +            }); +  } + +  // CodeScape IMG toolchain starting from v1.3. +  MultilibSet MtiMipsMultilibsV2; +  { +    auto BeHard = makeMultilib("/mips-r2-hard") +                      .flag("+EB") +                      .flag("-msoft-float") +                      .flag("-mnan=2008") +                      .flag("-muclibc"); +    auto BeSoft = makeMultilib("/mips-r2-soft") +                      .flag("+EB") +                      .flag("+msoft-float") +                      .flag("-mnan=2008"); +    auto ElHard = makeMultilib("/mipsel-r2-hard") +                      .flag("+EL") +                      .flag("-msoft-float") +                      .flag("-mnan=2008") +                      .flag("-muclibc"); +    auto ElSoft = makeMultilib("/mipsel-r2-soft") +                      .flag("+EL") +                      .flag("+msoft-float") +                      .flag("-mnan=2008") +                      .flag("-mmicromips"); +    auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") +                         .flag("+EB") +                         .flag("-msoft-float") +                         .flag("+mnan=2008") +                         .flag("-muclibc"); +    auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") +                         .flag("+EL") +                         .flag("-msoft-float") +                         .flag("+mnan=2008") +                         .flag("-muclibc") +                         .flag("-mmicromips"); +    auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") +                               .flag("+EB") +                               .flag("-msoft-float") +                               .flag("+mnan=2008") +                               .flag("+muclibc"); +    auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") +                               .flag("+EL") +                               .flag("-msoft-float") +                               .flag("+mnan=2008") +                               .flag("+muclibc"); +    auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") +                            .flag("+EB") +                            .flag("-msoft-float") +                            .flag("-mnan=2008") +                            .flag("+muclibc"); +    auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") +                            .flag("+EL") +                            .flag("-msoft-float") +                            .flag("-mnan=2008") +                            .flag("+muclibc"); +    auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") +                              .flag("+EL") +                              .flag("-msoft-float") +                              .flag("+mnan=2008") +                              .flag("+mmicromips"); +    auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") +                           .flag("+EL") +                           .flag("+msoft-float") +                           .flag("-mnan=2008") +                           .flag("+mmicromips"); + +    auto O32 = +        makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); +    auto N32 = +        makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); +    auto N64 = +        makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + +    MtiMipsMultilibsV2 = +        MultilibSet() +            .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, +                     BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, +                     ElHardUclibc, ElMicroHardNan, ElMicroSoft}) +            .Either(O32, N32, N64) +            .FilterOut(NonExistent) +            .setIncludeDirsCallback([](const Multilib &M) { +              return std::vector<std::string>({"/../../../../sysroot" + +                                               M.includeSuffix() + +                                               "/../usr/include"}); +            }) +            .setFilePathsCallback([](const Multilib &M) { +              return std::vector<std::string>( +                  {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); +            }); +  } +  for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { +    if (Candidate->select(Flags, Result.SelectedMultilib)) { +      Result.Multilibs = *Candidate; +      return true; +    } +  } +  return false; +} + +static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, +                                 FilterNonExistent &NonExistent, +                                 DetectedMultilibs &Result) { +  // CodeScape IMG toolchain v1.2 and early. +  MultilibSet ImgMultilibsV1; +  { +    auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); + +    auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + +    auto MAbi64 = +        makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + +    ImgMultilibsV1 = +        MultilibSet() +            .Maybe(Mips64r6) +            .Maybe(MAbi64) +            .Maybe(LittleEndian) +            .FilterOut(NonExistent) +            .setIncludeDirsCallback([](const Multilib &M) { +              return std::vector<std::string>( +                  {"/include", "/../../../../sysroot/usr/include"}); +            }); +  } + +  // CodeScape IMG toolchain starting from v1.3. +  MultilibSet ImgMultilibsV2; +  { +    auto BeHard = makeMultilib("/mips-r6-hard") +                      .flag("+EB") +                      .flag("-msoft-float") +                      .flag("-mmicromips"); +    auto BeSoft = makeMultilib("/mips-r6-soft") +                      .flag("+EB") +                      .flag("+msoft-float") +                      .flag("-mmicromips"); +    auto ElHard = makeMultilib("/mipsel-r6-hard") +                      .flag("+EL") +                      .flag("-msoft-float") +                      .flag("-mmicromips"); +    auto ElSoft = makeMultilib("/mipsel-r6-soft") +                      .flag("+EL") +                      .flag("+msoft-float") +                      .flag("-mmicromips"); +    auto BeMicroHard = makeMultilib("/micromips-r6-hard") +                           .flag("+EB") +                           .flag("-msoft-float") +                           .flag("+mmicromips"); +    auto BeMicroSoft = makeMultilib("/micromips-r6-soft") +                           .flag("+EB") +                           .flag("+msoft-float") +                           .flag("+mmicromips"); +    auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") +                           .flag("+EL") +                           .flag("-msoft-float") +                           .flag("+mmicromips"); +    auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") +                           .flag("+EL") +                           .flag("+msoft-float") +                           .flag("+mmicromips"); + +    auto O32 = +        makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); +    auto N32 = +        makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); +    auto N64 = +        makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + +    ImgMultilibsV2 = +        MultilibSet() +            .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, +                     ElMicroHard, ElMicroSoft}) +            .Either(O32, N32, N64) +            .FilterOut(NonExistent) +            .setIncludeDirsCallback([](const Multilib &M) { +              return std::vector<std::string>({"/../../../../sysroot" + +                                               M.includeSuffix() + +                                               "/../usr/include"}); +            }) +            .setFilePathsCallback([](const Multilib &M) { +              return std::vector<std::string>( +                  {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); +            }); +  } +  for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { +    if (Candidate->select(Flags, Result.SelectedMultilib)) { +      Result.Multilibs = *Candidate; +      return true; +    } +  } +  return false; +} + +bool clang::driver::findMIPSMultilibs(const Driver &D, +                                      const llvm::Triple &TargetTriple, +                                      StringRef Path, const ArgList &Args, +                                      DetectedMultilibs &Result) { +  FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + +  StringRef CPUName; +  StringRef ABIName; +  tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); + +  llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + +  Multilib::flags_list Flags; +  addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags); +  addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags); +  addMultilibFlag(isMips16(Args), "mips16", Flags); +  addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); +  addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || +                      CPUName == "mips32r5" || CPUName == "p5600", +                  "march=mips32r2", Flags); +  addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); +  addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); +  addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || +                      CPUName == "mips64r5" || CPUName == "octeon", +                  "march=mips64r2", Flags); +  addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); +  addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); +  addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); +  addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", +                  Flags); +  addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); +  addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); +  addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); +  addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); +  addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); +  addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); + +  if (TargetTriple.isAndroid()) +    return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, +                                    Result); + +  if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && +      TargetTriple.getOS() == llvm::Triple::Linux && +      TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) +    return findMipsMuslMultilibs(Flags, NonExistent, Result); + +  if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && +      TargetTriple.getOS() == llvm::Triple::Linux && +      TargetTriple.isGNUEnvironment()) +    return findMipsMtiMultilibs(Flags, NonExistent, Result); + +  if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && +      TargetTriple.getOS() == llvm::Triple::Linux && +      TargetTriple.isGNUEnvironment()) +    return findMipsImgMultilibs(Flags, NonExistent, Result); + +  if (findMipsCsMultilibs(Flags, NonExistent, Result)) +    return true; + +  // Fallback to the regular toolchain-tree structure. +  Multilib Default; +  Result.Multilibs.push_back(Default); +  Result.Multilibs.FilterOut(NonExistent); + +  if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { +    Result.BiarchSibling = Multilib(); +    return true; +  } + +  return false; +} + +static void findAndroidArmMultilibs(const Driver &D, +                                    const llvm::Triple &TargetTriple, +                                    StringRef Path, const ArgList &Args, +                                    DetectedMultilibs &Result) { +  // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. +  FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); +  Multilib ArmV7Multilib = makeMultilib("/armv7-a") +                               .flag("+march=armv7-a") +                               .flag("-mthumb"); +  Multilib ThumbMultilib = makeMultilib("/thumb") +                               .flag("-march=armv7-a") +                               .flag("+mthumb"); +  Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") +                               .flag("+march=armv7-a") +                               .flag("+mthumb"); +  Multilib DefaultMultilib = makeMultilib("") +                               .flag("-march=armv7-a") +                               .flag("-mthumb"); +  MultilibSet AndroidArmMultilibs = +      MultilibSet() +          .Either(ThumbMultilib, ArmV7Multilib, +                  ArmV7ThumbMultilib, DefaultMultilib) +          .FilterOut(NonExistent); + +  Multilib::flags_list Flags; +  llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ); +  bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm; +  bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb; +  bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7; +  bool IsThumbMode = IsThumbArch || +      Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) || +      (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::ISAKind::THUMB); +  bool IsArmV7Mode = (IsArmArch || IsThumbArch) && +      (llvm::ARM::parseArchVersion(Arch) == 7 || +       (IsArmArch && Arch == "" && IsV7SubArch)); +  addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags); +  addMultilibFlag(IsThumbMode, "mthumb", Flags); + +  if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) +    Result.Multilibs = AndroidArmMultilibs; +} + +static bool findMSP430Multilibs(const Driver &D, +                                const llvm::Triple &TargetTriple, +                                StringRef Path, const ArgList &Args, +                                DetectedMultilibs &Result) { +  FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); +  Multilib MSP430Multilib = makeMultilib("/430"); +  // FIXME: when clang starts to support msp430x ISA additional logic +  // to select between multilib must be implemented +  // Multilib MSP430xMultilib = makeMultilib("/large"); + +  Result.Multilibs.push_back(MSP430Multilib); +  Result.Multilibs.FilterOut(NonExistent); + +  Multilib::flags_list Flags; +  if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) +    return true; + +  return false; +} + +static void findRISCVMultilibs(const Driver &D, +                               const llvm::Triple &TargetTriple, StringRef Path, +                               const ArgList &Args, DetectedMultilibs &Result) { + +  FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); +  Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); +  Multilib Ilp32f = +      makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); +  Multilib Ilp32d = +      makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); +  Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64"); +  Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); +  Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); +  MultilibSet RISCVMultilibs = +      MultilibSet() +          .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) +          .FilterOut(NonExistent); + +  Multilib::flags_list Flags; +  bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64; +  StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); + +  addMultilibFlag(!IsRV64, "m32", Flags); +  addMultilibFlag(IsRV64, "m64", Flags); +  addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags); +  addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags); +  addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags); +  addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags); +  addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags); +  addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags); + +  if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) +    Result.Multilibs = RISCVMultilibs; +} + +static bool findBiarchMultilibs(const Driver &D, +                                const llvm::Triple &TargetTriple, +                                StringRef Path, const ArgList &Args, +                                bool NeedsBiarchSuffix, +                                DetectedMultilibs &Result) { +  Multilib Default; + +  // Some versions of SUSE and Fedora on ppc64 put 32-bit libs +  // in what would normally be GCCInstallPath and put the 64-bit +  // libs in a subdirectory named 64. The simple logic we follow is that +  // *if* there is a subdirectory of the right name with crtbegin.o in it, +  // we use that. If not, and if not a biarch triple alias, we look for +  // crtbegin.o without the subdirectory. + +  StringRef Suff64 = "/64"; +  // Solaris uses platform-specific suffixes instead of /64. +  if (TargetTriple.getOS() == llvm::Triple::Solaris) { +    switch (TargetTriple.getArch()) { +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      Suff64 = "/amd64"; +      break; +    case llvm::Triple::sparc: +    case llvm::Triple::sparcv9: +      Suff64 = "/sparcv9"; +      break; +    default: +      break; +    } +  } + +  Multilib Alt64 = Multilib() +                       .gccSuffix(Suff64) +                       .includeSuffix(Suff64) +                       .flag("-m32") +                       .flag("+m64") +                       .flag("-mx32"); +  Multilib Alt32 = Multilib() +                       .gccSuffix("/32") +                       .includeSuffix("/32") +                       .flag("+m32") +                       .flag("-m64") +                       .flag("-mx32"); +  Multilib Altx32 = Multilib() +                        .gccSuffix("/x32") +                        .includeSuffix("/x32") +                        .flag("-m32") +                        .flag("-m64") +                        .flag("+mx32"); + +  // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. +  FilterNonExistent NonExistent( +      Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS()); + +  // Determine default multilib from: 32, 64, x32 +  // Also handle cases such as 64 on 32, 32 on 64, etc. +  enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; +  const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; +  if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) +    Want = WANT64; +  else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) +    Want = WANT64; +  else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) +    Want = WANT32; +  else { +    if (TargetTriple.isArch32Bit()) +      Want = NeedsBiarchSuffix ? WANT64 : WANT32; +    else if (IsX32) +      Want = NeedsBiarchSuffix ? WANT64 : WANTX32; +    else +      Want = NeedsBiarchSuffix ? WANT32 : WANT64; +  } + +  if (Want == WANT32) +    Default.flag("+m32").flag("-m64").flag("-mx32"); +  else if (Want == WANT64) +    Default.flag("-m32").flag("+m64").flag("-mx32"); +  else if (Want == WANTX32) +    Default.flag("-m32").flag("-m64").flag("+mx32"); +  else +    return false; + +  Result.Multilibs.push_back(Default); +  Result.Multilibs.push_back(Alt64); +  Result.Multilibs.push_back(Alt32); +  Result.Multilibs.push_back(Altx32); + +  Result.Multilibs.FilterOut(NonExistent); + +  Multilib::flags_list Flags; +  addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); +  addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); +  addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); + +  if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) +    return false; + +  if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || +      Result.SelectedMultilib == Altx32) +    Result.BiarchSibling = Default; + +  return true; +} + +/// Generic_GCC - A tool chain using the 'gcc' command to perform +/// all subcommands; this relies on gcc translating the majority of +/// command line options. + +/// Less-than for GCCVersion, implementing a Strict Weak Ordering. +bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, +                                          int RHSPatch, +                                          StringRef RHSPatchSuffix) const { +  if (Major != RHSMajor) +    return Major < RHSMajor; +  if (Minor != RHSMinor) +    return Minor < RHSMinor; +  if (Patch != RHSPatch) { +    // Note that versions without a specified patch sort higher than those with +    // a patch. +    if (RHSPatch == -1) +      return true; +    if (Patch == -1) +      return false; + +    // Otherwise just sort on the patch itself. +    return Patch < RHSPatch; +  } +  if (PatchSuffix != RHSPatchSuffix) { +    // Sort empty suffixes higher. +    if (RHSPatchSuffix.empty()) +      return true; +    if (PatchSuffix.empty()) +      return false; + +    // Provide a lexicographic sort to make this a total ordering. +    return PatchSuffix < RHSPatchSuffix; +  } + +  // The versions are equal. +  return false; +} + +/// Parse a GCCVersion object out of a string of text. +/// +/// This is the primary means of forming GCCVersion objects. +/*static*/ +Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { +  const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; +  std::pair<StringRef, StringRef> First = VersionText.split('.'); +  std::pair<StringRef, StringRef> Second = First.second.split('.'); + +  GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; +  if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) +    return BadVersion; +  GoodVersion.MajorStr = First.first.str(); +  if (First.second.empty()) +    return GoodVersion; +  StringRef MinorStr = Second.first; +  if (Second.second.empty()) { +    if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) { +      GoodVersion.PatchSuffix = MinorStr.substr(EndNumber); +      MinorStr = MinorStr.slice(0, EndNumber); +    } +  } +  if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) +    return BadVersion; +  GoodVersion.MinorStr = MinorStr.str(); + +  // First look for a number prefix and parse that if present. Otherwise just +  // stash the entire patch string in the suffix, and leave the number +  // unspecified. This covers versions strings such as: +  //   5        (handled above) +  //   4.4 +  //   4.4-patched +  //   4.4.0 +  //   4.4.x +  //   4.4.2-rc4 +  //   4.4.x-patched +  // And retains any patch number it finds. +  StringRef PatchText = Second.second; +  if (!PatchText.empty()) { +    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) +        return BadVersion; +      GoodVersion.PatchSuffix = PatchText.substr(EndNumber); +    } +  } + +  return GoodVersion; +} + +static llvm::StringRef getGCCToolchainDir(const ArgList &Args, +                                          llvm::StringRef SysRoot) { +  const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain); +  if (A) +    return A->getValue(); + +  // If we have a SysRoot, ignore GCC_INSTALL_PREFIX. +  // GCC_INSTALL_PREFIX specifies the gcc installation for the default +  // sysroot and is likely not valid with a different sysroot. +  if (!SysRoot.empty()) +    return ""; + +  return GCC_INSTALL_PREFIX; +} + +/// Initialize a GCCInstallationDetector from the driver. +/// +/// This performs all of the autodetection and sets up the various paths. +/// Once constructed, a GCCInstallationDetector is essentially immutable. +/// +/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and +/// should instead pull the target out of the driver. This is currently +/// necessary because the driver doesn't store the final version of the target +/// triple. +void Generic_GCC::GCCInstallationDetector::init( +    const llvm::Triple &TargetTriple, const ArgList &Args, +    ArrayRef<std::string> ExtraTripleAliases) { +  llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() +                                         ? TargetTriple.get64BitArchVariant() +                                         : TargetTriple.get32BitArchVariant(); +  // The library directories which may contain GCC installations. +  SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; +  // The compatible GCC triples for this particular architecture. +  SmallVector<StringRef, 16> CandidateTripleAliases; +  SmallVector<StringRef, 16> CandidateBiarchTripleAliases; +  CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, +                           CandidateTripleAliases, CandidateBiarchLibDirs, +                           CandidateBiarchTripleAliases); + +  // Compute the set of prefixes for our search. +  SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(), +                                       D.PrefixDirs.end()); + +  StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot); +  if (GCCToolchainDir != "") { +    if (GCCToolchainDir.back() == '/') +      GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / + +    Prefixes.push_back(GCCToolchainDir); +  } else { +    // If we have a SysRoot, try that first. +    if (!D.SysRoot.empty()) { +      Prefixes.push_back(D.SysRoot); +      AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); +    } + +    // Then look for gcc installed alongside clang. +    Prefixes.push_back(D.InstalledDir + "/.."); + +    // Next, look for prefix(es) that correspond to distribution-supplied gcc +    // installations. +    if (D.SysRoot.empty()) { +      // Typically /usr. +      AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); +    } +  } + +  // Try to respect gcc-config on Gentoo. However, do that only +  // if --gcc-toolchain is not provided or equal to the Gentoo install +  // in /usr. This avoids accidentally enforcing the system GCC version +  // when using a custom toolchain. +  if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { +    SmallVector<StringRef, 16> GentooTestTriples; +    // Try to match an exact triple as target triple first. +    // e.g. crossdev -S x86_64-gentoo-linux-gnu will install gcc libs for +    // x86_64-gentoo-linux-gnu. But "clang -target x86_64-gentoo-linux-gnu" +    // may pick the libraries for x86_64-pc-linux-gnu even when exact matching +    // triple x86_64-gentoo-linux-gnu is present. +    GentooTestTriples.push_back(TargetTriple.str()); +    // Check rest of triples. +    GentooTestTriples.append(ExtraTripleAliases.begin(), +                             ExtraTripleAliases.end()); +    GentooTestTriples.append(CandidateTripleAliases.begin(), +                             CandidateTripleAliases.end()); +    if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples, +                          CandidateBiarchTripleAliases)) +      return; +  } + +  // Loop over the various components which exist and select the best GCC +  // installation available. GCC installs are ranked by version number. +  Version = GCCVersion::Parse("0.0.0"); +  for (const std::string &Prefix : Prefixes) { +    if (!D.getVFS().exists(Prefix)) +      continue; +    for (StringRef Suffix : CandidateLibDirs) { +      const std::string LibDir = Prefix + Suffix.str(); +      if (!D.getVFS().exists(LibDir)) +        continue; +      // Try to match the exact target triple first. +      ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str()); +      // Try rest of possible triples. +      for (StringRef Candidate : ExtraTripleAliases) // Try these first. +        ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); +      for (StringRef Candidate : CandidateTripleAliases) +        ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); +    } +    for (StringRef Suffix : CandidateBiarchLibDirs) { +      const std::string LibDir = Prefix + Suffix.str(); +      if (!D.getVFS().exists(LibDir)) +        continue; +      for (StringRef Candidate : CandidateBiarchTripleAliases) +        ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, +                               /*NeedsBiarchSuffix=*/ true); +    } +  } +} + +void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { +  for (const auto &InstallPath : CandidateGCCInstallPaths) +    OS << "Found candidate GCC installation: " << InstallPath << "\n"; + +  if (!GCCInstallPath.empty()) +    OS << "Selected GCC installation: " << GCCInstallPath << "\n"; + +  for (const auto &Multilib : Multilibs) +    OS << "Candidate multilib: " << Multilib << "\n"; + +  if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) +    OS << "Selected multilib: " << SelectedMultilib << "\n"; +} + +bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { +  if (BiarchSibling.hasValue()) { +    M = BiarchSibling.getValue(); +    return true; +  } +  return false; +} + +void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( +    const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes, +    StringRef SysRoot) { +  if (TargetTriple.getOS() == llvm::Triple::Solaris) { +    // Solaris is a special case. +    // The GCC installation is under +    //   /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/ +    // so we need to find those /usr/gcc/*/lib/gcc libdirs and go with +    // /usr/gcc/<version> as a prefix. + +    std::string PrefixDir = SysRoot.str() + "/usr/gcc"; +    std::error_code EC; +    for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), +                                       LE; +         !EC && LI != LE; LI = LI.increment(EC)) { +      StringRef VersionText = llvm::sys::path::filename(LI->path()); +      GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + +      // Filter out obviously bad entries. +      if (CandidateVersion.Major == -1 || CandidateVersion.isOlderThan(4, 1, 1)) +        continue; + +      std::string CandidatePrefix = PrefixDir + "/" + VersionText.str(); +      std::string CandidateLibPath = CandidatePrefix + "/lib/gcc"; +      if (!D.getVFS().exists(CandidateLibPath)) +        continue; + +      Prefixes.push_back(CandidatePrefix); +    } +    return; +  } + +  // Non-Solaris is much simpler - most systems just go with "/usr". +  if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { +    // Yet, still look for RHEL devtoolsets. +    Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); +    Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); +    Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); +    Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); +    Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); +    Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); +  } +  Prefixes.push_back(SysRoot.str() + "/usr"); +} + +/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( +    const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, +    SmallVectorImpl<StringRef> &LibDirs, +    SmallVectorImpl<StringRef> &TripleAliases, +    SmallVectorImpl<StringRef> &BiarchLibDirs, +    SmallVectorImpl<StringRef> &BiarchTripleAliases) { +  // Declare a bunch of static data sets that we'll select between below. These +  // are specifically designed to always refer to string literals to avoid any +  // lifetime or initialization issues. +  static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; +  static const char *const AArch64Triples[] = { +      "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", +      "aarch64-suse-linux", "aarch64-linux-android"}; +  static const char *const AArch64beLibDirs[] = {"/lib"}; +  static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", +                                                 "aarch64_be-linux-gnu"}; + +  static const char *const ARMLibDirs[] = {"/lib"}; +  static const char *const ARMTriples[] = {"arm-linux-gnueabi", +                                           "arm-linux-androideabi"}; +  static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", +                                             "armv7hl-redhat-linux-gnueabi", +                                             "armv6hl-suse-linux-gnueabi", +                                             "armv7hl-suse-linux-gnueabi"}; +  static const char *const ARMebLibDirs[] = {"/lib"}; +  static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", +                                             "armeb-linux-androideabi"}; +  static const char *const ARMebHFTriples[] = { +      "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; + +  static const char *const AVRLibDirs[] = {"/lib"}; +  static const char *const AVRTriples[] = {"avr"}; + +  static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; +  static const char *const X86_64Triples[] = { +      "x86_64-linux-gnu",       "x86_64-unknown-linux-gnu", +      "x86_64-pc-linux-gnu",    "x86_64-redhat-linux6E", +      "x86_64-redhat-linux",    "x86_64-suse-linux", +      "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", +      "x86_64-slackware-linux", "x86_64-unknown-linux", +      "x86_64-amazon-linux",    "x86_64-linux-android"}; +  static const char *const X32LibDirs[] = {"/libx32"}; +  static const char *const X86LibDirs[] = {"/lib32", "/lib"}; +  static const char *const X86Triples[] = { +      "i686-linux-gnu",       "i686-pc-linux-gnu",     "i486-linux-gnu", +      "i386-linux-gnu",       "i386-redhat-linux6E",   "i686-redhat-linux", +      "i586-redhat-linux",    "i386-redhat-linux",     "i586-suse-linux", +      "i486-slackware-linux", "i686-montavista-linux", "i586-linux-gnu", +      "i686-linux-android",   "i386-gnu",              "i486-gnu", +      "i586-gnu",             "i686-gnu"}; + +  static const char *const MIPSLibDirs[] = {"/lib"}; +  static const char *const MIPSTriples[] = { +      "mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", +      "mips-img-linux-gnu", "mipsisa32r6-linux-gnu"}; +  static const char *const MIPSELLibDirs[] = {"/lib"}; +  static const char *const MIPSELTriples[] = { +      "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu", +      "mipsel-linux-android"}; + +  static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; +  static const char *const MIPS64Triples[] = { +      "mips64-linux-gnu",      "mips-mti-linux-gnu", +      "mips-img-linux-gnu",    "mips64-linux-gnuabi64", +      "mipsisa64r6-linux-gnu", "mipsisa64r6-linux-gnuabi64"}; +  static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; +  static const char *const MIPS64ELTriples[] = { +      "mips64el-linux-gnu",      "mips-mti-linux-gnu", +      "mips-img-linux-gnu",      "mips64el-linux-gnuabi64", +      "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64", +      "mips64el-linux-android"}; + +  static const char *const MIPSN32LibDirs[] = {"/lib32"}; +  static const char *const MIPSN32Triples[] = {"mips64-linux-gnuabin32", +                                               "mipsisa64r6-linux-gnuabin32"}; +  static const char *const MIPSN32ELLibDirs[] = {"/lib32"}; +  static const char *const MIPSN32ELTriples[] = { +      "mips64el-linux-gnuabin32", "mipsisa64r6el-linux-gnuabin32"}; + +  static const char *const MSP430LibDirs[] = {"/lib"}; +  static const char *const MSP430Triples[] = {"msp430-elf"}; + +  static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; +  static const char *const PPCTriples[] = { +      "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", +      "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; +  static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; +  static const char *const PPC64Triples[] = { +      "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", +      "powerpc64-suse-linux", "ppc64-redhat-linux"}; +  static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; +  static const char *const PPC64LETriples[] = { +      "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", +      "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; + +  static const char *const RISCV32LibDirs[] = {"/lib32", "/lib"}; +  static const char *const RISCV32Triples[] = {"riscv32-unknown-linux-gnu", +                                               "riscv32-linux-gnu", +                                               "riscv32-unknown-elf"}; +  static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; +  static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", +                                               "riscv64-linux-gnu", +                                               "riscv64-unknown-elf", +                                               "riscv64-suse-linux"}; + +  static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; +  static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", +                                               "sparcv8-linux-gnu"}; +  static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; +  static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", +                                               "sparcv9-linux-gnu"}; + +  static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; +  static const char *const SystemZTriples[] = { +      "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", +      "s390x-suse-linux", "s390x-redhat-linux"}; + + +  using std::begin; +  using std::end; + +  if (TargetTriple.getOS() == llvm::Triple::Solaris) { +    static const char *const SolarisLibDirs[] = {"/lib"}; +    static const char *const SolarisSparcV8Triples[] = { +        "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"}; +    static const char *const SolarisSparcV9Triples[] = { +        "sparcv9-sun-solaris2.11", "sparcv9-sun-solaris2.12"}; +    static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11", +                                                    "i386-pc-solaris2.12"}; +    static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11", +                                                       "x86_64-pc-solaris2.12"}; +    LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); +    BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); +    switch (TargetTriple.getArch()) { +    case llvm::Triple::x86: +      TripleAliases.append(begin(SolarisX86Triples), end(SolarisX86Triples)); +      BiarchTripleAliases.append(begin(SolarisX86_64Triples), +                                 end(SolarisX86_64Triples)); +      break; +    case llvm::Triple::x86_64: +      TripleAliases.append(begin(SolarisX86_64Triples), +                           end(SolarisX86_64Triples)); +      BiarchTripleAliases.append(begin(SolarisX86Triples), +                                 end(SolarisX86Triples)); +      break; +    case llvm::Triple::sparc: +      TripleAliases.append(begin(SolarisSparcV8Triples), +                           end(SolarisSparcV8Triples)); +      BiarchTripleAliases.append(begin(SolarisSparcV9Triples), +                                 end(SolarisSparcV9Triples)); +      break; +    case llvm::Triple::sparcv9: +      TripleAliases.append(begin(SolarisSparcV9Triples), +                           end(SolarisSparcV9Triples)); +      BiarchTripleAliases.append(begin(SolarisSparcV8Triples), +                                 end(SolarisSparcV8Triples)); +      break; +    default: +      break; +    } +    return; +  } + +  // Android targets should not use GNU/Linux tools or libraries. +  if (TargetTriple.isAndroid()) { +    static const char *const AArch64AndroidTriples[] = { +        "aarch64-linux-android"}; +    static const char *const ARMAndroidTriples[] = {"arm-linux-androideabi"}; +    static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; +    static const char *const MIPS64ELAndroidTriples[] = { +        "mips64el-linux-android"}; +    static const char *const X86AndroidTriples[] = {"i686-linux-android"}; +    static const char *const X86_64AndroidTriples[] = {"x86_64-linux-android"}; + +    switch (TargetTriple.getArch()) { +    case llvm::Triple::aarch64: +      LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); +      TripleAliases.append(begin(AArch64AndroidTriples), +                           end(AArch64AndroidTriples)); +      break; +    case llvm::Triple::arm: +    case llvm::Triple::thumb: +      LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); +      TripleAliases.append(begin(ARMAndroidTriples), end(ARMAndroidTriples)); +      break; +    case llvm::Triple::mipsel: +      LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); +      TripleAliases.append(begin(MIPSELAndroidTriples), +                           end(MIPSELAndroidTriples)); +      BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); +      BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), +                                 end(MIPS64ELAndroidTriples)); +      break; +    case llvm::Triple::mips64el: +      LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); +      TripleAliases.append(begin(MIPS64ELAndroidTriples), +                           end(MIPS64ELAndroidTriples)); +      BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); +      BiarchTripleAliases.append(begin(MIPSELAndroidTriples), +                                 end(MIPSELAndroidTriples)); +      break; +    case llvm::Triple::x86_64: +      LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); +      TripleAliases.append(begin(X86_64AndroidTriples), +                           end(X86_64AndroidTriples)); +      BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); +      BiarchTripleAliases.append(begin(X86AndroidTriples), +                                 end(X86AndroidTriples)); +      break; +    case llvm::Triple::x86: +      LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); +      TripleAliases.append(begin(X86AndroidTriples), end(X86AndroidTriples)); +      BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); +      BiarchTripleAliases.append(begin(X86_64AndroidTriples), +                                 end(X86_64AndroidTriples)); +      break; +    default: +      break; +    } + +    return; +  } + +  switch (TargetTriple.getArch()) { +  case llvm::Triple::aarch64: +    LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); +    TripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); +    BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); +    BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); +    break; +  case llvm::Triple::aarch64_be: +    LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); +    TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); +    BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); +    BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); +    break; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); +    if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { +      TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); +    } else { +      TripleAliases.append(begin(ARMTriples), end(ARMTriples)); +    } +    break; +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: +    LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); +    if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { +      TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); +    } else { +      TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); +    } +    break; +  case llvm::Triple::avr: +    LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs)); +    TripleAliases.append(begin(AVRTriples), end(AVRTriples)); +    break; +  case llvm::Triple::x86_64: +    LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); +    TripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); +    // x32 is always available when x86_64 is available, so adding it as +    // secondary arch with x86_64 triples +    if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { +      BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs)); +      BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); +    } else { +      BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); +      BiarchTripleAliases.append(begin(X86Triples), end(X86Triples)); +    } +    break; +  case llvm::Triple::x86: +    LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); +    // MCU toolchain is 32 bit only and its triple alias is TargetTriple +    // itself, which will be appended below. +    if (!TargetTriple.isOSIAMCU()) { +      TripleAliases.append(begin(X86Triples), end(X86Triples)); +      BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); +      BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); +    } +    break; +  case llvm::Triple::mips: +    LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); +    TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); +    BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); +    BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); +    BiarchLibDirs.append(begin(MIPSN32LibDirs), end(MIPSN32LibDirs)); +    BiarchTripleAliases.append(begin(MIPSN32Triples), end(MIPSN32Triples)); +    break; +  case llvm::Triple::mipsel: +    LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); +    TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); +    TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); +    BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); +    BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); +    BiarchLibDirs.append(begin(MIPSN32ELLibDirs), end(MIPSN32ELLibDirs)); +    BiarchTripleAliases.append(begin(MIPSN32ELTriples), end(MIPSN32ELTriples)); +    break; +  case llvm::Triple::mips64: +    LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); +    TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); +    BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); +    BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); +    BiarchLibDirs.append(begin(MIPSN32LibDirs), end(MIPSN32LibDirs)); +    BiarchTripleAliases.append(begin(MIPSN32Triples), end(MIPSN32Triples)); +    break; +  case llvm::Triple::mips64el: +    LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); +    TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); +    BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); +    BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); +    BiarchLibDirs.append(begin(MIPSN32ELLibDirs), end(MIPSN32ELLibDirs)); +    BiarchTripleAliases.append(begin(MIPSN32ELTriples), end(MIPSN32ELTriples)); +    BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); +    break; +  case llvm::Triple::msp430: +    LibDirs.append(begin(MSP430LibDirs), end(MSP430LibDirs)); +    TripleAliases.append(begin(MSP430Triples), end(MSP430Triples)); +    break; +  case llvm::Triple::ppc: +    LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); +    TripleAliases.append(begin(PPCTriples), end(PPCTriples)); +    BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); +    BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); +    break; +  case llvm::Triple::ppc64: +    LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); +    TripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); +    BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); +    BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples)); +    break; +  case llvm::Triple::ppc64le: +    LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); +    TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); +    break; +  case llvm::Triple::riscv32: +    LibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); +    TripleAliases.append(begin(RISCV32Triples), end(RISCV32Triples)); +    BiarchLibDirs.append(begin(RISCV64LibDirs), end(RISCV64LibDirs)); +    BiarchTripleAliases.append(begin(RISCV64Triples), end(RISCV64Triples)); +    break; +  case llvm::Triple::riscv64: +    LibDirs.append(begin(RISCV64LibDirs), end(RISCV64LibDirs)); +    TripleAliases.append(begin(RISCV64Triples), end(RISCV64Triples)); +    BiarchLibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); +    BiarchTripleAliases.append(begin(RISCV32Triples), end(RISCV32Triples)); +    break; +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +    LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); +    TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); +    BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); +    BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); +    break; +  case llvm::Triple::sparcv9: +    LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); +    TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); +    BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); +    BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); +    break; +  case llvm::Triple::systemz: +    LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); +    TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); +    break; +  default: +    // By default, just rely on the standard lib directories and the original +    // triple. +    break; +  } + +  // Always append the drivers target triple to the end, in case it doesn't +  // match any of our aliases. +  TripleAliases.push_back(TargetTriple.str()); + +  // Also include the multiarch variant if it's different. +  if (TargetTriple.str() != BiarchTriple.str()) +    BiarchTripleAliases.push_back(BiarchTriple.str()); +} + +bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( +    const llvm::Triple &TargetTriple, const ArgList &Args, +    StringRef Path, bool NeedsBiarchSuffix) { +  llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); +  DetectedMultilibs Detected; + +  // Android standalone toolchain could have multilibs for ARM and Thumb. +  // Debian mips multilibs behave more like the rest of the biarch ones, +  // so handle them there +  if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { +    // It should also work without multilibs in a simplified toolchain. +    findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); +  } else if (TargetTriple.isMIPS()) { +    if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) +      return false; +  } else if (TargetTriple.isRISCV()) { +    findRISCVMultilibs(D, TargetTriple, Path, Args, Detected); +  } else if (isMSP430(TargetArch)) { +    findMSP430Multilibs(D, TargetTriple, Path, Args, Detected); +  } else if (TargetArch == llvm::Triple::avr) { +    // AVR has no multilibs. +  } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, +                                  NeedsBiarchSuffix, Detected)) { +    return false; +  } + +  Multilibs = Detected.Multilibs; +  SelectedMultilib = Detected.SelectedMultilib; +  BiarchSibling = Detected.BiarchSibling; + +  return true; +} + +void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( +    const llvm::Triple &TargetTriple, const ArgList &Args, +    const std::string &LibDir, StringRef CandidateTriple, +    bool NeedsBiarchSuffix) { +  llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); +  // Locations relative to the system lib directory where GCC's triple-specific +  // directories might reside. +  struct GCCLibSuffix { +    // Path from system lib directory to GCC triple-specific directory. +    std::string LibSuffix; +    // Path from GCC triple-specific directory back to system lib directory. +    // This is one '..' component per component in LibSuffix. +    StringRef ReversePath; +    // Whether this library suffix is relevant for the triple. +    bool Active; +  } Suffixes[] = { +      // This is the normal place. +      {"gcc/" + CandidateTriple.str(), "../..", true}, + +      // Debian puts cross-compilers in gcc-cross. +      {"gcc-cross/" + CandidateTriple.str(), "../..", +       TargetTriple.getOS() != llvm::Triple::Solaris}, + +      // The Freescale PPC SDK has the gcc libraries in +      // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do +      // this on Freescale triples, though, since some systems put a *lot* of +      // files in that location, not just GCC installation data. +      {CandidateTriple.str(), "..", +       TargetTriple.getVendor() == llvm::Triple::Freescale || +       TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}, + +      // Natively multiarch systems sometimes put the GCC triple-specific +      // directory within their multiarch lib directory, resulting in the +      // triple appearing twice. +      {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", +       TargetTriple.getOS() != llvm::Triple::Solaris}, + +      // Deal with cases (on Ubuntu) where the system architecture could be i386 +      // but the GCC target architecture could be (say) i686. +      // FIXME: It may be worthwhile to generalize this and look for a second +      // triple. +      {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", +       (TargetArch == llvm::Triple::x86 && +        TargetTriple.getOS() != llvm::Triple::Solaris)}, +      {"i386-gnu/gcc/" + CandidateTriple.str(), "../../..", +       (TargetArch == llvm::Triple::x86 && +        TargetTriple.getOS() != llvm::Triple::Solaris)}}; + +  for (auto &Suffix : Suffixes) { +    if (!Suffix.Active) +      continue; + +    StringRef LibSuffix = Suffix.LibSuffix; +    std::error_code EC; +    for (llvm::vfs::directory_iterator +             LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), +             LE; +         !EC && LI != LE; LI = LI.increment(EC)) { +      StringRef VersionText = llvm::sys::path::filename(LI->path()); +      GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); +      if (CandidateVersion.Major != -1) // Filter obviously bad entries. +        if (!CandidateGCCInstallPaths.insert(LI->path()).second) +          continue; // Saw this path before; no need to look at it again. +      if (CandidateVersion.isOlderThan(4, 1, 1)) +        continue; +      if (CandidateVersion <= Version) +        continue; + +      if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), +                               NeedsBiarchSuffix)) +        continue; + +      Version = CandidateVersion; +      GCCTriple.setTriple(CandidateTriple); +      // FIXME: We hack together the directory name here instead of +      // using LI to ensure stable path separators across Windows and +      // Linux. +      GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); +      GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); +      IsValid = true; +    } +  } +} + +bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( +    const llvm::Triple &TargetTriple, const ArgList &Args, +    const SmallVectorImpl<StringRef> &CandidateTriples, +    const SmallVectorImpl<StringRef> &CandidateBiarchTriples) { +  for (StringRef CandidateTriple : CandidateTriples) { +    if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) +      return true; +  } + +  for (StringRef CandidateTriple : CandidateBiarchTriples) { +    if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) +      return true; +  } +  return false; +} + +bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( +    const llvm::Triple &TargetTriple, const ArgList &Args, +    StringRef CandidateTriple, bool NeedsBiarchSuffix) { +  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = +      D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + +                                  CandidateTriple.str()); +  if (File) { +    SmallVector<StringRef, 2> Lines; +    File.get()->getBuffer().split(Lines, "\n"); +    for (StringRef Line : Lines) { +      Line = Line.trim(); +      // CURRENT=triple-version +      if (!Line.consume_front("CURRENT=")) +        continue; +      // Process the config file pointed to by CURRENT. +      llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile = +          D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/" + +                                      Line.str()); +      std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-'); +      // List of paths to scan for libraries. +      SmallVector<StringRef, 4> GentooScanPaths; +      // Scan the Config file to find installed GCC libraries path. +      // Typical content of the GCC config file: +      // LDPATH="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x:/usr/lib/gcc/ +      // (continued from previous line) x86_64-pc-linux-gnu/4.9.x/32" +      // MANPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/man" +      // INFOPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/info" +      // STDCXX_INCDIR="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x/include/g++-v4" +      // We are looking for the paths listed in LDPATH=... . +      if (ConfigFile) { +        SmallVector<StringRef, 2> ConfigLines; +        ConfigFile.get()->getBuffer().split(ConfigLines, "\n"); +        for (StringRef ConfLine : ConfigLines) { +          ConfLine = ConfLine.trim(); +          if (ConfLine.consume_front("LDPATH=")) { +            // Drop '"' from front and back if present. +            ConfLine.consume_back("\""); +            ConfLine.consume_front("\""); +            // Get all paths sperated by ':' +            ConfLine.split(GentooScanPaths, ':', -1, /*AllowEmpty*/ false); +          } +        } +      } +      // Test the path based on the version in /etc/env.d/gcc/config-{tuple}. +      std::string basePath = "/usr/lib/gcc/" + ActiveVersion.first.str() + "/" +          + ActiveVersion.second.str(); +      GentooScanPaths.push_back(StringRef(basePath)); + +      // Scan all paths for GCC libraries. +      for (const auto &GentooScanPath : GentooScanPaths) { +        std::string GentooPath = D.SysRoot + std::string(GentooScanPath); +        if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { +          if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, +                                   NeedsBiarchSuffix)) +            continue; + +          Version = GCCVersion::Parse(ActiveVersion.second); +          GCCInstallPath = GentooPath; +          GCCParentLibPath = GentooPath + std::string("/../../.."); +          GCCTriple.setTriple(ActiveVersion.first); +          IsValid = true; +          return true; +        } +      } +    } +  } + +  return false; +} + +Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, +                         const ArgList &Args) +    : ToolChain(D, Triple, Args), GCCInstallation(D), +      CudaInstallation(D, Triple, Args) { +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); +} + +Generic_GCC::~Generic_GCC() {} + +Tool *Generic_GCC::getTool(Action::ActionClass AC) const { +  switch (AC) { +  case Action::PreprocessJobClass: +    if (!Preprocess) +      Preprocess.reset(new clang::driver::tools::gcc::Preprocessor(*this)); +    return Preprocess.get(); +  case Action::CompileJobClass: +    if (!Compile) +      Compile.reset(new tools::gcc::Compiler(*this)); +    return Compile.get(); +  default: +    return ToolChain::getTool(AC); +  } +} + +Tool *Generic_GCC::buildAssembler() const { +  return new tools::gnutools::Assembler(*this); +} + +Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } + +void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { +  // Print the information about how we detected the GCC installation. +  GCCInstallation.print(OS); +  CudaInstallation.print(OS); +} + +bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { +  return getArch() == llvm::Triple::x86_64; +} + +bool Generic_GCC::isPICDefault() const { +  switch (getArch()) { +  case llvm::Triple::x86_64: +    return getTriple().isOSWindows(); +  case llvm::Triple::ppc64: +    // Big endian PPC is PIC by default +    return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: +    return true; +  default: +    return false; +  } +} + +bool Generic_GCC::isPIEDefault() const { return false; } + +bool Generic_GCC::isPICDefaultForced() const { +  return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); +} + +bool Generic_GCC::IsIntegratedAssemblerDefault() const { +  switch (getTriple().getArch()) { +  case llvm::Triple::x86: +  case llvm::Triple::x86_64: +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::avr: +  case llvm::Triple::bpfel: +  case llvm::Triple::bpfeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: +  case llvm::Triple::ppc: +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: +  case llvm::Triple::riscv32: +  case llvm::Triple::riscv64: +  case llvm::Triple::systemz: +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: +  case llvm::Triple::msp430: +    return true; +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +  case llvm::Triple::sparcv9: +    if (getTriple().isOSFreeBSD() || getTriple().isOSOpenBSD() || +        getTriple().isOSSolaris()) +      return true; +    return false; +  default: +    return false; +  } +} + +void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, +                                               ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  switch (GetCXXStdlibType(DriverArgs)) { +  case ToolChain::CST_Libcxx: +    addLibCxxIncludePaths(DriverArgs, CC1Args); +    break; + +  case ToolChain::CST_Libstdcxx: +    addLibStdCxxIncludePaths(DriverArgs, CC1Args); +    break; +  } +} + +void +Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                   llvm::opt::ArgStringList &CC1Args) const { +  // FIXME: The Linux behavior would probaby be a better approach here. +  addSystemInclude(DriverArgs, CC1Args, +                   getDriver().SysRoot + "/usr/include/c++/v1"); +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                      llvm::opt::ArgStringList &CC1Args) const { +  // By default, we don't assume we know where libstdc++ might be installed. +  // FIXME: If we have a valid GCCInstallation, use it. +} + +/// Helper to add the variant paths of a libstdc++ installation. +bool Generic_GCC::addLibStdCXXIncludePaths( +    Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, +    StringRef TargetMultiarchTriple, Twine IncludeSuffix, +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (!getVFS().exists(Base + Suffix)) +    return false; + +  addSystemInclude(DriverArgs, CC1Args, Base + Suffix); + +  // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If +  // that path exists or we have neither a GCC nor target multiarch triple, use +  // this vanilla search path. +  if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || +      getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { +    addSystemInclude(DriverArgs, CC1Args, +                     Base + Suffix + "/" + GCCTriple + IncludeSuffix); +  } else { +    // Otherwise try to use multiarch naming schemes which have normalized the +    // triples and put the triple before the suffix. +    // +    // GCC surprisingly uses *both* the GCC triple with a multilib suffix and +    // the target triple, so we support that here. +    addSystemInclude(DriverArgs, CC1Args, +                     Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); +    addSystemInclude(DriverArgs, CC1Args, +                     Base + "/" + TargetMultiarchTriple + Suffix); +  } + +  addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); +  return true; +} + +llvm::opt::DerivedArgList * +Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, +                           Action::OffloadKind DeviceOffloadKind) const { + +  // If this tool chain is used for an OpenMP offloading device we have to make +  // sure we always generate a shared library regardless of the commands the +  // user passed to the host. This is required because the runtime library +  // is required to load the device image dynamically at run time. +  if (DeviceOffloadKind == Action::OFK_OpenMP) { +    DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); +    const OptTable &Opts = getDriver().getOpts(); + +    // Request the shared library. Given that these options are decided +    // implicitly, they do not refer to any base argument. +    DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared)); +    DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC)); + +    // Filter all the arguments we don't care passing to the offloading +    // toolchain as they can mess up with the creation of a shared library. +    for (auto *A : Args) { +      switch ((options::ID)A->getOption().getID()) { +      default: +        DAL->append(A); +        break; +      case options::OPT_shared: +      case options::OPT_dynamic: +      case options::OPT_static: +      case options::OPT_fPIC: +      case options::OPT_fno_PIC: +      case options::OPT_fpic: +      case options::OPT_fno_pic: +      case options::OPT_fPIE: +      case options::OPT_fno_PIE: +      case options::OPT_fpie: +      case options::OPT_fno_pie: +        break; +      } +    } +    return DAL; +  } +  return nullptr; +} + +void Generic_ELF::anchor() {} + +void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, +                                        ArgStringList &CC1Args, +                                        Action::OffloadKind) const { +  const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); +  bool UseInitArrayDefault = +      getTriple().getArch() == llvm::Triple::aarch64 || +      getTriple().getArch() == llvm::Triple::aarch64_be || +      (getTriple().isOSFreeBSD() && +       getTriple().getOSMajorVersion() >= 12) || +      (getTriple().getOS() == llvm::Triple::Linux && +       ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || +        getTriple().isAndroid())) || +      getTriple().getOS() == llvm::Triple::NaCl || +      (getTriple().getVendor() == llvm::Triple::MipsTechnologies && +       !getTriple().hasEnvironment()) || +      getTriple().getOS() == llvm::Triple::Solaris || +      getTriple().getArch() == llvm::Triple::riscv32 || +      getTriple().getArch() == llvm::Triple::riscv64; + +  if (DriverArgs.hasFlag(options::OPT_fuse_init_array, +                         options::OPT_fno_use_init_array, UseInitArrayDefault)) +    CC1Args.push_back("-fuse-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h new file mode 100644 index 0000000000000..3bb38c498b35d --- /dev/null +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -0,0 +1,356 @@ +//===--- Gnu.h - Gnu Tool and ToolChain Implementations ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H + +#include "Cuda.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include <set> + +namespace clang { +namespace driver { + +struct DetectedMultilibs { +  /// The set of multilibs that the detected installation supports. +  MultilibSet Multilibs; + +  /// The primary multilib appropriate for the given flags. +  Multilib SelectedMultilib; + +  /// On Biarch systems, this corresponds to the default multilib when +  /// targeting the non-default multilib. Otherwise, it is empty. +  llvm::Optional<Multilib> BiarchSibling; +}; + +bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, +                       StringRef Path, const llvm::opt::ArgList &Args, +                       DetectedMultilibs &Result); + +namespace tools { + +/// Base class for all GNU tools that provide the same behavior when +/// it comes to response files support +class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { +  virtual void anchor(); + +public: +  GnuTool(const char *Name, const char *ShortName, const ToolChain &TC) +      : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {} +}; + +/// Directly call GNU Binutils' assembler and linker. +namespace gnutools { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) : GnuTool("GNU::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("GNU::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace gnutools + +/// gcc - Generic GCC tool implementations. +namespace gcc { +class LLVM_LIBRARY_VISIBILITY Common : public GnuTool { +public: +  Common(const char *Name, const char *ShortName, const ToolChain &TC) +      : GnuTool(Name, ShortName, TC) {} + +  // A gcc tool has an "integrated" assembler that it will call to produce an +  // object. Let it use that assembler so that we don't have to deal with +  // assembly syntax incompatibilities. +  bool hasIntegratedAssembler() const override { return true; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; + +  /// RenderExtraToolArgs - Render any arguments necessary to force +  /// the particular tool mode. +  virtual void RenderExtraToolArgs(const JobAction &JA, +                                   llvm::opt::ArgStringList &CmdArgs) const = 0; +}; + +class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common { +public: +  Preprocessor(const ToolChain &TC) +      : Common("gcc::Preprocessor", "gcc preprocessor", TC) {} + +  bool hasGoodDiagnostics() const override { return true; } +  bool hasIntegratedCPP() const override { return false; } + +  void RenderExtraToolArgs(const JobAction &JA, +                           llvm::opt::ArgStringList &CmdArgs) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Compiler : public Common { +public: +  Compiler(const ToolChain &TC) : Common("gcc::Compiler", "gcc frontend", TC) {} + +  bool hasGoodDiagnostics() const override { return true; } +  bool hasIntegratedCPP() const override { return true; } + +  void RenderExtraToolArgs(const JobAction &JA, +                           llvm::opt::ArgStringList &CmdArgs) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Common { +public: +  Linker(const ToolChain &TC) : Common("gcc::Linker", "linker (via gcc)", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void RenderExtraToolArgs(const JobAction &JA, +                           llvm::opt::ArgStringList &CmdArgs) const override; +}; +} // end namespace gcc +} // end namespace tools + +namespace toolchains { + +/// Generic_GCC - A tool chain using the 'gcc' command to perform +/// all subcommands; this relies on gcc translating the majority of +/// command line options. +class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { +public: +  /// Struct to store and manipulate GCC versions. +  /// +  /// We rely on assumptions about the form and structure of GCC version +  /// numbers: they consist of at most three '.'-separated components, and each +  /// component is a non-negative integer except for the last component. For +  /// the last component we are very flexible in order to tolerate release +  /// candidates or 'x' wildcards. +  /// +  /// Note that the ordering established among GCCVersions is based on the +  /// preferred version string to use. For example we prefer versions without +  /// a hard-coded patch number to those with a hard coded patch number. +  /// +  /// Currently this doesn't provide any logic for textual suffixes to patches +  /// in the way that (for example) Debian's version format does. If that ever +  /// becomes necessary, it can be added. +  struct GCCVersion { +    /// The unparsed text of the version. +    std::string Text; + +    /// The parsed major, minor, and patch numbers. +    int Major, Minor, Patch; + +    /// The text of the parsed major, and major+minor versions. +    std::string MajorStr, MinorStr; + +    /// Any textual suffix on the patch number. +    std::string PatchSuffix; + +    static GCCVersion Parse(StringRef VersionText); +    bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, +                     StringRef RHSPatchSuffix = StringRef()) const; +    bool operator<(const GCCVersion &RHS) const { +      return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix); +    } +    bool operator>(const GCCVersion &RHS) const { return RHS < *this; } +    bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } +    bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } +  }; + +  /// This is a class to find a viable GCC installation for Clang to +  /// use. +  /// +  /// This class tries to find a GCC installation on the system, and report +  /// information about it. It starts from the host information provided to the +  /// Driver, and has logic for fuzzing that where appropriate. +  class GCCInstallationDetector { +    bool IsValid; +    llvm::Triple GCCTriple; +    const Driver &D; + +    // FIXME: These might be better as path objects. +    std::string GCCInstallPath; +    std::string GCCParentLibPath; + +    /// The primary multilib appropriate for the given flags. +    Multilib SelectedMultilib; +    /// On Biarch systems, this corresponds to the default multilib when +    /// targeting the non-default multilib. Otherwise, it is empty. +    llvm::Optional<Multilib> BiarchSibling; + +    GCCVersion Version; + +    // We retain the list of install paths that were considered and rejected in +    // order to print out detailed information in verbose mode. +    std::set<std::string> CandidateGCCInstallPaths; + +    /// The set of multilibs that the detected installation supports. +    MultilibSet Multilibs; + +  public: +    explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} +    void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, +              ArrayRef<std::string> ExtraTripleAliases = None); + +    /// Check whether we detected a valid GCC install. +    bool isValid() const { return IsValid; } + +    /// Get the GCC triple for the detected install. +    const llvm::Triple &getTriple() const { return GCCTriple; } + +    /// Get the detected GCC installation path. +    StringRef getInstallPath() const { return GCCInstallPath; } + +    /// Get the detected GCC parent lib path. +    StringRef getParentLibPath() const { return GCCParentLibPath; } + +    /// Get the detected Multilib +    const Multilib &getMultilib() const { return SelectedMultilib; } + +    /// Get the whole MultilibSet +    const MultilibSet &getMultilibs() const { return Multilibs; } + +    /// Get the biarch sibling multilib (if it exists). +    /// \return true iff such a sibling exists +    bool getBiarchSibling(Multilib &M) const; + +    /// Get the detected GCC version string. +    const GCCVersion &getVersion() const { return Version; } + +    /// Print information about the detected GCC installation. +    void print(raw_ostream &OS) const; + +  private: +    static void +    CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, +                             const llvm::Triple &BiarchTriple, +                             SmallVectorImpl<StringRef> &LibDirs, +                             SmallVectorImpl<StringRef> &TripleAliases, +                             SmallVectorImpl<StringRef> &BiarchLibDirs, +                             SmallVectorImpl<StringRef> &BiarchTripleAliases); + +    void AddDefaultGCCPrefixes(const llvm::Triple &TargetTriple, +                               SmallVectorImpl<std::string> &Prefixes, +                               StringRef SysRoot); + +    bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, +                             const llvm::opt::ArgList &Args, +                             StringRef Path, +                             bool NeedsBiarchSuffix = false); + +    void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, +                                const llvm::opt::ArgList &Args, +                                const std::string &LibDir, +                                StringRef CandidateTriple, +                                bool NeedsBiarchSuffix = false); + +    bool ScanGentooConfigs(const llvm::Triple &TargetTriple, +                           const llvm::opt::ArgList &Args, +                           const SmallVectorImpl<StringRef> &CandidateTriples, +                           const SmallVectorImpl<StringRef> &BiarchTriples); + +    bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, +                             const llvm::opt::ArgList &Args, +                             StringRef CandidateTriple, +                             bool NeedsBiarchSuffix = false); +  }; + +protected: +  GCCInstallationDetector GCCInstallation; +  CudaInstallationDetector CudaInstallation; + +public: +  Generic_GCC(const Driver &D, const llvm::Triple &Triple, +              const llvm::opt::ArgList &Args); +  ~Generic_GCC() override; + +  void printVerboseInfo(raw_ostream &OS) const override; + +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; +  bool IsIntegratedAssemblerDefault() const override; +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; + +protected: +  Tool *getTool(Action::ActionClass AC) const override; +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; + +  /// \name ToolChain Implementation Helper Functions +  /// @{ + +  /// Check whether the target triple's architecture is 64-bits. +  bool isTarget64Bit() const { return getTriple().isArch64Bit(); } + +  /// Check whether the target triple's architecture is 32-bits. +  bool isTarget32Bit() const { return getTriple().isArch32Bit(); } + +  // FIXME: This should be final, but the CrossWindows toolchain does weird +  // things that can't be easily generalized. +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  virtual void +  addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                        llvm::opt::ArgStringList &CC1Args) const; +  virtual void +  addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                           llvm::opt::ArgStringList &CC1Args) const; + +  bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, +                                StringRef GCCMultiarchTriple, +                                StringRef TargetMultiarchTriple, +                                Twine IncludeSuffix, +                                const llvm::opt::ArgList &DriverArgs, +                                llvm::opt::ArgStringList &CC1Args) const; + +  /// @} + +private: +  mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess; +  mutable std::unique_ptr<tools::gcc::Compiler> Compile; +}; + +class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { +  virtual void anchor(); + +public: +  Generic_ELF(const Driver &D, const llvm::Triple &Triple, +              const llvm::opt::ArgList &Args) +      : Generic_GCC(D, Triple, Args) {} + +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp new file mode 100644 index 0000000000000..ad9384df6a242 --- /dev/null +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -0,0 +1,449 @@ +//===--- HIP.cpp - HIP Tool and ToolChain Implementations -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HIP.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Basic/Cuda.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +#if defined(_WIN32) || defined(_WIN64) +#define NULL_FILE "nul" +#else +#define NULL_FILE "/dev/null" +#endif + +namespace { + +static void addBCLib(const Driver &D, const ArgList &Args, +                     ArgStringList &CmdArgs, ArgStringList LibraryPaths, +                     StringRef BCName) { +  StringRef FullName; +  for (std::string LibraryPath : LibraryPaths) { +    SmallString<128> Path(LibraryPath); +    llvm::sys::path::append(Path, BCName); +    FullName = Path; +    if (llvm::sys::fs::exists(FullName)) { +      CmdArgs.push_back("-mlink-builtin-bitcode"); +      CmdArgs.push_back(Args.MakeArgString(FullName)); +      return; +    } +  } +  D.Diag(diag::err_drv_no_such_file) << BCName; +} + +static const char *getOutputFileName(Compilation &C, StringRef Base, +                                     const char *Postfix, +                                     const char *Extension) { +  const char *OutputFileName; +  if (C.getDriver().isSaveTempsEnabled()) { +    OutputFileName = +        C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension); +  } else { +    std::string TmpName = +        C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension); +    OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); +  } +  return OutputFileName; +} +} // namespace + +const char *AMDGCN::Linker::constructLLVMLinkCommand( +    Compilation &C, const JobAction &JA, const InputInfoList &Inputs, +    const ArgList &Args, StringRef SubArchName, +    StringRef OutputFilePrefix) const { +  ArgStringList CmdArgs; +  // Add the input bc's created by compile step. +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  // Add an intermediate output file. +  CmdArgs.push_back("-o"); +  auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc"); +  CmdArgs.push_back(OutputFileName); +  SmallString<128> ExecPath(C.getDriver().Dir); +  llvm::sys::path::append(ExecPath, "llvm-link"); +  const char *Exec = Args.MakeArgString(ExecPath); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +  return OutputFileName; +} + +const char *AMDGCN::Linker::constructOptCommand( +    Compilation &C, const JobAction &JA, const InputInfoList &Inputs, +    const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, +    llvm::StringRef OutputFilePrefix, const char *InputFileName) const { +  // Construct opt command. +  ArgStringList OptArgs; +  // The input to opt is the output from llvm-link. +  OptArgs.push_back(InputFileName); +  // Pass optimization arg to opt. +  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { +    StringRef OOpt = "3"; +    if (A->getOption().matches(options::OPT_O4) || +        A->getOption().matches(options::OPT_Ofast)) +      OOpt = "3"; +    else if (A->getOption().matches(options::OPT_O0)) +      OOpt = "0"; +    else if (A->getOption().matches(options::OPT_O)) { +      // -Os, -Oz, and -O(anything else) map to -O2 +      OOpt = llvm::StringSwitch<const char *>(A->getValue()) +                 .Case("1", "1") +                 .Case("2", "2") +                 .Case("3", "3") +                 .Case("s", "2") +                 .Case("z", "2") +                 .Default("2"); +    } +    OptArgs.push_back(Args.MakeArgString("-O" + OOpt)); +  } +  OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); +  OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); + +  for (const Arg *A : Args.filtered(options::OPT_mllvm)) { +    OptArgs.push_back(A->getValue(0)); +  } + +  OptArgs.push_back("-o"); +  auto OutputFileName = +      getOutputFileName(C, OutputFilePrefix, "-optimized", "bc"); +  OptArgs.push_back(OutputFileName); +  SmallString<128> OptPath(C.getDriver().Dir); +  llvm::sys::path::append(OptPath, "opt"); +  const char *OptExec = Args.MakeArgString(OptPath); +  C.addCommand(std::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs)); +  return OutputFileName; +} + +const char *AMDGCN::Linker::constructLlcCommand( +    Compilation &C, const JobAction &JA, const InputInfoList &Inputs, +    const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, +    llvm::StringRef OutputFilePrefix, const char *InputFileName, +    bool OutputIsAsm) const { +  // Construct llc command. +  ArgStringList LlcArgs{ +      InputFileName, "-mtriple=amdgcn-amd-amdhsa", +      Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")), +      Args.MakeArgString("-mcpu=" + SubArchName)}; + +  // Extract all the -m options +  std::vector<llvm::StringRef> Features; +  handleTargetFeaturesGroup( +    Args, Features, options::OPT_m_amdgpu_Features_Group); + +  // Add features to mattr such as xnack +  std::string MAttrString = "-mattr="; +  for(auto OneFeature : Features) { +    MAttrString.append(Args.MakeArgString(OneFeature)); +    if (OneFeature != Features.back()) +      MAttrString.append(","); +  } +  if(!Features.empty()) +    LlcArgs.push_back(Args.MakeArgString(MAttrString)); + +  for (const Arg *A : Args.filtered(options::OPT_mllvm)) { +    LlcArgs.push_back(A->getValue(0)); +  } + +  // Add output filename +  LlcArgs.push_back("-o"); +  auto LlcOutputFile = +      getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o"); +  LlcArgs.push_back(LlcOutputFile); +  SmallString<128> LlcPath(C.getDriver().Dir); +  llvm::sys::path::append(LlcPath, "llc"); +  const char *Llc = Args.MakeArgString(LlcPath); +  C.addCommand(std::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs)); +  return LlcOutputFile; +} + +void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, +                                          const InputInfoList &Inputs, +                                          const InputInfo &Output, +                                          const llvm::opt::ArgList &Args, +                                          const char *InputFileName) const { +  // Construct lld command. +  // The output from ld.lld is an HSA code object file. +  ArgStringList LldArgs{ +      "-flavor", "gnu", "-shared", "-o", Output.getFilename(), InputFileName}; +  SmallString<128> LldPath(C.getDriver().Dir); +  llvm::sys::path::append(LldPath, "lld"); +  const char *Lld = Args.MakeArgString(LldPath); +  C.addCommand(std::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs)); +} + +// Construct a clang-offload-bundler command to bundle code objects for +// different GPU's into a HIP fat binary. +void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, +                  StringRef OutputFileName, const InputInfoList &Inputs, +                  const llvm::opt::ArgList &Args, const Tool& T) { +  // Construct clang-offload-bundler command to bundle object files for +  // for different GPU archs. +  ArgStringList BundlerArgs; +  BundlerArgs.push_back(Args.MakeArgString("-type=o")); + +  // ToDo: Remove the dummy host binary entry which is required by +  // clang-offload-bundler. +  std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux"; +  std::string BundlerInputArg = "-inputs=" NULL_FILE; + +  for (const auto &II : Inputs) { +    const auto* A = II.getAction(); +    BundlerTargetArg = BundlerTargetArg + ",hip-amdgcn-amd-amdhsa-" + +                       StringRef(A->getOffloadingArch()).str(); +    BundlerInputArg = BundlerInputArg + "," + II.getFilename(); +  } +  BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); +  BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); + +  auto BundlerOutputArg = +      Args.MakeArgString(std::string("-outputs=").append(OutputFileName)); +  BundlerArgs.push_back(BundlerOutputArg); + +  SmallString<128> BundlerPath(C.getDriver().Dir); +  llvm::sys::path::append(BundlerPath, "clang-offload-bundler"); +  const char *Bundler = Args.MakeArgString(BundlerPath); +  C.addCommand(std::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs)); +} + +// For amdgcn the inputs of the linker job are device bitcode and output is +// object file. It calls llvm-link, opt, llc, then lld steps. +void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                   const InputInfo &Output, +                                   const InputInfoList &Inputs, +                                   const ArgList &Args, +                                   const char *LinkingOutput) const { + +  if (JA.getType() == types::TY_HIP_FATBIN) +    return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this); + +  assert(getToolChain().getTriple().getArch() == llvm::Triple::amdgcn && +         "Unsupported target"); + +  std::string SubArchName = JA.getOffloadingArch(); +  assert(StringRef(SubArchName).startswith("gfx") && "Unsupported sub arch"); + +  // Prefix for temporary file name. +  std::string Prefix = llvm::sys::path::stem(Inputs[0].getFilename()).str(); +  if (!C.getDriver().isSaveTempsEnabled()) +    Prefix += "-" + SubArchName; + +  // Each command outputs different files. +  const char *LLVMLinkCommand = +      constructLLVMLinkCommand(C, JA, Inputs, Args, SubArchName, Prefix); +  const char *OptCommand = constructOptCommand(C, JA, Inputs, Args, SubArchName, +                                               Prefix, LLVMLinkCommand); +  if (C.getDriver().isSaveTempsEnabled()) +    constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand, +                        /*OutputIsAsm=*/true); +  const char *LlcCommand = +      constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand); +  constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand); +} + +HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, +                             const ToolChain &HostTC, const ArgList &Args) +    : ToolChain(D, Triple, Args), HostTC(HostTC) { +  // Lookup binaries into the driver directory, this is used to +  // discover the clang-offload-bundler executable. +  getProgramPaths().push_back(getDriver().Dir); +} + +void HIPToolChain::addClangTargetOptions( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args, +    Action::OffloadKind DeviceOffloadingKind) const { +  HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); + +  StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); +  assert(!GpuArch.empty() && "Must have an explicit GPU arch."); +  (void) GpuArch; +  assert(DeviceOffloadingKind == Action::OFK_HIP && +         "Only HIP offloading kinds are supported for GPUs."); + +  CC1Args.push_back("-target-cpu"); +  CC1Args.push_back(DriverArgs.MakeArgStringRef(GpuArch)); +  CC1Args.push_back("-fcuda-is-device"); + +  if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, +                         options::OPT_fno_cuda_flush_denormals_to_zero, false)) +    CC1Args.push_back("-fcuda-flush-denormals-to-zero"); + +  if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, +                         options::OPT_fno_cuda_approx_transcendentals, false)) +    CC1Args.push_back("-fcuda-approx-transcendentals"); + +  if (DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, +                         false)) +    CC1Args.push_back("-fgpu-rdc"); + +  // Default to "hidden" visibility, as object level linking will not be +  // supported for the foreseeable future. +  if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, +                         options::OPT_fvisibility_ms_compat)) { +    CC1Args.append({"-fvisibility", "hidden"}); +    CC1Args.push_back("-fapply-global-visibility-to-externs"); +  } + +  if (DriverArgs.hasArg(options::OPT_nogpulib)) +    return; +  ArgStringList LibraryPaths; + +  // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. +  for (auto Path : +       DriverArgs.getAllArgValues(options::OPT_hip_device_lib_path_EQ)) +    LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); + +  addDirectoryList(DriverArgs, LibraryPaths, "-L", "HIP_DEVICE_LIB_PATH"); + +  llvm::SmallVector<std::string, 10> BCLibs; + +  // Add bitcode library in --hip-device-lib. +  for (auto Lib : DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ)) { +    BCLibs.push_back(DriverArgs.MakeArgString(Lib)); +  } + +  // If --hip-device-lib is not set, add the default bitcode libraries. +  if (BCLibs.empty()) { +    // Get the bc lib file name for ISA version. For example, +    // gfx803 => oclc_isa_version_803.amdgcn.bc. +    std::string GFXVersion = GpuArch.drop_front(3).str(); +    std::string ISAVerBC = "oclc_isa_version_" + GFXVersion + ".amdgcn.bc"; + +    llvm::StringRef FlushDenormalControlBC; +    if (DriverArgs.hasArg(options::OPT_fcuda_flush_denormals_to_zero)) +      FlushDenormalControlBC = "oclc_daz_opt_on.amdgcn.bc"; +    else +      FlushDenormalControlBC = "oclc_daz_opt_off.amdgcn.bc"; + +    llvm::StringRef WaveFrontSizeBC; +    if (stoi(GFXVersion) < 1000) +      WaveFrontSizeBC = "oclc_wavefrontsize64_on.amdgcn.bc"; +    else +      WaveFrontSizeBC = "oclc_wavefrontsize64_off.amdgcn.bc"; + +    BCLibs.append({"hip.amdgcn.bc", "opencl.amdgcn.bc", "ocml.amdgcn.bc", +                   "ockl.amdgcn.bc", "oclc_finite_only_off.amdgcn.bc", +                   FlushDenormalControlBC, +                   "oclc_correctly_rounded_sqrt_on.amdgcn.bc", +                   "oclc_unsafe_math_off.amdgcn.bc", ISAVerBC, +                   WaveFrontSizeBC}); +  } +  for (auto Lib : BCLibs) +    addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib); +} + +llvm::opt::DerivedArgList * +HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, +                             StringRef BoundArch, +                             Action::OffloadKind DeviceOffloadKind) const { +  DerivedArgList *DAL = +      HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); +  if (!DAL) +    DAL = new DerivedArgList(Args.getBaseArgs()); + +  const OptTable &Opts = getDriver().getOpts(); + +  for (Arg *A : Args) { +    if (A->getOption().matches(options::OPT_Xarch__)) { +      // Skip this argument unless the architecture matches BoundArch. +      if (BoundArch.empty() || A->getValue(0) != BoundArch) +        continue; + +      unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); +      unsigned Prev = Index; +      std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + +      // If the argument parsing failed or more than one argument was +      // consumed, the -Xarch_ argument's parameter tried to consume +      // extra arguments. Emit an error and ignore. +      // +      // We also want to disallow any options which would alter the +      // driver behavior; that isn't going to work in our model. We +      // use isDriverOption() as an approximation, although things +      // like -O4 are going to slip through. +      if (!XarchArg || Index > Prev + 1) { +        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) +            << A->getAsString(Args); +        continue; +      } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { +        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) +            << A->getAsString(Args); +        continue; +      } +      XarchArg->setBaseArg(A); +      A = XarchArg.release(); +      DAL->AddSynthesizedArg(A); +    } +    DAL->append(A); +  } + +  if (!BoundArch.empty()) { +    DAL->eraseArg(options::OPT_march_EQ); +    DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); +  } + +  return DAL; +} + +Tool *HIPToolChain::buildLinker() const { +  assert(getTriple().getArch() == llvm::Triple::amdgcn); +  return new tools::AMDGCN::Linker(*this); +} + +void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { +  HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +HIPToolChain::GetCXXStdlibType(const ArgList &Args) const { +  return HostTC.GetCXXStdlibType(Args); +} + +void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                              ArgStringList &CC1Args) const { +  HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, +                                                 ArgStringList &CC1Args) const { +  HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, +                                        ArgStringList &CC1Args) const { +  HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +SanitizerMask HIPToolChain::getSupportedSanitizers() const { +  // The HIPToolChain only supports sanitizers in the sense that it allows +  // sanitizer arguments on the command line if they are supported by the host +  // toolchain. The HIPToolChain will actually ignore any command line +  // arguments for any of these "supported" sanitizers. That means that no +  // sanitization of device code is actually supported at this time. +  // +  // This behavior is necessary because the host and device toolchains +  // invocations often share the command line, so the device toolchain must +  // tolerate flags meant only for the host toolchain. +  return HostTC.getSupportedSanitizers(); +} + +VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, +                                               const ArgList &Args) const { +  return HostTC.computeMSVCVersion(D, Args); +} diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h new file mode 100644 index 0000000000000..2d146ce5cc6fd --- /dev/null +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -0,0 +1,128 @@ +//===--- HIP.h - HIP ToolChain Implementations ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H + +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Tool.h" + +namespace clang { +namespace driver { + +namespace tools { + +namespace AMDGCN { +  // Construct command for creating HIP fatbin. +  void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, +                  StringRef OutputFileName, const InputInfoList &Inputs, +                  const llvm::opt::ArgList &TCArgs, const Tool& T); + +// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with +// device library, then compiles it to ISA in a shared object. +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) : Tool("AMDGCN::Linker", "amdgcn-link", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; + +private: +  /// \return llvm-link output file name. +  const char *constructLLVMLinkCommand(Compilation &C, const JobAction &JA, +                                       const InputInfoList &Inputs, +                                       const llvm::opt::ArgList &Args, +                                       llvm::StringRef SubArchName, +                                       llvm::StringRef OutputFilePrefix) const; + +  /// \return opt output file name. +  const char *constructOptCommand(Compilation &C, const JobAction &JA, +                                  const InputInfoList &Inputs, +                                  const llvm::opt::ArgList &Args, +                                  llvm::StringRef SubArchName, +                                  llvm::StringRef OutputFilePrefix, +                                  const char *InputFileName) const; + +  /// \return llc output file name. +  const char *constructLlcCommand(Compilation &C, const JobAction &JA, +                                  const InputInfoList &Inputs, +                                  const llvm::opt::ArgList &Args, +                                  llvm::StringRef SubArchName, +                                  llvm::StringRef OutputFilePrefix, +                                  const char *InputFileName, +                                  bool OutputIsAsm = false) const; + +  void constructLldCommand(Compilation &C, const JobAction &JA, +                           const InputInfoList &Inputs, const InputInfo &Output, +                           const llvm::opt::ArgList &Args, +                           const char *InputFileName) const; +}; + +} // end namespace AMDGCN +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HIPToolChain : public ToolChain { +public: +  HIPToolChain(const Driver &D, const llvm::Triple &Triple, +                const ToolChain &HostTC, const llvm::opt::ArgList &Args); + +  const llvm::Triple *getAuxTriple() const override { +    return &HostTC.getTriple(); +  } + +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; + +  bool useIntegratedAs() const override { return true; } +  bool isCrossCompiling() const override { return true; } +  bool isPICDefault() const override { return false; } +  bool isPIEDefault() const override { return false; } +  bool isPICDefaultForced() const override { return false; } +  bool SupportsProfiling() const override { return false; } +  bool IsMathErrnoDefault() const override { return false; } + +  void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; +  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &Args, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                           llvm::opt::ArgStringList &CC1Args) const override; + +  SanitizerMask getSupportedSanitizers() const override; + +  VersionTuple +  computeMSVCVersion(const Driver *D, +                     const llvm::opt::ArgList &Args) const override; + +  unsigned GetDefaultDwarfVersion() const override { return 2; } + +  const ToolChain &HostTC; + +protected: +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp new file mode 100644 index 0000000000000..18f550c9ceca1 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Haiku.cpp @@ -0,0 +1,34 @@ +//===--- Haiku.cpp - Haiku ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Haiku.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// Haiku - Haiku tool chain which can call as(1) and ld(1) directly. + +Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) +  : Generic_ELF(D, Triple, Args) { + +} + +void Haiku::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                  llvm::opt::ArgStringList &CC1Args) const { +  addSystemInclude(DriverArgs, CC1Args, +                   getDriver().SysRoot + "/system/develop/headers/c++/v1"); +} + +void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                     llvm::opt::ArgStringList &CC1Args) const { +  addLibStdCXXIncludePaths(getDriver().SysRoot, "/system/develop/headers/c++", +                           getTriple().str(), "", "", "", DriverArgs, CC1Args); +} diff --git a/clang/lib/Driver/ToolChains/Haiku.h b/clang/lib/Driver/ToolChains/Haiku.h new file mode 100644 index 0000000000000..2bc98322bebfb --- /dev/null +++ b/clang/lib/Driver/ToolChains/Haiku.h @@ -0,0 +1,41 @@ +//===--- Haiku.h - Haiku ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H + +#include "Gnu.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF { +public: +  Haiku(const Driver &D, const llvm::Triple &Triple, +          const llvm::opt::ArgList &Args); + +  bool isPIEDefault() const override { +    return getTriple().getArch() == llvm::Triple::x86_64; +  } + +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp new file mode 100644 index 0000000000000..96cc084e2821e --- /dev/null +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -0,0 +1,584 @@ +//===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Hexagon.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +// Default hvx-length for various versions. +static StringRef getDefaultHvxLength(StringRef Cpu) { +  return llvm::StringSwitch<StringRef>(Cpu) +      .Case("v60", "64b") +      .Case("v62", "64b") +      .Case("v65", "64b") +      .Case("v66", "128b") +      .Default("128b"); +} + +static void handleHVXWarnings(const Driver &D, const ArgList &Args) { +  // Handle the unsupported values passed to mhvx-length. +  if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { +    StringRef Val = A->getValue(); +    if (!Val.equals_lower("64b") && !Val.equals_lower("128b")) +      D.Diag(diag::err_drv_unsupported_option_argument) +          << A->getOption().getName() << Val; +  } +} + +// Handle hvx target features explicitly. +static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, +                                    std::vector<StringRef> &Features, +                                    bool &HasHVX) { +  // Handle HVX warnings. +  handleHVXWarnings(D, Args); + +  // Add the +hvx* features based on commandline flags. +  StringRef HVXFeature, HVXLength; +  StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args)); + +  // Handle -mhvx, -mhvx=, -mno-hvx. +  if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx, +                               options::OPT_mhexagon_hvx, +                               options::OPT_mhexagon_hvx_EQ)) { +    if (A->getOption().matches(options::OPT_mno_hexagon_hvx)) +      return; +    if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) { +      HasHVX = true; +      HVXFeature = Cpu = A->getValue(); +      HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower()); +    } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) { +      HasHVX = true; +      HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu); +    } +    Features.push_back(HVXFeature); +  } + +  // Handle -mhvx-length=. +  if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { +    // These flags are valid only if HVX in enabled. +    if (!HasHVX) +      D.Diag(diag::err_drv_invalid_hvx_length); +    else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ)) +      HVXLength = A->getValue(); +  } +  // Default hvx-length based on Cpu. +  else if (HasHVX) +    HVXLength = getDefaultHvxLength(Cpu); + +  if (!HVXLength.empty()) { +    HVXFeature = +        Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower()); +    Features.push_back(HVXFeature); +  } +} + +// Hexagon target features. +void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, +                                       std::vector<StringRef> &Features) { +  handleTargetFeaturesGroup(Args, Features, +                            options::OPT_m_hexagon_Features_Group); + +  bool UseLongCalls = false; +  if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, +                               options::OPT_mno_long_calls)) { +    if (A->getOption().matches(options::OPT_mlong_calls)) +      UseLongCalls = true; +  } + +  Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); + +  bool HasHVX = false; +  handleHVXTargetFeatures(D, Args, Features, HasHVX); + +  if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX) +    D.Diag(diag::warn_drv_vectorize_needs_hvx); +} + +// Hexagon tools start. +void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, +                                             ArgStringList &CmdArgs) const { +} + +void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                      const InputInfo &Output, +                                      const InputInfoList &Inputs, +                                      const ArgList &Args, +                                      const char *LinkingOutput) const { +  claimNoWarnArgs(Args); + +  auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); +  const Driver &D = HTC.getDriver(); +  ArgStringList CmdArgs; + +  CmdArgs.push_back("--arch=hexagon"); + +  RenderExtraToolArgs(JA, CmdArgs); + +  const char *AsName = "llvm-mc"; +  CmdArgs.push_back("-filetype=obj"); +  CmdArgs.push_back(Args.MakeArgString( +      "-mcpu=hexagon" + +      toolchains::HexagonToolChain::GetTargetCPUVersion(Args))); + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Unexpected output"); +    CmdArgs.push_back("-fsyntax-only"); +  } + +  if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { +    CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue()))); +  } + +  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 +  // wrong in is for linker inputs if they happened to have an odd +  // suffix; really the only way to get this to happen is a command +  // like '-x foobar a.c' which will treat a.c like a linker input. +  // +  // FIXME: For the linker case specifically, can we safely convert +  // inputs into '-Wl,' options? +  for (const auto &II : Inputs) { +    // Don't try to pass LLVM or AST inputs to a generic gcc. +    if (types::isLLVMIR(II.getType())) +      D.Diag(clang::diag::err_drv_no_linker_llvm_support) +          << HTC.getTripleString(); +    else if (II.getType() == types::TY_AST) +      D.Diag(clang::diag::err_drv_no_ast_support) +          << HTC.getTripleString(); +    else if (II.getType() == types::TY_ModuleFile) +      D.Diag(diag::err_drv_no_module_support) +          << HTC.getTripleString(); + +    if (II.isFilename()) +      CmdArgs.push_back(II.getFilename()); +    else +      // Don't render as input, we need gcc to do the translations. +      // FIXME: What is this? +      II.getInputArg().render(Args, CmdArgs); +  } + +  auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName)); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, +                                          ArgStringList &CmdArgs) const { +} + +static void +constructHexagonLinkArgs(Compilation &C, const JobAction &JA, +                         const toolchains::HexagonToolChain &HTC, +                         const InputInfo &Output, const InputInfoList &Inputs, +                         const ArgList &Args, ArgStringList &CmdArgs, +                         const char *LinkingOutput) { + +  const Driver &D = HTC.getDriver(); + +  //---------------------------------------------------------------------------- +  // +  //---------------------------------------------------------------------------- +  bool IsStatic = Args.hasArg(options::OPT_static); +  bool IsShared = Args.hasArg(options::OPT_shared); +  bool IsPIE = 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 UseG0 = false; +  bool UseShared = IsShared && !IsStatic; + +  //---------------------------------------------------------------------------- +  // Silence warnings for various options +  //---------------------------------------------------------------------------- +  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); + +  //---------------------------------------------------------------------------- +  // +  //---------------------------------------------------------------------------- +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("-s"); + +  if (Args.hasArg(options::OPT_r)) +    CmdArgs.push_back("-r"); + +  for (const auto &Opt : HTC.ExtraOpts) +    CmdArgs.push_back(Opt.c_str()); + +  CmdArgs.push_back("-march=hexagon"); +  StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); +  CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); + +  if (IsShared) { +    CmdArgs.push_back("-shared"); +    // The following should be the default, but doing as hexagon-gcc does. +    CmdArgs.push_back("-call_shared"); +  } + +  if (IsStatic) +    CmdArgs.push_back("-static"); + +  if (IsPIE && !IsShared) +    CmdArgs.push_back("-pie"); + +  if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { +    CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue()))); +    UseG0 = G.getValue() == 0; +  } + +  //---------------------------------------------------------------------------- +  // +  //---------------------------------------------------------------------------- +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  //---------------------------------------------------------------------------- +  // moslib +  //---------------------------------------------------------------------------- +  std::vector<std::string> OsLibs; +  bool HasStandalone = false; + +  for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { +    A->claim(); +    OsLibs.emplace_back(A->getValue()); +    HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); +  } +  if (OsLibs.empty()) { +    OsLibs.push_back("standalone"); +    HasStandalone = true; +  } + +  //---------------------------------------------------------------------------- +  // Start Files +  //---------------------------------------------------------------------------- +  const std::string MCpuSuffix = "/" + CpuVer.str(); +  const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; +  const std::string RootDir = +      HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; +  const std::string StartSubDir = +      "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); + +  auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, +                      const char *Name) -> std::string { +    std::string RelName = SubDir + Name; +    std::string P = HTC.GetFilePath(RelName.c_str()); +    if (llvm::sys::fs::exists(P)) +      return P; +    return RootDir + RelName; +  }; + +  if (IncStdLib && IncStartFiles) { +    if (!IsShared) { +      if (HasStandalone) { +        std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); +        CmdArgs.push_back(Args.MakeArgString(Crt0SA)); +      } +      std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); +      CmdArgs.push_back(Args.MakeArgString(Crt0)); +    } +    std::string Init = UseShared +          ? Find(RootDir, StartSubDir + "/pic", "/initS.o") +          : Find(RootDir, StartSubDir, "/init.o"); +    CmdArgs.push_back(Args.MakeArgString(Init)); +  } + +  //---------------------------------------------------------------------------- +  // Library Search Paths +  //---------------------------------------------------------------------------- +  const ToolChain::path_list &LibPaths = HTC.getFilePaths(); +  for (const auto &LibPath : LibPaths) +    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); + +  //---------------------------------------------------------------------------- +  // +  //---------------------------------------------------------------------------- +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_T_Group, options::OPT_e, options::OPT_s, +                   options::OPT_t, options::OPT_u_Group}); + +  AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); + +  //---------------------------------------------------------------------------- +  // Libraries +  //---------------------------------------------------------------------------- +  if (IncStdLib && IncDefLibs) { +    if (D.CCCIsCXX()) { +      if (HTC.ShouldLinkCXXStdlib(Args)) +        HTC.AddCXXStdlibLibArgs(Args, CmdArgs); +      CmdArgs.push_back("-lm"); +    } + +    CmdArgs.push_back("--start-group"); + +    if (!IsShared) { +      for (StringRef Lib : OsLibs) +        CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); +      CmdArgs.push_back("-lc"); +    } +    CmdArgs.push_back("-lgcc"); + +    CmdArgs.push_back("--end-group"); +  } + +  //---------------------------------------------------------------------------- +  // End files +  //---------------------------------------------------------------------------- +  if (IncStdLib && IncStartFiles) { +    std::string Fini = UseShared +          ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") +          : Find(RootDir, StartSubDir, "/fini.o"); +    CmdArgs.push_back(Args.MakeArgString(Fini)); +  } +} + +void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                   const InputInfo &Output, +                                   const InputInfoList &Inputs, +                                   const ArgList &Args, +                                   const char *LinkingOutput) const { +  auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); + +  ArgStringList CmdArgs; +  constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, +                           LinkingOutput); + +  const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} +// Hexagon tools end. + +/// Hexagon Toolchain + +std::string HexagonToolChain::getHexagonTargetDir( +      const std::string &InstalledDir, +      const SmallVectorImpl<std::string> &PrefixDirs) const { +  std::string InstallRelDir; +  const Driver &D = getDriver(); + +  // Locate the rest of the toolchain ... +  for (auto &I : PrefixDirs) +    if (D.getVFS().exists(I)) +      return I; + +  if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) +    return InstallRelDir; + +  return InstalledDir; +} + +Optional<unsigned> HexagonToolChain::getSmallDataThreshold( +      const ArgList &Args) { +  StringRef Gn = ""; +  if (Arg *A = Args.getLastArg(options::OPT_G)) { +    Gn = A->getValue(); +  } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, +                             options::OPT_fPIC)) { +    Gn = "0"; +  } + +  unsigned G; +  if (!Gn.getAsInteger(10, G)) +    return G; + +  return None; +} + +void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, +      ToolChain::path_list &LibPaths) const { +  const Driver &D = getDriver(); + +  //---------------------------------------------------------------------------- +  // -L Args +  //---------------------------------------------------------------------------- +  for (Arg *A : Args.filtered(options::OPT_L)) +    for (const char *Value : A->getValues()) +      LibPaths.push_back(Value); + +  //---------------------------------------------------------------------------- +  // Other standard paths +  //---------------------------------------------------------------------------- +  std::vector<std::string> RootDirs; +  std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), +            std::back_inserter(RootDirs)); + +  std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), +                                              D.PrefixDirs); +  if (llvm::find(RootDirs, TargetDir) == RootDirs.end()) +    RootDirs.push_back(TargetDir); + +  bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); +  // Assume G0 with -shared. +  bool HasG0 = Args.hasArg(options::OPT_shared); +  if (auto G = getSmallDataThreshold(Args)) +    HasG0 = G.getValue() == 0; + +  const std::string CpuVer = GetTargetCPUVersion(Args).str(); +  for (auto &Dir : RootDirs) { +    std::string LibDir = Dir + "/hexagon/lib"; +    std::string LibDirCpu = LibDir + '/' + CpuVer; +    if (HasG0) { +      if (HasPIC) +        LibPaths.push_back(LibDirCpu + "/G0/pic"); +      LibPaths.push_back(LibDirCpu + "/G0"); +    } +    LibPaths.push_back(LibDirCpu); +    LibPaths.push_back(LibDir); +  } +} + +HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, +                                   const llvm::opt::ArgList &Args) +    : Linux(D, Triple, Args) { +  const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), +                                                    D.PrefixDirs); + +  // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to +  // program paths +  const std::string BinDir(TargetDir + "/bin"); +  if (D.getVFS().exists(BinDir)) +    getProgramPaths().push_back(BinDir); + +  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, LibPaths); +} + +HexagonToolChain::~HexagonToolChain() {} + +Tool *HexagonToolChain::buildAssembler() const { +  return new tools::hexagon::Assembler(*this); +} + +Tool *HexagonToolChain::buildLinker() const { +  return new tools::hexagon::Linker(*this); +} + +unsigned HexagonToolChain::getOptimizationLevel( +    const llvm::opt::ArgList &DriverArgs) const { +  // Copied in large part from lib/Frontend/CompilerInvocation.cpp. +  Arg *A = DriverArgs.getLastArg(options::OPT_O_Group); +  if (!A) +    return 0; + +  if (A->getOption().matches(options::OPT_O0)) +    return 0; +  if (A->getOption().matches(options::OPT_Ofast) || +      A->getOption().matches(options::OPT_O4)) +    return 3; +  assert(A->getNumValues() != 0); +  StringRef S(A->getValue()); +  if (S == "s" || S == "z" || S.empty()) +    return 2; +  if (S == "g") +    return 1; + +  unsigned OptLevel; +  if (S.getAsInteger(10, OptLevel)) +    return 0; +  return OptLevel; +} + +void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, +                                             ArgStringList &CC1Args, +                                             Action::OffloadKind) const { +  if (DriverArgs.hasArg(options::OPT_ffixed_r19)) { +    CC1Args.push_back("-target-feature"); +    CC1Args.push_back("+reserved-r19"); +  } +  if (isAutoHVXEnabled(DriverArgs)) { +    CC1Args.push_back("-mllvm"); +    CC1Args.push_back("-hexagon-autohvx"); +  } +} + +void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                                 ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  const Driver &D = getDriver(); +  std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), +                                              D.PrefixDirs); +  addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); +} + + +void HexagonToolChain::addLibStdCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); +  std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); +  addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "", +                           DriverArgs, CC1Args); +} + +ToolChain::CXXStdlibType +HexagonToolChain::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 ToolChain::CST_Libstdcxx; +} + +bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) { +  if (Arg *A = Args.getLastArg(options::OPT_fvectorize, +                               options::OPT_fno_vectorize)) +    return A->getOption().matches(options::OPT_fvectorize); +  return false; +} + +// +// Returns the default CPU for Hexagon. This is the default compilation target +// if no Hexagon processor is selected at the command-line. +// +const StringRef HexagonToolChain::GetDefaultCPU() { +  return "hexagonv60"; +} + +const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { +  Arg *CpuArg = nullptr; +  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) +    CpuArg = A; + +  StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); +  if (CPU.startswith("hexagon")) +    return CPU.substr(sizeof("hexagon") - 1); +  return CPU; +} diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h new file mode 100644 index 0000000000000..d7b4a13d3a4f8 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Hexagon.h @@ -0,0 +1,111 @@ +//===--- Hexagon.h - Hexagon ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H + +#include "Linux.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace hexagon { +// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile +// and Compile. +// We simply use "clang -cc1" for those actions. +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("hexagon::Assembler", "hexagon-as", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void RenderExtraToolArgs(const JobAction &JA, +                           llvm::opt::ArgStringList &CmdArgs) const; +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("hexagon::Linker", "hexagon-ld", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  virtual void RenderExtraToolArgs(const JobAction &JA, +                                   llvm::opt::ArgStringList &CmdArgs) const; +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +                              std::vector<StringRef> &Features); + +} // end namespace hexagon. +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { +protected: +  GCCVersion GCCLibAndIncVersion; +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; + +  unsigned getOptimizationLevel(const llvm::opt::ArgList &DriverArgs) const; + +public: +  HexagonToolChain(const Driver &D, const llvm::Triple &Triple, +                   const llvm::opt::ArgList &Args); +  ~HexagonToolChain() override; + +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  const char *getDefaultLinker() const override { return "hexagon-link"; } + +  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + +  StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } +  bool IsIntegratedAssemblerDefault() const override { +    return true; +  } + +  std::string getHexagonTargetDir( +      const std::string &InstalledDir, +      const SmallVectorImpl<std::string> &PrefixDirs) const; +  void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, +      ToolChain::path_list &LibPaths) const; + +  static bool isAutoHVXEnabled(const llvm::opt::ArgList &Args); +  static const StringRef GetDefaultCPU(); +  static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); + +  static Optional<unsigned> getSmallDataThreshold( +      const llvm::opt::ArgList &Args); +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp new file mode 100644 index 0000000000000..92b0a7f2483f3 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -0,0 +1,168 @@ +//===--- Hurd.cpp - Hurd ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Hurd.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +/// Get our best guess at the multiarch triple for a target. +/// +/// Debian-based systems are starting to use a multiarch setup where they use +/// a target-triple directory in the library and header search paths. +/// Unfortunately, this triple does not align with the vanilla target triple, +/// so we provide a rough mapping here. +static std::string getMultiarchTriple(const Driver &D, +                                      const llvm::Triple &TargetTriple, +                                      StringRef SysRoot) { +  if (TargetTriple.getArch() == llvm::Triple::x86) { +    // We use the existence of '/lib/<triple>' as a directory to detect some +    // common hurd triples that don't quite match the Clang triple for both +    // 32-bit and 64-bit targets. Multiarch fixes its install triples to these +    // regardless of what the actual target triple is. +    if (D.getVFS().exists(SysRoot + "/lib/i386-gnu")) +      return "i386-gnu"; +  } + +  // For most architectures, just use whatever we have rather than trying to be +  // clever. +  return TargetTriple.str(); +} + +static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { +  // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and +  // using that variant while targeting other architectures causes problems +  // because the libraries are laid out in shared system roots that can't cope +  // with a 'lib32' library search path being considered. So we only enable +  // them when we know we may need it. +  // +  // FIXME: This is a bit of a hack. We should really unify this code for +  // reasoning about oslibdir spellings with the lib dir spellings in the +  // GCCInstallationDetector, but that is a more significant refactoring. + +  if (Triple.getArch() == llvm::Triple::x86) +    return "lib32"; + +  return Triple.isArch32Bit() ? "lib" : "lib64"; +} + +Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, +           const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  std::string SysRoot = computeSysRoot(); +  path_list &Paths = getFilePaths(); + +  const std::string OSLibDir = getOSLibDir(Triple, Args); +  const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + +  // If we are currently running Clang inside of the requested system root, add +  // its parent library paths to those searched. +  // FIXME: It's not clear whether we should use the driver's installed +  // directory ('Dir' below) or the ResourceDir. +  if (StringRef(D.Dir).startswith(SysRoot)) { +    addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); +    addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); +  } + +  addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); +  addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + +  addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); +  addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); + +  // If we are currently running Clang inside of the requested system root, add +  // its parent library path to those searched. +  // FIXME: It's not clear whether we should use the driver's installed +  // directory ('Dir' below) or the ResourceDir. +  if (StringRef(D.Dir).startswith(SysRoot)) +    addPathIfExists(D, D.Dir + "/../lib", Paths); + +  addPathIfExists(D, SysRoot + "/lib", Paths); +  addPathIfExists(D, SysRoot + "/usr/lib", Paths); +} + +bool Hurd::HasNativeLLVMSupport() const { return true; } + +Tool *Hurd::buildLinker() const { return new tools::gnutools::Linker(*this); } + +Tool *Hurd::buildAssembler() const { +  return new tools::gnutools::Assembler(*this); +} + +std::string Hurd::computeSysRoot() const { +  if (!getDriver().SysRoot.empty()) +    return getDriver().SysRoot; + +  return std::string(); +} + +std::string Hurd::getDynamicLinker(const ArgList &Args) const { +  if (getArch() == llvm::Triple::x86) +    return "/lib/ld.so"; + +  llvm_unreachable("unsupported architecture"); +} + +void Hurd::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                     ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); +  std::string SysRoot = computeSysRoot(); + +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) +    addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  // Check for configure-time C include directories. +  StringRef CIncludeDirs(C_INCLUDE_DIRS); +  if (CIncludeDirs != "") { +    SmallVector<StringRef, 5> Dirs; +    CIncludeDirs.split(Dirs, ":"); +    for (StringRef Dir : Dirs) { +      StringRef Prefix = +          llvm::sys::path::is_absolute(Dir) ? StringRef(SysRoot) : ""; +      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + Dir); +    } +    return; +  } + +  // Lacking those, try to detect the correct set of system includes for the +  // target triple. +  if (getTriple().getArch() == llvm::Triple::x86) { +    std::string Path = SysRoot + "/usr/include/i386-gnu"; +    if (D.getVFS().exists(Path)) +      addExternCSystemInclude(DriverArgs, CC1Args, Path); +  } + +  // Add an include of '/include' directly. This isn't provided by default by +  // system GCCs, but is often used with cross-compiling GCCs, and harmless to +  // add even when Clang is acting as-if it were a system compiler. +  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + +  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} diff --git a/clang/lib/Driver/ToolChains/Hurd.h b/clang/lib/Driver/ToolChains/Hurd.h new file mode 100644 index 0000000000000..a2c3d074e9f95 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Hurd.h @@ -0,0 +1,45 @@ +//===--- Hurd.h - Hurd ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Hurd_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Hurd_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Hurd : public Generic_ELF { +public: +  Hurd(const Driver &D, const llvm::Triple &Triple, +       const llvm::opt::ArgList &Args); + +  bool HasNativeLLVMSupport() const override; + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; + +  virtual std::string computeSysRoot() const; + +  virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; + +  std::vector<std::string> ExtraOpts; + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Hurd_H diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp new file mode 100644 index 0000000000000..6677843b2c533 --- /dev/null +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -0,0 +1,37 @@ +//===---  InterfaceStubs.cpp - Base InterfaceStubs Implementations C++  ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InterfaceStubs.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" + +namespace clang { +namespace driver { +namespace tools { +namespace ifstool { +void Merger::ConstructJob(Compilation &C, const JobAction &JA, +                          const InputInfo &Output, const InputInfoList &Inputs, +                          const llvm::opt::ArgList &Args, +                          const char *LinkingOutput) const { +  std::string Merger = getToolChain().GetProgramPath(getShortName()); +  llvm::opt::ArgStringList CmdArgs; +  CmdArgs.push_back("-action"); +  CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) +                        ? "write-ifs" +                        : "write-bin"); +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); +  for (const auto &Input : Inputs) +    CmdArgs.push_back(Input.getFilename()); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger), +                                         CmdArgs, Inputs)); +} +} // namespace ifstool +} // namespace tools +} // namespace driver +} // namespace clang diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.h b/clang/lib/Driver/ToolChains/InterfaceStubs.h new file mode 100644 index 0000000000000..4afa73701a4c5 --- /dev/null +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.h @@ -0,0 +1,36 @@ +//===---  InterfaceStubs.cpp - Base InterfaceStubs Implementations C++  ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace ifstool { +class LLVM_LIBRARY_VISIBILITY Merger : public Tool { +public: +  Merger(const ToolChain &TC) : Tool("IFS::Merger", "llvm-ifs", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace ifstool +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H diff --git a/clang/lib/Driver/ToolChains/Lanai.h b/clang/lib/Driver/ToolChains/Lanai.h new file mode 100644 index 0000000000000..dc04b0cfe2ee1 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Lanai.h @@ -0,0 +1,40 @@ +//===--- Lanai.h - Lanai ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF { +public: +  LanaiToolChain(const Driver &D, const llvm::Triple &Triple, +                 const llvm::opt::ArgList &Args) +      : Generic_ELF(D, Triple, Args) {} + +  // No support for finding a C++ standard library yet. +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override {} +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override {} + +  bool IsIntegratedAssemblerDefault() const override { return true; } +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp new file mode 100644 index 0000000000000..087783875ffe2 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -0,0 +1,1046 @@ +//===--- Linux.h - Linux ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Linux.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "Arch/RISCV.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Distro.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +/// Get our best guess at the multiarch triple for a target. +/// +/// Debian-based systems are starting to use a multiarch setup where they use +/// a target-triple directory in the library and header search paths. +/// Unfortunately, this triple does not align with the vanilla target triple, +/// so we provide a rough mapping here. +static std::string getMultiarchTriple(const Driver &D, +                                      const llvm::Triple &TargetTriple, +                                      StringRef SysRoot) { +  llvm::Triple::EnvironmentType TargetEnvironment = +      TargetTriple.getEnvironment(); +  bool IsAndroid = TargetTriple.isAndroid(); +  bool IsMipsR6 = TargetTriple.getSubArch() == llvm::Triple::MipsSubArch_r6; +  bool IsMipsN32Abi = TargetTriple.getEnvironment() == llvm::Triple::GNUABIN32; + +  // For most architectures, just use whatever we have rather than trying to be +  // clever. +  switch (TargetTriple.getArch()) { +  default: +    break; + +  // We use the existence of '/lib/<triple>' as a directory to detect some +  // common linux triples that don't quite match the Clang triple for both +  // 32-bit and 64-bit targets. Multiarch fixes its install triples to these +  // regardless of what the actual target triple is. +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    if (IsAndroid) { +      return "arm-linux-androideabi"; +    } else if (TargetEnvironment == llvm::Triple::GNUEABIHF) { +      if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf")) +        return "arm-linux-gnueabihf"; +    } else { +      if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi")) +        return "arm-linux-gnueabi"; +    } +    break; +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: +    if (TargetEnvironment == llvm::Triple::GNUEABIHF) { +      if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf")) +        return "armeb-linux-gnueabihf"; +    } else { +      if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi")) +        return "armeb-linux-gnueabi"; +    } +    break; +  case llvm::Triple::x86: +    if (IsAndroid) +      return "i686-linux-android"; +    if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu")) +      return "i386-linux-gnu"; +    break; +  case llvm::Triple::x86_64: +    if (IsAndroid) +      return "x86_64-linux-android"; +    // We don't want this for x32, otherwise it will match x86_64 libs +    if (TargetEnvironment != llvm::Triple::GNUX32 && +        D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu")) +      return "x86_64-linux-gnu"; +    break; +  case llvm::Triple::aarch64: +    if (IsAndroid) +      return "aarch64-linux-android"; +    if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu")) +      return "aarch64-linux-gnu"; +    break; +  case llvm::Triple::aarch64_be: +    if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu")) +      return "aarch64_be-linux-gnu"; +    break; +  case llvm::Triple::mips: { +    std::string MT = IsMipsR6 ? "mipsisa32r6-linux-gnu" : "mips-linux-gnu"; +    if (D.getVFS().exists(SysRoot + "/lib/" + MT)) +      return MT; +    break; +  } +  case llvm::Triple::mipsel: { +    if (IsAndroid) +      return "mipsel-linux-android"; +    std::string MT = IsMipsR6 ? "mipsisa32r6el-linux-gnu" : "mipsel-linux-gnu"; +    if (D.getVFS().exists(SysRoot + "/lib/" + MT)) +      return MT; +    break; +  } +  case llvm::Triple::mips64: { +    std::string MT = std::string(IsMipsR6 ? "mipsisa64r6" : "mips64") + +                     "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64"); +    if (D.getVFS().exists(SysRoot + "/lib/" + MT)) +      return MT; +    if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) +      return "mips64-linux-gnu"; +    break; +  } +  case llvm::Triple::mips64el: { +    if (IsAndroid) +      return "mips64el-linux-android"; +    std::string MT = std::string(IsMipsR6 ? "mipsisa64r6el" : "mips64el") + +                     "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64"); +    if (D.getVFS().exists(SysRoot + "/lib/" + MT)) +      return MT; +    if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) +      return "mips64el-linux-gnu"; +    break; +  } +  case llvm::Triple::ppc: +    if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) +      return "powerpc-linux-gnuspe"; +    if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu")) +      return "powerpc-linux-gnu"; +    break; +  case llvm::Triple::ppc64: +    if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu")) +      return "powerpc64-linux-gnu"; +    break; +  case llvm::Triple::ppc64le: +    if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) +      return "powerpc64le-linux-gnu"; +    break; +  case llvm::Triple::sparc: +    if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) +      return "sparc-linux-gnu"; +    break; +  case llvm::Triple::sparcv9: +    if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu")) +      return "sparc64-linux-gnu"; +    break; +  case llvm::Triple::systemz: +    if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu")) +      return "s390x-linux-gnu"; +    break; +  } +  return TargetTriple.str(); +} + +static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { +  if (Triple.isMIPS()) { +    if (Triple.isAndroid()) { +      StringRef CPUName; +      StringRef ABIName; +      tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); +      if (CPUName == "mips32r6") +        return "libr6"; +      if (CPUName == "mips32r2") +        return "libr2"; +    } +    // lib32 directory has a special meaning on MIPS targets. +    // It contains N32 ABI binaries. Use this folder if produce +    // code for N32 ABI only. +    if (tools::mips::hasMipsAbiArg(Args, "n32")) +      return "lib32"; +    return Triple.isArch32Bit() ? "lib" : "lib64"; +  } + +  // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and +  // using that variant while targeting other architectures causes problems +  // because the libraries are laid out in shared system roots that can't cope +  // with a 'lib32' library search path being considered. So we only enable +  // them when we know we may need it. +  // +  // FIXME: This is a bit of a hack. We should really unify this code for +  // reasoning about oslibdir spellings with the lib dir spellings in the +  // GCCInstallationDetector, but that is a more significant refactoring. +  if (Triple.getArch() == llvm::Triple::x86 || +      Triple.getArch() == llvm::Triple::ppc) +    return "lib32"; + +  if (Triple.getArch() == llvm::Triple::x86_64 && +      Triple.getEnvironment() == llvm::Triple::GNUX32) +    return "libx32"; + +  if (Triple.getArch() == llvm::Triple::riscv32) +    return "lib32"; + +  return Triple.isArch32Bit() ? "lib" : "lib64"; +} + +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, +                                  const Multilib &Multilib, +                                  StringRef InstallPath, +                                  ToolChain::path_list &Paths) { +  if (const auto &PathsCallback = Multilibs.filePathsCallback()) +    for (const auto &Path : PathsCallback(Multilib)) +      addPathIfExists(D, InstallPath + Path, Paths); +} + +Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  GCCInstallation.init(Triple, Args); +  Multilibs = GCCInstallation.getMultilibs(); +  SelectedMultilib = GCCInstallation.getMultilib(); +  llvm::Triple::ArchType Arch = Triple.getArch(); +  std::string SysRoot = computeSysRoot(); + +  // Cross-compiling binutils and GCC installations (vanilla and openSUSE at +  // least) put various tools in a triple-prefixed directory off of the parent +  // of the GCC installation. We use the GCC triple here to ensure that we end +  // up with tools that support the same amount of cross compiling as the +  // detected GCC installation. For example, if we find a GCC installation +  // targeting x86_64, but it is a bi-arch GCC installation, it can also be +  // used to target i386. +  // FIXME: This seems unlikely to be Linux-specific. +  ToolChain::path_list &PPaths = getProgramPaths(); +  if (GCCInstallation.isValid()) { +    PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + +                           GCCInstallation.getTriple().str() + "/bin") +                         .str()); +  } + +  Distro Distro(D.getVFS()); + +  if (Distro.IsAlpineLinux() || Triple.isAndroid()) { +    ExtraOpts.push_back("-z"); +    ExtraOpts.push_back("now"); +  } + +  if (Distro.IsOpenSUSE() || Distro.IsUbuntu() || Distro.IsAlpineLinux() || +      Triple.isAndroid()) { +    ExtraOpts.push_back("-z"); +    ExtraOpts.push_back("relro"); +  } + +  // The lld default page size is too large for Aarch64, which produces much +  // larger .so files and images for arm64 device targets. Use 4KB page size +  // for Android arm64 targets instead. +  if (Triple.isAArch64() && Triple.isAndroid()) { +    ExtraOpts.push_back("-z"); +    ExtraOpts.push_back("max-page-size=4096"); +  } + +  if (GCCInstallation.getParentLibPath().find("opt/rh/devtoolset") != +      StringRef::npos) +    // With devtoolset on RHEL, we want to add a bin directory that is relative +    // to the detected gcc install, because if we are using devtoolset gcc then +    // we want to use other tools from devtoolset (e.g. ld) instead of the +    // standard system tools. +    PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + +                     "/../bin").str()); + +  if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) +    ExtraOpts.push_back("-X"); + +  const bool IsAndroid = Triple.isAndroid(); +  const bool IsMips = Triple.isMIPS(); +  const bool IsHexagon = Arch == llvm::Triple::hexagon; +  const bool IsRISCV = Triple.isRISCV(); + +  if (IsMips && !SysRoot.empty()) +    ExtraOpts.push_back("--sysroot=" + SysRoot); + +  // Do not use 'gnu' hash style for Mips targets because .gnu.hash +  // and the MIPS ABI require .dynsym to be sorted in different ways. +  // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS +  // ABI requires a mapping between the GOT and the symbol table. +  // Android loader does not support .gnu.hash until API 23. +  // Hexagon linker/loader does not support .gnu.hash +  if (!IsMips && !IsHexagon) { +    if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() || +        (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick) || +        (IsAndroid && !Triple.isAndroidVersionLT(23))) +      ExtraOpts.push_back("--hash-style=gnu"); + +    if (Distro.IsDebian() || Distro.IsOpenSUSE() || +        Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty || +        Distro == Distro::UbuntuKarmic || +        (IsAndroid && Triple.isAndroidVersionLT(23))) +      ExtraOpts.push_back("--hash-style=both"); +  } + +#ifdef ENABLE_LINKER_BUILD_ID +  ExtraOpts.push_back("--build-id"); +#endif + +  if (IsAndroid || Distro.IsOpenSUSE()) +    ExtraOpts.push_back("--enable-new-dtags"); + +  // The selection of paths to try here is designed to match the patterns which +  // the GCC driver itself uses, as this is part of the GCC-compatible driver. +  // This was determined by running GCC in a fake filesystem, creating all +  // possible permutations of these directories, and seeing which ones it added +  // to the link paths. +  path_list &Paths = getFilePaths(); + +  const std::string OSLibDir = getOSLibDir(Triple, Args); +  const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + +  // Add the multilib suffixed paths where they are available. +  if (GCCInstallation.isValid()) { +    const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); +    const std::string &LibPath = GCCInstallation.getParentLibPath(); + +    // Add toolchain / multilib specific file paths. +    addMultilibsFilePaths(D, Multilibs, SelectedMultilib, +                          GCCInstallation.getInstallPath(), Paths); + +    // Sourcery CodeBench MIPS toolchain holds some libraries under +    // a biarch-like suffix of the GCC installation. +    addPathIfExists( +        D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), +        Paths); + +    // GCC cross compiling toolchains will install target libraries which ship +    // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as +    // any part of the GCC installation in +    // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat +    // debatable, but is the reality today. We need to search this tree even +    // when we have a sysroot somewhere else. It is the responsibility of +    // whomever is doing the cross build targeting a sysroot using a GCC +    // installation that is *not* within the system root to ensure two things: +    // +    //  1) Any DSOs that are linked in from this tree or from the install path +    //     above must be present on the system root and found via an +    //     appropriate rpath. +    //  2) There must not be libraries installed into +    //     <prefix>/<triple>/<libdir> unless they should be preferred over +    //     those within the system root. +    // +    // Note that this matches the GCC behavior. See the below comment for where +    // Clang diverges from GCC's behavior. +    addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + +                           OSLibDir + SelectedMultilib.osSuffix(), +                    Paths); + +    // If the GCC installation we found is inside of the sysroot, we want to +    // prefer libraries installed in the parent prefix of the GCC installation. +    // It is important to *not* use these paths when the GCC installation is +    // outside of the system root as that can pick up unintended libraries. +    // This usually happens when there is an external cross compiler on the +    // host system, and a more minimal sysroot available that is the target of +    // the cross. Note that GCC does include some of these directories in some +    // configurations but this seems somewhere between questionable and simply +    // a bug. +    if (StringRef(LibPath).startswith(SysRoot)) { +      addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); +      addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); +    } +  } + +  // Similar to the logic for GCC above, if we currently running Clang inside +  // of the requested system root, add its parent library paths to +  // those searched. +  // FIXME: It's not clear whether we should use the driver's installed +  // directory ('Dir' below) or the ResourceDir. +  if (StringRef(D.Dir).startswith(SysRoot)) { +    addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); +    addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); +  } + +  addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); +  addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + +  if (IsAndroid) { +    // Android sysroots contain a library directory for each supported OS +    // version as well as some unversioned libraries in the usual multiarch +    // directory. +    unsigned Major; +    unsigned Minor; +    unsigned Micro; +    Triple.getEnvironmentVersion(Major, Minor, Micro); +    addPathIfExists(D, +                    SysRoot + "/usr/lib/" + MultiarchTriple + "/" + +                        llvm::to_string(Major), +                    Paths); +  } + +  addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); +  // 64-bit OpenEmbedded sysroots may not have a /usr/lib dir. So they cannot +  // find /usr/lib64 as it is referenced as /usr/lib/../lib64. So we handle +  // this here. +  if (Triple.getVendor() == llvm::Triple::OpenEmbedded && +      Triple.isArch64Bit()) +    addPathIfExists(D, SysRoot + "/usr/" + OSLibDir, Paths); +  else +    addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); +  if (IsRISCV) { +    StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple); +    addPathIfExists(D, SysRoot + "/" + OSLibDir + "/" + ABIName, Paths); +    addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths); +  } + +  // Try walking via the GCC triple path in case of biarch or multiarch GCC +  // installations with strange symlinks. +  if (GCCInstallation.isValid()) { +    addPathIfExists(D, +                    SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + +                        "/../../" + OSLibDir, +                    Paths); + +    // Add the 'other' biarch variant path +    Multilib BiarchSibling; +    if (GCCInstallation.getBiarchSibling(BiarchSibling)) { +      addPathIfExists(D, GCCInstallation.getInstallPath() + +                             BiarchSibling.gccSuffix(), +                      Paths); +    } + +    // See comments above on the multilib variant for details of why this is +    // included even from outside the sysroot. +    const std::string &LibPath = GCCInstallation.getParentLibPath(); +    const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); +    const Multilib &Multilib = GCCInstallation.getMultilib(); +    addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + +                           Multilib.osSuffix(), +                    Paths); + +    // See comments above on the multilib variant for details of why this is +    // only included from within the sysroot. +    if (StringRef(LibPath).startswith(SysRoot)) +      addPathIfExists(D, LibPath, Paths); +  } + +  // Similar to the logic for GCC above, if we are currently running Clang +  // inside of the requested system root, add its parent library path to those +  // searched. +  // FIXME: It's not clear whether we should use the driver's installed +  // directory ('Dir' below) or the ResourceDir. +  if (StringRef(D.Dir).startswith(SysRoot)) +    addPathIfExists(D, D.Dir + "/../lib", Paths); + +  addPathIfExists(D, SysRoot + "/lib", Paths); +  addPathIfExists(D, SysRoot + "/usr/lib", Paths); +} + +ToolChain::CXXStdlibType Linux::GetDefaultCXXStdlibType() const { +  if (getTriple().isAndroid()) +    return ToolChain::CST_Libcxx; +  return ToolChain::CST_Libstdcxx; +} + +bool Linux::HasNativeLLVMSupport() const { return true; } + +Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } + +Tool *Linux::buildAssembler() const { +  return new tools::gnutools::Assembler(*this); +} + +std::string Linux::computeSysRoot() const { +  if (!getDriver().SysRoot.empty()) +    return getDriver().SysRoot; + +  if (getTriple().isAndroid()) { +    // Android toolchains typically include a sysroot at ../sysroot relative to +    // the clang binary. +    const StringRef ClangDir = getDriver().getInstalledDir(); +    std::string AndroidSysRootPath = (ClangDir + "/../sysroot").str(); +    if (getVFS().exists(AndroidSysRootPath)) +      return AndroidSysRootPath; +  } + +  if (!GCCInstallation.isValid() || !getTriple().isMIPS()) +    return std::string(); + +  // Standalone MIPS toolchains use different names for sysroot folder +  // and put it into different places. Here we try to check some known +  // variants. + +  const StringRef InstallDir = GCCInstallation.getInstallPath(); +  const StringRef TripleStr = GCCInstallation.getTriple().str(); +  const Multilib &Multilib = GCCInstallation.getMultilib(); + +  std::string Path = +      (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix()) +          .str(); + +  if (getVFS().exists(Path)) +    return Path; + +  Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); + +  if (getVFS().exists(Path)) +    return Path; + +  return std::string(); +} + +std::string Linux::getDynamicLinker(const ArgList &Args) const { +  const llvm::Triple::ArchType Arch = getArch(); +  const llvm::Triple &Triple = getTriple(); + +  const Distro Distro(getDriver().getVFS()); + +  if (Triple.isAndroid()) +    return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; + +  if (Triple.isMusl()) { +    std::string ArchName; +    bool IsArm = false; + +    switch (Arch) { +    case llvm::Triple::arm: +    case llvm::Triple::thumb: +      ArchName = "arm"; +      IsArm = true; +      break; +    case llvm::Triple::armeb: +    case llvm::Triple::thumbeb: +      ArchName = "armeb"; +      IsArm = true; +      break; +    default: +      ArchName = Triple.getArchName().str(); +    } +    if (IsArm && +        (Triple.getEnvironment() == llvm::Triple::MuslEABIHF || +         tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) +      ArchName += "hf"; + +    return "/lib/ld-musl-" + ArchName + ".so.1"; +  } + +  std::string LibDir; +  std::string Loader; + +  switch (Arch) { +  default: +    llvm_unreachable("unsupported architecture"); + +  case llvm::Triple::aarch64: +    LibDir = "lib"; +    Loader = "ld-linux-aarch64.so.1"; +    break; +  case llvm::Triple::aarch64_be: +    LibDir = "lib"; +    Loader = "ld-linux-aarch64_be.so.1"; +    break; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: { +    const bool HF = +        Triple.getEnvironment() == llvm::Triple::GNUEABIHF || +        tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard; + +    LibDir = "lib"; +    Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3"; +    break; +  } +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: { +    bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple); + +    LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple); + +    if (tools::mips::isUCLibc(Args)) +      Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0"; +    else if (!Triple.hasEnvironment() && +             Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies) +      Loader = +          Triple.isLittleEndian() ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1"; +    else +      Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1"; + +    break; +  } +  case llvm::Triple::ppc: +    LibDir = "lib"; +    Loader = "ld.so.1"; +    break; +  case llvm::Triple::ppc64: +    LibDir = "lib64"; +    Loader = +        (tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1"; +    break; +  case llvm::Triple::ppc64le: +    LibDir = "lib64"; +    Loader = +        (tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2"; +    break; +  case llvm::Triple::riscv32: { +    StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple); +    LibDir = "lib"; +    Loader = ("ld-linux-riscv32-" + ABIName + ".so.1").str(); +    break; +  } +  case llvm::Triple::riscv64: { +    StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple); +    LibDir = "lib"; +    Loader = ("ld-linux-riscv64-" + ABIName + ".so.1").str(); +    break; +  } +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +    LibDir = "lib"; +    Loader = "ld-linux.so.2"; +    break; +  case llvm::Triple::sparcv9: +    LibDir = "lib64"; +    Loader = "ld-linux.so.2"; +    break; +  case llvm::Triple::systemz: +    LibDir = "lib"; +    Loader = "ld64.so.1"; +    break; +  case llvm::Triple::x86: +    LibDir = "lib"; +    Loader = "ld-linux.so.2"; +    break; +  case llvm::Triple::x86_64: { +    bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32; + +    LibDir = X32 ? "libx32" : "lib64"; +    Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2"; +    break; +  } +  } + +  if (Distro == Distro::Exherbo && +      (Triple.getVendor() == llvm::Triple::UnknownVendor || +       Triple.getVendor() == llvm::Triple::PC)) +    return "/usr/" + Triple.str() + "/lib/" + Loader; +  return "/" + LibDir + "/" + Loader; +} + +void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                      ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); +  std::string SysRoot = computeSysRoot(); + +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) +    addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + +  SmallString<128> ResourceDirInclude(D.ResourceDir); +  llvm::sys::path::append(ResourceDirInclude, "include"); +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && +      (!getTriple().isMusl() || DriverArgs.hasArg(options::OPT_nostdlibinc))) +    addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  // Check for configure-time C include directories. +  StringRef CIncludeDirs(C_INCLUDE_DIRS); +  if (CIncludeDirs != "") { +    SmallVector<StringRef, 5> dirs; +    CIncludeDirs.split(dirs, ":"); +    for (StringRef dir : dirs) { +      StringRef Prefix = +          llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; +      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); +    } +    return; +  } + +  // Lacking those, try to detect the correct set of system includes for the +  // target triple. + +  // Add include directories specific to the selected multilib set and multilib. +  if (GCCInstallation.isValid()) { +    const auto &Callback = Multilibs.includeDirsCallback(); +    if (Callback) { +      for (const auto &Path : Callback(GCCInstallation.getMultilib())) +        addExternCSystemIncludeIfExists( +            DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); +    } +  } + +  // Implement generic Debian multiarch support. +  const StringRef X86_64MultiarchIncludeDirs[] = { +      "/usr/include/x86_64-linux-gnu", + +      // FIXME: These are older forms of multiarch. It's not clear that they're +      // in use in any released version of Debian, so we should consider +      // removing them. +      "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"}; +  const StringRef X86MultiarchIncludeDirs[] = { +      "/usr/include/i386-linux-gnu", + +      // FIXME: These are older forms of multiarch. It's not clear that they're +      // in use in any released version of Debian, so we should consider +      // removing them. +      "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", +      "/usr/include/i486-linux-gnu"}; +  const StringRef AArch64MultiarchIncludeDirs[] = { +      "/usr/include/aarch64-linux-gnu"}; +  const StringRef ARMMultiarchIncludeDirs[] = { +      "/usr/include/arm-linux-gnueabi"}; +  const StringRef ARMHFMultiarchIncludeDirs[] = { +      "/usr/include/arm-linux-gnueabihf"}; +  const StringRef ARMEBMultiarchIncludeDirs[] = { +      "/usr/include/armeb-linux-gnueabi"}; +  const StringRef ARMEBHFMultiarchIncludeDirs[] = { +      "/usr/include/armeb-linux-gnueabihf"}; +  const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"}; +  const StringRef MIPSELMultiarchIncludeDirs[] = { +      "/usr/include/mipsel-linux-gnu"}; +  const StringRef MIPS64MultiarchIncludeDirs[] = { +      "/usr/include/mips64-linux-gnuabi64"}; +  const StringRef MIPS64ELMultiarchIncludeDirs[] = { +      "/usr/include/mips64el-linux-gnuabi64"}; +  const StringRef MIPSN32MultiarchIncludeDirs[] = { +      "/usr/include/mips64-linux-gnuabin32"}; +  const StringRef MIPSN32ELMultiarchIncludeDirs[] = { +      "/usr/include/mips64el-linux-gnuabin32"}; +  const StringRef MIPSR6MultiarchIncludeDirs[] = { +      "/usr/include/mipsisa32-linux-gnu"}; +  const StringRef MIPSR6ELMultiarchIncludeDirs[] = { +      "/usr/include/mipsisa32r6el-linux-gnu"}; +  const StringRef MIPS64R6MultiarchIncludeDirs[] = { +      "/usr/include/mipsisa64r6-linux-gnuabi64"}; +  const StringRef MIPS64R6ELMultiarchIncludeDirs[] = { +      "/usr/include/mipsisa64r6el-linux-gnuabi64"}; +  const StringRef MIPSN32R6MultiarchIncludeDirs[] = { +      "/usr/include/mipsisa64r6-linux-gnuabin32"}; +  const StringRef MIPSN32R6ELMultiarchIncludeDirs[] = { +      "/usr/include/mipsisa64r6el-linux-gnuabin32"}; +  const StringRef PPCMultiarchIncludeDirs[] = { +      "/usr/include/powerpc-linux-gnu", +      "/usr/include/powerpc-linux-gnuspe"}; +  const StringRef PPC64MultiarchIncludeDirs[] = { +      "/usr/include/powerpc64-linux-gnu"}; +  const StringRef PPC64LEMultiarchIncludeDirs[] = { +      "/usr/include/powerpc64le-linux-gnu"}; +  const StringRef SparcMultiarchIncludeDirs[] = { +      "/usr/include/sparc-linux-gnu"}; +  const StringRef Sparc64MultiarchIncludeDirs[] = { +      "/usr/include/sparc64-linux-gnu"}; +  const StringRef SYSTEMZMultiarchIncludeDirs[] = { +      "/usr/include/s390x-linux-gnu"}; +  ArrayRef<StringRef> MultiarchIncludeDirs; +  switch (getTriple().getArch()) { +  case llvm::Triple::x86_64: +    MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; +    break; +  case llvm::Triple::x86: +    MultiarchIncludeDirs = X86MultiarchIncludeDirs; +    break; +  case llvm::Triple::aarch64: +  case llvm::Triple::aarch64_be: +    MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; +    break; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) +      MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; +    else +      MultiarchIncludeDirs = ARMMultiarchIncludeDirs; +    break; +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: +    if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) +      MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs; +    else +      MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs; +    break; +  case llvm::Triple::mips: +    if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6) +      MultiarchIncludeDirs = MIPSR6MultiarchIncludeDirs; +    else +      MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; +    break; +  case llvm::Triple::mipsel: +    if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6) +      MultiarchIncludeDirs = MIPSR6ELMultiarchIncludeDirs; +    else +      MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; +    break; +  case llvm::Triple::mips64: +    if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6) +      if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32) +        MultiarchIncludeDirs = MIPSN32R6MultiarchIncludeDirs; +      else +        MultiarchIncludeDirs = MIPS64R6MultiarchIncludeDirs; +    else if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32) +      MultiarchIncludeDirs = MIPSN32MultiarchIncludeDirs; +    else +      MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs; +    break; +  case llvm::Triple::mips64el: +    if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6) +      if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32) +        MultiarchIncludeDirs = MIPSN32R6ELMultiarchIncludeDirs; +      else +        MultiarchIncludeDirs = MIPS64R6ELMultiarchIncludeDirs; +    else if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32) +      MultiarchIncludeDirs = MIPSN32ELMultiarchIncludeDirs; +    else +      MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs; +    break; +  case llvm::Triple::ppc: +    MultiarchIncludeDirs = PPCMultiarchIncludeDirs; +    break; +  case llvm::Triple::ppc64: +    MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; +    break; +  case llvm::Triple::ppc64le: +    MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; +    break; +  case llvm::Triple::sparc: +    MultiarchIncludeDirs = SparcMultiarchIncludeDirs; +    break; +  case llvm::Triple::sparcv9: +    MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs; +    break; +  case llvm::Triple::systemz: +    MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs; +    break; +  default: +    break; +  } + +  const std::string AndroidMultiarchIncludeDir = +      std::string("/usr/include/") + +      getMultiarchTriple(D, getTriple(), SysRoot); +  const StringRef AndroidMultiarchIncludeDirs[] = {AndroidMultiarchIncludeDir}; +  if (getTriple().isAndroid()) +    MultiarchIncludeDirs = AndroidMultiarchIncludeDirs; + +  for (StringRef Dir : MultiarchIncludeDirs) { +    if (D.getVFS().exists(SysRoot + Dir)) { +      addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); +      break; +    } +  } + +  if (getTriple().getOS() == llvm::Triple::RTEMS) +    return; + +  // Add an include of '/include' directly. This isn't provided by default by +  // system GCCs, but is often used with cross-compiling GCCs, and harmless to +  // add even when Clang is acting as-if it were a system compiler. +  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + +  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl()) +    addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); +} + +static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, +                                           StringRef base) { +  std::error_code EC; +  int MaxVersion = 0; +  std::string MaxVersionString = ""; +  for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; +       !EC && LI != LE; LI = LI.increment(EC)) { +    StringRef VersionText = llvm::sys::path::filename(LI->path()); +    int Version; +    if (VersionText[0] == 'v' && +        !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { +      if (Version > MaxVersion) { +        MaxVersion = Version; +        MaxVersionString = VersionText; +      } +    } +  } +  return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; +} + +void Linux::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                  llvm::opt::ArgStringList &CC1Args) const { +  const std::string& SysRoot = computeSysRoot(); +  const std::string LibCXXIncludePathCandidates[] = { +      DetectLibcxxIncludePath(getVFS(), getDriver().Dir + "/../include/c++"), +      // If this is a development, non-installed, clang, libcxx will +      // not be found at ../include/c++ but it likely to be found at +      // one of the following two locations: +      DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/local/include/c++"), +      DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/include/c++") }; +  for (const auto &IncludePath : LibCXXIncludePathCandidates) { +    if (IncludePath.empty() || !getVFS().exists(IncludePath)) +      continue; +    // Use the first candidate that exists. +    addSystemInclude(DriverArgs, CC1Args, IncludePath); +    return; +  } +} + +void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                     llvm::opt::ArgStringList &CC1Args) const { +  // We need a detected GCC installation on Linux to provide libstdc++'s +  // headers. +  if (!GCCInstallation.isValid()) +    return; + +  // By default, look for the C++ headers in an include directory adjacent to +  // the lib directory of the GCC installation. Note that this is expect to be +  // equivalent to '/usr/include/c++/X.Y' in almost all cases. +  StringRef LibDir = GCCInstallation.getParentLibPath(); +  StringRef InstallDir = GCCInstallation.getInstallPath(); +  StringRef TripleStr = GCCInstallation.getTriple().str(); +  const Multilib &Multilib = GCCInstallation.getMultilib(); +  const std::string GCCMultiarchTriple = getMultiarchTriple( +      getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); +  const std::string TargetMultiarchTriple = +      getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); +  const GCCVersion &Version = GCCInstallation.getVersion(); + +  // The primary search for libstdc++ supports multiarch variants. +  if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", +                               "/c++/" + Version.Text, TripleStr, +                               GCCMultiarchTriple, TargetMultiarchTriple, +                               Multilib.includeSuffix(), DriverArgs, CC1Args)) +    return; + +  // Otherwise, fall back on a bunch of options which don't use multiarch +  // layouts for simplicity. +  const std::string LibStdCXXIncludePathCandidates[] = { +      // Gentoo is weird and places its headers inside the GCC install, +      // so if the first attempt to find the headers fails, try these patterns. +      InstallDir.str() + "/include/g++-v" + Version.Text, +      InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + +          Version.MinorStr, +      InstallDir.str() + "/include/g++-v" + Version.MajorStr, +      // Android standalone toolchain has C++ headers in yet another place. +      LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, +      // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, +      // without a subdirectory corresponding to the gcc version. +      LibDir.str() + "/../include/c++", +      // Cray's gcc installation puts headers under "g++" without a +      // version suffix. +      LibDir.str() + "/../include/g++", +  }; + +  for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { +    if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, +                                 /*GCCMultiarchTriple*/ "", +                                 /*TargetMultiarchTriple*/ "", +                                 Multilib.includeSuffix(), DriverArgs, CC1Args)) +      break; +  } +} + +void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, +                               ArgStringList &CC1Args) const { +  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, +                                ArgStringList &CC1Args) const { +  if (GCCInstallation.isValid()) { +    CC1Args.push_back("-isystem"); +    CC1Args.push_back(DriverArgs.MakeArgString( +        GCCInstallation.getParentLibPath() + "/../" + +        GCCInstallation.getTriple().str() + "/include")); +  } +} + +bool Linux::isPIEDefault() const { +  return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) || +          getTriple().isMusl() || getSanitizerArgs().requiresPIE(); +} + +bool Linux::isNoExecStackDefault() const { +    return getTriple().isAndroid(); +} + +bool Linux::IsMathErrnoDefault() const { +  if (getTriple().isAndroid()) +    return false; +  return Generic_ELF::IsMathErrnoDefault(); +} + +SanitizerMask Linux::getSupportedSanitizers() const { +  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; +  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; +  const bool IsMIPS = getTriple().isMIPS32(); +  const bool IsMIPS64 = getTriple().isMIPS64(); +  const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 || +                           getTriple().getArch() == llvm::Triple::ppc64le; +  const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || +                         getTriple().getArch() == llvm::Triple::aarch64_be; +  const bool IsArmArch = getTriple().getArch() == llvm::Triple::arm || +                         getTriple().getArch() == llvm::Triple::thumb || +                         getTriple().getArch() == llvm::Triple::armeb || +                         getTriple().getArch() == llvm::Triple::thumbeb; +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Fuzzer; +  Res |= SanitizerKind::FuzzerNoLink; +  Res |= SanitizerKind::KernelAddress; +  Res |= SanitizerKind::Memory; +  Res |= SanitizerKind::Vptr; +  Res |= SanitizerKind::SafeStack; +  if (IsX86_64 || IsMIPS64 || IsAArch64) +    Res |= SanitizerKind::DataFlow; +  if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64) +    Res |= SanitizerKind::Leak; +  if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) +    Res |= SanitizerKind::Thread; +  if (IsX86_64) +    Res |= SanitizerKind::KernelMemory; +  if (IsX86 || IsX86_64) +    Res |= SanitizerKind::Function; +  if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || +      IsPowerPC64) +    Res |= SanitizerKind::Scudo; +  if (IsX86_64 || IsAArch64) { +    Res |= SanitizerKind::HWAddress; +    Res |= SanitizerKind::KernelHWAddress; +  } +  return Res; +} + +void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, +                             llvm::opt::ArgStringList &CmdArgs) const { +  if (!needsProfileRT(Args)) return; + +  // Add linker option -u__llvm_runtime_variable to cause runtime +  // initialization module to be linked in. +  if ((!Args.hasArg(options::OPT_coverage)) && +      (!Args.hasArg(options::OPT_ftest_coverage))) +    CmdArgs.push_back(Args.MakeArgString( +        Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); +  ToolChain::addProfileRTLibs(Args, CmdArgs); +} diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h new file mode 100644 index 0000000000000..4c61994691c73 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -0,0 +1,61 @@ +//===--- Linux.h - Linux ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { +public: +  Linux(const Driver &D, const llvm::Triple &Triple, +        const llvm::opt::ArgList &Args); + +  bool HasNativeLLVMSupport() const override; + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const override; +  void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                           llvm::opt::ArgStringList &CC1Args) const override; +  CXXStdlibType GetDefaultCXXStdlibType() const override; +  bool isPIEDefault() const override; +  bool isNoExecStackDefault() const override; +  bool IsMathErrnoDefault() const override; +  SanitizerMask getSupportedSanitizers() const override; +  void addProfileRTLibs(const llvm::opt::ArgList &Args, +                        llvm::opt::ArgStringList &CmdArgs) const override; +  virtual std::string computeSysRoot() const; + +  virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; + +  std::vector<std::string> ExtraOpts; + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp new file mode 100644 index 0000000000000..bc77f015915dc --- /dev/null +++ b/clang/lib/Driver/ToolChains/MSP430.cpp @@ -0,0 +1,232 @@ +//===--- MSP430.cpp - MSP430 Helpers for Tools ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "CommonArgs.h" +#include "Gnu.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Multilib.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +static bool isSupportedMCU(const StringRef MCU) { +  return llvm::StringSwitch<bool>(MCU) +#define MSP430_MCU(NAME) .Case(NAME, true) +#include "clang/Basic/MSP430Target.def" +      .Default(false); +} + +static StringRef getSupportedHWMult(const Arg *MCU) { +  if (!MCU) +    return "none"; + +  return llvm::StringSwitch<StringRef>(MCU->getValue()) +#define MSP430_MCU_FEAT(NAME, HWMULT) .Case(NAME, HWMULT) +#include "clang/Basic/MSP430Target.def" +      .Default("none"); +} + +static StringRef getHWMultLib(const ArgList &Args) { +  StringRef HWMult = Args.getLastArgValue(options::OPT_mhwmult_EQ, "auto"); +  if (HWMult == "auto") { +    HWMult = getSupportedHWMult(Args.getLastArg(options::OPT_mmcu_EQ)); +  } + +  return llvm::StringSwitch<StringRef>(HWMult) +      .Case("16bit", "-lmul_16") +      .Case("32bit", "-lmul_32") +      .Case("f5series", "-lmul_f5") +      .Default("-lmul_none"); +} + +void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args, +                                     std::vector<StringRef> &Features) { +  const Arg *MCU = Args.getLastArg(options::OPT_mmcu_EQ); +  if (MCU && !isSupportedMCU(MCU->getValue())) { +    D.Diag(diag::err_drv_clang_unsupported) << MCU->getValue(); +    return; +  } + +  const Arg *HWMultArg = Args.getLastArg(options::OPT_mhwmult_EQ); +  if (!MCU && !HWMultArg) +    return; + +  StringRef HWMult = HWMultArg ? HWMultArg->getValue() : "auto"; +  StringRef SupportedHWMult = getSupportedHWMult(MCU); + +  if (HWMult == "auto") { +    // 'auto' - deduce hw multiplier support based on mcu name provided. +    // If no mcu name is provided, assume no hw multiplier is supported. +    if (!MCU) +      D.Diag(clang::diag::warn_drv_msp430_hwmult_no_device); +    HWMult = SupportedHWMult; +  } + +  if (HWMult == "none") { +    // 'none' - disable hw multiplier. +    Features.push_back("-hwmult16"); +    Features.push_back("-hwmult32"); +    Features.push_back("-hwmultf5"); +    return; +  } + +  if (MCU && SupportedHWMult == "none") +    D.Diag(clang::diag::warn_drv_msp430_hwmult_unsupported) << HWMult; +  if (MCU && HWMult != SupportedHWMult) +    D.Diag(clang::diag::warn_drv_msp430_hwmult_mismatch) +        << SupportedHWMult << HWMult; + +  if (HWMult == "16bit") { +    // '16bit' - for 16-bit only hw multiplier. +    Features.push_back("+hwmult16"); +  } else if (HWMult == "32bit") { +    // '32bit' - for 16/32-bit hw multiplier. +    Features.push_back("+hwmult32"); +  } else if (HWMult == "f5series") { +    // 'f5series' - for 16/32-bit hw multiplier supported by F5 series mcus. +    Features.push_back("+hwmultf5"); +  } else { +    D.Diag(clang::diag::err_drv_unsupported_option_argument) +        << HWMultArg->getAsString(Args) << HWMult; +  } +} + +/// MSP430 Toolchain +MSP430ToolChain::MSP430ToolChain(const Driver &D, const llvm::Triple &Triple, +                                 const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { + +  StringRef MultilibSuf = ""; + +  GCCInstallation.init(Triple, Args); +  if (GCCInstallation.isValid()) { +    MultilibSuf = GCCInstallation.getMultilib().gccSuffix(); + +    SmallString<128> GCCBinPath; +    llvm::sys::path::append(GCCBinPath, +                            GCCInstallation.getParentLibPath(), "..", "bin"); +    addPathIfExists(D, GCCBinPath, getProgramPaths()); + +    SmallString<128> GCCRtPath; +    llvm::sys::path::append(GCCRtPath, +                            GCCInstallation.getInstallPath(), MultilibSuf); +    addPathIfExists(D, GCCRtPath, getFilePaths()); +  } + +  SmallString<128> SysRootDir(computeSysRoot()); +  llvm::sys::path::append(SysRootDir, "lib", MultilibSuf); +  addPathIfExists(D, SysRootDir, getFilePaths()); +} + +std::string MSP430ToolChain::computeSysRoot() const { +  if (!getDriver().SysRoot.empty()) +    return getDriver().SysRoot; + +  SmallString<128> Dir; +  if (GCCInstallation.isValid()) +    llvm::sys::path::append(Dir, GCCInstallation.getParentLibPath(), "..", +                            GCCInstallation.getTriple().str()); +  else +    llvm::sys::path::append(Dir, getDriver().Dir, "..", getTriple().str()); + +  return Dir.str(); +} + +void MSP430ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                                ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  SmallString<128> Dir(computeSysRoot()); +  llvm::sys::path::append(Dir, "include"); +  addSystemInclude(DriverArgs, CC1Args, Dir.str()); +} + +void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs, +                                            ArgStringList &CC1Args, +                                            Action::OffloadKind) const { +  CC1Args.push_back("-nostdsysteminc"); + +  const auto *MCUArg = DriverArgs.getLastArg(options::OPT_mmcu_EQ); +  if (!MCUArg) +    return; + +  const StringRef MCU = MCUArg->getValue(); +  if (MCU.startswith("msp430i")) { +    // 'i' should be in lower case as it's defined in TI MSP430-GCC headers +    CC1Args.push_back(DriverArgs.MakeArgString( +        "-D__MSP430i" + MCU.drop_front(7).upper() + "__")); +  } else { +    CC1Args.push_back(DriverArgs.MakeArgString("-D__" + MCU.upper() + "__")); +  } +} + +Tool *MSP430ToolChain::buildLinker() const { +  return new tools::msp430::Linker(*this); +} + +void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const ArgList &Args, +                                  const char *LinkingOutput) const { +  const ToolChain &ToolChain = getToolChain(); +  const Driver &D = ToolChain.getDriver(); +  std::string Linker = ToolChain.GetProgramPath(getShortName()); +  ArgStringList CmdArgs; + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); + +  if (!Args.hasArg(options::OPT_T)) { +    if (const Arg *MCUArg = Args.getLastArg(options::OPT_mmcu_EQ)) +      CmdArgs.push_back( +          Args.MakeArgString("-T" + StringRef(MCUArg->getValue()) + ".ld")); +  } else { +    Args.AddAllArgs(CmdArgs, options::OPT_T); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); +  } + +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  CmdArgs.push_back("--start-group"); +  CmdArgs.push_back(Args.MakeArgString(getHWMultLib(Args))); +  CmdArgs.push_back("-lgcc"); +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    CmdArgs.push_back("-lc"); +    CmdArgs.push_back("-lcrt"); +    CmdArgs.push_back("-lnosys"); +  } +  CmdArgs.push_back("--end-group"); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +  } +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), +                                          CmdArgs, Inputs)); +} diff --git a/clang/lib/Driver/ToolChains/MSP430.h b/clang/lib/Driver/ToolChains/MSP430.h new file mode 100644 index 0000000000000..b5308a8dd6875 --- /dev/null +++ b/clang/lib/Driver/ToolChains/MSP430.h @@ -0,0 +1,74 @@ +//===--- MSP430.h - MSP430-specific Tool Helpers ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSP430_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSP430_H + +#include "Gnu.h" +#include "InputInfo.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" + +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MSP430ToolChain : public Generic_ELF { +public: +  MSP430ToolChain(const Driver &D, const llvm::Triple &Triple, +                  const llvm::opt::ArgList &Args); +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind) const override; + +  bool isPICDefault() const override { return false; } +  bool isPIEDefault() const override { return false; } +  bool isPICDefaultForced() const override { return true; } + +protected: +  Tool *buildLinker() const override; + +private: +  std::string computeSysRoot() const; +}; + +} // end namespace toolchains + +namespace tools { +namespace msp430 { + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) +      : GnuTool("MSP430::Linker", "msp430-elf-ld", TC) {} +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +void getMSP430TargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +                             std::vector<llvm::StringRef> &Features); +} // end namespace msp430 +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSP430_H diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp new file mode 100644 index 0000000000000..1d31844bfcc88 --- /dev/null +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -0,0 +1,1508 @@ +//===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MSVC.h" +#include "CommonArgs.h" +#include "Darwin.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include <cstdio> + +#ifdef _WIN32 +  #define WIN32_LEAN_AND_MEAN +  #define NOGDI +  #ifndef NOMINMAX +    #define NOMINMAX +  #endif +  #include <windows.h> +#endif + +#ifdef _MSC_VER +// Don't support SetupApi on MinGW. +#define USE_MSVC_SETUP_API + +// Make sure this comes before MSVCSetupApi.h +#include <comdef.h> + +#include "MSVCSetupApi.h" +#include "llvm/Support/COM.h" +_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); +_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); +_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); +_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); +_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); +_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); +#endif + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +// Defined below. +// Forward declare this so there aren't too many things above the constructor. +static bool getSystemRegistryString(const char *keyPath, const char *valueName, +                                    std::string &value, std::string *phValue); + +// Check various environment variables to try and find a toolchain. +static bool findVCToolChainViaEnvironment(std::string &Path, +                                          MSVCToolChain::ToolsetLayout &VSLayout) { +  // These variables are typically set by vcvarsall.bat +  // when launching a developer command prompt. +  if (llvm::Optional<std::string> VCToolsInstallDir = +          llvm::sys::Process::GetEnv("VCToolsInstallDir")) { +    // This is only set by newer Visual Studios, and it leads straight to +    // the toolchain directory. +    Path = std::move(*VCToolsInstallDir); +    VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; +    return true; +  } +  if (llvm::Optional<std::string> VCInstallDir = +          llvm::sys::Process::GetEnv("VCINSTALLDIR")) { +    // If the previous variable isn't set but this one is, then we've found +    // an older Visual Studio. This variable is set by newer Visual Studios too, +    // so this check has to appear second. +    // In older Visual Studios, the VC directory is the toolchain. +    Path = std::move(*VCInstallDir); +    VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; +    return true; +  } + +  // We couldn't find any VC environment variables. Let's walk through PATH and +  // see if it leads us to a VC toolchain bin directory. If it does, pick the +  // first one that we find. +  if (llvm::Optional<std::string> PathEnv = +          llvm::sys::Process::GetEnv("PATH")) { +    llvm::SmallVector<llvm::StringRef, 8> PathEntries; +    llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator); +    for (llvm::StringRef PathEntry : PathEntries) { +      if (PathEntry.empty()) +        continue; + +      llvm::SmallString<256> ExeTestPath; + +      // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. +      ExeTestPath = PathEntry; +      llvm::sys::path::append(ExeTestPath, "cl.exe"); +      if (!llvm::sys::fs::exists(ExeTestPath)) +        continue; + +      // cl.exe existing isn't a conclusive test for a VC toolchain; clang also +      // has a cl.exe. So let's check for link.exe too. +      ExeTestPath = PathEntry; +      llvm::sys::path::append(ExeTestPath, "link.exe"); +      if (!llvm::sys::fs::exists(ExeTestPath)) +        continue; + +      // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. +      llvm::StringRef TestPath = PathEntry; +      bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin"); +      if (!IsBin) { +        // Strip any architecture subdir like "amd64". +        TestPath = llvm::sys::path::parent_path(TestPath); +        IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin"); +      } +      if (IsBin) { +        llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath); +        llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath); +        if (ParentFilename == "VC") { +          Path = ParentPath; +          VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; +          return true; +        } +        if (ParentFilename == "x86ret" || ParentFilename == "x86chk" +          || ParentFilename == "amd64ret" || ParentFilename == "amd64chk") { +          Path = ParentPath; +          VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal; +          return true; +        } + +      } else { +        // This could be a new (>=VS2017) toolchain. If it is, we should find +        // path components with these prefixes when walking backwards through +        // the path. +        // Note: empty strings match anything. +        llvm::StringRef ExpectedPrefixes[] = {"",     "Host",  "bin", "", +                                              "MSVC", "Tools", "VC"}; + +        auto It = llvm::sys::path::rbegin(PathEntry); +        auto End = llvm::sys::path::rend(PathEntry); +        for (llvm::StringRef Prefix : ExpectedPrefixes) { +          if (It == End) +            goto NotAToolChain; +          if (!It->startswith(Prefix)) +            goto NotAToolChain; +          ++It; +        } + +        // We've found a new toolchain! +        // Back up 3 times (/bin/Host/arch) to get the root path. +        llvm::StringRef ToolChainPath(PathEntry); +        for (int i = 0; i < 3; ++i) +          ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); + +        Path = ToolChainPath; +        VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; +        return true; +      } + +    NotAToolChain: +      continue; +    } +  } +  return false; +} + +// Query the Setup Config server for installs, then pick the newest version +// and find its default VC toolchain. +// This is the preferred way to discover new Visual Studios, as they're no +// longer listed in the registry. +static bool findVCToolChainViaSetupConfig(std::string &Path, +                                          MSVCToolChain::ToolsetLayout &VSLayout) { +#if !defined(USE_MSVC_SETUP_API) +  return false; +#else +  // FIXME: This really should be done once in the top-level program's main +  // function, as it may have already been initialized with a different +  // threading model otherwise. +  llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded); +  HRESULT HR; + +  // _com_ptr_t will throw a _com_error if a COM calls fail. +  // The LLVM coding standards forbid exception handling, so we'll have to +  // stop them from being thrown in the first place. +  // The destructor will put the regular error handler back when we leave +  // this scope. +  struct SuppressCOMErrorsRAII { +    static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} + +    SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } + +    ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } + +  } COMErrorSuppressor; + +  ISetupConfigurationPtr Query; +  HR = Query.CreateInstance(__uuidof(SetupConfiguration)); +  if (FAILED(HR)) +    return false; + +  IEnumSetupInstancesPtr EnumInstances; +  HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); +  if (FAILED(HR)) +    return false; + +  ISetupInstancePtr Instance; +  HR = EnumInstances->Next(1, &Instance, nullptr); +  if (HR != S_OK) +    return false; + +  ISetupInstancePtr NewestInstance; +  Optional<uint64_t> NewestVersionNum; +  do { +    bstr_t VersionString; +    uint64_t VersionNum; +    HR = Instance->GetInstallationVersion(VersionString.GetAddress()); +    if (FAILED(HR)) +      continue; +    HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); +    if (FAILED(HR)) +      continue; +    if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { +      NewestInstance = Instance; +      NewestVersionNum = VersionNum; +    } +  } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); + +  if (!NewestInstance) +    return false; + +  bstr_t VCPathWide; +  HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); +  if (FAILED(HR)) +    return false; + +  std::string VCRootPath; +  llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); + +  llvm::SmallString<256> ToolsVersionFilePath(VCRootPath); +  llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", +                          "Microsoft.VCToolsVersion.default.txt"); + +  auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath); +  if (!ToolsVersionFile) +    return false; + +  llvm::SmallString<256> ToolchainPath(VCRootPath); +  llvm::sys::path::append(ToolchainPath, "Tools", "MSVC", +                          ToolsVersionFile->get()->getBuffer().rtrim()); +  if (!llvm::sys::fs::is_directory(ToolchainPath)) +    return false; + +  Path = ToolchainPath.str(); +  VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; +  return true; +#endif +} + +// Look in the registry for Visual Studio installs, and use that to get +// a toolchain path. VS2017 and newer don't get added to the registry. +// So if we find something here, we know that it's an older version. +static bool findVCToolChainViaRegistry(std::string &Path, +                                       MSVCToolChain::ToolsetLayout &VSLayout) { +  std::string VSInstallPath; +  if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", +                              "InstallDir", VSInstallPath, nullptr) || +      getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", +                              "InstallDir", VSInstallPath, nullptr)) { +    if (!VSInstallPath.empty()) { +      llvm::SmallString<256> VCPath(llvm::StringRef( +          VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)"))); +      llvm::sys::path::append(VCPath, "VC"); + +      Path = VCPath.str(); +      VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; +      return true; +    } +  } +  return false; +} + +// Try to find Exe from a Visual Studio distribution.  This first tries to find +// an installed copy of Visual Studio and, failing that, looks in the PATH, +// making sure that whatever executable that's found is not a same-named exe +// from clang itself to prevent clang from falling back to itself. +static std::string FindVisualStudioExecutable(const ToolChain &TC, +                                              const char *Exe) { +  const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); +  SmallString<128> FilePath(MSVC.getSubDirectoryPath( +      toolchains::MSVCToolChain::SubDirectoryType::Bin)); +  llvm::sys::path::append(FilePath, Exe); +  return llvm::sys::fs::can_execute(FilePath) ? FilePath.str() : Exe; +} + +void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                        const InputInfo &Output, +                                        const InputInfoList &Inputs, +                                        const ArgList &Args, +                                        const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain()); + +  assert((Output.isFilename() || Output.isNothing()) && "invalid output"); +  if (Output.isFilename()) +    CmdArgs.push_back( +        Args.MakeArgString(std::string("-out:") + Output.getFilename())); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && +      !C.getDriver().IsCLMode()) +    CmdArgs.push_back("-defaultlib:libcmt"); + +  if (!llvm::sys::Process::GetEnv("LIB")) { +    // If the VC environment hasn't been configured (perhaps because the user +    // did not run vcvarsall), try to build a consistent link environment.  If +    // the environment variable is set however, assume the user knows what +    // they're doing. +    CmdArgs.push_back(Args.MakeArgString( +        Twine("-libpath:") + +        TC.getSubDirectoryPath( +            toolchains::MSVCToolChain::SubDirectoryType::Lib))); + +    CmdArgs.push_back(Args.MakeArgString( +        Twine("-libpath:") + +        TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib, +                               "atlmfc"))); + +    if (TC.useUniversalCRT()) { +      std::string UniversalCRTLibPath; +      if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) +        CmdArgs.push_back( +            Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath)); +    } + +    std::string WindowsSdkLibPath; +    if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) +      CmdArgs.push_back( +          Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); +  } + +  if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) +    for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) +      CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); + +  CmdArgs.push_back("-nologo"); + +  if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7, +                  options::OPT__SLASH_Zd)) +    CmdArgs.push_back("-debug"); + +  // Pass on /Brepro if it was passed to the compiler. +  // Note that /Brepro maps to -mno-incremental-linker-compatible. +  bool DefaultIncrementalLinkerCompatible = +      C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); +  if (!Args.hasFlag(options::OPT_mincremental_linker_compatible, +                    options::OPT_mno_incremental_linker_compatible, +                    DefaultIncrementalLinkerCompatible)) +    CmdArgs.push_back("-Brepro"); + +  bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, +                         options::OPT_shared); +  if (DLL) { +    CmdArgs.push_back(Args.MakeArgString("-dll")); + +    SmallString<128> ImplibName(Output.getFilename()); +    llvm::sys::path::replace_extension(ImplibName, "lib"); +    CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); +  } + +  if (TC.getSanitizerArgs().needsFuzzer()) { +    if (!Args.hasArg(options::OPT_shared)) +      CmdArgs.push_back( +          Args.MakeArgString(std::string("-wholearchive:") + +                             TC.getCompilerRTArgString(Args, "fuzzer"))); +    CmdArgs.push_back(Args.MakeArgString("-debug")); +    // Prevent the linker from padding sections we use for instrumentation +    // arrays. +    CmdArgs.push_back(Args.MakeArgString("-incremental:no")); +  } + +  if (TC.getSanitizerArgs().needsAsanRt()) { +    CmdArgs.push_back(Args.MakeArgString("-debug")); +    CmdArgs.push_back(Args.MakeArgString("-incremental:no")); +    if (TC.getSanitizerArgs().needsSharedRt() || +        Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { +      for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) +        CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); +      // Make sure the dynamic runtime thunk is not optimized out at link time +      // to ensure proper SEH handling. +      CmdArgs.push_back(Args.MakeArgString( +          TC.getArch() == llvm::Triple::x86 +              ? "-include:___asan_seh_interceptor" +              : "-include:__asan_seh_interceptor")); +      // Make sure the linker consider all object files from the dynamic runtime +      // thunk. +      CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + +          TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); +    } else if (DLL) { +      CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); +    } else { +      for (const auto &Lib : {"asan", "asan_cxx"}) { +        CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); +        // Make sure the linker consider all object files from the static lib. +        // This is necessary because instrumented dlls need access to all the +        // interface exported by the static lib in the main executable. +        CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + +            TC.getCompilerRT(Args, Lib))); +      } +    } +  } + +  Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); + +  if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, +                   options::OPT_fno_openmp, false)) { +    CmdArgs.push_back("-nodefaultlib:vcomp.lib"); +    CmdArgs.push_back("-nodefaultlib:vcompd.lib"); +    CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + +                                         TC.getDriver().Dir + "/../lib")); +    switch (TC.getDriver().getOpenMPRuntime(Args)) { +    case Driver::OMPRT_OMP: +      CmdArgs.push_back("-defaultlib:libomp.lib"); +      break; +    case Driver::OMPRT_IOMP5: +      CmdArgs.push_back("-defaultlib:libiomp5md.lib"); +      break; +    case Driver::OMPRT_GOMP: +      break; +    case Driver::OMPRT_Unknown: +      // Already diagnosed. +      break; +    } +  } + +  // Add compiler-rt lib in case if it was explicitly +  // specified as an argument for --rtlib option. +  if (!Args.hasArg(options::OPT_nostdlib)) { +    AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); +  } + +  // Add filenames, libraries, and other linker inputs. +  for (const auto &Input : Inputs) { +    if (Input.isFilename()) { +      CmdArgs.push_back(Input.getFilename()); +      continue; +    } + +    const Arg &A = Input.getInputArg(); + +    // Render -l options differently for the MSVC linker. +    if (A.getOption().matches(options::OPT_l)) { +      StringRef Lib = A.getValue(); +      const char *LinkLibArg; +      if (Lib.endswith(".lib")) +        LinkLibArg = Args.MakeArgString(Lib); +      else +        LinkLibArg = Args.MakeArgString(Lib + ".lib"); +      CmdArgs.push_back(LinkLibArg); +      continue; +    } + +    // Otherwise, this is some other kind of linker input option like -Wl, -z, +    // or -L. Render it, even if MSVC doesn't understand it. +    A.renderAsInput(Args, CmdArgs); +  } + +  TC.addProfileRTLibs(Args, CmdArgs); + +  std::vector<const char *> Environment; + +  // We need to special case some linker paths.  In the case of lld, we need to +  // translate 'lld' into 'lld-link', and in the case of the regular msvc +  // linker, we need to use a special search algorithm. +  llvm::SmallString<128> linkPath; +  StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link"); +  if (Linker.equals_lower("lld")) +    Linker = "lld-link"; + +  if (Linker.equals_lower("link")) { +    // If we're using the MSVC linker, it's not sufficient to just use link +    // from the program PATH, because other environments like GnuWin32 install +    // their own link.exe which may come first. +    linkPath = FindVisualStudioExecutable(TC, "link.exe"); + +    if (!TC.FoundMSVCInstall() && !llvm::sys::fs::can_execute(linkPath)) { +      llvm::SmallString<128> ClPath; +      ClPath = TC.GetProgramPath("cl.exe"); +      if (llvm::sys::fs::can_execute(ClPath)) { +        linkPath = llvm::sys::path::parent_path(ClPath); +        llvm::sys::path::append(linkPath, "link.exe"); +        if (!llvm::sys::fs::can_execute(linkPath)) +          C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found); +      } else { +        C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found); +      } +    } + +#ifdef _WIN32 +    // When cross-compiling with VS2017 or newer, link.exe expects to have +    // its containing bin directory at the top of PATH, followed by the +    // native target bin directory. +    // e.g. when compiling for x86 on an x64 host, PATH should start with: +    // /bin/Hostx64/x86;/bin/Hostx64/x64 +    // This doesn't attempt to handle ToolsetLayout::DevDivInternal. +    if (TC.getIsVS2017OrNewer() && +        llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) { +      auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch(); + +      auto EnvBlockWide = +          std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>( +              GetEnvironmentStringsW(), FreeEnvironmentStringsW); +      if (!EnvBlockWide) +        goto SkipSettingEnvironment; + +      size_t EnvCount = 0; +      size_t EnvBlockLen = 0; +      while (EnvBlockWide[EnvBlockLen] != L'\0') { +        ++EnvCount; +        EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) + +                       1 /*string null-terminator*/; +      } +      ++EnvBlockLen; // add the block null-terminator + +      std::string EnvBlock; +      if (!llvm::convertUTF16ToUTF8String( +              llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()), +                                   EnvBlockLen * sizeof(EnvBlockWide[0])), +              EnvBlock)) +        goto SkipSettingEnvironment; + +      Environment.reserve(EnvCount); + +      // Now loop over each string in the block and copy them into the +      // environment vector, adjusting the PATH variable as needed when we +      // find it. +      for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { +        llvm::StringRef EnvVar(Cursor); +        if (EnvVar.startswith_lower("path=")) { +          using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType; +          constexpr size_t PrefixLen = 5; // strlen("path=") +          Environment.push_back(Args.MakeArgString( +              EnvVar.substr(0, PrefixLen) + +              TC.getSubDirectoryPath(SubDirectoryType::Bin) + +              llvm::Twine(llvm::sys::EnvPathSeparator) + +              TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) + +              (EnvVar.size() > PrefixLen +                   ? llvm::Twine(llvm::sys::EnvPathSeparator) + +                         EnvVar.substr(PrefixLen) +                   : ""))); +        } else { +          Environment.push_back(Args.MakeArgString(EnvVar)); +        } +        Cursor += EnvVar.size() + 1 /*null-terminator*/; +      } +    } +  SkipSettingEnvironment:; +#endif +  } else { +    linkPath = TC.GetProgramPath(Linker.str().c_str()); +  } + +  auto LinkCmd = std::make_unique<Command>( +      JA, *this, Args.MakeArgString(linkPath), CmdArgs, Inputs); +  if (!Environment.empty()) +    LinkCmd->setEnvironment(Environment); +  C.addCommand(std::move(LinkCmd)); +} + +void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA, +                                          const InputInfo &Output, +                                          const InputInfoList &Inputs, +                                          const ArgList &Args, +                                          const char *LinkingOutput) const { +  C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput)); +} + +std::unique_ptr<Command> visualstudio::Compiler::GetCommand( +    Compilation &C, const JobAction &JA, const InputInfo &Output, +    const InputInfoList &Inputs, const ArgList &Args, +    const char *LinkingOutput) const { +  ArgStringList CmdArgs; +  CmdArgs.push_back("/nologo"); +  CmdArgs.push_back("/c");  // Compile only. +  CmdArgs.push_back("/W0"); // No warnings. + +  // The goal is to be able to invoke this tool correctly based on +  // any flag accepted by clang-cl. + +  // These are spelled the same way in clang and cl.exe,. +  Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); + +  // Optimization level. +  if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin)) +    CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi" +                                                                      : "/Oi-"); +  if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { +    if (A->getOption().getID() == options::OPT_O0) { +      CmdArgs.push_back("/Od"); +    } else { +      CmdArgs.push_back("/Og"); + +      StringRef OptLevel = A->getValue(); +      if (OptLevel == "s" || OptLevel == "z") +        CmdArgs.push_back("/Os"); +      else +        CmdArgs.push_back("/Ot"); + +      CmdArgs.push_back("/Ob2"); +    } +  } +  if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, +                               options::OPT_fno_omit_frame_pointer)) +    CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer +                          ? "/Oy" +                          : "/Oy-"); +  if (!Args.hasArg(options::OPT_fwritable_strings)) +    CmdArgs.push_back("/GF"); + +  // Flags for which clang-cl has an alias. +  // FIXME: How can we ensure this stays in sync with relevant clang-cl options? + +  if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, +                   /*Default=*/false)) +    CmdArgs.push_back("/GR-"); + +  if (Args.hasFlag(options::OPT__SLASH_GS_, options::OPT__SLASH_GS, +                   /*Default=*/false)) +    CmdArgs.push_back("/GS-"); + +  if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections, +                               options::OPT_fno_function_sections)) +    CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections +                          ? "/Gy" +                          : "/Gy-"); +  if (Arg *A = Args.getLastArg(options::OPT_fdata_sections, +                               options::OPT_fno_data_sections)) +    CmdArgs.push_back( +        A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-"); +  if (Args.hasArg(options::OPT_fsyntax_only)) +    CmdArgs.push_back("/Zs"); +  if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only, +                  options::OPT__SLASH_Z7)) +    CmdArgs.push_back("/Z7"); + +  std::vector<std::string> Includes = +      Args.getAllArgValues(options::OPT_include); +  for (const auto &Include : Includes) +    CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include)); + +  // Flags that can simply be passed through. +  Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); +  Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); +  Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX); +  Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX_); +  Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH); +  Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl); + +  // The order of these flags is relevant, so pick the last one. +  if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, +                               options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) +    A->render(Args, CmdArgs); + +  // Use MSVC's default threadsafe statics behaviour unless there was a flag. +  if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics, +                               options::OPT_fno_threadsafe_statics)) { +    CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics +                          ? "/Zc:threadSafeInit" +                          : "/Zc:threadSafeInit-"); +  } + +  // Pass through all unknown arguments so that the fallback command can see +  // them too. +  Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); + +  // Input filename. +  assert(Inputs.size() == 1); +  const InputInfo &II = Inputs[0]; +  assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); +  CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp"); +  if (II.isFilename()) +    CmdArgs.push_back(II.getFilename()); +  else +    II.getInputArg().renderAsInput(Args, CmdArgs); + +  // Output filename. +  assert(Output.getType() == types::TY_Object); +  const char *Fo = +      Args.MakeArgString(std::string("/Fo") + Output.getFilename()); +  CmdArgs.push_back(Fo); + +  std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe"); +  return std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), +                                    CmdArgs, Inputs); +} + +MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, +                             const ArgList &Args) +    : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); + +  // Check the environment first, since that's probably the user telling us +  // what they want to use. +  // Failing that, just try to find the newest Visual Studio version we can +  // and use its default VC toolchain. +  findVCToolChainViaEnvironment(VCToolChainPath, VSLayout) || +      findVCToolChainViaSetupConfig(VCToolChainPath, VSLayout) || +      findVCToolChainViaRegistry(VCToolChainPath, VSLayout); +} + +Tool *MSVCToolChain::buildLinker() const { +  return new tools::visualstudio::Linker(*this); +} + +Tool *MSVCToolChain::buildAssembler() const { +  if (getTriple().isOSBinFormatMachO()) +    return new tools::darwin::Assembler(*this); +  getDriver().Diag(clang::diag::err_no_external_assembler); +  return nullptr; +} + +bool MSVCToolChain::IsIntegratedAssemblerDefault() const { +  return true; +} + +bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +  // Don't emit unwind tables by default for MachO targets. +  if (getTriple().isOSBinFormatMachO()) +    return false; + +  // All non-x86_32 Windows targets require unwind tables. However, LLVM +  // doesn't know how to generate them for all targets, so only enable +  // the ones that are actually implemented. +  return getArch() == llvm::Triple::x86_64 || +         getArch() == llvm::Triple::aarch64; +} + +bool MSVCToolChain::isPICDefault() const { +  return getArch() == llvm::Triple::x86_64; +} + +bool MSVCToolChain::isPIEDefault() const { +  return false; +} + +bool MSVCToolChain::isPICDefaultForced() const { +  return getArch() == llvm::Triple::x86_64; +} + +void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, +                                       ArgStringList &CC1Args) const { +  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { +  CudaInstallation.print(OS); +} + +// Windows SDKs and VC Toolchains group their contents into subdirectories based +// on the target architecture. This function converts an llvm::Triple::ArchType +// to the corresponding subdirectory name. +static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { +  using ArchType = llvm::Triple::ArchType; +  switch (Arch) { +  case ArchType::x86: +    return "x86"; +  case ArchType::x86_64: +    return "x64"; +  case ArchType::arm: +    return "arm"; +  case ArchType::aarch64: +    return "arm64"; +  default: +    return ""; +  } +} + +// Similar to the above function, but for Visual Studios before VS2017. +static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { +  using ArchType = llvm::Triple::ArchType; +  switch (Arch) { +  case ArchType::x86: +    // x86 is default in legacy VC toolchains. +    // e.g. x86 libs are directly in /lib as opposed to /lib/x86. +    return ""; +  case ArchType::x86_64: +    return "amd64"; +  case ArchType::arm: +    return "arm"; +  case ArchType::aarch64: +    return "arm64"; +  default: +    return ""; +  } +} + +// Similar to the above function, but for DevDiv internal builds. +static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { +  using ArchType = llvm::Triple::ArchType; +  switch (Arch) { +  case ArchType::x86: +    return "i386"; +  case ArchType::x86_64: +    return "amd64"; +  case ArchType::arm: +    return "arm"; +  case ArchType::aarch64: +    return "arm64"; +  default: +    return ""; +  } +} + +// Get the path to a specific subdirectory in the current toolchain for +// a given target architecture. +// VS2017 changed the VC toolchain layout, so this should be used instead +// of hardcoding paths. +std::string +MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type, +                                   llvm::StringRef SubdirParent, +                                   llvm::Triple::ArchType TargetArch) const { +  const char *SubdirName; +  const char *IncludeName; +  switch (VSLayout) { +  case ToolsetLayout::OlderVS: +    SubdirName = llvmArchToLegacyVCArch(TargetArch); +    IncludeName = "include"; +    break; +  case ToolsetLayout::VS2017OrNewer: +    SubdirName = llvmArchToWindowsSDKArch(TargetArch); +    IncludeName = "include"; +    break; +  case ToolsetLayout::DevDivInternal: +    SubdirName = llvmArchToDevDivInternalArch(TargetArch); +    IncludeName = "inc"; +    break; +  } + +  llvm::SmallString<256> Path(VCToolChainPath); +  if (!SubdirParent.empty()) +    llvm::sys::path::append(Path, SubdirParent); + +  switch (Type) { +  case SubDirectoryType::Bin: +    if (VSLayout == ToolsetLayout::VS2017OrNewer) { +      const bool HostIsX64 = +          llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit(); +      const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86"; +      llvm::sys::path::append(Path, "bin", HostName, SubdirName); +    } else { // OlderVS or DevDivInternal +      llvm::sys::path::append(Path, "bin", SubdirName); +    } +    break; +  case SubDirectoryType::Include: +    llvm::sys::path::append(Path, IncludeName); +    break; +  case SubDirectoryType::Lib: +    llvm::sys::path::append(Path, "lib", SubdirName); +    break; +  } +  return Path.str(); +} + +#ifdef _WIN32 +static bool readFullStringValue(HKEY hkey, const char *valueName, +                                std::string &value) { +  std::wstring WideValueName; +  if (!llvm::ConvertUTF8toWide(valueName, WideValueName)) +    return false; + +  DWORD result = 0; +  DWORD valueSize = 0; +  DWORD type = 0; +  // First just query for the required size. +  result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL, +                            &valueSize); +  if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize) +    return false; +  std::vector<BYTE> buffer(valueSize); +  result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0], +                            &valueSize); +  if (result == ERROR_SUCCESS) { +    std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()), +                           valueSize / sizeof(wchar_t)); +    if (valueSize && WideValue.back() == L'\0') { +      WideValue.pop_back(); +    } +    // The destination buffer must be empty as an invariant of the conversion +    // function; but this function is sometimes called in a loop that passes in +    // the same buffer, however. Simply clear it out so we can overwrite it. +    value.clear(); +    return llvm::convertWideToUTF8(WideValue, value); +  } +  return false; +} +#endif + +/// Read registry string. +/// This also supports a means to look for high-versioned keys by use +/// of a $VERSION placeholder in the key path. +/// $VERSION in the key path is a placeholder for the version number, +/// causing the highest value path to be searched for and used. +/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". +/// There can be additional characters in the component.  Only the numeric +/// characters are compared.  This function only searches HKLM. +static bool getSystemRegistryString(const char *keyPath, const char *valueName, +                                    std::string &value, std::string *phValue) { +#ifndef _WIN32 +  return false; +#else +  HKEY hRootKey = HKEY_LOCAL_MACHINE; +  HKEY hKey = NULL; +  long lResult; +  bool returnValue = false; + +  const char *placeHolder = strstr(keyPath, "$VERSION"); +  std::string bestName; +  // If we have a $VERSION placeholder, do the highest-version search. +  if (placeHolder) { +    const char *keyEnd = placeHolder - 1; +    const char *nextKey = placeHolder; +    // Find end of previous key. +    while ((keyEnd > keyPath) && (*keyEnd != '\\')) +      keyEnd--; +    // Find end of key containing $VERSION. +    while (*nextKey && (*nextKey != '\\')) +      nextKey++; +    size_t partialKeyLength = keyEnd - keyPath; +    char partialKey[256]; +    if (partialKeyLength >= sizeof(partialKey)) +      partialKeyLength = sizeof(partialKey) - 1; +    strncpy(partialKey, keyPath, partialKeyLength); +    partialKey[partialKeyLength] = '\0'; +    HKEY hTopKey = NULL; +    lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, +                            &hTopKey); +    if (lResult == ERROR_SUCCESS) { +      char keyName[256]; +      double bestValue = 0.0; +      DWORD index, size = sizeof(keyName) - 1; +      for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL, +                                    NULL, NULL) == ERROR_SUCCESS; +           index++) { +        const char *sp = keyName; +        while (*sp && !isDigit(*sp)) +          sp++; +        if (!*sp) +          continue; +        const char *ep = sp + 1; +        while (*ep && (isDigit(*ep) || (*ep == '.'))) +          ep++; +        char numBuf[32]; +        strncpy(numBuf, sp, sizeof(numBuf) - 1); +        numBuf[sizeof(numBuf) - 1] = '\0'; +        double dvalue = strtod(numBuf, NULL); +        if (dvalue > bestValue) { +          // Test that InstallDir is indeed there before keeping this index. +          // Open the chosen key path remainder. +          bestName = keyName; +          // Append rest of key. +          bestName.append(nextKey); +          lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, +                                  KEY_READ | KEY_WOW64_32KEY, &hKey); +          if (lResult == ERROR_SUCCESS) { +            if (readFullStringValue(hKey, valueName, value)) { +              bestValue = dvalue; +              if (phValue) +                *phValue = bestName; +              returnValue = true; +            } +            RegCloseKey(hKey); +          } +        } +        size = sizeof(keyName) - 1; +      } +      RegCloseKey(hTopKey); +    } +  } else { +    lResult = +        RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); +    if (lResult == ERROR_SUCCESS) { +      if (readFullStringValue(hKey, valueName, value)) +        returnValue = true; +      if (phValue) +        phValue->clear(); +      RegCloseKey(hKey); +    } +  } +  return returnValue; +#endif // _WIN32 +} + +// Find the most recent version of Universal CRT or Windows 10 SDK. +// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include +// directory by name and uses the last one of the list. +// So we compare entry names lexicographically to find the greatest one. +static bool getWindows10SDKVersionFromPath(const std::string &SDKPath, +                                           std::string &SDKVersion) { +  SDKVersion.clear(); + +  std::error_code EC; +  llvm::SmallString<128> IncludePath(SDKPath); +  llvm::sys::path::append(IncludePath, "Include"); +  for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd; +       DirIt != DirEnd && !EC; DirIt.increment(EC)) { +    if (!llvm::sys::fs::is_directory(DirIt->path())) +      continue; +    StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); +    // If WDK is installed, there could be subfolders like "wdf" in the +    // "Include" directory. +    // Allow only directories which names start with "10.". +    if (!CandidateName.startswith("10.")) +      continue; +    if (CandidateName > SDKVersion) +      SDKVersion = CandidateName; +  } + +  return !SDKVersion.empty(); +} + +/// Get Windows SDK installation directory. +static bool getWindowsSDKDir(std::string &Path, int &Major, +                             std::string &WindowsSDKIncludeVersion, +                             std::string &WindowsSDKLibVersion) { +  std::string RegistrySDKVersion; +  // Try the Windows registry. +  if (!getSystemRegistryString( +          "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", +          "InstallationFolder", Path, &RegistrySDKVersion)) +    return false; +  if (Path.empty() || RegistrySDKVersion.empty()) +    return false; + +  WindowsSDKIncludeVersion.clear(); +  WindowsSDKLibVersion.clear(); +  Major = 0; +  std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); +  if (Major <= 7) +    return true; +  if (Major == 8) { +    // Windows SDK 8.x installs libraries in a folder whose names depend on the +    // version of the OS you're targeting.  By default choose the newest, which +    // usually corresponds to the version of the OS you've installed the SDK on. +    const char *Tests[] = {"winv6.3", "win8", "win7"}; +    for (const char *Test : Tests) { +      llvm::SmallString<128> TestPath(Path); +      llvm::sys::path::append(TestPath, "Lib", Test); +      if (llvm::sys::fs::exists(TestPath.c_str())) { +        WindowsSDKLibVersion = Test; +        break; +      } +    } +    return !WindowsSDKLibVersion.empty(); +  } +  if (Major == 10) { +    if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion)) +      return false; +    WindowsSDKLibVersion = WindowsSDKIncludeVersion; +    return true; +  } +  // Unsupported SDK version +  return false; +} + +// Gets the library path required to link against the Windows SDK. +bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { +  std::string sdkPath; +  int sdkMajor = 0; +  std::string windowsSDKIncludeVersion; +  std::string windowsSDKLibVersion; + +  path.clear(); +  if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion, +                        windowsSDKLibVersion)) +    return false; + +  llvm::SmallString<128> libPath(sdkPath); +  llvm::sys::path::append(libPath, "Lib"); +  if (sdkMajor >= 8) { +    llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", +                            llvmArchToWindowsSDKArch(getArch())); +  } else { +    switch (getArch()) { +    // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. +    case llvm::Triple::x86: +      break; +    case llvm::Triple::x86_64: +      llvm::sys::path::append(libPath, "x64"); +      break; +    case llvm::Triple::arm: +      // It is not necessary to link against Windows SDK 7.x when targeting ARM. +      return false; +    default: +      return false; +    } +  } + +  path = libPath.str(); +  return true; +} + +// Check if the Include path of a specified version of Visual Studio contains +// specific header files. If not, they are probably shipped with Universal CRT. +bool MSVCToolChain::useUniversalCRT() const { +  llvm::SmallString<128> TestPath( +      getSubDirectoryPath(SubDirectoryType::Include)); +  llvm::sys::path::append(TestPath, "stdlib.h"); +  return !llvm::sys::fs::exists(TestPath); +} + +static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) { +  // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry +  // for the specific key "KitsRoot10". So do we. +  if (!getSystemRegistryString( +          "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", +          Path, nullptr)) +    return false; + +  return getWindows10SDKVersionFromPath(Path, UCRTVersion); +} + +bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { +  std::string UniversalCRTSdkPath; +  std::string UCRTVersion; + +  Path.clear(); +  if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) +    return false; + +  StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); +  if (ArchName.empty()) +    return false; + +  llvm::SmallString<128> LibPath(UniversalCRTSdkPath); +  llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); + +  Path = LibPath.str(); +  return true; +} + +static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) { +  unsigned Major, Minor, Micro; +  Triple.getEnvironmentVersion(Major, Minor, Micro); +  if (Major || Minor || Micro) +    return VersionTuple(Major, Minor, Micro); +  return VersionTuple(); +} + +static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) { +  VersionTuple Version; +#ifdef _WIN32 +  SmallString<128> ClExe(BinDir); +  llvm::sys::path::append(ClExe, "cl.exe"); + +  std::wstring ClExeWide; +  if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide)) +    return Version; + +  const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(), +                                                      nullptr); +  if (VersionSize == 0) +    return Version; + +  SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize); +  if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize, +                             VersionBlock.data())) +    return Version; + +  VS_FIXEDFILEINFO *FileInfo = nullptr; +  UINT FileInfoSize = 0; +  if (!::VerQueryValueW(VersionBlock.data(), L"\\", +                        reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) || +      FileInfoSize < sizeof(*FileInfo)) +    return Version; + +  const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF; +  const unsigned Minor = (FileInfo->dwFileVersionMS      ) & 0xFFFF; +  const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF; + +  Version = VersionTuple(Major, Minor, Micro); +#endif +  return Version; +} + +void MSVCToolChain::AddSystemIncludeWithSubfolder( +    const ArgList &DriverArgs, ArgStringList &CC1Args, +    const std::string &folder, const Twine &subfolder1, const Twine &subfolder2, +    const Twine &subfolder3) const { +  llvm::SmallString<128> path(folder); +  llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3); +  addSystemInclude(DriverArgs, CC1Args, path); +} + +void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                              ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir, +                                  "include"); +  } + +  // Add %INCLUDE%-like directories from the -imsvc flag. +  for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc)) +    addSystemInclude(DriverArgs, CC1Args, Path); + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat. +  if (llvm::Optional<std::string> cl_include_dir = +          llvm::sys::Process::GetEnv("INCLUDE")) { +    SmallVector<StringRef, 8> Dirs; +    StringRef(*cl_include_dir) +        .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false); +    for (StringRef Dir : Dirs) +      addSystemInclude(DriverArgs, CC1Args, Dir); +    if (!Dirs.empty()) +      return; +  } + +  // When built with access to the proper Windows APIs, try to actually find +  // the correct include paths first. +  if (!VCToolChainPath.empty()) { +    addSystemInclude(DriverArgs, CC1Args, +                     getSubDirectoryPath(SubDirectoryType::Include)); +    addSystemInclude(DriverArgs, CC1Args, +                     getSubDirectoryPath(SubDirectoryType::Include, "atlmfc")); + +    if (useUniversalCRT()) { +      std::string UniversalCRTSdkPath; +      std::string UCRTVersion; +      if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) { +        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, +                                      "Include", UCRTVersion, "ucrt"); +      } +    } + +    std::string WindowsSDKDir; +    int major; +    std::string windowsSDKIncludeVersion; +    std::string windowsSDKLibVersion; +    if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion, +                         windowsSDKLibVersion)) { +      if (major >= 8) { +        // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. +        // Anyway, llvm::sys::path::append is able to manage it. +        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, +                                      "include", windowsSDKIncludeVersion, +                                      "shared"); +        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, +                                      "include", windowsSDKIncludeVersion, +                                      "um"); +        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, +                                      "include", windowsSDKIncludeVersion, +                                      "winrt"); +      } else { +        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, +                                      "include"); +      } +    } + +    return; +  } + +#if defined(_WIN32) +  // As a fallback, select default install paths. +  // FIXME: Don't guess drives and paths like this on Windows. +  const StringRef Paths[] = { +    "C:/Program Files/Microsoft Visual Studio 10.0/VC/include", +    "C:/Program Files/Microsoft Visual Studio 9.0/VC/include", +    "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", +    "C:/Program Files/Microsoft Visual Studio 8/VC/include", +    "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" +  }; +  addSystemIncludes(DriverArgs, CC1Args, Paths); +#endif +} + +void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, +                                                 ArgStringList &CC1Args) const { +  // FIXME: There should probably be logic here to find libc++ on Windows. +} + +VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, +                                               const ArgList &Args) const { +  bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); +  VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); +  if (MSVT.empty()) +    MSVT = getMSVCVersionFromTriple(getTriple()); +  if (MSVT.empty() && IsWindowsMSVC) +    MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin)); +  if (MSVT.empty() && +      Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, +                   IsWindowsMSVC)) { +    // -fms-compatibility-version=19.11 is default, aka 2017, 15.3 +    MSVT = VersionTuple(19, 11); +  } +  return MSVT; +} + +std::string +MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, +                                           types::ID InputType) const { +  // The MSVC version doesn't care about the architecture, even though it +  // may look at the triple internally. +  VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); +  MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0), +                      MSVT.getSubminor().getValueOr(0)); + +  // For the rest of the triple, however, a computed architecture name may +  // be needed. +  llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType)); +  if (Triple.getEnvironment() == llvm::Triple::MSVC) { +    StringRef ObjFmt = Triple.getEnvironmentName().split('-').second; +    if (ObjFmt.empty()) +      Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str()); +    else +      Triple.setEnvironmentName( +          (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str()); +  } +  return Triple.getTriple(); +} + +SanitizerMask MSVCToolChain::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Fuzzer; +  Res |= SanitizerKind::FuzzerNoLink; +  Res &= ~SanitizerKind::CFIMFCall; +  return Res; +} + +static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, +                            bool SupportsForcingFramePointer, +                            const char *ExpandChar, const OptTable &Opts) { +  assert(A->getOption().matches(options::OPT__SLASH_O)); + +  StringRef OptStr = A->getValue(); +  for (size_t I = 0, E = OptStr.size(); I != E; ++I) { +    const char &OptChar = *(OptStr.data() + I); +    switch (OptChar) { +    default: +      break; +    case '1': +    case '2': +    case 'x': +    case 'd': +      // Ignore /O[12xd] flags that aren't the last one on the command line. +      // Only the last one gets expanded. +      if (&OptChar != ExpandChar) { +        A->claim(); +        break; +      } +      if (OptChar == 'd') { +        DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); +      } else { +        if (OptChar == '1') { +          DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); +        } else if (OptChar == '2' || OptChar == 'x') { +          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); +          DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); +        } +        if (SupportsForcingFramePointer && +            !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) +          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); +        if (OptChar == '1' || OptChar == '2') +          DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); +      } +      break; +    case 'b': +      if (I + 1 != E && isdigit(OptStr[I + 1])) { +        switch (OptStr[I + 1]) { +        case '0': +          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); +          break; +        case '1': +          DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); +          break; +        case '2': +          DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); +          break; +        } +        ++I; +      } +      break; +    case 'g': +      A->claim(); +      break; +    case 'i': +      if (I + 1 != E && OptStr[I + 1] == '-') { +        ++I; +        DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); +      } else { +        DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); +      } +      break; +    case 's': +      DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); +      break; +    case 't': +      DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); +      break; +    case 'y': { +      bool OmitFramePointer = true; +      if (I + 1 != E && OptStr[I + 1] == '-') { +        OmitFramePointer = false; +        ++I; +      } +      if (SupportsForcingFramePointer) { +        if (OmitFramePointer) +          DAL.AddFlagArg(A, +                         Opts.getOption(options::OPT_fomit_frame_pointer)); +        else +          DAL.AddFlagArg( +              A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); +      } else { +        // Don't warn about /Oy- in x86-64 builds (where +        // SupportsForcingFramePointer is false).  The flag having no effect +        // there is a compiler-internal optimization, and people shouldn't have +        // to special-case their build files for x86-64 clang-cl. +        A->claim(); +      } +      break; +    } +    } +  } +} + +static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, +                          const OptTable &Opts) { +  assert(A->getOption().matches(options::OPT_D)); + +  StringRef Val = A->getValue(); +  size_t Hash = Val.find('#'); +  if (Hash == StringRef::npos || Hash > Val.find('=')) { +    DAL.append(A); +    return; +  } + +  std::string NewVal = Val; +  NewVal[Hash] = '='; +  DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal); +} + +llvm::opt::DerivedArgList * +MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, +                             StringRef BoundArch, Action::OffloadKind) const { +  DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); +  const OptTable &Opts = getDriver().getOpts(); + +  // /Oy and /Oy- don't have an effect on X86-64 +  bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64; + +  // The -O[12xd] flag actually expands to several flags.  We must desugar the +  // flags so that options embedded can be negated.  For example, the '-O2' flag +  // enables '-Oy'.  Expanding '-O2' into its constituent flags allows us to +  // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single +  // aspect of '-O2'. +  // +  // Note that this expansion logic only applies to the *last* of '[12xd]'. + +  // First step is to search for the character we'd like to expand. +  const char *ExpandChar = nullptr; +  for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { +    StringRef OptStr = A->getValue(); +    for (size_t I = 0, E = OptStr.size(); I != E; ++I) { +      char OptChar = OptStr[I]; +      char PrevChar = I > 0 ? OptStr[I - 1] : '0'; +      if (PrevChar == 'b') { +        // OptChar does not expand; it's an argument to the previous char. +        continue; +      } +      if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') +        ExpandChar = OptStr.data() + I; +    } +  } + +  for (Arg *A : Args) { +    if (A->getOption().matches(options::OPT__SLASH_O)) { +      // The -O flag actually takes an amalgam of other options.  For example, +      // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. +      TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts); +    } else if (A->getOption().matches(options::OPT_D)) { +      // Translate -Dfoo#bar into -Dfoo=bar. +      TranslateDArg(A, *DAL, Opts); +    } else { +      DAL->append(A); +    } +  } + +  return DAL; +} diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h new file mode 100644 index 0000000000000..41a69a82fecfe --- /dev/null +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -0,0 +1,164 @@ +//===--- MSVC.h - MSVC ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H + +#include "Cuda.h" +#include "clang/Basic/DebugInfoOptions.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// Visual studio tools. +namespace visualstudio { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) +      : Tool("visualstudio::Linker", "linker", TC, RF_Full, +             llvm::sys::WEM_UTF16) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { +public: +  Compiler(const ToolChain &TC) +      : Tool("visualstudio::Compiler", "compiler", TC, RF_Full, +             llvm::sys::WEM_UTF16) {} + +  bool hasIntegratedAssembler() const override { return true; } +  bool hasIntegratedCPP() const override { return true; } +  bool isLinkJob() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; + +  std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA, +                                      const InputInfo &Output, +                                      const InputInfoList &Inputs, +                                      const llvm::opt::ArgList &TCArgs, +                                      const char *LinkingOutput) const; +}; +} // end namespace visualstudio + +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { +public: +  MSVCToolChain(const Driver &D, const llvm::Triple &Triple, +                const llvm::opt::ArgList &Args); + +  llvm::opt::DerivedArgList * +  TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, +                Action::OffloadKind DeviceOffloadKind) const override; + +  bool IsIntegratedAssemblerDefault() const override; +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; + +  /// Set CodeView as the default debug info format for non-MachO binary +  /// formats, and to DWARF otherwise. Users can use -gcodeview and -gdwarf to +  /// override the default. +  codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { +    return getTriple().isOSBinFormatMachO() ? codegenoptions::DIF_DWARF +                                            : codegenoptions::DIF_CodeView; +  } + +  /// Set the debugger tuning to "default", since we're definitely not tuning +  /// for GDB. +  llvm::DebuggerKind getDefaultDebuggerTuning() const override { +    return llvm::DebuggerKind::Default; +  } + +  enum class SubDirectoryType { +    Bin, +    Include, +    Lib, +  }; +  std::string getSubDirectoryPath(SubDirectoryType Type, +                                  llvm::StringRef SubdirParent, +                                  llvm::Triple::ArchType TargetArch) const; + +  // Convenience overload. +  // Uses the current target arch. +  std::string getSubDirectoryPath(SubDirectoryType Type, +                                  llvm::StringRef SubdirParent = "") const { +    return getSubDirectoryPath(Type, SubdirParent, getArch()); +  } + +  enum class ToolsetLayout { +    OlderVS, +    VS2017OrNewer, +    DevDivInternal, +  }; +  bool getIsVS2017OrNewer() const { return VSLayout == ToolsetLayout::VS2017OrNewer; } + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const override; + +  bool getWindowsSDKLibraryPath(std::string &path) const; +  /// Check if Universal CRT should be used if available +  bool getUniversalCRTLibraryPath(std::string &path) const; +  bool useUniversalCRT() const; +  VersionTuple +  computeMSVCVersion(const Driver *D, +                     const llvm::opt::ArgList &Args) const override; + +  std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, +                                          types::ID InputType) const override; +  SanitizerMask getSupportedSanitizers() const override; + +  void printVerboseInfo(raw_ostream &OS) const override; + +  bool FoundMSVCInstall() const { return !VCToolChainPath.empty(); } + +protected: +  void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, +                                     llvm::opt::ArgStringList &CC1Args, +                                     const std::string &folder, +                                     const Twine &subfolder1, +                                     const Twine &subfolder2 = "", +                                     const Twine &subfolder3 = "") const; + +  Tool *buildLinker() const override; +  Tool *buildAssembler() const override; +private: +  std::string VCToolChainPath; +  ToolsetLayout VSLayout = ToolsetLayout::OlderVS; +  CudaInstallationDetector CudaInstallation; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H diff --git a/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/clang/lib/Driver/ToolChains/MSVCSetupApi.h new file mode 100644 index 0000000000000..a890b85fd5e98 --- /dev/null +++ b/clang/lib/Driver/ToolChains/MSVCSetupApi.h @@ -0,0 +1,514 @@ +// <copyright file="Program.cpp" company="Microsoft Corporation"> +// Copyright (C) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +// </copyright> +// <license> +// The MIT License (MIT) +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// </license> + +#pragma once + +// Constants +// +#ifndef E_NOTFOUND +#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) +#endif + +#ifndef E_FILENOTFOUND +#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) +#endif + +// Enumerations +// +/// <summary> +/// The state of an instance. +/// </summary> +enum InstanceState : unsigned { +  /// <summary> +  /// The instance state has not been determined. +  /// </summary> +  eNone = 0, + +  /// <summary> +  /// The instance installation path exists. +  /// </summary> +  eLocal = 1, + +  /// <summary> +  /// A product is registered to the instance. +  /// </summary> +  eRegistered = 2, + +  /// <summary> +  /// No reboot is required for the instance. +  /// </summary> +  eNoRebootRequired = 4, + +  /// <summary> +  /// The instance represents a complete install. +  /// </summary> +  eComplete = MAXUINT, +}; + +// Forward interface declarations +// +#ifndef __ISetupInstance_FWD_DEFINED__ +#define __ISetupInstance_FWD_DEFINED__ +typedef struct ISetupInstance ISetupInstance; +#endif + +#ifndef __ISetupInstance2_FWD_DEFINED__ +#define __ISetupInstance2_FWD_DEFINED__ +typedef struct ISetupInstance2 ISetupInstance2; +#endif + +#ifndef __IEnumSetupInstances_FWD_DEFINED__ +#define __IEnumSetupInstances_FWD_DEFINED__ +typedef struct IEnumSetupInstances IEnumSetupInstances; +#endif + +#ifndef __ISetupConfiguration_FWD_DEFINED__ +#define __ISetupConfiguration_FWD_DEFINED__ +typedef struct ISetupConfiguration ISetupConfiguration; +#endif + +#ifndef __ISetupConfiguration2_FWD_DEFINED__ +#define __ISetupConfiguration2_FWD_DEFINED__ +typedef struct ISetupConfiguration2 ISetupConfiguration2; +#endif + +#ifndef __ISetupPackageReference_FWD_DEFINED__ +#define __ISetupPackageReference_FWD_DEFINED__ +typedef struct ISetupPackageReference ISetupPackageReference; +#endif + +#ifndef __ISetupHelper_FWD_DEFINED__ +#define __ISetupHelper_FWD_DEFINED__ +typedef struct ISetupHelper ISetupHelper; +#endif + +// Forward class declarations +// +#ifndef __SetupConfiguration_FWD_DEFINED__ +#define __SetupConfiguration_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class SetupConfiguration SetupConfiguration; +#endif + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Interface definitions +// +EXTERN_C const IID IID_ISetupInstance; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// Information about an instance of a product. +/// </summary> +struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") +    DECLSPEC_NOVTABLE ISetupInstance : public IUnknown { +  /// <summary> +  /// Gets the instance identifier (should match the name of the parent instance +  /// directory). +  /// </summary> +  /// <param name="pbstrInstanceId">The instance identifier.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist.</returns> +  STDMETHOD(GetInstanceId)(_Out_ BSTR *pbstrInstanceId) = 0; + +  /// <summary> +  /// Gets the local date and time when the installation was originally +  /// installed. +  /// </summary> +  /// <param name="pInstallDate">The local date and time when the installation +  /// was originally installed.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0; + +  /// <summary> +  /// Gets the unique name of the installation, often indicating the branch and +  /// other information used for telemetry. +  /// </summary> +  /// <param name="pbstrInstallationName">The unique name of the installation, +  /// often indicating the branch and other information used for +  /// telemetry.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(GetInstallationName)(_Out_ BSTR *pbstrInstallationName) = 0; + +  /// <summary> +  /// Gets the path to the installation root of the product. +  /// </summary> +  /// <param name="pbstrInstallationPath">The path to the installation root of +  /// the product.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(GetInstallationPath)(_Out_ BSTR *pbstrInstallationPath) = 0; + +  /// <summary> +  /// Gets the version of the product installed in this instance. +  /// </summary> +  /// <param name="pbstrInstallationVersion">The version of the product +  /// installed in this instance.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(GetInstallationVersion)(_Out_ BSTR *pbstrInstallationVersion) = 0; + +  /// <summary> +  /// Gets the display name (title) of the product installed in this instance. +  /// </summary> +  /// <param name="lcid">The LCID for the display name.</param> +  /// <param name="pbstrDisplayName">The display name (title) of the product +  /// installed in this instance.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0; + +  /// <summary> +  /// Gets the description of the product installed in this instance. +  /// </summary> +  /// <param name="lcid">The LCID for the description.</param> +  /// <param name="pbstrDescription">The description of the product installed in +  /// this instance.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0; + +  /// <summary> +  /// Resolves the optional relative path to the root path of the instance. +  /// </summary> +  /// <param name="pwszRelativePath">A relative path within the instance to +  /// resolve, or NULL to get the root path.</param> +  /// <param name="pbstrAbsolutePath">The full path to the optional relative +  /// path within the instance. If the relative path is NULL, the root path will +  /// always terminate in a backslash.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// property is not defined.</returns> +  STDMETHOD(ResolvePath) +  (_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupInstance2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// Information about an instance of a product. +/// </summary> +struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") +    DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance { +  /// <summary> +  /// Gets the state of the instance. +  /// </summary> +  /// <param name="pState">The state of the instance.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist.</returns> +  STDMETHOD(GetState)(_Out_ InstanceState *pState) = 0; + +  /// <summary> +  /// Gets an array of package references registered to the instance. +  /// </summary> +  /// <param name="ppsaPackages">Pointer to an array of <see +  /// cref="ISetupPackageReference"/>.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// packages property is not defined.</returns> +  STDMETHOD(GetPackages)(_Out_ LPSAFEARRAY *ppsaPackages) = 0; + +  /// <summary> +  /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents +  /// the registered product. +  /// </summary> +  /// <param name="ppPackage">Pointer to an instance of <see +  /// cref="ISetupPackageReference"/>. This may be NULL if <see +  /// cref="GetState"/> does not return <see cref="eComplete"/>.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the +  /// packages property is not defined.</returns> +  STDMETHOD(GetProduct) +  (_Outptr_result_maybenull_ ISetupPackageReference **ppPackage) = 0; + +  /// <summary> +  /// Gets the relative path to the product application, if available. +  /// </summary> +  /// <param name="pbstrProductPath">The relative path to the product +  /// application, if available.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_FILENOTFOUND if the instance state does not exist.</returns> +  STDMETHOD(GetProductPath) +  (_Outptr_result_maybenull_ BSTR *pbstrProductPath) = 0; +}; +#endif + +EXTERN_C const IID IID_IEnumSetupInstances; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// A enumerator of installed <see cref="ISetupInstance"/> objects. +/// </summary> +struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") +    DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown { +  /// <summary> +  /// Retrieves the next set of product instances in the enumeration sequence. +  /// </summary> +  /// <param name="celt">The number of product instances to retrieve.</param> +  /// <param name="rgelt">A pointer to an array of <see +  /// cref="ISetupInstance"/>.</param> +  /// <param name="pceltFetched">A pointer to the number of product instances +  /// retrieved. If celt is 1 this parameter may be NULL.</param> +  /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing +  /// was fetched (at end of enumeration), E_INVALIDARG if celt is greater than +  /// 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see +  /// cref="ISetupInstance"/> could not be allocated.</returns> +  STDMETHOD(Next) +  (_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt, +   _Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0; + +  /// <summary> +  /// Skips the next set of product instances in the enumeration sequence. +  /// </summary> +  /// <param name="celt">The number of product instances to skip.</param> +  /// <returns>S_OK if the number of elements could be skipped; otherwise, +  /// S_FALSE;</returns> +  STDMETHOD(Skip)(_In_ ULONG celt) = 0; + +  /// <summary> +  /// Resets the enumeration sequence to the beginning. +  /// </summary> +  /// <returns>Always returns S_OK;</returns> +  STDMETHOD(Reset)(void) = 0; + +  /// <summary> +  /// Creates a new enumeration object in the same state as the current +  /// enumeration object: the new object points to the same place in the +  /// enumeration sequence. +  /// </summary> +  /// <param name="ppenum">A pointer to a pointer to a new <see +  /// cref="IEnumSetupInstances"/> interface. If the method fails, this +  /// parameter is undefined.</param> +  /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns> +  STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupConfiguration; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// Gets information about product instances set up on the machine. +/// </summary> +struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") +    DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown { +  /// <summary> +  /// Enumerates all completed product instances installed. +  /// </summary> +  /// <param name="ppEnumInstances">An enumeration of completed, installed +  /// product instances.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; + +  /// <summary> +  /// Gets the instance for the current process path. +  /// </summary> +  /// <param name="ppInstance">The instance for the current process +  /// path.</param> +  /// <returns>The instance for the current process path, or E_NOTFOUND if not +  /// found.</returns> +  STDMETHOD(GetInstanceForCurrentProcess) +  (_Out_ ISetupInstance **ppInstance) = 0; + +  /// <summary> +  /// Gets the instance for the given path. +  /// </summary> +  /// <param name="ppInstance">The instance for the given path.</param> +  /// <returns>The instance for the given path, or E_NOTFOUND if not +  /// found.</returns> +  STDMETHOD(GetInstanceForPath) +  (_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupConfiguration2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// Gets information about product instances. +/// </summary> +struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") +    DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration { +  /// <summary> +  /// Enumerates all product instances. +  /// </summary> +  /// <param name="ppEnumInstances">An enumeration of all product +  /// instances.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(EnumAllInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupPackageReference; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// A reference to a package. +/// </summary> +struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") +    DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown { +  /// <summary> +  /// Gets the general package identifier. +  /// </summary> +  /// <param name="pbstrId">The general package identifier.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(GetId)(_Out_ BSTR *pbstrId) = 0; + +  /// <summary> +  /// Gets the version of the package. +  /// </summary> +  /// <param name="pbstrVersion">The version of the package.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(GetVersion)(_Out_ BSTR *pbstrVersion) = 0; + +  /// <summary> +  /// Gets the target process architecture of the package. +  /// </summary> +  /// <param name="pbstrChip">The target process architecture of the +  /// package.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(GetChip)(_Out_ BSTR *pbstrChip) = 0; + +  /// <summary> +  /// Gets the language and optional region identifier. +  /// </summary> +  /// <param name="pbstrLanguage">The language and optional region +  /// identifier.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(GetLanguage)(_Out_ BSTR *pbstrLanguage) = 0; + +  /// <summary> +  /// Gets the build branch of the package. +  /// </summary> +  /// <param name="pbstrBranch">The build branch of the package.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(GetBranch)(_Out_ BSTR *pbstrBranch) = 0; + +  /// <summary> +  /// Gets the type of the package. +  /// </summary> +  /// <param name="pbstrType">The type of the package.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(GetType)(_Out_ BSTR *pbstrType) = 0; + +  /// <summary> +  /// Gets the unique identifier consisting of all defined tokens. +  /// </summary> +  /// <param name="pbstrUniqueId">The unique identifier consisting of all +  /// defined tokens.</param> +  /// <returns>Standard HRESULT indicating success or failure, including +  /// E_UNEXPECTED if no Id was defined (required).</returns> +  STDMETHOD(GetUniqueId)(_Out_ BSTR *pbstrUniqueId) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// <summary> +/// Helper functions. +/// </summary> +/// <remarks> +/// You can query for this interface from the <see cref="SetupConfiguration"/> +/// class. +/// </remarks> +struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") +    DECLSPEC_NOVTABLE ISetupHelper : public IUnknown { +  /// <summary> +  /// Parses a dotted quad version string into a 64-bit unsigned integer. +  /// </summary> +  /// <param name="pwszVersion">The dotted quad version string to parse, e.g. +  /// 1.2.3.4.</param> +  /// <param name="pullVersion">A 64-bit unsigned integer representing the +  /// version. You can compare this to other versions.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(ParseVersion) +  (_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0; + +  /// <summary> +  /// Parses a dotted quad version string into a 64-bit unsigned integer. +  /// </summary> +  /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad +  /// version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param> +  /// <param name="pullMinVersion">A 64-bit unsigned integer representing the +  /// minimum version, which may be 0. You can compare this to other +  /// versions.</param> +  /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the +  /// maximum version, which may be MAXULONGLONG. You can compare this to other +  /// versions.</param> +  /// <returns>Standard HRESULT indicating success or failure.</returns> +  STDMETHOD(ParseVersionRange) +  (_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion, +   _Out_ PULONGLONG pullMaxVersion) = 0; +}; +#endif + +// Class declarations +// +EXTERN_C const CLSID CLSID_SetupConfiguration; + +#ifdef __cplusplus +/// <summary> +/// This class implements <see cref="ISetupConfiguration"/>, <see +/// cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>. +/// </summary> +class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration; +#endif + +// Function declarations +// +/// <summary> +/// Gets an <see cref="ISetupConfiguration"/> that provides information about +/// product instances installed on the machine. +/// </summary> +/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that +/// provides information about product instances installed on the +/// machine.</param> +/// <param name="pReserved">Reserved for future use.</param> +/// <returns>Standard HRESULT indicating success or failure.</returns> +STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration, +                                   _Reserved_ LPVOID pReserved); + +#ifdef __cplusplus +} +#endif diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp new file mode 100644 index 0000000000000..0d851114c225b --- /dev/null +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -0,0 +1,576 @@ +//===--- MinGW.cpp - MinGWToolChain Implementation ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MinGW.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include <system_error> + +using namespace clang::diag; +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +/// MinGW Tools +void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  if (getToolChain().getArch() == llvm::Triple::x86) { +    CmdArgs.push_back("--32"); +  } else if (getToolChain().getArch() == llvm::Triple::x86_64) { +    CmdArgs.push_back("--64"); +  } + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + +  if (Args.hasArg(options::OPT_gsplit_dwarf)) +    SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, +                   SplitDebugName(Args, Inputs[0], Output)); +} + +void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, +                                     ArgStringList &CmdArgs) const { +  if (Args.hasArg(options::OPT_mthreads)) +    CmdArgs.push_back("-lmingwthrd"); +  CmdArgs.push_back("-lmingw32"); + +  // Make use of compiler-rt if --rtlib option is used +  ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); +  if (RLT == ToolChain::RLT_Libgcc) { +    bool Static = Args.hasArg(options::OPT_static_libgcc) || +                  Args.hasArg(options::OPT_static); +    bool Shared = Args.hasArg(options::OPT_shared); +    bool CXX = getToolChain().getDriver().CCCIsCXX(); + +    if (Static || (!CXX && !Shared)) { +      CmdArgs.push_back("-lgcc"); +      CmdArgs.push_back("-lgcc_eh"); +    } else { +      CmdArgs.push_back("-lgcc_s"); +      CmdArgs.push_back("-lgcc"); +    } +  } else { +    AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); +  } + +  CmdArgs.push_back("-lmoldname"); +  CmdArgs.push_back("-lmingwex"); +  for (auto Lib : Args.getAllArgValues(options::OPT_l)) +    if (StringRef(Lib).startswith("msvcr") || StringRef(Lib).startswith("ucrt")) +      return; +  CmdArgs.push_back("-lmsvcrt"); +} + +void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                        const InputInfo &Output, +                                        const InputInfoList &Inputs, +                                        const ArgList &Args, +                                        const char *LinkingOutput) const { +  const ToolChain &TC = getToolChain(); +  const Driver &D = TC.getDriver(); +  const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); + +  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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("-s"); + +  CmdArgs.push_back("-m"); +  switch (TC.getArch()) { +  case llvm::Triple::x86: +    CmdArgs.push_back("i386pe"); +    break; +  case llvm::Triple::x86_64: +    CmdArgs.push_back("i386pep"); +    break; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    // FIXME: this is incorrect for WinCE +    CmdArgs.push_back("thumb2pe"); +    break; +  case llvm::Triple::aarch64: +    CmdArgs.push_back("arm64pe"); +    break; +  default: +    llvm_unreachable("Unsupported target architecture."); +  } + +  if (Args.hasArg(options::OPT_mwindows)) { +    CmdArgs.push_back("--subsystem"); +    CmdArgs.push_back("windows"); +  } else if (Args.hasArg(options::OPT_mconsole)) { +    CmdArgs.push_back("--subsystem"); +    CmdArgs.push_back("console"); +  } + +  if (Args.hasArg(options::OPT_mdll)) +    CmdArgs.push_back("--dll"); +  else if (Args.hasArg(options::OPT_shared)) +    CmdArgs.push_back("--shared"); +  if (Args.hasArg(options::OPT_static)) +    CmdArgs.push_back("-Bstatic"); +  else +    CmdArgs.push_back("-Bdynamic"); +  if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) { +    CmdArgs.push_back("-e"); +    if (TC.getArch() == llvm::Triple::x86) +      CmdArgs.push_back("_DllMainCRTStartup@12"); +    else +      CmdArgs.push_back("DllMainCRTStartup"); +    CmdArgs.push_back("--enable-auto-image-base"); +  } + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  Args.AddAllArgs(CmdArgs, options::OPT_e); +  // FIXME: add -N, -n flags +  Args.AddLastArg(CmdArgs, options::OPT_r); +  Args.AddLastArg(CmdArgs, options::OPT_s); +  Args.AddLastArg(CmdArgs, options::OPT_t); +  Args.AddAllArgs(CmdArgs, options::OPT_u_Group); +  Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { +      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o"))); +    } else { +      if (Args.hasArg(options::OPT_municode)) +        CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o"))); +      else +        CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o"))); +    } +    if (Args.hasArg(options::OPT_pg)) +      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o"))); +    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  TC.AddFilePathLibArgs(Args, CmdArgs); +  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + +  // TODO: Add profile stuff here + +  if (TC.ShouldLinkCXXStdlib(Args)) { +    bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && +                               !Args.hasArg(options::OPT_static); +    if (OnlyLibstdcxxStatic) +      CmdArgs.push_back("-Bstatic"); +    TC.AddCXXStdlibLibArgs(Args, CmdArgs); +    if (OnlyLibstdcxxStatic) +      CmdArgs.push_back("-Bdynamic"); +  } + +  bool HasWindowsApp = false; +  for (auto Lib : Args.getAllArgValues(options::OPT_l)) { +    if (Lib == "windowsapp") { +      HasWindowsApp = true; +      break; +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib)) { +    if (!Args.hasArg(options::OPT_nodefaultlibs)) { +      if (Args.hasArg(options::OPT_static)) +        CmdArgs.push_back("--start-group"); + +      if (Args.hasArg(options::OPT_fstack_protector) || +          Args.hasArg(options::OPT_fstack_protector_strong) || +          Args.hasArg(options::OPT_fstack_protector_all)) { +        CmdArgs.push_back("-lssp_nonshared"); +        CmdArgs.push_back("-lssp"); +      } + +      if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, +                       options::OPT_fno_openmp, false)) { +        switch (TC.getDriver().getOpenMPRuntime(Args)) { +        case Driver::OMPRT_OMP: +          CmdArgs.push_back("-lomp"); +          break; +        case Driver::OMPRT_IOMP5: +          CmdArgs.push_back("-liomp5md"); +          break; +        case Driver::OMPRT_GOMP: +          CmdArgs.push_back("-lgomp"); +          break; +        case Driver::OMPRT_Unknown: +          // Already diagnosed. +          break; +        } +      } + +      AddLibGCC(Args, CmdArgs); + +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lgmon"); + +      if (Args.hasArg(options::OPT_pthread)) +        CmdArgs.push_back("-lpthread"); + +      if (Sanitize.needsAsanRt()) { +        // MinGW always links against a shared MSVCRT. +        CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic", +                                                    ToolChain::FT_Shared)); +        CmdArgs.push_back( +            TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk")); +        CmdArgs.push_back("--require-defined"); +        CmdArgs.push_back(TC.getArch() == llvm::Triple::x86 +                              ? "___asan_seh_interceptor" +                              : "__asan_seh_interceptor"); +        // Make sure the linker consider all object files from the dynamic +        // runtime thunk. +        CmdArgs.push_back("--whole-archive"); +        CmdArgs.push_back( +            TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk")); +        CmdArgs.push_back("--no-whole-archive"); +      } + +      TC.addProfileRTLibs(Args, CmdArgs); + +      if (!HasWindowsApp) { +        // Add system libraries. If linking to libwindowsapp.a, that import +        // library replaces all these and we shouldn't accidentally try to +        // link to the normal desktop mode dlls. +        if (Args.hasArg(options::OPT_mwindows)) { +          CmdArgs.push_back("-lgdi32"); +          CmdArgs.push_back("-lcomdlg32"); +        } +        CmdArgs.push_back("-ladvapi32"); +        CmdArgs.push_back("-lshell32"); +        CmdArgs.push_back("-luser32"); +        CmdArgs.push_back("-lkernel32"); +      } + +      if (Args.hasArg(options::OPT_static)) +        CmdArgs.push_back("--end-group"); +      else +        AddLibGCC(Args, CmdArgs); +    } + +    if (!Args.hasArg(options::OPT_nostartfiles)) { +      // Add crtfastmath.o if available and fast math is enabled. +      TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs); + +      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); +    } +  } +  const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. +static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, +                           std::string &Ver) { +  auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); +  std::error_code EC; +  for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; +       LI = LI.increment(EC)) { +    StringRef VersionText = llvm::sys::path::filename(LI->path()); +    auto CandidateVersion = +        toolchains::Generic_GCC::GCCVersion::Parse(VersionText); +    if (CandidateVersion.Major == -1) +      continue; +    if (CandidateVersion <= Version) +      continue; +    Ver = VersionText; +    GccLibDir = LI->path(); +  } +  return Ver.size(); +} + +void toolchains::MinGW::findGccLibDir() { +  llvm::SmallVector<llvm::SmallString<32>, 2> Archs; +  Archs.emplace_back(getTriple().getArchName()); +  Archs[0] += "-w64-mingw32"; +  Archs.emplace_back("mingw32"); +  if (Arch.empty()) +    Arch = Archs[0].str(); +  // lib: Arch Linux, Ubuntu, Windows +  // lib64: openSUSE Linux +  for (StringRef CandidateLib : {"lib", "lib64"}) { +    for (StringRef CandidateArch : Archs) { +      llvm::SmallString<1024> LibDir(Base); +      llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); +      if (findGccVersion(LibDir, GccLibDir, Ver)) { +        Arch = CandidateArch; +        return; +      } +    } +  } +} + +llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { +  llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; +  Gccs.emplace_back(getTriple().getArchName()); +  Gccs[0] += "-w64-mingw32-gcc"; +  Gccs.emplace_back("mingw32-gcc"); +  // Please do not add "gcc" here +  for (StringRef CandidateGcc : Gccs) +    if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc)) +      return GPPName; +  return make_error_code(std::errc::no_such_file_or_directory); +} + +llvm::ErrorOr<std::string> toolchains::MinGW::findClangRelativeSysroot() { +  llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs; +  Subdirs.emplace_back(getTriple().str()); +  Subdirs.emplace_back(getTriple().getArchName()); +  Subdirs[1] += "-w64-mingw32"; +  StringRef ClangRoot = +      llvm::sys::path::parent_path(getDriver().getInstalledDir()); +  StringRef Sep = llvm::sys::path::get_separator(); +  for (StringRef CandidateSubdir : Subdirs) { +    if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { +      Arch = CandidateSubdir; +      return (ClangRoot + Sep + CandidateSubdir).str(); +    } +  } +  return make_error_code(std::errc::no_such_file_or_directory); +} + +toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, +                         const ArgList &Args) +    : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { +  getProgramPaths().push_back(getDriver().getInstalledDir()); + +  if (getDriver().SysRoot.size()) +    Base = getDriver().SysRoot; +  // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the +  // base as it could still be a base for a gcc setup with libgcc. +  else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot()) +    Base = llvm::sys::path::parent_path(TargetSubdir.get()); +  else if (llvm::ErrorOr<std::string> GPPName = findGcc()) +    Base = llvm::sys::path::parent_path( +        llvm::sys::path::parent_path(GPPName.get())); +  else +    Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); + +  Base += llvm::sys::path::get_separator(); +  findGccLibDir(); +  // GccLibDir must precede Base/lib so that the +  // correct crtbegin.o ,cetend.o would be found. +  getFilePaths().push_back(GccLibDir); +  getFilePaths().push_back( +      (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); +  getFilePaths().push_back(Base + "lib"); +  // openSUSE +  getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); + +  NativeLLVMSupport = +      Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) +          .equals_lower("lld"); +} + +bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; } + +Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { +  switch (AC) { +  case Action::PreprocessJobClass: +    if (!Preprocessor) +      Preprocessor.reset(new tools::gcc::Preprocessor(*this)); +    return Preprocessor.get(); +  case Action::CompileJobClass: +    if (!Compiler) +      Compiler.reset(new tools::gcc::Compiler(*this)); +    return Compiler.get(); +  default: +    return ToolChain::getTool(AC); +  } +} + +Tool *toolchains::MinGW::buildAssembler() const { +  return new tools::MinGW::Assembler(*this); +} + +Tool *toolchains::MinGW::buildLinker() const { +  return new tools::MinGW::Linker(*this); +} + +bool toolchains::MinGW::HasNativeLLVMSupport() const { +  return NativeLLVMSupport; +} + +bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { +  Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions, +                                      options::OPT_fseh_exceptions, +                                      options::OPT_fdwarf_exceptions); +  if (ExceptionArg && +      ExceptionArg->getOption().matches(options::OPT_fseh_exceptions)) +    return true; +  return getArch() == llvm::Triple::x86_64 || +         getArch() == llvm::Triple::aarch64; +} + +bool toolchains::MinGW::isPICDefault() const { +  return getArch() == llvm::Triple::x86_64; +} + +bool toolchains::MinGW::isPIEDefault() const { return false; } + +bool toolchains::MinGW::isPICDefaultForced() const { +  return getArch() == llvm::Triple::x86_64; +} + +llvm::ExceptionHandling +toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { +  if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64) +    return llvm::ExceptionHandling::WinEH; +  return llvm::ExceptionHandling::DwarfCFI; +} + +SanitizerMask toolchains::MinGW::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  return Res; +} + +void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, +                                           ArgStringList &CC1Args) const { +  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { +  CudaInstallation.print(OS); +} + +// Include directories for various hosts: + +// Windows, mingw.org +// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++ +// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32 +// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward +// c:\mingw\include +// c:\mingw\mingw32\include + +// Windows, mingw-w64 mingw-builds +// c:\mingw32\i686-w64-mingw32\include +// c:\mingw32\i686-w64-mingw32\include\c++ +// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32 +// c:\mingw32\i686-w64-mingw32\include\c++\backward + +// Windows, mingw-w64 msys2 +// c:\msys64\mingw32\include +// c:\msys64\mingw32\i686-w64-mingw32\include +// c:\msys64\mingw32\include\c++\4.9.2 +// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32 +// c:\msys64\mingw32\include\c++\4.9.2\backward + +// openSUSE +// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++ +// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32 +// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward +// /usr/x86_64-w64-mingw32/sys-root/mingw/include + +// Arch Linux +// /usr/i686-w64-mingw32/include/c++/5.1.0 +// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32 +// /usr/i686-w64-mingw32/include/c++/5.1.0/backward +// /usr/i686-w64-mingw32/include + +// Ubuntu +// /usr/include/c++/4.8 +// /usr/include/c++/4.8/x86_64-w64-mingw32 +// /usr/include/c++/4.8/backward +// /usr/x86_64-w64-mingw32/include + +void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                                  ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<1024> P(getDriver().ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { +    // openSUSE +    addSystemInclude(DriverArgs, CC1Args, +                     Base + Arch + "/sys-root/mingw/include"); +  } + +  addSystemInclude(DriverArgs, CC1Args, +                   Base + Arch + llvm::sys::path::get_separator() + "include"); +  addSystemInclude(DriverArgs, CC1Args, Base + "include"); +} + +void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  StringRef Slash = llvm::sys::path::get_separator(); + +  switch (GetCXXStdlibType(DriverArgs)) { +  case ToolChain::CST_Libcxx: +    addSystemInclude(DriverArgs, CC1Args, Base + Arch + Slash + "include" + +                                              Slash + "c++" + Slash + "v1"); +    addSystemInclude(DriverArgs, CC1Args, +                     Base + "include" + Slash + "c++" + Slash + "v1"); +    break; + +  case ToolChain::CST_Libstdcxx: +    llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases; +    CppIncludeBases.emplace_back(Base); +    llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); +    CppIncludeBases.emplace_back(Base); +    llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver); +    CppIncludeBases.emplace_back(Base); +    llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); +    CppIncludeBases.emplace_back(GccLibDir); +    llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); +    for (auto &CppIncludeBase : CppIncludeBases) { +      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); +      CppIncludeBase += Slash; +      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); +      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); +    } +    break; +  } +} diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h new file mode 100644 index 0000000000000..6752a405be879 --- /dev/null +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -0,0 +1,112 @@ +//===--- MinGW.h - MinGW ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H + +#include "Cuda.h" +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// MinGW -- Directly call GNU Binutils assembler and linker +namespace MinGW { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: +  Assembler(const ToolChain &TC) : Tool("MinGW::Assemble", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) +      : Tool("MinGW::Linker", "linker", TC, Tool::RF_Full) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; + +private: +  void AddLibGCC(const llvm::opt::ArgList &Args, +                 llvm::opt::ArgStringList &CmdArgs) const; +}; +} // end namespace MinGW +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { +public: +  MinGW(const Driver &D, const llvm::Triple &Triple, +        const llvm::opt::ArgList &Args); + +  bool HasNativeLLVMSupport() const override; + +  bool IsIntegratedAssemblerDefault() const override; +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; + +  SanitizerMask getSupportedSanitizers() const override; + +  llvm::ExceptionHandling GetExceptionModel( +      const llvm::opt::ArgList &Args) const override; + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                          llvm::opt::ArgStringList &CC1Args) const override; + +  void printVerboseInfo(raw_ostream &OS) const override; + +protected: +  Tool *getTool(Action::ActionClass AC) const override; +  Tool *buildLinker() const override; +  Tool *buildAssembler() const override; + +private: +  CudaInstallationDetector CudaInstallation; + +  std::string Base; +  std::string GccLibDir; +  std::string Ver; +  std::string Arch; +  mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; +  mutable std::unique_ptr<tools::gcc::Compiler> Compiler; +  void findGccLibDir(); +  llvm::ErrorOr<std::string> findGcc(); +  llvm::ErrorOr<std::string> findClangRelativeSysroot(); + +  bool NativeLLVMSupport; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H diff --git a/clang/lib/Driver/ToolChains/Minix.cpp b/clang/lib/Driver/ToolChains/Minix.cpp new file mode 100644 index 0000000000000..6947049ea52ee --- /dev/null +++ b/clang/lib/Driver/ToolChains/Minix.cpp @@ -0,0 +1,109 @@ +//===--- Minix.cpp - Minix ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Minix.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::minix::Linker::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; + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); +    CmdArgs.push_back( +        Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); +  } + +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_L, options::OPT_T_Group, options::OPT_e}); + +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  getToolChain().addProfileRTLibs(Args, CmdArgs); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (D.CCCIsCXX()) { +      if (getToolChain().ShouldLinkCXXStdlib(Args)) +        getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); +      CmdArgs.push_back("-lm"); +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_pthread)) +      CmdArgs.push_back("-lpthread"); +    CmdArgs.push_back("-lc"); +    CmdArgs.push_back("-lCompilerRT-Generic"); +    CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); +    CmdArgs.push_back( +        Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); +  } + +  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// Minix - Minix tool chain which can call as(1) and ld(1) directly. + +toolchains::Minix::Minix(const Driver &D, const llvm::Triple &Triple, +                         const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  getFilePaths().push_back(getDriver().Dir + "/../lib"); +  getFilePaths().push_back("/usr/lib"); +} + +Tool *toolchains::Minix::buildAssembler() const { +  return new tools::minix::Assembler(*this); +} + +Tool *toolchains::Minix::buildLinker() const { +  return new tools::minix::Linker(*this); +} diff --git a/clang/lib/Driver/ToolChains/Minix.h b/clang/lib/Driver/ToolChains/Minix.h new file mode 100644 index 0000000000000..1ed6acebab9c0 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Minix.h @@ -0,0 +1,65 @@ +//===--- Minix.h - Minix ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +/// minix -- Directly call GNU Binutils assembler and linker +namespace minix { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("minix::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("minix::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace minix +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { +public: +  Minix(const Driver &D, const llvm::Triple &Triple, +        const llvm::opt::ArgList &Args); + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H diff --git a/clang/lib/Driver/ToolChains/MipsLinux.cpp b/clang/lib/Driver/ToolChains/MipsLinux.cpp new file mode 100644 index 0000000000000..cfda7f4bb4dfd --- /dev/null +++ b/clang/lib/Driver/ToolChains/MipsLinux.cpp @@ -0,0 +1,140 @@ +//===-- MipsLinux.cpp - Mips ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MipsLinux.h" +#include "Arch/Mips.h" +#include "CommonArgs.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// Mips Toolchain +MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, +                                     const llvm::Triple &Triple, +                                     const ArgList &Args) +    : Linux(D, Triple, Args) { +  // Select the correct multilib according to the given arguments. +  DetectedMultilibs Result; +  findMIPSMultilibs(D, Triple, "", Args, Result); +  Multilibs = Result.Multilibs; +  SelectedMultilib = Result.SelectedMultilib; + +  // Find out the library suffix based on the ABI. +  LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); +  getFilePaths().clear(); +  getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix); +} + +void MipsLLVMToolChain::AddClangSystemIncludeArgs( +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  const Driver &D = getDriver(); + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  const auto &Callback = Multilibs.includeDirsCallback(); +  if (Callback) { +    for (const auto &Path : Callback(SelectedMultilib)) +      addExternCSystemIncludeIfExists(DriverArgs, CC1Args, +                                      D.getInstalledDir() + Path); +  } +} + +Tool *MipsLLVMToolChain::buildLinker() const { +  return new tools::gnutools::Linker(*this); +} + +std::string MipsLLVMToolChain::computeSysRoot() const { +  if (!getDriver().SysRoot.empty()) +    return getDriver().SysRoot + SelectedMultilib.osSuffix(); + +  const std::string InstalledDir(getDriver().getInstalledDir()); +  std::string SysRootPath = +      InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); +  if (llvm::sys::fs::exists(SysRootPath)) +    return SysRootPath; + +  return std::string(); +} + +ToolChain::CXXStdlibType +MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const { +  Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); +  if (A) { +    StringRef Value = A->getValue(); +    if (Value != "libc++") +      getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) +          << A->getAsString(Args); +  } + +  return ToolChain::CST_Libcxx; +} + +void MipsLLVMToolChain::addLibCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  if (const auto &Callback = Multilibs.includeDirsCallback()) { +    for (std::string Path : Callback(SelectedMultilib)) { +      Path = getDriver().getInstalledDir() + Path + "/c++/v1"; +      if (llvm::sys::fs::exists(Path)) { +        addSystemInclude(DriverArgs, CC1Args, Path); +        return; +      } +    } +  } +} + +void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, +                                            ArgStringList &CmdArgs) const { +  assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) && +         "Only -lc++ (aka libxx) is supported in this toolchain."); + +  CmdArgs.push_back("-lc++"); +  CmdArgs.push_back("-lc++abi"); +  CmdArgs.push_back("-lunwind"); +} + +std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, +                                             StringRef Component, +                                             FileType Type) const { +  SmallString<128> Path(getDriver().ResourceDir); +  llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, +                          getOS()); +  const char *Suffix; +  switch (Type) { +  case ToolChain::FT_Object: +    Suffix = ".o"; +    break; +  case ToolChain::FT_Static: +    Suffix = ".a"; +    break; +  case ToolChain::FT_Shared: +    Suffix = ".so"; +    break; +  } +  llvm::sys::path::append( +      Path, Twine("libclang_rt." + Component + "-" + "mips" + Suffix)); +  return Path.str(); +} diff --git a/clang/lib/Driver/ToolChains/MipsLinux.h b/clang/lib/Driver/ToolChains/MipsLinux.h new file mode 100644 index 0000000000000..31b547c0063ca --- /dev/null +++ b/clang/lib/Driver/ToolChains/MipsLinux.h @@ -0,0 +1,64 @@ +//===--- Mips.h - Mips ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_LINUX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_LINUX_H + +#include "Linux.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux { +protected: +  Tool *buildLinker() const override; + +public: +  MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple, +                    const llvm::opt::ArgList &Args); + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; + +  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  std::string +  getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, +                FileType Type = ToolChain::FT_Static) const override; + +  std::string computeSysRoot() const override; + +  RuntimeLibType GetDefaultRuntimeLibType() const override { +    return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc +                                     : RuntimeLibType::RLT_CompilerRT; +  } + +  const char *getDefaultLinker() const override { +    return "ld.lld"; +  } + +private: +  Multilib SelectedMultilib; +  std::string LibSuffix; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_LINUX_H diff --git a/clang/lib/Driver/ToolChains/Myriad.cpp b/clang/lib/Driver/ToolChains/Myriad.cpp new file mode 100644 index 0000000000000..2ce0f13ce3d1a --- /dev/null +++ b/clang/lib/Driver/ToolChains/Myriad.cpp @@ -0,0 +1,290 @@ +//===--- Myriad.cpp - Myriad ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Myriad.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +void tools::SHAVE::Compiler::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); +  const InputInfo &II = Inputs[0]; +  assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || +         II.getType() == types::TY_PP_CXX); + +  if (JA.getKind() == Action::PreprocessJobClass) { +    Args.ClaimAllArgs(); +    CmdArgs.push_back("-E"); +  } else { +    assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. +    CmdArgs.push_back("-S"); +    CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. +  } +  CmdArgs.push_back("-DMYRIAD2"); + +  // Append all -I, -iquote, -isystem paths, defines/undefines, 'f' +  // flags, 'g' flags, 'M' flags, optimize flags, warning options, +  // mcpu flags, mllvm flags, and Xclang flags. +  // These are spelled the same way in clang and moviCompile. +  Args.AddAllArgsExcept( +      CmdArgs, +      {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, +       options::OPT_D, options::OPT_U, options::OPT_f_Group, +       options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, +       options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ, +       options::OPT_mllvm, options::OPT_Xclang}, +      {options::OPT_fno_split_dwarf_inlining}); +  Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. + +  // If we're producing a dependency file, and assembly is the final action, +  // then the name of the target in the dependency file should be the '.o' +  // file, not the '.s' file produced by this step. For example, instead of +  //  /tmp/mumble.s: mumble.c .../someheader.h +  // the filename on the lefthand side should be "mumble.o" +  if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && +      C.getActions().size() == 1 && +      C.getActions()[0]->getKind() == Action::AssembleJobClass) { +    Arg *A = Args.getLastArg(options::OPT_o); +    if (A) { +      CmdArgs.push_back("-MT"); +      CmdArgs.push_back(Args.MakeArgString(A->getValue())); +    } +  } + +  CmdArgs.push_back(II.getFilename()); +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  std::string Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), +                                          CmdArgs, Inputs)); +} + +void tools::SHAVE::Assembler::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); +  const InputInfo &II = Inputs[0]; +  assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. +  assert(Output.getType() == types::TY_Object); + +  CmdArgs.push_back("-no6thSlotCompression"); +  const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); +  if (CPUArg) +    CmdArgs.push_back( +        Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); +  CmdArgs.push_back("-noSPrefixing"); +  CmdArgs.push_back("-a"); // Mystery option. +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); +  for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { +    A->claim(); +    CmdArgs.push_back( +        Args.MakeArgString(std::string("-i:") + A->getValue(0))); +  } +  CmdArgs.push_back(II.getFilename()); +  CmdArgs.push_back( +      Args.MakeArgString(std::string("-o:") + Output.getFilename())); + +  std::string Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), +                                          CmdArgs, Inputs)); +} + +void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                         const InputInfo &Output, +                                         const InputInfoList &Inputs, +                                         const ArgList &Args, +                                         const char *LinkingOutput) const { +  const auto &TC = +      static_cast<const toolchains::MyriadToolChain &>(getToolChain()); +  const llvm::Triple &T = TC.getTriple(); +  ArgStringList CmdArgs; +  bool UseStartfiles = +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); +  bool UseDefaultLibs = +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); +  // Silence warning if the args contain both -nostdlib and -stdlib=. +  Args.getLastArg(options::OPT_stdlib_EQ); + +  if (T.getArch() == llvm::Triple::sparc) +    CmdArgs.push_back("-EB"); +  else // SHAVE assumes little-endian, and sparcel is expressly so. +    CmdArgs.push_back("-EL"); + +  // The remaining logic is mostly like gnutools::Linker::ConstructJob, +  // but we never pass through a --sysroot option and various other bits. +  // For example, there are no sanitizers (yet) nor gold linker. + +  // Eat some arguments that may be present but have no effect. +  Args.ClaimAllArgs(options::OPT_g_Group); +  Args.ClaimAllArgs(options::OPT_w); +  Args.ClaimAllArgs(options::OPT_static_libgcc); + +  if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. +    CmdArgs.push_back("-s"); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  if (UseStartfiles) { +    // If you want startfiles, it means you want the builtin crti and crtbegin, +    // but not crt0. Myriad link commands provide their own crt0.o as needed. +    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); +    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); +  } + +  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, +                            options::OPT_e, options::OPT_s, options::OPT_t, +                            options::OPT_Z_Flag, options::OPT_r}); + +  TC.AddFilePathLibArgs(Args, CmdArgs); + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  if (UseDefaultLibs) { +    if (NeedsSanitizerDeps) +      linkSanitizerRuntimeDeps(TC, CmdArgs); +    if (C.getDriver().CCCIsCXX()) { +      if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { +        CmdArgs.push_back("-lc++"); +        CmdArgs.push_back("-lc++abi"); +      } else +        CmdArgs.push_back("-lstdc++"); +    } +    if (T.getOS() == llvm::Triple::RTEMS) { +      CmdArgs.push_back("--start-group"); +      CmdArgs.push_back("-lc"); +      CmdArgs.push_back("-lgcc"); // circularly dependent on rtems +      // You must provide your own "-L" option to enable finding these. +      CmdArgs.push_back("-lrtemscpu"); +      CmdArgs.push_back("-lrtemsbsp"); +      CmdArgs.push_back("--end-group"); +    } else { +      CmdArgs.push_back("-lc"); +      CmdArgs.push_back("-lgcc"); +    } +  } +  if (UseStartfiles) { +    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); +  } + +  std::string Exec = +      Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld")); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), +                                          CmdArgs, Inputs)); +} + +MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, +                                 const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use +  // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. +  // This won't work to find gcc. Instead we give the installation detector an +  // extra triple, which is preferable to further hacks of the logic that at +  // present is based solely on getArch(). In particular, it would be wrong to +  // choose the myriad installation when targeting a non-myriad sparc install. +  switch (Triple.getArch()) { +  default: +    D.Diag(clang::diag::err_target_unsupported_arch) +        << Triple.getArchName() << "myriad"; +    LLVM_FALLTHROUGH; +  case llvm::Triple::shave: +    return; +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: +    GCCInstallation.init(Triple, Args, {"sparc-myriad-rtems"}); +  } + +  if (GCCInstallation.isValid()) { +    // This directory contains crt{i,n,begin,end}.o as well as libgcc. +    // These files are tied to a particular version of gcc. +    SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); +    addPathIfExists(D, CompilerSupportDir, getFilePaths()); +  } +  // libstd++ and libc++ must both be found in this one place. +  addPathIfExists(D, D.Dir + "/../sparc-myriad-rtems/lib", getFilePaths()); +} + +MyriadToolChain::~MyriadToolChain() {} + +void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                                ArgStringList &CC1Args) const { +  if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); +} + +void MyriadToolChain::addLibCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  std::string Path(getDriver().getInstalledDir()); +  addSystemInclude(DriverArgs, CC1Args, Path + "/../include/c++/v1"); +} + +void MyriadToolChain::addLibStdCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  StringRef LibDir = GCCInstallation.getParentLibPath(); +  const GCCVersion &Version = GCCInstallation.getVersion(); +  StringRef TripleStr = GCCInstallation.getTriple().str(); +  const Multilib &Multilib = GCCInstallation.getMultilib(); +  addLibStdCXXIncludePaths( +      LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, +      "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); +} + +// MyriadToolChain handles several triples: +//  {shave,sparc{,el}}-myriad-{rtems,unknown}-elf +Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { +  // The inherited method works fine if not targeting the SHAVE. +  if (!isShaveCompilation(getTriple())) +    return ToolChain::SelectTool(JA); +  switch (JA.getKind()) { +  case Action::PreprocessJobClass: +  case Action::CompileJobClass: +    if (!Compiler) +      Compiler.reset(new tools::SHAVE::Compiler(*this)); +    return Compiler.get(); +  case Action::AssembleJobClass: +    if (!Assembler) +      Assembler.reset(new tools::SHAVE::Assembler(*this)); +    return Assembler.get(); +  default: +    return ToolChain::getTool(JA.getKind()); +  } +} + +Tool *MyriadToolChain::buildLinker() const { +  return new tools::Myriad::Linker(*this); +} + +SanitizerMask MyriadToolChain::getSupportedSanitizers() const { +  return SanitizerKind::Address; +} diff --git a/clang/lib/Driver/ToolChains/Myriad.h b/clang/lib/Driver/ToolChains/Myriad.h new file mode 100644 index 0000000000000..9f5225fbc62c9 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Myriad.h @@ -0,0 +1,103 @@ +//===--- Myriad.h - Myriad ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// SHAVE tools -- Directly call moviCompile and moviAsm +namespace SHAVE { +class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { +public: +  Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {} + +  bool hasIntegratedCPP() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: +  Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {} + +  bool hasIntegratedCPP() const override { return false; } // not sure. + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace SHAVE + +/// The Myriad toolchain uses tools that are in two different namespaces. +/// The Compiler and Assembler as defined above are in the SHAVE namespace, +/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, +/// is in the Myriad namespace. +namespace Myriad { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", TC) {} +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace Myriad +} // end namespace tools + +namespace toolchains { + +/// MyriadToolChain - A tool chain using either clang or the external compiler +/// installed by the Movidius SDK to perform all subcommands. +class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF { +public: +  MyriadToolChain(const Driver &D, const llvm::Triple &Triple, +                  const llvm::opt::ArgList &Args); +  ~MyriadToolChain() override; + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  Tool *SelectTool(const JobAction &JA) const override; +  unsigned GetDefaultDwarfVersion() const override { return 2; } +  SanitizerMask getSupportedSanitizers() const override; + +protected: +  Tool *buildLinker() const override; +  bool isShaveCompilation(const llvm::Triple &T) const { +    return T.getArch() == llvm::Triple::shave; +  } + +private: +  mutable std::unique_ptr<Tool> Compiler; +  mutable std::unique_ptr<Tool> Assembler; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H diff --git a/clang/lib/Driver/ToolChains/NaCl.cpp b/clang/lib/Driver/ToolChains/NaCl.cpp new file mode 100644 index 0000000000000..97241c8840273 --- /dev/null +++ b/clang/lib/Driver/ToolChains/NaCl.cpp @@ -0,0 +1,370 @@ +//===--- NaCl.cpp - Native Client ToolChain Implementations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NaCl.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +// NaCl ARM assembly (inline or standalone) can be written with a set of macros +// for the various SFI requirements like register masking. The assembly tool +// inserts the file containing the macros as an input into all the assembly +// jobs. +void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  const toolchains::NaClToolChain &ToolChain = +      static_cast<const toolchains::NaClToolChain &>(getToolChain()); +  InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), +                       "nacl-arm-macros.s"); +  InputInfoList NewInputs; +  NewInputs.push_back(NaClMacros); +  NewInputs.append(Inputs.begin(), Inputs.end()); +  gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args, +                                    LinkingOutput); +} + +// This is quite similar to gnutools::Linker::ConstructJob with changes that +// we use static by default, do not yet support sanitizers or LTO, and a few +// others. Eventually we can support more of that and hopefully migrate back +// to gnutools::Linker. +void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                     const InputInfo &Output, +                                     const InputInfoList &Inputs, +                                     const ArgList &Args, +                                     const char *LinkingOutput) const { + +  const toolchains::NaClToolChain &ToolChain = +      static_cast<const toolchains::NaClToolChain &>(getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  const llvm::Triple::ArchType Arch = ToolChain.getArch(); +  const bool IsStatic = +      !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared); + +  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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); + +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("-s"); + +  // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag +  // from there is --build-id, which we do want. +  CmdArgs.push_back("--build-id"); + +  if (!IsStatic) +    CmdArgs.push_back("--eh-frame-hdr"); + +  CmdArgs.push_back("-m"); +  if (Arch == llvm::Triple::x86) +    CmdArgs.push_back("elf_i386_nacl"); +  else if (Arch == llvm::Triple::arm) +    CmdArgs.push_back("armelf_nacl"); +  else if (Arch == llvm::Triple::x86_64) +    CmdArgs.push_back("elf_x86_64_nacl"); +  else if (Arch == llvm::Triple::mipsel) +    CmdArgs.push_back("mipselelf_nacl"); +  else +    D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() +                                              << "Native Client"; + +  if (IsStatic) +    CmdArgs.push_back("-static"); +  else if (Args.hasArg(options::OPT_shared)) +    CmdArgs.push_back("-shared"); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + +    const char *crtbegin; +    if (IsStatic) +      crtbegin = "crtbeginT.o"; +    else if (Args.hasArg(options::OPT_shared)) +      crtbegin = "crtbeginS.o"; +    else +      crtbegin = "crtbegin.o"; +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  Args.AddAllArgs(CmdArgs, options::OPT_u); + +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (D.CCCIsCXX() && +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (ToolChain.ShouldLinkCXXStdlib(Args)) { +      bool OnlyLibstdcxxStatic = +          Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; +      if (OnlyLibstdcxxStatic) +        CmdArgs.push_back("-Bstatic"); +      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (OnlyLibstdcxxStatic) +        CmdArgs.push_back("-Bdynamic"); +    } +    CmdArgs.push_back("-lm"); +  } + +  if (!Args.hasArg(options::OPT_nostdlib)) { +    if (!Args.hasArg(options::OPT_nodefaultlibs)) { +      // Always use groups, since it has no effect on dynamic libraries. +      CmdArgs.push_back("--start-group"); +      CmdArgs.push_back("-lc"); +      // NaCl's libc++ currently requires libpthread, so just always include it +      // in the group for C++. +      if (Args.hasArg(options::OPT_pthread) || +          Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { +        // Gold, used by Mips, handles nested groups differently than ld, and +        // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, +        // which is not a desired behaviour here. +        // See https://sourceware.org/ml/binutils/2015-03/msg00034.html +        if (getToolChain().getArch() == llvm::Triple::mipsel) +          CmdArgs.push_back("-lnacl"); + +        CmdArgs.push_back("-lpthread"); +      } + +      CmdArgs.push_back("-lgcc"); +      CmdArgs.push_back("--as-needed"); +      if (IsStatic) +        CmdArgs.push_back("-lgcc_eh"); +      else +        CmdArgs.push_back("-lgcc_s"); +      CmdArgs.push_back("--no-as-needed"); + +      // Mips needs to create and use pnacl_legacy library that contains +      // definitions from bitcode/pnaclmm.c and definitions for +      // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). +      if (getToolChain().getArch() == llvm::Triple::mipsel) +        CmdArgs.push_back("-lpnacl_legacy"); + +      CmdArgs.push_back("--end-group"); +    } + +    if (!Args.hasArg(options::OPT_nostartfiles)) { +      const char *crtend; +      if (Args.hasArg(options::OPT_shared)) +        crtend = "crtendS.o"; +      else +        crtend = "crtend.o"; + +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +    } +  } + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// NaCl Toolchain +NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, +                             const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { + +  // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the +  // default paths, and must instead only use the paths provided +  // with this toolchain based on architecture. +  path_list &file_paths = getFilePaths(); +  path_list &prog_paths = getProgramPaths(); + +  file_paths.clear(); +  prog_paths.clear(); + +  // Path for library files (libc.a, ...) +  std::string FilePath(getDriver().Dir + "/../"); + +  // Path for tools (clang, ld, etc..) +  std::string ProgPath(getDriver().Dir + "/../"); + +  // Path for toolchain libraries (libgcc.a, ...) +  std::string ToolPath(getDriver().ResourceDir + "/lib/"); + +  switch (Triple.getArch()) { +  case llvm::Triple::x86: +    file_paths.push_back(FilePath + "x86_64-nacl/lib32"); +    file_paths.push_back(FilePath + "i686-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); +    file_paths.push_back(ToolPath + "i686-nacl"); +    break; +  case llvm::Triple::x86_64: +    file_paths.push_back(FilePath + "x86_64-nacl/lib"); +    file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); +    file_paths.push_back(ToolPath + "x86_64-nacl"); +    break; +  case llvm::Triple::arm: +    file_paths.push_back(FilePath + "arm-nacl/lib"); +    file_paths.push_back(FilePath + "arm-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "arm-nacl/bin"); +    file_paths.push_back(ToolPath + "arm-nacl"); +    break; +  case llvm::Triple::mipsel: +    file_paths.push_back(FilePath + "mipsel-nacl/lib"); +    file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "bin"); +    file_paths.push_back(ToolPath + "mipsel-nacl"); +    break; +  default: +    break; +  } + +  NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); +} + +void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                              ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  SmallString<128> P(D.Dir + "/../"); +  switch (getTriple().getArch()) { +  case llvm::Triple::x86: +    // x86 is special because multilib style uses x86_64-nacl/include for libc +    // headers but the SDK wants i686-nacl/usr/include. The other architectures +    // have the same substring. +    llvm::sys::path::append(P, "i686-nacl/usr/include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    llvm::sys::path::remove_filename(P); +    llvm::sys::path::remove_filename(P); +    llvm::sys::path::remove_filename(P); +    llvm::sys::path::append(P, "x86_64-nacl/include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    return; +  case llvm::Triple::arm: +    llvm::sys::path::append(P, "arm-nacl/usr/include"); +    break; +  case llvm::Triple::x86_64: +    llvm::sys::path::append(P, "x86_64-nacl/usr/include"); +    break; +  case llvm::Triple::mipsel: +    llvm::sys::path::append(P, "mipsel-nacl/usr/include"); +    break; +  default: +    return; +  } + +  addSystemInclude(DriverArgs, CC1Args, P.str()); +  llvm::sys::path::remove_filename(P); +  llvm::sys::path::remove_filename(P); +  llvm::sys::path::append(P, "include"); +  addSystemInclude(DriverArgs, CC1Args, P.str()); +} + +void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, +                                        ArgStringList &CmdArgs) const { +  // Check for -stdlib= flags. We only support libc++ but this consumes the arg +  // if the value is libc++, and emits an error for other values. +  GetCXXStdlibType(Args); +  CmdArgs.push_back("-lc++"); +} + +void NaClToolChain::addLibCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); + +  SmallString<128> P(D.Dir + "/../"); +  switch (getTriple().getArch()) { +  default: +    break; +  case llvm::Triple::arm: +    llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  case llvm::Triple::x86: +    llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  case llvm::Triple::x86_64: +    llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  case llvm::Triple::mipsel: +    llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  } +} + +ToolChain::CXXStdlibType +NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { +  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { +    StringRef Value = A->getValue(); +    if (Value == "libc++") +      return ToolChain::CST_Libcxx; +    getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) +        << A->getAsString(Args); +  } + +  return ToolChain::CST_Libcxx; +} + +std::string +NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, +                                           types::ID InputType) const { +  llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); +  if (TheTriple.getArch() == llvm::Triple::arm && +      TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) +    TheTriple.setEnvironment(llvm::Triple::GNUEABIHF); +  return TheTriple.getTriple(); +} + +Tool *NaClToolChain::buildLinker() const { +  return new tools::nacltools::Linker(*this); +} + +Tool *NaClToolChain::buildAssembler() const { +  if (getTriple().getArch() == llvm::Triple::arm) +    return new tools::nacltools::AssemblerARM(*this); +  return new tools::gnutools::Assembler(*this); +} diff --git a/clang/lib/Driver/ToolChains/NaCl.h b/clang/lib/Driver/ToolChains/NaCl.h new file mode 100644 index 0000000000000..ab243f8087bb1 --- /dev/null +++ b/clang/lib/Driver/ToolChains/NaCl.h @@ -0,0 +1,88 @@ +//===--- NaCl.h - Native Client ToolChain Implementations -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace nacltools { +class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler { +public: +  AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {} + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("NaCl::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace nacltools +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF { +public: +  NaClToolChain(const Driver &D, const llvm::Triple &Triple, +                const llvm::opt::ArgList &Args); + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  bool IsIntegratedAssemblerDefault() const override { +    return getTriple().getArch() == llvm::Triple::mipsel; +  } + +  // Get the path to the file containing NaCl's ARM macros. +  // It lives in NaClToolChain because the ARMAssembler tool needs a +  // const char * that it can pass around, +  const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); } + +  std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, +                                          types::ID InputType) const override; + +protected: +  Tool *buildLinker() const override; +  Tool *buildAssembler() const override; + +private: +  std::string NaClArmMacrosPath; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp new file mode 100644 index 0000000000000..405142204199d --- /dev/null +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -0,0 +1,511 @@ +//===--- NetBSD.cpp - NetBSD ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NetBSD.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                     const InputInfo &Output, +                                     const InputInfoList &Inputs, +                                     const ArgList &Args, +                                     const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  // GNU as needs different flags for creating the correct output format +  // on architectures with different ABIs or optional feature sets. +  switch (getToolChain().getArch()) { +  case llvm::Triple::x86: +    CmdArgs.push_back("--32"); +    break; +  case llvm::Triple::arm: +  case llvm::Triple::armeb: +  case llvm::Triple::thumb: +  case llvm::Triple::thumbeb: { +    StringRef MArch, MCPU; +    arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); +    std::string Arch = +        arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); +    CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); +    break; +  } + +  case llvm::Triple::mips: +  case llvm::Triple::mipsel: +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: { +    StringRef CPUName; +    StringRef ABIName; +    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + +    CmdArgs.push_back("-march"); +    CmdArgs.push_back(CPUName.data()); + +    CmdArgs.push_back("-mabi"); +    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); + +    if (getToolChain().getTriple().isLittleEndian()) +      CmdArgs.push_back("-EL"); +    else +      CmdArgs.push_back("-EB"); + +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } + +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: { +    CmdArgs.push_back("-32"); +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } + +  case llvm::Triple::sparcv9: { +    CmdArgs.push_back("-64"); +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } + +  default: +    break; +  } + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                  const InputInfo &Output, +                                  const InputInfoList &Inputs, +                                  const ArgList &Args, +                                  const char *LinkingOutput) const { +  const toolchains::NetBSD &ToolChain = +    static_cast<const toolchains::NetBSD &>(getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  ArgStringList CmdArgs; + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  CmdArgs.push_back("--eh-frame-hdr"); +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +    if (Args.hasArg(options::OPT_pie)) { +      Args.AddAllArgs(CmdArgs, options::OPT_pie); +      CmdArgs.push_back("--no-dynamic-linker"); +    } +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-Bshareable"); +    } else { +      Args.AddAllArgs(CmdArgs, options::OPT_pie); +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/libexec/ld.elf_so"); +    } +  } + +  // Many NetBSD architectures support more than one ABI. +  // Determine the correct emulation for ld. +  switch (ToolChain.getArch()) { +  case llvm::Triple::x86: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf_i386"); +    break; +  case llvm::Triple::arm: +  case llvm::Triple::thumb: +    CmdArgs.push_back("-m"); +    switch (ToolChain.getTriple().getEnvironment()) { +    case llvm::Triple::EABI: +    case llvm::Triple::GNUEABI: +      CmdArgs.push_back("armelf_nbsd_eabi"); +      break; +    case llvm::Triple::EABIHF: +    case llvm::Triple::GNUEABIHF: +      CmdArgs.push_back("armelf_nbsd_eabihf"); +      break; +    default: +      CmdArgs.push_back("armelf_nbsd"); +      break; +    } +    break; +  case llvm::Triple::armeb: +  case llvm::Triple::thumbeb: +    arm::appendBE8LinkFlag(Args, CmdArgs, ToolChain.getEffectiveTriple()); +    CmdArgs.push_back("-m"); +    switch (ToolChain.getTriple().getEnvironment()) { +    case llvm::Triple::EABI: +    case llvm::Triple::GNUEABI: +      CmdArgs.push_back("armelfb_nbsd_eabi"); +      break; +    case llvm::Triple::EABIHF: +    case llvm::Triple::GNUEABIHF: +      CmdArgs.push_back("armelfb_nbsd_eabihf"); +      break; +    default: +      CmdArgs.push_back("armelfb_nbsd"); +      break; +    } +    break; +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: +    if (mips::hasMipsAbiArg(Args, "32")) { +      CmdArgs.push_back("-m"); +      if (ToolChain.getArch() == llvm::Triple::mips64) +        CmdArgs.push_back("elf32btsmip"); +      else +        CmdArgs.push_back("elf32ltsmip"); +    } else if (mips::hasMipsAbiArg(Args, "64")) { +      CmdArgs.push_back("-m"); +      if (ToolChain.getArch() == llvm::Triple::mips64) +        CmdArgs.push_back("elf64btsmip"); +      else +        CmdArgs.push_back("elf64ltsmip"); +    } +    break; +  case llvm::Triple::ppc: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf32ppc_nbsd"); +    break; + +  case llvm::Triple::ppc64: +  case llvm::Triple::ppc64le: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf64ppc"); +    break; + +  case llvm::Triple::sparc: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf32_sparc"); +    break; + +  case llvm::Triple::sparcv9: +    CmdArgs.push_back("-m"); +    CmdArgs.push_back("elf64_sparc"); +    break; + +  default: +    break; +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back( +          Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); +    } +    CmdArgs.push_back( +        Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { +      CmdArgs.push_back( +          Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); +    } else { +      CmdArgs.push_back( +          Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); +    } +  } + +  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); + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); +  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); +  if (SanArgs.needsSharedRt()) { +    CmdArgs.push_back("-rpath"); +    CmdArgs.push_back(Args.MakeArgString( +        ToolChain.getCompilerRTPath().c_str())); +  } + +  unsigned Major, Minor, Micro; +  ToolChain.getTriple().getOSVersion(Major, Minor, Micro); +  bool useLibgcc = true; +  if (Major >= 7 || Major == 0) { +    switch (ToolChain.getArch()) { +    case llvm::Triple::aarch64: +    case llvm::Triple::aarch64_be: +    case llvm::Triple::arm: +    case llvm::Triple::armeb: +    case llvm::Triple::thumb: +    case llvm::Triple::thumbeb: +    case llvm::Triple::ppc: +    case llvm::Triple::ppc64: +    case llvm::Triple::ppc64le: +    case llvm::Triple::sparc: +    case llvm::Triple::sparcv9: +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      useLibgcc = false; +      break; +    default: +      break; +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    // Use the static OpenMP runtime with -static-openmp +    bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && +                        !Args.hasArg(options::OPT_static); +    addOpenMPRuntime(CmdArgs, getToolChain(), Args, StaticOpenMP); + +    if (D.CCCIsCXX()) { +      if (ToolChain.ShouldLinkCXXStdlib(Args)) +        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      CmdArgs.push_back("-lm"); +    } +    if (NeedsSanitizerDeps) +      linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); +    if (NeedsXRayDeps) +      linkXRayRuntimeDeps(ToolChain, CmdArgs); +    if (Args.hasArg(options::OPT_pthread)) +      CmdArgs.push_back("-lpthread"); +    CmdArgs.push_back("-lc"); + +    if (useLibgcc) { +      if (Args.hasArg(options::OPT_static)) { +        // libgcc_eh depends on libc, so resolve as much as possible, +        // pull in any new requirements from libc and then get the rest +        // of libgcc. +        CmdArgs.push_back("-lgcc_eh"); +        CmdArgs.push_back("-lc"); +        CmdArgs.push_back("-lgcc"); +      } else { +        CmdArgs.push_back("-lgcc"); +        CmdArgs.push_back("--as-needed"); +        CmdArgs.push_back("-lgcc_s"); +        CmdArgs.push_back("--no-as-needed"); +      } +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      CmdArgs.push_back( +          Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); +    else +      CmdArgs.push_back( +          Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +  } + +  ToolChain.addProfileRTLibs(Args, CmdArgs); + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. + +NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  if (!Args.hasArg(options::OPT_nostdlib)) { +    // When targeting a 32-bit platform, try the special directory used on +    // 64-bit hosts, and only fall back to the main library directory if that +    // doesn't work. +    // FIXME: It'd be nicer to test if this directory exists, but I'm not sure +    // what all logic is needed to emulate the '=' prefix here. +    switch (Triple.getArch()) { +    case llvm::Triple::x86: +      getFilePaths().push_back("=/usr/lib/i386"); +      break; +    case llvm::Triple::arm: +    case llvm::Triple::armeb: +    case llvm::Triple::thumb: +    case llvm::Triple::thumbeb: +      switch (Triple.getEnvironment()) { +      case llvm::Triple::EABI: +      case llvm::Triple::GNUEABI: +        getFilePaths().push_back("=/usr/lib/eabi"); +        break; +      case llvm::Triple::EABIHF: +      case llvm::Triple::GNUEABIHF: +        getFilePaths().push_back("=/usr/lib/eabihf"); +        break; +      default: +        getFilePaths().push_back("=/usr/lib/oabi"); +        break; +      } +      break; +    case llvm::Triple::mips64: +    case llvm::Triple::mips64el: +      if (tools::mips::hasMipsAbiArg(Args, "o32")) +        getFilePaths().push_back("=/usr/lib/o32"); +      else if (tools::mips::hasMipsAbiArg(Args, "64")) +        getFilePaths().push_back("=/usr/lib/64"); +      break; +    case llvm::Triple::ppc: +      getFilePaths().push_back("=/usr/lib/powerpc"); +      break; +    case llvm::Triple::sparc: +      getFilePaths().push_back("=/usr/lib/sparc"); +      break; +    default: +      break; +    } + +    getFilePaths().push_back("=/usr/lib"); +  } +} + +Tool *NetBSD::buildAssembler() const { +  return new tools::netbsd::Assembler(*this); +} + +Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } + +ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { +  unsigned Major, Minor, Micro; +  getTriple().getOSVersion(Major, Minor, Micro); +  if (Major >= 7 || Major == 0) { +    switch (getArch()) { +    case llvm::Triple::aarch64: +    case llvm::Triple::aarch64_be: +    case llvm::Triple::arm: +    case llvm::Triple::armeb: +    case llvm::Triple::thumb: +    case llvm::Triple::thumbeb: +    case llvm::Triple::ppc: +    case llvm::Triple::ppc64: +    case llvm::Triple::ppc64le: +    case llvm::Triple::sparc: +    case llvm::Triple::sparcv9: +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +      return ToolChain::CST_Libcxx; +    default: +      break; +    } +  } +  return ToolChain::CST_Libstdcxx; +} + +void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                   llvm::opt::ArgStringList &CC1Args) const { +  const std::string Candidates[] = { +    // directory relative to build tree +    getDriver().Dir + "/../include/c++/v1", +    // system install with full upstream path +    getDriver().SysRoot + "/usr/include/c++/v1", +    // system install from src +    getDriver().SysRoot + "/usr/include/c++", +  }; + +  for (const auto &IncludePath : Candidates) { +    if (!getVFS().exists(IncludePath + "/__config")) +      continue; + +    // Use the first candidate that looks valid. +    addSystemInclude(DriverArgs, CC1Args, IncludePath); +    return; +  } +} + +void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                                      llvm::opt::ArgStringList &CC1Args) const { +  addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "", +                           "", DriverArgs, CC1Args); +} + +llvm::ExceptionHandling NetBSD::GetExceptionModel(const ArgList &Args) const { +  // NetBSD uses Dwarf exceptions on ARM. +  llvm::Triple::ArchType TArch = getTriple().getArch(); +  if (TArch == llvm::Triple::arm || TArch == llvm::Triple::armeb || +      TArch == llvm::Triple::thumb || TArch == llvm::Triple::thumbeb) +    return llvm::ExceptionHandling::DwarfCFI; +  return llvm::ExceptionHandling::None; +} + +SanitizerMask NetBSD::getSupportedSanitizers() const { +  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; +  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  if (IsX86 || IsX86_64) { +    Res |= SanitizerKind::Address; +    Res |= SanitizerKind::PointerCompare; +    Res |= SanitizerKind::PointerSubtract; +    Res |= SanitizerKind::Function; +    Res |= SanitizerKind::Leak; +    Res |= SanitizerKind::SafeStack; +    Res |= SanitizerKind::Scudo; +    Res |= SanitizerKind::Vptr; +  } +  if (IsX86_64) { +    Res |= SanitizerKind::DataFlow; +    Res |= SanitizerKind::Fuzzer; +    Res |= SanitizerKind::FuzzerNoLink; +    Res |= SanitizerKind::HWAddress; +    Res |= SanitizerKind::KernelAddress; +    Res |= SanitizerKind::KernelHWAddress; +    Res |= SanitizerKind::KernelMemory; +    Res |= SanitizerKind::Memory; +    Res |= SanitizerKind::Thread; +  } +  return Res; +} + +void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, +                                   ArgStringList &CC1Args, +                                   Action::OffloadKind) const { +  const SanitizerArgs &SanArgs = getSanitizerArgs(); +  if (SanArgs.hasAnySanitizer()) +    CC1Args.push_back("-D_REENTRANT"); + +  unsigned Major, Minor, Micro; +  getTriple().getOSVersion(Major, Minor, Micro); +  bool UseInitArrayDefault = +    Major >= 9 || Major == 0 || +    getTriple().getArch() == llvm::Triple::aarch64 || +    getTriple().getArch() == llvm::Triple::aarch64_be || +    getTriple().getArch() == llvm::Triple::arm || +    getTriple().getArch() == llvm::Triple::armeb; + +  if (DriverArgs.hasFlag(options::OPT_fuse_init_array, +                         options::OPT_fno_use_init_array, UseInitArrayDefault)) +    CC1Args.push_back("-fuse-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/NetBSD.h b/clang/lib/Driver/ToolChains/NetBSD.h new file mode 100644 index 0000000000000..6d404263f625c --- /dev/null +++ b/clang/lib/Driver/ToolChains/NetBSD.h @@ -0,0 +1,91 @@ +//===--- NetBSD.h - NetBSD ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// netbsd -- Directly call GNU Binutils assembler and linker +namespace netbsd { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("netbsd::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("netbsd::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace netbsd +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { +public: +  NetBSD(const Driver &D, const llvm::Triple &Triple, +         const llvm::opt::ArgList &Args); + +  bool IsMathErrnoDefault() const override { return false; } +  bool IsObjCNonFragileABIDefault() const override { return true; } + +  CXXStdlibType GetDefaultCXXStdlibType() const override; + +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; + +  bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { +    return true; +  } + +  llvm::ExceptionHandling GetExceptionModel( +      const llvm::opt::ArgList &Args) const override; + +  SanitizerMask getSupportedSanitizers() const override; + +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp new file mode 100644 index 0000000000000..e93f5fcc3d819 --- /dev/null +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -0,0 +1,269 @@ +//===--- OpenBSD.cpp - OpenBSD ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "OpenBSD.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                      const InputInfo &Output, +                                      const InputInfoList &Inputs, +                                      const ArgList &Args, +                                      const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  switch (getToolChain().getArch()) { +  case llvm::Triple::x86: +    // When building 32-bit code on OpenBSD/amd64, we have to explicitly +    // instruct as in the base system to assemble 32-bit code. +    CmdArgs.push_back("--32"); +    break; + +  case llvm::Triple::ppc: +    CmdArgs.push_back("-mppc"); +    CmdArgs.push_back("-many"); +    break; + +  case llvm::Triple::sparc: +  case llvm::Triple::sparcel: { +    CmdArgs.push_back("-32"); +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } + +  case llvm::Triple::sparcv9: { +    CmdArgs.push_back("-64"); +    std::string CPU = getCPUName(Args, getToolChain().getTriple()); +    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } + +  case llvm::Triple::mips64: +  case llvm::Triple::mips64el: { +    StringRef CPUName; +    StringRef ABIName; +    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + +    CmdArgs.push_back("-mabi"); +    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); + +    if (getToolChain().getTriple().isLittleEndian()) +      CmdArgs.push_back("-EL"); +    else +      CmdArgs.push_back("-EB"); + +    AddAssemblerKPIC(getToolChain(), Args, CmdArgs); +    break; +  } + +  default: +    break; +  } + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                   const InputInfo &Output, +                                   const InputInfoList &Inputs, +                                   const ArgList &Args, +                                   const char *LinkingOutput) const { +  const toolchains::OpenBSD &ToolChain = +      static_cast<const toolchains::OpenBSD &>(getToolChain()); +  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 (ToolChain.getArch() == llvm::Triple::mips64) +    CmdArgs.push_back("-EB"); +  else if (ToolChain.getArch() == llvm::Triple::mips64el) +    CmdArgs.push_back("-EL"); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { +    CmdArgs.push_back("-e"); +    CmdArgs.push_back("__start"); +  } + +  CmdArgs.push_back("--eh-frame-hdr"); +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    CmdArgs.push_back("-Bdynamic"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-shared"); +    } else { +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/usr/libexec/ld.so"); +    } +  } + +  if (Args.hasArg(options::OPT_pie)) +    CmdArgs.push_back("-pie"); +  if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg)) +    CmdArgs.push_back("-nopie"); + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    const char *crt0 = nullptr; +    const char *crtbegin = nullptr; +    if (!Args.hasArg(options::OPT_shared)) { +      if (Args.hasArg(options::OPT_pg)) +        crt0 = "gcrt0.o"; +      else if (Args.hasArg(options::OPT_static) && +               !Args.hasArg(options::OPT_nopie)) +        crt0 = "rcrt0.o"; +      else +        crt0 = "crt0.o"; +      crtbegin = "crtbegin.o"; +    } else { +      crtbegin = "crtbeginS.o"; +    } + +    if (crt0) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, +                            options::OPT_s, options::OPT_t, +                            options::OPT_Z_Flag, options::OPT_r}); + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); +  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (D.CCCIsCXX()) { +      if (ToolChain.ShouldLinkCXXStdlib(Args)) +        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lm_p"); +      else +        CmdArgs.push_back("-lm"); +    } +    if (NeedsSanitizerDeps) { +      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); +      linkSanitizerRuntimeDeps(ToolChain, CmdArgs); +    } +    if (NeedsXRayDeps) { +      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); +      linkXRayRuntimeDeps(ToolChain, CmdArgs); +    } +    // FIXME: For some reason GCC passes -lgcc before adding +    // the default system libraries. Just mimic this for now. +    CmdArgs.push_back("-lcompiler_rt"); + +    if (Args.hasArg(options::OPT_pthread)) { +      if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lpthread_p"); +      else +        CmdArgs.push_back("-lpthread"); +    } + +    if (!Args.hasArg(options::OPT_shared)) { +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lc_p"); +      else +        CmdArgs.push_back("-lc"); +    } + +    CmdArgs.push_back("-lcompiler_rt"); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    const char *crtend = nullptr; +    if (!Args.hasArg(options::OPT_shared)) +      crtend = "crtend.o"; +    else +      crtend = "crtendS.o"; + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); +  } + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +SanitizerMask OpenBSD::getSupportedSanitizers() const { +  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; +  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + +  // For future use, only UBsan at the moment +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); + +  if (IsX86 || IsX86_64) { +    Res |= SanitizerKind::Vptr; +    Res |= SanitizerKind::Fuzzer; +    Res |= SanitizerKind::FuzzerNoLink; +  } + +  return Res; +} + +/// 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) +    : Generic_ELF(D, Triple, Args) { +  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, +                                  ArgStringList &CmdArgs) const { +  bool Profiling = Args.hasArg(options::OPT_pg); + +  CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); +  CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); +} + +Tool *OpenBSD::buildAssembler() const { +  return new tools::openbsd::Assembler(*this); +} + +Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h new file mode 100644 index 0000000000000..c92d109b7c16c --- /dev/null +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -0,0 +1,87 @@ +//===--- OpenBSD.h - OpenBSD ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// openbsd -- Directly call GNU Binutils assembler and linker +namespace openbsd { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: +  Assembler(const ToolChain &TC) +      : GnuTool("openbsd::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("openbsd::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace openbsd +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { +public: +  OpenBSD(const Driver &D, const llvm::Triple &Triple, +          const llvm::opt::ArgList &Args); + +  bool IsMathErrnoDefault() const override { return false; } +  bool IsObjCNonFragileABIDefault() const override { return true; } +  bool isPIEDefault() const override { return true; } + +  RuntimeLibType GetDefaultRuntimeLibType() const override { +    return ToolChain::RLT_CompilerRT; +  } +  CXXStdlibType GetDefaultCXXStdlibType() const override { +    return ToolChain::CST_Libcxx; +  } + +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; + +  unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { +    return 2; +  } +  unsigned GetDefaultDwarfVersion() const override { return 2; } + +  SanitizerMask getSupportedSanitizers() const override; + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp new file mode 100644 index 0000000000000..af2e3a21a0af7 --- /dev/null +++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -0,0 +1,28 @@ +//===-- PPCLinux.cpp - PowerPC ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PPCLinux.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver::toolchains; +using namespace llvm::opt; + +void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                                  ArgStringList &CC1Args) const { +  if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) && +      !DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    const Driver &D = getDriver(); +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include", "ppc_wrappers"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} diff --git a/clang/lib/Driver/ToolChains/PPCLinux.h b/clang/lib/Driver/ToolChains/PPCLinux.h new file mode 100644 index 0000000000000..b3ef7b61dc3aa --- /dev/null +++ b/clang/lib/Driver/ToolChains/PPCLinux.h @@ -0,0 +1,33 @@ +//===--- PPCLinux.h - PowerPC ToolChain Implementations ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_LINUX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_LINUX_H + +#include "Linux.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY PPCLinuxToolChain : public Linux { +public: +  PPCLinuxToolChain(const Driver &D, const llvm::Triple &Triple, +                    const llvm::opt::ArgList &Args) +      : Linux(D, Triple, Args) {} + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_LINUX_H diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp new file mode 100644 index 0000000000000..4e8840296205d --- /dev/null +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -0,0 +1,432 @@ +//===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PS4CPU.h" +#include "FreeBSD.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +using clang::driver::tools::AddLinkerInputs; + +void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, +                                     ArgStringList &CmdArgs) { +  if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, +                    false) || +       Args.hasFlag(options::OPT_fprofile_generate, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasFlag(options::OPT_fprofile_generate_EQ, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasFlag(options::OPT_fprofile_instr_generate, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasArg(options::OPT_fcreate_profile) || +       Args.hasArg(options::OPT_coverage))) +    CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); +} + +void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  assert(Inputs.size() == 1 && "Unexpected number of inputs."); +  const InputInfo &Input = Inputs[0]; +  assert(Input.isFilename() && "Invalid input."); +  CmdArgs.push_back(Input.getFilename()); + +  const char *Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { +  const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +  if (SanArgs.needsUbsanRt()) { +    CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); +  } +  if (SanArgs.needsAsanRt()) { +    CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); +  } +} + +void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, +                                     ArgStringList &CmdArgs) { +  const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +  if (SanArgs.needsUbsanRt()) +    CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); +  if (SanArgs.needsAsanRt()) +    CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); +} + +static void ConstructPS4LinkJob(const Tool &T, Compilation &C, +                                const JobAction &JA, const InputInfo &Output, +                                const InputInfoList &Inputs, +                                const ArgList &Args, +                                const char *LinkingOutput) { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(T.getToolChain()); +  const Driver &D = ToolChain.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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_pie)) +    CmdArgs.push_back("-pie"); + +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); +  if (Args.hasArg(options::OPT_shared)) +    CmdArgs.push_back("--oformat=so"); + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) +    AddPS4SanitizerArgs(ToolChain, CmdArgs); + +  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_r); + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (Args.hasArg(options::OPT_pthread)) { +    CmdArgs.push_back("-lpthread"); +  } + +  const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); + +  C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +static void ConstructGoldLinkJob(const Tool &T, Compilation &C, +                                 const JobAction &JA, const InputInfo &Output, +                                 const InputInfoList &Inputs, +                                 const ArgList &Args, +                                 const char *LinkingOutput) { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(T.getToolChain()); +  const Driver &D = ToolChain.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 (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_pie)) +    CmdArgs.push_back("-pie"); + +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    CmdArgs.push_back("--eh-frame-hdr"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-Bshareable"); +    } else { +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/libexec/ld-elf.so.1"); +    } +    CmdArgs.push_back("--enable-new-dtags"); +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) +    AddPS4SanitizerArgs(ToolChain, CmdArgs); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    const char *crt1 = nullptr; +    if (!Args.hasArg(options::OPT_shared)) { +      if (Args.hasArg(options::OPT_pg)) +        crt1 = "gcrt1.o"; +      else if (Args.hasArg(options::OPT_pie)) +        crt1 = "Scrt1.o"; +      else +        crt1 = "crt1.o"; +    } +    if (crt1) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + +    const char *crtbegin = nullptr; +    if (Args.hasArg(options::OPT_static)) +      crtbegin = "crtbeginT.o"; +    else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      crtbegin = "crtbeginS.o"; +    else +      crtbegin = "crtbegin.o"; + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  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_r); + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    // For PS4, we always want to pass libm, libstdc++ and libkernel +    // libraries for both C and C++ compilations. +    CmdArgs.push_back("-lkernel"); +    if (D.CCCIsCXX()) { +      if (ToolChain.ShouldLinkCXXStdlib(Args)) +        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lm_p"); +      else +        CmdArgs.push_back("-lm"); +    } +    // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding +    // the default system libraries. Just mimic this for now. +    if (Args.hasArg(options::OPT_pg)) +      CmdArgs.push_back("-lgcc_p"); +    else +      CmdArgs.push_back("-lcompiler_rt"); +    if (Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-lstdc++"); +    } else if (Args.hasArg(options::OPT_pg)) { +      CmdArgs.push_back("-lgcc_eh_p"); +    } else { +      CmdArgs.push_back("--as-needed"); +      CmdArgs.push_back("-lstdc++"); +      CmdArgs.push_back("--no-as-needed"); +    } + +    if (Args.hasArg(options::OPT_pthread)) { +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lpthread_p"); +      else +        CmdArgs.push_back("-lpthread"); +    } + +    if (Args.hasArg(options::OPT_pg)) { +      if (Args.hasArg(options::OPT_shared)) +        CmdArgs.push_back("-lc"); +      else { +        if (Args.hasArg(options::OPT_static)) { +          CmdArgs.push_back("--start-group"); +          CmdArgs.push_back("-lc_p"); +          CmdArgs.push_back("-lpthread_p"); +          CmdArgs.push_back("--end-group"); +        } else { +          CmdArgs.push_back("-lc_p"); +        } +      } +      CmdArgs.push_back("-lgcc_p"); +    } else { +      if (Args.hasArg(options::OPT_static)) { +        CmdArgs.push_back("--start-group"); +        CmdArgs.push_back("-lc"); +        CmdArgs.push_back("-lpthread"); +        CmdArgs.push_back("--end-group"); +      } else { +        CmdArgs.push_back("-lc"); +      } +      CmdArgs.push_back("-lcompiler_rt"); +    } + +    if (Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-lstdc++"); +    } else if (Args.hasArg(options::OPT_pg)) { +      CmdArgs.push_back("-lgcc_eh_p"); +    } else { +      CmdArgs.push_back("--as-needed"); +      CmdArgs.push_back("-lstdc++"); +      CmdArgs.push_back("--no-as-needed"); +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); +    else +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +  } + +  const char *Exec = +#ifdef _WIN32 +      Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); +#else +      Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); +#endif + +  C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, +                                       const InputInfo &Output, +                                       const InputInfoList &Inputs, +                                       const ArgList &Args, +                                       const char *LinkingOutput) const { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  bool PS4Linker; +  StringRef LinkerOptName; +  if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { +    LinkerOptName = A->getValue(); +    if (LinkerOptName != "ps4" && LinkerOptName != "gold") +      D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; +  } + +  if (LinkerOptName == "gold") +    PS4Linker = false; +  else if (LinkerOptName == "ps4") +    PS4Linker = true; +  else +    PS4Linker = !Args.hasArg(options::OPT_shared); + +  if (PS4Linker) +    ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); +  else +    ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); +} + +toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, +                           const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  if (Args.hasArg(clang::driver::options::OPT_static)) +    D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" +                                                            << "PS4"; + +  // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR +  // if it exists; otherwise use the driver's installation path, which +  // should be <SDK_DIR>/host_tools/bin. + +  SmallString<512> PS4SDKDir; +  if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { +    if (!llvm::sys::fs::exists(EnvValue)) +      getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; +    PS4SDKDir = EnvValue; +  } else { +    PS4SDKDir = getDriver().Dir; +    llvm::sys::path::append(PS4SDKDir, "/../../"); +  } + +  // By default, the driver won't report a warning if it can't find +  // PS4's include or lib directories. This behavior could be changed if +  // -Weverything or -Winvalid-or-nonexistent-directory options are passed. +  // If -isysroot was passed, use that as the SDK base path. +  std::string PrefixDir; +  if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +    PrefixDir = A->getValue(); +    if (!llvm::sys::fs::exists(PrefixDir)) +      getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; +  } else +    PrefixDir = PS4SDKDir.str(); + +  SmallString<512> PS4SDKIncludeDir(PrefixDir); +  llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); +  if (!Args.hasArg(options::OPT_nostdinc) && +      !Args.hasArg(options::OPT_nostdlibinc) && +      !Args.hasArg(options::OPT_isysroot) && +      !Args.hasArg(options::OPT__sysroot_EQ) && +      !llvm::sys::fs::exists(PS4SDKIncludeDir)) { +    getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) +        << "PS4 system headers" << PS4SDKIncludeDir; +  } + +  SmallString<512> PS4SDKLibDir(PS4SDKDir); +  llvm::sys::path::append(PS4SDKLibDir, "target/lib"); +  if (!Args.hasArg(options::OPT_nostdlib) && +      !Args.hasArg(options::OPT_nodefaultlibs) && +      !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && +      !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && +      !Args.hasArg(options::OPT_emit_ast) && +      !llvm::sys::fs::exists(PS4SDKLibDir)) { +    getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) +        << "PS4 system libraries" << PS4SDKLibDir; +    return; +  } +  getFilePaths().push_back(PS4SDKLibDir.str()); +} + +Tool *toolchains::PS4CPU::buildAssembler() const { +  return new tools::PS4cpu::Assemble(*this); +} + +Tool *toolchains::PS4CPU::buildLinker() const { +  return new tools::PS4cpu::Link(*this); +} + +bool toolchains::PS4CPU::isPICDefault() const { return true; } + +bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } + +SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Vptr; +  return Res; +} diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h new file mode 100644 index 0000000000000..e9f0891c11944 --- /dev/null +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -0,0 +1,96 @@ +//===--- PS4CPU.h - PS4CPU ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace PS4cpu { + +void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, +                      llvm::opt::ArgStringList &CmdArgs); + +void addSanitizerArgs(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs); + +class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { +public: +  Assemble(const ToolChain &TC) +      : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, +                    const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Link : public Tool { +public: +  Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, +                    const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace PS4cpu +} // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { +public: +  PS4CPU(const Driver &D, const llvm::Triple &Triple, +         const llvm::opt::ArgList &Args); + +  // No support for finding a C++ standard library yet. +  void addLibCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override {} +  void addLibStdCxxIncludePaths( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override {} + +  bool IsMathErrnoDefault() const override { return false; } +  bool IsObjCNonFragileABIDefault() const override { return true; } +  bool HasNativeLLVMSupport() const override; +  bool isPICDefault() const override; + +  unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { +    return 2; // SSPStrong +  } + +  llvm::DebuggerKind getDefaultDebuggerTuning() const override { +    return llvm::DebuggerKind::SCE; +  } + +  SanitizerMask getSupportedSanitizers() const override; + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp new file mode 100644 index 0000000000000..22dc5117f1962 --- /dev/null +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -0,0 +1,147 @@ +//===--- RISCVToolchain.cpp - RISCV ToolChain Implementations ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RISCVToolchain.h" +#include "Arch/RISCV.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +/// RISCV Toolchain +RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, +                               const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  GCCInstallation.init(Triple, Args); +  getFilePaths().push_back(computeSysRoot() + "/lib"); +  if (GCCInstallation.isValid()) { +    getFilePaths().push_back(GCCInstallation.getInstallPath().str()); +    getProgramPaths().push_back( +        (GCCInstallation.getParentLibPath() + "/../bin").str()); +  } +} + +Tool *RISCVToolChain::buildLinker() const { +  return new tools::RISCV::Linker(*this); +} + +void RISCVToolChain::addClangTargetOptions( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args, +    Action::OffloadKind) const { +  CC1Args.push_back("-nostdsysteminc"); +  CC1Args.push_back("-fuse-init-array"); +} + +void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                               ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { +    SmallString<128> Dir(computeSysRoot()); +    llvm::sys::path::append(Dir, "include"); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +  } +} + +void RISCVToolChain::addLibStdCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  const GCCVersion &Version = GCCInstallation.getVersion(); +  StringRef TripleStr = GCCInstallation.getTriple().str(); +  const Multilib &Multilib = GCCInstallation.getMultilib(); +  addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text, +      "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); +} + +std::string RISCVToolChain::computeSysRoot() const { +  if (!getDriver().SysRoot.empty()) +    return getDriver().SysRoot; + +  if (!GCCInstallation.isValid()) +    return std::string(); + +  StringRef LibDir = GCCInstallation.getParentLibPath(); +  StringRef TripleStr = GCCInstallation.getTriple().str(); +  std::string SysRootDir = LibDir.str() + "/../" + TripleStr.str(); + +  if (!llvm::sys::fs::exists(SysRootDir)) +    return std::string(); + +  return SysRootDir; +} + +void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                 const InputInfo &Output, +                                 const InputInfoList &Inputs, +                                 const ArgList &Args, +                                 const char *LinkingOutput) const { +  const ToolChain &ToolChain = getToolChain(); +  const Driver &D = ToolChain.getDriver(); +  ArgStringList CmdArgs; + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  std::string Linker = getToolChain().GetProgramPath(getShortName()); + +  if (D.isUsingLTO()) { +    assert(!Inputs.empty() && "Must have at least one input."); +    AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], +                  D.getLTOMode() == LTOK_Thin); +  } + +  bool WantCRTs = +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + +  if (WantCRTs) { +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  Args.AddAllArgs(CmdArgs, +                  {options::OPT_T_Group, options::OPT_e, options::OPT_s, +                   options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  // TODO: add C++ includes and libs if compiling C++. + +  if (!Args.hasArg(options::OPT_nostdlib) && +      !Args.hasArg(options::OPT_nodefaultlibs)) { +    if (ToolChain.ShouldLinkCXXStdlib(Args)) +      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +    CmdArgs.push_back("--start-group"); +    CmdArgs.push_back("-lc"); +    CmdArgs.push_back("-lgloss"); +    CmdArgs.push_back("--end-group"); +    CmdArgs.push_back("-lgcc"); +  } + +  if (WantCRTs) +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); +  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), +                                          CmdArgs, Inputs)); +} +// RISCV tools end. diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h new file mode 100644 index 0000000000000..673d749d76ff7 --- /dev/null +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -0,0 +1,63 @@ +//===--- RISCVToolchain.h - RISCV ToolChain Implementations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_RISCVTOOLCHAIN_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_RISCVTOOLCHAIN_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY RISCVToolChain : public Generic_ELF { +public: +  RISCVToolChain(const Driver &D, const llvm::Triple &Triple, +                 const llvm::opt::ArgList &Args); + +  bool IsIntegratedAssemblerDefault() const override { return true; } +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind) const override; +  bool HasNativeLLVMSupport() const override { return true; } +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void +  addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                           llvm::opt::ArgStringList &CC1Args) const override; + +protected: +  Tool *buildLinker() const override; + +private: +  std::string computeSysRoot() const; +}; + +} // end namespace toolchains + +namespace tools { +namespace RISCV { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  Linker(const ToolChain &TC) : GnuTool("RISCV::Linker", "ld", TC) {} +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace RISCV +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_RISCVTOOLCHAIN_H diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp new file mode 100644 index 0000000000000..fc4e2cf151ef1 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -0,0 +1,289 @@ +//===--- Solaris.cpp - Solaris ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Solaris.h" +#include "CommonArgs.h" +#include "clang/Basic/LangStandard.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                      const InputInfo &Output, +                                      const InputInfoList &Inputs, +                                      const ArgList &Args, +                                      const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                   const InputInfo &Output, +                                   const InputInfoList &Inputs, +                                   const ArgList &Args, +                                   const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  // Demangle C++ names in errors +  CmdArgs.push_back("-C"); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { +    CmdArgs.push_back("-e"); +    CmdArgs.push_back("_start"); +  } + +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +    CmdArgs.push_back("-dn"); +  } else { +    CmdArgs.push_back("-Bdynamic"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-shared"); +    } + +    // libpthread has been folded into libc since Solaris 10, no need to do +    // anything for pthreads. Claim argument to avoid warning. +    Args.ClaimAllArgs(options::OPT_pthread); +    Args.ClaimAllArgs(options::OPT_pthreads); +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) +      CmdArgs.push_back( +          Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + +    const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi); +    bool HaveAnsi = false; +    const LangStandard *LangStd = nullptr; +    if (Std) { +      HaveAnsi = Std->getOption().matches(options::OPT_ansi); +      if (!HaveAnsi) +        LangStd = LangStandard::getLangStandardForName(Std->getValue()); +    } + +    const char *values_X = "values-Xa.o"; +    // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409. +    if (HaveAnsi || (LangStd && !LangStd->isGNUMode())) +      values_X = "values-Xc.o"; +    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X))); + +    const char *values_xpg = "values-xpg6.o"; +    // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409. +    if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99()) +      values_xpg = "values-xpg4.o"; +    CmdArgs.push_back( +        Args.MakeArgString(getToolChain().GetFilePath(values_xpg))); +    CmdArgs.push_back( +        Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); +  } + +  getToolChain().AddFilePathLibArgs(Args, CmdArgs); + +  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, +                            options::OPT_e, options::OPT_r}); + +  bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (getToolChain().ShouldLinkCXXStdlib(Args)) +      getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); +    if (Args.hasArg(options::OPT_fstack_protector) || +        Args.hasArg(options::OPT_fstack_protector_strong) || +        Args.hasArg(options::OPT_fstack_protector_all)) { +      // Explicitly link ssp libraries, not folded into Solaris libc. +      CmdArgs.push_back("-lssp_nonshared"); +      CmdArgs.push_back("-lssp"); +    } +    CmdArgs.push_back("-lgcc_s"); +    CmdArgs.push_back("-lc"); +    if (!Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-lgcc"); +      CmdArgs.push_back("-lm"); +    } +    if (NeedsSanitizerDeps) +      linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    CmdArgs.push_back( +        Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); +  } +  CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + +  getToolChain().addProfileRTLibs(Args, CmdArgs); + +  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) { +  switch (Triple.getArch()) { +  case llvm::Triple::x86: +  case llvm::Triple::sparc: +    break; +  case llvm::Triple::x86_64: +    return "/amd64"; +  case llvm::Triple::sparcv9: +    return "/sparcv9"; +  default: +    llvm_unreachable("Unsupported architecture"); +  } +  return ""; +} + +/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. + +Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, +                 const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { + +  GCCInstallation.init(Triple, Args); + +  StringRef LibSuffix = getSolarisLibSuffix(Triple); +  path_list &Paths = getFilePaths(); +  if (GCCInstallation.isValid()) { +    // On Solaris gcc uses both an architecture-specific path with triple in it +    // as well as a more generic lib path (+arch suffix). +    addPathIfExists(D, +                    GCCInstallation.getInstallPath() + +                        GCCInstallation.getMultilib().gccSuffix(), +                    Paths); +    addPathIfExists(D, GCCInstallation.getParentLibPath() + LibSuffix, Paths); +  } + +  // If we are currently running Clang inside of the requested system root, +  // add its parent library path to those searched. +  if (StringRef(D.Dir).startswith(D.SysRoot)) +    addPathIfExists(D, D.Dir + "/../lib", Paths); + +  addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths); +} + +SanitizerMask Solaris::getSupportedSanitizers() const { +  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; +  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  // FIXME: Omit X86_64 until 64-bit support is figured out. +  if (IsX86) { +    Res |= SanitizerKind::Address; +    Res |= SanitizerKind::PointerCompare; +    Res |= SanitizerKind::PointerSubtract; +  } +  if (IsX86 || IsX86_64) +    Res |= SanitizerKind::Function; +  Res |= SanitizerKind::Vptr; +  return Res; +} + +Tool *Solaris::buildAssembler() const { +  return new tools::solaris::Assembler(*this); +} + +Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } + +void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                        ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); + +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) +    addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  // Check for configure-time C include directories. +  StringRef CIncludeDirs(C_INCLUDE_DIRS); +  if (CIncludeDirs != "") { +    SmallVector<StringRef, 5> dirs; +    CIncludeDirs.split(dirs, ":"); +    for (StringRef dir : dirs) { +      StringRef Prefix = +          llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; +      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); +    } +    return; +  } + +  // Add include directories specific to the selected multilib set and multilib. +  if (GCCInstallation.isValid()) { +    const MultilibSet::IncludeDirsFunc &Callback = +        Multilibs.includeDirsCallback(); +    if (Callback) { +      for (const auto &Path : Callback(GCCInstallation.getMultilib())) +        addExternCSystemIncludeIfExists( +            DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); +    } +  } + +  addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); +} + +void Solaris::addLibStdCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  // We need a detected GCC installation on Solaris (similar to Linux) +  // to provide libstdc++'s headers. +  if (!GCCInstallation.isValid()) +    return; + +  // By default, look for the C++ headers in an include directory adjacent to +  // the lib directory of the GCC installation. +  // On Solaris this usually looks like /usr/gcc/X.Y/include/c++/X.Y.Z +  StringRef LibDir = GCCInstallation.getParentLibPath(); +  StringRef TripleStr = GCCInstallation.getTriple().str(); +  const Multilib &Multilib = GCCInstallation.getMultilib(); +  const GCCVersion &Version = GCCInstallation.getVersion(); + +  // The primary search for libstdc++ supports multiarch variants. +  addLibStdCXXIncludePaths(LibDir.str() + "/../include", "/c++/" + Version.Text, +                           TripleStr, +                           /*GCCMultiarchTriple*/ "", +                           /*TargetMultiarchTriple*/ "", +                           Multilib.includeSuffix(), DriverArgs, CC1Args); +} diff --git a/clang/lib/Driver/ToolChains/Solaris.h b/clang/lib/Driver/ToolChains/Solaris.h new file mode 100644 index 0000000000000..b79e626ef38df --- /dev/null +++ b/clang/lib/Driver/ToolChains/Solaris.h @@ -0,0 +1,77 @@ +//===--- Solaris.h - Solaris ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// solaris -- Directly call Solaris assembler and linker +namespace solaris { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: +  Assembler(const ToolChain &TC) +      : Tool("solaris::Assembler", "assembler", TC) {} + +  bool hasIntegratedCPP() const override { return false; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } + +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace solaris +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_ELF { +public: +  Solaris(const Driver &D, const llvm::Triple &Triple, +          const llvm::opt::ArgList &Args); + +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; + +  void +  addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, +                           llvm::opt::ArgStringList &CC1Args) const override; + +  SanitizerMask getSupportedSanitizers() const override; +  unsigned GetDefaultDwarfVersion() const override { return 2; } + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H diff --git a/clang/lib/Driver/ToolChains/TCE.cpp b/clang/lib/Driver/ToolChains/TCE.cpp new file mode 100644 index 0000000000000..33a81c54bd429 --- /dev/null +++ b/clang/lib/Driver/ToolChains/TCE.cpp @@ -0,0 +1,46 @@ +//===--- TCE.cpp - TCE ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TCE.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// 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, +                           const ArgList &Args) +    : ToolChain(D, Triple, Args) { +  // Path mangling to find libexec +  std::string Path(getDriver().Dir); + +  Path += "/../libexec"; +  getProgramPaths().push_back(Path); +} + +TCEToolChain::~TCEToolChain() {} + +bool TCEToolChain::IsMathErrnoDefault() const { return true; } + +bool TCEToolChain::isPICDefault() const { return false; } + +bool TCEToolChain::isPIEDefault() const { return false; } + +bool TCEToolChain::isPICDefaultForced() const { return false; } + +TCELEToolChain::TCELEToolChain(const Driver &D, const llvm::Triple& Triple, +                               const ArgList &Args) +  : TCEToolChain(D, Triple, Args) { +} + +TCELEToolChain::~TCELEToolChain() {} diff --git a/clang/lib/Driver/ToolChains/TCE.h b/clang/lib/Driver/ToolChains/TCE.h new file mode 100644 index 0000000000000..72933dae965e9 --- /dev/null +++ b/clang/lib/Driver/ToolChains/TCE.h @@ -0,0 +1,46 @@ +//===--- TCE.h - TCE Tool and ToolChain Implementations ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H + +#include "clang/Driver/Driver.h" +#include "clang/Driver/ToolChain.h" +#include <set> + +namespace clang { +namespace driver { +namespace toolchains { + +/// TCEToolChain - A tool chain using the llvm bitcode tools to perform +/// all subcommands. See http://tce.cs.tut.fi for our peculiar target. +class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { +public: +  TCEToolChain(const Driver &D, const llvm::Triple &Triple, +               const llvm::opt::ArgList &Args); +  ~TCEToolChain() override; + +  bool IsMathErrnoDefault() const override; +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; +}; + +/// Toolchain for little endian TCE cores. +class LLVM_LIBRARY_VISIBILITY TCELEToolChain : public TCEToolChain { +public: +  TCELEToolChain(const Driver &D, const llvm::Triple &Triple, +                 const llvm::opt::ArgList &Args); +  ~TCELEToolChain() override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp new file mode 100644 index 0000000000000..3add913b700fa --- /dev/null +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -0,0 +1,289 @@ +//===--- WebAssembly.cpp - WebAssembly ToolChain Implementation -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// Following the conventions in https://wiki.debian.org/Multiarch/Tuples, +/// we remove the vendor field to form the multiarch triple. +static std::string getMultiarchTriple(const Driver &D, +                                      const llvm::Triple &TargetTriple, +                                      StringRef SysRoot) { +    return (TargetTriple.getArchName() + "-" + +            TargetTriple.getOSAndEnvironmentName()).str(); +} + +std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { +  const ToolChain &ToolChain = getToolChain(); +  if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { +    StringRef UseLinker = A->getValue(); +    if (!UseLinker.empty()) { +      if (llvm::sys::path::is_absolute(UseLinker) && +          llvm::sys::fs::can_execute(UseLinker)) +        return UseLinker; + +      // Accept 'lld', and 'ld' as aliases for the default linker +      if (UseLinker != "lld" && UseLinker != "ld") +        ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) +            << A->getAsString(Args); +    } +  } + +  return ToolChain.GetProgramPath(ToolChain.getDefaultLinker()); +} + +void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                const InputInfo &Output, +                                const InputInfoList &Inputs, +                                const ArgList &Args, +                                const char *LinkingOutput) const { + +  const ToolChain &ToolChain = getToolChain(); +  const char *Linker = Args.MakeArgString(getLinkerPath(Args)); +  ArgStringList CmdArgs; + +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("--strip-all"); + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  Args.AddAllArgs(CmdArgs, options::OPT_u); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (ToolChain.ShouldLinkCXXStdlib(Args)) +      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + +    if (Args.hasArg(options::OPT_pthread)) { +      CmdArgs.push_back("-lpthread"); +      CmdArgs.push_back("--shared-memory"); +    } + +    CmdArgs.push_back("-lc"); +    AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); +  } + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); +} + +WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, +                         const llvm::opt::ArgList &Args) +    : ToolChain(D, Triple, Args) { + +  assert(Triple.isArch32Bit() != Triple.isArch64Bit()); + +  getProgramPaths().push_back(getDriver().getInstalledDir()); + +  if (getTriple().getOS() == llvm::Triple::UnknownOS) { +    // Theoretically an "unknown" OS should mean no standard libraries, however +    // it could also mean that a custom set of libraries is in use, so just add +    // /lib to the search path. Disable multiarch in this case, to discourage +    // paths containing "unknown" from acquiring meanings. +    getFilePaths().push_back(getDriver().SysRoot + "/lib"); +  } else { +    const std::string MultiarchTriple = +        getMultiarchTriple(getDriver(), Triple, getDriver().SysRoot); +    getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple); +  } +} + +bool WebAssembly::IsMathErrnoDefault() const { return false; } + +bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } + +bool WebAssembly::UseObjCMixedDispatch() const { return true; } + +bool WebAssembly::isPICDefault() const { return false; } + +bool WebAssembly::isPIEDefault() const { return false; } + +bool WebAssembly::isPICDefaultForced() const { return false; } + +bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } + +bool WebAssembly::hasBlocksRuntime() const { return false; } + +// TODO: Support profiling. +bool WebAssembly::SupportsProfiling() const { return false; } + +bool WebAssembly::HasNativeLLVMSupport() const { return true; } + +void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, +                                        ArgStringList &CC1Args, +                                        Action::OffloadKind) const { +  if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, +                         options::OPT_fno_use_init_array, true)) +    CC1Args.push_back("-fuse-init-array"); + +  // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext +  if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread, +                         false)) { +    if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, +                           false)) +      getDriver().Diag(diag::err_drv_argument_not_allowed_with) +          << "-pthread" +          << "-mno-atomics"; +    if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory, +                           options::OPT_mbulk_memory, false)) +      getDriver().Diag(diag::err_drv_argument_not_allowed_with) +          << "-pthread" +          << "-mno-bulk-memory"; +    if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, +                           options::OPT_mmutable_globals, false)) +      getDriver().Diag(diag::err_drv_argument_not_allowed_with) +          << "-pthread" +          << "-mno-mutable-globals"; +    if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext, +                           false)) +      getDriver().Diag(diag::err_drv_argument_not_allowed_with) +          << "-pthread" +          << "-mno-sign-ext"; +    CC1Args.push_back("-target-feature"); +    CC1Args.push_back("+atomics"); +    CC1Args.push_back("-target-feature"); +    CC1Args.push_back("+bulk-memory"); +    CC1Args.push_back("-target-feature"); +    CC1Args.push_back("+mutable-globals"); +    CC1Args.push_back("-target-feature"); +    CC1Args.push_back("+sign-ext"); +  } + +  if (DriverArgs.getLastArg(options::OPT_fwasm_exceptions)) { +    // '-fwasm-exceptions' is not compatible with '-mno-exception-handling' +    if (DriverArgs.hasFlag(options::OPT_mno_exception_handing, +                           options::OPT_mexception_handing, false)) +      getDriver().Diag(diag::err_drv_argument_not_allowed_with) +          << "-fwasm-exceptions" +          << "-mno-exception-handling"; +    // '-fwasm-exceptions' is not compatible with +    // '-mllvm -enable-emscripten-cxx-exceptions' +    for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { +      if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") +        getDriver().Diag(diag::err_drv_argument_not_allowed_with) +            << "-fwasm-exceptions" +            << "-mllvm -enable-emscripten-cxx-exceptions"; +    } +    // '-fwasm-exceptions' implies exception-handling +    CC1Args.push_back("-target-feature"); +    CC1Args.push_back("+exception-handling"); +  } +} + +ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const { +  return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType +WebAssembly::GetCXXStdlibType(const ArgList &Args) const { +  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { +    StringRef Value = A->getValue(); +    if (Value != "libc++") +      getDriver().Diag(diag::err_drv_invalid_stdlib_name) +          << A->getAsString(Args); +  } +  return ToolChain::CST_Libcxx; +} + +void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                            ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  const Driver &D = getDriver(); + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  // Check for configure-time C include directories. +  StringRef CIncludeDirs(C_INCLUDE_DIRS); +  if (CIncludeDirs != "") { +    SmallVector<StringRef, 5> dirs; +    CIncludeDirs.split(dirs, ":"); +    for (StringRef dir : dirs) { +      StringRef Prefix = +          llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; +      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); +    } +    return; +  } + +  if (getTriple().getOS() != llvm::Triple::UnknownOS) { +    const std::string MultiarchTriple = +        getMultiarchTriple(D, getTriple(), D.SysRoot); +    addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include/" + MultiarchTriple); +  } +  addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); +} + +void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, +                                               ArgStringList &CC1Args) const { +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && +      !DriverArgs.hasArg(options::OPT_nostdincxx)) { +    if (getTriple().getOS() != llvm::Triple::UnknownOS) { +      const std::string MultiarchTriple = +          getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); +      addSystemInclude(DriverArgs, CC1Args, +                       getDriver().SysRoot + "/include/" + MultiarchTriple + +                           "/c++/v1"); +    } +    addSystemInclude(DriverArgs, CC1Args, +                     getDriver().SysRoot + "/include/c++/v1"); +  } +} + +void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                                      llvm::opt::ArgStringList &CmdArgs) const { + +  switch (GetCXXStdlibType(Args)) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    CmdArgs.push_back("-lc++abi"); +    break; +  case ToolChain::CST_Libstdcxx: +    llvm_unreachable("invalid stdlib name"); +  } +} + +SanitizerMask WebAssembly::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  if (getTriple().isOSEmscripten()) { +    Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address; +  } +  return Res; +} + +Tool *WebAssembly::buildLinker() const { +  return new tools::wasm::Linker(*this); +} diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h new file mode 100644 index 0000000000000..67d5fce845765 --- /dev/null +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -0,0 +1,80 @@ +//===--- WebAssembly.h - WebAssembly ToolChain Implementations --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace wasm { + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: +  explicit Linker(const ToolChain &TC) +      : GnuTool("wasm::Linker", "linker", TC) {} +  bool isLinkJob() const override { return true; } +  bool hasIntegratedCPP() const override { return false; } +  std::string getLinkerPath(const llvm::opt::ArgList &Args) const; +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +} // end namespace wasm +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain { +public: +  WebAssembly(const Driver &D, const llvm::Triple &Triple, +              const llvm::opt::ArgList &Args); + +private: +  bool IsMathErrnoDefault() const override; +  bool IsObjCNonFragileABIDefault() const override; +  bool UseObjCMixedDispatch() const override; +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; +  bool IsIntegratedAssemblerDefault() const override; +  bool hasBlocksRuntime() const override; +  bool SupportsProfiling() const override; +  bool HasNativeLLVMSupport() const override; +  void +  addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                        llvm::opt::ArgStringList &CC1Args, +                        Action::OffloadKind DeviceOffloadKind) const override; +  RuntimeLibType GetDefaultRuntimeLibType() const override; +  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; +  SanitizerMask getSupportedSanitizers() const override; + +  const char *getDefaultLinker() const override { return "wasm-ld"; } + +  Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H diff --git a/clang/lib/Driver/ToolChains/XCore.cpp b/clang/lib/Driver/ToolChains/XCore.cpp new file mode 100644 index 0000000000000..ba3a6d44addaf --- /dev/null +++ b/clang/lib/Driver/ToolChains/XCore.cpp @@ -0,0 +1,149 @@ +//===--- XCore.cpp - XCore ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "XCore.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// XCore Tools +// We pass assemble and link construction to the xcc tool. + +void tools::XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  CmdArgs.push_back("-c"); + +  if (Args.hasArg(options::OPT_v)) +    CmdArgs.push_back("-v"); + +  if (Arg *A = Args.getLastArg(options::OPT_g_Group)) +    if (!A->getOption().matches(options::OPT_g0)) +      CmdArgs.push_back("-g"); + +  if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, +                   false)) +    CmdArgs.push_back("-fverbose-asm"); + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  for (const auto &II : Inputs) +    CmdArgs.push_back(II.getFilename()); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                        const InputInfo &Output, +                                        const InputInfoList &Inputs, +                                        const ArgList &Args, +                                        const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if (Args.hasArg(options::OPT_v)) +    CmdArgs.push_back("-v"); + +  // Pass -fexceptions through to the linker if it was present. +  if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, +                   false)) +    CmdArgs.push_back("-fexceptions"); + +  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + +  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// XCore tool chain +XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, +                               const ArgList &Args) +    : ToolChain(D, Triple, Args) { +  // ProgramPaths are found via 'PATH' environment variable. +} + +Tool *XCoreToolChain::buildAssembler() const { +  return new tools::XCore::Assembler(*this); +} + +Tool *XCoreToolChain::buildLinker() const { +  return new tools::XCore::Linker(*this); +} + +bool XCoreToolChain::isPICDefault() const { return false; } + +bool XCoreToolChain::isPIEDefault() const { return false; } + +bool XCoreToolChain::isPICDefaultForced() const { return false; } + +bool XCoreToolChain::SupportsProfiling() const { return false; } + +bool XCoreToolChain::hasBlocksRuntime() const { return false; } + +void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                               ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; +  if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) { +    SmallVector<StringRef, 4> Dirs; +    const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; +    StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); +    ArrayRef<StringRef> DirVec(Dirs); +    addSystemIncludes(DriverArgs, CC1Args, DirVec); +  } +} + +void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, +                                           ArgStringList &CC1Args, +                                           Action::OffloadKind) const { +  CC1Args.push_back("-nostdsysteminc"); +} + +void XCoreToolChain::AddClangCXXStdlibIncludeArgs( +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; +  if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) { +    SmallVector<StringRef, 4> Dirs; +    const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; +    StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); +    ArrayRef<StringRef> DirVec(Dirs); +    addSystemIncludes(DriverArgs, CC1Args, DirVec); +  } +} + +void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args, +                                         ArgStringList &CmdArgs) const { +  // We don't output any lib args. This is handled by xcc. +} diff --git a/clang/lib/Driver/ToolChains/XCore.h b/clang/lib/Driver/ToolChains/XCore.h new file mode 100644 index 0000000000000..41dce08454c0b --- /dev/null +++ b/clang/lib/Driver/ToolChains/XCore.h @@ -0,0 +1,82 @@ +//===--- XCore.h - XCore ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace XCore { +// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and +// Compile. +// We simply use "clang -cc1" for those actions. +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: +  Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {} + +  bool hasIntegratedCPP() const override { return false; } +  bool isLinkJob() const override { return true; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; +} // end namespace XCore. +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain { +public: +  XCoreToolChain(const Driver &D, const llvm::Triple &Triple, +                 const llvm::opt::ArgList &Args); + +protected: +  Tool *buildAssembler() const override; +  Tool *buildLinker() const override; + +public: +  bool isPICDefault() const override; +  bool isPIEDefault() const override; +  bool isPICDefaultForced() const override; +  bool SupportsProfiling() const override; +  bool hasBlocksRuntime() const override; +  void +  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                            llvm::opt::ArgStringList &CC1Args) const override; +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args, +                             Action::OffloadKind DeviceOffloadKind) const override; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp new file mode 100644 index 0000000000000..a30710645af3a --- /dev/null +++ b/clang/lib/Driver/Types.cpp @@ -0,0 +1,400 @@ +//===--- Types.cpp - Driver input & temporary type information ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Types.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include <cassert> +#include <cstring> + +using namespace clang::driver; +using namespace clang::driver::types; + +struct TypeInfo { +  const char *Name; +  const char *TempSuffix; +  ID PreprocessedType; +  const llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> Phases; +}; + +static const TypeInfo TypeInfos[] = { +#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, ...) \ +  { NAME, TEMP_SUFFIX, TY_##PP_TYPE, { __VA_ARGS__ }, }, +#include "clang/Driver/Types.def" +#undef TYPE +}; +static const unsigned numTypes = llvm::array_lengthof(TypeInfos); + +static const TypeInfo &getInfo(unsigned id) { +  assert(id > 0 && id - 1 < numTypes && "Invalid Type ID."); +  return TypeInfos[id - 1]; +} + +const char *types::getTypeName(ID Id) { +  return getInfo(Id).Name; +} + +types::ID types::getPreprocessedType(ID Id) { +  ID PPT = getInfo(Id).PreprocessedType; +  assert((llvm::is_contained(getInfo(Id).Phases, phases::Preprocess) != +          (PPT == TY_INVALID)) && +         "Unexpected Preprocess Type."); +  return PPT; +} + +static bool isPrepeocessedModuleType(ID Id) { +  return Id == TY_CXXModule || Id == TY_PP_CXXModule; +} + +types::ID types::getPrecompiledType(ID Id) { +  if (isPrepeocessedModuleType(Id)) +    return TY_ModuleFile; +  if (onlyPrecompileType(Id)) +    return TY_PCH; +  return TY_INVALID; +} + +const char *types::getTypeTempSuffix(ID Id, bool CLMode) { +  if (CLMode) { +    switch (Id) { +    case TY_Object: +    case TY_LTO_BC: +      return "obj"; +    case TY_Image: +      return "exe"; +    case TY_PP_Asm: +      return "asm"; +    default: +      break; +    } +  } +  return getInfo(Id).TempSuffix; +} + +bool types::onlyAssembleType(ID Id) { +  return llvm::is_contained(getInfo(Id).Phases, phases::Assemble) && +         !llvm::is_contained(getInfo(Id).Phases, phases::Compile) && +         !llvm::is_contained(getInfo(Id).Phases, phases::Backend); +} + +bool types::onlyPrecompileType(ID Id) { +  return llvm::is_contained(getInfo(Id).Phases, phases::Precompile) && +         !isPrepeocessedModuleType(Id); +} + +bool types::canTypeBeUserSpecified(ID Id) { +  static const clang::driver::types::ID kStaticLangageTypes[] = { +      TY_CUDA_DEVICE,   TY_HIP_DEVICE,    TY_PP_CHeader, +      TY_PP_ObjCHeader, TY_PP_CXXHeader,  TY_PP_ObjCXXHeader, +      TY_PP_CXXModule,  TY_LTO_IR,        TY_LTO_BC, +      TY_Plist,         TY_RewrittenObjC, TY_RewrittenLegacyObjC, +      TY_Remap,         TY_PCH,           TY_Object, +      TY_Image,         TY_dSYM,          TY_Dependencies, +      TY_CUDA_FATBIN,   TY_HIP_FATBIN}; +  return !llvm::is_contained(kStaticLangageTypes, Id); +} + +bool types::appendSuffixForType(ID Id) { +  return Id == TY_PCH || Id == TY_dSYM || Id == TY_CUDA_FATBIN || +         Id == TY_HIP_FATBIN; +} + +bool types::canLipoType(ID Id) { +  return (Id == TY_Nothing || +          Id == TY_Image || +          Id == TY_Object || +          Id == TY_LTO_BC); +} + +bool types::isAcceptedByClang(ID Id) { +  switch (Id) { +  default: +    return false; + +  case TY_Asm: +  case TY_C: case TY_PP_C: +  case TY_CL: +  case TY_CUDA: case TY_PP_CUDA: +  case TY_CUDA_DEVICE: +  case TY_HIP: +  case TY_PP_HIP: +  case TY_HIP_DEVICE: +  case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: +  case TY_CXX: case TY_PP_CXX: +  case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: +  case TY_CHeader: case TY_PP_CHeader: +  case TY_CLHeader: +  case TY_ObjCHeader: case TY_PP_ObjCHeader: +  case TY_CXXHeader: case TY_PP_CXXHeader: +  case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: +  case TY_CXXModule: case TY_PP_CXXModule: +  case TY_AST: case TY_ModuleFile: +  case TY_LLVM_IR: case TY_LLVM_BC: +    return true; +  } +} + +bool types::isObjC(ID Id) { +  switch (Id) { +  default: +    return false; + +  case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: +  case TY_ObjCXX: case TY_PP_ObjCXX: +  case TY_ObjCHeader: case TY_PP_ObjCHeader: +  case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_PP_ObjCXX_Alias: +    return true; +  } +} + +bool types::isCXX(ID Id) { +  switch (Id) { +  default: +    return false; + +  case TY_CXX: case TY_PP_CXX: +  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_CXXModule: case TY_PP_CXXModule: +  case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: +  case TY_HIP: +  case TY_PP_HIP: +  case TY_HIP_DEVICE: +    return true; +  } +} + +bool types::isLLVMIR(ID Id) { +  switch (Id) { +  default: +    return false; + +  case TY_LLVM_IR: +  case TY_LLVM_BC: +  case TY_LTO_IR: +  case TY_LTO_BC: +    return true; +  } +} + +bool types::isCuda(ID Id) { +  switch (Id) { +  default: +    return false; + +  case TY_CUDA: +  case TY_PP_CUDA: +  case TY_CUDA_DEVICE: +    return true; +  } +} + +bool types::isHIP(ID Id) { +  switch (Id) { +  default: +    return false; + +  case TY_HIP: +  case TY_PP_HIP: +  case TY_HIP_DEVICE: +    return true; +  } +} + +bool types::isSrcFile(ID Id) { +  return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; +} + +types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { +  return llvm::StringSwitch<types::ID>(Ext) +           .Case("c", TY_C) +           .Case("C", TY_CXX) +           .Case("F", TY_Fortran) +           .Case("f", TY_PP_Fortran) +           .Case("h", TY_CHeader) +           .Case("H", TY_CXXHeader) +           .Case("i", TY_PP_C) +           .Case("m", TY_ObjC) +           .Case("M", TY_ObjCXX) +           .Case("o", TY_Object) +           .Case("S", TY_Asm) +           .Case("s", TY_PP_Asm) +           .Case("bc", TY_LLVM_BC) +           .Case("cc", TY_CXX) +           .Case("CC", TY_CXX) +           .Case("cl", TY_CL) +           .Case("cp", TY_CXX) +           .Case("cu", TY_CUDA) +           .Case("hh", TY_CXXHeader) +           .Case("ii", TY_PP_CXX) +           .Case("ll", TY_LLVM_IR) +           .Case("mi", TY_PP_ObjC) +           .Case("mm", TY_ObjCXX) +           .Case("rs", TY_RenderScript) +           .Case("adb", TY_Ada) +           .Case("ads", TY_Ada) +           .Case("asm", TY_PP_Asm) +           .Case("ast", TY_AST) +           .Case("ccm", TY_CXXModule) +           .Case("cpp", TY_CXX) +           .Case("CPP", TY_CXX) +           .Case("c++", TY_CXX) +           .Case("C++", TY_CXX) +           .Case("cui", TY_PP_CUDA) +           .Case("cxx", TY_CXX) +           .Case("CXX", TY_CXX) +           .Case("F90", TY_Fortran) +           .Case("f90", TY_PP_Fortran) +           .Case("F95", TY_Fortran) +           .Case("f95", TY_PP_Fortran) +           .Case("for", TY_PP_Fortran) +           .Case("FOR", TY_PP_Fortran) +           .Case("fpp", TY_Fortran) +           .Case("FPP", TY_Fortran) +           .Case("gch", TY_PCH) +           .Case("hip", TY_HIP) +           .Case("hpp", TY_CXXHeader) +           .Case("iim", TY_PP_CXXModule) +           .Case("lib", TY_Object) +           .Case("mii", TY_PP_ObjCXX) +           .Case("obj", TY_Object) +           .Case("ifs", TY_IFS) +           .Case("pch", TY_PCH) +           .Case("pcm", TY_ModuleFile) +           .Case("c++m", TY_CXXModule) +           .Case("cppm", TY_CXXModule) +           .Case("cxxm", TY_CXXModule) +           .Default(TY_INVALID); +} + +types::ID types::lookupTypeForTypeSpecifier(const char *Name) { +  for (unsigned i=0; i<numTypes; ++i) { +    types::ID Id = (types::ID) (i + 1); +    if (canTypeBeUserSpecified(Id) && +        strcmp(Name, getInfo(Id).Name) == 0) +      return Id; +  } + +  return TY_INVALID; +} + +// FIXME: Why don't we just put this list in the defs file, eh. +// FIXME: The list is now in Types.def but for now this function will verify +//        the old behavior and a subsequent change will delete most of the body. +void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { +  P = getInfo(Id).Phases; +  assert(0 < P.size() && "Not enough phases in list"); +  assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list"); +} + +void types::getCompilationPhases(const clang::driver::Driver &Driver, +                                 llvm::opt::DerivedArgList &DAL, ID Id, +                                 llvm::SmallVectorImpl<phases::ID> &P) { +  llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList; +  types::getCompilationPhases(Id, PhaseList); + +  // Filter to compiler mode. When the compiler is run as a preprocessor then +  // compilation is not an option. +  // -S runs the compiler in Assembly listing mode. +  if (Driver.CCCIsCPP() || DAL.getLastArg(options::OPT_E) || +      DAL.getLastArg(options::OPT__SLASH_EP) || +      DAL.getLastArg(options::OPT_M, options::OPT_MM) || +      DAL.getLastArg(options::OPT__SLASH_P)) +    llvm::copy_if(PhaseList, std::back_inserter(P), +                  [](phases::ID Phase) { return Phase <= phases::Preprocess; }); + +  // --precompile only runs up to precompilation. +  // This is a clang extension and is not compatible with GCC. +  else if (DAL.getLastArg(options::OPT__precompile)) +    llvm::copy_if(PhaseList, std::back_inserter(P), +                  [](phases::ID Phase) { return Phase <= phases::Precompile; }); + +  // Treat Interface Stubs like its own compilation mode. +  else if (DAL.getLastArg(options::OPT_emit_interface_stubs)) { +    llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList; +    llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList; +    phases::ID LastPhase = phases::IfsMerge; +    if (Id != types::TY_IFS) { +      if (DAL.hasArg(options::OPT_c)) +        LastPhase = phases::Compile; +      PL = IfsModePhaseList; +      types::getCompilationPhases(types::TY_IFS_CPP, PL); +    } +    llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) { +      return Phase <= LastPhase; +    }); +  } + +  // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. +  else if (DAL.getLastArg(options::OPT_fsyntax_only) || +           DAL.getLastArg(options::OPT_print_supported_cpus) || +           DAL.getLastArg(options::OPT_module_file_info) || +           DAL.getLastArg(options::OPT_verify_pch) || +           DAL.getLastArg(options::OPT_rewrite_objc) || +           DAL.getLastArg(options::OPT_rewrite_legacy_objc) || +           DAL.getLastArg(options::OPT__migrate) || +           DAL.getLastArg(options::OPT__analyze) || +           DAL.getLastArg(options::OPT_emit_ast)) +    llvm::copy_if(PhaseList, std::back_inserter(P), +                  [](phases::ID Phase) { return Phase <= phases::Compile; }); + +  else if (DAL.getLastArg(options::OPT_S) || +           DAL.getLastArg(options::OPT_emit_llvm)) +    llvm::copy_if(PhaseList, std::back_inserter(P), +                  [](phases::ID Phase) { return Phase <= phases::Backend; }); + +  else if (DAL.getLastArg(options::OPT_c)) +    llvm::copy_if(PhaseList, std::back_inserter(P), +                  [](phases::ID Phase) { return Phase <= phases::Assemble; }); + +  // Generally means, do every phase until Link. +  else +    P = PhaseList; +} + +ID types::lookupCXXTypeForCType(ID Id) { +  switch (Id) { +  default: +    return Id; + +  case types::TY_C: +    return types::TY_CXX; +  case types::TY_PP_C: +    return types::TY_PP_CXX; +  case types::TY_CHeader: +    return types::TY_CXXHeader; +  case types::TY_PP_CHeader: +    return types::TY_PP_CXXHeader; +  } +} + +ID types::lookupHeaderTypeForSourceType(ID Id) { +  switch (Id) { +  default: +    return Id; + +  // FIXME: Handle preprocessed input types. +  case types::TY_C: +    return types::TY_CHeader; +  case types::TY_CXX: +  case types::TY_CXXModule: +    return types::TY_CXXHeader; +  case types::TY_ObjC: +    return types::TY_ObjCHeader; +  case types::TY_ObjCXX: +    return types::TY_ObjCXXHeader; +  case types::TY_CL: +    return types::TY_CLHeader; +  } +} diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp new file mode 100644 index 0000000000000..16e7c7ecf36b4 --- /dev/null +++ b/clang/lib/Driver/XRayArgs.cpp @@ -0,0 +1,241 @@ +//===--- XRayArgs.cpp - Arguments for XRay --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "clang/Driver/XRayArgs.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/SpecialCaseList.h" + +using namespace clang; +using namespace clang::driver; +using namespace llvm::opt; + +namespace { +constexpr char XRayInstrumentOption[] = "-fxray-instrument"; +constexpr char XRayInstructionThresholdOption[] = +    "-fxray-instruction-threshold="; +constexpr const char *const XRaySupportedModes[] = {"xray-fdr", "xray-basic"}; +} // namespace + +XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { +  const Driver &D = TC.getDriver(); +  const llvm::Triple &Triple = TC.getTriple(); +  if (Args.hasFlag(options::OPT_fxray_instrument, +                   options::OPT_fnoxray_instrument, false)) { +    if (Triple.getOS() == llvm::Triple::Linux) { +      switch (Triple.getArch()) { +      case llvm::Triple::x86_64: +      case llvm::Triple::arm: +      case llvm::Triple::aarch64: +      case llvm::Triple::ppc64le: +      case llvm::Triple::mips: +      case llvm::Triple::mipsel: +      case llvm::Triple::mips64: +      case llvm::Triple::mips64el: +        break; +      default: +        D.Diag(diag::err_drv_clang_unsupported) +            << (std::string(XRayInstrumentOption) + " on " + Triple.str()); +      } +    } else if (Triple.isOSFreeBSD() || +               Triple.isOSOpenBSD() || +               Triple.isOSNetBSD() || +               Triple.isMacOSX()) { +      if (Triple.getArch() != llvm::Triple::x86_64) { +        D.Diag(diag::err_drv_clang_unsupported) +            << (std::string(XRayInstrumentOption) + " on " + Triple.str()); +      } +    } else if (Triple.getOS() == llvm::Triple::Fuchsia) { +      switch (Triple.getArch()) { +      case llvm::Triple::x86_64: +      case llvm::Triple::aarch64: +        break; +      default: +        D.Diag(diag::err_drv_clang_unsupported) +            << (std::string(XRayInstrumentOption) + " on " + Triple.str()); +      } +    } else { +      D.Diag(diag::err_drv_clang_unsupported) +          << (std::string(XRayInstrumentOption) + " on " + Triple.str()); +    } +    XRayInstrument = true; +    if (const Arg *A = +            Args.getLastArg(options::OPT_fxray_instruction_threshold_, +                            options::OPT_fxray_instruction_threshold_EQ)) { +      StringRef S = A->getValue(); +      if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) +        D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; +    } + +    // By default, the back-end will not emit the lowering for XRay customevent +    // calls if the function is not instrumented. In the future we will change +    // this default to be the reverse, but in the meantime we're going to +    // introduce the new functionality behind a flag. +    if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, +                     options::OPT_fnoxray_always_emit_customevents, false)) +      XRayAlwaysEmitCustomEvents = true; + +    if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, +                     options::OPT_fnoxray_always_emit_typedevents, false)) +      XRayAlwaysEmitTypedEvents = true; + +    if (!Args.hasFlag(options::OPT_fxray_link_deps, +                      options::OPT_fnoxray_link_deps, true)) +      XRayRT = false; + +    auto Bundles = +        Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); +    if (Bundles.empty()) +      InstrumentationBundle.Mask = XRayInstrKind::All; +    else +      for (const auto &B : Bundles) { +        llvm::SmallVector<StringRef, 2> BundleParts; +        llvm::SplitString(B, BundleParts, ","); +        for (const auto &P : BundleParts) { +          // TODO: Automate the generation of the string case table. +          auto Valid = llvm::StringSwitch<bool>(P) +                           .Cases("none", "all", "function", "custom", true) +                           .Default(false); + +          if (!Valid) { +            D.Diag(clang::diag::err_drv_invalid_value) +                << "-fxray-instrumentation-bundle=" << P; +            continue; +          } + +          auto Mask = parseXRayInstrValue(P); +          if (Mask == XRayInstrKind::None) { +            InstrumentationBundle.clear(); +            break; +          } + +          InstrumentationBundle.Mask |= Mask; +        } +      } + +    // Validate the always/never attribute files. We also make sure that they +    // are treated as actual dependencies. +    for (const auto &Filename : +         Args.getAllArgValues(options::OPT_fxray_always_instrument)) { +      if (llvm::sys::fs::exists(Filename)) { +        AlwaysInstrumentFiles.push_back(Filename); +        ExtraDeps.push_back(Filename); +      } else +        D.Diag(clang::diag::err_drv_no_such_file) << Filename; +    } + +    for (const auto &Filename : +         Args.getAllArgValues(options::OPT_fxray_never_instrument)) { +      if (llvm::sys::fs::exists(Filename)) { +        NeverInstrumentFiles.push_back(Filename); +        ExtraDeps.push_back(Filename); +      } else +        D.Diag(clang::diag::err_drv_no_such_file) << Filename; +    } + +    for (const auto &Filename : +         Args.getAllArgValues(options::OPT_fxray_attr_list)) { +      if (llvm::sys::fs::exists(Filename)) { +        AttrListFiles.push_back(Filename); +        ExtraDeps.push_back(Filename); +      } else +        D.Diag(clang::diag::err_drv_no_such_file) << Filename; +    } + +    // Get the list of modes we want to support. +    auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); +    if (SpecifiedModes.empty()) +      llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); +    else +      for (const auto &Arg : SpecifiedModes) { +        // Parse CSV values for -fxray-modes=... +        llvm::SmallVector<StringRef, 2> ModeParts; +        llvm::SplitString(Arg, ModeParts, ","); +        for (const auto &M : ModeParts) +          if (M == "none") +            Modes.clear(); +          else if (M == "all") +            llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); +          else +            Modes.push_back(M); +      } + +    // Then we want to sort and unique the modes we've collected. +    llvm::sort(Modes); +    Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); +  } +} + +void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, +                       ArgStringList &CmdArgs, types::ID InputType) const { +  if (!XRayInstrument) +    return; + +  CmdArgs.push_back(XRayInstrumentOption); + +  if (XRayAlwaysEmitCustomEvents) +    CmdArgs.push_back("-fxray-always-emit-customevents"); + +  if (XRayAlwaysEmitTypedEvents) +    CmdArgs.push_back("-fxray-always-emit-typedevents"); + +  CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + +                                       Twine(InstructionThreshold))); + +  for (const auto &Always : AlwaysInstrumentFiles) { +    SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); +    AlwaysInstrumentOpt += Always; +    CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); +  } + +  for (const auto &Never : NeverInstrumentFiles) { +    SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); +    NeverInstrumentOpt += Never; +    CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); +  } + +  for (const auto &AttrFile : AttrListFiles) { +    SmallString<64> AttrListFileOpt("-fxray-attr-list="); +    AttrListFileOpt += AttrFile; +    CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); +  } + +  for (const auto &Dep : ExtraDeps) { +    SmallString<64> ExtraDepOpt("-fdepfile-entry="); +    ExtraDepOpt += Dep; +    CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); +  } + +  for (const auto &Mode : Modes) { +    SmallString<64> ModeOpt("-fxray-modes="); +    ModeOpt += Mode; +    CmdArgs.push_back(Args.MakeArgString(ModeOpt)); +  } + +  SmallString<64> Bundle("-fxray-instrumentation-bundle="); +  if (InstrumentationBundle.full()) { +    Bundle += "all"; +  } else if (InstrumentationBundle.empty()) { +    Bundle += "none"; +  } else { +    if (InstrumentationBundle.has(XRayInstrKind::Function)) +      Bundle += "function"; +    if (InstrumentationBundle.has(XRayInstrKind::Custom)) +      Bundle += "custom"; +    if (InstrumentationBundle.has(XRayInstrKind::Typed)) +      Bundle += "typed"; +  } +  CmdArgs.push_back(Args.MakeArgString(Bundle)); +}  | 
