diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Action.cpp | 232 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Compilation.cpp | 52 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Driver.cpp | 773 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Job.cpp | 44 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp | 135 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp | 227 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp | 80 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp | 1267 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/ToolChains.h | 116 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Tools.cpp | 1456 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Tools.h | 61 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Types.cpp | 5 |
13 files changed, 3333 insertions, 1117 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Action.cpp b/contrib/llvm/tools/clang/lib/Driver/Action.cpp index e9490e96db8d..29a46794d4b9 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Action.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Action.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Action.h" +#include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Regex.h" @@ -21,8 +22,8 @@ const char *Action::getClassName(ActionClass AC) { switch (AC) { case InputClass: return "input"; case BindArchClass: return "bind-arch"; - case CudaDeviceClass: return "cuda-device"; - case CudaHostClass: return "cuda-host"; + case OffloadClass: + return "offload"; case PreprocessJobClass: return "preprocessor"; case PrecompileJobClass: return "precompiler"; case AnalyzeJobClass: return "analyzer"; @@ -40,6 +41,82 @@ const char *Action::getClassName(ActionClass AC) { 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; + + 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"; + + // TODO: Add other programming models here. + } + + if (!ActiveOffloadKindMask) + return ""; + + std::string Res("host"); + if (ActiveOffloadKindMask & OFK_Cuda) + Res += "-cuda"; + + // TODO: Add other programming models here. + + return Res; +} + +std::string +Action::getOffloadingFileNamePrefix(llvm::StringRef NormalizedTriple) const { + // A file prefix is only generated for device actions and consists of the + // offload kind and triple. + if (!OffloadingDeviceKind) + return ""; + + std::string Res("-"); + Res += getOffloadingKindPrefix(); + Res += "-"; + Res += NormalizedTriple; + return Res; +} + void InputAction::anchor() {} InputAction::InputAction(const Arg &_Input, types::ID _Type) @@ -51,45 +128,138 @@ void BindArchAction::anchor() {} BindArchAction::BindArchAction(Action *Input, const char *_ArchName) : Action(BindArchClass, Input), ArchName(_ArchName) {} -// Converts CUDA GPU architecture, e.g. "sm_21", to its corresponding virtual -// compute arch, e.g. "compute_20". Returns null if the input arch is null or -// doesn't match an existing arch. -static const char* GpuArchToComputeName(const char *ArchName) { - if (!ArchName) - return nullptr; - return llvm::StringSwitch<const char *>(ArchName) - .Cases("sm_20", "sm_21", "compute_20") - .Case("sm_30", "compute_30") - .Case("sm_32", "compute_32") - .Case("sm_35", "compute_35") - .Case("sm_37", "compute_37") - .Case("sm_50", "compute_50") - .Case("sm_52", "compute_52") - .Case("sm_53", "compute_53") - .Default(nullptr); +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 CudaDeviceAction::anchor() {} +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()); +} -CudaDeviceAction::CudaDeviceAction(Action *Input, const char *ArchName, - bool AtTopLevel) - : Action(CudaDeviceClass, Input), GpuArchName(ArchName), - AtTopLevel(AtTopLevel) { - assert(IsValidGpuArchName(GpuArchName)); +void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const { + doOnHostDependence(Work); + doOnEachDeviceDependence(Work); } -const char *CudaDeviceAction::getComputeArchName() const { - return GpuArchToComputeName(GpuArchName); +void OffloadAction::doOnEachDependence(bool IsHostDependence, + const OffloadActionWorkTy &Work) const { + if (IsHostDependence) + doOnHostDependence(Work); + else + doOnEachDeviceDependence(Work); } -bool CudaDeviceAction::IsValidGpuArchName(llvm::StringRef ArchName) { - return GpuArchToComputeName(ArchName.data()) != nullptr; +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; } -void CudaHostAction::anchor() {} +bool OffloadAction::hasSingleDeviceDependence( + bool DoNotConsiderHostActions) const { + if (DoNotConsiderHostActions) + return getInputs().size() == (HostTC ? 2 : 1); + return !HostTC && getInputs().size() == 1; +} -CudaHostAction::CudaHostAction(Action *Input, const ActionList &DeviceActions) - : Action(CudaHostClass, Input), DeviceActions(DeviceActions) {} +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() {} diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index 1c2eecd3ccc5..6a2616f0c2a4 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -24,10 +24,13 @@ using namespace llvm::opt; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) - : TheDriver(D), DefaultToolChain(_DefaultToolChain), - CudaHostToolChain(&DefaultToolChain), CudaDeviceToolChain(nullptr), + : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u), Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr), - ForDiagnostics(false) {} + ForDiagnostics(false) { + // The offloading host toolchain is the default tool chain. + OrderedOffloadingToolchains.insert( + std::make_pair(Action::OFK_Host, &DefaultToolChain)); +} Compilation::~Compilation() { delete TranslatedArgs; @@ -42,6 +45,7 @@ Compilation::~Compilation() { // Free redirections of stdout/stderr. if (Redirects) { + delete Redirects[0]; delete Redirects[1]; delete Redirects[2]; delete [] Redirects; @@ -163,39 +167,17 @@ int Compilation::ExecuteCommand(const Command &C, return ExecutionFailed ? 1 : Res; } -typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList; - -static bool ActionFailed(const Action *A, - const FailingCommandList &FailingCommands) { - - if (FailingCommands.empty()) - return false; - - for (FailingCommandList::const_iterator CI = FailingCommands.begin(), - CE = FailingCommands.end(); CI != CE; ++CI) - if (A == &(CI->second->getSource())) - return true; - - for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI) - if (ActionFailed(*AI, FailingCommands)) - return true; - - return false; -} - -static bool InputsOk(const Command &C, - const FailingCommandList &FailingCommands) { - return !ActionFailed(&C.getSource(), FailingCommands); -} - -void Compilation::ExecuteJobs(const JobList &Jobs, - FailingCommandList &FailingCommands) const { +void Compilation::ExecuteJobs( + const JobList &Jobs, + SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const { for (const auto &Job : Jobs) { - if (!InputsOk(Job, FailingCommands)) - continue; const Command *FailingCommand = nullptr; - if (int Res = ExecuteCommand(Job, FailingCommand)) + if (int Res = ExecuteCommand(Job, FailingCommand)) { FailingCommands.push_back(std::make_pair(Res, FailingCommand)); + // Bail as soon as one command fails, so we don't output duplicate error + // messages if we die on e.g. the same file. + return; + } } } @@ -232,3 +214,7 @@ void Compilation::initCompilationForDiagnostics() { StringRef Compilation::getSysRoot() const { return getDriver().SysRoot; } + +void Compilation::Redirect(const StringRef** Redirects) { + this->Redirects = Redirects; +} diff --git a/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp index 57bf89635987..4ebbc533232f 100644 --- a/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp @@ -62,6 +62,8 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::sys::path::append(ResourceDir, "include"); addSystemInclude(DriverArgs, CC1Args, ResourceDir); } + for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) + addSystemInclude(DriverArgs, CC1Args, P); addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 1e0a48d52928..02f4a9997711 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -23,6 +23,7 @@ #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" @@ -41,6 +42,7 @@ #include "llvm/Support/raw_ostream.h" #include <map> #include <memory> +#include <utility> using namespace clang::driver; using namespace clang; @@ -49,9 +51,9 @@ using namespace llvm::opt; Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, DiagnosticsEngine &Diags, IntrusiveRefCntPtr<vfs::FileSystem> VFS) - : Opts(createDriverOptTable()), Diags(Diags), VFS(VFS), Mode(GCCMode), - SaveTemps(SaveTempsNone), LTOMode(LTOK_None), - ClangExecutable(ClangExecutable), + : Opts(createDriverOptTable()), Diags(Diags), VFS(std::move(VFS)), + Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), + LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), @@ -146,7 +148,9 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { } for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) - Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); + Diags.Report(IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl : + diag::err_drv_unknown_argument) + << A->getAsString(Args); return Args; } @@ -276,6 +280,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { 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) @@ -294,7 +302,8 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { /// /// 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(StringRef DefaultTargetTriple, +static llvm::Triple computeTargetTriple(const Driver &D, + StringRef DefaultTargetTriple, const ArgList &Args, StringRef DarwinArchName = "") { // FIXME: Already done in Compilation *Driver::BuildCompilation @@ -339,8 +348,9 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, return Target; // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. - if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, - options::OPT_m32, options::OPT_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)) { @@ -365,6 +375,25 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, 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"); + } + return Target; } @@ -394,6 +423,33 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) { } } +void Driver::CreateOffloadingDeviceToolChains(Compilation &C, + InputList &Inputs) { + + // + // CUDA + // + // We need to generate a CUDA toolchain if any of the inputs has a CUDA type. + if (llvm::any_of(Inputs, [](std::pair<types::ID, const llvm::opt::Arg *> &I) { + return types::isCuda(I.first); + })) { + const ToolChain &TC = getToolChain( + C.getInputArgs(), + llvm::Triple(C.getSingleOffloadToolChain<Action::OFK_Host>() + ->getTriple() + .isArch64Bit() + ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda")); + C.addOffloadDeviceToolChain(&TC, Action::OFK_Cuda); + } + + // + // TODO: Add support for other offloading programming models here. + // + + return; +} + Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); @@ -479,6 +535,28 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { setLTOMode(Args); + // Ignore -fembed-bitcode options with LTO + // since the output will be bitcode anyway. + if (getLTOMode() == LTOK_None) { + 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); + } + } else { + // claim the bitcode option under LTO so no warning is issued. + Args.ClaimAllArgs(options::OPT_fembed_bitcode_EQ); + } + std::unique_ptr<llvm::opt::InputArgList> UArgs = llvm::make_unique<InputArgList>(std::move(Args)); @@ -486,16 +564,12 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); // Owned by the host. - const ToolChain &TC = - getToolChain(*UArgs, computeTargetTriple(DefaultTargetTriple, *UArgs)); + const ToolChain &TC = getToolChain( + *UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs)); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs); - C->setCudaDeviceToolChain( - &getToolChain(C->getArgs(), llvm::Triple(TC.getTriple().isArch64Bit() - ? "nvptx64-nvidia-cuda" - : "nvptx-nvidia-cuda"))); if (!HandleImmediateArgs(*C)) return C; @@ -503,13 +577,15 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { 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->getDefaultToolChain(), C->getArgs(), Inputs, - C->getActions()); + BuildActions(*C, C->getArgs(), Inputs, C->getActions()); if (CCCPrintPhases) { PrintActions(*C); @@ -623,7 +699,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, if (TC.getTriple().isOSBinFormatMachO()) BuildUniversalActions(C, TC, Inputs); else - BuildActions(C, TC, C.getArgs(), Inputs, C.getActions()); + BuildActions(C, C.getArgs(), Inputs, C.getActions()); BuildJobs(C); @@ -947,18 +1023,34 @@ static unsigned PrintActions1(const Compilation &C, Action *A, os << "\"" << IA->getInputArg().getValue() << "\""; } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { os << '"' << BIA->getArchName() << '"' << ", {" - << PrintActions1(C, *BIA->begin(), Ids) << "}"; - } else if (CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { - os << '"' << CDA->getGpuArchName() << '"' << ", {" - << PrintActions1(C, *CDA->begin(), Ids) << "}"; + << PrintActions1(C, *BIA->input_begin(), Ids) << "}"; + } 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) << "}"; + IsFirst = false; + }); } else { - const ActionList *AL; - if (CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { - os << "{" << PrintActions1(C, *CHA->begin(), Ids) << "}" - << ", gpu binaries "; - AL = &CHA->getDeviceActions(); - } else - AL = &A->getInputs(); + const ActionList *AL = &A->getInputs(); if (AL->size()) { const char *Prefix = "{"; @@ -971,10 +1063,24 @@ static unsigned PrintActions1(const Compilation &C, Action *A, 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 << ")"; + } + } + unsigned Id = Ids.size(); Ids[A] = Id; llvm::errs() << Id << ": " << os.str() << ", " - << types::getTypeName(A->getType()) << "\n"; + << types::getTypeName(A->getType()) << offload_os.str() << "\n"; return Id; } @@ -994,7 +1100,7 @@ static bool ContainsCompileOrAssembleAction(const Action *A) { isa<AssembleJobAction>(A)) return true; - for (const Action *Input : *A) + for (const Action *Input : A->inputs()) if (ContainsCompileOrAssembleAction(Input)) return true; @@ -1033,7 +1139,7 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); ActionList SingleActions; - BuildActions(C, TC, Args, BAInputs, SingleActions); + BuildActions(C, Args, BAInputs, SingleActions); // Add in arch bindings for every top level action, as well as lipo and // dsymutil steps if needed. @@ -1091,7 +1197,7 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, /// \brief Check that the file referenced by Value exists. If it doesn't, /// issue a diagnostic and return false. static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args, - StringRef Value) { + StringRef Value, types::ID Ty) { if (!D.getCheckInputsExist()) return true; @@ -1111,9 +1217,18 @@ static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args, if (llvm::sys::fs::exists(Twine(Path))) return true; - if (D.IsCLMode() && !llvm::sys::path::is_absolute(Twine(Path)) && - llvm::sys::Process::FindInEnvPath("LIB", Value)) - return true; + if (D.IsCLMode()) { + if (!llvm::sys::path::is_absolute(Twine(Path)) && + 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; + } + } D.Diag(clang::diag::err_drv_no_such_file) << Path; return false; @@ -1229,19 +1344,19 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } - if (DiagnoseInputExistence(*this, Args, Value)) + if (DiagnoseInputExistence(*this, Args, Value, Ty)) Inputs.push_back(std::make_pair(Ty, A)); } else if (A->getOption().matches(options::OPT__SLASH_Tc)) { StringRef Value = A->getValue(); - if (DiagnoseInputExistence(*this, Args, Value)) { + if (DiagnoseInputExistence(*this, Args, Value, types::TY_C)) { 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(*this, Args, Value)) { + if (DiagnoseInputExistence(*this, Args, Value, types::TY_CXX)) { Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); Inputs.push_back(std::make_pair(types::TY_CXX, InputArg)); } @@ -1283,32 +1398,43 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, static Action *buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg, Action *HostAction, ActionList &Actions) { - Arg *PartialCompilationArg = Args.getLastArg(options::OPT_cuda_host_only, - options::OPT_cuda_device_only); - // Host-only compilation case. - if (PartialCompilationArg && - PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only)) - return C.MakeAction<CudaHostAction>(HostAction, ActionList()); + Arg *PartialCompilationArg = Args.getLastArg( + options::OPT_cuda_host_only, options::OPT_cuda_device_only, + options::OPT_cuda_compile_host_device); + bool CompileHostOnly = + PartialCompilationArg && + PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only); + bool CompileDeviceOnly = + PartialCompilationArg && + PartialCompilationArg->getOption().matches(options::OPT_cuda_device_only); + + if (CompileHostOnly) { + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch=*/nullptr, Action::OFK_Cuda); + return C.MakeAction<OffloadAction>(HDep); + } // Collect all cuda_gpu_arch parameters, removing duplicates. - SmallVector<const char *, 4> GpuArchList; - llvm::StringSet<> GpuArchNames; + SmallVector<CudaArch, 4> GpuArchList; + llvm::SmallSet<CudaArch, 4> GpuArchs; for (Arg *A : Args) { if (!A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) continue; A->claim(); - const auto& Arch = A->getValue(); - if (!CudaDeviceAction::IsValidGpuArchName(Arch)) - C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << Arch; - else if (GpuArchNames.insert(Arch).second) + const auto &ArchStr = A->getValue(); + CudaArch Arch = StringToCudaArch(ArchStr); + if (Arch == CudaArch::UNKNOWN) + C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; + else if (GpuArchs.insert(Arch).second) 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("sm_20"); + GpuArchList.push_back(CudaArch::SM_20); // Replicate inputs for each GPU architecture. Driver::InputList CudaDeviceInputs; @@ -1316,61 +1442,81 @@ static Action *buildCudaActions(Compilation &C, DerivedArgList &Args, CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg)); // Build actions for all device inputs. - assert(C.getCudaDeviceToolChain() && - "Missing toolchain for device-side compilation."); ActionList CudaDeviceActions; - C.getDriver().BuildActions(C, *C.getCudaDeviceToolChain(), Args, - CudaDeviceInputs, CudaDeviceActions); + C.getDriver().BuildActions(C, Args, CudaDeviceInputs, CudaDeviceActions); assert(GpuArchList.size() == CudaDeviceActions.size() && "Failed to create actions for all devices"); // Check whether any of device actions stopped before they could generate PTX. bool PartialCompilation = llvm::any_of(CudaDeviceActions, [](const Action *a) { - return a->getKind() != Action::BackendJobClass; + return a->getKind() != Action::AssembleJobClass; }); + const ToolChain *CudaTC = C.getSingleOffloadToolChain<Action::OFK_Cuda>(); + // Figure out what to do with device actions -- pass them as inputs to the // host action or run each of them independently. - bool DeviceOnlyCompilation = PartialCompilationArg != nullptr; - if (PartialCompilation || DeviceOnlyCompilation) { + if (PartialCompilation || CompileDeviceOnly) { // In case of partial or device-only compilation results of device actions // are not consumed by the host action device actions have to be added to // top-level actions list with AtTopLevel=true and run independently. // -o is ambiguous if we have more than one top-level action. if (Args.hasArg(options::OPT_o) && - (!DeviceOnlyCompilation || GpuArchList.size() > 1)) { + (!CompileDeviceOnly || GpuArchList.size() > 1)) { C.getDriver().Diag( clang::diag::err_drv_output_argument_with_multiple_files); return nullptr; } - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) - Actions.push_back(C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I], - GpuArchList[I], - /* AtTopLevel */ true)); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + OffloadAction::DeviceDependences DDep; + DDep.add(*CudaDeviceActions[I], *CudaTC, CudaArchToString(GpuArchList[I]), + Action::OFK_Cuda); + Actions.push_back( + C.MakeAction<OffloadAction>(DDep, CudaDeviceActions[I]->getType())); + } // Kill host action in case of device-only compilation. - if (DeviceOnlyCompilation) + if (CompileDeviceOnly) return nullptr; return HostAction; } - // Outputs of device actions during complete CUDA compilation get created - // with AtTopLevel=false and become inputs for the host action. + // If we're not a partial or device-only compilation, 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 compilation. ActionList DeviceActions; - for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) - DeviceActions.push_back( - C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I], GpuArchList[I], - /* AtTopLevel */ false)); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + 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, *CudaTC, CudaArchToString(GpuArchList[I]), Action::OFK_Cuda); + DeviceActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType())); + } + } + auto FatbinAction = + C.MakeAction<LinkJobAction>(DeviceActions, types::TY_CUDA_FATBIN); + // Return a new host action that incorporates original host action and all // device actions. - return C.MakeAction<CudaHostAction>(HostAction, DeviceActions); + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + /*BoundArch=*/nullptr, Action::OFK_Cuda); + OffloadAction::DeviceDependences DDep; + DDep.add(*FatbinAction, *CudaTC, /*BoundArch=*/nullptr, Action::OFK_Cuda); + return C.MakeAction<OffloadAction>(HDep, DDep); } -void Driver::BuildActions(Compilation &C, const ToolChain &TC, - DerivedArgList &Args, const InputList &Inputs, - ActionList &Actions) const { +void Driver::BuildActions(Compilation &C, DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); if (!SuppressMissingInputWarning && Inputs.empty()) { @@ -1423,6 +1569,61 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, } } + // Diagnose unsupported forms of /Yc /Yu. Ignore /Yc/Yu for now if: + // * no filename after it + // * both /Yc and /Yu passed but with different filenames + // * corresponding file not also passed as /FI + Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); + Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); + if (YcArg && YcArg->getValue()[0] == '\0') { + Diag(clang::diag::warn_drv_ycyu_no_arg_clang_cl) << YcArg->getSpelling(); + Args.eraseArg(options::OPT__SLASH_Yc); + YcArg = nullptr; + } + if (YuArg && YuArg->getValue()[0] == '\0') { + Diag(clang::diag::warn_drv_ycyu_no_arg_clang_cl) << YuArg->getSpelling(); + Args.eraseArg(options::OPT__SLASH_Yu); + YuArg = nullptr; + } + 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 || YuArg) { + StringRef Val = YcArg ? YcArg->getValue() : YuArg->getValue(); + bool FoundMatchingInclude = false; + for (const Arg *Inc : Args.filtered(options::OPT_include)) { + // FIXME: Do case-insensitive matching and consider / and \ as equal. + if (Inc->getValue() == Val) + FoundMatchingInclude = true; + } + if (!FoundMatchingInclude) { + Diag(clang::diag::warn_drv_ycyu_no_fi_arg_clang_cl) + << (YcArg ? YcArg : YuArg)->getSpelling(); + 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; + } + if (Args.hasArg(options::OPT__SLASH_Y_)) { + // /Y- disables all pch handling. 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; + } + + // Track the host offload kinds used on this compilation. + unsigned CompilationActiveOffloadHostKinds = 0u; + // Construct the actions to perform. ActionList LinkerInputs; @@ -1466,12 +1667,34 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, continue; } + if (YcArg) { + // Add a separate precompile phase for the compile phase. + if (FinalPhase >= phases::Compile) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL; + types::getCompilationPhases(types::TY_CXXHeader, PCHPL); + Arg *PchInputArg = MakeInputArg(Args, Opts, YcArg->getValue()); + + // Build the pipeline for the pch file. + Action *ClangClPch = C.MakeAction<InputAction>(*PchInputArg, InputType); + 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. + } + } + phases::ID CudaInjectionPhase = (phases::Compile < FinalPhase && llvm::find(PL, phases::Compile) != PL.end()) ? phases::Compile : FinalPhase; + // Track the host offload kinds used on this input. + unsigned InputActiveOffloadHostKinds = 0u; + // Build the pipeline for this file. Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end(); @@ -1497,27 +1720,42 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, continue; // Otherwise construct the appropriate action. - Current = ConstructPhaseAction(C, TC, Args, Phase, Current); + Current = ConstructPhaseAction(C, Args, Phase, Current); if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase) { Current = buildCudaActions(C, Args, InputArg, Current, Actions); if (!Current) break; + + // We produced a CUDA action for this input, so the host has to support + // CUDA. + InputActiveOffloadHostKinds |= Action::OFK_Cuda; + CompilationActiveOffloadHostKinds |= Action::OFK_Cuda; } if (Current->getType() == types::TY_Nothing) break; } - // If we ended with something, add to the output list. - if (Current) + // If we ended with something, add to the output list. Also, propagate the + // offload information to the top-level host action related with the current + // input. + if (Current) { + if (InputActiveOffloadHostKinds) + Current->propagateHostOffloadInfo(InputActiveOffloadHostKinds, + /*BoundArch=*/nullptr); Actions.push_back(Current); + } } - // Add a link action if necessary. - if (!LinkerInputs.empty()) + // Add a link action if necessary and propagate the offload information for + // the current compilation. + if (!LinkerInputs.empty()) { Actions.push_back( C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image)); + Actions.back()->propagateHostOffloadInfo(CompilationActiveOffloadHostKinds, + /*BoundArch=*/nullptr); + } // If we are linking, claim any options which are obviously only used for // compilation. @@ -1529,14 +1767,14 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC, // Claim ignored clang-cl options. Args.ClaimAllArgs(options::OPT_cl_ignored_Group); - // Claim --cuda-host-only arg which may be passed to non-CUDA - // compilations and should not trigger warnings there. + // 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 ToolChain &TC, - const ArgList &Args, phases::ID Phase, - Action *Input) const { +Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, + phases::ID Phase, Action *Input) const { llvm::PrettyStackTraceString CrashInfo("Constructing phase actions"); // Build the appropriate action. switch (Phase) { @@ -1600,7 +1838,7 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ToolChain &TC, return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm); } case phases::Assemble: - return C.MakeAction<AssembleJobAction>(Input, types::TY_Object); + return C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object); } llvm_unreachable("invalid phase in ConstructPhaseAction"); @@ -1632,6 +1870,8 @@ void Driver::BuildJobs(Compilation &C) const { 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 @@ -1651,7 +1891,8 @@ void Driver::BuildJobs(Compilation &C) const { /*BoundArch*/ nullptr, /*AtTopLevel*/ true, /*MultipleArchs*/ ArchNames.size() > 1, - /*LinkingOutput*/ LinkingOutput); + /*LinkingOutput*/ LinkingOutput, CachedResults, + /*BuildForOffloadDevice*/ false); } // If the user passed -Qunused-arguments or there were errors, don't warn @@ -1663,8 +1904,9 @@ void Driver::BuildJobs(Compilation &C) const { // Claim -### here. (void)C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); - // Claim --driver-mode, it was handled earlier. + // 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 @@ -1691,74 +1933,123 @@ void Driver::BuildJobs(Compilation &C) const { continue; } - Diag(clang::diag::warn_drv_unused_argument) - << A->getAsString(C.getArgs()); + // 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()); } } } - +/// Collapse an offloading action looking for a job of the given type. The input +/// action is changed to the input of the collapsed sequence. If we effectively +/// had a collapse return the corresponding offloading action, otherwise return +/// null. +template <typename T> +static OffloadAction *collapseOffloadingAction(Action *&CurAction) { + if (!CurAction) + return nullptr; + if (auto *OA = dyn_cast<OffloadAction>(CurAction)) { + if (OA->hasHostDependence()) + if (auto *HDep = dyn_cast<T>(OA->getHostDependence())) { + CurAction = HDep; + return OA; + } + if (OA->hasSingleDeviceDependence()) + if (auto *DDep = dyn_cast<T>(OA->getSingleDeviceDependence())) { + CurAction = DDep; + return OA; + } + } + return nullptr; +} // Returns a Tool for a given JobAction. In case the action and its // predecessors can be combined, updates Inputs with the inputs of the // first combined action. If one of the collapsed actions is a // CudaHostAction, updates CollapsedCHA with the pointer to it so the // caller can deal with extra handling such action requires. static const Tool *selectToolForJob(Compilation &C, bool SaveTemps, - const ToolChain *TC, const JobAction *JA, + bool EmbedBitcode, const ToolChain *TC, + const JobAction *JA, const ActionList *&Inputs, - const CudaHostAction *&CollapsedCHA) { + ActionList &CollapsedOffloadAction) { const Tool *ToolForJob = nullptr; - CollapsedCHA = nullptr; + CollapsedOffloadAction.clear(); // See if we should look for a compiler with an integrated assembler. We match // bottom up, so what we are actually looking for is an assembler job with a // compiler input. + // Look through offload actions between assembler and backend actions. + Action *BackendJA = (isa<AssembleJobAction>(JA) && Inputs->size() == 1) + ? *Inputs->begin() + : nullptr; + auto *BackendOA = collapseOffloadingAction<BackendJobAction>(BackendJA); + if (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) && - isa<AssembleJobAction>(JA) && Inputs->size() == 1 && - isa<BackendJobAction>(*Inputs->begin())) { - // A BackendJob is always preceded by a CompileJob, and without - // -save-temps they will always get combined together, so instead of - // checking the backend tool, check if the tool for the CompileJob - // has an integrated assembler. - const ActionList *BackendInputs = &(*Inputs)[0]->getInputs(); - // Compile job may be wrapped in CudaHostAction, extract it if - // that's the case and update CollapsedCHA if we combine phases. - CudaHostAction *CHA = dyn_cast<CudaHostAction>(*BackendInputs->begin()); - JobAction *CompileJA = - cast<CompileJobAction>(CHA ? *CHA->begin() : *BackendInputs->begin()); - assert(CompileJA && "Backend job is not preceeded by compile job."); - const Tool *Compiler = TC->SelectTool(*CompileJA); + !C.getArgs().hasArg(options::OPT__SLASH_Fa) && BackendJA && + isa<BackendJobAction>(BackendJA)) { + // A BackendJob is always preceded by a CompileJob, and without -save-temps + // or -fembed-bitcode, they will always get combined together, so instead of + // checking the backend tool, check if the tool for the CompileJob has an + // integrated assembler. For -fembed-bitcode, CompileJob is still used to + // look up tools for BackendJob, but they need to match before we can split + // them. + + // Look through offload actions between backend and compile actions. + Action *CompileJA = *BackendJA->getInputs().begin(); + auto *CompileOA = collapseOffloadingAction<CompileJobAction>(CompileJA); + + assert(CompileJA && isa<CompileJobAction>(CompileJA) && + "Backend job is not preceeded by compile job."); + const Tool *Compiler = TC->SelectTool(*cast<CompileJobAction>(CompileJA)); if (!Compiler) 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) { + JobAction *InputJA = cast<JobAction>(*Inputs->begin()); + const Tool *BackendTool = TC->SelectTool(*InputJA); + if (BackendTool == Compiler) + CompileJA = InputJA; + } if (Compiler->hasIntegratedAssembler()) { Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; - CollapsedCHA = CHA; + // Save the collapsed offload actions because they may still contain + // device actions. + if (CompileOA) + CollapsedOffloadAction.push_back(CompileOA); + if (BackendOA) + CollapsedOffloadAction.push_back(BackendOA); } } // A backend job should always be combined with the preceding compile job - // unless OPT_save_temps is enabled and the compiler is capable of emitting - // LLVM IR as an intermediate output. + // unless OPT_save_temps or OPT_fembed_bitcode is enabled and the compiler is + // capable of emitting LLVM IR as an intermediate output. if (isa<BackendJobAction>(JA)) { // Check if the compiler supports emitting LLVM IR. assert(Inputs->size() == 1); - // Compile job may be wrapped in CudaHostAction, extract it if - // that's the case and update CollapsedCHA if we combine phases. - CudaHostAction *CHA = dyn_cast<CudaHostAction>(*Inputs->begin()); - JobAction *CompileJA = - cast<CompileJobAction>(CHA ? *CHA->begin() : *Inputs->begin()); - assert(CompileJA && "Backend job is not preceeded by compile job."); - const Tool *Compiler = TC->SelectTool(*CompileJA); + + // Look through offload actions between backend and compile actions. + Action *CompileJA = *JA->getInputs().begin(); + auto *CompileOA = collapseOffloadingAction<CompileJobAction>(CompileJA); + + assert(CompileJA && isa<CompileJobAction>(CompileJA) && + "Backend job is not preceeded by compile job."); + const Tool *Compiler = TC->SelectTool(*cast<CompileJobAction>(CompileJA)); if (!Compiler) return nullptr; - if (!Compiler->canEmitIR() || !SaveTemps) { + if (!Compiler->canEmitIR() || + (!SaveTemps && !EmbedBitcode)) { Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; - CollapsedCHA = CHA; + + if (CompileOA) + CollapsedOffloadAction.push_back(CompileOA); } } @@ -1769,33 +2060,112 @@ static const Tool *selectToolForJob(Compilation &C, bool SaveTemps, // See if we should use an integrated preprocessor. We do so when we have // exactly one input, since this is the only use case we care about // (irrelevant since we don't support combine yet). - if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin()) && + + // Look through offload actions after preprocessing. + Action *PreprocessJA = (Inputs->size() == 1) ? *Inputs->begin() : nullptr; + auto *PreprocessOA = + collapseOffloadingAction<PreprocessJobAction>(PreprocessJA); + + if (PreprocessJA && isa<PreprocessJobAction>(PreprocessJA) && !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && !C.getArgs().hasArg(options::OPT_traditional_cpp) && !SaveTemps && !C.getArgs().hasArg(options::OPT_rewrite_objc) && - ToolForJob->hasIntegratedCPP()) - Inputs = &(*Inputs)[0]->getInputs(); + ToolForJob->hasIntegratedCPP()) { + Inputs = &PreprocessJA->getInputs(); + if (PreprocessOA) + CollapsedOffloadAction.push_back(PreprocessOA); + } return ToolForJob; } -InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, - const ToolChain *TC, const char *BoundArch, - bool AtTopLevel, bool MultipleArchs, - const char *LinkingOutput) const { +InputInfo Driver::BuildJobsForAction( + Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, + bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, + std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, + bool BuildForOffloadDevice) const { + // 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. + std::string TriplePlusArch = TC->getTriple().normalize(); + if (BoundArch) { + TriplePlusArch += "-"; + TriplePlusArch += BoundArch; + } + std::pair<const Action *, std::string> ActionTC = {A, TriplePlusArch}; + auto CachedResult = CachedResults.find(ActionTC); + if (CachedResult != CachedResults.end()) { + return CachedResult->second; + } + InputInfo Result = BuildJobsForActionNoCache( + C, A, TC, BoundArch, AtTopLevel, MultipleArchs, LinkingOutput, + CachedResults, BuildForOffloadDevice); + CachedResults[ActionTC] = Result; + return Result; +} + +InputInfo Driver::BuildJobsForActionNoCache( + Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, + bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, + std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults, + bool BuildForOffloadDevice) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); - InputInfoList CudaDeviceInputInfos; - if (const CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { - // Append outputs of device jobs to the input list. - for (const Action *DA : CHA->getDeviceActions()) { - CudaDeviceInputInfos.push_back( - BuildJobsForAction(C, DA, TC, nullptr, AtTopLevel, - /*MultipleArchs*/ false, LinkingOutput)); + InputInfoList OffloadDependencesInputInfo; + if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) { + // 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 dependences 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, /*BuildForOffloadDevice=*/true); + }); + return DevA; } - // Override current action with a real host compile action and continue - // processing it. - A = *CHA->begin(); + + // 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=*/BuildForOffloadDevice, + [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { + OffloadDependencesInputInfo.push_back(BuildJobsForAction( + C, DepA, DepTC, DepBoundArch, /*AtTopLevel=*/false, + /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, CachedResults, + /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != + Action::OFK_None)); + }); + + A = BuildForOffloadDevice + ? OA->getSingleDeviceDependence(/*DoNotConsiderHostActions=*/true) + : OA->getHostDependence(); } if (const InputAction *IA = dyn_cast<InputAction>(A)) { @@ -1815,43 +2185,41 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, const char *ArchName = BAA->getArchName(); if (ArchName) - TC = &getToolChain( - C.getArgs(), - computeTargetTriple(DefaultTargetTriple, C.getArgs(), ArchName)); + TC = &getToolChain(C.getArgs(), + computeTargetTriple(*this, DefaultTargetTriple, + C.getArgs(), ArchName)); else TC = &C.getDefaultToolChain(); - return BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel, - MultipleArchs, LinkingOutput); + return BuildJobsForAction(C, *BAA->input_begin(), TC, ArchName, AtTopLevel, + MultipleArchs, LinkingOutput, CachedResults, + BuildForOffloadDevice); } - if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { - // Initial processing of CudaDeviceAction carries host params. - // Call BuildJobsForAction() again, now with correct device parameters. - assert(CDA->getGpuArchName() && "No GPU name in device action."); - return BuildJobsForAction(C, *CDA->begin(), C.getCudaDeviceToolChain(), - CDA->getGpuArchName(), CDA->isAtTopLevel(), - /*MultipleArchs*/ true, LinkingOutput); - } const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); - const CudaHostAction *CollapsedCHA = nullptr; + ActionList CollapsedOffloadActions; + const Tool *T = - selectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs, CollapsedCHA); + selectToolForJob(C, isSaveTempsEnabled(), embedBitcodeEnabled(), TC, JA, + Inputs, CollapsedOffloadActions); if (!T) return InputInfo(); - // If we've collapsed action list that contained CudaHostAction we - // need to build jobs for device-side inputs it may have held. - if (CollapsedCHA) { - for (const Action *DA : CollapsedCHA->getDeviceActions()) { - CudaDeviceInputInfos.push_back( - BuildJobsForAction(C, DA, TC, "", AtTopLevel, - /*MultipleArchs*/ false, LinkingOutput)); - } - } + // 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=*/BuildForOffloadDevice, + [&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { + OffloadDependencesInputInfo.push_back(BuildJobsForAction( + C, DepA, DepTC, DepBoundArch, AtTopLevel, + /*MultipleArchs=*/!!DepBoundArch, LinkingOutput, CachedResults, + /*BuildForOffloadDevice=*/DepA->getOffloadingDeviceKind() != + Action::OFK_None)); + }); // Only use pipes when there is exactly one input. InputInfoList InputInfos; @@ -1861,9 +2229,9 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, // FIXME: Clean this up. bool SubJobAtTopLevel = AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)); - InputInfos.push_back(BuildJobsForAction(C, Input, TC, BoundArch, - SubJobAtTopLevel, MultipleArchs, - LinkingOutput)); + InputInfos.push_back(BuildJobsForAction( + C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, LinkingOutput, + CachedResults, BuildForOffloadDevice)); } // Always use the first input as the base input. @@ -1874,9 +2242,10 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, if (JA->getType() == types::TY_dSYM) BaseInput = InputInfos[0].getFilename(); - // Append outputs of cuda device jobs to the input list - if (CudaDeviceInputInfos.size()) - InputInfos.append(CudaDeviceInputInfos.begin(), CudaDeviceInputInfos.end()); + // Append outputs of offload device jobs to the input list + if (!OffloadDependencesInputInfo.empty()) + InputInfos.append(OffloadDependencesInputInfo.begin(), + OffloadDependencesInputInfo.end()); // Determine the place to write output to, if any. InputInfo Result; @@ -1884,7 +2253,8 @@ InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A, Result = InputInfo(A, BaseInput); else Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, - AtTopLevel, MultipleArchs), + AtTopLevel, MultipleArchs, + TC->getTriple().normalize()), BaseInput); if (CCCPrintBindings && !CCGenDiagnostics) { @@ -1944,7 +2314,8 @@ static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue, const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, const char *BoundArch, bool AtTopLevel, - bool MultipleArchs) const { + bool MultipleArchs, + StringRef NormalizedTriple) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { @@ -2030,11 +2401,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image); } else if (MultipleArchs && BoundArch) { SmallString<128> Output(getDefaultImageName()); + Output += JA.getOffloadingFileNamePrefix(NormalizedTriple); Output += "-"; Output.append(BoundArch); NamedOutput = C.getArgs().MakeArgString(Output.c_str()); - } else + } else { NamedOutput = getDefaultImageName(); + } + } else if (JA.getType() == types::TY_PCH && IsCLMode()) { + NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName).c_str()); } else { const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); assert(Suffix && "All types used for output should have a suffix."); @@ -2043,6 +2418,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, if (!types::appendSuffixForType(JA.getType())) End = BaseName.rfind('.'); SmallString<128> Suffixed(BaseName.substr(0, End)); + Suffixed += JA.getOffloadingFileNamePrefix(NormalizedTriple); if (MultipleArchs && BoundArch) { Suffixed += "-"; Suffixed.append(BoundArch); @@ -2088,7 +2464,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } // As an annoying special case, PCH generation doesn't strip the pathname. - if (JA.getType() == types::TY_PCH) { + if (JA.getType() == types::TY_PCH && !IsCLMode()) { llvm::sys::path::remove_filename(BasePath); if (BasePath.empty()) BasePath = NamedOutput; @@ -2200,12 +2576,34 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, 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 { + Output = BaseName; + llvm::sys::path::replace_extension(Output, ".pch"); + } + return Output.str(); +} + const ToolChain &Driver::getToolChain(const ArgList &Args, const llvm::Triple &Target) const { ToolChain *&TC = ToolChains[Target.str()]; if (!TC) { switch (Target.getOS()) { + case llvm::Triple::Haiku: + TC = new toolchains::Haiku(*this, Target, Args); + break; case llvm::Triple::CloudABI: TC = new toolchains::CloudABI(*this, Target, Args); break; @@ -2235,6 +2633,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Minix(*this, Target, Args); break; case llvm::Triple::Linux: + case llvm::Triple::ELFIAMCU: if (Target.getArch() == llvm::Triple::hexagon) TC = new toolchains::HexagonToolChain(*this, Target, Args); else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) && @@ -2290,6 +2689,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::hexagon: TC = new toolchains::HexagonToolChain(*this, Target, Args); break; + case llvm::Triple::lanai: + TC = new toolchains::LanaiToolChain(*this, Target, Args); + break; case llvm::Triple::xcore: TC = new toolchains::XCoreToolChain(*this, Target, Args); break; @@ -2314,7 +2716,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, 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.begin())->getType())) + 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. @@ -2363,6 +2766,34 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, 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(const char *Str, + MutableArrayRef<unsigned> Digits) { + if (*Str == '\0') + return false; + + char *End; + unsigned CurDigit = 0; + while (CurDigit < Digits.size()) { + unsigned Digit = (unsigned)strtol(Str, &End, 10); + Digits[CurDigit] = Digit; + if (*Str != '\0' && *End == '\0') + return true; + if (*End != '.' || Str == End) + return false; + Str = End + 1; + CurDigit++; + } + + // More digits than requested, bail out... + return false; +} + std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const { unsigned IncludedFlagsBitmask = 0; unsigned ExcludedFlagsBitmask = options::NoDriverOption; diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 22904e5398a0..2d99b1f22385 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -40,17 +41,16 @@ static int skipArgs(const char *Flag, bool HaveCrashVFS) { // These flags are all of the form -Flag <Arg> and are treated as two // arguments. Therefore, we need to skip the flag and the next argument. bool Res = llvm::StringSwitch<bool>(Flag) - .Cases("-I", "-MF", "-MT", "-MQ", true) + .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) .Cases("-o", "-coverage-file", "-dependency-file", true) .Cases("-fdebug-compilation-dir", "-idirafter", true) .Cases("-include", "-include-pch", "-internal-isystem", true) .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) - .Cases("-resource-dir", "-serialize-diagnostic-file", true) .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) .Cases("-header-include-file", "-diagnostic-log-file", true) // Some include flags shouldn't be skipped if we have a crash VFS - .Case("-isysroot", !HaveCrashVFS) + .Cases("-isysroot", "-I", "-F", "-resource-dir", !HaveCrashVFS) .Default(false); // Match found. @@ -71,7 +71,8 @@ static int skipArgs(const char *Flag, bool HaveCrashVFS) { // These flags are treated as a single argument (e.g., -F<Dir>). StringRef FlagRef(Flag); - if (FlagRef.startswith("-F") || FlagRef.startswith("-I") || + if ((!HaveCrashVFS && + (FlagRef.startswith("-F") || FlagRef.startswith("-I"))) || FlagRef.startswith("-fmodules-cache-path=")) return 1; @@ -194,6 +195,18 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, printArg(OS, "-ivfsoverlay", Quote); OS << ' '; printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); + + // Insert -fmodules-cache-path and use the relative module directory + // <name>.cache/vfs/modules where we already dumped the modules. + SmallString<128> RelModCacheDir = llvm::sys::path::parent_path( + llvm::sys::path::parent_path(CrashInfo->VFSPath)); + llvm::sys::path::append(RelModCacheDir, "modules"); + + std::string ModCachePath = "-fmodules-cache-path="; + ModCachePath.append(RelModCacheDir.c_str()); + + OS << ' '; + printArg(OS, ModCachePath.c_str(), Quote); } if (ResponseFile != nullptr) { @@ -297,6 +310,29 @@ int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg, return SecondaryStatus; } +ForceSuccessCommand::ForceSuccessCommand(const Action &Source_, + const Tool &Creator_, + const char *Executable_, + const 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(const 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) diff --git a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp index 68747155b81c..b8de5ad49182 100644 --- a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp @@ -19,6 +19,7 @@ #include "llvm/Config/llvm-config.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/Process.h" @@ -71,6 +72,11 @@ bool MSVCToolChain::IsUnwindTablesDefault() const { // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms // such as ARM and PPC actually require unwind tables, but LLVM doesn't know // how to generate them yet. + + // Don't emit unwind tables by default for MachO targets. + if (getTriple().isOSBinFormatMachO()) + return false; + return getArch() == llvm::Triple::x86_64; } @@ -89,23 +95,31 @@ bool MSVCToolChain::isPICDefaultForced() const { #ifdef USE_WIN32 static bool readFullStringValue(HKEY hkey, const char *valueName, std::string &value) { - // FIXME: We should be using the W versions of the registry functions, but - // doing so requires UTF8 / UTF16 conversions similar to how we handle command - // line arguments. The UTF8 conversion functions are not exposed publicly - // from LLVM though, so in order to do this we will probably need to create - // a registry abstraction in LLVMSupport that is Windows only. + 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 = RegQueryValueEx(hkey, valueName, NULL, &type, NULL, &valueSize); - if (result != ERROR_SUCCESS || type != REG_SZ) + 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 = RegQueryValueEx(hkey, valueName, NULL, NULL, &buffer[0], &valueSize); - if (result == ERROR_SUCCESS) - value.assign(reinterpret_cast<const char *>(buffer.data())); - return result; + 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)); + // 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 @@ -141,19 +155,20 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, nextKey++; size_t partialKeyLength = keyEnd - keyPath; char partialKey[256]; - if (partialKeyLength > sizeof(partialKey)) - partialKeyLength = sizeof(partialKey); + if (partialKeyLength >= sizeof(partialKey)) + partialKeyLength = sizeof(partialKey) - 1; strncpy(partialKey, keyPath, partialKeyLength); partialKey[partialKeyLength] = '\0'; HKEY hTopKey = NULL; - lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, - &hTopKey); + 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; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, - NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL, + NULL, NULL) == ERROR_SUCCESS; + index++) { const char *sp = keyName; while (*sp && !isDigit(*sp)) sp++; @@ -172,8 +187,8 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, bestName = keyName; // Append rest of key. bestName.append(nextKey); - lResult = RegOpenKeyEx(hTopKey, bestName.c_str(), 0, - KEY_READ | KEY_WOW64_32KEY, &hKey); + lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, + KEY_READ | KEY_WOW64_32KEY, &hKey); if (lResult == ERROR_SUCCESS) { lResult = readFullStringValue(hKey, valueName, value); if (lResult == ERROR_SUCCESS) { @@ -191,7 +206,7 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, } } else { lResult = - RegOpenKeyEx(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); if (lResult == ERROR_SUCCESS) { lResult = readFullStringValue(hKey, valueName, value); if (lResult == ERROR_SUCCESS) @@ -402,7 +417,10 @@ bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath, SmallString<128> FilePath(PathSegment); llvm::sys::path::append(FilePath, "cl.exe"); - if (llvm::sys::fs::can_execute(FilePath.c_str()) && + // Checking if cl.exe exists is a small optimization over calling + // can_execute, which really only checks for existence but will also do + // extra checks for cl.exe.exe. These add up when walking a long path. + if (llvm::sys::fs::exists(FilePath.c_str()) && !llvm::sys::fs::equivalent(FilePath.c_str(), clangProgramPath)) { // If we found it on the PATH, use it exactly as is with no // modifications. @@ -452,6 +470,45 @@ bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath, return true; } +VersionTuple MSVCToolChain::getMSVCVersionFromExe() const { + VersionTuple Version; +#ifdef USE_WIN32 + std::string BinPath; + if (!getVisualStudioBinariesFolder("", BinPath)) + return Version; + SmallString<128> ClExe(BinPath); + 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; +} + // Get Visual Studio installation directory. bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const { // First check the environment variables that vsvars32.bat sets. @@ -527,6 +584,10 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, "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; @@ -609,7 +670,7 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, ToolChain::ComputeEffectiveClangTriple(Args, InputType); llvm::Triple Triple(TripleStr); VersionTuple MSVT = - tools::visualstudio::getMSVCVersion(/*D=*/nullptr, Triple, Args, + tools::visualstudio::getMSVCVersion(/*D=*/nullptr, *this, Triple, Args, /*IsWindowsMSVC=*/true); if (MSVT.empty()) return TripleStr; @@ -659,7 +720,8 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); } - if (SupportsForcingFramePointer) + 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') @@ -669,8 +731,20 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, } break; case 'b': - if (I + 1 != E && isdigit(OptStr[I + 1])) + 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': break; @@ -701,6 +775,12 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, else DAL.AddFlagArg( A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); + } else { + // Don't warn about /Oy- in 64-bit 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 64-bit clang-cl. + A->claim(); } break; } @@ -748,7 +828,12 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, continue; StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { - const char &OptChar = *(OptStr.data() + 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; } diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp index 2fded1c80da9..30cc3f45c9e0 100644 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp @@ -39,6 +39,7 @@ enum : SanitizerMask { TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI, TrappingDefault = CFI, + CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast, }; enum CoverageFeature { @@ -49,6 +50,7 @@ enum CoverageFeature { CoverageTraceBB = 1 << 4, CoverageTraceCmp = 1 << 5, Coverage8bitCounters = 1 << 6, + CoverageTracePC = 1 << 7, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -157,11 +159,10 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, } bool SanitizerArgs::needsUbsanRt() const { - return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) && - !Sanitizers.has(Address) && - !Sanitizers.has(Memory) && - !Sanitizers.has(Thread) && - !CfiCrossDso; + return ((Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || + CoverageFeatures) && + !Sanitizers.has(Address) && !Sanitizers.has(Memory) && + !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) && !CfiCrossDso; } bool SanitizerArgs::needsCfiRt() const { @@ -180,25 +181,8 @@ bool SanitizerArgs::needsUnwindTables() const { return Sanitizers.Mask & NeedsUnwindTables; } -void SanitizerArgs::clear() { - Sanitizers.clear(); - RecoverableSanitizers.clear(); - TrapSanitizers.clear(); - BlacklistFiles.clear(); - ExtraDeps.clear(); - CoverageFeatures = 0; - MsanTrackOrigins = 0; - MsanUseAfterDtor = false; - NeedPIE = false; - AsanFieldPadding = 0; - AsanSharedRuntime = false; - LinkCXXRuntimes = false; - CfiCrossDso = false; -} - SanitizerArgs::SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args) { - clear(); SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. @@ -284,6 +268,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } + // Enable toolchain specific default sanitizers if not explicitly disabled. + Kinds |= TC.getDefaultSanitizers() & ~AllRemove; + // We disable the vptr sanitizer if it was enabled by group expansion but RTTI // is disabled. if ((Kinds & Vptr) && @@ -324,7 +311,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address), std::make_pair(KernelAddress, Leak), std::make_pair(KernelAddress, Thread), - std::make_pair(KernelAddress, Memory)}; + std::make_pair(KernelAddress, Memory), + std::make_pair(Efficiency, Address), + std::make_pair(Efficiency, Leak), + std::make_pair(Efficiency, Thread), + std::make_pair(Efficiency, Memory), + std::make_pair(Efficiency, KernelAddress)}; for (auto G : IncompatibleGroups) { SanitizerMask Group = G.first; if (Kinds & Group) { @@ -347,11 +339,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, for (const auto *Arg : Args) { const char *DeprecatedReplacement = nullptr; if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { - DeprecatedReplacement = "-fsanitize-recover=undefined,integer"; + 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"; + 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)) { @@ -448,42 +442,59 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, NeedPIE |= CfiCrossDso; } + Stats = Args.hasFlag(options::OPT_fsanitize_stats, + options::OPT_fno_sanitize_stats, false); + // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. - if (AllAddedKinds & SupportsCoverage) { - for (const auto *Arg : Args) { - if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { - Arg->claim(); - int LegacySanitizeCoverage; - if (Arg->getNumValues() == 1 && - !StringRef(Arg->getValue(0)) - .getAsInteger(0, LegacySanitizeCoverage) && - LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { - // TODO: Add deprecation notice for this form. - switch (LegacySanitizeCoverage) { - case 0: - CoverageFeatures = 0; - break; - case 1: - CoverageFeatures = CoverageFunc; - break; - case 2: - CoverageFeatures = CoverageBB; - break; - case 3: - CoverageFeatures = CoverageEdge; - break; - case 4: - CoverageFeatures = CoverageEdge | CoverageIndirCall; - break; - } - continue; + 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) && + LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { + switch (LegacySanitizeCoverage) { + case 0: + CoverageFeatures = 0; + Arg->claim(); + break; + case 1: + D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) + << "-fsanitize-coverage=func"; + CoverageFeatures = CoverageFunc; + break; + case 2: + D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) + << "-fsanitize-coverage=bb"; + CoverageFeatures = CoverageBB; + break; + case 3: + D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) + << "-fsanitize-coverage=edge"; + CoverageFeatures = CoverageEdge; + break; + case 4: + D.Diag(diag::warn_drv_deprecated_arg) + << Arg->getAsString(Args) + << "-fsanitize-coverage=edge,indirect-calls"; + CoverageFeatures = CoverageEdge | CoverageIndirCall; + break; } - CoverageFeatures |= parseCoverageFeatures(D, Arg); - } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { + continue; + } + CoverageFeatures |= parseCoverageFeatures(D, Arg); + + // Disable coverage and not claim the flags if there is at least one + // non-supporting sanitizer. + if (!(AllAddedKinds & ~setGroupBits(SupportsCoverage))) { Arg->claim(); - CoverageFeatures &= ~parseCoverageFeatures(D, Arg); + } 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. @@ -512,6 +523,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "-fsanitize-coverage=8bit-counters" << "-fsanitize-coverage=(func|bb|edge)"; + // trace-pc w/o func/bb/edge implies edge. + if ((CoverageFeatures & CoverageTracePC) && + !(CoverageFeatures & CoverageTypes)) + CoverageFeatures |= CoverageEdge; if (AllAddedKinds & Address) { AsanSharedRuntime = @@ -543,6 +558,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } + AsanUseAfterScope = + Args.hasArg(options::OPT_fsanitize_address_use_after_scope); + if (AsanUseAfterScope && !(AllAddedKinds & Address)) { + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fsanitize-address-use-after-scope" + << "-fsanitize=address"; + } + // Parse -link-cxx-sanitizer flag. LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); @@ -565,9 +588,62 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) { 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)); +} + void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const { + // 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(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), + std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc")}; + for (auto F : CoverageFlags) { + if (CoverageFeatures & F.first) + CmdArgs.push_back(Args.MakeArgString(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))); @@ -601,23 +677,15 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (CfiCrossDso) CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso")); + if (Stats) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats")); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); - // Translate available CoverageFeatures to corresponding clang-cc1 flags. - 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(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters")}; - for (auto F : CoverageFlags) { - if (CoverageFeatures & F.first) - CmdArgs.push_back(Args.MakeArgString(F.second)); - } + if (AsanUseAfterScope) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-use-after-scope")); // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as @@ -627,14 +695,14 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (Sanitizers.has(Memory) || Sanitizers.has(Address)) CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); - 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"))); + // 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="; } } @@ -655,6 +723,10 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, if (A->getOption().matches(options::OPT_fsanitize_EQ) && 0 == strcmp("all", Value)) Kind = 0; + // Similarly, don't accept -fsanitize=efficiency-all. + else if (A->getOption().matches(options::OPT_fsanitize_EQ) && + 0 == strcmp("efficiency-all", Value)) + Kind = 0; else Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); @@ -681,6 +753,7 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { .Case("trace-bb", CoverageTraceBB) .Case("trace-cmp", CoverageTraceCmp) .Case("8bit-counters", Coverage8bitCounters) + .Case("trace-pc", CoverageTracePC) .Default(0); if (F == 0) D.Diag(clang::diag::err_drv_unsupported_option_argument) diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index cbbd485a9b77..e96688cbaf81 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -9,6 +9,7 @@ #include "Tools.h" #include "clang/Basic/ObjCRuntime.h" +#include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" @@ -247,8 +248,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::InputClass: case Action::BindArchClass: - case Action::CudaDeviceClass: - case Action::CudaHostClass: + case Action::OffloadClass: case Action::LipoJobClass: case Action::DsymutilJobClass: case Action::VerifyDebugInfoJobClass: @@ -341,19 +341,26 @@ std::string ToolChain::GetProgramPath(const char *Name) const { std::string ToolChain::GetLinkerPath() const { if (Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { - StringRef Suffix = A->getValue(); - - // If we're passed -fuse-ld= with no argument, or with the argument ld, - // then use whatever the default system linker is. - if (Suffix.empty() || Suffix == "ld") - return GetProgramPath("ld"); - - llvm::SmallString<8> LinkerName("ld."); - LinkerName.append(Suffix); - - std::string LinkerPath(GetProgramPath(LinkerName.c_str())); - if (llvm::sys::fs::exists(LinkerPath)) - return LinkerPath; + StringRef UseLinker = A->getValue(); + + if (llvm::sys::path::is_absolute(UseLinker)) { + // If we're passed -fuse-ld= with what looks like an absolute path, + // don't attempt to second-guess that. + if (llvm::sys::fs::exists(UseLinker)) + return UseLinker; + } else { + // If we're passed -fuse-ld= with no argument, or with the argument ld, + // then use whatever the default system linker is. + if (UseLinker.empty() || UseLinker == "ld") + return GetProgramPath("ld"); + + llvm::SmallString<8> LinkerName("ld."); + LinkerName.append(UseLinker); + + std::string LinkerPath(GetProgramPath(LinkerName.c_str())); + if (llvm::sys::fs::exists(LinkerPath)) + return LinkerPath; + } getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); return ""; @@ -515,7 +522,6 @@ void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, if (!needsProfileRT(Args)) return; CmdArgs.push_back(getCompilerRTArgString(Args, "profile")); - return; } ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( @@ -533,18 +539,41 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( return GetDefaultRuntimeLibType(); } +static bool ParseCXXStdlibType(const StringRef& Name, + ToolChain::CXXStdlibType& Type) { + if (Name == "libc++") + Type = ToolChain::CST_Libcxx; + else if (Name == "libstdc++") + Type = ToolChain::CST_Libstdcxx; + else + return false; + + return true; +} + ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ - if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + ToolChain::CXXStdlibType Type; + bool HasValidType = false; + bool ForcePlatformDefault = false; + + const Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); + if (A) { StringRef Value = A->getValue(); - if (Value == "libc++") - return ToolChain::CST_Libcxx; - if (Value == "libstdc++") - return ToolChain::CST_Libstdcxx; - getDriver().Diag(diag::err_drv_invalid_stdlib_name) - << A->getAsString(Args); + HasValidType = ParseCXXStdlibType(Value, Type); + + // Only use in tests to override CLANG_DEFAULT_CXX_STDLIB! + if (Value == "platform") + ForcePlatformDefault = true; + else if (!HasValidType) + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); } - return ToolChain::CST_Libstdcxx; + if (!HasValidType && (ForcePlatformDefault || + !ParseCXXStdlibType(CLANG_DEFAULT_CXX_STDLIB, Type))) + Type = GetDefaultCXXStdlibType(); + + return Type; } /// \brief Utility function to add a system include directory to CC1 arguments. @@ -666,3 +695,6 @@ SanitizerMask ToolChain::getSupportedSanitizers() const { void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const {} + +void ToolChain::AddIAMCUIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const {} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index 99c7b8e68c61..4ecbf2bac3c3 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "ToolChains.h" +#include "clang/Basic/Cuda.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" #include "clang/Basic/VirtualFileSystem.h" @@ -65,6 +66,16 @@ types::ID MachO::LookupTypeForExtension(const char *Ext) const { 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()) @@ -319,64 +330,74 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, } } +StringRef Darwin::getPlatformFamily() const { + switch (TargetPlatform) { + case DarwinPlatformKind::MacOS: + return "MacOSX"; + case DarwinPlatformKind::IPhoneOS: + case DarwinPlatformKind::IPhoneOSSimulator: + return "iPhone"; + case DarwinPlatformKind::TvOS: + case DarwinPlatformKind::TvOSSimulator: + return "AppleTV"; + case DarwinPlatformKind::WatchOS: + case DarwinPlatformKind::WatchOSSimulator: + 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() const { + switch(TargetPlatform) { + case DarwinPlatformKind::MacOS: + return "osx"; + case DarwinPlatformKind::IPhoneOS: + return "ios"; + case DarwinPlatformKind::IPhoneOSSimulator: + return "iossim"; + case DarwinPlatformKind::TvOS: + return "tvos"; + case DarwinPlatformKind::TvOSSimulator: + return "tvossim"; + case DarwinPlatformKind::WatchOS: + return "watchos"; + case DarwinPlatformKind::WatchOSSimulator: + return "watchossim"; + } + llvm_unreachable("Unsupported platform"); +} + void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; - // TODO: Clean this up once autoconf is gone - SmallString<128> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "lib", "darwin"); - const char *Library = "libclang_rt.profile_osx.a"; - - // Select the appropriate runtime library for the target. - if (isTargetWatchOS()) { - Library = "libclang_rt.profile_watchos.a"; - } else if (isTargetWatchOSSimulator()) { - llvm::sys::path::append(P, "libclang_rt.profile_watchossim.a"); - Library = getVFS().exists(P) ? "libclang_rt.profile_watchossim.a" - : "libclang_rt.profile_watchos.a"; - } else if (isTargetTvOS()) { - Library = "libclang_rt.profile_tvos.a"; - } else if (isTargetTvOSSimulator()) { - llvm::sys::path::append(P, "libclang_rt.profile_tvossim.a"); - Library = getVFS().exists(P) ? "libclang_rt.profile_tvossim.a" - : "libclang_rt.profile_tvos.a"; - } else if (isTargetIPhoneOS()) { - Library = "libclang_rt.profile_ios.a"; - } else if (isTargetIOSSimulator()) { - llvm::sys::path::append(P, "libclang_rt.profile_iossim.a"); - Library = getVFS().exists(P) ? "libclang_rt.profile_iossim.a" - : "libclang_rt.profile_ios.a"; - } else { - assert(isTargetMacOS() && "unexpected non MacOS platform"); - } - AddLinkRuntimeLib(Args, CmdArgs, Library, + AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.profile_") + + getOSLibraryNameSuffix() + ".a").str(), /*AlwaysLink*/ true); - return; } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) const { - if (!Args.hasArg(options::OPT_dynamiclib) && - !Args.hasArg(options::OPT_bundle)) { - // Sanitizer runtime libraries requires C++. - AddCXXStdlibLibArgs(Args, CmdArgs); - } - // ASan is not supported on watchOS. - assert(isTargetMacOS() || isTargetIOSSimulator()); - StringRef OS = isTargetMacOS() ? "osx" : "iossim"; AddLinkRuntimeLib( Args, CmdArgs, - (Twine("libclang_rt.") + Sanitizer + "_" + OS + "_dynamic.dylib").str(), + (Twine("libclang_rt.") + Sanitizer + "_" + + getOSLibraryNameSuffix() + "_dynamic.dylib").str(), /*AlwaysLink*/ true, /*IsEmbedded*/ false, /*AddRPath*/ true); - - if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { - // Add explicit dependcy on -lc++abi, as -lc++ doesn't re-export - // all RTTI-related symbols that UBSan uses. - CmdArgs.push_back("-lc++abi"); - } } void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, @@ -413,6 +434,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); if (Sanitize.needsTsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); + if (Sanitize.needsStatsRt()) { + StringRef OS = isTargetMacOS() ? "osx" : "iossim"; + AddLinkRuntimeLib(Args, CmdArgs, + (Twine("libclang_rt.stats_client_") + OS + ".a").str(), + /*AlwaysLink=*/true); + AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + } + if (Sanitize.needsEsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "esan"); // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. @@ -529,11 +559,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef isysroot = A->getValue(); - // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - size_t BeginSDK = isysroot.rfind("SDKs/"); - size_t EndSDK = isysroot.rfind(".sdk"); - if (BeginSDK != StringRef::npos && EndSDK != StringRef::npos) { - StringRef SDK = isysroot.slice(BeginSDK + 5, EndSDK); + StringRef SDK = getSDKName(isysroot); + if (SDK.size() > 0) { // Slice the version number out. // Version number is between the first and the last number. size_t StartVer = SDK.find_first_of("0123456789"); @@ -686,6 +713,17 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Platform = WatchOSSimulator; setTarget(Platform, 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(); + } + } } void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, @@ -735,7 +773,6 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, 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). @@ -1025,11 +1062,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, } } - // Default to use libc++ on OS X 10.9+ and iOS 7+. - if (((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || - (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || - isTargetWatchOSBased()) && - !Args.getLastArg(options::OPT_stdlib_EQ)) + if (!Args.getLastArg(options::OPT_stdlib_EQ) && + GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), "libc++"); @@ -1068,7 +1102,15 @@ bool Darwin::UseSjLjExceptions(const ArgList &Args) const { return false; // Only watchOS uses the new DWARF/Compact unwinding method. - return !isTargetWatchOS(); + llvm::Triple Triple(ComputeLLVMTriple(Args)); + return !Triple.isWatchABI(); +} + +bool Darwin::SupportsEmbeddedBitcode() const { + assert(TargetInitialized && "Target not initialized!"); + if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0)) + return false; + return true; } bool MachO::isPICDefault() const { return true; } @@ -1212,14 +1254,18 @@ void Darwin::CheckObjCARC() const { } SanitizerMask Darwin::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (isTargetMacOS() || isTargetIOSSimulator()) - Res |= SanitizerKind::Address; + Res |= SanitizerKind::Address; if (isTargetMacOS()) { if (!isMacosxVersionLT(10, 9)) Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; - Res |= SanitizerKind::Thread; + if (IsX86_64) + Res |= SanitizerKind::Thread; + } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) { + if (IsX86_64) + Res |= SanitizerKind::Thread; } return Res; } @@ -1241,6 +1287,8 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) return BadVersion; GoodVersion.MajorStr = First.first.str(); + if (First.second.empty()) + return GoodVersion; if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; GoodVersion.MinorStr = Second.first.str(); @@ -1248,6 +1296,7 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { // 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.0 // 4.4.x @@ -1353,9 +1402,17 @@ void Generic_GCC::GCCInstallationDetector::init( // Then look for gcc installed alongside clang. Prefixes.push_back(D.InstalledDir + "/.."); - // And finally in /usr. - if (D.SysRoot.empty()) + // Then look for distribution supplied gcc installations. + if (D.SysRoot.empty()) { + // Look for RHEL devtoolsets. + 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("/opt/rh/devtoolset-1.1/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-1.0/root/usr"); + // And finally in /usr. Prefixes.push_back("/usr"); + } } // Loop over the various components which exist and select the best GCC @@ -1553,9 +1610,13 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { break; case llvm::Triple::x86: LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); - TripleAliases.append(begin(X86Triples), end(X86Triples)); - BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); - BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + // 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)); @@ -1631,9 +1692,33 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.push_back(BiarchTriple.str()); } +// 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; + return CudaVersion::UNKNOWN; +} + // \brief -- try common CUDA installation paths looking for files we need for // CUDA compilation. - void Generic_GCC::CudaInstallationDetector::init( const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args) { SmallVector<std::string, 4> CudaPathCandidates; @@ -1643,6 +1728,8 @@ void Generic_GCC::CudaInstallationDetector::init( Args.getLastArgValue(options::OPT_cuda_path_EQ)); else { CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); + // FIXME: Uncomment this once we can compile the cuda 8 headers. + // CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-8.0"); CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.5"); CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.0"); } @@ -1651,19 +1738,19 @@ void Generic_GCC::CudaInstallationDetector::init( if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) continue; - CudaInstallPath = CudaPath; - CudaIncludePath = CudaInstallPath + "/include"; - CudaLibDevicePath = CudaInstallPath + "/nvvm/libdevice"; - CudaLibPath = - CudaInstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib"); + InstallPath = CudaPath; + BinPath = CudaPath + "/bin"; + IncludePath = InstallPath + "/include"; + LibDevicePath = InstallPath + "/nvvm/libdevice"; + LibPath = InstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib"); - if (!(D.getVFS().exists(CudaIncludePath) && - D.getVFS().exists(CudaLibPath) && - D.getVFS().exists(CudaLibDevicePath))) + auto &FS = D.getVFS(); + if (!(FS.exists(IncludePath) && FS.exists(BinPath) && FS.exists(LibPath) && + FS.exists(LibDevicePath))) continue; std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(CudaLibDevicePath, EC), LE; + 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); @@ -1673,41 +1760,74 @@ void Generic_GCC::CudaInstallationDetector::init( continue; StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); - CudaLibDeviceMap[GpuArch] = FilePath.str(); + LibDeviceMap[GpuArch] = FilePath.str(); // Insert map entries for specifc devices with this compute capability. if (GpuArch == "compute_20") { - CudaLibDeviceMap["sm_20"] = FilePath; - CudaLibDeviceMap["sm_21"] = FilePath; + LibDeviceMap["sm_20"] = FilePath; + LibDeviceMap["sm_21"] = FilePath; } else if (GpuArch == "compute_30") { - CudaLibDeviceMap["sm_30"] = FilePath; - CudaLibDeviceMap["sm_32"] = FilePath; + LibDeviceMap["sm_30"] = FilePath; + LibDeviceMap["sm_32"] = FilePath; } else if (GpuArch == "compute_35") { - CudaLibDeviceMap["sm_35"] = FilePath; - CudaLibDeviceMap["sm_37"] = FilePath; + LibDeviceMap["sm_35"] = FilePath; + LibDeviceMap["sm_37"] = FilePath; + } else if (GpuArch == "compute_50") { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + LibDeviceMap["sm_60"] = FilePath; + LibDeviceMap["sm_61"] = FilePath; + LibDeviceMap["sm_62"] = FilePath; } } + 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()); + } + IsValid = true; break; } } +void Generic_GCC::CudaInstallationDetector::CheckCudaVersionSupportsArch( + CudaArch Arch) const { + if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || + ArchsWithVersionTooLowErrors.count(Arch) > 0) + return; + + auto RequiredVersion = MinVersionForCudaArch(Arch); + if (Version < RequiredVersion) { + ArchsWithVersionTooLowErrors.insert(Arch); + D.Diag(diag::err_drv_cuda_version_too_low) + << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version) + << CudaVersionToString(RequiredVersion); + } +} + void Generic_GCC::CudaInstallationDetector::print(raw_ostream &OS) const { if (isValid()) - OS << "Found CUDA installation: " << CudaInstallPath << "\n"; + OS << "Found CUDA installation: " << InstallPath << ", version " + << CudaVersionToString(Version) << "\n"; } namespace { // Filter to remove Multilibs that don't exist as a suffix to Path class FilterNonExistent { - StringRef Base; + StringRef Base, File; vfs::FileSystem &VFS; public: - FilterNonExistent(StringRef Base, vfs::FileSystem &VFS) - : Base(Base), VFS(VFS) {} + FilterNonExistent(StringRef Base, StringRef File, vfs::FileSystem &VFS) + : Base(Base), File(File), VFS(VFS) {} bool operator()(const Multilib &M) { - return !VFS.exists(Base + M.gccSuffix() + "/crtbegin.o"); + return !VFS.exists(Base + M.gccSuffix() + File); } }; } // end anonymous namespace @@ -1720,6 +1840,10 @@ static void addMultilibFlag(bool Enabled, const char *const Flag, Flags.push_back(std::string("-") + Flag); } +static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; +} + static bool isMipsArch(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; @@ -1765,38 +1889,151 @@ static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } -static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, - StringRef Path, const ArgList &Args, - DetectedMultilibs &Result) { - // Some MIPS toolchains put libraries and object files compiled - // using different options in to the sub-directoris which names - // reflects the flags used for compilation. For example sysroot - // directory might looks like the following examples: - // - // /usr - // /lib <= crt*.o files compiled with '-mips32' - // /mips16 - // /usr - // /lib <= crt*.o files compiled with '-mips16' - // /el - // /usr - // /lib <= crt*.o files compiled with '-mips16 -EL' - // - // or - // - // /usr - // /lib <= crt*.o files compiled with '-mips32r2' - // /mips16 - // /usr - // /lib <= crt*.o files compiled with '-mips32r2 -mips16' - // /mips32 - // /usr - // /lib <= crt*.o files compiled with '-mips32' - - FilterNonExistent NonExistent(Path, D.getVFS()); - - // Check for FSF toolchain multilibs - MultilibSet FSFMipsMultilibs; +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(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); + + if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = AndroidMipsMultilibs; + 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") @@ -1838,7 +2075,7 @@ static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); - FSFMipsMultilibs = + MtiMipsMultilibsV1 = MultilibSet() .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, MArchDefault) @@ -1857,128 +2094,118 @@ static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, .Maybe(Nan2008) .FilterOut(".*sof/nan2008") .FilterOut(NonExistent) - .setIncludeDirsCallback([](StringRef InstallDir, - StringRef TripleStr, const Multilib &M) { - std::vector<std::string> Dirs; - Dirs.push_back((InstallDir + "/include").str()); - std::string SysRootInc = - InstallDir.str() + "/../../../../sysroot"; + .setIncludeDirsCallback([](const Multilib &M) { + std::vector<std::string> Dirs({"/include"}); if (StringRef(M.includeSuffix()).startswith("/uclibc")) - Dirs.push_back(SysRootInc + "/uclibc/usr/include"); + Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); else - Dirs.push_back(SysRootInc + "/usr/include"); + Dirs.push_back("/../../../../sysroot/usr/include"); return Dirs; }); } - // Check for Musl toolchain multilibs - MultilibSet MuslMipsMultilibs; + // CodeScape IMG toolchain starting from v1.3. + MultilibSet MtiMipsMultilibsV2; { - 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([]( - StringRef InstallDir, StringRef TripleStr, const Multilib &M) { - std::vector<std::string> Dirs; - Dirs.push_back( - (InstallDir + "/../sysroot" + M.osSuffix() + "/usr/include").str()); - return Dirs; - }); - } - - // 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 = + 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(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") + .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, + BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, + ElHardUclibc, ElMicroHardNan, ElMicroSoft}) + .Either(O32, N32, N64) .FilterOut(NonExistent) - .setIncludeDirsCallback([](StringRef InstallDir, - StringRef TripleStr, const Multilib &M) { - std::vector<std::string> Dirs; - Dirs.push_back((InstallDir + "/include").str()); - std::string SysRootInc = - InstallDir.str() + "/../../../../" + TripleStr.str(); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) - Dirs.push_back(SysRootInc + "/libc/uclibc/usr/include"); - else - Dirs.push_back(SysRootInc + "/libc/usr/include"); - return Dirs; + .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()}); }); } - - MultilibSet AndroidMipsMultilibs = - MultilibSet() - .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) - .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) - .FilterOut(NonExistent); - - 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); + for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *Candidate; + return true; + } } + return false; +} - MultilibSet ImgMultilibs; +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"); @@ -1987,22 +2214,91 @@ static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, auto MAbi64 = makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); - ImgMultilibs = + ImgMultilibsV1 = MultilibSet() .Maybe(Mips64r6) .Maybe(MAbi64) .Maybe(LittleEndian) .FilterOut(NonExistent) - .setIncludeDirsCallback([](StringRef InstallDir, - StringRef TripleStr, const Multilib &M) { - std::vector<std::string> Dirs; - Dirs.push_back((InstallDir + "/include").str()); - Dirs.push_back( - (InstallDir + "/../../../../sysroot/usr/include").str()); - return Dirs; + .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; +} + +static bool 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); @@ -2033,67 +2329,82 @@ static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); - if (TargetTriple.isAndroid()) { - // Select Android toolchain. It's the only choice in that case. - if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = AndroidMipsMultilibs; - return true; - } - return false; - } + if (TargetTriple.isAndroid()) + return findMipsAndroidMultilibs(Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) { - if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = MuslMipsMultilibs; - return true; - } - return false; - } + TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) + return findMipsMuslMultilibs(Flags, NonExistent, Result); + + if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::GNU) + return findMipsMtiMultilibs(Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) { - // Select mips-img-linux-gnu toolchain. - if (ImgMultilibs.select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = ImgMultilibs; - return true; - } - return false; - } + TargetTriple.getEnvironment() == llvm::Triple::GNU) + return findMipsImgMultilibs(Flags, NonExistent, Result); - // Sort candidates. Toolchain that best meets the directories goes first. - // Then select the first toolchains matches command line flags. - MultilibSet *candidates[] = {&DebianMipsMultilibs, &FSFMipsMultilibs, - &CSMipsMultilibs}; - std::sort( - std::begin(candidates), std::end(candidates), - [](MultilibSet *a, MultilibSet *b) { return a->size() > b->size(); }); - for (const auto &candidate : candidates) { - if (candidate->select(Flags, Result.SelectedMultilib)) { - if (candidate == &DebianMipsMultilibs) - Result.BiarchSibling = Multilib(); - Result.Multilibs = *candidate; - return true; - } - } + 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); + // 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; - } + 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("+armv7") + .flag("-thumb"); + Multilib ThumbMultilib = makeMultilib("/thumb") + .flag("-armv7") + .flag("+thumb"); + Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") + .flag("+armv7") + .flag("+thumb"); + Multilib DefaultMultilib = makeMultilib("") + .flag("-armv7") + .flag("-thumb"); + 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::IK_THUMB); + bool IsArmV7Mode = (IsArmArch || IsThumbArch) && + (llvm::ARM::parseArchVersion(Arch) == 7 || + (IsArmArch && Arch == "" && IsV7SubArch)); + addMultilibFlag(IsArmV7Mode, "armv7", Flags); + addMultilibFlag(IsThumbMode, "thumb", Flags); + + if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = AndroidArmMultilibs; +} + static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -2126,7 +2437,9 @@ static bool findBiarchMultilibs(const Driver &D, .flag("-m64") .flag("+mx32"); - FilterNonExistent NonExistent(Path, D.getVFS()); + // 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. @@ -2285,9 +2598,13 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( 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 (isMipsArch(TargetArch)) { + if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { + // It should also work without multilibs in a simplified toolchain. + findAndroidArmMultilibs(D, TargetTriple, LI->getName(), Args, Detected); + } else if (isMipsArch(TargetArch)) { if (!findMIPSMultilibs(D, TargetTriple, LI->getName(), Args, Detected)) continue; } else if (!findBiarchMultilibs(D, TargetTriple, LI->getName(), Args, @@ -2378,6 +2695,8 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::ppc64: case llvm::Triple::ppc64le: case llvm::Triple::systemz: + case llvm::Triple::mips: + case llvm::Triple::mipsel: return true; default: return false; @@ -2417,7 +2736,6 @@ bool Generic_GCC::addLibStdCXXIncludePaths( return true; } - void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); @@ -2473,10 +2791,9 @@ void MipsLLVMToolChain::AddClangSystemIncludeArgs( const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { - const auto IncludePaths = - Callback(D.getInstalledDir(), getTripleString(), SelectedMultilib); - for (const auto &Path : IncludePaths) - addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path); + for (const auto &Path : Callback(SelectedMultilib)) + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + D.getInstalledDir() + Path); } } @@ -2521,11 +2838,10 @@ void MipsLLVMToolChain::AddClangCXXStdlibIncludeArgs( const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { - const auto IncludePaths = Callback(getDriver().getInstalledDir(), - getTripleString(), SelectedMultilib); - for (const auto &Path : IncludePaths) { - if (llvm::sys::fs::exists(Path + "/c++/v1")) { - addSystemInclude(DriverArgs, CC1Args, Path + "/c++/v1"); + for (std::string Path : Callback(SelectedMultilib)) { + Path = getDriver().getInstalledDir() + Path + "/c++/v1"; + if (llvm::sys::fs::exists(Path)) { + addSystemInclude(DriverArgs, CC1Args, Path); break; } } @@ -2569,14 +2885,9 @@ std::string HexagonToolChain::getHexagonTargetDir( if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) return InstallRelDir; - std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/target"; - if (getVFS().exists(PrefixRelDir)) - return PrefixRelDir; - return InstallRelDir; } - Optional<unsigned> HexagonToolChain::getSmallDataThreshold( const ArgList &Args) { StringRef Gn = ""; @@ -2595,7 +2906,6 @@ Optional<unsigned> HexagonToolChain::getSmallDataThreshold( return None; } - void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, ToolChain::path_list &LibPaths) const { const Driver &D = getDriver(); @@ -2971,6 +3281,48 @@ Tool *CloudABI::buildLinker() const { return new tools::cloudabi::Linker(*this); } +SanitizerMask CloudABI::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::SafeStack; + return Res; +} + +SanitizerMask CloudABI::getDefaultSanitizers() const { + return SanitizerKind::SafeStack; +} + +/// 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::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: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/system/develop/headers/c++/v1"); + break; + case ToolChain::CST_Libstdcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/system/develop/headers/c++"); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/system/develop/headers/c++/backward"); + + StringRef Triple = getTriple().str(); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/system/develop/headers/c++/" + + Triple); + break; + } +} + /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, @@ -3000,16 +3352,7 @@ Tool *Bitrig::buildAssembler() const { Tool *Bitrig::buildLinker() const { return new tools::bitrig::Linker(*this); } -ToolChain::CXXStdlibType Bitrig::GetCXXStdlibType(const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - StringRef Value = A->getValue(); - if (Value == "libstdc++") - return ToolChain::CST_Libstdcxx; - if (Value == "libc++") - return ToolChain::CST_Libcxx; - - getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - } +ToolChain::CXXStdlibType Bitrig::GetDefaultCXXStdlibType() const { return ToolChain::CST_Libcxx; } @@ -3073,16 +3416,7 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } -ToolChain::CXXStdlibType FreeBSD::GetCXXStdlibType(const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - StringRef Value = A->getValue(); - if (Value == "libstdc++") - return ToolChain::CST_Libstdcxx; - if (Value == "libc++") - return ToolChain::CST_Libcxx; - - getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - } +ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { if (getTriple().getOSMajorVersion() >= 10) return ToolChain::CST_Libcxx; return ToolChain::CST_Libstdcxx; @@ -3170,7 +3504,6 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - if (getDriver().UseStdLib) { // 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 @@ -3226,20 +3559,10 @@ Tool *NetBSD::buildAssembler() const { Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } -ToolChain::CXXStdlibType NetBSD::GetCXXStdlibType(const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - StringRef Value = A->getValue(); - if (Value == "libstdc++") - return ToolChain::CST_Libstdcxx; - if (Value == "libc++") - return ToolChain::CST_Libcxx; - - getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - } - +ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { unsigned Major, Minor, Micro; getTriple().getOSVersion(Major, Minor, Micro); - if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) { + if (Major >= 7 || Major == 0) { switch (getArch()) { case llvm::Triple::aarch64: case llvm::Triple::arm: @@ -3381,7 +3704,6 @@ enum Distro { DebianJessie, DebianStretch, Exherbo, - RHEL4, RHEL5, RHEL6, RHEL7, @@ -3408,7 +3730,7 @@ enum Distro { }; static bool IsRedhat(enum Distro Distro) { - return Distro == Fedora || (Distro >= RHEL4 && Distro <= RHEL7); + return Distro == Fedora || (Distro >= RHEL5 && Distro <= RHEL7); } static bool IsOpenSUSE(enum Distro Distro) { return Distro == OpenSUSE; } @@ -3450,7 +3772,8 @@ static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) { .Case("wily", UbuntuWily) .Case("xenial", UbuntuXenial) .Default(UnknownDistro); - return Version; + if (Version != UnknownDistro) + return Version; } File = llvm::MemoryBuffer::getFile("/etc/redhat-release"); @@ -3459,15 +3782,14 @@ static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) { if (Data.startswith("Fedora release")) return Fedora; if (Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS")) { + Data.startswith("CentOS") || + Data.startswith("Scientific Linux")) { if (Data.find("release 7") != StringRef::npos) return RHEL7; else if (Data.find("release 6") != StringRef::npos) return RHEL6; else if (Data.find("release 5") != StringRef::npos) return RHEL5; - else if (Data.find("release 4") != StringRef::npos) - return RHEL4; } return UnknownDistro; } @@ -3640,6 +3962,15 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { 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); @@ -3692,13 +4023,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("--hash-style=both"); } - if (IsRedhat(Distro)) + if (IsRedhat(Distro) && Distro != RHEL5 && Distro != RHEL6) ExtraOpts.push_back("--no-add-needed"); - if ((IsDebian(Distro) && Distro >= DebianSqueeze) || IsOpenSUSE(Distro) || - (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || - (IsUbuntu(Distro) && Distro >= UbuntuKarmic)) - ExtraOpts.push_back("--build-id"); +#ifdef ENABLE_LINKER_BUILD_ID + ExtraOpts.push_back("--build-id"); +#endif if (IsOpenSUSE(Distro)) ExtraOpts.push_back("--enable-new-dtags"); @@ -3718,6 +4048,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); const Multilib &Multilib = GCCInstallation.getMultilib(); + const MultilibSet &Multilibs = GCCInstallation.getMultilibs(); + + // Add toolchain / multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, Multilib, + GCCInstallation.getInstallPath(), Paths); // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. @@ -3857,6 +4192,125 @@ std::string Linux::computeSysRoot() const { return std::string(); } +std::string Linux::getDynamicLinker(const ArgList &Args) const { + const llvm::Triple::ArchType Arch = getArch(); + const llvm::Triple &Triple = getTriple(); + + const enum Distro Distro = DetectDistro(getDriver(), Arch); + + if (Triple.isAndroid()) + return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; + else if (Triple.isMusl()) { + std::string ArchName; + switch (Arch) { + case llvm::Triple::thumb: + ArchName = "arm"; + break; + case llvm::Triple::thumbeb: + ArchName = "armeb"; + break; + default: + ArchName = Triple.getArchName().str(); + } + if (Triple.getEnvironment() == llvm::Triple::MuslEABIHF) + 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 LE = (Triple.getArch() == llvm::Triple::mipsel) || + (Triple.getArch() == 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 = LE ? "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::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 == 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(); @@ -3897,11 +4351,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (GCCInstallation.isValid()) { const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { - const auto IncludePaths = Callback(GCCInstallation.getInstallPath(), - GCCInstallation.getTriple().str(), - GCCInstallation.getMultilib()); - for (const auto &Path : IncludePaths) - addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path); + for (const auto &Path : Callback(GCCInstallation.getMultilib())) + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); } } @@ -4028,7 +4480,6 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } - static std::string DetectLibcxxIncludePath(StringRef base) { std::error_code EC; int MaxVersion = 0; @@ -4058,11 +4509,11 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { const std::string LibCXXIncludePathCandidates[] = { DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"), - - // We also check the system as for a long time this is the only place - // Clang looked. - // FIXME: We should really remove this. It doesn't make any sense. - DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/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(getDriver().SysRoot + "/usr/local/include/c++"), + DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") }; for (const auto &IncludePath : LibCXXIncludePathCandidates) { if (IncludePath.empty() || !getVFS().exists(IncludePath)) continue; @@ -4103,6 +4554,7 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, 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, @@ -4127,10 +4579,23 @@ void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nocudainc)) return; - if (CudaInstallation.isValid()) { - addSystemInclude(DriverArgs, CC1Args, CudaInstallation.getIncludePath()); - CC1Args.push_back("-include"); - CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); + if (!CudaInstallation.isValid()) { + getDriver().Diag(diag::err_drv_no_cuda_installation); + return; + } + + addSystemInclude(DriverArgs, CC1Args, CudaInstallation.getIncludePath()); + CC1Args.push_back("-include"); + CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); +} + +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")); } } @@ -4158,6 +4623,8 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::Thread; if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64) Res |= SanitizerKind::Memory; + if (IsX86_64) + Res |= SanitizerKind::Efficiency; if (IsX86 || IsX86_64) { Res |= SanitizerKind::Function; } @@ -4200,13 +4667,16 @@ Tool *DragonFly::buildLinker() const { return new tools::dragonfly::Linker(*this); } -/// Stub for CUDA toolchain. At the moment we don't have assembler or -/// linker and need toolchain mainly to propagate device-side options -/// to CC1. +/// 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 ArgList &Args) - : Linux(D, Triple, Args) {} + : Linux(D, Triple, Args) { + if (CudaInstallation.isValid()) + getProgramPaths().push_back(CudaInstallation.getBinPath()); +} void CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, @@ -4214,6 +4684,14 @@ CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, Linux::addClangTargetOptions(DriverArgs, CC1Args); 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.hasArg(options::OPT_nocudalib)) return; @@ -4231,6 +4709,18 @@ CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, } } +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)); + } + Linux::AddCudaIncludeArgs(DriverArgs, CC1Args); +} + llvm::opt::DerivedArgList * CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const { @@ -4240,7 +4730,7 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches BoundArch - if (A->getValue(0) != StringRef(BoundArch)) + if (!BoundArch || A->getValue(0) != StringRef(BoundArch)) continue; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); @@ -4271,10 +4761,21 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, DAL->append(A); } - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + if (BoundArch) { + 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 { + return new tools::NVPTX::Linker(*this); +} + /// XCore tool chain XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) @@ -4341,7 +4842,7 @@ void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args, MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_GCC(D, Triple, 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 @@ -4432,6 +4933,11 @@ Tool *MyriadToolChain::buildLinker() const { WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) : ToolChain(D, Triple, Args) { + + assert(Triple.isArch32Bit() != Triple.isArch64Bit()); + getFilePaths().push_back( + getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64")); + // Use LLD by default. DefaultLinker = "lld"; } @@ -4467,6 +4973,29 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-fuse-init-array"); } +ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const { + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const { + return ToolChain::CST_Libcxx; +} + +void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nostdinc)) + addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); +} + +void WebAssembly::AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && + !DriverArgs.hasArg(options::OPT_nostdincxx)) + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/include/c++/v1"); +} + Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } @@ -4476,12 +5005,12 @@ PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) if (Args.hasArg(options::OPT_static)) D.Diag(diag::err_drv_unsupported_opt_for_target) << "-static" << "PS4"; - // Determine where to find the PS4 libraries. We use SCE_PS4_SDK_DIR + // 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_PS4_SDK_DIR")) { + 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; diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index f940e5847e14..4e5c3f7f96a6 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -11,12 +11,14 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H #include "Tools.h" +#include "clang/Basic/Cuda.h" #include "clang/Basic/VersionTuple.h" #include "clang/Driver/Action.h" #include "clang/Driver/Multilib.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Support/Compiler.h" #include <set> #include <vector> @@ -158,36 +160,52 @@ protected: GCCInstallationDetector GCCInstallation; // \brief A class to find a viable CUDA installation - class CudaInstallationDetector { - bool IsValid; + private: const Driver &D; - std::string CudaInstallPath; - std::string CudaLibPath; - std::string CudaLibDevicePath; - std::string CudaIncludePath; - llvm::StringMap<std::string> CudaLibDeviceMap; + 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> ArchsWithVersionTooLowErrors; public: - CudaInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + CudaInstallationDetector(const Driver &D) : D(D) {} void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); + /// \brief 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; + /// \brief Check whether we detected a valid Cuda install. bool isValid() const { return IsValid; } /// \brief Print information about the detected CUDA installation. void print(raw_ostream &OS) const; + /// \brief Get the deteced Cuda install's version. + CudaVersion version() const { return Version; } /// \brief Get the detected Cuda installation path. - StringRef getInstallPath() const { return CudaInstallPath; } + StringRef getInstallPath() const { return InstallPath; } + /// \brief Get the detected path to Cuda's bin directory. + StringRef getBinPath() const { return BinPath; } /// \brief Get the detected Cuda Include path. - StringRef getIncludePath() const { return CudaIncludePath; } + StringRef getIncludePath() const { return IncludePath; } /// \brief Get the detected Cuda library path. - StringRef getLibPath() const { return CudaLibPath; } + StringRef getLibPath() const { return LibPath; } /// \brief Get the detected Cuda device library path. - StringRef getLibDevicePath() const { return CudaLibDevicePath; } + StringRef getLibDevicePath() const { return LibDevicePath; } /// \brief Get libdevice file for given architecture std::string getLibDeviceFile(StringRef Gpu) const { - return CudaLibDeviceMap.lookup(Gpu); + return LibDeviceMap.lookup(Gpu); } }; @@ -493,6 +511,10 @@ protected: return TargetVersion < VersionTuple(V0, V1, V2); } + StringRef getPlatformFamily() const; + static StringRef getSDKName(StringRef isysroot); + StringRef getOSLibraryNameSuffix() const; + public: /// } /// @name ToolChain Implementation @@ -507,6 +529,7 @@ public: TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const override; + CXXStdlibType GetDefaultCXXStdlibType() const override; ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; bool hasBlocksRuntime() const override; @@ -536,6 +559,8 @@ public: bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + bool SupportsEmbeddedBitcode() const override; + SanitizerMask getSupportedSanitizers() const override; }; @@ -609,7 +634,10 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool isPIEDefault() const override { return false; } + bool isPIEDefault() const override { return true; } + + SanitizerMask getSupportedSanitizers() const override; + SanitizerMask getDefaultSanitizers() const override; protected: Tool *buildLinker() const override; @@ -667,6 +695,18 @@ private: void findGccLibDir(); }; +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 + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { public: OpenBSD(const Driver &D, const llvm::Triple &Triple, @@ -694,7 +734,7 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType GetDefaultCXXStdlibType() const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -718,7 +758,7 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType GetDefaultCXXStdlibType() const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -746,7 +786,7 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType GetDefaultCXXStdlibType() const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, @@ -795,12 +835,16 @@ public: 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; bool isPIEDefault() 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: @@ -818,6 +862,24 @@ public: const char *BoundArch) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + + // Never try to use the integrated assembler with CUDA; always fork out to + // ptxas. + bool useIntegratedAs() const override { return false; } + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + const Generic_GCC::CudaInstallationDetector &cudaInstallation() const { + return CudaInstallation; + } + Generic_GCC::CudaInstallationDetector &cudaInstallation() { + return CudaInstallation; + } + +protected: + Tool *buildAssembler() const override; // ptxas + Tool *buildLinker() const override; // fatbinary (ok, not really a linker) }; class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux { @@ -856,6 +918,14 @@ private: std::string LibSuffix; }; +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) {} + bool IsIntegratedAssemblerDefault() const override { return true; } +}; + class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { protected: GCCVersion GCCLibAndIncVersion; @@ -900,6 +970,7 @@ protected: public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); + unsigned GetDefaultDwarfVersion() const override { return 2; } bool IsIntegratedAssemblerDefault() const override { return true; } }; @@ -987,6 +1058,7 @@ public: bool getVisualStudioInstallDir(std::string &path) const; bool getVisualStudioBinariesFolder(const char *clangProgramPath, std::string &path) const; + VersionTuple getMSVCVersionFromExe() const override; std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; @@ -1064,7 +1136,7 @@ public: /// 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_GCC { +class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF { public: MyriadToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); @@ -1109,6 +1181,14 @@ private: bool HasNativeLLVMSupport() const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) 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; Tool *buildLinker() const override; }; diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index b139cd47688e..a40d6378521c 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -96,6 +96,14 @@ static const char *getSparcAsmModeForCPU(StringRef Name, .Case("niagara2", "-Av8plusb") .Case("niagara3", "-Av8plusd") .Case("niagara4", "-Av8plusd") + .Case("leon2", "-Av8") + .Case("at697e", "-Av8") + .Case("at697f", "-Av8") + .Case("leon3", "-Av8") + .Case("ut699", "-Av8") + .Case("gr712rc", "-Av8") + .Case("leon4", "-Av8") + .Case("gr740", "-Av8") .Default("-Av8"); } } @@ -288,13 +296,47 @@ static bool forwardToGCC(const Option &O) { !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } +/// Add the C++ include args of other offloading toolchains. If this is a host +/// job, the device toolchains are added. If this is a device job, the host +/// toolchains will be added. +static void addExtraOffloadCXXStdlibIncludeArgs(Compilation &C, + const JobAction &JA, + const ArgList &Args, + ArgStringList &CmdArgs) { + + if (JA.isHostOffloading(Action::OFK_Cuda)) + C.getSingleOffloadToolChain<Action::OFK_Cuda>() + ->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + else if (JA.isDeviceOffloading(Action::OFK_Cuda)) + C.getSingleOffloadToolChain<Action::OFK_Host>() + ->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + + // TODO: Add support for other programming models here. +} + +/// Add the include args that are specific of each offloading programming model. +static void addExtraOffloadSpecificIncludeArgs(Compilation &C, + const JobAction &JA, + const ArgList &Args, + ArgStringList &CmdArgs) { + + if (JA.isHostOffloading(Action::OFK_Cuda)) + C.getSingleOffloadToolChain<Action::OFK_Host>()->AddCudaIncludeArgs( + Args, CmdArgs); + else if (JA.isDeviceOffloading(Action::OFK_Cuda)) + C.getSingleOffloadToolChain<Action::OFK_Cuda>()->AddCudaIncludeArgs( + Args, CmdArgs); + + // TODO: Add support for other programming models here. +} + void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, - const InputInfoList &Inputs, - const ToolChain *AuxToolChain) const { + const InputInfoList &Inputs) const { Arg *A; + const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); CheckPreprocessingOptions(D, Args); @@ -386,9 +428,74 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // 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. + int YcIndex = -1, YuIndex = -1; + { + int AI = -1; + const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); + const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); + for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { + // Walk the whole i_Group and skip non "-include" flags so that the index + // here matches the index in the next loop below. + ++AI; + if (!A->getOption().matches(options::OPT_include)) + continue; + if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0) + YcIndex = AI; + if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0) + YuIndex = AI; + } + } + if (isa<PrecompileJobAction>(JA) && YcIndex != -1) { + Driver::InputList Inputs; + D.BuildInputs(getToolChain(), C.getArgs(), Inputs); + assert(Inputs.size() == 1 && "Need one input when building pch"); + CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") + + Inputs[0].second->getValue())); + } + bool RenderedImplicitInclude = false; + int AI = -1; for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - if (A->getOption().matches(options::OPT_include)) { + ++AI; + + if (getToolChain().getDriver().IsCLMode() && + A->getOption().matches(options::OPT_include)) { + // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h + // include is compiled into foo.h, and everything after goes into + // the .obj file. /Yufoo.h means that all includes prior to and including + // foo.h are completely skipped and replaced with a use of the pch file + // for foo.h. (Each flag can have at most one value, multiple /Yc flags + // just mean that the last one wins.) If /Yc and /Yu are both present + // and refer to the same file, /Yc wins. + // Note that OPT__SLASH_FI gets mapped to OPT_include. + // FIXME: The code here assumes that /Yc and /Yu refer to the same file. + // cl.exe seems to support both flags with different values, but that + // seems strange (which flag does /Fp now refer to?), so don't implement + // that until someone needs it. + int PchIndex = YcIndex != -1 ? YcIndex : YuIndex; + if (PchIndex != -1) { + if (isa<PrecompileJobAction>(JA)) { + // When building the pch, skip all includes after the pch. + assert(YcIndex != -1 && PchIndex == YcIndex); + if (AI >= YcIndex) + continue; + } else { + // When using the pch, skip all includes prior to the pch. + if (AI < PchIndex) { + A->claim(); + continue; + } + if (AI == PchIndex) { + A->claim(); + CmdArgs.push_back("-include-pch"); + CmdArgs.push_back( + Args.MakeArgString(D.GetClPchPath(C, A->getValue()))); + continue; + } + } + } + } else if (A->getOption().matches(options::OPT_include)) { + // Handling of gcc-style gch precompiled headers. bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; @@ -436,6 +543,13 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, << 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; } // Not translated, render as usual. @@ -485,26 +599,27 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH"); - // Optional AuxToolChain indicates that we need to include headers - // for more than one target. If that's the case, add include paths - // from AuxToolChain right after include paths of the same kind for - // the current target. + // 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())) { getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs); - if (AuxToolChain) - AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + addExtraOffloadCXXStdlibIncludeArgs(C, JA, Args, CmdArgs); } - // Add system include arguments. - getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs); - if (AuxToolChain) - AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + // Add system include arguments for all targets but IAMCU. + if (!IsIAMCU) { + getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs); + addExtraOffloadCXXStdlibIncludeArgs(C, JA, Args, CmdArgs); + } else { + // For IAMCU add special include arguments. + getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); + } - // Add CUDA include arguments, if needed. - if (types::isCuda(Inputs[0].getType())) - getToolChain().AddCudaIncludeArgs(Args, CmdArgs); + // Add offload include arguments, if needed. + addExtraOffloadSpecificIncludeArgs(C, JA, Args, CmdArgs); } // FIXME: Move to target hook. @@ -698,6 +813,7 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { 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: @@ -724,10 +840,12 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { 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; @@ -737,7 +855,12 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { break; default: // Assume "soft", but warn the user we are guessing. - ABI = FloatABI::Soft; + 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"; @@ -879,10 +1002,6 @@ static void getARMTargetFeatures(const ToolChain &TC, Features.push_back("-crc"); } - if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_1a) { - Features.insert(Features.begin(), "+v8.1a"); - } - // 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. @@ -904,6 +1023,10 @@ static void getARMTargetFeatures(const ToolChain &TC, // 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 { @@ -954,7 +1077,7 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, } else if (Triple.isOSBinFormatMachO()) { if (useAAPCSForMachO(Triple)) { ABIName = "aapcs"; - } else if (Triple.isWatchOS()) { + } else if (Triple.isWatchABI()) { ABIName = "aapcs16"; } else { ABIName = "apcs-gnu"; @@ -968,6 +1091,8 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, case llvm::Triple::Android: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: + case llvm::Triple::MuslEABI: + case llvm::Triple::MuslEABIHF: ABIName = "aapcs-linux"; break; case llvm::Triple::EABIHF: @@ -1112,8 +1237,10 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, } // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android). - if (Triple.isAndroid()) + if (Triple.isAndroid()) { + DefMips32CPU = "mips32"; DefMips64CPU = "mips64r6"; + } // MIPS3 is the default for mips64*-unknown-openbsd. if (Triple.getOS() == llvm::Triple::OpenBSD) @@ -1148,6 +1275,30 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, } } + 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. if (Triple.getArch() == llvm::Triple::mips || @@ -1160,7 +1311,7 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, if (CPUName.empty()) { // Deduce CPU name from ABI name. CPUName = llvm::StringSwitch<const char *>(ABIName) - .Cases("o32", "eabi", DefMips32CPU) + .Case("o32", DefMips32CPU) .Cases("n32", "n64", DefMips64CPU) .Default(""); } @@ -1286,8 +1437,9 @@ static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa, "msa"); - // Add the last -mfp32/-mfpxx/-mfp64 or if none are given and the ABI is O32 - // pass -mfpxx + // 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)) @@ -1300,6 +1452,9 @@ static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { Features.push_back(Args.MakeArgString("+fpxx")); Features.push_back(Args.MakeArgString("+nooddspreg")); + } else if (mips::isFP64ADefault(Triple, CPUName)) { + Features.push_back(Args.MakeArgString("+fp64")); + Features.push_back(Args.MakeArgString("+nooddspreg")); } AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, @@ -1359,6 +1514,19 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v)); A->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; + } } /// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. @@ -1408,6 +1576,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) { .Case("power6x", "pwr6x") .Case("power7", "pwr7") .Case("power8", "pwr8") + .Case("power9", "pwr9") .Case("pwr3", "pwr3") .Case("pwr4", "pwr4") .Case("pwr5", "pwr5") @@ -1416,6 +1585,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) { .Case("pwr6x", "pwr6x") .Case("pwr7", "pwr7") .Case("pwr8", "pwr8") + .Case("pwr9", "pwr9") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") .Case("powerpc64le", "ppc64le") @@ -1554,29 +1724,79 @@ static std::string getR600TargetGPU(const ArgList &Args) { return ""; } -void Clang::AddSparcTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getDriver(); - std::string Triple = getToolChain().ComputeEffectiveClangTriple(Args); +static std::string getLanaiTargetCPU(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + return A->getValue(); + } + return ""; +} - bool SoftFloatABI = false; +sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, + const ArgList &Args) { + sparc::FloatABI ABI = sparc::FloatABI::Invalid; if (Arg *A = - Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) - SoftFloatABI = true; + 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(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, and - // perhaps LLVM should implement that, too. However, since llvm - // currently does not support Sparc soft-float, at all, display an - // error if it's requested. - if (SoftFloatABI) { - D.Diag(diag::err_drv_unsupported_opt_for_target) << "-msoft-float" - << Triple; + // 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; +} + +static void getSparcTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<const char *> &Features) { + sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args); + if (FloatABI == sparc::FloatABI::Soft) + Features.push_back("+soft-float"); +} + +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"); +} + static const char *getSystemZTargetCPU(const ArgList &Args) { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) return A->getValue(); @@ -1771,6 +1991,9 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, return "hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + case llvm::Triple::lanai: + return getLanaiTargetCPU(Args); + case llvm::Triple::systemz: return getSystemZTargetCPU(Args); @@ -1817,6 +2040,17 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); + + // 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"); + } } /// This is a helper function for validating the optional refinement step @@ -2045,6 +2279,13 @@ void Clang::AddX86TargetArgs(const ArgList &Args, << A->getOption().getName() << Value; } } + + // 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, @@ -2069,6 +2310,29 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, 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. @@ -2093,12 +2357,14 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, .Case("crypto", "+crypto") .Case("fp16", "+fullfp16") .Case("profile", "+spe") + .Case("ras", "+ras") .Case("nofp", "-fp-armv8") .Case("nosimd", "-neon") .Case("nocrc", "-crc") .Case("nocrypto", "-crypto") .Case("nofp16", "-fullfp16") .Case("noprofile", "-spe") + .Case("noras", "-ras") .Default(nullptr); if (result) Features.push_back(result); @@ -2116,11 +2382,15 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, std::vector<const char *> &Features) { std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; - if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57" || - CPU == "cortex-a72" || CPU == "cortex-a35" || CPU == "exynos-m1") { + if (CPU == "cortex-a53" || CPU == "cortex-a57" || + CPU == "cortex-a72" || CPU == "cortex-a35" || CPU == "exynos-m1" || + CPU == "kryo" || CPU == "cortex-a73" || CPU == "vulcan") { Features.push_back("+neon"); Features.push_back("+crc"); Features.push_back("+crypto"); + } else if (CPU == "cyclone") { + Features.push_back("+neon"); + Features.push_back("+crypto"); } else if (CPU == "generic") { Features.push_back("+neon"); } else { @@ -2277,6 +2547,23 @@ static void getWebAssemblyTargetFeatures(const ArgList &Args, handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); } +static void getAMDGPUTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<const char *> &Features) { + if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) { + StringRef value = dAbi->getValue(); + if (value == "1.0") { + Features.push_back("+amdgpu-debugger-insert-nops"); + Features.push_back("+amdgpu-debugger-reserve-regs"); + Features.push_back("+amdgpu-debugger-emit-prologue"); + } else { + D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); + } + } + + handleTargetFeaturesGroup( + Args, Features, options::OPT_m_amdgpu_Features_Group); +} + static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool ForAS) { @@ -2321,6 +2608,15 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, case llvm::Triple::wasm32: case llvm::Triple::wasm64: getWebAssemblyTargetFeatures(Args, Features); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + getSparcTargetFeatures(D, Args, Features); + break; + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + getAMDGPUTargetFeatures(D, Args, Features); break; } @@ -2401,11 +2697,9 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, } if (types::isCXX(InputType)) { - // Disable C++ EH by default on XCore, PS4, and MSVC. - // FIXME: Remove MSVC from this list once things work. - bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore && - !Triple.isPS4CPU() && - !Triple.isWindowsMSVCEnvironment(); + // 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); @@ -2464,8 +2758,8 @@ static bool ContainsCompileAction(const Action *A) { if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) return true; - for (const auto &Act : *A) - if (ContainsCompileAction(Act)) + for (const auto &AI : A->inputs()) + if (ContainsCompileAction(AI)) return true; return false; @@ -2495,16 +2789,16 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { // 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) { +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; + return codegenoptions::NoDebugInfo; if (A.getOption().matches(options::OPT_gline_tables_only) || A.getOption().matches(options::OPT_ggdb1)) - return CodeGenOptions::DebugLineTablesOnly; - return CodeGenOptions::LimitedDebugInfo; + return codegenoptions::DebugLineTablesOnly; + return codegenoptions::LimitedDebugInfo; } // Extract the integer N from a string spelled "-dwarf-N", returning 0 @@ -2520,17 +2814,17 @@ static unsigned DwarfVersionNum(StringRef ArgValue) { } static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, - CodeGenOptions::DebugInfoKind DebugInfoKind, + codegenoptions::DebugInfoKind DebugInfoKind, unsigned DwarfVersion, llvm::DebuggerKind DebuggerTuning) { switch (DebugInfoKind) { - case CodeGenOptions::DebugLineTablesOnly: + case codegenoptions::DebugLineTablesOnly: CmdArgs.push_back("-debug-info-kind=line-tables-only"); break; - case CodeGenOptions::LimitedDebugInfo: + case codegenoptions::LimitedDebugInfo: CmdArgs.push_back("-debug-info-kind=limited"); break; - case CodeGenOptions::FullDebugInfo: + case codegenoptions::FullDebugInfo: CmdArgs.push_back("-debug-info-kind=standalone"); break; default: @@ -2580,6 +2874,9 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, // When using an integrated assembler, translate -Wa, and -Xassembler // options. bool CompressDebugSections = false; + + bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS; + const char *MipsTargetFeature = nullptr; for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { A->claim(); @@ -2618,7 +2915,26 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-soft-float"); continue; } - break; + + 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") { @@ -2635,6 +2951,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { CompressDebugSections = false; + } 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 @@ -2647,9 +2969,9 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, 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); + RenderDebugEnablingArgs(Args, CmdArgs, + codegenoptions::LimitedDebugInfo, + DwarfVersion, llvm::DebuggerKind::Default); } } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || Value.startswith("-mhwdiv") || Value.startswith("-march")) { @@ -2666,6 +2988,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, else D.Diag(diag::warn_debug_compression_unavailable); } + if (UseRelaxRelocations) + CmdArgs.push_back("--mrelax-relocations"); + if (MipsTargetFeature != nullptr) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(MipsTargetFeature); + } } // This adds the static libclang_rt.builtins-arch.a directly to the command line @@ -2749,12 +3077,12 @@ static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer, - bool IsShared) { - // Static runtimes must be forced into executable, so we wrap them in + bool IsShared, bool IsWhole) { + // Wrap any static runtimes that must be forced into executable in // whole-archive. - if (!IsShared) CmdArgs.push_back("-whole-archive"); + if (IsWhole) CmdArgs.push_back("-whole-archive"); CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); - if (!IsShared) CmdArgs.push_back("-no-whole-archive"); + if (IsWhole) CmdArgs.push_back("-no-whole-archive"); } // Tries to use a file with the list of dynamic symbols that need to be exported @@ -2787,12 +3115,17 @@ static void collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl<StringRef> &SharedRuntimes, SmallVectorImpl<StringRef> &StaticRuntimes, - SmallVectorImpl<StringRef> &HelperStaticRuntimes) { + SmallVectorImpl<StringRef> &NonWholeStaticRuntimes, + SmallVectorImpl<StringRef> &HelperStaticRuntimes, + SmallVectorImpl<StringRef> &RequiredSymbols) { const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Collect shared runtimes. if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { SharedRuntimes.push_back("asan"); } + // The stats_client library is also statically linked into DSOs. + if (SanArgs.needsStatsRt()) + StaticRuntimes.push_back("stats_client"); // Collect static runtimes. if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) { @@ -2831,8 +3164,17 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("safestack"); if (SanArgs.needsCfiRt()) StaticRuntimes.push_back("cfi"); - if (SanArgs.needsCfiDiagRt()) + if (SanArgs.needsCfiDiagRt()) { StaticRuntimes.push_back("cfi_diag"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } + if (SanArgs.needsStatsRt()) { + NonWholeStaticRuntimes.push_back("stats"); + RequiredSymbols.push_back("__sanitizer_stats_register"); + } + if (SanArgs.needsEsanRt()) + StaticRuntimes.push_back("esan"); } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, @@ -2840,18 +3182,27 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes, - HelperStaticRuntimes; + NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, - HelperStaticRuntimes); + NonWholeStaticRuntimes, HelperStaticRuntimes, + RequiredSymbols); for (auto RT : SharedRuntimes) - addSanitizerRuntime(TC, Args, CmdArgs, RT, true); + addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false); for (auto RT : HelperStaticRuntimes) - addSanitizerRuntime(TC, Args, CmdArgs, RT, false); + addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); bool AddExportDynamic = false; for (auto RT : StaticRuntimes) { - addSanitizerRuntime(TC, Args, CmdArgs, RT, false); + 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) @@ -2859,6 +3210,33 @@ static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, return !StaticRuntimes.empty(); } +static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); + CmdArgs.push_back("-no-whole-archive"); + return true; + } + return false; +} + +static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-latomic"); + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + CmdArgs.push_back("-lc++"); + else + CmdArgs.push_back("-lstdc++"); + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + CmdArgs.push_back("-ldl"); +} + static bool 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)) @@ -2900,6 +3278,8 @@ static bool shouldUseFramePointerForTarget(const ArgList &Args, 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 @@ -3092,7 +3472,7 @@ static void appendUserToPath(SmallVectorImpl<char> &Result) { Result.append(UID.begin(), UID.end()); } -VersionTuple visualstudio::getMSVCVersion(const Driver *D, +VersionTuple visualstudio::getMSVCVersion(const Driver *D, const ToolChain &TC, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, bool IsWindowsMSVC) { @@ -3134,7 +3514,14 @@ VersionTuple visualstudio::getMSVCVersion(const Driver *D, if (Major || Minor || Micro) return VersionTuple(Major, Minor, Micro); - return VersionTuple(18); + if (IsWindowsMSVC) { + VersionTuple MSVT = TC.getMSVCVersionFromExe(); + if (!MSVT.empty()) + return MSVT; + + // FIXME: Consider bumping this to 19 (MSVC2015) soon. + return VersionTuple(18); + } } return VersionTuple(); } @@ -3142,16 +3529,27 @@ VersionTuple visualstudio::getMSVCVersion(const Driver *D, static void addPGOAndCoverageFlags(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 *ProfileGenerateArg = Args.getLastArg( options::OPT_fprofile_instr_generate, - options::OPT_fprofile_instr_generate_EQ, options::OPT_fprofile_generate, - options::OPT_fprofile_generate_EQ, + 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 = Args.getLastArg( options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, @@ -3160,6 +3558,10 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) ProfileUseArg = nullptr; + 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(); @@ -3167,20 +3569,27 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, if (ProfileGenerateArg) { if (ProfileGenerateArg->getOption().matches( options::OPT_fprofile_instr_generate_EQ)) - ProfileGenerateArg->render(Args, CmdArgs); - else if (ProfileGenerateArg->getOption().matches( - options::OPT_fprofile_generate_EQ)) { - SmallString<128> Path(ProfileGenerateArg->getValue()); + 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 (PGOGenerateArg) { + CmdArgs.push_back("-fprofile-instrument=llvm"); + if (PGOGenerateArg->getOption().matches( + options::OPT_fprofile_generate_EQ)) { + SmallString<128> Path(PGOGenerateArg->getValue()); llvm::sys::path::append(Path, "default.profraw"); CmdArgs.push_back( - Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); - } else - Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); + Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path)); + } } if (ProfileUseArg) { if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) - ProfileUseArg->render(Args, CmdArgs); + 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( @@ -3190,7 +3599,7 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, if (Path.empty() || llvm::sys::fs::is_directory(Path)) llvm::sys::path::append(Path, "default.profdata"); CmdArgs.push_back( - Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path)); } } @@ -3392,8 +3801,6 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, static const char *RelocationModelName(llvm::Reloc::Model Model) { switch (Model) { - case llvm::Reloc::Default: - return nullptr; case llvm::Reloc::Static: return "static"; case llvm::Reloc::PIC_: @@ -3432,6 +3839,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().isWindowsCygwinEnvironment(); bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); bool IsPS4CPU = getToolChain().getTriple().isPS4CPU(); + bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); // Check number of inputs for sanity. We need at least one input. assert(Inputs.size() >= 1 && "Must have at least one input."); @@ -3439,9 +3847,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // CUDA compilation may have multiple inputs (source file + results of // device-side compilations). All other jobs are expected to have exactly one // input. - bool IsCuda = types::isCuda(Input.getType()); + bool IsCuda = JA.isOffloading(Action::OFK_Cuda); assert((IsCuda || Inputs.size() == 1) && "Unable to handle multiple inputs."); + // 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. @@ -3451,23 +3863,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-triple"); CmdArgs.push_back(Args.MakeArgString(TripleStr)); - const ToolChain *AuxToolChain = nullptr; if (IsCuda) { - // FIXME: We need a (better) way to pass information about - // particular compilation pass we're constructing here. For now we - // can check which toolchain we're using and pick the other one to - // extract the triple. - if (&getToolChain() == C.getCudaDeviceToolChain()) - AuxToolChain = C.getCudaHostToolChain(); - else if (&getToolChain() == C.getCudaHostToolChain()) - AuxToolChain = C.getCudaDeviceToolChain(); + // We have to pass the triple of the host if compiling for a CUDA device and + // vice-versa. + std::string NormalizedTriple; + if (JA.isDeviceOffloading(Action::OFK_Cuda)) + NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>() + ->getTriple() + .normalize(); else - llvm_unreachable("Can't figure out CUDA compilation mode."); - assert(AuxToolChain != nullptr && "No aux toolchain."); + NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>() + ->getTriple() + .normalize(); + CmdArgs.push_back("-aux-triple"); - CmdArgs.push_back(Args.MakeArgString(AuxToolChain->getTriple().str())); - CmdArgs.push_back("-fcuda-target-overloads"); - CmdArgs.push_back("-fcuda-disable-target-call-checks"); + CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); } if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || @@ -3566,6 +3976,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + // Embed-bitcode option. + if (C.getDriver().embedBitcodeEnabled() && + (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-optzns"); + } + if (C.getDriver().embedBitcodeMarkerOnly()) + 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. @@ -3575,6 +3996,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Disable the verification pass in -asserts builds. #ifdef NDEBUG CmdArgs.push_back("-disable-llvm-verifier"); + // Discard LLVM value names in -asserts builds. + CmdArgs.push_back("-discard-value-names"); #endif // Set the main file name, so that debug info works even with @@ -3600,8 +4023,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); - if (!IsWindowsMSVC) - CmdArgs.push_back("-analyzer-checker=unix"); + if (!IsWindowsMSVC) { + 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 (IsPS4CPU) { @@ -3666,10 +4098,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (PICLevel > 0) { CmdArgs.push_back("-pic-level"); CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); - if (IsPIE) { - CmdArgs.push_back("-pie-level"); - CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); - } + if (IsPIE) + CmdArgs.push_back("-pic-is-pie"); } if (Arg *A = Args.getLastArg(options::OPT_meabi)) { @@ -3708,6 +4138,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables, + true)) + CmdArgs.push_back("-fno-jump-tables"); + if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); CmdArgs.push_back(A->getValue()); @@ -3727,7 +4161,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) - CmdArgs.push_back("-mrtd"); + CmdArgs.push_back("-fdefault-calling-conv=stdcall"); if (shouldUseFramePointer(Args, getToolChain().getTriple())) CmdArgs.push_back("-mdisable-fp-elim"); @@ -3923,9 +4357,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("Arguments"); } - // Enable -mconstructor-aliases except on darwin, where we have to - // work around a linker bug; see <rdar://problem/7651567>. - if (!getToolChain().getTriple().isOSDarwin()) + // 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 (!getToolChain().getTriple().isOSDarwin() && + !getToolChain().getTriple().isNVPTX()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we @@ -4018,11 +4454,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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; @@ -4045,13 +4489,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, unsigned DwarfVersion = 0; llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning(); // These two are potentially updated by AddClangCLArgs. - enum CodeGenOptions::DebugInfoKind DebugInfoKind = - CodeGenOptions::NoDebugInfo; + codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; bool EmitCodeView = false; // Add clang-cl arguments. + types::ID InputType = Input.getType(); if (getToolChain().getDriver().IsCLMode()) - AddClangCLArgs(Args, CmdArgs, &DebugInfoKind, &EmitCodeView); + AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { @@ -4064,7 +4508,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Explicitly error on some things we know we don't support and can't just // ignore. - types::ID InputType = Input.getType(); if (!Args.hasArg(options::OPT_fallow_unsupported)) { Arg *Unsupported; if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() && @@ -4101,12 +4544,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. // But -gsplit-dwarf is not a g_group option, hence we have to check the // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.) - if (SplitDwarfArg && DebugInfoKind < CodeGenOptions::LimitedDebugInfo && + if (SplitDwarfArg && DebugInfoKind < codegenoptions::LimitedDebugInfo && A->getIndex() > SplitDwarfArg->getIndex()) SplitDwarfArg = nullptr; } else // For any other 'g' option, use Limited. - DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + DebugInfoKind = codegenoptions::LimitedDebugInfo; } // If a debugger tuning argument appeared, remember it. @@ -4131,7 +4574,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // DwarfVersion remains at 0 if no explicit choice was made. CmdArgs.push_back("-gcodeview"); } else if (DwarfVersion == 0 && - DebugInfoKind != CodeGenOptions::NoDebugInfo) { + DebugInfoKind != codegenoptions::NoDebugInfo) { DwarfVersion = getToolChain().GetDefaultDwarfVersion(); } @@ -4145,7 +4588,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: Move backend command line options to the module. if (Args.hasArg(options::OPT_gmodules)) { - DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + DebugInfoKind = codegenoptions::LimitedDebugInfo; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); } @@ -4154,7 +4597,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // splitting and extraction. // FIXME: Currently only works on Linux. if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { - DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + DebugInfoKind = codegenoptions::LimitedDebugInfo; CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } @@ -4167,8 +4610,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, options::OPT_fno_standalone_debug, getToolChain().GetDefaultStandaloneDebug()); - if (DebugInfoKind == CodeGenOptions::LimitedDebugInfo && NeedFullDebug) - DebugInfoKind = CodeGenOptions::FullDebugInfo; + if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) + DebugInfoKind = codegenoptions::FullDebugInfo; RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, DebuggerTuning); @@ -4214,6 +4657,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-fxray-instrument"); + if (const Arg *A = + Args.getLastArg(options::OPT_fxray_instruction_threshold_, + options::OPT_fxray_instruction_threshold_EQ)) { + CmdArgs.push_back("-fxray-instruction-threshold"); + CmdArgs.push_back(A->getValue()); + } + } + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); // Add runtime flag for PS4 when PGO or Coverage are enabled. @@ -4312,8 +4766,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // // FIXME: Support -fpreprocessed if (types::getPreprocessedType(InputType) != types::TY_INVALID) - AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs, - AuxToolChain); + 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". @@ -4555,7 +5008,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); // Emulated TLS is enabled by default on Android, and can be enabled manually // with -femulated-tls. - bool EmulatedTLSDefault = Triple.isAndroid(); + bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isWindowsCygwinEnvironment(); if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, EmulatedTLSDefault)) CmdArgs.push_back("-femulated-tls"); @@ -4569,7 +5022,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward flags for OpenMP if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false)) + options::OPT_fno_openmp, false)) { switch (getOpenMPRuntime(getToolChain(), Args)) { case OMPRT_OMP: case OMPRT_IOMP5: @@ -4582,6 +5035,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fopenmp_use_tls, options::OPT_fnoopenmp_use_tls, /*Default=*/true)) CmdArgs.push_back("-fnoopenmp-use-tls"); + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -4592,6 +5046,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // semantic analysis, etc. break; } + } const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); Sanitize.addArgs(getToolChain(), Args, CmdArgs, InputType); @@ -4660,15 +5115,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; - if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { - Args.ClaimAllArgs(options::OPT_fno_stack_protector); - Args.ClaimAllArgs(options::OPT_fstack_protector_all); - Args.ClaimAllArgs(options::OPT_fstack_protector_strong); - Args.ClaimAllArgs(options::OPT_fstack_protector); - } else 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 (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, @@ -4749,6 +5199,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arm-restrict-it"); } + // Forward -cl options to -cc1 + if (Args.getLastArg(options::OPT_cl_opt_disable)) { + CmdArgs.push_back("-cl-opt-disable"); + } + if (Args.getLastArg(options::OPT_cl_strict_aliasing)) { + CmdArgs.push_back("-cl-strict-aliasing"); + } + if (Args.getLastArg(options::OPT_cl_single_precision_constant)) { + CmdArgs.push_back("-cl-single-precision-constant"); + } + if (Args.getLastArg(options::OPT_cl_finite_math_only)) { + CmdArgs.push_back("-cl-finite-math-only"); + } + if (Args.getLastArg(options::OPT_cl_kernel_arg_info)) { + CmdArgs.push_back("-cl-kernel-arg-info"); + } + if (Args.getLastArg(options::OPT_cl_unsafe_math_optimizations)) { + CmdArgs.push_back("-cl-unsafe-math-optimizations"); + } + if (Args.getLastArg(options::OPT_cl_fast_relaxed_math)) { + CmdArgs.push_back("-cl-fast-relaxed-math"); + } + if (Args.getLastArg(options::OPT_cl_mad_enable)) { + CmdArgs.push_back("-cl-mad-enable"); + } + if (Args.getLastArg(options::OPT_cl_no_signed_zeros)) { + CmdArgs.push_back("-cl-no-signed-zeros"); + } + if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { + std::string CLStdStr = "-cl-std="; + CLStdStr += A->getValue(); + CmdArgs.push_back(Args.MakeArgString(CLStdStr)); + } + if (Args.getLastArg(options::OPT_cl_denorms_are_zero)) { + CmdArgs.push_back("-cl-denorms-are-zero"); + } + // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { @@ -4841,28 +5328,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fimplicit_modules, options::OPT_fno_implicit_modules)) { CmdArgs.push_back("-fno-implicit-modules"); - } - - // -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); - - // -fmodule-map-file can be used to specify files containing module - // definitions. - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); - - // -fmodule-file can be used to specify files containing precompiled modules. - if (HaveModules) - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); - else - Args.ClaimAllArgs(options::OPT_fmodule_file); - - // -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 (HaveModules) { + } else if (HaveModules) { + // -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. @@ -4881,6 +5352,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Path)); } + // -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); + + // -fmodule-file can be used to specify files containing precompiled modules. + 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 (HaveModules && C.isForDiagnostics()) { @@ -4995,17 +5480,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fms-compatibility-version=18.00 is default. VersionTuple MSVT = visualstudio::getMSVCVersion( - &D, getToolChain().getTriple(), Args, IsWindowsMSVC); + &D, getToolChain(), getToolChain().getTriple(), Args, IsWindowsMSVC); if (!MSVT.empty()) CmdArgs.push_back( Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); bool IsMSVC2015Compatible = MSVT.getMajor() >= 19; if (ImplyVCPPCXXVer) { - if (IsMSVC2015Compatible) - CmdArgs.push_back("-std=c++14"); - else - CmdArgs.push_back("-std=c++11"); + StringRef LanguageStandard; + if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) { + LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue()) + .Case("c++14", "-std=c++14") + .Case("c++latest", "-std=c++1z") + .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. @@ -5046,8 +5546,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fno_inline)) CmdArgs.push_back("-fno-inline"); - if (Args.hasArg(options::OPT_fno_inline_functions)) - CmdArgs.push_back("-fno-inline-functions"); + if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions, + options::OPT_finline_hint_functions, + options::OPT_fno_inline_functions)) + InlineArg->render(Args, CmdArgs); ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); @@ -5156,7 +5658,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime, CmdArgs); - if (getToolChain().UseSjLjExceptions(Args)) + if (Args.hasArg(options::OPT_fsjlj_exceptions) || + getToolChain().UseSjLjExceptions(Args)) CmdArgs.push_back("-fsjlj-exceptions"); // C++ "sane" operator new. @@ -5286,43 +5789,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); } - // Color diagnostics are the default, unless the terminal doesn't support - // them. - // Support both clang's -f[no-]color-diagnostics and gcc's - // -f[no-]diagnostics-colors[=never|always|auto]. - enum { Colors_On, Colors_Off, Colors_Auto } ShowColors = Colors_Auto; - for (const auto &Arg : Args) { - const Option &O = Arg->getOption(); + // 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 (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; - - Arg->claim(); - if (O.matches(options::OPT_fcolor_diagnostics) || - O.matches(options::OPT_fdiagnostics_color)) { - ShowColors = Colors_On; - } else if (O.matches(options::OPT_fno_color_diagnostics) || - O.matches(options::OPT_fno_diagnostics_color)) { - ShowColors = Colors_Off; - } else { - assert(O.matches(options::OPT_fdiagnostics_color_EQ)); - StringRef value(Arg->getValue()); - if (value == "always") - ShowColors = Colors_On; - else if (value == "never") - ShowColors = Colors_Off; - else if (value == "auto") - ShowColors = Colors_Auto; - else + if (O.matches(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value != "always" && Value != "never" && Value != "auto") getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) - << ("-fdiagnostics-color=" + value).str(); + << ("-fdiagnostics-color=" + Value).str(); } + A->claim(); } - if (ShowColors == Colors_On || - (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors())) + if (D.getDiags().getDiagnosticOptions().ShowColors) CmdArgs.push_back("-fcolor-diagnostics"); if (Args.hasArg(options::OPT_fansi_escape_codes)) @@ -5376,6 +5863,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); + if (Arg *A = Args.getLastArg( + options::OPT_fsanitize_undefined_strip_path_components_EQ)) + A->render(Args, CmdArgs); + // -fdollars-in-identifiers default varies depending on platform and // language; only pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, @@ -5407,7 +5898,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // -// FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. +// FIXME: Now that PR4941 has been fixed this can be enabled. #if 0 if (getToolChain().getTriple().isOSDarwin() && (getToolChain().getArch() == llvm::Triple::arm || @@ -5478,7 +5969,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // 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. - if (C.getDriver().isSaveTempsEnabled() && isa<CompileJobAction>(JA)) + // 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().embedBitcodeEnabled() && isa<CompileJobAction>(JA)) CmdArgs.push_back("-disable-llvm-passes"); if (Output.getType() == types::TY_Dependencies) { @@ -5540,6 +6037,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(I->getFilename()); } + bool WholeProgramVTables = + Args.hasFlag(options::OPT_fwhole_program_vtables, + options::OPT_fno_whole_program_vtables, false); + if (WholeProgramVTables) { + if (!D.isUsingLTO()) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-fwhole-program-vtables" + << "-flto"; + CmdArgs.push_back("-fwhole-program-vtables"); + } + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && @@ -5548,6 +6056,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); C.addCommand(llvm::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(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec, + CmdArgs, Inputs)); } else { C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -5555,7 +6069,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle the debug info splitting at object creation time if we're // creating an object. // TODO: Currently only works on linux with newer objcopy. - if (SplitDwarf && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) + if (SplitDwarf && Output.getType() == types::TY_Object) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut); if (Arg *A = Args.getLastArg(options::OPT_pg)) @@ -5711,10 +6225,9 @@ static bool maybeConsumeDash(const std::string &EH, size_t &I) { namespace { struct EHFlags { - EHFlags() : Synch(false), Asynch(false), NoExceptC(false) {} - bool Synch; - bool Asynch; - bool NoExceptC; + bool Synch = false; + bool Asynch = false; + bool NoUnwindC = false; }; } // end anonymous namespace @@ -5723,8 +6236,7 @@ struct EHFlags { /// - 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 noexcept. This -/// modifier is an optimization, so we ignore it for now. +/// - 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; @@ -5736,12 +6248,16 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { switch (EHVal[I]) { case 'a': EH.Asynch = maybeConsumeDash(EHVal, I); + if (EH.Asynch) + EH.Synch = false; continue; case 'c': - EH.NoExceptC = maybeConsumeDash(EHVal, I); + EH.NoUnwindC = maybeConsumeDash(EHVal, I); continue; case 's': EH.Synch = maybeConsumeDash(EHVal, I); + if (EH.Synch) + EH.Asynch = false; continue; default: break; @@ -5750,12 +6266,21 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { 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, ArgStringList &CmdArgs, - enum CodeGenOptions::DebugInfoKind *DebugInfoKind, +void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, + ArgStringList &CmdArgs, + codegenoptions::DebugInfoKind *DebugInfoKind, bool *EmitCodeView) const { unsigned RTOptionID = options::OPT__SLASH_MT; @@ -5786,11 +6311,13 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs, 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: @@ -5819,23 +6346,36 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs, /*default=*/false)) CmdArgs.push_back("-fno-rtti-data"); - // Emit CodeView if -Z7 is present. - *EmitCodeView = Args.hasArg(options::OPT__SLASH_Z7); - bool EmitDwarf = Args.hasArg(options::OPT_gdwarf); - // If we are emitting CV but not DWARF, don't build information that LLVM - // can't yet process. - if (*EmitCodeView && !EmitDwarf) - *DebugInfoKind = CodeGenOptions::DebugLineTablesOnly; - if (*EmitCodeView) + // 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 or -Zd are present. + if (Arg *DebugInfoArg = + Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd)) { + *EmitCodeView = true; + if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) + *DebugInfoKind = codegenoptions::LimitedDebugInfo; + else + *DebugInfoKind = codegenoptions::DebugLineTablesOnly; CmdArgs.push_back("-gcodeview"); + } else { + *EmitCodeView = false; + } const Driver &D = getToolChain().getDriver(); EHFlags EH = parseClangCLEHFlags(D, Args); - // FIXME: Do something with NoExceptC. if (EH.Synch || EH.Asynch) { - CmdArgs.push_back("-fcxx-exceptions"); + 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)) { @@ -5882,6 +6422,15 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back("-fms-memptr-rep=virtual"); } + if (Args.getLastArg(options::OPT__SLASH_Gd)) + CmdArgs.push_back("-fdefault-calling-conv=cdecl"); + else if (Args.getLastArg(options::OPT__SLASH_Gr)) + CmdArgs.push_back("-fdefault-calling-conv=fastcall"); + else if (Args.getLastArg(options::OPT__SLASH_Gz)) + CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + else if (Args.getLastArg(options::OPT__SLASH_Gv)) + CmdArgs.push_back("-fdefault-calling-conv=vectorcall"); + if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ)) A->render(Args, CmdArgs); @@ -5975,24 +6524,28 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // 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) { - 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(); - RenderDebugEnablingArgs(Args, CmdArgs, - (WantDebug ? CodeGenOptions::LimitedDebugInfo - : CodeGenOptions::NoDebugInfo), - DwarfVersion, llvm::DebuggerKind::Default); - + // 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); @@ -6004,6 +6557,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // And pass along -I options Args.AddAllArgs(CmdArgs, options::OPT_I); } + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, + llvm::DebuggerKind::Default); // Handle -fPIC et al -- the relocation-model affects the assembler // for some targets. @@ -6203,7 +6758,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, } } - const std::string customGCCName = D.getCCCGenericGCCName(); + const std::string &customGCCName = D.getCCCGenericGCCName(); const char *GCCName; if (!customGCCName.empty()) GCCName = customGCCName.c_str(); @@ -6528,6 +7083,7 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + CmdArgs.push_back("-shared"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), @@ -6551,7 +7107,10 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const char *Linker = Args.MakeArgString(getToolChain().GetLinkerPath()); + + const ToolChain &ToolChain = getToolChain(); + const Driver &D = ToolChain.getDriver(); + const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); ArgStringList CmdArgs; CmdArgs.push_back("-flavor"); CmdArgs.push_back("ld"); @@ -6563,9 +7122,48 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (areOptimizationsEnabled(Args)) CmdArgs.push_back("--gc-sections"); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("--strip-all"); + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-shared"); + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-Bstatic"); + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("rcrt1.o"))); + else if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); + else + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + } + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX()) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); + + 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("crtn.o"))); + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); } @@ -6684,6 +7282,14 @@ mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { .Default(NanLegacy); } +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)); @@ -6709,10 +7315,21 @@ bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { 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.getVendor() != llvm::Triple::MipsTechnologies && + !Triple.isAndroid()) return false; if (ABIName != "32") @@ -6842,6 +7459,12 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, // CloudABI only supports static linkage. CmdArgs.push_back("-Bstatic"); + + // CloudABI uses Position Independent Executables exclusively. + CmdArgs.push_back("-pie"); + CmdArgs.push_back("--no-dynamic-linker"); + CmdArgs.push_back("-zrelro"); + CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("--gc-sections"); @@ -6982,12 +7605,9 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, const Driver &D = getToolChain().getDriver(); const toolchains::MachO &MachOTC = getMachOToolChain(); - unsigned Version[3] = {0, 0, 0}; + unsigned Version[5] = {0, 0, 0, 0, 0}; if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { - bool HadExtra; - if (!Driver::GetReleaseVersion(A->getValue(), Version[0], Version[1], - Version[2], HadExtra) || - HadExtra) + if (!Driver::GetReleaseVersion(A->getValue(), Version)) D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); } @@ -7121,6 +7741,15 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, else CmdArgs.push_back("-no_pie"); } + // for embed-bitcode, use -bitcode_bundle in linker command + if (C.getDriver().embedBitcodeEnabled() || + C.getDriver().embedBitcodeMarkerOnly()) { + // Check if the toolchain supports bitcode build flow. + if (MachOTC.SupportsEmbeddedBitcode()) + CmdArgs.push_back("-bitcode_bundle"); + else + D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain); + } Args.AddLastArg(CmdArgs, options::OPT_prebind); Args.AddLastArg(CmdArgs, options::OPT_noprebind); @@ -8187,6 +8816,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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"); } @@ -8288,15 +8918,15 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crt0.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("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); } else { CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); } } @@ -8313,7 +8943,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, unsigned Major, Minor, Micro; getToolChain().getTriple().getOSVersion(Major, Minor, Micro); bool useLibgcc = true; - if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) { + if (Major >= 7 || Major == 0) { switch (getToolChain().getArch()) { case llvm::Triple::aarch64: case llvm::Triple::arm: @@ -8362,12 +8992,12 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); else CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } @@ -8472,12 +9102,12 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_march_EQ); // FIXME: remove krait check when GNU tools support krait cpu - // for now replace it with -march=armv7-a to avoid a lower + // for now replace it with -mcpu=cortex-a15 to avoid a lower // march from being picked in the absence of a cpu flag. Arg *A; if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && StringRef(A->getValue()).lower() == "krait") - CmdArgs.push_back("-march=armv7-a"); + CmdArgs.push_back("-mcpu=cortex-a15"); else Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); @@ -8599,6 +9229,7 @@ static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { bool isAndroid = Triple.isAndroid(); bool isCygMing = Triple.isOSCygMing(); + bool IsIAMCU = Triple.isOSIAMCU(); bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || Args.hasArg(options::OPT_static); if (!D.CCCIsCXX()) @@ -8615,7 +9246,7 @@ static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, CmdArgs.push_back("--no-as-needed"); } - if (StaticLibgcc && !isAndroid) + if (StaticLibgcc && !isAndroid && !IsIAMCU) CmdArgs.push_back("-lgcc_eh"); else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); @@ -8629,72 +9260,6 @@ static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, CmdArgs.push_back("-ldl"); } -static std::string getLinuxDynamicLinker(const ArgList &Args, - const toolchains::Linux &ToolChain) { - const llvm::Triple::ArchType Arch = ToolChain.getArch(); - - if (ToolChain.getTriple().isAndroid()) { - if (ToolChain.getTriple().isArch64Bit()) - return "/system/bin/linker64"; - else - return "/system/bin/linker"; - } else if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::sparc || - Arch == llvm::Triple::sparcel) - return "/lib/ld-linux.so.2"; - else if (Arch == llvm::Triple::aarch64) - return "/lib/ld-linux-aarch64.so.1"; - else if (Arch == llvm::Triple::aarch64_be) - return "/lib/ld-linux-aarch64_be.so.1"; - else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) { - if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF || - arm::getARMFloatABI(ToolChain, Args) == arm::FloatABI::Hard) - return "/lib/ld-linux-armhf.so.3"; - else - return "/lib/ld-linux.so.3"; - } else if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) { - // TODO: check which dynamic linker name. - if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF || - arm::getARMFloatABI(ToolChain, Args) == arm::FloatABI::Hard) - return "/lib/ld-linux-armhf.so.3"; - else - return "/lib/ld-linux.so.3"; - } else if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el) { - std::string LibDir = - "/lib" + mips::getMipsABILibSuffix(Args, ToolChain.getTriple()); - StringRef LibName; - bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple()); - if (mips::isUCLibc(Args)) - LibName = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0"; - else if (!ToolChain.getTriple().hasEnvironment()) { - bool LE = (ToolChain.getTriple().getArch() == llvm::Triple::mipsel) || - (ToolChain.getTriple().getArch() == llvm::Triple::mips64el); - LibName = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1"; - } else - LibName = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1"; - - return (LibDir + "/" + LibName).str(); - } else if (Arch == llvm::Triple::ppc) - return "/lib/ld.so.1"; - else if (Arch == llvm::Triple::ppc64) { - if (ppc::hasPPCAbiArg(Args, "elfv2")) - return "/lib64/ld64.so.2"; - return "/lib64/ld64.so.1"; - } else if (Arch == llvm::Triple::ppc64le) { - if (ppc::hasPPCAbiArg(Args, "elfv1")) - return "/lib64/ld64.so.1"; - return "/lib64/ld64.so.2"; - } else if (Arch == llvm::Triple::systemz) - return "/lib/ld64.so.1"; - else if (Arch == llvm::Triple::sparcv9) - return "/lib64/ld-linux.so.2"; - else if (Arch == llvm::Triple::x86_64 && - ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32) - return "/libx32/ld-linux-x32.so.2"; - else - return "/lib64/ld-linux-x86-64.so.2"; -} - static void AddRunTimeLibs(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { // Make use of compiler-rt if --rtlib option is used @@ -8712,7 +9277,16 @@ static void AddRunTimeLibs(const ToolChain &TC, const Driver &D, } break; case ToolChain::RLT_Libgcc: - AddLibgcc(TC.getTriple(), D, CmdArgs, Args); + // 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.getTriple(), D, CmdArgs, Args); break; } } @@ -8720,6 +9294,8 @@ static void AddRunTimeLibs(const ToolChain &TC, const Driver &D, 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"; @@ -8730,7 +9306,7 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "armelf_linux_eabi"; case llvm::Triple::armeb: case llvm::Triple::thumbeb: - return "armebelf_linux_eabi"; /* TODO: check which NAME. */ + return "armelfb_linux_eabi"; case llvm::Triple::ppc: return "elf32ppclinux"; case llvm::Triple::ppc64: @@ -8779,6 +9355,7 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool isAndroid = ToolChain.getTriple().isAndroid(); + const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); @@ -8839,20 +9416,23 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-shared"); } - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || - Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb || - (!Args.hasArg(options::OPT_static) && - !Args.hasArg(options::OPT_shared))) { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back(Args.MakeArgString( - D.DyldPrefix + getLinuxDynamicLinker(Args, ToolChain))); + if (!Args.hasArg(options::OPT_static)) { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (!Args.hasArg(options::OPT_shared)) { + 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) { + if (!isAndroid && !IsIAMCU) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) @@ -8868,18 +9448,22 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); } - const char *crtbegin; - if (Args.hasArg(options::OPT_static)) - crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared)) - crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; - else if (IsPIE) - crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; - else - crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; + if (IsIAMCU) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + else { + const char *crtbegin; + if (Args.hasArg(options::OPT_static)) + crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared)) + crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; + else if (IsPIE) + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; + else + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; - if (HasCRTBeginEndFiles) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + if (HasCRTBeginEndFiles) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } // Add crtfastmath.o if available and fast math is enabled. ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); @@ -8897,6 +9481,7 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -8923,6 +9508,9 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + if (NeedsXRayDeps) + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); + bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); @@ -8958,15 +9546,29 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (WantPthread && !isAndroid) CmdArgs.push_back("-lpthread"); + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("--wrap=pthread_create"); + CmdArgs.push_back("-lc"); + // Add IAMCU specific libs, if needed. + if (IsIAMCU) + CmdArgs.push_back("-lgloss"); + if (Args.hasArg(options::OPT_static)) 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)) { + if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) { const char *crtend; if (Args.hasArg(options::OPT_shared)) crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; @@ -9457,9 +10059,14 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, WindowsSdkLibPath.c_str())); } + 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)) + if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7, + options::OPT__SLASH_Zd)) CmdArgs.push_back("-debug"); bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, @@ -9512,6 +10119,12 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // 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()) { @@ -9620,6 +10233,11 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( 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 @@ -9643,6 +10261,8 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( // 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); @@ -9651,6 +10271,10 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) A->render(Args, CmdArgs); + // 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]; @@ -10135,12 +10759,12 @@ void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, } 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")); + // 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")); } } @@ -10168,7 +10792,6 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-S"); CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. } - CmdArgs.push_back("-mcpu=myriad2"); CmdArgs.push_back("-DMYRIAD2"); // Append all -I, -iquote, -isystem paths, defines/undefines, @@ -10178,7 +10801,8 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, 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_O_Group, options::OPT_W_Group, + options::OPT_mcpu_EQ}); // 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' @@ -10218,7 +10842,10 @@ void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.getType() == types::TY_Object); CmdArgs.push_back("-no6thSlotCompression"); - CmdArgs.push_back("-cv:myriad2"); // Chip Version + 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); @@ -10332,7 +10959,7 @@ void PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Input.getFilename()); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ps4-as")); + Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -10400,7 +11027,7 @@ static void ConstructPS4LinkJob(const Tool &T, Compilation &C, CmdArgs.push_back("-lpthread"); } - const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); } @@ -10573,9 +11200,9 @@ static void ConstructGoldLinkJob(const Tool &T, Compilation &C, const char *Exec = #ifdef LLVM_ON_WIN32 - Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld.gold")); + Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); #else - Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld")); + Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); #endif C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); @@ -10609,3 +11236,120 @@ void PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, else ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); } + +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"); + + // Obtain architecture from the action. + CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch()); + 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"); + if (Args.hasFlag(options::OPT_cuda_noopt_device_debug, + options::OPT_no_cuda_noopt_device_debug, false)) { + // 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"); + } + + CmdArgs.push_back("--gpu-name"); + CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); + CmdArgs.push_back("--output-file"); + CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); + 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)); + + const char *Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// 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; + 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())); + + 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); + + // 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(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index 2b137f4a6d0b..02bdb8e5e2d2 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -10,11 +10,11 @@ #ifndef LLVM_CLANG_LIB_DRIVER_TOOLS_H #define LLVM_CLANG_LIB_DRIVER_TOOLS_H +#include "clang/Basic/DebugInfoOptions.h" #include "clang/Basic/VersionTuple.h" #include "clang/Driver/Tool.h" #include "clang/Driver/Types.h" #include "clang/Driver/Util.h" -#include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" #include "llvm/Support/Compiler.h" @@ -57,8 +57,7 @@ private: const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, - const InputInfoList &Inputs, - const ToolChain *AuxToolChain) const; + const InputInfoList &Inputs) const; void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; @@ -82,6 +81,8 @@ private: 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; @@ -91,9 +92,9 @@ private: llvm::opt::ArgStringList &cmdArgs, RewriteKind rewrite) const; - void AddClangCLArgs(const llvm::opt::ArgList &Args, + void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType, llvm::opt::ArgStringList &CmdArgs, - enum CodeGenOptions::DebugInfoKind *DebugInfoKind, + codegenoptions::DebugInfoKind *DebugInfoKind, bool *EmitCodeView) const; visualstudio::Compiler *getCLFallback() const; @@ -289,6 +290,7 @@ enum class FloatABI { }; NanEncoding getSupportedNanEncoding(StringRef &CPU); +bool hasCompactBranches(StringRef &CPU); void getMipsCPUAndABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, StringRef &CPUName, StringRef &ABIName); @@ -297,6 +299,7 @@ std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, 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, @@ -680,7 +683,8 @@ public: /// Visual studio tools. namespace visualstudio { -VersionTuple getMSVCVersion(const Driver *D, const llvm::Triple &Triple, +VersionTuple getMSVCVersion(const Driver *D, const ToolChain &TC, + const llvm::Triple &Triple, const llvm::opt::ArgList &Args, bool IsWindowsMSVC); class LLVM_LIBRARY_VISIBILITY Linker : public Tool { @@ -773,6 +777,16 @@ enum class FloatABI { FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); } // end namespace ppc +namespace sparc { +enum class FloatABI { + Invalid, + Soft, + Hard, +}; + +FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args); +} // end namespace sparc + namespace XCore { // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and // Compile. @@ -903,6 +917,41 @@ public: }; } // end namespace PS4cpu +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; +}; + +} // end namespace NVPTX + } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Driver/Types.cpp b/contrib/llvm/tools/clang/lib/Driver/Types.cpp index c29ce9462a07..f8e1e40dc6bf 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Types.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Types.cpp @@ -204,6 +204,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("pcm", TY_ModuleFile) .Case("pch", TY_PCH) .Case("gch", TY_PCH) + .Case("rs", TY_RenderScript) .Default(TY_INVALID); } @@ -232,8 +233,7 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { P.push_back(phases::Compile); P.push_back(phases::Backend); } - if (Id != TY_CUDA_DEVICE) - P.push_back(phases::Assemble); + P.push_back(phases::Assemble); } } @@ -242,7 +242,6 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { } assert(0 < P.size() && "Not enough phases in list"); assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list"); - return; } ID types::lookupCXXTypeForCType(ID Id) { |