diff options
Diffstat (limited to 'lib/Driver/Driver.cpp')
-rw-r--r-- | lib/Driver/Driver.cpp | 215 |
1 files changed, 145 insertions, 70 deletions
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index a784e218f139..396ddf4dd816 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1,9 +1,8 @@ //===--- Driver.cpp - Clang GCC Compatible Driver -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -39,6 +38,7 @@ #include "ToolChains/NetBSD.h" #include "ToolChains/OpenBSD.h" #include "ToolChains/PS4CPU.h" +#include "ToolChains/PPCLinux.h" #include "ToolChains/RISCVToolchain.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" @@ -90,6 +90,33 @@ using namespace clang::driver; using namespace clang; using namespace llvm::opt; +// static +std::string Driver::GetResourcesPath(StringRef BinaryPath, + StringRef CustomResourceDir) { + // Since the resource directory is embedded in the module hash, it's important + // that all places that need it call this function, so that they get the + // exact same string ("a/../b/" and "b/" get different hashes, for example). + + // Dir is bin/ or lib/, depending on where BinaryPath is. + std::string Dir = llvm::sys::path::parent_path(BinaryPath); + + SmallString<128> P(Dir); + if (CustomResourceDir != "") { + llvm::sys::path::append(P, CustomResourceDir); + } else { + // On Windows, libclang.dll is in bin/. + // On non-Windows, libclang.so/.dylib is in lib/. + // With a static-library build of libclang, LibClangPath will contain the + // path of the embedding binary, which for LLVM binaries will be in bin/. + // ../lib gets us to lib/ in both cases. + P = llvm::sys::path::parent_path(Dir); + llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang", + CLANG_VERSION_STRING); + } + + return P.str(); +} + Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) @@ -106,7 +133,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, // Provide a sane fallback if no VFS is specified. if (!this->VFS) - this->VFS = llvm::vfs::getRealFileSystem(); + this->VFS = llvm::vfs::createPhysicalFileSystem().release(); Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); @@ -120,17 +147,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, #endif // Compute the path to the resource directory. - StringRef ClangResourceDir(CLANG_RESOURCE_DIR); - SmallString<128> P(Dir); - if (ClangResourceDir != "") { - llvm::sys::path::append(P, ClangResourceDir); - } else { - StringRef ClangLibdirSuffix(CLANG_LIBDIR_SUFFIX); - P = llvm::sys::path::parent_path(Dir); - llvm::sys::path::append(P, Twine("lib") + ClangLibdirSuffix, "clang", - CLANG_VERSION_STRING); - } - ResourceDir = P.str(); + ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); } void Driver::ParseDriverMode(StringRef ProgramName, @@ -230,8 +247,9 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, : diag::err_drv_unknown_argument; Diags.Report(DiagID) << ArgString; } else { - DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl_with_suggestion - : diag::err_drv_unknown_argument_with_suggestion; + DiagID = IsCLMode() + ? diag::warn_drv_unknown_argument_clang_cl_with_suggestion + : diag::err_drv_unknown_argument_with_suggestion; Diags.Report(DiagID) << ArgString << Nearest; } ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) > @@ -262,11 +280,13 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || + (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || (PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || + (PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { @@ -946,6 +966,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions) : std::move(*CLOptions)); + // The args for config files or /clang: flags belong to different InputArgList + // objects than Args. This copies an Arg from one of those other InputArgLists + // to the ownership of Args. auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) { unsigned Index = Args.MakeIndex(Opt->getSpelling()); Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(), @@ -987,6 +1010,11 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } } + // Check for working directory option before accessing any files + if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) + if (VFS->setCurrentWorkingDirectory(WD->getValue())) + Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); + // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintPhases; @@ -1401,11 +1429,13 @@ void Driver::generateCompilationDiagnostics( } void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) { - // Since commandLineFitsWithinSystemLimits() may underestimate system's capacity - // if the tool does not support response files, there is a chance/ that things - // will just work without a response file, so we silently just skip it. + // Since commandLineFitsWithinSystemLimits() may underestimate system's + // capacity if the tool does not support response files, there is a chance/ + // that things will just work without a response file, so we silently just + // skip it. if (Cmd.getCreator().getResponseFilesSupport() == Tool::RF_None || - llvm::sys::commandLineFitsWithinSystemLimits(Cmd.getExecutable(), Cmd.getArguments())) + llvm::sys::commandLineFitsWithinSystemLimits(Cmd.getExecutable(), + Cmd.getArguments())) return; std::string TmpName = GetTemporaryPath("response", "txt"); @@ -1559,8 +1589,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // We want to show cc1-only options only when clang is invoked with -cc1 or // -Xclang. - if (std::find(Flags.begin(), Flags.end(), "-Xclang") != Flags.end() || - std::find(Flags.begin(), Flags.end(), "-cc1") != Flags.end()) + if (llvm::is_contained(Flags, "-Xclang") || llvm::is_contained(Flags, "-cc1")) DisableFlags &= ~options::NoDriverOption; StringRef Cur; @@ -1625,11 +1654,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { if (C.getArgs().hasArg(options::OPT_dumpversion)) { // Since -dumpversion is only implemented for pedantic GCC compatibility, we // return an answer which matches our definition of __VERSION__. - // - // If we want to return a more correct answer some day, then we should - // introduce a non-pedantically GCC compatible mode to Clang in which we - // provide sensible definitions for -dumpversion, __VERSION__, etc. - llvm::outs() << "4.2.1\n"; + llvm::outs() << CLANG_VERSION_STRING << "\n"; return false; } @@ -1651,7 +1676,8 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } if (C.getArgs().hasArg(options::OPT_v) || - C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { + C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) || + C.getArgs().hasArg(options::OPT_print_supported_cpus)) { PrintVersion(C, llvm::errs()); SuppressMissingInputWarning = true; } @@ -1680,7 +1706,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { bool separator = false; for (const std::string &Path : TC.getProgramPaths()) { if (separator) - llvm::outs() << ':'; + llvm::outs() << llvm::sys::EnvPathSeparator; llvm::outs() << Path; separator = true; } @@ -1691,7 +1717,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { for (const std::string &Path : TC.getFilePaths()) { // Always print a separator. ResourceDir was the first item shown. - llvm::outs() << ':'; + llvm::outs() << llvm::sys::EnvPathSeparator; // Interpretation of leading '=' is needed only for NetBSD. if (Path[0] == '=') llvm::outs() << sysroot << Path.substr(1); @@ -1960,31 +1986,20 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, } } -/// 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, types::ID Ty) { - if (!D.getCheckInputsExist()) +bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, + types::ID Ty, bool TypoCorrect) const { + if (!getCheckInputsExist()) return true; // stdin always exists. if (Value == "-") return true; - SmallString<64> Path(Value); - if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) { - if (!llvm::sys::path::is_absolute(Path)) { - SmallString<64> Directory(WorkDir->getValue()); - llvm::sys::path::append(Directory, Value); - Path.assign(Directory); - } - } - - if (D.getVFS().exists(Path)) + if (getVFS().exists(Value)) return true; - if (D.IsCLMode()) { - if (!llvm::sys::path::is_absolute(Twine(Path)) && + if (IsCLMode()) { + if (!llvm::sys::path::is_absolute(Twine(Value)) && llvm::sys::Process::FindInEnvPath("LIB", Value)) return true; @@ -1996,7 +2011,26 @@ static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args, } } - D.Diag(clang::diag::err_drv_no_such_file) << Path; + if (TypoCorrect) { + // Check if the filename is a typo for an option flag. OptTable thinks + // that all args that are not known options and that start with / are + // filenames, but e.g. `/diagnostic:caret` is more likely a typo for + // the option `/diagnostics:caret` than a reference to a file in the root + // directory. + unsigned IncludedFlagsBitmask; + unsigned ExcludedFlagsBitmask; + std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = + getIncludeExcludeOptionFlagMasks(IsCLMode()); + std::string Nearest; + if (getOpts().findNearest(Value, Nearest, IncludedFlagsBitmask, + ExcludedFlagsBitmask) <= 1) { + Diag(clang::diag::err_drv_no_such_file_with_suggestion) + << Value << Nearest; + return false; + } + } + + Diag(clang::diag::err_drv_no_such_file) << Value; return false; } @@ -2019,7 +2053,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Arg *Previous = nullptr; bool ShowNote = false; - for (Arg *A : Args.filtered(options::OPT__SLASH_TC, options::OPT__SLASH_TP)) { + for (Arg *A : + Args.filtered(options::OPT__SLASH_TC, options::OPT__SLASH_TP)) { if (Previous) { Diag(clang::diag::warn_drv_overriding_flag_option) << Previous->getSpelling() << A->getSpelling(); @@ -2084,6 +2119,12 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Diag(clang::diag::warn_drv_treating_input_as_cxx) << getTypeName(OldTy) << getTypeName(Ty); } + + // If running with -fthinlto-index=, extensions that normally identify + // native object files actually identify LLVM bitcode files. + if (Args.hasArgNoClaim(options::OPT_fthinlto_index_EQ) && + Ty == types::TY_Object) + Ty = types::TY_LLVM_BC; } // -ObjC and -ObjC++ override the default language, but only for "source @@ -2112,19 +2153,21 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } - if (DiagnoseInputExistence(*this, Args, Value, Ty)) + if (DiagnoseInputExistence(Args, Value, Ty, /*TypoCorrect=*/true)) Inputs.push_back(std::make_pair(Ty, A)); } else if (A->getOption().matches(options::OPT__SLASH_Tc)) { StringRef Value = A->getValue(); - if (DiagnoseInputExistence(*this, Args, Value, types::TY_C)) { + if (DiagnoseInputExistence(Args, Value, types::TY_C, + /*TypoCorrect=*/false)) { Arg *InputArg = MakeInputArg(Args, *Opts, A->getValue()); Inputs.push_back(std::make_pair(types::TY_C, InputArg)); } A->claim(); } else if (A->getOption().matches(options::OPT__SLASH_Tp)) { StringRef Value = A->getValue(); - if (DiagnoseInputExistence(*this, Args, Value, types::TY_CXX)) { + if (DiagnoseInputExistence(Args, Value, types::TY_CXX, + /*TypoCorrect=*/false)) { Arg *InputArg = MakeInputArg(Args, *Opts, A->getValue()); Inputs.push_back(std::make_pair(types::TY_CXX, InputArg)); } @@ -2146,7 +2189,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Diag(clang::diag::err_drv_unknown_language) << A->getValue(); InputType = types::TY_Object; } - } else if (A->getOption().getID() == options::OPT__SLASH_U) { + } else if (A->getOption().getID() == options::OPT_U) { assert(A->getNumValues() == 1 && "The /U option has one value."); StringRef Val = A->getValue(0); if (Val.find_first_of("/\\") != StringRef::npos) { @@ -2278,6 +2321,9 @@ class OffloadingActionBuilder final { /// Flag that is set to true if this builder acted on the current input. bool IsActive = false; + + /// Flag for -fgpu-rdc. + bool Relocatable = false; public: CudaActionBuilderBase(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs, @@ -2323,6 +2369,12 @@ class OffloadingActionBuilder final { // If this is an unbundling action use it as is for each CUDA toolchain. if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { + + // If -fgpu-rdc is disabled, should not unbundle since there is no + // device code to link. + if (!Relocatable) + return ABRT_Inactive; + CudaDeviceActions.clear(); auto *IA = cast<InputAction>(UA->getInputs().back()); std::string FileName = IA->getInputArg().getAsString(Args); @@ -2394,6 +2446,9 @@ class OffloadingActionBuilder final { !C.hasOffloadToolChain<Action::OFK_HIP>()) return false; + Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, + options::OPT_fno_gpu_rdc, /*Default=*/false); + const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); assert(HostTC && "No toolchain for host compilation."); if (HostTC->getTriple().isNVPTX() || @@ -2579,13 +2634,11 @@ class OffloadingActionBuilder final { class HIPActionBuilder final : public CudaActionBuilderBase { /// The linker inputs obtained for each device arch. SmallVector<ActionList, 8> DeviceLinkerInputs; - bool Relocatable; public: HIPActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) - : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP), - Relocatable(false) {} + : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {} bool canUseBundlerUnbundler() const override { return true; } @@ -2690,13 +2743,6 @@ class OffloadingActionBuilder final { ++I; } } - - bool initialize() override { - Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, - options::OPT_fno_gpu_rdc, /*Default=*/false); - - return CudaActionBuilderBase::initialize(); - } }; /// OpenMP action builder. The host bitcode is passed to the device frontend @@ -3341,6 +3387,18 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Args.ClaimAllArgs(options::OPT_cl_compile_Group); } + // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom + // Compile phase that prints out supported cpu models and quits. + if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { + // Use the -mcpu=? flag as the dummy input to cc1. + Actions.clear(); + Action *InputAc = C.MakeAction<InputAction>(*A, types::TY_C); + Actions.push_back( + C.MakeAction<PrecompileJobAction>(InputAc, types::TY_Nothing)); + for (auto &I : Inputs) + I.second->claim(); + } + // Claim ignored clang-cl options. Args.ClaimAllArgs(options::OPT_cl_ignored_Group); @@ -3426,6 +3484,8 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); + if (Args.hasArg(options::OPT_emit_iterface_stubs)) + return C.MakeAction<CompileJobAction>(Input, types::TY_IFS); return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); } case phases::Backend: { @@ -3963,9 +4023,9 @@ InputInfo Driver::BuildJobsForActionNoCache( Input.claim(); if (Input.getOption().matches(options::OPT_INPUT)) { const char *Name = Input.getValue(); - return InputInfo(A, Name, /* BaseInput = */ Name); + return InputInfo(A, Name, /* _BaseInput = */ Name); } - return InputInfo(A, &Input, /* BaseInput = */ ""); + return InputInfo(A, &Input, /* _BaseInput = */ ""); } if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) { @@ -4244,10 +4304,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir); if (CCGenDiagnostics && A) { SmallString<128> CrashDirectory(A->getValue()); + if (!getVFS().exists(CrashDirectory)) + llvm::sys::fs::create_directories(CrashDirectory); llvm::sys::path::append(CrashDirectory, Split.first); const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%"; - std::error_code EC = - llvm::sys::fs::createUniqueFile(CrashDirectory + Middle + Suffix, TmpName); + std::error_code EC = llvm::sys::fs::createUniqueFile( + CrashDirectory + Middle + Suffix, TmpName); if (EC) { Diag(clang::diag::err_unable_to_make_temp) << EC.message(); return ""; @@ -4401,6 +4463,11 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { if (llvm::sys::fs::exists(Twine(P))) return P.str(); + SmallString<128> D(Dir); + llvm::sys::path::append(D, "..", Name); + if (llvm::sys::fs::exists(Twine(D))) + return D.str(); + if (auto P = SearchPaths(TC.getLibraryPaths())) return *P; @@ -4558,6 +4625,11 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, !Target.hasEnvironment()) TC = llvm::make_unique<toolchains::MipsLLVMToolChain>(*this, Target, Args); + else if (Target.getArch() == llvm::Triple::ppc || + Target.getArch() == llvm::Triple::ppc64 || + Target.getArch() == llvm::Triple::ppc64le) + TC = llvm::make_unique<toolchains::PPCLinuxToolChain>(*this, Target, + Args); else TC = llvm::make_unique<toolchains::Linux>(*this, Target, Args); break; @@ -4571,6 +4643,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = llvm::make_unique<toolchains::Solaris>(*this, Target, Args); break; case llvm::Triple::AMDHSA: + case llvm::Triple::AMDPAL: + case llvm::Triple::Mesa3D: TC = llvm::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args); break; case llvm::Triple::Win32: @@ -4750,7 +4824,8 @@ bool Driver::GetReleaseVersion(StringRef Str, return false; } -std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { +std::pair<unsigned, unsigned> +Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { unsigned IncludedFlagsBitmask = 0; unsigned ExcludedFlagsBitmask = options::NoDriverOption; |