diff options
Diffstat (limited to 'lib/Driver')
-rw-r--r-- | lib/Driver/Action.cpp | 16 | ||||
-rw-r--r-- | lib/Driver/Compilation.cpp | 5 | ||||
-rw-r--r-- | lib/Driver/CrossWindowsToolChain.cpp | 6 | ||||
-rw-r--r-- | lib/Driver/Driver.cpp | 367 | ||||
-rw-r--r-- | lib/Driver/DriverOptions.cpp | 2 | ||||
-rw-r--r-- | lib/Driver/Job.cpp | 32 | ||||
-rw-r--r-- | lib/Driver/MSVCToolChain.cpp | 324 | ||||
-rw-r--r-- | lib/Driver/MinGWToolChain.cpp | 16 | ||||
-rw-r--r-- | lib/Driver/Multilib.cpp | 5 | ||||
-rw-r--r-- | lib/Driver/SanitizerArgs.cpp | 67 | ||||
-rw-r--r-- | lib/Driver/ToolChain.cpp | 233 | ||||
-rw-r--r-- | lib/Driver/ToolChains.cpp | 1582 | ||||
-rw-r--r-- | lib/Driver/ToolChains.h | 342 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 3351 | ||||
-rw-r--r-- | lib/Driver/Tools.h | 919 | ||||
-rw-r--r-- | lib/Driver/Types.cpp | 13 |
16 files changed, 4935 insertions, 2345 deletions
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 3219dc1..49dccd2 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -65,13 +65,12 @@ CudaDeviceAction::CudaDeviceAction(std::unique_ptr<Action> Input, void CudaHostAction::anchor() {} CudaHostAction::CudaHostAction(std::unique_ptr<Action> Input, - const ActionList &_DeviceActions) - : Action(CudaHostClass, std::move(Input)), DeviceActions(_DeviceActions) {} + const ActionList &DeviceActions) + : Action(CudaHostClass, std::move(Input)), DeviceActions(DeviceActions) {} CudaHostAction::~CudaHostAction() { - for (iterator it = DeviceActions.begin(), ie = DeviceActions.end(); it != ie; - ++it) - delete *it; + for (auto &DA : DeviceActions) + delete DA; } void JobAction::anchor() {} @@ -153,13 +152,6 @@ VerifyJobAction::VerifyJobAction(ActionClass Kind, "ActionClass is not a valid VerifyJobAction"); } -VerifyJobAction::VerifyJobAction(ActionClass Kind, ActionList &Inputs, - types::ID Type) - : JobAction(Kind, Inputs, Type) { - assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) && - "ActionClass is not a valid VerifyJobAction"); -} - void VerifyDebugInfoJobAction::anchor() {} VerifyDebugInfoJobAction::VerifyDebugInfoJobAction( diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 101d1fc..e4af2a6 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -24,8 +24,9 @@ using namespace llvm::opt; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) - : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args), - TranslatedArgs(_TranslatedArgs), Redirects(nullptr), + : TheDriver(D), DefaultToolChain(_DefaultToolChain), + CudaHostToolChain(&DefaultToolChain), CudaDeviceToolChain(nullptr), + Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr), ForDiagnostics(false) {} Compilation::~Compilation() { diff --git a/lib/Driver/CrossWindowsToolChain.cpp b/lib/Driver/CrossWindowsToolChain.cpp index ffb1469..57bf896 100644 --- a/lib/Driver/CrossWindowsToolChain.cpp +++ b/lib/Driver/CrossWindowsToolChain.cpp @@ -107,6 +107,12 @@ AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs, } } +clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + return Res; +} + Tool *CrossWindowsToolChain::buildLinker() const { return new tools::CrossWindows::Linker(*this); } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 180c412..4f8481c 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -11,6 +11,7 @@ #include "InputInfo.h" #include "ToolChains.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" @@ -46,9 +47,11 @@ using namespace clang; using namespace llvm::opt; Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, - DiagnosticsEngine &Diags) - : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode), - SaveTemps(SaveTempsNone), ClangExecutable(ClangExecutable), + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) + : Opts(createDriverOptTable()), Diags(Diags), VFS(VFS), Mode(GCCMode), + SaveTemps(SaveTempsNone), LTOMode(LTOK_None), + ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), @@ -57,8 +60,13 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { + // Provide a sane fallback if no VFS is specified. + if (!this->VFS) + this->VFS = vfs::getRealFileSystem(); + Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); + InstalledDir = Dir; // Provide a sensible default installed dir. // Compute the path to the resource directory. StringRef ClangResourceDir(CLANG_RESOURCE_DIR); @@ -174,10 +182,8 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; - // -c and partial CUDA compilations only run up to the assembler. - } else if ((PhaseArg = DAL.getLastArg(options::OPT_c)) || - (PhaseArg = DAL.getLastArg(options::OPT_cuda_device_only)) || - (PhaseArg = DAL.getLastArg(options::OPT_cuda_host_only))) { + // -c compilation only runs up to the assembler. + } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; // Otherwise do everything. @@ -203,6 +209,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DerivedArgList *DAL = new DerivedArgList(Args); bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); + bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs); for (Arg *A : Args) { // Unfortunately, we have to parse some forwarding options (-Xassembler, // -Xlinker, -Xpreprocessor) because we either integrate their functionality @@ -217,7 +224,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_Xlinker__no_demangle)); // Add the remaining values as Xlinker arguments. - for (const StringRef Val : A->getValues()) + for (StringRef Val : A->getValues()) if (Val != "--no-demangle") DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker), Val); @@ -246,7 +253,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { StringRef Value = A->getValue(); // Rewrite unless -nostdlib is present. - if (!HasNostdlib && Value == "stdc++") { + if (!HasNostdlib && !HasNodefaultlib && Value == "stdc++") { DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_reserved_lib_stdcxx)); continue; } @@ -261,7 +268,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // Pick up inputs via the -- option. if (A->getOption().matches(options::OPT__DASH_DASH)) { A->claim(); - for (const StringRef Val : A->getValues()) + for (StringRef Val : A->getValues()) DAL->append(MakeInputArg(*DAL, Opts, Val)); continue; } @@ -327,7 +334,8 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, } // Skip further flag support on OSes which don't support '-m32' or '-m64'. - if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix) + if (Target.getArch() == llvm::Triple::tce || + Target.getOS() == llvm::Triple::Minix) return Target; // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. @@ -360,6 +368,32 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, return Target; } +// \brief Parse the LTO options and record the type of LTO compilation +// based on which -f(no-)?lto(=.*)? option occurs last. +void Driver::setLTOMode(const llvm::opt::ArgList &Args) { + LTOMode = LTOK_None; + if (!Args.hasFlag(options::OPT_flto, options::OPT_flto_EQ, + options::OPT_fno_lto, false)) + return; + + StringRef LTOName("full"); + + const Arg *A = Args.getLastArg(options::OPT_flto_EQ); + if (A) + LTOName = A->getValue(); + + LTOMode = llvm::StringSwitch<LTOKind>(LTOName) + .Case("full", LTOK_Full) + .Case("thin", LTOK_Thin) + .Default(LTOK_Unknown); + + if (LTOMode == LTOK_Unknown) { + assert(A); + Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() + << A->getValue(); + } +} + Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); @@ -387,6 +421,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { InputArgList Args = ParseArgStrings(ArgList.slice(1)); + // Silence driver warnings if requested + Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w)); + // -no-canonical-prefixes is used very early in main. Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); @@ -411,6 +448,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // clang-cl targets MSVC-style Win32. llvm::Triple T(DefaultTargetTriple); T.setOS(llvm::Triple::Win32); + T.setVendor(llvm::Triple::PC); T.setEnvironment(llvm::Triple::MSVC); DefaultTargetTriple = T.str(); } @@ -439,6 +477,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { .Default(SaveTempsCwd); } + setLTOMode(Args); + std::unique_ptr<llvm::opt::InputArgList> UArgs = llvm::make_unique<InputArgList>(std::move(Args)); @@ -452,6 +492,10 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // 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; @@ -462,10 +506,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // 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->getDefaultToolChain(), C->getArgs(), Inputs, - C->getActions()); + BuildUniversalActions(*C, C->getDefaultToolChain(), Inputs); else - BuildActions(C->getDefaultToolChain(), C->getArgs(), Inputs, + BuildActions(*C, C->getDefaultToolChain(), C->getArgs(), Inputs, C->getActions()); if (CCCPrintPhases) { @@ -578,9 +621,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C, // Darwin OSes this uses the driver-driver and builds universal actions. const ToolChain &TC = C.getDefaultToolChain(); if (TC.getTriple().isOSBinFormatMachO()) - BuildUniversalActions(TC, C.getArgs(), Inputs, C.getActions()); + BuildUniversalActions(C, TC, Inputs); else - BuildActions(TC, C.getArgs(), Inputs, C.getActions()); + BuildActions(C, TC, C.getArgs(), Inputs, C.getActions()); BuildJobs(C); @@ -761,6 +804,9 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { } else OS << "Thread model: " << TC.getThreadModel(); OS << '\n'; + + // Print out the install directory. + OS << "InstalledDir: " << InstalledDir << '\n'; } /// PrintDiagnosticCategories - Implement the --print-diagnostic-categories @@ -906,7 +952,7 @@ static unsigned PrintActions1(const Compilation &C, Action *A, os << '"' << CDA->getGpuArchName() << '"' << ", {" << PrintActions1(C, *CDA->begin(), Ids) << "}"; } else { - ActionList *AL; + const ActionList *AL; if (CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { os << "{" << PrintActions1(C, *CHA->begin(), Ids) << "}" << ", gpu binaries "; @@ -914,12 +960,15 @@ static unsigned PrintActions1(const Compilation &C, Action *A, } else AL = &A->getInputs(); - const char *Prefix = "{"; - for (Action *PreRequisite : *AL) { - os << Prefix << PrintActions1(C, PreRequisite, Ids); - Prefix = ", "; - } - os << "}"; + if (AL->size()) { + const char *Prefix = "{"; + for (Action *PreRequisite : *AL) { + os << Prefix << PrintActions1(C, PreRequisite, Ids); + Prefix = ", "; + } + os << "}"; + } else + os << "{}"; } unsigned Id = Ids.size(); @@ -945,16 +994,17 @@ static bool ContainsCompileOrAssembleAction(const Action *A) { isa<AssembleJobAction>(A)) return true; - for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it) - if (ContainsCompileOrAssembleAction(*it)) + for (const Action *Input : *A) + if (ContainsCompileOrAssembleAction(Input)) return true; return false; } -void Driver::BuildUniversalActions(const ToolChain &TC, DerivedArgList &Args, - const InputList &BAInputs, - ActionList &Actions) const { +void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, + const InputList &BAInputs) const { + DerivedArgList &Args = C.getArgs(); + ActionList &Actions = C.getActions(); llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); // Collect the list of architectures. Duplicates are allowed, but should only // be handled once (in the order seen). @@ -983,13 +1033,11 @@ void Driver::BuildUniversalActions(const ToolChain &TC, DerivedArgList &Args, Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); ActionList SingleActions; - BuildActions(TC, Args, BAInputs, SingleActions); + BuildActions(C, TC, Args, BAInputs, SingleActions); // Add in arch bindings for every top level action, as well as lipo and // dsymutil steps if needed. - for (unsigned i = 0, e = SingleActions.size(); i != e; ++i) { - Action *Act = SingleActions[i]; - + for (Action* Act : SingleActions) { // Make sure we can lipo this kind of output. If not (and it is an actual // output) then we disallow, since we can't create an output file with the // right name without overwriting it. We could remove this oddity by just @@ -1228,18 +1276,23 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } -// For each unique --cuda-gpu-arch= argument creates a TY_CUDA_DEVICE input -// action and then wraps each in CudaDeviceAction paired with appropriate GPU -// arch name. If we're only building device-side code, each action remains -// independent. Otherwise we pass device-side actions as inputs to a new -// CudaHostAction which combines both host and device side actions. +// For each unique --cuda-gpu-arch= argument creates a TY_CUDA_DEVICE +// input action and then wraps each in CudaDeviceAction paired with +// appropriate GPU arch name. In case of partial (i.e preprocessing +// only) or device-only compilation, each device action is added to /p +// Actions and /p Current is released. Otherwise the function creates +// and returns a new CudaHostAction which wraps /p Current and device +// side actions. static std::unique_ptr<Action> -buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args, - const Arg *InputArg, const types::ID InputType, - std::unique_ptr<Action> Current, ActionList &Actions) { - - assert(InputType == types::TY_CUDA && - "CUDA Actions only apply to CUDA inputs."); +buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg, + std::unique_ptr<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 std::unique_ptr<Action>( + new CudaHostAction(std::move(HostAction), {})); // Collect all cuda_gpu_arch parameters, removing duplicates. SmallVector<const char *, 4> GpuArchList; @@ -1259,20 +1312,22 @@ buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args, // Replicate inputs for each GPU architecture. Driver::InputList CudaDeviceInputs; - for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) 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; - D.BuildActions(TC, Args, CudaDeviceInputs, CudaDeviceActions); + C.getDriver().BuildActions(C, *C.getCudaDeviceToolChain(), 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 = false; - bool DeviceOnlyCompilation = Args.hasArg(options::OPT_cuda_device_only); - for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) { - if (CudaDeviceActions[i]->getKind() != Action::BackendJobClass) { + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { + if (CudaDeviceActions[I]->getKind() != Action::BackendJobClass) { PartialCompilation = true; break; } @@ -1280,6 +1335,7 @@ buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args, // 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) { // 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 @@ -1288,35 +1344,37 @@ buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args, // -o is ambiguous if we have more than one top-level action. if (Args.hasArg(options::OPT_o) && (!DeviceOnlyCompilation || GpuArchList.size() > 1)) { - D.Diag(clang::diag::err_drv_output_argument_with_multiple_files); + 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( - new CudaDeviceAction(std::unique_ptr<Action>(CudaDeviceActions[i]), - GpuArchList[i], /* AtTopLevel */ true)); + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) + Actions.push_back(new CudaDeviceAction( + std::unique_ptr<Action>(CudaDeviceActions[I]), GpuArchList[I], + /* AtTopLevel */ true)); // Kill host action in case of device-only compilation. if (DeviceOnlyCompilation) - Current.reset(nullptr); - return Current; - } else { - // Outputs of device actions during complete CUDA compilation get created - // with AtTopLevel=false and become inputs for the host action. - ActionList DeviceActions; - for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) - DeviceActions.push_back( - new CudaDeviceAction(std::unique_ptr<Action>(CudaDeviceActions[i]), - GpuArchList[i], /* AtTopLevel */ false)); - // Return a new host action that incorporates original host action and all - // device actions. - return std::unique_ptr<Action>( - new CudaHostAction(std::move(Current), DeviceActions)); - } + HostAction.reset(nullptr); + return HostAction; + } + + // Outputs of device actions during complete CUDA compilation get created + // with AtTopLevel=false and become inputs for the host action. + ActionList DeviceActions; + for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) + DeviceActions.push_back(new CudaDeviceAction( + std::unique_ptr<Action>(CudaDeviceActions[I]), GpuArchList[I], + /* AtTopLevel */ false)); + // Return a new host action that incorporates original host action and all + // device actions. + return std::unique_ptr<Action>( + new CudaHostAction(std::move(HostAction), DeviceActions)); } -void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, - const InputList &Inputs, ActionList &Actions) const { +void Driver::BuildActions(Compilation &C, const ToolChain &TC, + DerivedArgList &Args, const InputList &Inputs, + ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); if (!SuppressMissingInputWarning && Inputs.empty()) { @@ -1373,9 +1431,9 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, ActionList LinkerInputs; llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; - for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { - types::ID InputType = Inputs[i].first; - const Arg *InputArg = Inputs[i].second; + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; PL.clear(); types::getCompilationPhases(InputType, PL); @@ -1412,24 +1470,12 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, continue; } - phases::ID CudaInjectionPhase; - if (isSaveTempsEnabled()) { - // All phases are done independently, inject GPU blobs during compilation - // phase as that's where we generate glue code to init them. - CudaInjectionPhase = phases::Compile; - } else { - // Assumes that clang does everything up until linking phase, so we inject - // cuda device actions at the last step before linking. Otherwise CUDA - // host action forces preprocessor into a separate invocation. - if (FinalPhase == phases::Link) { - for (auto i = PL.begin(), e = PL.end(); i != e; ++i) { - auto next = i + 1; - if (next != e && *next == phases::Link) - CudaInjectionPhase = *i; - } - } else - CudaInjectionPhase = FinalPhase; - } + phases::ID CudaInjectionPhase = FinalPhase; + for (const auto &Phase : PL) + if (Phase <= FinalPhase && Phase == phases::Compile) { + CudaInjectionPhase = Phase; + break; + } // Build the pipeline for this file. std::unique_ptr<Action> Current(new InputAction(*InputArg, InputType)); @@ -1457,10 +1503,9 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, // Otherwise construct the appropriate action. Current = ConstructPhaseAction(TC, Args, Phase, std::move(Current)); - if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase && - !Args.hasArg(options::OPT_cuda_host_only)) { - Current = buildCudaActions(*this, TC, Args, InputArg, InputType, - std::move(Current), Actions); + if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase) { + Current = + buildCudaActions(C, Args, InputArg, std::move(Current), Actions); if (!Current) break; } @@ -1487,6 +1532,10 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, // 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. + Args.ClaimAllArgs(options::OPT_cuda_host_only); } std::unique_ptr<Action> @@ -1551,7 +1600,7 @@ Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args, types::TY_LLVM_BC); } case phases::Backend: { - if (IsUsingLTO(Args)) { + if (isUsingLTO()) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return llvm::make_unique<BackendJobAction>(std::move(Input), Output); @@ -1572,10 +1621,6 @@ Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args, llvm_unreachable("invalid phase in ConstructPhaseAction"); } -bool Driver::IsUsingLTO(const ArgList &Args) const { - return Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false); -} - void Driver::BuildJobs(Compilation &C) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); @@ -1668,10 +1713,17 @@ void Driver::BuildJobs(Compilation &C) const { } } -static const Tool *SelectToolForJob(Compilation &C, bool SaveTemps, +// 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, - const ActionList *&Inputs) { + const ActionList *&Inputs, + const CudaHostAction *&CollapsedCHA) { const Tool *ToolForJob = nullptr; + CollapsedCHA = nullptr; // 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 @@ -1688,13 +1740,19 @@ static const Tool *SelectToolForJob(Compilation &C, bool SaveTemps, // checking the backend tool, check if the tool for the CompileJob // has an integrated assembler. const ActionList *BackendInputs = &(*Inputs)[0]->getInputs(); - JobAction *CompileJA = cast<CompileJobAction>(*BackendInputs->begin()); + // 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); if (!Compiler) return nullptr; if (Compiler->hasIntegratedAssembler()) { - Inputs = &(*BackendInputs)[0]->getInputs(); + Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; + CollapsedCHA = CHA; } } @@ -1704,19 +1762,19 @@ static const Tool *SelectToolForJob(Compilation &C, bool SaveTemps, if (isa<BackendJobAction>(JA)) { // Check if the compiler supports emitting LLVM IR. assert(Inputs->size() == 1); - JobAction *CompileJA; - // Extract real host action, if it's a CudaHostAction. - if (CudaHostAction *CudaHA = dyn_cast<CudaHostAction>(*Inputs->begin())) - CompileJA = cast<CompileJobAction>(*CudaHA->begin()); - else - CompileJA = cast<CompileJobAction>(*Inputs->begin()); - + // 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); if (!Compiler) return nullptr; if (!Compiler->canEmitIR() || !SaveTemps) { - Inputs = &(*Inputs)[0]->getInputs(); + Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; + CollapsedCHA = CHA; } } @@ -1749,7 +1807,7 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, InputInfo II; // Append outputs of device jobs to the input list. for (const Action *DA : CHA->getDeviceActions()) { - BuildJobsForAction(C, DA, TC, "", AtTopLevel, + BuildJobsForAction(C, DA, TC, nullptr, AtTopLevel, /*MultipleArchs*/ false, LinkingOutput, II); CudaDeviceInputInfos.push_back(II); } @@ -1789,13 +1847,10 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, } if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { - // Figure out which NVPTX triple to use for device-side compilation based on - // whether host is 64-bit. - llvm::Triple DeviceTriple(C.getDefaultToolChain().getTriple().isArch64Bit() - ? "nvptx64-nvidia-cuda" - : "nvptx-nvidia-cuda"); - BuildJobsForAction(C, *CDA->begin(), - &getToolChain(C.getArgs(), DeviceTriple), + // Initial processing of CudaDeviceAction carries host params. + // Call BuildJobsForAction() again, now with correct device parameters. + assert(CDA->getGpuArchName() && "No GPU name in device action."); + BuildJobsForAction(C, *CDA->begin(), C.getCudaDeviceToolChain(), CDA->getGpuArchName(), CDA->isAtTopLevel(), /*MultipleArchs*/ true, LinkingOutput, Result); return; @@ -1804,10 +1859,23 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); - const Tool *T = SelectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs); + const CudaHostAction *CollapsedCHA = nullptr; + const Tool *T = + selectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs, CollapsedCHA); if (!T) return; + // If we've collapsed action list that contained CudaHostAction we + // need to build jobs for device-side inputs it may have held. + if (CollapsedCHA) { + InputInfo II; + for (const Action *DA : CollapsedCHA->getDeviceActions()) { + BuildJobsForAction(C, DA, TC, "", AtTopLevel, + /*MultipleArchs*/ false, LinkingOutput, II); + CudaDeviceInputInfos.push_back(II); + } + } + // Only use pipes when there is exactly one input. InputInfoList InputInfos; for (const Action *Input : *Inputs) { @@ -2091,6 +2159,11 @@ void Driver::generatePrefixedToolNames( // FIXME: Needs a better variable than DefaultTargetTriple Names.emplace_back(DefaultTargetTriple + "-" + Tool); Names.emplace_back(Tool); + + // Allow the discovery of tools prefixed with LLVM's default target triple. + std::string LLVMDefaultTargetTriple = llvm::sys::getDefaultTargetTriple(); + if (LLVMDefaultTargetTriple != DefaultTargetTriple) + Names.emplace_back(LLVMDefaultTargetTriple + "-" + Tool); } static bool ScanDirForExecutable(SmallString<128> &Dir, @@ -2163,6 +2236,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: TC = new toolchains::DarwinClang(*this, Target, Args); break; case llvm::Triple::DragonFly: @@ -2185,16 +2260,22 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; case llvm::Triple::Linux: if (Target.getArch() == llvm::Triple::hexagon) - TC = new toolchains::Hexagon_TC(*this, Target, Args); + TC = new toolchains::HexagonToolChain(*this, Target, Args); + else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) && + !Target.hasEnvironment()) + TC = new toolchains::MipsLLVMToolChain(*this, Target, Args); else TC = new toolchains::Linux(*this, Target, Args); break; case llvm::Triple::NaCl: - TC = new toolchains::NaCl_TC(*this, Target, Args); + TC = new toolchains::NaClToolChain(*this, Target, Args); break; case llvm::Triple::Solaris: TC = new toolchains::Solaris(*this, Target, Args); break; + case llvm::Triple::AMDHSA: + TC = new toolchains::AMDGPUToolChain(*this, Target, Args); + break; case llvm::Triple::Win32: switch (Target.getEnvironment()) { default: @@ -2220,24 +2301,36 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::CUDA: TC = new toolchains::CudaToolChain(*this, Target, Args); break; + case llvm::Triple::PS4: + TC = new toolchains::PS4CPU(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. - if (Target.getArchName() == "tce") + switch (Target.getArch()) { + case llvm::Triple::tce: TC = new toolchains::TCEToolChain(*this, Target, Args); - else if (Target.getArch() == llvm::Triple::hexagon) - TC = new toolchains::Hexagon_TC(*this, Target, Args); - else if (Target.getArch() == llvm::Triple::xcore) - TC = new toolchains::XCore(*this, Target, Args); - else if (Target.getArch() == llvm::Triple::shave) - TC = new toolchains::SHAVEToolChain(*this, Target, Args); - else if (Target.isOSBinFormatELF()) - TC = new toolchains::Generic_ELF(*this, Target, Args); - else if (Target.isOSBinFormatMachO()) - TC = new toolchains::MachO(*this, Target, Args); - else - TC = new toolchains::Generic_GCC(*this, Target, Args); - break; + break; + case llvm::Triple::hexagon: + TC = new toolchains::HexagonToolChain(*this, Target, Args); + break; + case llvm::Triple::xcore: + TC = new toolchains::XCoreToolChain(*this, Target, Args); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + TC = new toolchains::WebAssembly(*this, Target, Args); + break; + default: + if (Target.getVendor() == llvm::Triple::Myriad) + TC = new toolchains::MyriadToolChain(*this, Target, Args); + else if (Target.isOSBinFormatELF()) + TC = new toolchains::Generic_ELF(*this, Target, Args); + else if (Target.isOSBinFormatMachO()) + TC = new toolchains::MachO(*this, Target, Args); + else + TC = new toolchains::Generic_GCC(*this, Target, Args); + } } } return *TC; diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp index 6ff1cba..8d5332b 100644 --- a/lib/Driver/DriverOptions.cpp +++ b/lib/Driver/DriverOptions.cpp @@ -34,7 +34,7 @@ namespace { class DriverOptTable : public OptTable { public: DriverOptTable() - : OptTable(InfoTable, llvm::array_lengthof(InfoTable)) {} + : OptTable(InfoTable) {} }; } diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 42bba56..22904e5 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "InputInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Job.h" @@ -26,9 +27,14 @@ using llvm::StringRef; using llvm::ArrayRef; Command::Command(const Action &Source, const Tool &Creator, - const char *Executable, const ArgStringList &Arguments) + const char *Executable, const ArgStringList &Arguments, + ArrayRef<InputInfo> Inputs) : Source(Source), Creator(Creator), Executable(Executable), - Arguments(Arguments), ResponseFile(nullptr) {} + Arguments(Arguments), ResponseFile(nullptr) { + for (const auto &II : Inputs) + if (II.isFilename()) + InputFilenames.push_back(II.getFilename()); +} static int skipArgs(const char *Flag, bool HaveCrashVFS) { // These flags are all of the form -Flag <Arg> and are treated as two @@ -42,6 +48,7 @@ static int skipArgs(const char *Flag, bool HaveCrashVFS) { .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) .Default(false); @@ -98,7 +105,9 @@ void Command::writeResponseFile(raw_ostream &OS) const { return; } - // In regular response files, we send all arguments to the response file + // In regular response files, we send all arguments to the response file. + // Wrapping all arguments in double quotes ensures that both Unix tools and + // Windows tools understand the response file. for (const char *Arg : Arguments) { OS << '"'; @@ -155,13 +164,6 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name } - StringRef MainFilename; - // We'll need the argument to -main-file-name to find the input file name. - if (CrashInfo) - for (size_t I = 0, E = Args.size(); I + 1 < E; ++I) - if (StringRef(Args[I]).equals("-main-file-name")) - MainFilename = Args[I + 1]; - bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty(); for (size_t i = 0, e = Args.size(); i < e; ++i) { const char *const Arg = Args[i]; @@ -170,8 +172,11 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, if (int Skip = skipArgs(Arg, HaveCrashVFS)) { i += Skip - 1; continue; - } else if (llvm::sys::path::filename(Arg) == MainFilename && - (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) { + } + auto Found = std::find_if(InputFilenames.begin(), InputFilenames.end(), + [&Arg](StringRef IF) { return IF == Arg; }); + if (Found != InputFilenames.end() && + (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) { // Replace the input file name with the crashinfo's file name. OS << ' '; StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); @@ -254,8 +259,9 @@ int Command::Execute(const StringRef **Redirects, std::string *ErrMsg, FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, const char *Executable_, const ArgStringList &Arguments_, + ArrayRef<InputInfo> Inputs, std::unique_ptr<Command> Fallback_) - : Command(Source_, Creator_, Executable_, Arguments_), + : Command(Source_, Creator_, Executable_, Arguments_, Inputs), Fallback(std::move(Fallback_)) {} void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp index c816b29..b7e576e 100644 --- a/lib/Driver/MSVCToolChain.cpp +++ b/lib/Driver/MSVCToolChain.cpp @@ -205,27 +205,103 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, #endif // USE_WIN32 } +// Convert LLVM's ArchType +// to the corresponding name of Windows SDK libraries subfolder +static StringRef getWindowsSDKArch(llvm::Triple::ArchType Arch) { + switch (Arch) { + case llvm::Triple::x86: + return "x86"; + case llvm::Triple::x86_64: + return "x64"; + case llvm::Triple::arm: + return "arm"; + default: + return ""; + } +} + +// Find the most recent version of Universal CRT or Windows 10 SDK. +// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include +// directory by name and uses the last one of the list. +// So we compare entry names lexicographically to find the greatest one. +static bool getWindows10SDKVersion(const std::string &SDKPath, + std::string &SDKVersion) { + SDKVersion.clear(); + + std::error_code EC; + llvm::SmallString<128> IncludePath(SDKPath); + llvm::sys::path::append(IncludePath, "Include"); + for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd; + DirIt != DirEnd && !EC; DirIt.increment(EC)) { + if (!llvm::sys::fs::is_directory(DirIt->path())) + continue; + StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); + // If WDK is installed, there could be subfolders like "wdf" in the + // "Include" directory. + // Allow only directories which names start with "10.". + if (!CandidateName.startswith("10.")) + continue; + if (CandidateName > SDKVersion) + SDKVersion = CandidateName; + } + + return !SDKVersion.empty(); +} + /// \brief Get Windows SDK installation directory. -bool MSVCToolChain::getWindowsSDKDir(std::string &path, int &major, - int &minor) const { - std::string sdkVersion; +bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major, + std::string &WindowsSDKIncludeVersion, + std::string &WindowsSDKLibVersion) const { + std::string RegistrySDKVersion; // Try the Windows registry. - bool hasSDKDir = getSystemRegistryString( - "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", - "InstallationFolder", path, &sdkVersion); - if (!sdkVersion.empty()) - std::sscanf(sdkVersion.c_str(), "v%d.%d", &major, &minor); - return hasSDKDir && !path.empty(); + if (!getSystemRegistryString( + "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", Path, &RegistrySDKVersion)) + return false; + if (Path.empty() || RegistrySDKVersion.empty()) + return false; + + WindowsSDKIncludeVersion.clear(); + WindowsSDKLibVersion.clear(); + Major = 0; + std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); + if (Major <= 7) + return true; + if (Major == 8) { + // Windows SDK 8.x installs libraries in a folder whose names depend on the + // version of the OS you're targeting. By default choose the newest, which + // usually corresponds to the version of the OS you've installed the SDK on. + const char *Tests[] = {"winv6.3", "win8", "win7"}; + for (const char *Test : Tests) { + llvm::SmallString<128> TestPath(Path); + llvm::sys::path::append(TestPath, "Lib", Test); + if (llvm::sys::fs::exists(TestPath.c_str())) { + WindowsSDKLibVersion = Test; + break; + } + } + return !WindowsSDKLibVersion.empty(); + } + if (Major == 10) { + if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion)) + return false; + WindowsSDKLibVersion = WindowsSDKIncludeVersion; + return true; + } + // Unsupported SDK version + return false; } // Gets the library path required to link against the Windows SDK. bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { std::string sdkPath; int sdkMajor = 0; - int sdkMinor = 0; + std::string windowsSDKIncludeVersion; + std::string windowsSDKLibVersion; path.clear(); - if (!getWindowsSDKDir(sdkPath, sdkMajor, sdkMinor)) + if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion, + windowsSDKLibVersion)) return false; llvm::SmallString<128> libPath(sdkPath); @@ -245,44 +321,57 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { return false; } } else { - // Windows SDK 8.x installs libraries in a folder whose names depend on the - // version of the OS you're targeting. By default choose the newest, which - // usually corresponds to the version of the OS you've installed the SDK on. - const char *tests[] = {"winv6.3", "win8", "win7"}; - bool found = false; - for (const char *test : tests) { - llvm::SmallString<128> testPath(libPath); - llvm::sys::path::append(testPath, test); - if (llvm::sys::fs::exists(testPath.c_str())) { - libPath = testPath; - found = true; - break; - } - } - - if (!found) - return false; - - llvm::sys::path::append(libPath, "um"); - switch (getArch()) { - case llvm::Triple::x86: - llvm::sys::path::append(libPath, "x86"); - break; - case llvm::Triple::x86_64: - llvm::sys::path::append(libPath, "x64"); - break; - case llvm::Triple::arm: - llvm::sys::path::append(libPath, "arm"); - break; - default: + const StringRef archName = getWindowsSDKArch(getArch()); + if (archName.empty()) return false; - } + llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", archName); } path = libPath.str(); return true; } +// Check if the Include path of a specified version of Visual Studio contains +// specific header files. If not, they are probably shipped with Universal CRT. +bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT( + std::string &VisualStudioDir) const { + llvm::SmallString<128> TestPath(VisualStudioDir); + llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h"); + + return !llvm::sys::fs::exists(TestPath); +} + +bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path, + std::string &UCRTVersion) const { + // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry + // for the specific key "KitsRoot10". So do we. + if (!getSystemRegistryString( + "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", + Path, nullptr)) + return false; + + return getWindows10SDKVersion(Path, UCRTVersion); +} + +bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { + std::string UniversalCRTSdkPath; + std::string UCRTVersion; + + Path.clear(); + if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) + return false; + + StringRef ArchName = getWindowsSDKArch(getArch()); + if (ArchName.empty()) + return false; + + llvm::SmallString<128> LibPath(UniversalCRTSdkPath); + llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); + + Path = LibPath.str(); + return true; +} + // Get the location to use for Visual Studio binaries. The location priority // is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on // system (as reported by the registry). @@ -419,12 +508,12 @@ bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const { return false; } -void MSVCToolChain::AddSystemIncludeWithSubfolder(const ArgList &DriverArgs, - ArgStringList &CC1Args, - const std::string &folder, - const char *subfolder) const { +void MSVCToolChain::AddSystemIncludeWithSubfolder( + const ArgList &DriverArgs, ArgStringList &CC1Args, + const std::string &folder, const Twine &subfolder1, const Twine &subfolder2, + const Twine &subfolder3) const { llvm::SmallString<128> path(folder); - llvm::sys::path::append(path, subfolder); + llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3); addSystemInclude(DriverArgs, CC1Args, path); } @@ -434,9 +523,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P); + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir, + "include"); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) @@ -460,16 +548,33 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (getVisualStudioInstallDir(VSDir)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include"); + if (useUniversalCRT(VSDir)) { + std::string UniversalCRTSdkPath; + std::string UCRTVersion; + if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) { + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, + "Include", UCRTVersion, "ucrt"); + } + } + std::string WindowsSDKDir; - int major, minor; - if (getWindowsSDKDir(WindowsSDKDir, major, minor)) { + int major; + std::string windowsSDKIncludeVersion; + std::string windowsSDKLibVersion; + if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion, + windowsSDKLibVersion)) { if (major >= 8) { + // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. + // Anyway, llvm::sys::path::append is able to manage it. AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include\\shared"); + "include", windowsSDKIncludeVersion, + "shared"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include\\um"); + "include", windowsSDKIncludeVersion, + "um"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include\\winrt"); + "include", windowsSDKIncludeVersion, + "winrt"); } else { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include"); @@ -528,3 +633,112 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers() const { Res |= SanitizerKind::Address; return Res; } + +llvm::opt::DerivedArgList * +MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // /Oy and /Oy- only has an effect under X86-32. + bool SupportsForcingFramePointer = getArch() == llvm::Triple::x86; + + // The -O[12xd] flag actually expands to several flags. We must desugar the + // flags so that options embedded can be negated. For example, the '-O2' flag + // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to + // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single + // aspect of '-O2'. + // + // Note that this expansion logic only applies to the *last* of '[12xd]'. + + // First step is to search for the character we'd like to expand. + const char *ExpandChar = nullptr; + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT__SLASH_O)) + continue; + StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + const char &OptChar = *(OptStr.data() + I); + if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') + ExpandChar = OptStr.data() + I; + } + } + + // The -O flag actually takes an amalgam of other options. For example, + // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT__SLASH_O)) { + DAL->append(A); + continue; + } + + StringRef OptStr = A->getValue(); + for (size_t I = 0, E = OptStr.size(); I != E; ++I) { + const char &OptChar = *(OptStr.data() + I); + switch (OptChar) { + default: + break; + case '1': + case '2': + case 'x': + case 'd': + if (&OptChar == ExpandChar) { + if (OptChar == 'd') { + DAL->AddFlagArg(A, Opts.getOption(options::OPT_O0)); + } else { + if (OptChar == '1') { + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + } else if (OptChar == '2' || OptChar == 'x') { + DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); + } + if (SupportsForcingFramePointer) + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_fomit_frame_pointer)); + if (OptChar == '1' || OptChar == '2') + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_ffunction_sections)); + } + } + break; + case 'b': + if (I + 1 != E && isdigit(OptStr[I + 1])) + ++I; + break; + case 'g': + break; + case 'i': + if (I + 1 != E && OptStr[I + 1] == '-') { + ++I; + DAL->AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); + } else { + DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + } + break; + case 's': + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + break; + case 't': + DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); + break; + case 'y': { + bool OmitFramePointer = true; + if (I + 1 != E && OptStr[I + 1] == '-') { + OmitFramePointer = false; + ++I; + } + if (SupportsForcingFramePointer) { + if (OmitFramePointer) + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_fomit_frame_pointer)); + else + DAL->AddFlagArg( + A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); + } + break; + } + } + } + } + return DAL; +} diff --git a/lib/Driver/MinGWToolChain.cpp b/lib/Driver/MinGWToolChain.cpp index 938440b..c5287bb 100644 --- a/lib/Driver/MinGWToolChain.cpp +++ b/lib/Driver/MinGWToolChain.cpp @@ -66,23 +66,17 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); -// In Windows there aren't any standard install locations, we search -// for gcc on the PATH. In Linux the base is always /usr. -#ifdef LLVM_ON_WIN32 + // On Windows if there is no sysroot we search for gcc on the PATH. if (getDriver().SysRoot.size()) - Base = getDriver().SysRoot; + Base = getDriver().SysRoot; +#ifdef LLVM_ON_WIN32 else if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName("gcc")) Base = llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get())); - else - Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); -#else - if (getDriver().SysRoot.size()) - Base = getDriver().SysRoot; - else - Base = "/usr"; #endif + if (!Base.size()) + Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); Base += llvm::sys::path::get_separator(); findGccLibDir(); diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp index 8acda67..34ad6a7 100644 --- a/lib/Driver/Multilib.cpp +++ b/lib/Driver/Multilib.cpp @@ -260,16 +260,15 @@ bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { return false; }, Multilibs); - if (Filtered.size() == 0) { + if (Filtered.size() == 0) return false; - } else if (Filtered.size() == 1) { + if (Filtered.size() == 1) { M = Filtered[0]; return true; } // TODO: pick the "best" multlib when more than one is suitable assert(false); - return false; } diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index c3ad8ef..2fded1c 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -29,11 +29,11 @@ enum : SanitizerMask { NeedsUbsanRt = Undefined | Integer | CFI, NeedsUbsanCxxRt = Vptr | CFI, NotAllowedWithTrap = Vptr, - RequiresPIE = Memory | DataFlow, + RequiresPIE = DataFlow, NeedsUnwindTables = Address | Thread | Memory | DataFlow, SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow, RecoverableByDefault = Undefined | Integer, - Unrecoverable = Address | Unreachable | Return, + Unrecoverable = Unreachable | Return, LegacyFsanitizeRecoverMask = Undefined | Integer, NeedsLTO = CFI, TrappingSupported = @@ -90,6 +90,8 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, BlacklistFile = "tsan_blacklist.txt"; else if (Kinds & DataFlow) BlacklistFile = "dfsan_abilist.txt"; + else if (Kinds & CFI) + BlacklistFile = "cfi_blacklist.txt"; if (BlacklistFile) { clang::SmallString<64> Path(D.ResourceDir); @@ -158,11 +160,20 @@ bool SanitizerArgs::needsUbsanRt() const { return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) && !Sanitizers.has(Address) && !Sanitizers.has(Memory) && - !Sanitizers.has(Thread); + !Sanitizers.has(Thread) && + !CfiCrossDso; +} + +bool SanitizerArgs::needsCfiRt() const { + return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso; +} + +bool SanitizerArgs::needsCfiDiagRt() const { + return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso; } bool SanitizerArgs::requiresPIE() const { - return AsanZeroBaseShadow || (Sanitizers.Mask & RequiresPIE); + return NeedPIE || (Sanitizers.Mask & RequiresPIE); } bool SanitizerArgs::needsUnwindTables() const { @@ -174,13 +185,15 @@ void SanitizerArgs::clear() { RecoverableSanitizers.clear(); TrapSanitizers.clear(); BlacklistFiles.clear(); + ExtraDeps.clear(); CoverageFeatures = 0; MsanTrackOrigins = 0; MsanUseAfterDtor = false; + NeedPIE = false; AsanFieldPadding = 0; - AsanZeroBaseShadow = false; AsanSharedRuntime = false; LinkCXXRuntimes = false; + CfiCrossDso = false; } SanitizerArgs::SanitizerArgs(const ToolChain &TC, @@ -280,7 +293,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } // Check that LTO is enabled if we need it. - if ((Kinds & NeedsLTO) && !D.IsUsingLTO(Args)) { + if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } @@ -381,13 +394,16 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { Arg->claim(); std::string BLPath = Arg->getValue(); - if (llvm::sys::fs::exists(BLPath)) + if (llvm::sys::fs::exists(BLPath)) { BlacklistFiles.push_back(BLPath); - else + ExtraDeps.push_back(BLPath); + } else D.Diag(clang::diag::err_drv_no_such_file) << BLPath; + } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { Arg->claim(); BlacklistFiles.clear(); + ExtraDeps.clear(); } } // Validate blacklists format. @@ -418,8 +434,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } } - MsanUseAfterDtor = - Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor); + MsanUseAfterDtor = + Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor); + NeedPIE |= !(TC.getTriple().isOSLinux() && + TC.getTriple().getArch() == llvm::Triple::x86_64); + } + + if (AllAddedKinds & CFI) { + CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, + options::OPT_fno_sanitize_cfi_cross_dso, false); + // Without PIE, external function address may resolve to a PLT record, which + // can not be verified by the target module. + NeedPIE |= CfiCrossDso; } // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the @@ -489,10 +515,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (AllAddedKinds & Address) { AsanSharedRuntime = - Args.hasArg(options::OPT_shared_libasan) || - (TC.getTriple().getEnvironment() == llvm::Triple::Android); - AsanZeroBaseShadow = - (TC.getTriple().getEnvironment() == llvm::Triple::Android); + Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid(); + NeedPIE |= TC.getTriple().isAndroid(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { StringRef S = A->getValue(); @@ -561,6 +585,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, BlacklistOpt += BLPath; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } + for (const auto &Dep : ExtraDeps) { + SmallString<64> ExtraDepOpt("-fdepfile-entry="); + ExtraDepOpt += Dep; + CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); + } if (MsanTrackOrigins) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + @@ -569,6 +598,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanUseAfterDtor) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor")); + if (CfiCrossDso) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso")); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); @@ -599,11 +631,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, // 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=" + tools::getCompilerRT(TC, "ubsan_standalone"))); + "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone"))); if (types::isCXX(InputType)) - CmdArgs.push_back( - Args.MakeArgString("--dependent-lib=" + - tools::getCompilerRT(TC, "ubsan_standalone_cxx"))); + CmdArgs.push_back(Args.MakeArgString( + "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx"))); } } diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index d40bb95..cbbd485 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -22,8 +22,13 @@ #include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetParser.h" + using namespace clang::driver; +using namespace clang::driver::tools; using namespace clang; +using namespace llvm; using namespace llvm::opt; static llvm::opt::Arg *GetRTTIArgument(const ArgList &Args) { @@ -72,9 +77,7 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, ToolChain::~ToolChain() { } -const Driver &ToolChain::getDriver() const { - return D; -} +vfs::FileSystem &ToolChain::getVFS() const { return getDriver().getVFS(); } bool ToolChain::useIntegratedAs() const { return Args.hasFlag(options::OPT_fintegrated_as, @@ -88,6 +91,99 @@ const SanitizerArgs& ToolChain::getSanitizerArgs() const { return *SanitizerArguments.get(); } +namespace { +struct DriverSuffix { + const char *Suffix; + const char *ModeFlag; +}; + +const DriverSuffix *FindDriverSuffix(StringRef ProgName) { + // A list of known driver suffixes. Suffixes are compared against the + // program name in order. If there is a match, the frontend type is updated as + // necessary by applying the ModeFlag. + static const DriverSuffix DriverSuffixes[] = { + {"clang", nullptr}, + {"clang++", "--driver-mode=g++"}, + {"clang-c++", "--driver-mode=g++"}, + {"clang-cc", nullptr}, + {"clang-cpp", "--driver-mode=cpp"}, + {"clang-g++", "--driver-mode=g++"}, + {"clang-gcc", nullptr}, + {"clang-cl", "--driver-mode=cl"}, + {"cc", nullptr}, + {"cpp", "--driver-mode=cpp"}, + {"cl", "--driver-mode=cl"}, + {"++", "--driver-mode=g++"}, + }; + + for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) + if (ProgName.endswith(DriverSuffixes[i].Suffix)) + return &DriverSuffixes[i]; + return nullptr; +} + +/// Normalize the program name from argv[0] by stripping the file extension if +/// present and lower-casing the string on Windows. +std::string normalizeProgramName(llvm::StringRef Argv0) { + std::string ProgName = llvm::sys::path::stem(Argv0); +#ifdef LLVM_ON_WIN32 + // Transform to lowercase for case insensitive file systems. + std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); +#endif + return ProgName; +} + +const DriverSuffix *parseDriverSuffix(StringRef ProgName) { + // Try to infer frontend type and default target from the program name by + // comparing it against DriverSuffixes in order. + + // If there is a match, the function tries to identify a target as prefix. + // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target + // prefix "x86_64-linux". If such a target prefix is found, it may be + // added via -target as implicit first argument. + const DriverSuffix *DS = FindDriverSuffix(ProgName); + + if (!DS) { + // Try again after stripping any trailing version number: + // clang++3.5 -> clang++ + ProgName = ProgName.rtrim("0123456789."); + DS = FindDriverSuffix(ProgName); + } + + if (!DS) { + // Try again after stripping trailing -component. + // clang++-tot -> clang++ + ProgName = ProgName.slice(0, ProgName.rfind('-')); + DS = FindDriverSuffix(ProgName); + } + return DS; +} +} // anonymous namespace + +std::pair<std::string, std::string> +ToolChain::getTargetAndModeFromProgramName(StringRef PN) { + std::string ProgName = normalizeProgramName(PN); + const DriverSuffix *DS = parseDriverSuffix(ProgName); + if (!DS) + return std::make_pair("", ""); + std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag; + + std::string::size_type LastComponent = + ProgName.rfind('-', ProgName.size() - strlen(DS->Suffix)); + if (LastComponent == std::string::npos) + return std::make_pair("", ModeFlag); + + // Infer target from the prefix. + StringRef Prefix(ProgName); + Prefix = Prefix.slice(0, LastComponent); + std::string IgnoredError; + std::string Target; + if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { + Target = Prefix; + } + return std::make_pair(Target, ModeFlag); +} + StringRef ToolChain::getDefaultUniversalArchName() const { // In universal driver terms, the arch name accepted by -arch isn't exactly // the same as the ones that appear in the triple. Roughly speaking, this is @@ -171,9 +267,64 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { llvm_unreachable("Invalid tool kind."); } +static StringRef getArchNameForCompilerRTLib(const ToolChain &TC, + const ArgList &Args) { + const llvm::Triple &Triple = TC.getTriple(); + bool IsWindows = Triple.isOSWindows(); + + if (Triple.isWindowsMSVCEnvironment() && TC.getArch() == llvm::Triple::x86) + return "i386"; + + if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) + return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) + ? "armhf" + : "arm"; + + return TC.getArchName(); +} + +std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, + bool Shared) const { + const llvm::Triple &TT = getTriple(); + const char *Env = TT.isAndroid() ? "-android" : ""; + bool IsITANMSVCWindows = + TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment(); + + StringRef Arch = getArchNameForCompilerRTLib(*this, Args); + const char *Prefix = IsITANMSVCWindows ? "" : "lib"; + const char *Suffix = Shared ? (Triple.isOSWindows() ? ".dll" : ".so") + : (IsITANMSVCWindows ? ".lib" : ".a"); + + SmallString<128> Path(getDriver().ResourceDir); + StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS(); + llvm::sys::path::append(Path, "lib", OSLibName); + llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + + Arch + Env + Suffix); + return Path.str(); +} + +const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, + StringRef Component, + bool Shared) const { + return Args.MakeArgString(getCompilerRT(Args, Component, Shared)); +} + +bool ToolChain::needsProfileRT(const ArgList &Args) { + if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || + Args.hasArg(options::OPT_fprofile_instr_generate) || + Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage)) + return true; + + return false; +} + Tool *ToolChain::SelectTool(const JobAction &JA) const { - if (getDriver().ShouldUseClangCompiler(JA)) - return getClang(); + if (getDriver().ShouldUseClangCompiler(JA)) return getClang(); Action::ActionClass AC = JA.getKind(); if (AC == Action::AssembleJobClass && useIntegratedAs()) return getClangAs(); @@ -182,7 +333,6 @@ Tool *ToolChain::SelectTool(const JobAction &JA) const { std::string ToolChain::GetFilePath(const char *Name) const { return D.GetFilePath(Name, *this); - } std::string ToolChain::GetProgramPath(const char *Name) const { @@ -209,10 +359,9 @@ std::string ToolChain::GetLinkerPath() const { return ""; } - return GetProgramPath("ld"); + return GetProgramPath(DefaultLinker); } - types::ID ToolChain::LookupTypeForExtension(const char *Ext) const { return types::lookupTypeForExtension(Ext); } @@ -244,11 +393,13 @@ ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const { bool ToolChain::isThreadModelSupported(const StringRef Model) const { if (Model == "single") { - // FIXME: 'single' is only supported on ARM so far. + // FIXME: 'single' is only supported on ARM and WebAssembly so far. return Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::armeb || Triple.getArch() == llvm::Triple::thumb || - Triple.getArch() == llvm::Triple::thumbeb; + Triple.getArch() == llvm::Triple::thumbeb || + Triple.getArch() == llvm::Triple::wasm32 || + Triple.getArch() == llvm::Triple::wasm64; } else if (Model == "posix") return true; @@ -310,15 +461,15 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, MCPU = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) MArch = A->getValue(); - std::string CPU = Triple.isOSBinFormatMachO() - ? tools::arm::getARMCPUForMArch(MArch, Triple) - : tools::arm::getARMTargetCPU(MCPU, MArch, Triple); - StringRef Suffix = - tools::arm::getLLVMArchSuffixForARM(CPU, - tools::arm::getARMArch(MArch, Triple)); - bool ThumbDefault = Suffix.startswith("v6m") || Suffix.startswith("v7m") || - Suffix.startswith("v7em") || - (Suffix.startswith("v7") && getTriple().isOSBinFormatMachO()); + std::string CPU = + Triple.isOSBinFormatMachO() + ? tools::arm::getARMCPUForMArch(MArch, Triple).str() + : tools::arm::getARMTargetCPU(MCPU, MArch, Triple); + StringRef Suffix = + tools::arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); + bool IsMProfile = ARM::parseArchProfile(Suffix) == ARM::PK_M; + bool ThumbDefault = IsMProfile || (ARM::parseArchVersion(Suffix) == 7 && + getTriple().isOSBinFormatMachO()); // FIXME: this is invalid for WindowsCE if (getTriple().isOSWindows()) ThumbDefault = true; @@ -328,10 +479,9 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, else ArchName = "arm"; - // Assembly files should start in ARM mode. - if (InputType != types::TY_PP_Asm && - Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) - { + // Assembly files should start in ARM mode, unless arch is M-profile. + if ((InputType != types::TY_PP_Asm && Args.hasFlag(options::OPT_mthumb, + options::OPT_mno_thumb, ThumbDefault)) || IsMProfile) { if (IsBigEndian) ArchName = "thumbeb"; else @@ -344,7 +494,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, } } -std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args, +std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { return ComputeLLVMTriple(Args, InputType); } @@ -360,9 +510,16 @@ void ToolChain::addClangTargetOptions(const ArgList &DriverArgs, void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} +void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (!needsProfileRT(Args)) return; + + CmdArgs.push_back(getCompilerRTArgString(Args, "profile")); + return; +} + ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( - const ArgList &Args) const -{ + const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { StringRef Value = A->getValue(); if (Value == "compiler-rt") @@ -424,10 +581,9 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, ArrayRef<StringRef> Paths) { - for (ArrayRef<StringRef>::iterator I = Paths.begin(), E = Paths.end(); - I != E; ++I) { + for (StringRef Path : Paths) { CC1Args.push_back("-internal-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString(*I)); + CC1Args.push_back(DriverArgs.MakeArgString(Path)); } } @@ -460,6 +616,13 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, } } +void ToolChain::AddFilePathLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + for (const auto &LibPath : getFilePaths()) + if(LibPath.length() > 0) + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); +} + void ToolChain::AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-lcc_kext"); @@ -491,9 +654,15 @@ bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args, SanitizerMask ToolChain::getSupportedSanitizers() const { // Return sanitizers which don't require runtime support and are not - // platform or architecture-dependent. + // platform dependent. using namespace SanitizerKind; - return (Undefined & ~Vptr & ~Function) | CFI | CFICastStrict | - UnsignedIntegerOverflow | LocalBounds; + SanitizerMask Res = (Undefined & ~Vptr & ~Function) | (CFI & ~CFIICall) | + CFICastStrict | UnsignedIntegerOverflow | LocalBounds; + if (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64) + Res |= CFIICall; + return Res; } +void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const {} diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 15e36a1..b02430e 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1,4 +1,4 @@ -//===--- ToolChains.cpp - ToolChain Implementations -----------------------===// +//===--- ToolChains.cpp - ToolChain Implementations -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,6 +10,7 @@ #include "ToolChains.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -24,6 +25,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -65,6 +67,8 @@ bool MachO::HasNativeLLVMSupport() const { return true; } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { + if (isTargetWatchOSBased()) + return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); if (isTargetIOSBased()) return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); if (isNonFragile) @@ -74,7 +78,9 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { - if (isTargetIOSBased()) + if (isTargetWatchOSBased()) + return true; + else if (isTargetIOSBased()) return !isIPhoneOSVersionLT(3, 2); else { assert(isTargetMacOS() && "unexpected darwin target"); @@ -104,10 +110,10 @@ static const char *ArmMachOArchName(StringRef Arch) { } static const char *ArmMachOArchNameCPU(StringRef CPU) { - unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(CPU); + unsigned ArchKind = llvm::ARM::parseCPUArch(CPU); if (ArchKind == llvm::ARM::AK_INVALID) return nullptr; - StringRef Arch = llvm::ARMTargetParser::getArchName(ArchKind); + StringRef Arch = llvm::ARM::getArchName(ArchKind); // FIXME: Make sure this MachO triple mangling is really necessary. // ARMv5* normalises to ARMv5. @@ -142,7 +148,7 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const { return "arm64"; case llvm::Triple::thumb: - case llvm::Triple::arm: { + case llvm::Triple::arm: if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) if (const char *Arch = ArmMachOArchName(A->getValue())) return Arch; @@ -153,7 +159,6 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const { return "arm"; } - } } Darwin::~Darwin() {} @@ -177,7 +182,14 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, return Triple.getTriple(); SmallString<16> Str; - Str += isTargetIOSBased() ? "ios" : "macosx"; + if (isTargetWatchOSBased()) + Str += "watchos"; + else if (isTargetTvOSBased()) + Str += "tvos"; + else if (isTargetIOSBased()) + Str += "ios"; + else + Str += "macosx"; Str += getTargetVersion().getAsString(); Triple.setOSName(Str); @@ -216,16 +228,17 @@ DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple, : Darwin(D, Triple, Args) {} void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { - // For iOS, 64-bit, promote certain warnings to errors. - if (!isTargetMacOS() && getTriple().isArch64Bit()) { + // For modern targets, promote certain warnings to errors. + if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { // Always enable -Wdeprecated-objc-isa-usage and promote it // to an error. CC1Args.push_back("-Wdeprecated-objc-isa-usage"); CC1Args.push_back("-Werror=deprecated-objc-isa-usage"); - // Also error about implicit function declarations, as that - // can impact calling conventions. - CC1Args.push_back("-Werror=implicit-function-declaration"); + // For iOS and watchOS, also error about implicit function declarations, + // as that can impact calling conventions. + if (!isTargetMacOS()) + CC1Args.push_back("-Werror=implicit-function-declaration"); } } @@ -253,7 +266,15 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, llvm::sys::path::remove_filename(P); // 'bin' llvm::sys::path::append(P, "lib", "arc", "libarclite_"); // Mash in the platform. - if (isTargetIOSSimulator()) + if (isTargetWatchOSSimulator()) + P += "watchsimulator"; + else if (isTargetWatchOS()) + P += "watchos"; + else if (isTargetTvOSSimulator()) + P += "appletvsimulator"; + else if (isTargetTvOS()) + P += "appletvos"; + else if (isTargetIOSSimulator()) P += "iphonesimulator"; else if (isTargetIPhoneOS()) P += "iphoneos"; @@ -276,7 +297,7 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless // we explicitly force linking with this library). - if (AlwaysLink || llvm::sys::fs::exists(P)) + if (AlwaysLink || getVFS().exists(P)) CmdArgs.push_back(Args.MakeArgString(P)); // Adding the rpaths might negatively interact when other rpaths are involved, @@ -300,23 +321,38 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, - false) || - Args.hasArg(options::OPT_fprofile_generate) || - Args.hasArg(options::OPT_fprofile_generate_EQ) || - Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || - Args.hasArg(options::OPT_fcreate_profile) || - Args.hasArg(options::OPT_coverage))) - return; + 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 (isTargetIOSBased()) - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a", - /*AlwaysLink*/ true); - else - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a", - /*AlwaysLink*/ true); + 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, + /*AlwaysLink*/ true); + return; } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, @@ -327,6 +363,7 @@ void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, // Sanitizer runtime libraries requires C++. AddCXXStdlibLibArgs(Args, CmdArgs); } + // ASan is not supported on watchOS. assert(isTargetMacOS() || isTargetIOSSimulator()); StringRef OS = isTargetMacOS() ? "osx" : "iossim"; AddLinkRuntimeLib( @@ -374,13 +411,21 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); if (Sanitize.needsUbsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); + if (Sanitize.needsTsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. - if (isTargetIOSBased()) { + if (isTargetWatchOSBased()) { + // We currently always need a static runtime library for watchOS. + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.watchos.a"); + } else if (isTargetTvOSBased()) { + // We currently always need a static runtime library for tvOS. + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.tvos.a"); + } else if (isTargetIOSBased()) { // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, // it never went into the SDK. // Linking against libgcc_s.1 isn't needed for iOS 5.0+ @@ -425,13 +470,13 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // isysroot. if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { // Warn if the path does not exist. - if (!llvm::sys::fs::exists(A->getValue())) + if (!getVFS().exists(A->getValue())) getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); } else { if (char *env = ::getenv("SDKROOT")) { // We only use this value as the default if it is an absolute path, // exists, and it is not the root path. - if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env) && + if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && StringRef(env) != "/") { Args.append(Args.MakeSeparateArg( nullptr, Opts.getOption(options::OPT_isysroot), env)); @@ -441,25 +486,46 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); + Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ); + Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ); - if (OSXVersion && iOSVersion) { + if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) { + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << OSXVersion->getAsString(Args) + << (iOSVersion ? iOSVersion : + TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); + iOSVersion = TvOSVersion = WatchOSVersion = nullptr; + } else if (iOSVersion && (TvOSVersion || WatchOSVersion)) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << OSXVersion->getAsString(Args) << iOSVersion->getAsString(Args); - iOSVersion = nullptr; - } else if (!OSXVersion && !iOSVersion) { + << iOSVersion->getAsString(Args) + << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); + TvOSVersion = WatchOSVersion = nullptr; + } else if (TvOSVersion && WatchOSVersion) { + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << TvOSVersion->getAsString(Args) + << WatchOSVersion->getAsString(Args); + WatchOSVersion = nullptr; + } else if (!OSXVersion && !iOSVersion && !TvOSVersion && !WatchOSVersion) { // If no deployment target was specified on the command line, check for // environment defines. std::string OSXTarget; std::string iOSTarget; + std::string TvOSTarget; + std::string WatchOSTarget; + if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) OSXTarget = env; if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) iOSTarget = env; + if (char *env = ::getenv("TVOS_DEPLOYMENT_TARGET")) + TvOSTarget = env; + if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET")) + WatchOSTarget = env; // If there is no command-line argument to specify the Target version and // no environment variable defined, see if we can set the default based // on -isysroot. - if (iOSTarget.empty() && OSXTarget.empty() && + if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef isysroot = A->getValue(); @@ -479,6 +545,12 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { iOSTarget = Version; else if (SDK.startswith("MacOSX")) OSXTarget = Version; + else if (SDK.startswith("WatchOS") || + SDK.startswith("WatchSimulator")) + WatchOSTarget = Version; + else if (SDK.startswith("AppleTVOS") || + SDK.startswith("AppleTVSimulator")) + TvOSTarget = Version; } } } @@ -486,7 +558,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // If no OSX or iOS target has been specified, try to guess platform // from arch name and compute the version from the triple. - if (OSXTarget.empty() && iOSTarget.empty()) { + if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() && + WatchOSTarget.empty()) { StringRef MachOArchName = getMachOArchName(Args); unsigned Major, Minor, Micro; if (MachOArchName == "armv7" || MachOArchName == "armv7s" || @@ -494,6 +567,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { getTriple().getiOSVersion(Major, Minor, Micro); llvm::raw_string_ostream(iOSTarget) << Major << '.' << Minor << '.' << Micro; + } else if (MachOArchName == "armv7k") { + getTriple().getWatchOSVersion(Major, Minor, Micro); + llvm::raw_string_ostream(WatchOSTarget) << Major << '.' << Minor << '.' + << Micro; } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && MachOArchName != "armv7em") { if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) { @@ -505,15 +582,32 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } + // Do not allow conflicts with the watchOS target. + if (!WatchOSTarget.empty() && (!iOSTarget.empty() || !TvOSTarget.empty())) { + getDriver().Diag(diag::err_drv_conflicting_deployment_targets) + << "WATCHOS_DEPLOYMENT_TARGET" + << (!iOSTarget.empty() ? "IPHONEOS_DEPLOYMENT_TARGET" : + "TVOS_DEPLOYMENT_TARGET"); + } + + // Do not allow conflicts with the tvOS target. + if (!TvOSTarget.empty() && !iOSTarget.empty()) { + getDriver().Diag(diag::err_drv_conflicting_deployment_targets) + << "TVOS_DEPLOYMENT_TARGET" + << "IPHONEOS_DEPLOYMENT_TARGET"; + } + // Allow conflicts among OSX and iOS for historical reasons, but choose the // default platform. - if (!OSXTarget.empty() && !iOSTarget.empty()) { + if (!OSXTarget.empty() && (!iOSTarget.empty() || + !WatchOSTarget.empty() || + !TvOSTarget.empty())) { if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::thumb) OSXTarget = ""; else - iOSTarget = ""; + iOSTarget = WatchOSTarget = TvOSTarget = ""; } if (!OSXTarget.empty()) { @@ -524,6 +618,14 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget); Args.append(iOSVersion); + } else if (!TvOSTarget.empty()) { + const Option O = Opts.getOption(options::OPT_mtvos_version_min_EQ); + TvOSVersion = Args.MakeJoinedArg(nullptr, O, TvOSTarget); + Args.append(TvOSVersion); + } else if (!WatchOSTarget.empty()) { + const Option O = Opts.getOption(options::OPT_mwatchos_version_min_EQ); + WatchOSVersion = Args.MakeJoinedArg(nullptr, O, WatchOSTarget); + Args.append(WatchOSVersion); } } @@ -532,6 +634,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Platform = MacOS; else if (iOSVersion) Platform = IPhoneOS; + else if (TvOSVersion) + Platform = TvOS; + else if (WatchOSVersion) + Platform = WatchOS; else llvm_unreachable("Unable to infer Darwin variant"); @@ -539,7 +645,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { unsigned Major, Minor, Micro; bool HadExtra; if (Platform == MacOS) { - assert(!iOSVersion && "Unknown target platform!"); + assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && + "Unknown target platform!"); if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) @@ -552,6 +659,18 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << iOSVersion->getAsString(Args); + } else if (Platform == TvOS) { + if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, + Micro, HadExtra) || HadExtra || + Major >= 10 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << TvOSVersion->getAsString(Args); + } else if (Platform == WatchOS) { + if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor, + Micro, HadExtra) || HadExtra || + Major >= 10 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << WatchOSVersion->getAsString(Args); } else llvm_unreachable("unknown kind of Darwin platform"); @@ -559,6 +678,12 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) Platform = IPhoneOSSimulator; + if (TvOSVersion && (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64)) + Platform = TvOSSimulator; + if (WatchOSVersion && (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64)) + Platform = WatchOSSimulator; setTarget(Platform, Major, Minor, Micro); } @@ -572,7 +697,7 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, CmdArgs.push_back("-lc++"); break; - case ToolChain::CST_Libstdcxx: { + case ToolChain::CST_Libstdcxx: // Unfortunately, -lstdc++ doesn't always exist in the standard search path; // it was previously found in the gcc lib dir. However, for all the Darwin // platforms we care about it was -lstdc++.6, so we search for that @@ -583,10 +708,10 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, SmallString<128> P(A->getValue()); llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); - if (!llvm::sys::fs::exists(P)) { + if (!getVFS().exists(P)) { llvm::sys::path::remove_filename(P); llvm::sys::path::append(P, "libstdc++.6.dylib"); - if (llvm::sys::fs::exists(P)) { + if (getVFS().exists(P)) { CmdArgs.push_back(Args.MakeArgString(P)); return; } @@ -596,8 +721,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, // Otherwise, look in the root. // FIXME: This should be removed someday when we don't have to care about // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. - if (!llvm::sys::fs::exists("/usr/lib/libstdc++.dylib") && - llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib")) { + if (!getVFS().exists("/usr/lib/libstdc++.dylib") && + getVFS().exists("/usr/lib/libstdc++.6.dylib")) { CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); return; } @@ -606,7 +731,6 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, CmdArgs.push_back("-lstdc++"); break; } - } } void DarwinClang::AddCCKextLibArgs(const ArgList &Args, @@ -620,17 +744,19 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, llvm::sys::path::append(P, "lib", "darwin"); // Use the newer cc_kext for iOS ARM after 6.0. - if (!isTargetIPhoneOS() || isTargetIOSSimulator() || - getTriple().getArch() == llvm::Triple::aarch64 || - !isIPhoneOSVersionLT(6, 0)) { - llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); + if (isTargetWatchOS()) { + llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a"); + } else if (isTargetTvOS()) { + llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); + } else if (isTargetIPhoneOS()) { + llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); } else { - llvm::sys::path::append(P, "libclang_rt.cc_kext_ios5.a"); + llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. - if (llvm::sys::fs::exists(P)) + if (getVFS().exists(P)) CmdArgs.push_back(Args.MakeArgString(P)); } @@ -856,7 +982,7 @@ void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, // { hard-float, soft-float } llvm::SmallString<32> CompilerRT = StringRef("libclang_rt."); CompilerRT += - tools::arm::getARMFloatABI(getDriver(), Args, getTriple()) == "hard" + (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard) ? "hard" : "soft"; CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; @@ -883,8 +1009,9 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // FIXME: It would be far better to avoid inserting those -static arguments, // but we can't check the deployment target in the translation code until // it is set here. - if (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0)) { - for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie;) { + if (isTargetWatchOSBased() || + (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { + for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { Arg *A = *it; ++it; if (A->getOption().getID() != options::OPT_mkernel && @@ -900,7 +1027,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))) && + (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || + isTargetWatchOSBased()) && !Args.getLastArg(options::OPT_stdlib_EQ)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), "libc++"); @@ -933,10 +1061,14 @@ bool MachO::UseDwarfDebugFlags() const { return false; } -bool Darwin::UseSjLjExceptions() const { +bool Darwin::UseSjLjExceptions(const ArgList &Args) const { // Darwin uses SjLj exceptions on ARM. - return (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb); + if (getTriple().getArch() != llvm::Triple::arm && + getTriple().getArch() != llvm::Triple::thumb) + return false; + + // Only watchOS uses the new DWARF/Compact unwinding method. + return !isTargetWatchOS(); } bool MachO::isPICDefault() const { return true; } @@ -957,7 +1089,15 @@ void Darwin::addMinVersionArgs(const ArgList &Args, ArgStringList &CmdArgs) const { VersionTuple TargetVersion = getTargetVersion(); - if (isTargetIOSSimulator()) + if (isTargetWatchOS()) + CmdArgs.push_back("-watchos_version_min"); + else if (isTargetWatchOSSimulator()) + CmdArgs.push_back("-watchos_simulator_version_min"); + else if (isTargetTvOS()) + CmdArgs.push_back("-tvos_version_min"); + else if (isTargetTvOSSimulator()) + CmdArgs.push_back("-tvos_simulator_version_min"); + else if (isTargetIOSSimulator()) CmdArgs.push_back("-ios_simulator_version_min"); else if (isTargetIOSBased()) CmdArgs.push_back("-iphoneos_version_min"); @@ -974,7 +1114,9 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, // Derived from startfile spec. if (Args.hasArg(options::OPT_dynamiclib)) { // Derived from darwin_dylib1 spec. - if (isTargetIOSSimulator()) { + if (isTargetWatchOSBased()) { + ; // watchOS does not need dylib1.o. + } else if (isTargetIOSSimulator()) { ; // iOS simulator does not need dylib1.o. } else if (isTargetIPhoneOS()) { if (isIPhoneOSVersionLT(3, 1)) @@ -989,7 +1131,9 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, if (Args.hasArg(options::OPT_bundle)) { if (!Args.hasArg(options::OPT_static)) { // Derived from darwin_bundle1 spec. - if (isTargetIOSSimulator()) { + if (isTargetWatchOSBased()) { + ; // watchOS does not need bundle1.o. + } else if (isTargetIOSSimulator()) { ; // iOS simulator does not need bundle1.o. } else if (isTargetIPhoneOS()) { if (isIPhoneOSVersionLT(3, 1)) @@ -1024,7 +1168,9 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, CmdArgs.push_back("-lcrt0.o"); } else { // Derived from darwin_crt1 spec. - if (isTargetIOSSimulator()) { + if (isTargetWatchOSBased()) { + ; // watchOS does not need crt1.o. + } else if (isTargetIOSSimulator()) { ; // iOS simulator does not need crt1.o. } else if (isTargetIPhoneOS()) { if (getArch() == llvm::Triple::aarch64) @@ -1049,6 +1195,7 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, } if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && + !isTargetWatchOS() && isMacosxVersionLT(10, 5)) { const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); CmdArgs.push_back(Str); @@ -1058,7 +1205,8 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); } void Darwin::CheckObjCARC() const { - if (isTargetIOSBased() || (isTargetMacOS() && !isMacosxVersionLT(10, 6))) + if (isTargetIOSBased() || isTargetWatchOSBased() || + (isTargetMacOS() && !isMacosxVersionLT(10, 6))) return; getDriver().Diag(diag::err_arc_unsupported_on_toolchain); } @@ -1071,6 +1219,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const { if (!isMacosxVersionLT(10, 9)) Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Thread; } return Res; } @@ -1170,7 +1319,8 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { /// necessary because the driver doesn't store the final version of the target /// triple. void Generic_GCC::GCCInstallationDetector::init( - const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) { + const llvm::Triple &TargetTriple, const ArgList &Args, + ArrayRef<std::string> ExtraTripleAliases) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); @@ -1212,20 +1362,22 @@ void Generic_GCC::GCCInstallationDetector::init( // installation available. GCC installs are ranked by version number. Version = GCCVersion::Parse("0.0.0"); for (const std::string &Prefix : Prefixes) { - if (!llvm::sys::fs::exists(Prefix)) + if (!D.getVFS().exists(Prefix)) continue; - for (const StringRef Suffix : CandidateLibDirs) { + for (StringRef Suffix : CandidateLibDirs) { const std::string LibDir = Prefix + Suffix.str(); - if (!llvm::sys::fs::exists(LibDir)) + if (!D.getVFS().exists(LibDir)) continue; - for (const StringRef Candidate : CandidateTripleAliases) + for (StringRef Candidate : ExtraTripleAliases) // Try these first. + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); + for (StringRef Candidate : CandidateTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); } - for (const StringRef Suffix : CandidateBiarchLibDirs) { + for (StringRef Suffix : CandidateBiarchLibDirs) { const std::string LibDir = Prefix + Suffix.str(); - if (!llvm::sys::fs::exists(LibDir)) + if (!D.getVFS().exists(LibDir)) continue; - for (const StringRef Candidate : CandidateBiarchTripleAliases) + for (StringRef Candidate : CandidateBiarchTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, /*NeedsBiarchSuffix=*/ true); } @@ -1300,8 +1452,9 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "i586-linux-gnu"}; static const char *const MIPSLibDirs[] = {"/lib"}; - static const char *const MIPSTriples[] = { - "mips-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu"}; + static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", + "mips-mti-linux-gnu", + "mips-img-linux-gnu"}; static const char *const MIPSELLibDirs[] = {"/lib"}; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", "mipsel-linux-android", "mips-img-linux-gnu"}; @@ -1340,9 +1493,20 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", "s390x-redhat-linux"}; + // Solaris. + static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; + static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", + "i386-pc-solaris2.11"}; + using std::begin; using std::end; + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); + TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); + return; + } + switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); @@ -1436,6 +1600,7 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); break; case llvm::Triple::sparc: + case llvm::Triple::sparcel: LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); @@ -1451,7 +1616,6 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); break; - default: // By default, just rely on the standard lib directories and the original // triple. @@ -1467,15 +1631,83 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.push_back(BiarchTriple.str()); } +// \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; + + if (Args.hasArg(options::OPT_cuda_path_EQ)) + CudaPathCandidates.push_back( + Args.getLastArgValue(options::OPT_cuda_path_EQ)); + else { + CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); + CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.5"); + CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.0"); + } + + for (const auto &CudaPath : CudaPathCandidates) { + if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) + continue; + + CudaInstallPath = CudaPath; + CudaIncludePath = CudaInstallPath + "/include"; + CudaLibDevicePath = CudaInstallPath + "/nvvm/libdevice"; + CudaLibPath = + CudaInstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib"); + + if (!(D.getVFS().exists(CudaIncludePath) && + D.getVFS().exists(CudaLibPath) && + D.getVFS().exists(CudaLibDevicePath))) + continue; + + std::error_code EC; + for (llvm::sys::fs::directory_iterator LI(CudaLibDevicePath, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = llvm::sys::path::filename(FilePath); + // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc + const StringRef LibDeviceName = "libdevice."; + if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) + continue; + StringRef GpuArch = FileName.slice( + LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); + CudaLibDeviceMap[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; + } else if (GpuArch == "compute_30") { + CudaLibDeviceMap["sm_30"] = FilePath; + CudaLibDeviceMap["sm_32"] = FilePath; + } else if (GpuArch == "compute_35") { + CudaLibDeviceMap["sm_35"] = FilePath; + CudaLibDeviceMap["sm_37"] = FilePath; + } + } + + IsValid = true; + break; + } +} + +void Generic_GCC::CudaInstallationDetector::print(raw_ostream &OS) const { + if (isValid()) + OS << "Found CUDA installation: " << CudaInstallPath << "\n"; +} + namespace { // Filter to remove Multilibs that don't exist as a suffix to Path class FilterNonExistent { StringRef Base; + vfs::FileSystem &VFS; public: - FilterNonExistent(StringRef Base) : Base(Base) {} + FilterNonExistent(StringRef Base, vfs::FileSystem &VFS) + : Base(Base), VFS(VFS) {} bool operator()(const Multilib &M) { - return !llvm::sys::fs::exists(Base + M.gccSuffix() + "/crtbegin.o"); + return !VFS.exists(Base + M.gccSuffix() + "/crtbegin.o"); } }; } // end anonymous namespace @@ -1515,6 +1747,7 @@ static bool isMicroMips(const ArgList &Args) { return A && A->getOption().matches(options::OPT_mmicromips); } +namespace { struct DetectedMultilibs { /// The set of multilibs that the detected installation supports. MultilibSet Multilibs; @@ -1526,13 +1759,15 @@ struct DetectedMultilibs { /// targeting the non-default multilib. Otherwise, it is empty. llvm::Optional<Multilib> BiarchSibling; }; +} // end anonymous namespace static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } -static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, - const ArgList &Args, DetectedMultilibs &Result) { +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 @@ -1558,7 +1793,7 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, // /usr // /lib <= crt*.o files compiled with '-mips32' - FilterNonExistent NonExistent(Path); + FilterNonExistent NonExistent(Path, D.getVFS()); // Check for FSF toolchain multilibs MultilibSet FSFMipsMultilibs; @@ -1636,6 +1871,32 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, }); } + // Check for 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([]( + 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; { @@ -1754,7 +2015,7 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, addMultilibFlag(isMips16(Args), "mips16", Flags); addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || - CPUName == "mips32r5", + CPUName == "mips32r5" || CPUName == "p5600", "march=mips32r2", Flags); addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); @@ -1772,7 +2033,7 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); - if (TargetTriple.getEnvironment() == llvm::Triple::Android) { + if (TargetTriple.isAndroid()) { // Select Android toolchain. It's the only choice in that case. if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) { Result.Multilibs = AndroidMipsMultilibs; @@ -1781,6 +2042,16 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, return false; } + 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; + } + if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.getEnvironment() == llvm::Triple::GNU) { @@ -1823,11 +2094,11 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, return false; } -static bool findBiarchMultilibs(const llvm::Triple &TargetTriple, +static bool findBiarchMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { - // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that @@ -1855,7 +2126,7 @@ static bool findBiarchMultilibs(const llvm::Triple &TargetTriple, .flag("-m64") .flag("+mx32"); - FilterNonExistent NonExistent(Path); + FilterNonExistent NonExistent(Path, D.getVFS()); // Determine default multilib from: 32, 64, x32 // Also handle cases such as 64 on 32, 32 on 64, etc. @@ -1907,6 +2178,56 @@ static bool findBiarchMultilibs(const llvm::Triple &TargetTriple, return true; } +void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( + const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, + const std::string &LibDir, StringRef CandidateTriple, + bool NeedsBiarchSuffix) { + // Solaris is a special case. The GCC installation is under + // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we + // need to iterate twice. + std::error_code EC; + for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + + if (CandidateVersion.Major != -1) // Filter obviously bad entries. + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) + continue; // Saw this path before; no need to look at it again. + if (CandidateVersion.isOlderThan(4, 1, 1)) + continue; + if (CandidateVersion <= Version) + continue; + + GCCInstallPath = + LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); + if (!D.getVFS().exists(GCCInstallPath)) + continue; + + // If we make it here there has to be at least one GCC version, let's just + // use the latest one. + std::error_code EEC; + for (vfs::directory_iterator + LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), + LLE; + !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { + + StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); + GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); + + if (CandidateSubVersion > Version) + Version = CandidateSubVersion; + } + + GCCTriple.setTriple(CandidateTriple); + + GCCInstallPath += "/" + Version.Text; + GCCParentLibPath = GCCInstallPath + "/../../../../"; + + IsValid = true; + } +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, @@ -1914,41 +2235,48 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back - // up to the lib directory. - const std::string LibSuffixes[] = { - "/gcc/" + CandidateTriple.str(), + // up to the lib directory. Specifically, the number of "up" steps + // in the second half of each row is 1 + the number of path separators + // in the first half. + const std::string LibAndInstallSuffixes[][2] = { + {"/gcc/" + CandidateTriple.str(), "/../../.."}, + // Debian puts cross-compilers in gcc-cross - "/gcc-cross/" + CandidateTriple.str(), - "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), + {"/gcc-cross/" + CandidateTriple.str(), "/../../.."}, + + {"/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), + "/../../../.."}, // The Freescale PPC SDK has the gcc libraries in // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. - "/" + CandidateTriple.str(), + {"/" + CandidateTriple.str(), "/../.."}, // Ubuntu has a strange mis-matched pair of triples that this happens to // match. // FIXME: It may be worthwhile to generalize this and look for a second // triple. - "/i386-linux-gnu/gcc/" + CandidateTriple.str()}; - const std::string InstallSuffixes[] = { - "/../../..", // gcc/ - "/../../..", // gcc-cross/ - "/../../../..", // <triple>/gcc/ - "/../..", // <triple>/ - "/../../../.." // i386-linux-gnu/gcc/<triple>/ - }; + {"/i386-linux-gnu/gcc/" + CandidateTriple.str(), "/../../../.."}}; + + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, + NeedsBiarchSuffix); + return; + } + // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. - const unsigned NumLibSuffixes = - (llvm::array_lengthof(LibSuffixes) - (TargetArch != llvm::Triple::x86)); + const unsigned NumLibSuffixes = (llvm::array_lengthof(LibAndInstallSuffixes) - + (TargetArch != llvm::Triple::x86)); for (unsigned i = 0; i < NumLibSuffixes; ++i) { - StringRef LibSuffix = LibSuffixes[i]; + StringRef LibSuffix = LibAndInstallSuffixes[i][0]; std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE; + for (vfs::directory_iterator + LI = D.getVFS().dir_begin(LibDir + LibSuffix, EC), + LE; !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + StringRef VersionText = llvm::sys::path::filename(LI->getName()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->path()).second) + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; @@ -1960,9 +2288,9 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // Debian mips multilibs behave more like the rest of the biarch ones, // so handle them there if (isMipsArch(TargetArch)) { - if (!findMIPSMultilibs(TargetTriple, LI->path(), Args, Detected)) + if (!findMIPSMultilibs(D, TargetTriple, LI->getName(), Args, Detected)) continue; - } else if (!findBiarchMultilibs(TargetTriple, LI->path(), Args, + } else if (!findBiarchMultilibs(D, TargetTriple, LI->getName(), Args, NeedsBiarchSuffix, Detected)) { continue; } @@ -1975,8 +2303,9 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // FIXME: We hack together the directory name here instead of // using LI to ensure stable path separators across Windows and // Linux. - GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str(); - GCCParentLibPath = GCCInstallPath + InstallSuffixes[i]; + GCCInstallPath = + LibDir + LibAndInstallSuffixes[i][0] + "/" + VersionText.str(); + GCCParentLibPath = GCCInstallPath + LibAndInstallSuffixes[i][1]; IsValid = true; } } @@ -1984,7 +2313,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), GCCInstallation() { + : ToolChain(D, Triple, Args), GCCInstallation(D), CudaInstallation(D) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -2016,6 +2345,7 @@ Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { // Print the information about how we detected the GCC installation. GCCInstallation.print(OS); + CudaInstallation.print(OS); } bool Generic_GCC::IsUnwindTablesDefault() const { @@ -2047,9 +2377,6 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: case llvm::Triple::systemz: return true; default: @@ -2057,6 +2384,40 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { } } +/// \brief Helper to add the variant paths of a libstdc++ installation. +bool Generic_GCC::addLibStdCXXIncludePaths( + Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, Twine IncludeSuffix, + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!getVFS().exists(Base + Suffix)) + return false; + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix); + + // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If + // that path exists or we have neither a GCC nor target multiarch triple, use + // this vanilla search path. + if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || + getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { + addSystemInclude(DriverArgs, CC1Args, + Base + Suffix + "/" + GCCTriple + IncludeSuffix); + } else { + // Otherwise try to use multiarch naming schemes which have normalized the + // triples and put the triple before the suffix. + // + // GCC surprisingly uses *both* the GCC triple with a multilib suffix and + // the target triple, so we support that here. + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + TargetMultiarchTriple + Suffix); + } + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); + return true; +} + + void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); @@ -2064,238 +2425,324 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || (getTriple().getOS() == llvm::Triple::Linux && - (!V.isOlderThan(4, 7, 0) || - getTriple().getEnvironment() == llvm::Triple::Android)) || - getTriple().getOS() == llvm::Triple::NaCl; + (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || + getTriple().getOS() == llvm::Triple::NaCl || + (getTriple().getVendor() == llvm::Triple::MipsTechnologies && + !getTriple().hasEnvironment()); if (DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, UseInitArrayDefault)) CC1Args.push_back("-fuse-init-array"); } +/// Mips Toolchain +MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args) + : Linux(D, Triple, Args) { + // Select the correct multilib according to the given arguments. + DetectedMultilibs Result; + findMIPSMultilibs(D, Triple, "", Args, Result); + Multilibs = Result.Multilibs; + SelectedMultilib = Result.SelectedMultilib; + + // Find out the library suffix based on the ABI. + LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); + getFilePaths().clear(); + getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix); + + // Use LLD by default. + DefaultLinker = "lld"; +} + +void MipsLLVMToolChain::AddClangSystemIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + const Driver &D = getDriver(); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + const auto &Callback = Multilibs.includeDirsCallback(); + if (Callback) { + const auto IncludePaths = + Callback(D.getInstalledDir(), getTripleString(), SelectedMultilib); + for (const auto &Path : IncludePaths) + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path); + } +} + +Tool *MipsLLVMToolChain::buildLinker() const { + return new tools::gnutools::Linker(*this); +} + +std::string MipsLLVMToolChain::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot + SelectedMultilib.osSuffix(); + + const std::string InstalledDir(getDriver().getInstalledDir()); + std::string SysRootPath = + InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); + if (llvm::sys::fs::exists(SysRootPath)) + return SysRootPath; + + return std::string(); +} + +ToolChain::CXXStdlibType +MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const { + Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); + if (A) { + StringRef Value = A->getValue(); + if (Value != "libc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +void MipsLLVMToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + assert((GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) && + "Only -lc++ (aka libcxx) is suported in this toolchain."); + + 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"); + break; + } + } + } +} + +void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) && + "Only -lc++ (aka libxx) is suported in this toolchain."); + + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); +} + +std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, + StringRef Component, + bool Shared) const { + SmallString<128> Path(getDriver().ResourceDir); + llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, + getOS()); + llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" + + "mips" + (Shared ? ".so" : ".a"))); + return Path.str(); +} + /// Hexagon Toolchain -std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir, - const ArgList &Args) { +std::string HexagonToolChain::getHexagonTargetDir( + const std::string &InstalledDir, + const SmallVectorImpl<std::string> &PrefixDirs) const { + std::string InstallRelDir; + const Driver &D = getDriver(); // Locate the rest of the toolchain ... - std::string GccToolchain = getGCCToolchainDir(Args); - - if (!GccToolchain.empty()) - return GccToolchain; + for (auto &I : PrefixDirs) + if (D.getVFS().exists(I)) + return I; - std::string InstallRelDir = InstalledDir + "/../../gnu"; - if (llvm::sys::fs::exists(InstallRelDir)) + if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) return InstallRelDir; - std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu"; - if (llvm::sys::fs::exists(PrefixRelDir)) + std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/target"; + if (getVFS().exists(PrefixRelDir)) return PrefixRelDir; return InstallRelDir; } -const char *Hexagon_TC::GetSmallDataThreshold(const ArgList &Args) { - Arg *A; - A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ, - options::OPT_msmall_data_threshold_EQ); - if (A) - return A->getValue(); +Optional<unsigned> HexagonToolChain::getSmallDataThreshold( + const ArgList &Args) { + StringRef Gn = ""; + if (Arg *A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ, + options::OPT_msmall_data_threshold_EQ)) { + Gn = A->getValue(); + } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, + options::OPT_fPIC)) { + Gn = "0"; + } - A = Args.getLastArg(options::OPT_shared, options::OPT_fpic, - options::OPT_fPIC); - if (A) - return "0"; + unsigned G; + if (!Gn.getAsInteger(10, G)) + return G; - return 0; + return None; } -bool Hexagon_TC::UsesG0(const char *smallDataThreshold) { - return smallDataThreshold && smallDataThreshold[0] == '0'; -} -static void GetHexagonLibraryPaths(const ArgList &Args, const std::string &Ver, - const std::string &MarchString, - const std::string &InstalledDir, - ToolChain::path_list *LibPaths) { - bool buildingLib = Args.hasArg(options::OPT_shared); +void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, + ToolChain::path_list &LibPaths) const { + const Driver &D = getDriver(); //---------------------------------------------------------------------------- // -L Args //---------------------------------------------------------------------------- for (Arg *A : Args.filtered(options::OPT_L)) for (const char *Value : A->getValues()) - LibPaths->push_back(Value); + LibPaths.push_back(Value); //---------------------------------------------------------------------------- // Other standard paths //---------------------------------------------------------------------------- - const std::string MarchSuffix = "/" + MarchString; - const std::string G0Suffix = "/G0"; - const std::string MarchG0Suffix = MarchSuffix + G0Suffix; - const std::string RootDir = Hexagon_TC::GetGnuDir(InstalledDir, Args) + "/"; - - // lib/gcc/hexagon/... - std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/"; - if (buildingLib) { - LibPaths->push_back(LibGCCHexagonDir + Ver + MarchG0Suffix); - LibPaths->push_back(LibGCCHexagonDir + Ver + G0Suffix); - } - LibPaths->push_back(LibGCCHexagonDir + Ver + MarchSuffix); - LibPaths->push_back(LibGCCHexagonDir + Ver); - - // lib/gcc/... - LibPaths->push_back(RootDir + "lib/gcc"); - - // hexagon/lib/... - std::string HexagonLibDir = RootDir + "hexagon/lib"; - if (buildingLib) { - LibPaths->push_back(HexagonLibDir + MarchG0Suffix); - LibPaths->push_back(HexagonLibDir + G0Suffix); + std::vector<std::string> RootDirs; + std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), RootDirs.begin()); + + std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), + D.PrefixDirs); + if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end()) + RootDirs.push_back(TargetDir); + + bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); + // Assume G0 with -shared. + bool HasG0 = Args.hasArg(options::OPT_shared); + if (auto G = getSmallDataThreshold(Args)) + HasG0 = G.getValue() == 0; + + const std::string CpuVer = GetTargetCPUVersion(Args).str(); + for (auto &Dir : RootDirs) { + std::string LibDir = Dir + "/hexagon/lib"; + std::string LibDirCpu = LibDir + '/' + CpuVer; + if (HasG0) { + if (HasPIC) + LibPaths.push_back(LibDirCpu + "/G0/pic"); + LibPaths.push_back(LibDirCpu + "/G0"); + } + LibPaths.push_back(LibDirCpu); + LibPaths.push_back(LibDir); } - LibPaths->push_back(HexagonLibDir + MarchSuffix); - LibPaths->push_back(HexagonLibDir); } -Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) +HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) : Linux(D, Triple, Args) { - const std::string InstalledDir(getDriver().getInstalledDir()); - const std::string GnuDir = Hexagon_TC::GetGnuDir(InstalledDir, Args); + const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), + D.PrefixDirs); // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to // program paths - const std::string BinDir(GnuDir + "/bin"); - if (llvm::sys::fs::exists(BinDir)) + const std::string BinDir(TargetDir + "/bin"); + if (D.getVFS().exists(BinDir)) getProgramPaths().push_back(BinDir); - // Determine version of GCC libraries and headers to use. - const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon"); - std::error_code ec; - GCCVersion MaxVersion = GCCVersion::Parse("0.0.0"); - for (llvm::sys::fs::directory_iterator di(HexagonDir, ec), de; - !ec && di != de; di = di.increment(ec)) { - GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->path())); - if (MaxVersion < cv) - MaxVersion = cv; - } - GCCLibAndIncVersion = MaxVersion; - - ToolChain::path_list *LibPaths = &getFilePaths(); + ToolChain::path_list &LibPaths = getFilePaths(); // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets // 'elf' OS type, so the Linux paths are not appropriate. When we actually // support 'linux' we'll need to fix this up - LibPaths->clear(); - - GetHexagonLibraryPaths(Args, GetGCCLibAndIncVersion(), GetTargetCPU(Args), - InstalledDir, LibPaths); + LibPaths.clear(); + getHexagonLibraryPaths(Args, LibPaths); } -Hexagon_TC::~Hexagon_TC() {} +HexagonToolChain::~HexagonToolChain() {} -Tool *Hexagon_TC::buildAssembler() const { +Tool *HexagonToolChain::buildAssembler() const { return new tools::hexagon::Assembler(*this); } -Tool *Hexagon_TC::buildLinker() const { +Tool *HexagonToolChain::buildLinker() const { return new tools::hexagon::Linker(*this); } -void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - const Driver &D = getDriver(); - +void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - std::string Ver(GetGCCLibAndIncVersion()); - std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir, DriverArgs); - std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver); - addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include"); - addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed"); - addExternCSystemInclude(DriverArgs, CC1Args, GnuDir + "/hexagon/include"); + const Driver &D = getDriver(); + std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), + D.PrefixDirs); + addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); } -void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - +void HexagonToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; const Driver &D = getDriver(); - std::string Ver(GetGCCLibAndIncVersion()); - SmallString<128> IncludeDir( - Hexagon_TC::GetGnuDir(D.InstalledDir, DriverArgs)); - - llvm::sys::path::append(IncludeDir, "hexagon/include/c++/"); - llvm::sys::path::append(IncludeDir, Ver); - addSystemInclude(DriverArgs, CC1Args, IncludeDir); + std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); + addSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include/c++"); } ToolChain::CXXStdlibType -Hexagon_TC::GetCXXStdlibType(const ArgList &Args) const { +HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); if (!A) return ToolChain::CST_Libstdcxx; StringRef Value = A->getValue(); - if (Value != "libstdc++") { + if (Value != "libstdc++") getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - } return ToolChain::CST_Libstdcxx; } -static int getHexagonVersion(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ); - // Select the default CPU (v4) if none was given. - if (!A) - return 4; +// +// Returns the default CPU for Hexagon. This is the default compilation target +// if no Hexagon processor is selected at the command-line. +// +const StringRef HexagonToolChain::GetDefaultCPU() { + return "hexagonv60"; +} - // FIXME: produce errors if we cannot parse the version. - StringRef WhichHexagon = A->getValue(); - if (WhichHexagon.startswith("hexagonv")) { - int Val; - if (!WhichHexagon.substr(sizeof("hexagonv") - 1).getAsInteger(10, Val)) - return Val; - } - if (WhichHexagon.startswith("v")) { - int Val; - if (!WhichHexagon.substr(1).getAsInteger(10, Val)) - return Val; +const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { + Arg *CpuArg = nullptr; + + for (auto &A : Args) { + if (A->getOption().matches(options::OPT_mcpu_EQ)) { + CpuArg = A; + A->claim(); + } } - // FIXME: should probably be an error. - return 4; + StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); + if (CPU.startswith("hexagon")) + return CPU.substr(sizeof("hexagon") - 1); + return CPU; } +// End Hexagon -StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args) { - int V = getHexagonVersion(Args); - // FIXME: We don't support versions < 4. We should error on them. - switch (V) { - default: - llvm_unreachable("Unexpected version"); - case 5: - return "v5"; - case 4: - return "v4"; - case 3: - return "v3"; - case 2: - return "v2"; - case 1: - return "v1"; - } +/// AMDGPU Toolchain +AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { } + +Tool *AMDGPUToolChain::buildLinker() const { + return new tools::amdgpu::Linker(*this); } -// End Hexagon +// End AMDGPU /// NaCl Toolchain -NaCl_TC::NaCl_TC(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) +NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) : Generic_ELF(D, Triple, Args) { // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the @@ -2317,45 +2764,39 @@ NaCl_TC::NaCl_TC(const Driver &D, const llvm::Triple &Triple, std::string ToolPath(getDriver().ResourceDir + "/lib/"); switch (Triple.getArch()) { - case llvm::Triple::x86: { + case llvm::Triple::x86: file_paths.push_back(FilePath + "x86_64-nacl/lib32"); - file_paths.push_back(FilePath + "x86_64-nacl/usr/lib32"); + file_paths.push_back(FilePath + "i686-nacl/usr/lib"); prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); file_paths.push_back(ToolPath + "i686-nacl"); break; - } - case llvm::Triple::x86_64: { + case llvm::Triple::x86_64: file_paths.push_back(FilePath + "x86_64-nacl/lib"); file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); file_paths.push_back(ToolPath + "x86_64-nacl"); break; - } - case llvm::Triple::arm: { + case llvm::Triple::arm: file_paths.push_back(FilePath + "arm-nacl/lib"); file_paths.push_back(FilePath + "arm-nacl/usr/lib"); prog_paths.push_back(ProgPath + "arm-nacl/bin"); file_paths.push_back(ToolPath + "arm-nacl"); break; - } - case llvm::Triple::mipsel: { + case llvm::Triple::mipsel: file_paths.push_back(FilePath + "mipsel-nacl/lib"); file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); prog_paths.push_back(ProgPath + "bin"); file_paths.push_back(ToolPath + "mipsel-nacl"); break; - } default: break; } - // Use provided linker, not system linker - Linker = GetProgramPath("ld"); NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); } -void NaCl_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { const Driver &D = getDriver(); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; @@ -2371,12 +2812,21 @@ void NaCl_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, SmallString<128> P(D.Dir + "/../"); switch (getTriple().getArch()) { + case llvm::Triple::x86: + // x86 is special because multilib style uses x86_64-nacl/include for libc + // headers but the SDK wants i686-nacl/usr/include. The other architectures + // have the same substring. + llvm::sys::path::append(P, "i686-nacl/usr/include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + llvm::sys::path::remove_filename(P); + llvm::sys::path::remove_filename(P); + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, "x86_64-nacl/include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + return; case llvm::Triple::arm: llvm::sys::path::append(P, "arm-nacl/usr/include"); break; - case llvm::Triple::x86: - llvm::sys::path::append(P, "x86_64-nacl/usr/include"); - break; case llvm::Triple::x86_64: llvm::sys::path::append(P, "x86_64-nacl/usr/include"); break; @@ -2394,16 +2844,16 @@ void NaCl_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, P.str()); } -void NaCl_TC::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { +void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { // Check for -stdlib= flags. We only support libc++ but this consumes the arg // if the value is libc++, and emits an error for other values. GetCXXStdlibType(Args); CmdArgs.push_back("-lc++"); } -void NaCl_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void NaClToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { const Driver &D = getDriver(); if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) @@ -2436,7 +2886,8 @@ void NaCl_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -ToolChain::CXXStdlibType NaCl_TC::GetCXXStdlibType(const ArgList &Args) const { +ToolChain::CXXStdlibType +NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); if (Value == "libc++") @@ -2447,8 +2898,9 @@ ToolChain::CXXStdlibType NaCl_TC::GetCXXStdlibType(const ArgList &Args) const { return ToolChain::CST_Libcxx; } -std::string NaCl_TC::ComputeEffectiveClangTriple(const ArgList &Args, - types::ID InputType) const { +std::string +NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); if (TheTriple.getArch() == llvm::Triple::arm && TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) @@ -2456,11 +2908,11 @@ std::string NaCl_TC::ComputeEffectiveClangTriple(const ArgList &Args, return TheTriple.getTriple(); } -Tool *NaCl_TC::buildLinker() const { +Tool *NaClToolChain::buildLinker() const { return new tools::nacltools::Linker(*this); } -Tool *NaCl_TC::buildAssembler() const { +Tool *NaClToolChain::buildAssembler() const { if (getTriple().getArch() == llvm::Triple::arm) return new tools::nacltools::AssemblerARM(*this); return new tools::gnutools::Assembler(*this); @@ -2619,7 +3071,7 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::ppc) && - llvm::sys::fs::exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) + D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); else getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); @@ -2666,7 +3118,7 @@ Tool *FreeBSD::buildAssembler() const { Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } -bool FreeBSD::UseSjLjExceptions() const { +bool FreeBSD::UseSjLjExceptions(const ArgList &Args) const { // FreeBSD uses SjLj exceptions on ARM oabi. switch (getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: @@ -2829,18 +3281,46 @@ Tool *Minix::buildAssembler() const { Tool *Minix::buildLinker() const { return new tools::minix::Linker(*this); } +static void addPathIfExists(const Driver &D, const Twine &Path, + ToolChain::path_list &Paths) { + if (D.getVFS().exists(Path)) + Paths.push_back(Path.str()); +} + /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_GCC(D, Triple, Args) { - getProgramPaths().push_back(getDriver().getInstalledDir()); + GCCInstallation.init(Triple, Args); + + path_list &Paths = getFilePaths(); + if (GCCInstallation.isValid()) + addPathIfExists(D, GCCInstallation.getInstallPath(), Paths); + + addPathIfExists(D, getDriver().getInstalledDir(), Paths); if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); + addPathIfExists(D, getDriver().Dir, Paths); - getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); + addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); + + std::string LibPath = "/usr/lib/"; + switch (Triple.getArch()) { + case llvm::Triple::x86: + case llvm::Triple::sparc: + break; + case llvm::Triple::x86_64: + LibPath += "amd64/"; + break; + case llvm::Triple::sparcv9: + LibPath += "sparcv9/"; + break; + default: + llvm_unreachable("Unsupported architecture"); + } + + addPathIfExists(D, getDriver().SysRoot + LibPath, Paths); } Tool *Solaris::buildAssembler() const { @@ -2849,6 +3329,31 @@ Tool *Solaris::buildAssembler() const { Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } +void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + // Include the support directory for things like xlocale and fudged system + // headers. + addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris"); + + if (GCCInstallation.isValid()) { + GCCVersion Version = GCCInstallation.getVersion(); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/gcc/" + + Version.MajorStr + "." + + Version.MinorStr + + "/include/c++/" + Version.Text); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr + + "." + Version.MinorStr + "/include/c++/" + + Version.Text + "/" + + GCCInstallation.getTriple().str()); + } +} + /// Distribution (very bare-bones at the moment). enum Distro { @@ -2884,6 +3389,7 @@ enum Distro { UbuntuUtopic, UbuntuVivid, UbuntuWily, + UbuntuXenial, UnknownDistro }; @@ -2898,10 +3404,10 @@ static bool IsDebian(enum Distro Distro) { } static bool IsUbuntu(enum Distro Distro) { - return Distro >= UbuntuHardy && Distro <= UbuntuWily; + return Distro >= UbuntuHardy && Distro <= UbuntuXenial; } -static Distro DetectDistro(llvm::Triple::ArchType Arch) { +static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = llvm::MemoryBuffer::getFile("/etc/lsb-release"); if (File) { @@ -2909,7 +3415,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { SmallVector<StringRef, 16> Lines; Data.split(Lines, "\n"); Distro Version = UnknownDistro; - for (const StringRef Line : Lines) + for (StringRef Line : Lines) if (Version == UnknownDistro && Line.startswith("DISTRIB_CODENAME=")) Version = llvm::StringSwitch<Distro>(Line.substr(17)) .Case("hardy", UbuntuHardy) @@ -2928,6 +3434,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { .Case("utopic", UbuntuUtopic) .Case("vivid", UbuntuVivid) .Case("wily", UbuntuWily) + .Case("xenial", UbuntuXenial) .Default(UnknownDistro); return Version; } @@ -2967,13 +3474,13 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { return UnknownDistro; } - if (llvm::sys::fs::exists("/etc/SuSE-release")) + if (D.getVFS().exists("/etc/SuSE-release")) return OpenSUSE; - if (llvm::sys::fs::exists("/etc/exherbo-release")) + if (D.getVFS().exists("/etc/exherbo-release")) return Exherbo; - if (llvm::sys::fs::exists("/etc/arch-release")) + if (D.getVFS().exists("/etc/arch-release")) return ArchLinux; return UnknownDistro; @@ -2985,9 +3492,11 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const llvm::Triple &TargetTriple, +static std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, StringRef SysRoot) { - llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment(); + llvm::Triple::EnvironmentType TargetEnvironment = + TargetTriple.getEnvironment(); // For most architectures, just use whatever we have rather than trying to be // clever. @@ -3002,92 +3511,91 @@ static std::string getMultiarchTriple(const llvm::Triple &TargetTriple, case llvm::Triple::arm: case llvm::Triple::thumb: if (TargetEnvironment == llvm::Triple::GNUEABIHF) { - if (llvm::sys::fs::exists(SysRoot + "/lib/arm-linux-gnueabihf")) + if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf")) return "arm-linux-gnueabihf"; } else { - if (llvm::sys::fs::exists(SysRoot + "/lib/arm-linux-gnueabi")) + if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi")) return "arm-linux-gnueabi"; } break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: if (TargetEnvironment == llvm::Triple::GNUEABIHF) { - if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabihf")) + if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf")) return "armeb-linux-gnueabihf"; } else { - if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabi")) + if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi")) return "armeb-linux-gnueabi"; } break; case llvm::Triple::x86: - if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu")) return "i386-linux-gnu"; break; case llvm::Triple::x86_64: // We don't want this for x32, otherwise it will match x86_64 libs if (TargetEnvironment != llvm::Triple::GNUX32 && - llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) + D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; break; case llvm::Triple::aarch64: - if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu")) return "aarch64-linux-gnu"; break; case llvm::Triple::aarch64_be: - if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64_be-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu")) return "aarch64_be-linux-gnu"; break; case llvm::Triple::mips: - if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; break; case llvm::Triple::mipsel: - if (llvm::sys::fs::exists(SysRoot + "/lib/mipsel-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu")) return "mipsel-linux-gnu"; break; case llvm::Triple::mips64: - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) return "mips64-linux-gnu"; - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnuabi64")) + if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64")) return "mips64-linux-gnuabi64"; break; case llvm::Triple::mips64el: - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) return "mips64el-linux-gnu"; - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) + if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) return "mips64el-linux-gnuabi64"; break; case llvm::Triple::ppc: - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) return "powerpc-linux-gnuspe"; - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; break; case llvm::Triple::ppc64: - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu")) return "powerpc64-linux-gnu"; break; case llvm::Triple::ppc64le: - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64le-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) return "powerpc64le-linux-gnu"; break; case llvm::Triple::sparc: - if (llvm::sys::fs::exists(SysRoot + "/lib/sparc-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) return "sparc-linux-gnu"; break; case llvm::Triple::sparcv9: - if (llvm::sys::fs::exists(SysRoot + "/lib/sparc64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu")) return "sparc64-linux-gnu"; break; + case llvm::Triple::systemz: + if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu")) + return "s390x-linux-gnu"; + break; } return TargetTriple.str(); } -static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { - if (llvm::sys::fs::exists(Path)) - Paths.push_back(Path.str()); -} - static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { if (isMipsArch(Triple.getArch())) { // lib32 directory has a special meaning on MIPS targets. @@ -3120,7 +3628,8 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(D, Triple, Args); + GCCInstallation.init(Triple, Args); + CudaInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); @@ -3138,9 +3647,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) GCCInstallation.getTriple().str() + "/bin") .str()); - Linker = GetLinkerPath(); - - Distro Distro = DetectDistro(Arch); + Distro Distro = DetectDistro(D, Arch); if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); @@ -3150,7 +3657,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); - const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android; + const bool IsAndroid = Triple.isAndroid(); const bool IsMips = isMipsArch(Arch); if (IsMips && !SysRoot.empty()) @@ -3190,7 +3697,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) path_list &Paths = getFilePaths(); const std::string OSLibDir = getOSLibDir(Triple, Args); - const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot); + const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { @@ -3200,7 +3707,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. - addPathIfExists((GCCInstallation.getInstallPath() + Multilib.gccSuffix()), + addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(), Paths); // GCC cross compiling toolchains will install target libraries which ship @@ -3221,8 +3728,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // // Note that this matches the GCC behavior. See the below comment for where // Clang diverges from GCC's behavior. - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + - Multilib.osSuffix(), + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + + OSLibDir + Multilib.osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to @@ -3235,8 +3742,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // configurations but this seems somewhere between questionable and simply // a bug. if (StringRef(LibPath).startswith(SysRoot)) { - addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(LibPath + "/../" + OSLibDir, Paths); + addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } @@ -3246,27 +3753,29 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) { - addPathIfExists(D.Dir + "/../lib/" + MultiarchTriple, Paths); - addPathIfExists(D.Dir + "/../" + OSLibDir, Paths); + addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); + addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } - addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); - addPathIfExists(SysRoot + "/lib/../" + OSLibDir, Paths); - addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); - addPathIfExists(SysRoot + "/usr/lib/../" + OSLibDir, Paths); + addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) { - addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + + addPathIfExists(D, + SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + OSLibDir, Paths); // Add the 'other' biarch variant path Multilib BiarchSibling; if (GCCInstallation.getBiarchSibling(BiarchSibling)) { - addPathIfExists( - GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), Paths); + addPathIfExists(D, GCCInstallation.getInstallPath() + + BiarchSibling.gccSuffix(), + Paths); } // See comments above on the multilib variant for details of why this is @@ -3274,14 +3783,14 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const std::string &LibPath = GCCInstallation.getParentLibPath(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const Multilib &Multilib = GCCInstallation.getMultilib(); - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib" + - Multilib.osSuffix(), + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + + Multilib.osSuffix(), Paths); // See comments above on the multilib variant for details of why this is // only included from within the sysroot. if (StringRef(LibPath).startswith(SysRoot)) - addPathIfExists(LibPath, Paths); + addPathIfExists(D, LibPath, Paths); } // Similar to the logic for GCC above, if we are currently running Clang @@ -3290,10 +3799,10 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) - addPathIfExists(D.Dir + "/../lib", Paths); + addPathIfExists(D, D.Dir + "/../lib", Paths); - addPathIfExists(SysRoot + "/lib", Paths); - addPathIfExists(SysRoot + "/usr/lib", Paths); + addPathIfExists(D, SysRoot + "/lib", Paths); + addPathIfExists(D, SysRoot + "/usr/lib", Paths); } bool Linux::HasNativeLLVMSupport() const { return true; } @@ -3323,12 +3832,12 @@ std::string Linux::computeSysRoot() const { (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix()) .str(); - if (llvm::sys::fs::exists(Path)) + if (getVFS().exists(Path)) return Path; Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); - if (llvm::sys::fs::exists(Path)) + if (getVFS().exists(Path)) return Path; return std::string(); @@ -3404,6 +3913,10 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, "/usr/include/arm-linux-gnueabi"}; const StringRef ARMHFMultiarchIncludeDirs[] = { "/usr/include/arm-linux-gnueabihf"}; + const StringRef ARMEBMultiarchIncludeDirs[] = { + "/usr/include/armeb-linux-gnueabi"}; + const StringRef ARMEBHFMultiarchIncludeDirs[] = { + "/usr/include/armeb-linux-gnueabihf"}; const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"}; const StringRef MIPSELMultiarchIncludeDirs[] = { "/usr/include/mipsel-linux-gnu"}; @@ -3422,6 +3935,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, "/usr/include/sparc-linux-gnu"}; const StringRef Sparc64MultiarchIncludeDirs[] = { "/usr/include/sparc64-linux-gnu"}; + const StringRef SYSTEMZMultiarchIncludeDirs[] = { + "/usr/include/s390x-linux-gnu"}; ArrayRef<StringRef> MultiarchIncludeDirs; switch (getTriple().getArch()) { case llvm::Triple::x86_64: @@ -3435,11 +3950,19 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; break; case llvm::Triple::arm: + case llvm::Triple::thumb: if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; else MultiarchIncludeDirs = ARMMultiarchIncludeDirs; break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) + MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs; + else + MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs; + break; case llvm::Triple::mips: MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; break; @@ -3467,11 +3990,14 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, case llvm::Triple::sparcv9: MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs; break; + case llvm::Triple::systemz: + MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs; + break; default: break; } for (StringRef Dir : MultiarchIncludeDirs) { - if (llvm::sys::fs::exists(SysRoot + Dir)) { + if (D.getVFS().exists(SysRoot + Dir)) { addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); break; } @@ -3488,37 +4014,24 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } -/// \brief Helper to add the variant paths of a libstdc++ installation. -/*static*/ bool Linux::addLibStdCXXIncludePaths( - Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, - StringRef TargetMultiarchTriple, Twine IncludeSuffix, - const ArgList &DriverArgs, ArgStringList &CC1Args) { - if (!llvm::sys::fs::exists(Base + Suffix)) - return false; - - addSystemInclude(DriverArgs, CC1Args, Base + Suffix); - // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If - // that path exists or we have neither a GCC nor target multiarch triple, use - // this vanilla search path. - if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || - llvm::sys::fs::exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { - addSystemInclude(DriverArgs, CC1Args, - Base + Suffix + "/" + GCCTriple + IncludeSuffix); - } else { - // Otherwise try to use multiarch naming schemes which have normalized the - // triples and put the triple before the suffix. - // - // GCC surprisingly uses *both* the GCC triple with a multilib suffix and - // the target triple, so we support that here. - addSystemInclude(DriverArgs, CC1Args, - Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); - addSystemInclude(DriverArgs, CC1Args, - Base + "/" + TargetMultiarchTriple + Suffix); +static std::string DetectLibcxxIncludePath(StringRef base) { + std::error_code EC; + int MaxVersion = 0; + std::string MaxVersionString = ""; + for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE; + LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + int Version; + if (VersionText[0] == 'v' && + !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { + if (Version > MaxVersion) { + MaxVersion = Version; + MaxVersionString = VersionText; + } + } } - - addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); - return true; + return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, @@ -3530,17 +4043,14 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, // Check if libc++ has been enabled and provide its include paths if so. if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { const std::string LibCXXIncludePathCandidates[] = { - // The primary location is within the Clang installation. - // FIXME: We shouldn't hard code 'v1' here to make Clang future proof to - // newer ABI versions. - getDriver().Dir + "/../include/c++/v1", + 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. - getDriver().SysRoot + "/usr/include/c++/v1"}; + DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++")}; for (const auto &IncludePath : LibCXXIncludePathCandidates) { - if (!llvm::sys::fs::exists(IncludePath)) + if (IncludePath.empty() || !getVFS().exists(IncludePath)) continue; // Add the first candidate that exists. addSystemInclude(DriverArgs, CC1Args, IncludePath); @@ -3561,10 +4071,10 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); - const std::string GCCMultiarchTriple = - getMultiarchTriple(GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string GCCMultiarchTriple = getMultiarchTriple( + getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); const std::string TargetMultiarchTriple = - getMultiarchTriple(getTriple(), getDriver().SysRoot); + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); // The primary search for libstdc++ supports multiarch variants. @@ -3598,6 +4108,18 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } +void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + 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"); + } +} + bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask Linux::getSupportedSanitizers() const { @@ -3607,24 +4129,39 @@ SanitizerMask Linux::getSupportedSanitizers() const { getTriple().getArch() == llvm::Triple::mips64el; const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 || getTriple().getArch() == llvm::Triple::ppc64le; + const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::Vptr; - if (IsX86_64 || IsMIPS64) { + Res |= SanitizerKind::SafeStack; + if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; + if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::Leak; + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) Res |= SanitizerKind::Thread; - } - if (IsX86_64 || IsMIPS64 || IsPowerPC64) + if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64) Res |= SanitizerKind::Memory; if (IsX86 || IsX86_64) { Res |= SanitizerKind::Function; - Res |= SanitizerKind::SafeStack; } return Res; } +void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (!needsProfileRT(Args)) return; + + // Add linker option -u__llvm_runtime_variable to cause runtime + // initialization module to be linked in. + if (!Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back(Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + ToolChain::addProfileRTLibs(Args, CmdArgs); +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, @@ -3638,10 +4175,7 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); - if (llvm::sys::fs::exists("/usr/lib/gcc47")) - getFilePaths().push_back("/usr/lib/gcc47"); - else - getFilePaths().push_back("/usr/lib/gcc44"); + getFilePaths().push_back("/usr/lib/gcc50"); } Tool *DragonFly::buildAssembler() const { @@ -3665,6 +4199,22 @@ CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { Linux::addClangTargetOptions(DriverArgs, CC1Args); CC1Args.push_back("-fcuda-is-device"); + + if (DriverArgs.hasArg(options::OPT_nocudalib)) + return; + + std::string LibDeviceFile = CudaInstallation.getLibDeviceFile( + DriverArgs.getLastArgValue(options::OPT_march_EQ)); + if (!LibDeviceFile.empty()) { + CC1Args.push_back("-mlink-cuda-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); + + // Libdevice in CUDA-7.0 requires PTX version that's more recent + // than LLVM defaults to. Use PTX4.2 which is the PTX version that + // came with CUDA-7.0. + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+ptx42"); + } } llvm::opt::DerivedArgList * @@ -3712,29 +4262,32 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } /// XCore tool chain -XCore::XCore(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) +XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) : ToolChain(D, Triple, Args) { // ProgramPaths are found via 'PATH' environment variable. } -Tool *XCore::buildAssembler() const { +Tool *XCoreToolChain::buildAssembler() const { return new tools::XCore::Assembler(*this); } -Tool *XCore::buildLinker() const { return new tools::XCore::Linker(*this); } +Tool *XCoreToolChain::buildLinker() const { + return new tools::XCore::Linker(*this); +} -bool XCore::isPICDefault() const { return false; } +bool XCoreToolChain::isPICDefault() const { return false; } -bool XCore::isPIEDefault() const { return false; } +bool XCoreToolChain::isPIEDefault() const { return false; } -bool XCore::isPICDefaultForced() const { return false; } +bool XCoreToolChain::isPICDefaultForced() const { return false; } -bool XCore::SupportsProfiling() const { return false; } +bool XCoreToolChain::SupportsProfiling() const { return false; } -bool XCore::hasBlocksRuntime() const { return false; } +bool XCoreToolChain::hasBlocksRuntime() const { return false; } -void XCore::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc)) return; @@ -3747,13 +4300,13 @@ void XCore::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } } -void XCore::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { CC1Args.push_back("-nostdsysteminc"); } -void XCore::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void XCoreToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) @@ -3767,15 +4320,84 @@ void XCore::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -void XCore::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { +void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { // We don't output any lib args. This is handled by xcc. } -// SHAVEToolChain does not call Clang's C compiler. -// We override SelectTool to avoid testing ShouldUseClangCompiler(). -Tool *SHAVEToolChain::SelectTool(const JobAction &JA) const { +MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_GCC(D, Triple, Args) { + // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use + // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. + // This won't work to find gcc. Instead we give the installation detector an + // extra triple, which is preferable to further hacks of the logic that at + // present is based solely on getArch(). In particular, it would be wrong to + // choose the myriad installation when targeting a non-myriad sparc install. + switch (Triple.getArch()) { + default: + D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() + << "myriad"; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::shave: + GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"}); + } + + if (GCCInstallation.isValid()) { + // The contents of LibDir are independent of the version of gcc. + // This contains libc, libg (a superset of libc), libm, libstdc++, libssp. + SmallString<128> LibDir(GCCInstallation.getParentLibPath()); + if (Triple.getArch() == llvm::Triple::sparcel) + llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib/le"); + else + llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib"); + addPathIfExists(D, LibDir, getFilePaths()); + + // This directory contains crt{i,n,begin,end}.o as well as libgcc. + // These files are tied to a particular version of gcc. + SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); + // There are actually 4 choices: {le,be} x {fpu,nofpu} + // but as this toolchain is for LEON sparc, it can assume FPU. + if (Triple.getArch() == llvm::Triple::sparcel) + llvm::sys::path::append(CompilerSupportDir, "le"); + addPathIfExists(D, CompilerSupportDir, getFilePaths()); + } +} + +MyriadToolChain::~MyriadToolChain() {} + +void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nostdinc)) + addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); +} + +void MyriadToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + // Only libstdc++, for now. + StringRef LibDir = GCCInstallation.getParentLibPath(); + const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + + addLibStdCXXIncludePaths( + LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, + "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); +} + +// MyriadToolChain handles several triples: +// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf +Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { + // The inherited method works fine if not targeting the SHAVE. + if (!isShaveCompilation(getTriple())) + return ToolChain::SelectTool(JA); switch (JA.getKind()) { + case Action::PreprocessJobClass: case Action::CompileJobClass: if (!Compiler) Compiler.reset(new tools::SHAVE::Compiler(*this)); @@ -3789,28 +4411,122 @@ Tool *SHAVEToolChain::SelectTool(const JobAction &JA) const { } } -SHAVEToolChain::SHAVEToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_GCC(D, Triple, Args) {} +Tool *MyriadToolChain::buildLinker() const { + return new tools::Myriad::Linker(*this); +} + +WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : ToolChain(D, Triple, Args) { + // Use LLD by default. + DefaultLinker = "lld"; +} + +bool WebAssembly::IsMathErrnoDefault() const { return false; } + +bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } + +bool WebAssembly::UseObjCMixedDispatch() const { return true; } + +bool WebAssembly::isPICDefault() const { return false; } + +bool WebAssembly::isPIEDefault() const { return false; } + +bool WebAssembly::isPICDefaultForced() const { return false; } + +bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } + +// TODO: Support Objective C stuff. +bool WebAssembly::SupportsObjCGC() const { return false; } -SHAVEToolChain::~SHAVEToolChain() {} +bool WebAssembly::hasBlocksRuntime() const { return false; } -/// Following are methods necessary to avoid having moviClang be an abstract -/// class. +// TODO: Support profiling. +bool WebAssembly::SupportsProfiling() const { return false; } -Tool *SHAVEToolChain::getTool(Action::ActionClass AC) const { - // SelectTool() must find a tool using the method in the superclass. - // There's nothing we can do if that fails. - llvm_unreachable("SHAVEToolChain can't getTool"); +bool WebAssembly::HasNativeLLVMSupport() const { return true; } + +void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fuse-init-array"); } -Tool *SHAVEToolChain::buildLinker() const { - // SHAVEToolChain executables can not be linked except by the vendor tools. - llvm_unreachable("SHAVEToolChain can't buildLinker"); +Tool *WebAssembly::buildLinker() const { + return new tools::wasm::Linker(*this); } -Tool *SHAVEToolChain::buildAssembler() const { - // This one you'd think should be reachable since we expose an - // assembler to the driver, except not the way it expects. - llvm_unreachable("SHAVEToolChain can't buildAssembler"); +PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, 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 + // 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 (!llvm::sys::fs::exists(EnvValue)) + getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; + PS4SDKDir = EnvValue; + } else { + PS4SDKDir = getDriver().Dir; + llvm::sys::path::append(PS4SDKDir, "/../../"); + } + + // By default, the driver won't report a warning if it can't find + // PS4's include or lib directories. This behavior could be changed if + // -Weverything or -Winvalid-or-nonexistent-directory options are passed. + // If -isysroot was passed, use that as the SDK base path. + std::string PrefixDir; + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + PrefixDir = A->getValue(); + if (!llvm::sys::fs::exists(PrefixDir)) + getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; + } else + PrefixDir = PS4SDKDir.str(); + + SmallString<512> PS4SDKIncludeDir(PrefixDir); + llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); + if (!Args.hasArg(options::OPT_nostdinc) && + !Args.hasArg(options::OPT_nostdlibinc) && + !Args.hasArg(options::OPT_isysroot) && + !Args.hasArg(options::OPT__sysroot_EQ) && + !llvm::sys::fs::exists(PS4SDKIncludeDir)) { + getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << "PS4 system headers" << PS4SDKIncludeDir; + } + + SmallString<512> PS4SDKLibDir(PS4SDKDir); + llvm::sys::path::append(PS4SDKLibDir, "target/lib"); + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs) && + !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && + !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && + !Args.hasArg(options::OPT_emit_ast) && + !llvm::sys::fs::exists(PS4SDKLibDir)) { + getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << "PS4 system libraries" << PS4SDKLibDir; + return; + } + getFilePaths().push_back(PS4SDKLibDir.str()); +} + +Tool *PS4CPU::buildAssembler() const { + return new tools::PS4cpu::Assemble(*this); +} + +Tool *PS4CPU::buildLinker() const { return new tools::PS4cpu::Link(*this); } + +bool PS4CPU::isPICDefault() const { return true; } + +bool PS4CPU::HasNativeLLVMSupport() const { return true; } + +SanitizerMask PS4CPU::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::Vptr; + return Res; } diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 59eaade..f4b6b15 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -78,6 +78,7 @@ public: class GCCInstallationDetector { bool IsValid; llvm::Triple GCCTriple; + const Driver &D; // FIXME: These might be better as path objects. std::string GCCInstallPath; @@ -99,9 +100,9 @@ public: MultilibSet Multilibs; public: - GCCInstallationDetector() : IsValid(false) {} - void init(const Driver &D, const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args); + explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, + ArrayRef<std::string> ExtraTripleAliases = None); /// \brief Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } @@ -145,11 +146,53 @@ public: const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix = false); + + void scanLibDirForGCCTripleSolaris(const llvm::Triple &TargetArch, + const llvm::opt::ArgList &Args, + const std::string &LibDir, + StringRef CandidateTriple, + bool NeedsBiarchSuffix = false); }; protected: GCCInstallationDetector GCCInstallation; + // \brief A class to find a viable CUDA installation + + class CudaInstallationDetector { + bool IsValid; + const Driver &D; + std::string CudaInstallPath; + std::string CudaLibPath; + std::string CudaLibDevicePath; + std::string CudaIncludePath; + llvm::StringMap<std::string> CudaLibDeviceMap; + + public: + CudaInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); + + /// \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 detected Cuda installation path. + StringRef getInstallPath() const { return CudaInstallPath; } + /// \brief Get the detected Cuda Include path. + StringRef getIncludePath() const { return CudaIncludePath; } + /// \brief Get the detected Cuda library path. + StringRef getLibPath() const { return CudaLibPath; } + /// \brief Get the detected Cuda device library path. + StringRef getLibDevicePath() const { return CudaLibDevicePath; } + /// \brief Get libdevice file for given architecture + std::string getLibDeviceFile(StringRef Gpu) const { + return CudaLibDeviceMap.lookup(Gpu); + } + }; + + CudaInstallationDetector CudaInstallation; + public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); @@ -177,6 +220,13 @@ protected: /// \brief Check whether the target triple's architecture is 32-bits. bool isTarget32Bit() const { return getTriple().isArch32Bit(); } + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, + StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, + Twine IncludeSuffix, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + /// @} private: @@ -236,8 +286,8 @@ public: /// Add any profiling runtime libraries that are needed. This is essentially a /// MachO specific version of addProfileRT in Tools.cpp. - virtual void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override { // There aren't any profiling libs for embedded targets currently. } @@ -293,7 +343,9 @@ public: bool UseDwarfDebugFlags() const override; - bool UseSjLjExceptions() const override { return false; } + bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override { + return false; + } /// } }; @@ -308,7 +360,15 @@ public: // the argument translation business. mutable bool TargetInitialized; - enum DarwinPlatformKind { MacOS, IPhoneOS, IPhoneOSSimulator }; + enum DarwinPlatformKind { + MacOS, + IPhoneOS, + IPhoneOSSimulator, + TvOS, + TvOSSimulator, + WatchOS, + WatchOSSimulator + }; mutable DarwinPlatformKind TargetPlatform; @@ -336,7 +396,8 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; bool isKernelStatic() const override { - return !isTargetIPhoneOS() || isIPhoneOSVersionLT(6, 0); + return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && + !isTargetWatchOS()); } void addProfileRTLibs(const llvm::opt::ArgList &Args, @@ -365,12 +426,13 @@ protected: bool isTargetIPhoneOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOS; + return TargetPlatform == IPhoneOS || TargetPlatform == TvOS; } bool isTargetIOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOSSimulator; + return TargetPlatform == IPhoneOSSimulator || + TargetPlatform == TvOSSimulator; } bool isTargetIOSBased() const { @@ -378,6 +440,36 @@ protected: return isTargetIPhoneOS() || isTargetIOSSimulator(); } + bool isTargetTvOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == TvOS; + } + + bool isTargetTvOSSimulator() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == TvOSSimulator; + } + + bool isTargetTvOSBased() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator; + } + + bool isTargetWatchOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == WatchOS; + } + + bool isTargetWatchOSSimulator() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == WatchOSSimulator; + } + + bool isTargetWatchOSBased() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator; + } + bool isTargetMacOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == MacOS; @@ -428,7 +520,7 @@ public: unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { // Stack protectors default to on for user code on 10.5, // and for everything in 10.6 and beyond - if (isTargetIOSBased()) + if (isTargetIOSBased() || isTargetWatchOSBased()) return 1; else if (isTargetMacOS() && !isMacosxVersionLT(10, 6)) return 1; @@ -442,7 +534,7 @@ public: void CheckObjCARC() const override; - bool UseSjLjExceptions() const override; + bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; }; @@ -469,6 +561,15 @@ public: void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // Darwin defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::LLDB; + } + /// } private: @@ -521,6 +622,12 @@ public: bool IsIntegratedAssemblerDefault() const override { return true; } + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; @@ -572,6 +679,7 @@ public: unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; } + unsigned GetDefaultDwarfVersion() const override { return 2; } protected: Tool *buildAssembler() const override; @@ -615,9 +723,16 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool UseSjLjExceptions() const override; + bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // FreeBSD defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::LLDB; + } protected: Tool *buildAssembler() const override; @@ -679,26 +794,19 @@ public: void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; bool 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; - std::string Linker; std::vector<std::string> ExtraOpts; protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; - -private: - static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, - StringRef GCCTriple, - StringRef GCCMultiarchTriple, - StringRef TargetMultiarchTriple, - Twine IncludeSuffix, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args); - - std::string computeSysRoot() const; }; class LLVM_LIBRARY_VISIBILITY CudaToolChain : public Linux { @@ -713,16 +821,52 @@ public: llvm::opt::ArgStringList &CC1Args) const override; }; -class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { +class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux { +protected: + Tool *buildLinker() const override; + +public: + MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + bool Shared = false) const override; + + std::string computeSysRoot() const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc + : RuntimeLibType::RLT_CompilerRT; + } + +private: + Multilib SelectedMultilib; + std::string LibSuffix; +}; + +class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { protected: GCCVersion GCCLibAndIncVersion; Tool *buildAssembler() const override; Tool *buildLinker() const override; public: - Hexagon_TC(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~Hexagon_TC() override; + HexagonToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~HexagonToolChain() override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -733,21 +877,37 @@ public: CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } + bool IsIntegratedAssemblerDefault() const override { + return true; + } + + std::string getHexagonTargetDir( + const std::string &InstalledDir, + const SmallVectorImpl<std::string> &PrefixDirs) const; + void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, + ToolChain::path_list &LibPaths) const; - static std::string GetGnuDir(const std::string &InstalledDir, - const llvm::opt::ArgList &Args); + static const StringRef GetDefaultCPU(); + static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); - static StringRef GetTargetCPU(const llvm::opt::ArgList &Args); + static Optional<unsigned> getSmallDataThreshold( + const llvm::opt::ArgList &Args); +}; - static const char *GetSmallDataThreshold(const llvm::opt::ArgList &Args); +class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { +protected: + Tool *buildLinker() const override; - static bool UsesG0(const char *smallDataThreshold); +public: + AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + bool IsIntegratedAssemblerDefault() const override { return true; } }; -class LLVM_LIBRARY_VISIBILITY NaCl_TC : public Generic_ELF { +class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF { public: - NaCl_TC(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + NaClToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -765,14 +925,13 @@ public: return getTriple().getArch() == llvm::Triple::mipsel; } - // Get the path to the file containing NaCl's ARM macros. It lives in NaCl_TC - // because the AssembleARM tool needs a const char * that it can pass around - // and the toolchain outlives all the jobs. + // Get the path to the file containing NaCl's ARM macros. + // It lives in NaClToolChain because the ARMAssembler tool needs a + // const char * that it can pass around, const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); } std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; - std::string Linker; protected: Tool *buildLinker() const override; @@ -801,6 +960,10 @@ public: MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const override; + bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault() const override; bool isPICDefault() const override; @@ -814,8 +977,14 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool getWindowsSDKDir(std::string &path, int &major, int &minor) const; + bool getWindowsSDKDir(std::string &path, int &major, + std::string &windowsSDKIncludeVersion, + std::string &windowsSDKLibVersion) const; bool getWindowsSDKLibraryPath(std::string &path) const; + /// \brief Check if Universal CRT should be used if available + bool useUniversalCRT(std::string &visualStudioDir) const; + bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const; + bool getUniversalCRTLibraryPath(std::string &path) const; bool getVisualStudioInstallDir(std::string &path) const; bool getVisualStudioBinariesFolder(const char *clangProgramPath, std::string &path) const; @@ -828,7 +997,9 @@ protected: void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const std::string &folder, - const char *subfolder) const; + const Twine &subfolder1, + const Twine &subfolder2 = "", + const Twine &subfolder3 = "") const; Tool *buildLinker() const override; Tool *buildAssembler() const override; @@ -858,15 +1029,17 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + SanitizerMask getSupportedSanitizers() const override; + protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; }; -class LLVM_LIBRARY_VISIBILITY XCore : public ToolChain { +class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain { public: - XCore(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + XCoreToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); protected: Tool *buildAssembler() const override; @@ -890,29 +1063,84 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; }; -/// SHAVEToolChain - A tool chain using the compiler installed by the the -// Movidius SDK into MV_TOOLS_DIR (which we assume will be copied to llvm's -// installation dir) to perform all subcommands. -class LLVM_LIBRARY_VISIBILITY SHAVEToolChain : public Generic_GCC { +/// 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 { public: - SHAVEToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~SHAVEToolChain() override; + MyriadToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~MyriadToolChain() override; - virtual Tool *SelectTool(const JobAction &JA) 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 *SelectTool(const JobAction &JA) const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } protected: - Tool *getTool(Action::ActionClass AC) const override; - Tool *buildAssembler() const override; Tool *buildLinker() const override; + bool isShaveCompilation(const llvm::Triple &T) const { + return T.getArch() == llvm::Triple::shave; + } private: mutable std::unique_ptr<Tool> Compiler; mutable std::unique_ptr<Tool> Assembler; }; +class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain { +public: + WebAssembly(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +private: + bool IsMathErrnoDefault() const override; + bool IsObjCNonFragileABIDefault() const override; + bool UseObjCMixedDispatch() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + bool IsIntegratedAssemblerDefault() const override; + bool hasBlocksRuntime() const override; + bool SupportsObjCGC() const override; + bool SupportsProfiling() const override; + bool HasNativeLLVMSupport() const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + Tool *buildLinker() const override; +}; + +class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { +public: + PS4CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsMathErrnoDefault() const override { return false; } + bool IsObjCNonFragileABIDefault() const override { return true; } + bool HasNativeLLVMSupport() const override; + bool isPICDefault() const override; + + unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { + return 2; // SSPStrong + } + + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::SCE; + } + + SanitizerMask getSupportedSanitizers() const override; + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + } // end namespace toolchains } // end namespace driver } // end namespace clang -#endif +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index b801705..7a185dc 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1,4 +1,4 @@ -//===--- Tools.cpp - Tools Implementations --------------------------------===// +//===--- Tools.cpp - Tools Implementations ----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -32,7 +32,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -41,6 +41,7 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetParser.h" #ifdef LLVM_ON_UNIX #include <unistd.h> // For getuid(). @@ -51,18 +52,51 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -static void addAssemblerKPIC(const ArgList &Args, ArgStringList &CmdArgs) { - Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie); - if (!LastPICArg) - return; - if (LastPICArg->getOption().matches(options::OPT_fPIC) || - LastPICArg->getOption().matches(options::OPT_fpic) || - LastPICArg->getOption().matches(options::OPT_fPIE) || - LastPICArg->getOption().matches(options::OPT_fpie)) { - CmdArgs.push_back("-KPIC"); +static void handleTargetFeaturesGroup(const ArgList &Args, + std::vector<const char *> &Features, + OptSpecifier Group) { + for (const Arg *A : Args.filtered(Group)) { + StringRef Name = A->getOption().getName(); + A->claim(); + + // Skip over "-m". + assert(Name.startswith("m") && "Invalid feature name."); + Name = Name.substr(1); + + bool IsNegative = Name.startswith("no-"); + if (IsNegative) + Name = Name.substr(3); + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + } +} + +static const char *getSparcAsmModeForCPU(StringRef Name, + const llvm::Triple &Triple) { + if (Triple.getArch() == llvm::Triple::sparcv9) { + return llvm::StringSwitch<const char *>(Name) + .Case("niagara", "-Av9b") + .Case("niagara2", "-Av9b") + .Case("niagara3", "-Av9d") + .Case("niagara4", "-Av9d") + .Default("-Av9"); + } else { + return llvm::StringSwitch<const char *>(Name) + .Case("v8", "-Av8") + .Case("supersparc", "-Av8") + .Case("sparclite", "-Asparclite") + .Case("f934", "-Asparclite") + .Case("hypersparc", "-Av8") + .Case("sparclite86x", "-Asparclite") + .Case("sparclet", "-Asparclet") + .Case("tsc701", "-Asparclet") + .Case("v9", "-Av8plus") + .Case("ultrasparc", "-Av8plus") + .Case("ultrasparc3", "-Av8plus") + .Case("niagara", "-Av8plusb") + .Case("niagara2", "-Av8plusb") + .Case("niagara3", "-Av8plusd") + .Case("niagara4", "-Av8plusd") + .Default("-Av8"); } } @@ -199,13 +233,9 @@ static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (const auto &II : Inputs) { - if (!TC.HasNativeLLVMSupport()) { + if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) // Don't try to pass LLVM inputs unless we have native support. - if (II.getType() == types::TY_LLVM_IR || - II.getType() == types::TY_LTO_IR || - II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) - D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); - } + D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); // Add filenames immediately. if (II.isFilename()) { @@ -262,7 +292,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, - const InputInfoList &Inputs) const { + const InputInfoList &Inputs, + const ToolChain *AuxToolChain) const { Arg *A; CheckPreprocessingOptions(D, Args); @@ -412,11 +443,11 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); - Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F, - options::OPT_index_header_map); + Args.AddAllArgs(CmdArgs, + {options::OPT_D, options::OPT_U, options::OPT_I_Group, + options::OPT_F, options::OPT_index_header_map}); - // Add -Wp, and -Xassembler if using the preprocessor. + // Add -Wp, and -Xpreprocessor if using the preprocessor. // FIXME: There is a very unfortunate problem here, some troubled // souls abuse -Wp, to pass preprocessor options in gcc syntax. To @@ -454,12 +485,26 @@ 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. + // Add C++ include arguments, if needed. - if (types::isCXX(Inputs[0].getType())) + if (types::isCXX(Inputs[0].getType())) { getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + if (AuxToolChain) + AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + } // Add system include arguments. getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs); + if (AuxToolChain) + AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + + // Add CUDA include arguments, if needed. + if (types::isCuda(Inputs[0].getType())) + getToolChain().AddCudaIncludeArgs(Args, CmdArgs); } // FIXME: Move to target hook. @@ -498,6 +543,8 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) { return false; case llvm::Triple::xcore: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: return true; } } @@ -507,13 +554,13 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) { // Get SubArch (vN). static int getARMSubArchVersionNumber(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); - return llvm::ARMTargetParser::parseArchVersion(Arch); + return llvm::ARM::parseArchVersion(Arch); } // True if M-profile. static bool isARMMProfile(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); - unsigned Profile = llvm::ARMTargetParser::parseArchProfile(Arch); + unsigned Profile = llvm::ARM::parseArchProfile(Arch); return Profile == llvm::ARM::PK_M; } @@ -542,19 +589,8 @@ static void getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, static void getARMHWDivFeatures(const Driver &D, const Arg *A, const ArgList &Args, StringRef HWDiv, std::vector<const char *> &Features) { - if (HWDiv == "arm") { - Features.push_back("+hwdiv-arm"); - Features.push_back("-hwdiv"); - } else if (HWDiv == "thumb") { - Features.push_back("-hwdiv-arm"); - Features.push_back("+hwdiv"); - } else if (HWDiv == "arm,thumb" || HWDiv == "thumb,arm") { - Features.push_back("+hwdiv-arm"); - Features.push_back("+hwdiv"); - } else if (HWDiv == "none") { - Features.push_back("-hwdiv-arm"); - Features.push_back("-hwdiv"); - } else + unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv); + if (!llvm::ARM::getHWDivFeatures(HWDivID, Features)) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -562,82 +598,125 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A, static void getARMFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args, StringRef FPU, std::vector<const char *> &Features) { - unsigned FPUID = llvm::ARMTargetParser::parseFPU(FPU); - if (!llvm::ARMTargetParser::getFPUFeatures(FPUID, Features)) + unsigned FPUID = llvm::ARM::parseFPU(FPU); + if (!llvm::ARM::getFPUFeatures(FPUID, Features)) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } +// Decode ARM features from string like +[no]featureA+[no]featureB+... +static bool DecodeARMFeatures(const Driver &D, StringRef text, + std::vector<const char *> &Features) { + SmallVector<StringRef, 8> Split; + text.split(Split, StringRef("+"), -1, false); + + for (StringRef Feature : Split) { + const char *FeatureName = llvm::ARM::getArchExtFeature(Feature); + if (FeatureName) + Features.push_back(FeatureName); + else + return false; + } + return true; +} + // Check if -march is valid by checking if it can be canonicalised and parsed. // getARMArch is used here instead of just checking the -march value in order // to handle -march=native correctly. static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef ArchName, + std::vector<const char *> &Features, const llvm::Triple &Triple) { + std::pair<StringRef, StringRef> Split = ArchName.split("+"); + std::string MArch = arm::getARMArch(ArchName, Triple); - if (llvm::ARMTargetParser::parseArch(MArch) == llvm::ARM::AK_INVALID) + if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID || + (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } // Check -mcpu=. Needs ArchName to handle -mcpu=generic. static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef CPUName, llvm::StringRef ArchName, + std::vector<const char *> &Features, const llvm::Triple &Triple) { + std::pair<StringRef, StringRef> Split = CPUName.split("+"); + std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); - std::string Arch = arm::getARMArch(ArchName, Triple); - if (strcmp(arm::getLLVMArchSuffixForARM(CPU, Arch), "") == 0) + if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() || + (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } +static bool useAAPCSForMachO(const llvm::Triple &T) { + // The backend is hardwired to assume AAPCS for M-class processors, ensure + // the frontend matches that. + return T.getEnvironment() == llvm::Triple::EABI || + T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T); +} + // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. -StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args, - const llvm::Triple &Triple) { - StringRef FloatABI; +arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { + const Driver &D = TC.getDriver(); + const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(Args)); + auto SubArch = getARMSubArchVersionNumber(Triple); + arm::FloatABI ABI = FloatABI::Invalid; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { - if (A->getOption().matches(options::OPT_msoft_float)) - FloatABI = "soft"; - else if (A->getOption().matches(options::OPT_mhard_float)) - FloatABI = "hard"; - else { - FloatABI = A->getValue(); - if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") { + if (A->getOption().matches(options::OPT_msoft_float)) { + ABI = FloatABI::Soft; + } else if (A->getOption().matches(options::OPT_mhard_float)) { + ABI = FloatABI::Hard; + } else { + ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue()) + .Case("soft", FloatABI::Soft) + .Case("softfp", FloatABI::SoftFP) + .Case("hard", FloatABI::Hard) + .Default(FloatABI::Invalid); + if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); - FloatABI = "soft"; + ABI = FloatABI::Soft; } } + + // It is incorrect to select hard float ABI on MachO platforms if the ABI is + // "apcs-gnu". + if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple) && + ABI == FloatABI::Hard) { + D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) + << Triple.getArchName(); + } } // If unspecified, choose the default based on the platform. - if (FloatABI.empty()) { + if (ABI == FloatABI::Invalid) { switch (Triple.getOS()) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: - case llvm::Triple::IOS: { + case llvm::Triple::IOS: + case llvm::Triple::TvOS: { // Darwin defaults to "softfp" for v6 and v7. - // - if (getARMSubArchVersionNumber(Triple) == 6 || - getARMSubArchVersionNumber(Triple) == 7) - FloatABI = "softfp"; - else - FloatABI = "soft"; + ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; break; } + case llvm::Triple::WatchOS: + ABI = FloatABI::Hard; + break; // FIXME: this is invalid for WindowsCE case llvm::Triple::Win32: - FloatABI = "hard"; + ABI = FloatABI::Hard; break; case llvm::Triple::FreeBSD: switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: - FloatABI = "hard"; + ABI = FloatABI::Hard; break; default: // FreeBSD defaults to soft float - FloatABI = "soft"; + ABI = FloatABI::Soft; break; } break; @@ -645,28 +724,20 @@ StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args, default: switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: - FloatABI = "hard"; - break; - case llvm::Triple::GNUEABI: - FloatABI = "softfp"; - break; case llvm::Triple::EABIHF: - FloatABI = "hard"; + ABI = FloatABI::Hard; break; + case llvm::Triple::GNUEABI: case llvm::Triple::EABI: // EABI is always AAPCS, and if it was not marked 'hard', it's softfp - FloatABI = "softfp"; + ABI = FloatABI::SoftFP; break; - case llvm::Triple::Android: { - if (getARMSubArchVersionNumber(Triple) == 7) - FloatABI = "softfp"; - else - FloatABI = "soft"; + case llvm::Triple::Android: + ABI = (SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; break; - } default: // Assume "soft", but warn the user we are guessing. - FloatABI = "soft"; + ABI = FloatABI::Soft; if (Triple.getOS() != llvm::Triple::UnknownOS || !Triple.isOSBinFormatMachO()) D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; @@ -675,16 +746,20 @@ StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args, } } - return FloatABI; + assert(ABI != FloatABI::Invalid && "must select an ABI"); + return ABI; } -static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, +static void getARMTargetFeatures(const ToolChain &TC, + const llvm::Triple &Triple, const ArgList &Args, std::vector<const char *> &Features, bool ForAS) { + const Driver &D = TC.getDriver(); + bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); - StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); + arm::FloatABI ABI = arm::getARMFloatABI(TC, Args); const Arg *WaCPU = nullptr, *WaFPU = nullptr; const Arg *WaHDiv = nullptr, *WaArch = nullptr; @@ -702,11 +777,11 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, // assembler and the frontend behave the same. // Use software floating point operations? - if (FloatABI == "soft") + if (ABI == arm::FloatABI::Soft) Features.push_back("+soft-float"); // Use software floating point argument passing? - if (FloatABI != "hard") + if (ABI != arm::FloatABI::Hard) Features.push_back("+soft-float-abi"); } else { // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down @@ -726,29 +801,6 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, } } - // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. - const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); - if (WaFPU) { - if (FPUArg) - D.Diag(clang::diag::warn_drv_unused_argument) - << FPUArg->getAsString(Args); - getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), - Features); - } else if (FPUArg) { - getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); - } - - // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. - const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); - if (WaHDiv) { - if (HDivArg) - D.Diag(clang::diag::warn_drv_unused_argument) - << HDivArg->getAsString(Args); - getARMHWDivFeatures(D, WaHDiv, Args, - StringRef(WaHDiv->getValue()).substr(8), Features); - } else if (HDivArg) - getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); - // Check -march. ClangAs gives preference to -Wa,-march=. const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); StringRef ArchName; @@ -757,12 +809,12 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, D.Diag(clang::diag::warn_drv_unused_argument) << ArchArg->getAsString(Args); ArchName = StringRef(WaArch->getValue()).substr(7); - checkARMArchName(D, WaArch, Args, ArchName, Triple); + checkARMArchName(D, WaArch, Args, ArchName, Features, Triple); // FIXME: Set Arch. D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args); } else if (ArchArg) { ArchName = ArchArg->getValue(); - checkARMArchName(D, ArchArg, Args, ArchName, Triple); + checkARMArchName(D, ArchArg, Args, ArchName, Features, Triple); } // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. @@ -773,15 +825,47 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, D.Diag(clang::diag::warn_drv_unused_argument) << CPUArg->getAsString(Args); CPUName = StringRef(WaCPU->getValue()).substr(6); - checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Triple); + checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple); } else if (CPUArg) { CPUName = CPUArg->getValue(); - checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Triple); + checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple); } + // Add CPU features for generic CPUs + if (CPUName == "native") { + llvm::StringMap<bool> HostFeatures; + if (llvm::sys::getHostCPUFeatures(HostFeatures)) + for (auto &F : HostFeatures) + Features.push_back( + Args.MakeArgString((F.second ? "+" : "-") + F.first())); + } + + // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. + const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); + if (WaFPU) { + if (FPUArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << FPUArg->getAsString(Args); + getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), + Features); + } else if (FPUArg) { + getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); + } + + // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. + const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); + if (WaHDiv) { + if (HDivArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << HDivArg->getAsString(Args); + getARMHWDivFeatures(D, WaHDiv, Args, + StringRef(WaHDiv->getValue()).substr(8), Features); + } else if (HDivArg) + getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); + // Setting -msoft-float effectively disables NEON because of the GCC // implementation, although the same isn't true of VFP or VFP3. - if (FloatABI == "soft") { + if (ABI == arm::FloatABI::Soft) { Features.push_back("-neon"); // Also need to explicitly disable features which imply NEON. Features.push_back("-crypto"); @@ -806,31 +890,72 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, options::OPT_mno_long_calls)) { if (A->getOption().matches(options::OPT_mlong_calls)) Features.push_back("+long-calls"); - } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6))) { + } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) && + !Triple.isWatchOS()) { Features.push_back("+long-calls"); } -} -void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, - bool KernelOrKext) const { - const Driver &D = getToolChain().getDriver(); - // Get the effective triple, which takes into account the deployment target. - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); - llvm::Triple Triple(TripleStr); + // Kernel code has more strict alignment requirements. + if (KernelOrKext) + Features.push_back("+strict-align"); + else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, + options::OPT_munaligned_access)) { + if (A->getOption().matches(options::OPT_munaligned_access)) { + // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). + if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) + D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; + } else + Features.push_back("+strict-align"); + } else { + // Assume pre-ARMv6 doesn't support unaligned accesses. + // + // ARMv6 may or may not support unaligned accesses depending on the + // SCTLR.U bit, which is architecture-specific. We assume ARMv6 + // Darwin and NetBSD targets support unaligned accesses, and others don't. + // + // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit + // which raises an alignment fault on unaligned accesses. Linux + // defaults this bit to 0 and handles it as a system-wide (not + // per-process) setting. It is therefore safe to assume that ARMv7+ + // Linux targets support unaligned accesses. The same goes for NaCl. + // + // The above behavior is consistent with GCC. + int VersionNum = getARMSubArchVersionNumber(Triple); + if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { + if (VersionNum < 6 || + Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) + Features.push_back("+strict-align"); + } else if (Triple.isOSLinux() || Triple.isOSNaCl()) { + if (VersionNum < 7) + Features.push_back("+strict-align"); + } else + Features.push_back("+strict-align"); + } + // llvm does not support reserving registers in general. There is support + // for reserving r9 on ARM though (defined as a platform-specific register + // in ARM EABI). + if (Args.hasArg(options::OPT_ffixed_r9)) + Features.push_back("+reserve-r9"); + + // The kext linker doesn't know how to deal with movw/movt. + if (KernelOrKext) + Features.push_back("+no-movt"); +} + +void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, + ArgStringList &CmdArgs, bool KernelOrKext) const { // Select the ABI to use. - // // FIXME: Support -meabi. // FIXME: Parts of this are duplicated in the backend, unify this somehow. const char *ABIName = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); } else if (Triple.isOSBinFormatMachO()) { - // The backend is hardwired to assume AAPCS for M-class processors, ensure - // the frontend matches that. - if (Triple.getEnvironment() == llvm::Triple::EABI || - Triple.getOS() == llvm::Triple::UnknownOS || isARMMProfile(Triple)) { + if (useAAPCSForMachO(Triple)) { ABIName = "aapcs"; + } else if (Triple.isWatchOS()) { + ABIName = "aapcs16"; } else { ABIName = "apcs-gnu"; } @@ -861,50 +986,24 @@ void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back(ABIName); // Determine floating point ABI from the options & target defaults. - StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); - if (FloatABI == "soft") { + arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); + if (ABI == arm::FloatABI::Soft) { // Floating point operations and argument passing are soft. - // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); - } else if (FloatABI == "softfp") { + } else if (ABI == arm::FloatABI::SoftFP) { // Floating point operations are hard, but argument passing is soft. CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. - assert(FloatABI == "hard" && "Invalid float abi!"); + assert(ABI == arm::FloatABI::Hard && "Invalid float abi!"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } - // Kernel code has more strict alignment requirements. - if (KernelOrKext) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-strict-align"); - - // The kext linker doesn't know how to deal with movw/movt. - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-use-movt=0"); - } - - // -mkernel implies -mstrict-align; don't add the redundant option. - if (!KernelOrKext) { - if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, - options::OPT_munaligned_access)) { - CmdArgs.push_back("-backend-option"); - if (A->getOption().matches(options::OPT_mno_unaligned_access)) - CmdArgs.push_back("-arm-strict-align"); - else { - if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) - D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; - CmdArgs.push_back("-arm-no-strict-align"); - } - } - } - // Forward the -mglobal-merge option for explicit control over the pass. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { @@ -918,14 +1017,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, if (!Args.hasFlag(options::OPT_mimplicit_float, options::OPT_mno_implicit_float, true)) CmdArgs.push_back("-no-implicit-float"); - - // llvm does not support reserving registers in general. There is support - // for reserving r9 on ARM though (defined as a platform-specific register - // in ARM EABI). - if (Args.hasArg(options::OPT_ffixed_r9)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-reserve-r9"); - } } // ARM tools end. @@ -936,7 +1027,7 @@ static std::string getAArch64TargetCPU(const ArgList &Args) { std::string CPU; // If we have -mtune or -mcpu, use that. if ((A = Args.getLastArg(options::OPT_mtune_EQ))) { - CPU = A->getValue(); + CPU = StringRef(A->getValue()).lower(); } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { StringRef Mcpu = A->getValue(); CPU = Mcpu.split("+").first.lower(); @@ -981,15 +1072,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); - if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, - options::OPT_munaligned_access)) { - CmdArgs.push_back("-backend-option"); - if (A->getOption().matches(options::OPT_mno_unaligned_access)) - CmdArgs.push_back("-aarch64-strict-align"); - else - CmdArgs.push_back("-aarch64-no-strict-align"); - } - if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, options::OPT_mno_fix_cortex_a53_835769)) { CmdArgs.push_back("-backend-option"); @@ -997,7 +1079,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); else CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); - } else if (Triple.getEnvironment() == llvm::Triple::Android) { + } else if (Triple.isAndroid()) { // Enabled A53 errata (835769) workaround by default on android CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); @@ -1012,11 +1094,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, else CmdArgs.push_back("-aarch64-global-merge=true"); } - - if (Args.hasArg(options::OPT_ffixed_x18)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-aarch64-reserve-x18"); - } } // Get CPU and ABI names. They are not independent @@ -1034,6 +1111,10 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, DefMips64CPU = "mips64r6"; } + // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android). + if (Triple.isAndroid()) + DefMips64CPU = "mips64r6"; + // MIPS3 is the default for mips64*-unknown-openbsd. if (Triple.getOS() == llvm::Triple::OpenBSD) DefMips64CPU = "mips3"; @@ -1087,6 +1168,16 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, // FIXME: Warn on inconsistent use of -march and -mabi. } +std::string mips::getMipsABILibSuffix(const ArgList &Args, + const llvm::Triple &Triple) { + StringRef CPUName, ABIName; + tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + return llvm::StringSwitch<std::string>(ABIName) + .Case("o32", "") + .Case("n32", "32") + .Case("n64", "64"); +} + // Convert ABI name to the GNU tools acceptable variant. static StringRef getGnuCompatibleMipsABIName(StringRef ABI) { return llvm::StringSwitch<llvm::StringRef>(ABI) @@ -1097,33 +1188,37 @@ static StringRef getGnuCompatibleMipsABIName(StringRef ABI) { // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, // and -mfloat-abi=. -static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { - StringRef FloatABI; +static mips::FloatABI getMipsFloatABI(const Driver &D, const ArgList &Args) { + mips::FloatABI ABI = mips::FloatABI::Invalid; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) - FloatABI = "soft"; + ABI = mips::FloatABI::Soft; else if (A->getOption().matches(options::OPT_mhard_float)) - FloatABI = "hard"; + ABI = mips::FloatABI::Hard; else { - FloatABI = A->getValue(); - if (FloatABI != "soft" && FloatABI != "hard") { + ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue()) + .Case("soft", mips::FloatABI::Soft) + .Case("hard", mips::FloatABI::Hard) + .Default(mips::FloatABI::Invalid); + if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); - FloatABI = "hard"; + ABI = mips::FloatABI::Hard; } } } // If unspecified, choose the default based on the platform. - if (FloatABI.empty()) { + if (ABI == mips::FloatABI::Invalid) { // Assume "hard", because it's a default value used by gcc. // When we start to recognize specific target MIPS processors, // we will be able to select the default more correctly. - FloatABI = "hard"; + ABI = mips::FloatABI::Hard; } - return FloatABI; + assert(ABI != mips::FloatABI::Invalid && "must select an ABI"); + return ABI; } static void AddTargetFeature(const ArgList &Args, @@ -1149,8 +1244,8 @@ static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, AddTargetFeature(Args, Features, options::OPT_mno_abicalls, options::OPT_mabicalls, "noabicalls"); - StringRef FloatABI = getMipsFloatABI(D, Args); - if (FloatABI == "soft") { + mips::FloatABI FloatABI = getMipsFloatABI(D, Args); + if (FloatABI == mips::FloatABI::Soft) { // FIXME: Note, this is a hack. We need to pass the selected float // mode to the MipsTargetInfoBase to define appropriate macros there. // Now it is the only method. @@ -1222,16 +1317,15 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); - StringRef FloatABI = getMipsFloatABI(D, Args); - - if (FloatABI == "soft") { + mips::FloatABI ABI = getMipsFloatABI(D, Args); + if (ABI == mips::FloatABI::Soft) { // Floating point operations and argument passing are soft. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. - assert(FloatABI == "hard" && "Invalid float abi!"); + assert(ABI == mips::FloatABI::Hard && "Invalid float abi!"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } @@ -1331,33 +1425,54 @@ static std::string getPPCTargetCPU(const ArgList &Args) { return ""; } -static void getPPCTargetFeatures(const ArgList &Args, +static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, std::vector<const char *> &Features) { - for (const Arg *A : Args.filtered(options::OPT_m_ppc_Features_Group)) { - StringRef Name = A->getOption().getName(); - A->claim(); + handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); - // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); - Name = Name.substr(1); + ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); + if (FloatABI == ppc::FloatABI::Soft && + !(Triple.getArch() == llvm::Triple::ppc64 || + Triple.getArch() == llvm::Triple::ppc64le)) + Features.push_back("+soft-float"); + else if (FloatABI == ppc::FloatABI::Soft && + (Triple.getArch() == llvm::Triple::ppc64 || + Triple.getArch() == llvm::Triple::ppc64le)) + D.Diag(diag::err_drv_invalid_mfloat_abi) + << "soft float is not supported for ppc64"; - bool IsNegative = Name.startswith("no-"); - if (IsNegative) - Name = Name.substr(3); + // Altivec is a bit weird, allow overriding of the Altivec feature here. + AddTargetFeature(Args, Features, options::OPT_faltivec, + options::OPT_fno_altivec, "altivec"); +} - // Note that gcc calls this mfcrf and LLVM calls this mfocrf so we - // pass the correct option to the backend while calling the frontend - // option the same. - // TODO: Change the LLVM backend option maybe? - if (Name == "mfcrf") - Name = "mfocrf"; +ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) { + ppc::FloatABI ABI = ppc::FloatABI::Invalid; + if (Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ)) { + if (A->getOption().matches(options::OPT_msoft_float)) + ABI = ppc::FloatABI::Soft; + else if (A->getOption().matches(options::OPT_mhard_float)) + ABI = ppc::FloatABI::Hard; + else { + ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue()) + .Case("soft", ppc::FloatABI::Soft) + .Case("hard", ppc::FloatABI::Hard) + .Default(ppc::FloatABI::Invalid); + if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { + D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); + ABI = ppc::FloatABI::Hard; + } + } + } - Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + // If unspecified, choose the default based on the platform. + if (ABI == ppc::FloatABI::Invalid) { + ABI = ppc::FloatABI::Hard; } - // Altivec is a bit weird, allow overriding of the Altivec feature here. - AddTargetFeature(Args, Features, options::OPT_faltivec, - options::OPT_fno_altivec, "altivec"); + return ABI; } void Clang::AddPPCTargetArgs(const ArgList &Args, @@ -1396,6 +1511,21 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, if (StringRef(A->getValue()) != "altivec") ABIName = A->getValue(); + ppc::FloatABI FloatABI = + ppc::getPPCFloatABI(getToolChain().getDriver(), Args); + + if (FloatABI == ppc::FloatABI::Soft) { + // Floating point operations and argument passing are soft. + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + } else { + // Floating point operations and argument passing are hard. + assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); + } + if (ABIName) { CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); @@ -1533,7 +1663,7 @@ static const char *getX86TargetCPU(const ArgList &Args, return "btver2"; // On Android use targets compatible with gcc - if (Triple.getEnvironment() == llvm::Triple::Android) + if (Triple.isAndroid()) return Is64Bit ? "x86-64" : "i686"; // Everything else goes to x86-64 in 64-bit mode. @@ -1555,6 +1685,25 @@ static const char *getX86TargetCPU(const ArgList &Args, } } +/// Get the (LLVM) name of the WebAssembly cpu we are targeting. +static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { + // If we have -mcpu=, use that. + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPU = A->getValue(); + +#ifdef __wasm__ + // Handle "native" by examining the host. "native" isn't meaningful when + // cross compiling, so only support this when the host is also WebAssembly. + if (CPU == "native") + return llvm::sys::getHostCPUName(); +#endif + + return CPU; + } + + return "generic"; +} + static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, bool FromAs = false) { switch (T.getArch()) { @@ -1619,7 +1768,8 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, return getX86TargetCPU(Args, T); case llvm::Triple::hexagon: - return "hexagon" + toolchains::Hexagon_TC::GetTargetCPU(Args).str(); + return "hexagon" + + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); case llvm::Triple::systemz: return getSystemZTargetCPU(Args); @@ -1627,11 +1777,15 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T, case llvm::Triple::r600: case llvm::Triple::amdgcn: return getR600TargetGPU(Args); + + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + return getWebAssemblyTargetCPU(Args); } } static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, bool IsThinLTO) { // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. @@ -1647,13 +1801,29 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, std::string CPU = getCPUName(Args, ToolChain.getTriple()); if (!CPU.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); + + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + StringRef OOpt; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O)) + OOpt = A->getValue(); + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + if (!OOpt.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); + } + + if (IsThinLTO) + CmdArgs.push_back("-plugin-opt=thinlto"); } /// This is a helper function for validating the optional refinement step /// parameter in reciprocal argument strings. Return false if there is an error /// parsing the refinement step. Otherwise, return true and set the Position /// of the refinement step in the input string. -static bool getRefinementStep(const StringRef &In, const Driver &D, +static bool getRefinementStep(StringRef In, const Driver &D, const Arg &A, size_t &Position) { const char RefinementStepToken = ':'; Position = In.find(RefinementStepToken); @@ -1807,7 +1977,7 @@ static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::Triple::ArchType ArchType = Triple.getArch(); // Add features to be compatible with gcc for Android. - if (Triple.getEnvironment() == llvm::Triple::Android) { + if (Triple.isAndroid()) { if (ArchType == llvm::Triple::x86_64) { Features.push_back("+sse4.2"); Features.push_back("+popcnt"); @@ -1841,20 +2011,7 @@ static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, // Now add any that the user explicitly requested on the command line, // which may override the defaults. - for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group)) { - StringRef Name = A->getOption().getName(); - A->claim(); - - // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); - Name = Name.substr(1); - - bool IsNegative = Name.startswith("no-"); - if (IsNegative) - Name = Name.substr(3); - - Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); - } + handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group); } void Clang::AddX86TargetArgs(const ArgList &Args, @@ -1895,11 +2052,11 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, CmdArgs.push_back("-mqdsp6-compat"); CmdArgs.push_back("-Wreturn-type"); - if (const char *v = toolchains::Hexagon_TC::GetSmallDataThreshold(Args)) { - std::string SmallDataThreshold = "-hexagon-small-data-threshold="; - SmallDataThreshold += v; + if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { + std::string N = llvm::utostr(G.getValue()); + std::string Opt = std::string("-hexagon-small-data-threshold=") + N; CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold)); + CmdArgs.push_back(Args.MakeArgString(Opt)); } if (!Args.hasArg(options::OPT_fno_short_enums)) @@ -1918,16 +2075,20 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); - for (const StringRef Feature : Split) { + for (StringRef Feature : Split) { const char *result = llvm::StringSwitch<const char *>(Feature) .Case("fp", "+fp-armv8") .Case("simd", "+neon") .Case("crc", "+crc") .Case("crypto", "+crypto") + .Case("fp16", "+fullfp16") + .Case("profile", "+spe") .Case("nofp", "-fp-armv8") .Case("nosimd", "-neon") .Case("nocrc", "-crc") .Case("nocrypto", "-crypto") + .Case("nofp16", "-fullfp16") + .Case("noprofile", "-spe") .Default(nullptr); if (result) Features.push_back(result); @@ -1946,7 +2107,7 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57" || - CPU == "cortex-a72") { + CPU == "cortex-a72" || CPU == "cortex-a35") { Features.push_back("+neon"); Features.push_back("+crc"); Features.push_back("+crypto"); @@ -1973,6 +2134,8 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, // ok, no additional features. } else if (Split.first == "armv8.1-a" || Split.first == "armv8.1a") { Features.push_back("+v8.1a"); + } else if (Split.first == "armv8.2-a" || Split.first == "armv8.2a" ) { + Features.push_back("+v8.2a"); } else { return false; } @@ -1999,10 +2162,11 @@ static bool getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector<const char *> &Features) { + std::string MtuneLowerCase = Mtune.lower(); // Handle CPU name is 'native'. - if (Mtune == "native") - Mtune = llvm::sys::getHostCPUName(); - if (Mtune == "cyclone") { + if (MtuneLowerCase == "native") + MtuneLowerCase = llvm::sys::getHostCPUName(); + if (MtuneLowerCase == "cyclone") { Features.push_back("+zcm"); Features.push_back("+zcz"); } @@ -2062,11 +2226,51 @@ static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, else Features.push_back("-crc"); } + + if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, + options::OPT_munaligned_access)) + if (A->getOption().matches(options::OPT_mno_unaligned_access)) + Features.push_back("+strict-align"); + + if (Args.hasArg(options::OPT_ffixed_x18)) + Features.push_back("+reserve-x18"); } -static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, +static void getHexagonTargetFeatures(const ArgList &Args, + std::vector<const char *> &Features) { + bool HasHVX = false, HasHVXD = false; + + // FIXME: This should be able to use handleTargetFeaturesGroup except it is + // doing dependent option handling here rather than in initFeatureMap or a + // similar handler. + for (auto &A : Args) { + auto &Opt = A->getOption(); + if (Opt.matches(options::OPT_mhexagon_hvx)) + HasHVX = true; + else if (Opt.matches(options::OPT_mno_hexagon_hvx)) + HasHVXD = HasHVX = false; + else if (Opt.matches(options::OPT_mhexagon_hvx_double)) + HasHVXD = HasHVX = true; + else if (Opt.matches(options::OPT_mno_hexagon_hvx_double)) + HasHVXD = false; + else + continue; + A->claim(); + } + + Features.push_back(HasHVX ? "+hvx" : "-hvx"); + Features.push_back(HasHVXD ? "+hvx-double" : "-hvx-double"); +} + +static void getWebAssemblyTargetFeatures(const ArgList &Args, + std::vector<const char *> &Features) { + handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); +} + +static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool ForAS) { + const Driver &D = TC.getDriver(); std::vector<const char *> Features; switch (Triple.getArch()) { default: @@ -2082,13 +2286,13 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - getARMTargetFeatures(D, Triple, Args, Features, ForAS); + getARMTargetFeatures(TC, Triple, Args, Features, ForAS); break; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: - getPPCTargetFeatures(Args, Features); + getPPCTargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::systemz: getSystemZTargetFeatures(Args, Features); @@ -2101,6 +2305,13 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::x86_64: getX86TargetFeatures(D, Triple, Args, Features); break; + case llvm::Triple::hexagon: + getHexagonTargetFeatures(Args, Features); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + getWebAssemblyTargetFeatures(Args, Features); + break; } // Find the last of each feature. @@ -2272,6 +2483,67 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } +// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases +// to the corresponding DebugInfoKind. +static CodeGenOptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { + assert(A.getOption().matches(options::OPT_gN_Group) && + "Not a -g option that specifies a debug-info level"); + if (A.getOption().matches(options::OPT_g0) || + A.getOption().matches(options::OPT_ggdb0)) + return CodeGenOptions::NoDebugInfo; + if (A.getOption().matches(options::OPT_gline_tables_only) || + A.getOption().matches(options::OPT_ggdb1)) + return CodeGenOptions::DebugLineTablesOnly; + return CodeGenOptions::LimitedDebugInfo; +} + +// Extract the integer N from a string spelled "-dwarf-N", returning 0 +// on mismatch. The StringRef input (rather than an Arg) allows +// for use by the "-Xassembler" option parser. +static unsigned DwarfVersionNum(StringRef ArgValue) { + return llvm::StringSwitch<unsigned>(ArgValue) + .Case("-gdwarf-2", 2) + .Case("-gdwarf-3", 3) + .Case("-gdwarf-4", 4) + .Case("-gdwarf-5", 5) + .Default(0); +} + +static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, + CodeGenOptions::DebugInfoKind DebugInfoKind, + unsigned DwarfVersion, + llvm::DebuggerKind DebuggerTuning) { + switch (DebugInfoKind) { + case CodeGenOptions::DebugLineTablesOnly: + CmdArgs.push_back("-debug-info-kind=line-tables-only"); + break; + case CodeGenOptions::LimitedDebugInfo: + CmdArgs.push_back("-debug-info-kind=limited"); + break; + case CodeGenOptions::FullDebugInfo: + CmdArgs.push_back("-debug-info-kind=standalone"); + break; + default: + break; + } + if (DwarfVersion > 0) + CmdArgs.push_back( + Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); + switch (DebuggerTuning) { + case llvm::DebuggerKind::GDB: + CmdArgs.push_back("-debugger-tuning=gdb"); + break; + case llvm::DebuggerKind::LLDB: + CmdArgs.push_back("-debugger-tuning=lldb"); + break; + case llvm::DebuggerKind::SCE: + CmdArgs.push_back("-debugger-tuning=sce"); + break; + default: + break; + } +} + static void CollectArgsForIntegratedAssembler(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, @@ -2279,6 +2551,15 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, if (UseRelaxAll(C, Args)) CmdArgs.push_back("-mrelax-all"); + // Only default to -mincremental-linker-compatible if we think we are + // targeting the MSVC linker. + bool DefaultIncrementalLinkerCompatible = + C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); + if (Args.hasFlag(options::OPT_mincremental_linker_compatible, + options::OPT_mno_incremental_linker_compatible, + DefaultIncrementalLinkerCompatible)) + CmdArgs.push_back("-mincremental-linker-compatible"); + // When passing -I arguments to the assembler we sometimes need to // unconditionally take the next argument. For example, when parsing // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the @@ -2293,13 +2574,43 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { A->claim(); - for (const StringRef Value : A->getValues()) { + for (StringRef Value : A->getValues()) { if (TakeNextArg) { CmdArgs.push_back(Value.data()); TakeNextArg = false; continue; } + switch (C.getDefaultToolChain().getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + if (Value == "--trap") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+use-tcc-in-div"); + continue; + } + if (Value == "--break") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-use-tcc-in-div"); + continue; + } + if (Value.startswith("-msoft-float")) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+soft-float"); + continue; + } + if (Value.startswith("-mhard-float")) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-soft-float"); + continue; + } + break; + } + if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. } else if (Value == "-L") { @@ -2321,7 +2632,15 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, if (Value == "-I") TakeNextArg = true; } else if (Value.startswith("-gdwarf-")) { - CmdArgs.push_back(Value.data()); + // "-gdwarf-N" options are not cc1as options. + unsigned DwarfVersion = DwarfVersionNum(Value); + if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. + CmdArgs.push_back(Value.data()); + } else { + RenderDebugEnablingArgs( + Args, CmdArgs, CodeGenOptions::LimitedDebugInfo, DwarfVersion, + llvm::DebuggerKind::Default); + } } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || Value.startswith("-mhwdiv") || Value.startswith("-march")) { // Do nothing, we'll validate it later. @@ -2339,76 +2658,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } -// Until ARM libraries are build separately, we have them all in one library -static StringRef getArchNameForCompilerRTLib(const ToolChain &TC) { - if (TC.getTriple().isWindowsMSVCEnvironment() && - TC.getArch() == llvm::Triple::x86) - return "i386"; - if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) - return "arm"; - return TC.getArchName(); -} - -static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) { - // The runtimes are located in the OS-specific resource directory. - SmallString<128> Res(TC.getDriver().ResourceDir); - const llvm::Triple &Triple = TC.getTriple(); - // TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected. - StringRef OSLibName = - (Triple.getOS() == llvm::Triple::FreeBSD) ? "freebsd" : TC.getOS(); - llvm::sys::path::append(Res, "lib", OSLibName); - return Res; -} - -SmallString<128> tools::getCompilerRT(const ToolChain &TC, StringRef Component, - bool Shared) { - const char *Env = TC.getTriple().getEnvironment() == llvm::Triple::Android - ? "-android" - : ""; - - bool IsOSWindows = TC.getTriple().isOSWindows(); - bool IsITANMSVCWindows = TC.getTriple().isWindowsMSVCEnvironment() || - TC.getTriple().isWindowsItaniumEnvironment(); - StringRef Arch = getArchNameForCompilerRTLib(TC); - const char *Prefix = IsITANMSVCWindows ? "" : "lib"; - const char *Suffix = - Shared ? (IsOSWindows ? ".dll" : ".so") : (IsITANMSVCWindows ? ".lib" : ".a"); - - SmallString<128> Path = getCompilerRTLibDir(TC); - llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + - Arch + Env + Suffix); - - return Path; -} - // This adds the static libclang_rt.builtins-arch.a directly to the command line // FIXME: Make sure we can also emit shared objects if they're requested // and available, check for possible errors, etc. static void addClangRT(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "builtins"))); - - if (!TC.getTriple().isOSWindows()) { - // FIXME: why do we link against gcc when we are using compiler-rt? - CmdArgs.push_back("-lgcc_s"); - if (TC.getDriver().CCCIsCXX()) - CmdArgs.push_back("-lgcc_eh"); - } -} - -static void addProfileRT(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, - false) || - Args.hasArg(options::OPT_fprofile_generate) || - Args.hasArg(options::OPT_fprofile_generate_EQ) || - Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || - Args.hasArg(options::OPT_fcreate_profile) || - Args.hasArg(options::OPT_coverage))) - return; - - CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "profile"))); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); } namespace { @@ -2487,11 +2742,9 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, bool IsShared) { // Static runtimes must be forced into executable, so we wrap them in // whole-archive. - if (!IsShared) - CmdArgs.push_back("-whole-archive"); - CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Sanitizer, IsShared))); - if (!IsShared) - CmdArgs.push_back("-no-whole-archive"); + if (!IsShared) CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); + if (!IsShared) CmdArgs.push_back("-no-whole-archive"); } // Tries to use a file with the list of dynamic symbols that need to be exported @@ -2499,7 +2752,7 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { - SmallString<128> SanRT = getCompilerRT(TC, Sanitizer); + SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); if (llvm::sys::fs::exists(SanRT + ".syms")) { CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); return true; @@ -2532,8 +2785,7 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, } // Collect static runtimes. - if (Args.hasArg(options::OPT_shared) || - (TC.getTriple().getEnvironment() == llvm::Triple::Android)) { + if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) { // Don't link static runtimes into DSOs or if compiling for Android. return; } @@ -2567,6 +2819,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, } if (SanArgs.needsSafeStackRt()) StaticRuntimes.push_back("safestack"); + if (SanArgs.needsCfiRt()) + StaticRuntimes.push_back("cfi"); + if (SanArgs.needsCfiDiagRt()) + StaticRuntimes.push_back("cfi_diag"); } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, @@ -2603,9 +2859,15 @@ static bool areOptimizationsEnabled(const ArgList &Args) { static bool shouldUseFramePointerForTarget(const ArgList &Args, const llvm::Triple &Triple) { - // XCore never wants frame pointers, regardless of OS. - if (Triple.getArch() == llvm::Triple::xcore) { + switch (Triple.getArch()) { + case llvm::Triple::xcore: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + // XCore never wants frame pointers, regardless of OS. + // WebAssembly never wants frame pointers. return false; + default: + break; } if (Triple.isOSLinux()) { @@ -2628,6 +2890,10 @@ static bool shouldUseFramePointerForTarget(const ArgList &Args, switch (Triple.getArch()) { case llvm::Triple::x86: return !areOptimizationsEnabled(Args); + case llvm::Triple::arm: + case llvm::Triple::thumb: + // Windows on ARM builds with FPO disabled to aid fast stack walking + return true; default: // All other supported Windows ISAs use xdata unwind information, so frame // pointers are not generally useful. @@ -2643,6 +2909,8 @@ static bool shouldUseFramePointer(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) return A->getOption().matches(options::OPT_fno_omit_frame_pointer); + if (Args.hasArg(options::OPT_pg)) + return true; return shouldUseFramePointerForTarget(Args, Triple); } @@ -2652,6 +2920,8 @@ static bool shouldUseLeafFramePointer(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, options::OPT_momit_leaf_frame_pointer)) return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); + if (Args.hasArg(options::OPT_pg)) + return true; if (Triple.isPS4CPU()) return false; @@ -2700,12 +2970,13 @@ static void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, ExtractArgs.push_back(OutFile); const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy")); + InputInfo II(Output.getFilename(), types::TY_Object, Output.getFilename()); // First extract the dwo sections. - C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs)); + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II)); // Then remove them from the original .o file. - C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs)); + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs, II)); } /// \brief Vectorize at all optimization levels greater than 1 except for -Oz. @@ -2774,6 +3045,7 @@ static VersionTuple getMSCompatibilityVersion(unsigned Version) { static void claimNoWarnArgs(const ArgList &Args) { // Don't warn about unused -f(no-)?lto. This can happen when we're // preprocessing, precompiling or assembling. + Args.ClaimAllArgs(options::OPT_flto_EQ); Args.ClaimAllArgs(options::OPT_flto); Args.ClaimAllArgs(options::OPT_fno_lto); } @@ -2863,42 +3135,53 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, 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_generate_EQ, + options::OPT_fno_profile_instr_generate); + if (ProfileGenerateArg && + ProfileGenerateArg->getOption().matches( + options::OPT_fno_profile_instr_generate)) + ProfileGenerateArg = nullptr; auto *ProfileUseArg = Args.getLastArg( options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, - options::OPT_fprofile_use, options::OPT_fprofile_use_EQ); + options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, + options::OPT_fno_profile_instr_use); + if (ProfileUseArg && + ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) + ProfileUseArg = nullptr; if (ProfileGenerateArg && ProfileUseArg) D.Diag(diag::err_drv_argument_not_allowed_with) << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling(); - if (ProfileGenerateArg && - ProfileGenerateArg->getOption().matches( - options::OPT_fprofile_instr_generate_EQ)) - ProfileGenerateArg->render(Args, CmdArgs); - else if (ProfileGenerateArg && - ProfileGenerateArg->getOption().matches( - options::OPT_fprofile_generate_EQ)) { - SmallString<128> Path(ProfileGenerateArg->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); - - if (ProfileUseArg && - ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) - ProfileUseArg->render(Args, CmdArgs); - else if (ProfileUseArg && - (ProfileUseArg->getOption().matches(options::OPT_fprofile_use_EQ) || - ProfileUseArg->getOption().matches( - options::OPT_fprofile_instr_use))) { - SmallString<128> Path( - ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); - if (Path.empty() || llvm::sys::fs::is_directory(Path)) - llvm::sys::path::append(Path, "default.profdata"); - CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + 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()); + 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); + } + + if (ProfileUseArg) { + if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) + ProfileUseArg->render(Args, CmdArgs); + else if ((ProfileUseArg->getOption().matches( + options::OPT_fprofile_use_EQ) || + ProfileUseArg->getOption().matches( + options::OPT_fprofile_instr_use))) { + SmallString<128> Path( + ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); + if (Path.empty() || llvm::sys::fs::is_directory(Path)) + llvm::sys::path::append(Path, "default.profdata"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + } } if (Args.hasArg(options::OPT_ftest_coverage) || @@ -2909,12 +3192,15 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, Args.hasArg(options::OPT_coverage)) CmdArgs.push_back("-femit-coverage-data"); - if (Args.hasArg(options::OPT_fcoverage_mapping) && !ProfileGenerateArg) + if (Args.hasFlag(options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, false) && + !ProfileGenerateArg) D.Diag(diag::err_drv_argument_only_allowed_with) << "-fcoverage-mapping" << "-fprofile-instr-generate"; - if (Args.hasArg(options::OPT_fcoverage_mapping)) + if (Args.hasFlag(options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, false)) CmdArgs.push_back("-fcoverage-mapping"); if (C.getArgs().hasArg(options::OPT_c) || @@ -2939,9 +3225,192 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, } } +static void addPS4ProfileRTArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasFlag(options::OPT_fprofile_generate, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_generate_EQ, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, + options::OPT_fno_profile_instr_generate, false) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage))) + CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); +} + +/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, +/// smooshes them together with platform defaults, to decide whether +/// this compile should be using PIC mode or not. Returns a tuple of +/// (RelocationModel, PICLevel, IsPIE). +static std::tuple<llvm::Reloc::Model, unsigned, bool> +ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple, + const ArgList &Args) { + // FIXME: why does this code...and so much everywhere else, use both + // ToolChain.getTriple() and Triple? + bool PIE = ToolChain.isPIEDefault(); + bool PIC = PIE || ToolChain.isPICDefault(); + // The Darwin default to use PIC does not apply when using -static. + if (ToolChain.getTriple().isOSDarwin() && Args.hasArg(options::OPT_static)) + PIE = PIC = false; + bool IsPICLevelTwo = PIC; + + bool KernelOrKext = + Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); + + // Android-specific defaults for PIC/PIE + if (ToolChain.getTriple().isAndroid()) { + switch (ToolChain.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::aarch64: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + PIC = true; // "-fpic" + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + PIC = true; // "-fPIC" + IsPICLevelTwo = true; + break; + + default: + break; + } + } + + // OpenBSD-specific defaults for PIE + if (ToolChain.getTriple().getOS() == llvm::Triple::OpenBSD) { + switch (ToolChain.getArch()) { + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::sparcel: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + IsPICLevelTwo = false; // "-fpie" + break; + + case llvm::Triple::ppc: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + IsPICLevelTwo = true; // "-fPIE" + break; + + default: + break; + } + } + + // The last argument relating to either PIC or PIE wins, and no + // other argument is used. If the last argument is any flavor of the + // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE + // option implicitly enables PIC at the same level. + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); + // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness + // is forced, then neither PIC nor PIE flags will have no effect. + if (!ToolChain.isPICDefaultForced()) { + if (LastPICArg) { + Option O = LastPICArg->getOption(); + if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { + PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); + PIC = + PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); + IsPICLevelTwo = + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); + } else { + PIE = PIC = false; + if (Triple.isPS4CPU()) { + Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); + StringRef Model = ModelArg ? ModelArg->getValue() : ""; + if (Model != "kernel") { + PIC = true; + ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) + << LastPICArg->getSpelling(); + } + } + } + } + } + + // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the + // PIC level would've been set to level 1, force it back to level 2 PIC + // instead. + if (PIC && (ToolChain.getTriple().isOSDarwin() || Triple.isPS4CPU())) + IsPICLevelTwo |= ToolChain.isPICDefault(); + + // This kernel flags are a trump-card: they will disable PIC/PIE + // generation, independent of the argument order. + if (KernelOrKext && ((!Triple.isiOS() || Triple.isOSVersionLT(6)) && + !Triple.isWatchOS())) + PIC = PIE = false; + + if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { + // This is a very special mode. It trumps the other modes, almost no one + // uses it, and it isn't even valid on any OS but Darwin. + if (!ToolChain.getTriple().isOSDarwin()) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << ToolChain.getTriple().str(); + + // FIXME: Warn when this flag trumps some other PIC or PIE flag. + + // Only a forced PIC mode can cause the actual compile to have PIC defines + // etc., no flags are sufficient. This behavior was selected to closely + // match that of llvm-gcc and Apple GCC before that. + PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); + + return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2 : 0, false); + } + + if (PIC) + return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2 : 1, PIE); + + return std::make_tuple(llvm::Reloc::Static, 0, false); +} + +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_: + return "pic"; + case llvm::Reloc::DynamicNoPIC: + return "dynamic-no-pic"; + } + llvm_unreachable("Unknown Reloc::Model kind"); +} + +static void AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, + ArgStringList &CmdArgs) { + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(ToolChain, ToolChain.getTriple(), Args); + + if (RelocationModel != llvm::Reloc::Static) + CmdArgs.push_back("-KPIC"); +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); + const llvm::Triple Triple(TripleStr); + bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); const Driver &D = getToolChain().getDriver(); @@ -2951,6 +3420,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, bool IsWindowsCygnus = getToolChain().getTriple().isWindowsCygwinEnvironment(); bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); + bool IsPS4CPU = getToolChain().getTriple().isPS4CPU(); // Check number of inputs for sanity. We need at least one input. assert(Inputs.size() >= 1 && "Must have at least one input."); @@ -2968,17 +3438,34 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add the "effective" target triple. CmdArgs.push_back("-triple"); - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); CmdArgs.push_back(Args.MakeArgString(TripleStr)); - const llvm::Triple TT(TripleStr); - if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm || - TT.getArch() == llvm::Triple::thumb)) { - unsigned Offset = TT.getArch() == llvm::Triple::arm ? 4 : 6; + 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(); + else + llvm_unreachable("Can't figure out CUDA compilation mode."); + assert(AuxToolChain != nullptr && "No aux toolchain."); + 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"); + } + + if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb)) { + unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; unsigned Version; - TT.getArchName().substr(Offset).getAsInteger(10, Version); + Triple.getArchName().substr(Offset).getAsInteger(10, Version); if (Version < 7) - D.Diag(diag::err_target_unsupported_arch) << TT.getArchName() + D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() << TripleStr; } @@ -3026,10 +3513,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else { assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); - - if (JA.getType() == types::TY_LTO_IR || JA.getType() == types::TY_LTO_BC) { - CmdArgs.push_back("-flto"); - } if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); } else if (JA.getType() == types::TY_LLVM_IR || @@ -3060,6 +3543,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // the use-list order, since serialization to bitcode is part of the flow. if (JA.getType() == types::TY_LLVM_BC) CmdArgs.push_back("-emit-llvm-uselists"); + + if (D.isUsingLTO()) + Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); + } + + if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { + if (!types::isLLVMIR(Input.getType())) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) + << "-x ir"; + Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } // We normally speed up the clang process a bit by skipping destructors at @@ -3115,6 +3608,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); + + // Default nullability checks. + CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull"); + CmdArgs.push_back( + "-analyzer-checker=nullability.NullReturnedFromNonnull"); } // Set the output format. The default is plist, for (lame) historical @@ -3136,136 +3634,29 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CheckCodeGenerationOptions(D, Args); - bool PIE = getToolChain().isPIEDefault(); - bool PIC = PIE || getToolChain().isPICDefault(); - bool IsPICLevelTwo = PIC; - - // Android-specific defaults for PIC/PIE - if (getToolChain().getTriple().getEnvironment() == llvm::Triple::Android) { - switch (getToolChain().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::aarch64: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - PIC = true; // "-fpic" - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - PIC = true; // "-fPIC" - IsPICLevelTwo = true; - break; + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Triple, Args); - default: - break; - } + const char *RMName = RelocationModelName(RelocationModel); + if (RMName) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); } - - // OpenBSD-specific defaults for PIE - if (getToolChain().getTriple().getOS() == llvm::Triple::OpenBSD) { - switch (getToolChain().getArch()) { - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::sparcel: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - IsPICLevelTwo = false; // "-fpie" - break; - - case llvm::Triple::ppc: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - IsPICLevelTwo = true; // "-fPIE" - break; - - default: - break; + 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"); } } - // For the PIC and PIE flag options, this logic is different from the - // legacy logic in very old versions of GCC, as that logic was just - // a bug no one had ever fixed. This logic is both more rational and - // consistent with GCC's new logic now that the bugs are fixed. The last - // argument relating to either PIC or PIE wins, and no other argument is - // used. If the last argument is any flavor of the '-fno-...' arguments, - // both PIC and PIE are disabled. Any PIE option implicitly enables PIC - // at the same level. - Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie); - // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness - // is forced, then neither PIC nor PIE flags will have no effect. - if (!getToolChain().isPICDefaultForced()) { - if (LastPICArg) { - Option O = LastPICArg->getOption(); - if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || - O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { - PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); - PIC = - PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); - IsPICLevelTwo = - O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); - } else { - PIE = PIC = false; - } - } - } - - // Introduce a Darwin-specific hack. If the default is PIC but the flags - // specified while enabling PIC enabled level 1 PIC, just force it back to - // level 2 PIC instead. This matches the behavior of Darwin GCC (based on my - // informal testing). - if (PIC && getToolChain().getTriple().isOSDarwin()) - IsPICLevelTwo |= getToolChain().isPICDefault(); - - // Note that these flags are trump-cards. Regardless of the order w.r.t. the - // PIC or PIE options above, if these show up, PIC is disabled. - llvm::Triple Triple(TripleStr); - if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6))) - PIC = PIE = false; - if (Args.hasArg(options::OPT_static)) - PIC = PIE = false; - - if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { - // This is a very special mode. It trumps the other modes, almost no one - // uses it, and it isn't even valid on any OS but Darwin. - if (!getToolChain().getTriple().isOSDarwin()) - D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << getToolChain().getTriple().str(); - - // FIXME: Warn when this flag trumps some other PIC or PIE flag. - - CmdArgs.push_back("-mrelocation-model"); - CmdArgs.push_back("dynamic-no-pic"); - - // Only a forced PIC mode can cause the actual compile to have PIC defines - // etc., no flags are sufficient. This behavior was selected to closely - // match that of llvm-gcc and Apple GCC before that. - if (getToolChain().isPICDefault() && getToolChain().isPICDefaultForced()) { - CmdArgs.push_back("-pic-level"); - CmdArgs.push_back("2"); - } - } else { - // Currently, LLVM only knows about PIC vs. static; the PIE differences are - // handled in Clang's IRGen by the -pie-level flag. - CmdArgs.push_back("-mrelocation-model"); - CmdArgs.push_back(PIC ? "pic" : "static"); - - if (PIC) { - CmdArgs.push_back("-pic-level"); - CmdArgs.push_back(IsPICLevelTwo ? "2" : "1"); - if (PIE) { - CmdArgs.push_back("-pie-level"); - CmdArgs.push_back(IsPICLevelTwo ? "2" : "1"); - } - } + if (Arg *A = Args.getLastArg(options::OPT_meabi)) { + CmdArgs.push_back("-meabi"); + CmdArgs.push_back(A->getValue()); } CmdArgs.push_back("-mthread-model"); @@ -3343,6 +3734,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); + if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, + options::OPT_fno_strict_vtable_pointers, + false)) + CmdArgs.push_back("-fstrict-vtable-pointers"); if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); @@ -3520,7 +3915,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (KernelOrKext && getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-fforbid-guard-variables"); - if (Args.hasArg(options::OPT_mms_bitfields)) { + if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, + false)) { CmdArgs.push_back("-mms-bitfields"); } @@ -3565,7 +3961,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Add the target features - getTargetFeatures(D, Triple, Args, CmdArgs, false); + getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, false); // Add target specific flags. switch (getToolChain().getArch()) { @@ -3576,7 +3972,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - AddARMTargetArgs(Args, CmdArgs, KernelOrKext); + // Use the effective triple, which takes into account the deployment target. + AddARMTargetArgs(Triple, Args, CmdArgs, KernelOrKext); break; case llvm::Triple::aarch64: @@ -3613,9 +4010,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; } + // The 'g' groups options involve a somewhat intricate sequence of decisions + // about what to pass from the driver to the frontend, but by the time they + // reach cc1 they've been factored into three well-defined orthogonal choices: + // * what level of debug info to generate + // * what dwarf version to write + // * what debugger tuning to use + // This avoids having to monkey around further in cc1 other than to disable + // codeview if not running in a Windows environment. Perhaps even that + // decision should be made in the driver as well though. + unsigned DwarfVersion = 0; + llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning(); + // These two are potentially updated by AddClangCLArgs. + enum CodeGenOptions::DebugInfoKind DebugInfoKind = + CodeGenOptions::NoDebugInfo; + bool EmitCodeView = false; + // Add clang-cl arguments. if (getToolChain().getDriver().IsCLMode()) - AddClangCLArgs(Args, CmdArgs); + AddClangCLArgs(Args, CmdArgs, &DebugInfoKind, &EmitCodeView); // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { @@ -3656,57 +4069,86 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, : "-"); } - // Use the last option from "-g" group. "-gline-tables-only" and "-gdwarf-x" - // are preserved, all other debug options are substituted with "-g". Args.ClaimAllArgs(options::OPT_g_Group); + Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { - if (A->getOption().matches(options::OPT_gline_tables_only) || - A->getOption().matches(options::OPT_g1)) { - // FIXME: we should support specifying dwarf version with - // -gline-tables-only. - CmdArgs.push_back("-gline-tables-only"); - // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. - const llvm::Triple &Triple = getToolChain().getTriple(); - if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || - Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::Solaris) - CmdArgs.push_back("-gdwarf-2"); - } else if (A->getOption().matches(options::OPT_gdwarf_2)) - CmdArgs.push_back("-gdwarf-2"); - else if (A->getOption().matches(options::OPT_gdwarf_3)) - CmdArgs.push_back("-gdwarf-3"); - else if (A->getOption().matches(options::OPT_gdwarf_4)) - CmdArgs.push_back("-gdwarf-4"); - else if (!A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_ggdb0)) { - // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. - const llvm::Triple &Triple = getToolChain().getTriple(); - if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || - Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::Solaris) - CmdArgs.push_back("-gdwarf-2"); - else - CmdArgs.push_back("-g"); - } + // If the last option explicitly specified a debug-info level, use it. + if (A->getOption().matches(options::OPT_gN_Group)) { + DebugInfoKind = DebugLevelToInfoKind(*A); + // 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 && + A->getIndex() > SplitDwarfArg->getIndex()) + SplitDwarfArg = nullptr; + } else + // For any other 'g' option, use Limited. + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + } + + // If a debugger tuning argument appeared, remember it. + if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, + options::OPT_ggdbN_Group)) { + if (A->getOption().matches(options::OPT_glldb)) + DebuggerTuning = llvm::DebuggerKind::LLDB; + else if (A->getOption().matches(options::OPT_gsce)) + DebuggerTuning = llvm::DebuggerKind::SCE; + else + DebuggerTuning = llvm::DebuggerKind::GDB; + } + + // If a -gdwarf argument appeared, remember it. + if (Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5)) + DwarfVersion = DwarfVersionNum(A->getSpelling()); + + // Forward -gcodeview. + // 'EmitCodeView might have been set by CL-compatibility argument parsing. + if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { + // DwarfVersion remains at 0 if no explicit choice was made. + CmdArgs.push_back("-gcodeview"); + } else if (DwarfVersion == 0 && + DebugInfoKind != CodeGenOptions::NoDebugInfo) { + DwarfVersion = getToolChain().GetDefaultDwarfVersion(); } // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. Args.ClaimAllArgs(options::OPT_g_flags_Group); + + // PS4 defaults to no column info if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default*/ true)) + /*Default=*/ !IsPS4CPU)) CmdArgs.push_back("-dwarf-column-info"); // FIXME: Move backend command line options to the module. + if (Args.hasArg(options::OPT_gmodules)) { + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + CmdArgs.push_back("-dwarf-ext-refs"); + CmdArgs.push_back("-fmodule-format=obj"); + } + // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. // FIXME: Currently only works on Linux. - if (getToolChain().getTriple().isOSLinux() && - Args.hasArg(options::OPT_gsplit_dwarf)) { - CmdArgs.push_back("-g"); + if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } + // After we've dealt with all combinations of things that could + // make DebugInfoKind be other than None or DebugLineTablesOnly, + // figure out if we need to "upgrade" it to standalone debug info. + // We parse these two '-f' options whether or not they will be used, + // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" + bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, + options::OPT_fno_standalone_debug, + getToolChain().GetDefaultStandaloneDebug()); + if (DebugInfoKind == CodeGenOptions::LimitedDebugInfo && NeedFullDebug) + DebugInfoKind = CodeGenOptions::FullDebugInfo; + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, + DebuggerTuning); + // -ggnu-pubnames turns on gnu style pubnames in the backend. if (Args.hasArg(options::OPT_ggnu_pubnames)) { CmdArgs.push_back("-backend-option"); @@ -3715,7 +4157,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -gdwarf-aranges turns on the emission of the aranges section in the // backend. - if (Args.hasArg(options::OPT_gdwarf_aranges)) { + // Always enabled on the PS4. + if (Args.hasArg(options::OPT_gdwarf_aranges) || IsPS4CPU) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-generate-arange-section"); } @@ -3747,6 +4190,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); + // Add runtime flag for PS4 when PGO or Coverage are enabled. + if (getToolChain().getTriple().isPS4CPU()) + addPS4ProfileRTArgs(getToolChain(), Args, CmdArgs); + // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { CmdArgs.push_back("-nostdsysteminc"); @@ -3839,7 +4286,8 @@ 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); + AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs, + AuxToolChain); // 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". @@ -3861,6 +4309,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, for (const Arg *A : Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) { D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args); + A->claim(); } claimNoWarnArgs(Args); @@ -3956,6 +4405,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs); + for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; + else + CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); + A->claim(); + } + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { CmdArgs.push_back("-ftemplate-depth"); @@ -4068,9 +4526,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); - Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug); - Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug); 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(); + if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, + EmulatedTLSDefault)) + CmdArgs.push_back("-femulated-tls"); // AltiVec-like language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) { Args.AddLastArg(CmdArgs, options::OPT_faltivec); @@ -4092,10 +4554,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // given, decide a default based on the target. Otherwise rely on the // options and pass the right information to the frontend. if (!Args.hasFlag(options::OPT_fopenmp_use_tls, - options::OPT_fnoopenmp_use_tls, - getToolChain().getArch() == llvm::Triple::ppc || - getToolChain().getArch() == llvm::Triple::ppc64 || - getToolChain().getArch() == llvm::Triple::ppc64le)) + options::OPT_fnoopenmp_use_tls, /*Default=*/true)) CmdArgs.push_back("-fnoopenmp-use-tls"); break; default: @@ -4134,7 +4593,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_lax_vector_conversions)) CmdArgs.push_back("-fno-lax-vector-conversions"); - if (Args.getLastArg(options::OPT_fapple_kext)) + if (Args.getLastArg(options::OPT_fapple_kext) || + (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) CmdArgs.push_back("-fapple-kext"); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); @@ -4215,14 +4675,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, - false)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-force-align-stack"); - } - if (!Args.hasFlag(options::OPT_mno_stackrealign, options::OPT_mstackrealign, - false)) { + false)) CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); - } if (Args.hasArg(options::OPT_mstack_alignment)) { StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); @@ -4238,9 +4692,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } - if (getToolChain().getArch() == llvm::Triple::aarch64 || - getToolChain().getArch() == llvm::Triple::aarch64_be) + switch (getToolChain().getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + default: + break; + } if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { @@ -4251,8 +4715,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-no-restrict-it"); } - } else if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm || - TT.getArch() == llvm::Triple::thumb)) { + } else if (Triple.isOSWindows() && + (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb)) { // Windows on ARM expects restricted IT blocks CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-restrict-it"); @@ -4268,15 +4733,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - if (Args.hasArg(options::OPT_mkernel)) { - if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType)) - CmdArgs.push_back("-fapple-kext"); - if (!Args.hasArg(options::OPT_fbuiltin)) - CmdArgs.push_back("-fno-builtin"); - Args.ClaimAllArgs(options::OPT_fno_builtin); - } - // -fbuiltin is default. - else if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin)) + // -fbuiltin is default unless -mkernel is used + if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, + !Args.hasArg(options::OPT_mkernel))) CmdArgs.push_back("-fno-builtin"); if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, @@ -4345,7 +4804,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); // -fmodule-file can be used to specify files containing precompiled modules. - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); + 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. @@ -4453,11 +4915,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // -fuse-cxa-atexit is default. - if (!Args.hasFlag(options::OPT_fuse_cxa_atexit, - options::OPT_fno_use_cxa_atexit, - !IsWindowsCygnus && !IsWindowsGNU && - getToolChain().getArch() != llvm::Triple::hexagon && - getToolChain().getArch() != llvm::Triple::xcore) || + if (!Args.hasFlag( + options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, + !IsWindowsCygnus && !IsWindowsGNU && + getToolChain().getTriple().getOS() != llvm::Triple::Solaris && + getToolChain().getArch() != llvm::Triple::hexagon && + getToolChain().getArch() != llvm::Triple::xcore && + ((getToolChain().getTriple().getVendor() != + llvm::Triple::MipsTechnologies) || + getToolChain().getTriple().hasEnvironment())) || KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); @@ -4499,6 +4965,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_borland_extensions, false)) CmdArgs.push_back("-fborland-extensions"); + // -fno-declspec is default, except for PS4. + if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, + getToolChain().getTriple().isPS4())) + CmdArgs.push_back("-fdeclspec"); + else if (Args.hasArg(options::OPT_fno_declspec)) + CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. + // -fthreadsafe-static is default, except for MSVC compatibility versions less // than 19. if (!Args.hasFlag(options::OPT_fthreadsafe_statics, @@ -4585,6 +5058,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_objc_arc_exceptions, /*default*/ types::isCXX(InputType))) CmdArgs.push_back("-fobjc-arc-exceptions"); + } // -fobjc-infer-related-result-type is the default, except in the Objective-C @@ -4608,6 +5082,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + // Pass down -fobjc-weak or -fno-objc-weak if present. + if (types::isObjC(InputType)) { + auto WeakArg = Args.getLastArg(options::OPT_fobjc_weak, + options::OPT_fno_objc_weak); + if (!WeakArg) { + // nothing to do + } else if (GCArg) { + if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) + D.Diag(diag::err_objc_weak_with_gc); + } else if (!objcRuntime.allowsWeak()) { + if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) + D.Diag(diag::err_objc_weak_unsupported); + } else { + WeakArg->render(Args, CmdArgs); + } + } + if (Args.hasFlag(options::OPT_fapplication_extension, options::OPT_fno_application_extension, false)) CmdArgs.push_back("-fapplication-extension"); @@ -4617,7 +5108,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime, CmdArgs); - if (getToolChain().UseSjLjExceptions()) + if (getToolChain().UseSjLjExceptions(Args)) CmdArgs.push_back("-fsjlj-exceptions"); // C++ "sane" operator new. @@ -4676,14 +5167,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - if (KernelOrKext || isNoCommonDefault(getToolChain().getTriple())) { - if (!Args.hasArg(options::OPT_fcommon)) - CmdArgs.push_back("-fno-common"); - Args.ClaimAllArgs(options::OPT_fno_common); - } - - // -fcommon is default, only pass non-default. - else if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common)) + // -fcommon is the default unless compiling kernel code or the target says so + bool NoCommonDefault = + KernelOrKext || isNoCommonDefault(getToolChain().getTriple()); + if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, + !NoCommonDefault)) CmdArgs.push_back("-fno-common"); // -fsigned-bitfields is default, and clang doesn't yet support @@ -4918,10 +5406,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -fparse-all-comments to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); + // Turn -fplugin=name.so into -load name.so + for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) { + CmdArgs.push_back("-load"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); - bool OptDisabled = false; for (const Arg *A : Args.filtered(options::OPT_mllvm)) { A->claim(); @@ -4929,17 +5423,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // it and developers have been trained to spell it with -mllvm. if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") { CmdArgs.push_back("-disable-llvm-optzns"); - OptDisabled = true; } else A->render(Args, CmdArgs); } // With -save-temps, we want to save the unoptimized bitcode output from the - // CompileJobAction, so disable optimizations if they are not already - // disabled. - if (C.getDriver().isSaveTempsEnabled() && !OptDisabled && - isa<CompileJobAction>(JA)) - CmdArgs.push_back("-disable-llvm-optzns"); + // CompileJobAction, use -disable-llvm-passes to get pristine IR generated + // by the frontend. + if (C.getDriver().isSaveTempsEnabled() && isa<CompileJobAction>(JA)) + CmdArgs.push_back("-disable-llvm-passes"); if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. @@ -4982,8 +5474,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add the split debug info name to the command lines here so we // can propagate it to the backend. - bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) && - getToolChain().getTriple().isOSLinux() && + bool SplitDwarf = SplitDwarfArg && getToolChain().getTriple().isOSLinux() && (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)); const char *SplitDwarfOut; @@ -4996,11 +5487,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Host-side cuda compilation receives device-side outputs as Inputs[1...]. // Include them with -fcuda-include-gpubinary. if (IsCuda && Inputs.size() > 1) - for (InputInfoList::const_iterator it = std::next(Inputs.begin()), - ie = Inputs.end(); - it != ie; ++it) { + for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) { CmdArgs.push_back("-fcuda-include-gpubinary"); - CmdArgs.push_back(it->getFilename()); + CmdArgs.push_back(I->getFilename()); } // Finally add the compile command to the compilation. @@ -5009,10 +5498,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, (InputType == types::TY_C || InputType == types::TY_CXX)) { auto CLCommand = getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); - C.addCommand(llvm::make_unique<FallbackCommand>(JA, *this, Exec, CmdArgs, - std::move(CLCommand))); + C.addCommand(llvm::make_unique<FallbackCommand>( + JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand))); } else { - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } // Handle the debug info splitting at object creation time if we're @@ -5153,7 +5642,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, // -fgnu-runtime } else { assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime)); - // Legacy behaviour is to target the gnustep runtime if we are i + // Legacy behaviour is to target the gnustep runtime if we are in // non-fragile mode or the GCC runtime in fragile mode. if (isNonFragile) runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6)); @@ -5172,12 +5661,14 @@ static bool maybeConsumeDash(const std::string &EH, size_t &I) { return !HaveDash; } +namespace { struct EHFlags { EHFlags() : Synch(false), Asynch(false), NoExceptC(false) {} bool Synch; bool Asynch; bool NoExceptC; }; +} // end anonymous namespace /// /EH controls whether to run destructor cleanups when exceptions are /// thrown. There are three modifiers: @@ -5212,14 +5703,12 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { } } - // FIXME: Disable C++ EH completely, until it becomes more reliable. Users - // can use -Xclang to manually enable C++ EH until then. - EH = EHFlags(); - return EH; } -void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const { +void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs, + enum CodeGenOptions::DebugInfoKind *DebugInfoKind, + bool *EmitCodeView) const { unsigned RTOptionID = options::OPT__SLASH_MT; if (Args.hasArg(options::OPT__SLASH_LDd)) @@ -5230,39 +5719,46 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) RTOptionID = A->getOption().getID(); + StringRef FlagForCRT; switch (RTOptionID) { case options::OPT__SLASH_MD: if (Args.hasArg(options::OPT__SLASH_LDd)) CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); CmdArgs.push_back("-D_DLL"); - CmdArgs.push_back("--dependent-lib=msvcrt"); + FlagForCRT = "--dependent-lib=msvcrt"; break; case options::OPT__SLASH_MDd: CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); CmdArgs.push_back("-D_DLL"); - CmdArgs.push_back("--dependent-lib=msvcrtd"); + FlagForCRT = "--dependent-lib=msvcrtd"; break; case options::OPT__SLASH_MT: if (Args.hasArg(options::OPT__SLASH_LDd)) CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("--dependent-lib=libcmt"); + FlagForCRT = "--dependent-lib=libcmt"; break; case options::OPT__SLASH_MTd: CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("--dependent-lib=libcmtd"); + FlagForCRT = "--dependent-lib=libcmtd"; break; default: llvm_unreachable("Unexpected option ID."); } - // This provides POSIX compatibility (maps 'open' to '_open'), which most - // users want. The /Za flag to cl.exe turns this off, but it's not - // implemented in clang. - CmdArgs.push_back("--dependent-lib=oldnames"); + if (Args.hasArg(options::OPT__SLASH_Zl)) { + CmdArgs.push_back("-D_VC_NODEFAULTLIB"); + } else { + CmdArgs.push_back(FlagForCRT.data()); + + // This provides POSIX compatibility (maps 'open' to '_open'), which most + // users want. The /Za flag to cl.exe turns this off, but it's not + // implemented in clang. + CmdArgs.push_back("--dependent-lib=oldnames"); + } // Both /showIncludes and /E (and /EP) write to stdout. Allowing both // would produce interleaved output, so ignore /showIncludes in such cases. @@ -5275,6 +5771,16 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const { /*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) + CmdArgs.push_back("-gcodeview"); + const Driver &D = getToolChain().getDriver(); EHFlags EH = parseClangCLEHFlags(D, Args); // FIXME: Do something with NoExceptC. @@ -5366,6 +5872,10 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; + std::string TripleStr = + getToolChain().ComputeEffectiveClangTriple(Args, Input.getType()); + const llvm::Triple Triple(TripleStr); + // Don't warn about "clang -w -c foo.s" Args.ClaimAllArgs(options::OPT_w); // and "clang -emit-llvm -c foo.s" @@ -5380,8 +5890,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Add the "effective" target triple. CmdArgs.push_back("-triple"); - std::string TripleStr = - getToolChain().ComputeEffectiveClangTriple(Args, Input.getType()); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Set the output mode, we currently only expect to be used as a real @@ -5395,7 +5903,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Clang::getBaseInputName(Args, Input)); // Add the target cpu - const llvm::Triple Triple(TripleStr); std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); @@ -5403,8 +5910,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } // Add the target features - const Driver &D = getToolChain().getDriver(); - getTargetFeatures(D, Triple, Args, CmdArgs, true); + getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true); // Ignore explicit -force_cpusubtype_ALL option. (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); @@ -5423,17 +5929,21 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // with an actual assembly file. 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)) - if (!A->getOption().matches(options::OPT_g0)) - CmdArgs.push_back("-g"); - - if (Args.hasArg(options::OPT_gdwarf_2)) - CmdArgs.push_back("-gdwarf-2"); - if (Args.hasArg(options::OPT_gdwarf_3)) - CmdArgs.push_back("-gdwarf-3"); - if (Args.hasArg(options::OPT_gdwarf_4)) - CmdArgs.push_back("-gdwarf-4"); + 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); // Add the -fdebug-compilation-dir flag if needed. addDebugCompDirArg(Args, CmdArgs); @@ -5442,6 +5952,23 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // assembler on assembly source files. CmdArgs.push_back("-dwarf-debug-producer"); CmdArgs.push_back(Args.MakeArgString(getClangFullVersion())); + + // And pass along -I options + Args.AddAllArgs(CmdArgs, options::OPT_I); + } + + // Handle -fPIC et al -- the relocation-model affects the assembler + // for some targets. + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Triple, Args); + + const char *RMName = RelocationModelName(RelocationModel); + if (RMName) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); } // Optionally embed the -cc1as level arguments into the debug info, for build @@ -5500,7 +6027,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); // Handle the debug info splitting at object creation time if we're // creating an object. @@ -5555,12 +6082,22 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // // FIXME: The triple class should directly provide the information we want // here. - const llvm::Triple::ArchType Arch = getToolChain().getArch(); - if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) + switch (getToolChain().getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::ppc: CmdArgs.push_back("-m32"); - else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64 || - Arch == llvm::Triple::ppc64le) + break; + case llvm::Triple::x86_64: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: CmdArgs.push_back("-m64"); + break; + case llvm::Triple::sparcel: + CmdArgs.push_back("-EL"); + break; + } if (Output.isFilename()) { CmdArgs.push_back("-o"); @@ -5582,8 +6119,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // inputs into '-Wl,' options? for (const auto &II : Inputs) { // Don't try to pass LLVM or AST inputs to a generic gcc. - if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || - II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) + if (types::isLLVMIR(II.getType())) D.Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_AST) @@ -5623,7 +6159,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, GCCName = "gcc"; const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void gcc::Preprocessor::RenderExtraToolArgs(const JobAction &JA, @@ -5661,7 +6197,9 @@ void gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // Hexagon tools start. void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const {} + ArgStringList &CmdArgs) const { +} + void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -5669,15 +6207,21 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { claimNoWarnArgs(Args); - const Driver &D = getToolChain().getDriver(); + auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); + const Driver &D = HTC.getDriver(); ArgStringList CmdArgs; - std::string MarchString = "-march="; - MarchString += toolchains::Hexagon_TC::GetTargetCPU(Args); - CmdArgs.push_back(Args.MakeArgString(MarchString)); + std::string MArchString = "-march=hexagon"; + CmdArgs.push_back(Args.MakeArgString(MArchString)); RenderExtraToolArgs(JA, CmdArgs); + std::string AsName = "hexagon-llvm-mc"; + std::string MCpuString = "-mcpu=hexagon" + + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + CmdArgs.push_back("-filetype=obj"); + CmdArgs.push_back(Args.MakeArgString(MCpuString)); + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -5686,8 +6230,10 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fsyntax-only"); } - if (const char *v = toolchains::Hexagon_TC::GetSmallDataThreshold(Args)) - CmdArgs.push_back(Args.MakeArgString(std::string("-G") + v)); + if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { + std::string N = llvm::utostr(G.getValue()); + CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N)); + } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -5701,61 +6247,56 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // inputs into '-Wl,' options? for (const auto &II : Inputs) { // Don't try to pass LLVM or AST inputs to a generic gcc. - if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || - II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) + if (types::isLLVMIR(II.getType())) D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString(); + << HTC.getTripleString(); else if (II.getType() == types::TY_AST) D.Diag(clang::diag::err_drv_no_ast_support) - << getToolChain().getTripleString(); + << HTC.getTripleString(); else if (II.getType() == types::TY_ModuleFile) D.Diag(diag::err_drv_no_module_support) - << getToolChain().getTripleString(); + << HTC.getTripleString(); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else // Don't render as input, we need gcc to do the translations. - // FIXME: Pranav: What is this ? + // FIXME: What is this? II.getInputArg().render(Args, CmdArgs); } - const char *GCCName = "hexagon-as"; - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str())); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { - // The types are (hopefully) good enough. } -static void constructHexagonLinkArgs(Compilation &C, const JobAction &JA, - const toolchains::Hexagon_TC &ToolChain, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - ArgStringList &CmdArgs, - const char *LinkingOutput) { +static void +constructHexagonLinkArgs(Compilation &C, const JobAction &JA, + const toolchains::HexagonToolChain &HTC, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const char *LinkingOutput) { - const Driver &D = ToolChain.getDriver(); + const Driver &D = HTC.getDriver(); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- - bool hasStaticArg = Args.hasArg(options::OPT_static); - bool buildingLib = Args.hasArg(options::OPT_shared); - bool buildPIE = Args.hasArg(options::OPT_pie); - bool incStdLib = !Args.hasArg(options::OPT_nostdlib); - bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles); - bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); - bool useG0 = false; - bool useShared = buildingLib && !hasStaticArg; + bool IsStatic = Args.hasArg(options::OPT_static); + bool IsShared = Args.hasArg(options::OPT_shared); + bool IsPIE = Args.hasArg(options::OPT_pie); + bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); + bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); + bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); + bool UseG0 = false; + bool UseShared = IsShared && !IsStatic; //---------------------------------------------------------------------------- // Silence warnings for various options //---------------------------------------------------------------------------- - Args.ClaimAllArgs(options::OPT_g_Group); Args.ClaimAllArgs(options::OPT_emit_llvm); Args.ClaimAllArgs(options::OPT_w); // Other warning options are already @@ -5765,27 +6306,37 @@ static void constructHexagonLinkArgs(Compilation &C, const JobAction &JA, //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- - for (const auto &Opt : ToolChain.ExtraOpts) + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + if (Args.hasArg(options::OPT_r)) + CmdArgs.push_back("-r"); + + for (const auto &Opt : HTC.ExtraOpts) CmdArgs.push_back(Opt.c_str()); - std::string MarchString = toolchains::Hexagon_TC::GetTargetCPU(Args); - CmdArgs.push_back(Args.MakeArgString("-m" + MarchString)); + CmdArgs.push_back("-march=hexagon"); + std::string CpuVer = + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + std::string MCpuString = "-mcpu=hexagon" + CpuVer; + CmdArgs.push_back(Args.MakeArgString(MCpuString)); - if (buildingLib) { + if (IsShared) { CmdArgs.push_back("-shared"); - CmdArgs.push_back("-call_shared"); // should be the default, but doing as - // hexagon-gcc does + // The following should be the default, but doing as hexagon-gcc does. + CmdArgs.push_back("-call_shared"); } - if (hasStaticArg) + if (IsStatic) CmdArgs.push_back("-static"); - if (buildPIE && !buildingLib) + if (IsPIE && !IsShared) CmdArgs.push_back("-pie"); - if (const char *v = toolchains::Hexagon_TC::GetSmallDataThreshold(Args)) { - CmdArgs.push_back(Args.MakeArgString(std::string("-G") + v)); - useG0 = toolchains::Hexagon_TC::UsesG0(v); + if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { + std::string N = llvm::utostr(G.getValue()); + CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N)); + UseG0 = G.getValue() == 0; } //---------------------------------------------------------------------------- @@ -5794,77 +6345,85 @@ static void constructHexagonLinkArgs(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - const std::string MarchSuffix = "/" + MarchString; - const std::string G0Suffix = "/G0"; - const std::string MarchG0Suffix = MarchSuffix + G0Suffix; - const std::string RootDir = - toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir, Args) + "/"; - const std::string StartFilesDir = - RootDir + "hexagon/lib" + (useG0 ? MarchG0Suffix : MarchSuffix); - //---------------------------------------------------------------------------- // moslib //---------------------------------------------------------------------------- - std::vector<std::string> oslibs; - bool hasStandalone = false; + std::vector<std::string> OsLibs; + bool HasStandalone = false; for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { A->claim(); - oslibs.emplace_back(A->getValue()); - hasStandalone = hasStandalone || (oslibs.back() == "standalone"); + OsLibs.emplace_back(A->getValue()); + HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); } - if (oslibs.empty()) { - oslibs.push_back("standalone"); - hasStandalone = true; + if (OsLibs.empty()) { + OsLibs.push_back("standalone"); + HasStandalone = true; } //---------------------------------------------------------------------------- // Start Files //---------------------------------------------------------------------------- - if (incStdLib && incStartFiles) { - - if (!buildingLib) { - if (hasStandalone) { - CmdArgs.push_back( - Args.MakeArgString(StartFilesDir + "/crt0_standalone.o")); + const std::string MCpuSuffix = "/" + CpuVer; + const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; + const std::string RootDir = + HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; + const std::string StartSubDir = + "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); + + auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, + const char *Name) -> std::string { + std::string RelName = SubDir + Name; + std::string P = HTC.GetFilePath(RelName.c_str()); + if (llvm::sys::fs::exists(P)) + return P; + return RootDir + RelName; + }; + + if (IncStdLib && IncStartFiles) { + if (!IsShared) { + if (HasStandalone) { + std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); + CmdArgs.push_back(Args.MakeArgString(Crt0SA)); } - CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o")); + std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); + CmdArgs.push_back(Args.MakeArgString(Crt0)); } - std::string initObj = useShared ? "/initS.o" : "/init.o"; - CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj)); + std::string Init = UseShared + ? Find(RootDir, StartSubDir + "/pic", "/initS.o") + : Find(RootDir, StartSubDir, "/init.o"); + CmdArgs.push_back(Args.MakeArgString(Init)); } //---------------------------------------------------------------------------- // Library Search Paths //---------------------------------------------------------------------------- - const ToolChain::path_list &LibPaths = ToolChain.getFilePaths(); + const ToolChain::path_list &LibPaths = HTC.getFilePaths(); for (const auto &LibPath : LibPaths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_u_Group); + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(HTC, Inputs, Args, CmdArgs); //---------------------------------------------------------------------------- // Libraries //---------------------------------------------------------------------------- - if (incStdLib && incDefLibs) { + if (IncStdLib && IncDefLibs) { if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + HTC.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } CmdArgs.push_back("--start-group"); - if (!buildingLib) { - for (const std::string &Lib : oslibs) + if (!IsShared) { + for (const std::string &Lib : OsLibs) CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); CmdArgs.push_back("-lc"); } @@ -5876,9 +6435,11 @@ static void constructHexagonLinkArgs(Compilation &C, const JobAction &JA, //---------------------------------------------------------------------------- // End files //---------------------------------------------------------------------------- - if (incStdLib && incStartFiles) { - std::string finiObj = useShared ? "/finiS.o" : "/fini.o"; - CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj)); + if (IncStdLib && IncStartFiles) { + std::string Fini = UseShared + ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") + : Find(RootDir, StartSubDir, "/fini.o"); + CmdArgs.push_back(Args.MakeArgString(Fini)); } } @@ -5887,60 +6448,101 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - - const toolchains::Hexagon_TC &ToolChain = - static_cast<const toolchains::Hexagon_TC &>(getToolChain()); + auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); ArgStringList CmdArgs; - constructHexagonLinkArgs(C, JA, ToolChain, Output, Inputs, Args, CmdArgs, + constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, LinkingOutput); - std::string Linker = ToolChain.GetProgramPath("hexagon-ld"); + std::string Linker = HTC.GetProgramPath("hexagon-link"); C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs)); + CmdArgs, Inputs)); } // Hexagon tools end. +void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + + std::string Linker = getToolChain().GetProgramPath(getShortName()); + ArgStringList CmdArgs; + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("old-gnu"); + CmdArgs.push_back("-target"); + CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), + CmdArgs, Inputs)); +} +// AMDGPU tools end. + +wasm::Linker::Linker(const ToolChain &TC) + : GnuTool("wasm::Linker", "lld", TC) {} + +bool wasm::Linker::isLinkJob() const { + return true; +} + +bool wasm::Linker::hasIntegratedCPP() const { + return false; +} + +void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const char *Linker = Args.MakeArgString(getToolChain().GetLinkerPath()); + ArgStringList CmdArgs; + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("ld"); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); +} + const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch; if (!Arch.empty()) MArch = Arch; else MArch = Triple.getArchName(); - MArch = StringRef(MArch).lower(); + MArch = StringRef(MArch).split("+").first.lower(); // Handle -march=native. if (MArch == "native") { std::string CPU = llvm::sys::getHostCPUName(); if (CPU != "generic") { // Translate the native cpu into the architecture suffix for that CPU. - const char *Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch); + StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); // If there is no valid architecture suffix for this CPU we don't know how // to handle it, so return no architecture. - if (strcmp(Suffix, "") == 0) + if (Suffix.empty()) MArch = ""; else - MArch = std::string("arm") + Suffix; + MArch = std::string("arm") + Suffix.str(); } } return MArch; } + /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. -const char *arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { +StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch = getARMArch(Arch, Triple); // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch // here means an -march=native that we can't handle, so instead return no CPU. if (MArch.empty()) - return ""; + return StringRef(); // We need to return an empty string here on invalid MArch values as the // various places that call this function can't cope with a null result. - const char *result = Triple.getARMCPUForArch(MArch); - if (result) - return result; - else - return ""; + return Triple.getARMCPUForArch(MArch); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. @@ -5949,7 +6551,7 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. if (!CPU.empty()) { - std::string MCPU = StringRef(CPU).lower(); + std::string MCPU = StringRef(CPU).split("+").first.lower(); // Handle -mcpu=native. if (MCPU == "native") return llvm::sys::getHostCPUName(); @@ -5963,15 +6565,26 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular /// CPU (or Arch, if CPU is generic). // FIXME: This is redundant with -mcpu, why does LLVM use this. -const char *arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch) { - if (CPU == "generic" && - llvm::ARMTargetParser::parseArch(Arch) == llvm::ARM::AK_ARMV8_1A) - return "v8.1a"; - - unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(CPU); +StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { + unsigned ArchKind; + if (CPU == "generic") { + std::string ARMArch = tools::arm::getARMArch(Arch, Triple); + ArchKind = llvm::ARM::parseArch(ARMArch); + if (ArchKind == llvm::ARM::AK_INVALID) + // In case of generic Arch, i.e. "arm", + // extract arch from default cpu of the Triple + ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); + } else { + // FIXME: horrible hack to get around the fact that Cortex-A7 is only an + // armv7k triple if it's actually been specified via "-arch armv7k". + ArchKind = (Arch == "armv7k" || Arch == "thumbv7k") + ? (unsigned)llvm::ARM::AK_ARMV7K + : llvm::ARM::parseCPUArch(CPU); + } if (ArchKind == llvm::ARM::AK_INVALID) return ""; - return llvm::ARMTargetParser::getSubArch(ArchKind); + return llvm::ARM::getSubArch(ArchKind); } void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs, @@ -5986,6 +6599,9 @@ void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs, } mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { + // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008 + // was first introduced in Release 3. However, other compilers have + // traditionally allowed it for Release 2 so we should do the same. return (NanEncoding)llvm::StringSwitch<int>(CPU) .Case("mips1", NanLegacy) .Case("mips2", NanLegacy) @@ -5993,12 +6609,12 @@ mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { .Case("mips4", NanLegacy) .Case("mips5", NanLegacy) .Case("mips32", NanLegacy) - .Case("mips32r2", NanLegacy) + .Case("mips32r2", NanLegacy | Nan2008) .Case("mips32r3", NanLegacy | Nan2008) .Case("mips32r5", NanLegacy | Nan2008) .Case("mips32r6", Nan2008) .Case("mips64", NanLegacy) - .Case("mips64r2", NanLegacy) + .Case("mips64r2", NanLegacy | Nan2008) .Case("mips64r3", NanLegacy | Nan2008) .Case("mips64r5", NanLegacy | Nan2008) .Case("mips64r6", Nan2008) @@ -6031,7 +6647,7 @@ bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { } bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, - StringRef ABIName, StringRef FloatABI) { + StringRef ABIName, mips::FloatABI FloatABI) { if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && Triple.getVendor() != llvm::Triple::MipsTechnologies) return false; @@ -6041,7 +6657,7 @@ bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is // present. - if (FloatABI == "soft") + if (FloatABI == mips::FloatABI::Soft) return false; return llvm::StringSwitch<bool>(CPUName) @@ -6053,7 +6669,7 @@ bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, - StringRef FloatABI) { + mips::FloatABI FloatABI) { bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI); // FPXX shouldn't be used if -msingle-float is present. @@ -6173,42 +6789,34 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); - const ToolChain::path_list &Paths = ToolChain.getFilePaths(); - for (const auto &Path : Paths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_r); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - if (D.IsUsingLTO(Args)) - AddGoldPlugin(ToolChain, Args, CmdArgs); + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lcompiler_rt"); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -6228,11 +6836,11 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, SourceAction = SourceAction->getInputs()[0]; } - // If -fno_integrated_as is used add -Q to the darwin assember driver to make + // If -fno-integrated-as is used add -Q to the darwin assember driver to make // sure it runs its system assembler not clang's integrated assembler. // Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as. // FIXME: at run-time detect assembler capabilities or rely on version - // information forwarded by -target-assembler-version (future) + // information forwarded by -target-assembler-version. if (Args.hasArg(options::OPT_fno_integrated_as)) { const llvm::Triple &T(getToolChain().getTriple()); if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) @@ -6276,7 +6884,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // asm_final spec is empty. const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void darwin::MachOTool::anchor() {} @@ -6334,15 +6942,34 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, options::OPT_fno_application_extension, false)) CmdArgs.push_back("-application_extension"); - // If we are using LTO, then automatically create a temporary file path for - // the linker to use, so that it's lifetime will extend past a possible - // dsymutil step. - if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) { - const char *TmpPath = C.getArgs().MakeArgString( - D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); - C.addTempFile(TmpPath); - CmdArgs.push_back("-object_path_lto"); - CmdArgs.push_back(TmpPath); + if (D.isUsingLTO()) { + // If we are using LTO, then automatically create a temporary file path for + // the linker to use, so that it's lifetime will extend past a possible + // dsymutil step. + if (Version[0] >= 116 && NeedsTempPath(Inputs)) { + const char *TmpPath = C.getArgs().MakeArgString( + D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); + C.addTempFile(TmpPath); + CmdArgs.push_back("-object_path_lto"); + CmdArgs.push_back(TmpPath); + } + + // Use -lto_library option to specify the libLTO.dylib path. Try to find + // it in clang installed libraries. If not found, the option is not used + // and 'ld' will use its default mechanism to search for libLTO.dylib. + if (Version[0] >= 133) { + // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib + StringRef P = llvm::sys::path::parent_path(D.getInstalledDir()); + SmallString<128> LibLTOPath(P); + llvm::sys::path::append(LibLTOPath, "lib"); + llvm::sys::path::append(LibLTOPath, "libLTO.dylib"); + if (llvm::sys::fs::exists(LibLTOPath)) { + CmdArgs.push_back("-lto_library"); + CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); + } else { + D.Diag(diag::warn_drv_lto_libpath); + } + } } // Derived from the "link" spec. @@ -6509,7 +7136,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("touch")); CmdArgs.push_back(Output.getFilename()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, None)); return; } @@ -6517,13 +7144,11 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs); - Args.AddAllArgs(CmdArgs, options::OPT_d_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_u_Group); - Args.AddLastArg(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_r); + // It seems that the 'e' option is completely ignored for dynamic executables + // (the default), and with static executables, the last one wins, as expected. + Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_u_Group, + options::OPT_e, options::OPT_r}); // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading // members of static archive libraries which implement Objective-C classes or @@ -6534,8 +7159,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); // SafeStack requires its own runtime libraries @@ -6567,12 +7191,11 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, InputFileList.push_back(II.getFilename()); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) addOpenMPRuntime(CmdArgs, getToolChain(), Args); - if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (isObjCRuntimeLinked(Args) && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { // We use arclite library for both ARC and subscripting support. getMachOToolChain().AddLinkARCArgs(Args, CmdArgs); @@ -6591,13 +7214,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fnested_functions)) CmdArgs.push_back("-allow_stack_execute"); - // TODO: It would be nice to use addProfileRT() here, but darwin's compiler-rt - // paths are different enough from other toolchains that this needs a fair - // amount of refactoring done first. getMachOToolChain().addProfileRTLibs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); @@ -6607,8 +7226,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { // endfile_spec is empty. } @@ -6619,8 +7237,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, for (const Arg *A : Args.filtered(options::OPT_iframework)) CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue())); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { if (A->getValue() == StringRef("Accelerate")) { CmdArgs.push_back("-framework"); @@ -6631,7 +7248,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); std::unique_ptr<Command> Cmd = - llvm::make_unique<Command>(JA, *this, Exec, CmdArgs); + llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs); Cmd->setInputFileList(std::move(InputFileList)); C.addCommand(std::move(Cmd)); } @@ -6655,7 +7272,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, @@ -6675,7 +7292,7 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, @@ -6698,7 +7315,7 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -6718,7 +7335,7 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -6726,32 +7343,12 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - // FIXME: Find a real GCC, don't hard-code versions here - std::string GCCLibPath = "/usr/gcc/4.5/lib/gcc/"; - const llvm::Triple &T = getToolChain().getTriple(); - std::string LibPath = "/usr/lib/"; - const llvm::Triple::ArchType Arch = T.getArch(); - switch (Arch) { - case llvm::Triple::x86: - GCCLibPath += - ("i386-" + T.getVendorName() + "-" + T.getOSName()).str() + "/4.5.2/"; - break; - case llvm::Triple::x86_64: - GCCLibPath += ("i386-" + T.getVendorName() + "-" + T.getOSName()).str(); - GCCLibPath += "/4.5.2/amd64/"; - LibPath += "amd64/"; - break; - default: - llvm_unreachable("Unsupported architecture"); - } - ArgStringList CmdArgs; // Demangle C++ names in errors CmdArgs.push_back("-C"); - if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } @@ -6765,7 +7362,8 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("--dynamic-linker"); - CmdArgs.push_back(Args.MakeArgString(LibPath + "ld.so.1")); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("ld.so.1"))); } } @@ -6776,53 +7374,46 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(LibPath + "crt1.o")); - CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o")); - CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o")); - CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o")); - } else { - CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o")); - CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o")); - CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o")); - } - if (getToolChain().getDriver().CCCIsCXX()) - CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.o")); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o"))); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); } - CmdArgs.push_back(Args.MakeArgString("-L" + GCCLibPath)); + getToolChain().AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_r); + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_r}); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("-lc"); if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { - CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtend.o")); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); } - CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o")); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -6832,7 +7423,6 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; - bool NeedsKPIC = false; switch (getToolChain().getArch()) { case llvm::Triple::x86: @@ -6847,16 +7437,21 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, break; case llvm::Triple::sparc: - case llvm::Triple::sparcel: + case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); - NeedsKPIC = true; + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; + } - case llvm::Triple::sparcv9: + case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - CmdArgs.push_back("-Av9a"); - NeedsKPIC = true; + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; + } case llvm::Triple::mips64: case llvm::Triple::mips64el: { @@ -6872,7 +7467,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-EL"); - NeedsKPIC = true; + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } @@ -6880,9 +7475,6 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, break; } - if (NeedsKPIC) - addAssemblerKPIC(Args, CmdArgs); - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); @@ -6892,7 +7484,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -6916,8 +7508,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, else if (getToolChain().getArch() == llvm::Triple::mips64el) CmdArgs.push_back("-EL"); - if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } @@ -6947,8 +7538,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back( @@ -6970,18 +7560,13 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1")); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_r); + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_r}); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) @@ -7011,8 +7596,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lgcc"); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); @@ -7022,7 +7606,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void bitrig::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -7042,7 +7626,7 @@ void bitrig::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -7053,8 +7637,7 @@ void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; - if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } @@ -7081,8 +7664,7 @@ void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back( @@ -7098,14 +7680,12 @@ void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_e}); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) @@ -7145,8 +7725,7 @@ void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch)); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); @@ -7156,7 +7735,7 @@ void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -7169,14 +7748,19 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) + switch (getToolChain().getArch()) { + default: + break; + case llvm::Triple::x86: CmdArgs.push_back("--32"); - else if (getToolChain().getArch() == llvm::Triple::ppc) + break; + case llvm::Triple::ppc: CmdArgs.push_back("-a32"); - else if (getToolChain().getArch() == llvm::Triple::mips || - getToolChain().getArch() == llvm::Triple::mipsel || - getToolChain().getArch() == llvm::Triple::mips64 || - getToolChain().getArch() == llvm::Triple::mips64el) { + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); @@ -7193,20 +7777,25 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-EL"); - addAssemblerKPIC(Args, CmdArgs); - } else if (getToolChain().getArch() == llvm::Triple::arm || - getToolChain().getArch() == llvm::Triple::armeb || - getToolChain().getArch() == llvm::Triple::thumb || - getToolChain().getArch() == llvm::Triple::thumbeb) { - const Driver &D = getToolChain().getDriver(); - const llvm::Triple &Triple = getToolChain().getTriple(); - StringRef FloatABI = arm::getARMFloatABI(D, Args, Triple); + if (Arg *A = Args.getLastArg(options::OPT_G)) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-G" + v)); + A->claim(); + } + + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: { + arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); - if (FloatABI == "hard") { + if (ABI == arm::FloatABI::Hard) CmdArgs.push_back("-mfpu=vfp"); - } else { + else CmdArgs.push_back("-mfpu=softvfp"); - } switch (getToolChain().getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: @@ -7218,15 +7807,16 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, default: CmdArgs.push_back("-matpcs"); } - } else if (getToolChain().getArch() == llvm::Triple::sparc || - getToolChain().getArch() == llvm::Triple::sparcel || - getToolChain().getArch() == llvm::Triple::sparcv9) { - if (getToolChain().getArch() == llvm::Triple::sparc) - CmdArgs.push_back("-Av8plusa"); - else - CmdArgs.push_back("-Av9a"); - - addAssemblerKPIC(Args, CmdArgs); + break; + } + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: { + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -7238,7 +7828,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -7302,6 +7892,17 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf32ppc_fbsd"); } + if (Arg *A = Args.getLastArg(options::OPT_G)) { + if (ToolChain.getArch() == llvm::Triple::mips || + ToolChain.getArch() == llvm::Triple::mipsel || + ToolChain.getArch() == llvm::Triple::mips64 || + ToolChain.getArch() == llvm::Triple::mips64el) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-G" + v)); + A->claim(); + } + } + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -7309,8 +7910,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) @@ -7337,9 +7937,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_L); - const ToolChain::path_list &Paths = ToolChain.getFilePaths(); - for (const auto &Path : Paths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); @@ -7347,14 +7945,13 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - if (D.IsUsingLTO(Args)) - AddGoldPlugin(ToolChain, Args, CmdArgs); + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, ToolChain, Args); if (D.CCCIsCXX()) { ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); @@ -7410,8 +8007,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || IsPIE) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else @@ -7419,10 +8015,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - addProfileRT(ToolChain, Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -7471,21 +8067,26 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-EL"); - addAssemblerKPIC(Args, CmdArgs); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } case llvm::Triple::sparc: - case llvm::Triple::sparcel: + case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); - addAssemblerKPIC(Args, CmdArgs); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; + } - case llvm::Triple::sparcv9: + case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - CmdArgs.push_back("-Av9"); - addAssemblerKPIC(Args, CmdArgs); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; + } default: break; @@ -7500,7 +8101,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -7620,8 +8221,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); @@ -7669,8 +8269,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, getToolChain(), Args); if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); @@ -7697,8 +8296,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); @@ -7708,10 +8306,10 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -7721,8 +8319,16 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { claimNoWarnArgs(Args); + std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); + llvm::Triple Triple = llvm::Triple(TripleStr); + ArgStringList CmdArgs; - bool NeedsKPIC = false; + + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Triple, Args); switch (getToolChain().getArch()) { default: @@ -7755,22 +8361,26 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mlittle-endian"); break; case llvm::Triple::sparc: - case llvm::Triple::sparcel: + case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); - CmdArgs.push_back("-Av8plusa"); - NeedsKPIC = true; + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; - case llvm::Triple::sparcv9: + } + case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - CmdArgs.push_back("-Av9a"); - NeedsKPIC = true; + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; + } case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { - const llvm::Triple &Triple = getToolChain().getTriple(); - switch (Triple.getSubArch()) { + const llvm::Triple &Triple2 = getToolChain().getTriple(); + switch (Triple2.getSubArch()) { case llvm::Triple::ARMSubArch_v7: CmdArgs.push_back("-mfpu=neon"); break; @@ -7781,10 +8391,18 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, break; } - StringRef ARMFloatABI = tools::arm::getARMFloatABI( - getToolChain().getDriver(), Args, - llvm::Triple(getToolChain().ComputeEffectiveClangTriple(Args))); - CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=" + ARMFloatABI)); + switch (arm::getARMFloatABI(getToolChain(), Args)) { + case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!"); + case arm::FloatABI::Soft: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft")); + break; + case arm::FloatABI::SoftFP: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp")); + break; + case arm::FloatABI::Hard: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard")); + break; + } Args.AddLastArg(CmdArgs, options::OPT_march_EQ); @@ -7817,18 +8435,7 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, // or -mshared (not implemented) is in effect. - bool IsPicOrPie = false; - if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie)) { - if (A->getOption().matches(options::OPT_fPIC) || - A->getOption().matches(options::OPT_fpic) || - A->getOption().matches(options::OPT_fPIE) || - A->getOption().matches(options::OPT_fpie)) - IsPicOrPie = true; - } - if (!IsPicOrPie) + if (RelocationModel == llvm::Reloc::Static) CmdArgs.push_back("-mno-shared"); // LLVM doesn't support -mplt yet and acts as if it is always given. @@ -7847,13 +8454,13 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. - StringRef MIPSFloatABI = getMipsFloatABI(getToolChain().getDriver(), Args); if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, options::OPT_mfp64)) { A->claim(); A->render(Args, CmdArgs); - } else if (mips::shouldUseFPXX(Args, getToolChain().getTriple(), CPUName, - ABIName, MIPSFloatABI)) + } else if (mips::shouldUseFPXX( + Args, getToolChain().getTriple(), CPUName, ABIName, + getMipsFloatABI(getToolChain().getDriver(), Args))) CmdArgs.push_back("-mfpxx"); // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of @@ -7890,7 +8497,7 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, options::OPT_mno_odd_spreg); - NeedsKPIC = true; + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } case llvm::Triple::systemz: { @@ -7902,9 +8509,7 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } } - if (NeedsKPIC) - addAssemblerKPIC(Args, CmdArgs); - + Args.AddAllArgs(CmdArgs, options::OPT_I); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); @@ -7914,7 +8519,7 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); // Handle the debug info splitting at object creation time if we're // creating an object. @@ -7927,7 +8532,7 @@ void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { - bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android; + bool isAndroid = Triple.isAndroid(); bool isCygMing = Triple.isOSCygMing(); bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || Args.hasArg(options::OPT_static); @@ -7963,7 +8568,7 @@ static std::string getLinuxDynamicLinker(const ArgList &Args, const toolchains::Linux &ToolChain) { const llvm::Triple::ArchType Arch = ToolChain.getArch(); - if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) { + if (ToolChain.getTriple().isAndroid()) { if (ToolChain.getTriple().isArch64Bit()) return "/system/bin/linker64"; else @@ -7977,33 +8582,30 @@ static std::string getLinuxDynamicLinker(const ArgList &Args, 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 || - tools::arm::getARMFloatABI(ToolChain.getDriver(), Args, ToolChain.getTriple()) == "hard") + 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 || - tools::arm::getARMFloatABI(ToolChain.getDriver(), Args, ToolChain.getTriple()) == "hard") + 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) { - StringRef CPUName; - StringRef ABIName; - mips::getMipsCPUAndABI(Args, ToolChain.getTriple(), CPUName, ABIName); - bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple()); - - StringRef LibDir = llvm::StringSwitch<llvm::StringRef>(ABIName) - .Case("o32", "/lib") - .Case("n32", "/lib32") - .Case("n64", "/lib64") - .Default("/lib"); + 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 + 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(); @@ -8018,7 +8620,7 @@ static std::string getLinuxDynamicLinker(const ArgList &Args, return "/lib64/ld64.so.1"; return "/lib64/ld64.so.2"; } else if (Arch == llvm::Triple::systemz) - return "/lib64/ld64.so.1"; + return "/lib/ld64.so.1"; else if (Arch == llvm::Triple::sparcv9) return "/lib64/ld-linux.so.2"; else if (Arch == llvm::Triple::x86_64 && @@ -8106,12 +8708,18 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const toolchains::Linux &ToolChain = static_cast<const toolchains::Linux &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + + std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); + llvm::Triple Triple = llvm::Triple(TripleStr); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); - const bool isAndroid = - ToolChain.getTriple().getEnvironment() == llvm::Triple::Android; + const bool isAndroid = ToolChain.getTriple().isAndroid(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + const bool HasCRTBeginEndFiles = + ToolChain.getTriple().hasEnvironment() || + (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); ArgStringList CmdArgs; @@ -8123,6 +8731,14 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + if (llvm::sys::path::filename(Exec) == "lld") { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("old-gnu"); + CmdArgs.push_back("-target"); + CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); + } + if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); @@ -8136,9 +8752,7 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-s"); if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) - arm::appendEBLinkFlags( - Args, CmdArgs, - llvm::Triple(getToolChain().ComputeEffectiveClangTriple(Args))); + arm::appendEBLinkFlags(Args, CmdArgs, Triple); for (const auto &Opt : ToolChain.ExtraOpts) CmdArgs.push_back(Opt.c_str()); @@ -8172,8 +8786,7 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!isAndroid) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { @@ -8199,7 +8812,9 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; - 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); @@ -8208,13 +8823,10 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); - const ToolChain::path_list &Paths = ToolChain.getFilePaths(); - - for (const auto &Path : Paths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (D.IsUsingLTO(Args)) - AddGoldPlugin(ToolChain, Args, CmdArgs); + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); @@ -8222,10 +8834,10 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); - if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX() && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) @@ -8298,14 +8910,14 @@ void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, else crtend = isAndroid ? "crtend_android.o" : "crtend.o"; - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + if (HasCRTBeginEndFiles) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); if (!isAndroid) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } } - C.addCommand( - llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(), CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } // NaCl ARM assembly (inline or standalone) can be written with a set of macros @@ -8317,8 +8929,8 @@ void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NaCl_TC &ToolChain = - static_cast<const toolchains::NaCl_TC &>(getToolChain()); + const toolchains::NaClToolChain &ToolChain = + static_cast<const toolchains::NaClToolChain &>(getToolChain()); InputInfo NaClMacros(ToolChain.GetNaClArmMacrosPath(), types::TY_PP_Asm, "nacl-arm-macros.s"); InputInfoList NewInputs; @@ -8338,8 +8950,8 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NaCl_TC &ToolChain = - static_cast<const toolchains::NaCl_TC &>(getToolChain()); + const toolchains::NaClToolChain &ToolChain = + static_cast<const toolchains::NaClToolChain &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsStatic = @@ -8364,8 +8976,8 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); - // NaCl_TC doesn't have ExtraOpts like Linux; the only relevant flag from - // there is --build-id, which we do want. + // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag + // from there is --build-id, which we do want. CmdArgs.push_back("--build-id"); if (!IsStatic) @@ -8391,8 +9003,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); @@ -8410,18 +9021,15 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); - const ToolChain::path_list &Paths = ToolChain.getFilePaths(); - - for (const auto &Path : Paths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX() && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; if (OnlyLibstdcxxStatic) @@ -8480,8 +9088,8 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - C.addCommand( - llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(), CmdArgs)); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -8501,7 +9109,7 @@ void minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -8519,8 +9127,7 @@ void minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back( @@ -8528,24 +9135,21 @@ void minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_e}); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); @@ -8556,7 +9160,7 @@ void minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } /// DragonFly Tools @@ -8585,7 +9189,7 @@ void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -8595,7 +9199,6 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; - bool UseGCC47 = llvm::sys::fs::exists("/usr/lib/gcc47"); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); @@ -8612,7 +9215,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } - CmdArgs.push_back("--hash-style=both"); + CmdArgs.push_back("--hash-style=gnu"); + CmdArgs.push_back("--enable-new-dtags"); } // When building 32-bit code on DragonFly/pc64, we have to explicitly @@ -8629,8 +9233,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back( @@ -8653,29 +9256,17 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_e}); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { - // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of - // rpaths - if (UseGCC47) - CmdArgs.push_back("-L/usr/lib/gcc47"); - else - CmdArgs.push_back("-L/usr/lib/gcc44"); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + CmdArgs.push_back("-L/usr/lib/gcc50"); if (!Args.hasArg(options::OPT_static)) { - if (UseGCC47) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib/gcc47"); - } else { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib/gcc44"); - } + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("/usr/lib/gcc50"); } if (D.CCCIsCXX()) { @@ -8690,34 +9281,25 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - if (UseGCC47) { - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_static_libgcc)) { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_static_libgcc)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lgcc_eh"); - } else { - if (Args.hasArg(options::OPT_shared_libgcc)) { + } else { + if (Args.hasArg(options::OPT_shared_libgcc)) { CmdArgs.push_back("-lgcc_pic"); if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lgcc"); - } else { + } else { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_pic"); CmdArgs.push_back("--no-as-needed"); - } - } - } else { - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-lgcc_pic"); - } else { - CmdArgs.push_back("-lgcc"); } } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); @@ -8727,10 +9309,10 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } - addProfileRT(getToolChain(), Args, CmdArgs); + getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } // Try to find Exe from a Visual Studio distribution. This first tries to find @@ -8766,8 +9348,8 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(std::string("-out:") + Output.getFilename())); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles) && !C.getDriver().IsCLMode()) + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && + !C.getDriver().IsCLMode()) CmdArgs.push_back("-defaultlib:libcmt"); if (!llvm::sys::Process::GetEnv("LIB")) { @@ -8795,6 +9377,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back( Args.MakeArgString(std::string("-libpath:") + LibDir.c_str())); + + if (MSVC.useUniversalCRT(VisualStudioDir)) { + std::string UniversalCRTLibPath; + if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + UniversalCRTLibPath.c_str())); + } } std::string WindowsSdkLibPath; @@ -8805,7 +9394,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-nologo"); - if (Args.hasArg(options::OPT_g_Group)) + if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) CmdArgs.push_back("-debug"); bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, @@ -8822,28 +9411,42 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { - static const char *CompilerRTComponents[] = { - "asan_dynamic", "asan_dynamic_runtime_thunk", - }; - for (const auto &Component : CompilerRTComponents) - CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Component))); + 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("-include:___asan_seh_interceptor")); } else if (DLL) { - CmdArgs.push_back( - Args.MakeArgString(getCompilerRT(TC, "asan_dll_thunk"))); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); } else { - static const char *CompilerRTComponents[] = { - "asan", "asan_cxx", - }; - for (const auto &Component : CompilerRTComponents) - CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Component))); + for (const auto &Lib : {"asan", "asan_cxx"}) + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); } } Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + CmdArgs.push_back("-nodefaultlib:vcomp.lib"); + CmdArgs.push_back("-nodefaultlib:vcompd.lib"); + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + TC.getDriver().Dir + "/../lib")); + switch (getOpenMPRuntime(getToolChain(), Args)) { + case OMPRT_OMP: + CmdArgs.push_back("-defaultlib:libomp.lib"); + break; + case OMPRT_IOMP5: + CmdArgs.push_back("-defaultlib:libiomp5md.lib"); + break; + case OMPRT_GOMP: + break; + case OMPRT_Unknown: + // Already diagnosed. + break; + } + } + // Add filenames, libraries, and other linker inputs. for (const auto &Input : Inputs) { if (Input.isFilename()) { @@ -8891,7 +9494,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(linkPath); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA, @@ -8915,21 +9518,34 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( // any flag accepted by clang-cl. // These are spelled the same way in clang and cl.exe,. - Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); - Args.AddAllArgs(CmdArgs, options::OPT_I); + Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); // Optimization level. + if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin)) + CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi" + : "/Oi-"); if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { if (A->getOption().getID() == options::OPT_O0) { CmdArgs.push_back("/Od"); } else { + CmdArgs.push_back("/Og"); + StringRef OptLevel = A->getValue(); - if (OptLevel == "1" || OptLevel == "2" || OptLevel == "s") - A->render(Args, CmdArgs); - else if (OptLevel == "3") - CmdArgs.push_back("/Ox"); + if (OptLevel == "s" || OptLevel == "z") + CmdArgs.push_back("/Os"); + else + CmdArgs.push_back("/Ot"); + + CmdArgs.push_back("/Ob2"); } } + if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, + options::OPT_fno_omit_frame_pointer)) + CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer + ? "/Oy" + : "/Oy-"); + if (!Args.hasArg(options::OPT_fwritable_strings)) + CmdArgs.push_back("/GF"); // Flags for which clang-cl has an alias. // FIXME: How can we ensure this stays in sync with relevant clang-cl options? @@ -8948,7 +9564,8 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-"); if (Args.hasArg(options::OPT_fsyntax_only)) CmdArgs.push_back("/Zs"); - if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only)) + if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only, + options::OPT__SLASH_Z7)) CmdArgs.push_back("/Z7"); std::vector<std::string> Includes = @@ -8960,6 +9577,7 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl); // The order of these flags is relevant, so pick the last one. if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, @@ -8986,7 +9604,7 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe", D.getClangProgramPath()); return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs); + CmdArgs, Inputs); } /// MinGW Tools @@ -9013,7 +9631,7 @@ void MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); if (Args.hasArg(options::OPT_gsplit_dwarf)) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, @@ -9026,8 +9644,24 @@ void MinGW::Linker::AddLibGCC(const ArgList &Args, CmdArgs.push_back("-lmingwthrd"); CmdArgs.push_back("-lmingw32"); - // Add libgcc or compiler-rt. - AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); + // Make use of compiler-rt if --rtlib option is used + ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); + if (RLT == ToolChain::RLT_Libgcc) { + bool Static = Args.hasArg(options::OPT_static_libgcc) || + Args.hasArg(options::OPT_static); + bool Shared = Args.hasArg(options::OPT_shared); + bool CXX = getToolChain().getDriver().CCCIsCXX(); + + if (Static || (!CXX && !Shared)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); + } else { + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("-lgcc"); + } + } else { + AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); + } CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); @@ -9057,6 +9691,8 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (LinkerName.equals_lower("lld")) { CmdArgs.push_back("-flavor"); CmdArgs.push_back("gnu"); + } else if (!LinkerName.equals_lower("ld")) { + D.Diag(diag::err_drv_unsupported_linker) << LinkerName; } if (!D.SysRoot.empty()) @@ -9110,8 +9746,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_u_Group); Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o"))); } else { @@ -9126,18 +9761,15 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_L); - const ToolChain::path_list Paths = TC.getFilePaths(); - for (const auto &Path : Paths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); - + TC.AddFilePathLibArgs(Args, CmdArgs); AddLinkerInputs(TC, Inputs, Args, CmdArgs); // TODO: Add ASan stuff here // TODO: Add profile stuff here - if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX() && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) @@ -9193,7 +9825,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } /// XCore Tools @@ -9229,7 +9861,7 @@ void XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -9257,7 +9889,7 @@ void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void CrossWindows::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -9296,7 +9928,7 @@ void CrossWindows::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const std::string Assembler = TC.GetProgramPath("as"); Exec = Args.MakeArgString(Assembler); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -9375,8 +10007,7 @@ void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic" : "-Bdynamic"); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back("--entry"); CmdArgs.push_back(Args.MakeArgString(EntryPoint)); } @@ -9398,8 +10029,7 @@ void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ImpLib)); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { const std::string CRTPath(D.SysRoot + "/usr/lib/"); const char *CRTBegin; @@ -9409,11 +10039,7 @@ void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_L); - - const auto &Paths = TC.getFilePaths(); - for (const auto &Path : Paths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); - + TC.AddFilePathLibArgs(Args, CmdArgs); AddLinkerInputs(TC, Inputs, Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && @@ -9435,10 +10061,25 @@ void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - const std::string Linker = TC.GetProgramPath("ld"); - Exec = Args.MakeArgString(Linker); + if (TC.getSanitizerArgs().needsAsanRt()) { + // TODO handle /MT[d] /MD[d] + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); + } else { + for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); + // Make sure the dynamic runtime thunk is not optimized out at link time + // to ensure proper SEH handling. + CmdArgs.push_back(Args.MakeArgString("--undefined")); + CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86 + ? "___asan_seh_interceptor" + : "__asan_seh_interceptor")); + } + } + + Exec = Args.MakeArgString(TC.GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, @@ -9446,35 +10087,46 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - ArgStringList CmdArgs; - assert(Inputs.size() == 1); const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); - assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. - - // Append all -I, -iquote, -isystem paths. - Args.AddAllArgs(CmdArgs, options::OPT_clang_i_Group); - // These are spelled the same way in clang and moviCompile. - Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); + assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || + II.getType() == types::TY_PP_CXX); - CmdArgs.push_back("-DMYRIAD2"); + if (JA.getKind() == Action::PreprocessJobClass) { + Args.ClaimAllArgs(); + CmdArgs.push_back("-E"); + } else { + assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. + CmdArgs.push_back("-S"); + CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. + } CmdArgs.push_back("-mcpu=myriad2"); - CmdArgs.push_back("-S"); - - // Any -O option passes through without translation. What about -Ofast ? - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - A->render(Args, CmdArgs); + CmdArgs.push_back("-DMYRIAD2"); - if (Args.hasFlag(options::OPT_ffunction_sections, - options::OPT_fno_function_sections)) { - CmdArgs.push_back("-ffunction-sections"); + // Append all -I, -iquote, -isystem paths, defines/undefines, + // 'f' flags, optimize flags, and warning options. + // These are spelled the same way in clang and moviCompile. + Args.AddAllArgs(CmdArgs, {options::OPT_I_Group, options::OPT_clang_i_Group, + options::OPT_std_EQ, options::OPT_D, options::OPT_U, + options::OPT_f_Group, options::OPT_f_clang_Group, + options::OPT_g_Group, options::OPT_M_Group, + options::OPT_O_Group, options::OPT_W_Group}); + + // If we're producing a dependency file, and assembly is the final action, + // then the name of the target in the dependency file should be the '.o' + // file, not the '.s' file produced by this step. For example, instead of + // /tmp/mumble.s: mumble.c .../someheader.h + // the filename on the lefthand side should be "mumble.o" + if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && + C.getActions().size() == 1 && + C.getActions()[0]->getKind() == Action::AssembleJobClass) { + Arg *A = Args.getLastArg(options::OPT_o); + if (A) { + CmdArgs.push_back("-MT"); + CmdArgs.push_back(Args.MakeArgString(A->getValue())); + } } - if (Args.hasArg(options::OPT_fno_inline_functions)) - CmdArgs.push_back("-fno-inline-functions"); - - CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. CmdArgs.push_back(II.getFilename()); CmdArgs.push_back("-o"); @@ -9482,8 +10134,8 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, std::string Exec = Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); - C.addCommand( - llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); } void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -9499,13 +10151,14 @@ 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 ? + CmdArgs.push_back("-cv:myriad2"); // Chip Version CmdArgs.push_back("-noSPrefixing"); CmdArgs.push_back("-a"); // Mystery option. - for (auto Arg : Args.filtered(options::OPT_I)) { - Arg->claim(); + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { + A->claim(); CmdArgs.push_back( - Args.MakeArgString(std::string("-i:") + Arg->getValue(0))); + Args.MakeArgString(std::string("-i:") + A->getValue(0))); } CmdArgs.push_back("-elf"); // Output format. CmdArgs.push_back(II.getFilename()); @@ -9514,6 +10167,378 @@ void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, std::string Exec = Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); - C.addCommand( - llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +} + +void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &TC = + static_cast<const toolchains::MyriadToolChain &>(getToolChain()); + const llvm::Triple &T = TC.getTriple(); + ArgStringList CmdArgs; + bool UseStartfiles = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + bool UseDefaultLibs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); + + if (T.getArch() == llvm::Triple::sparc) + CmdArgs.push_back("-EB"); + else // SHAVE assumes little-endian, and sparcel is expressly so. + CmdArgs.push_back("-EL"); + + // The remaining logic is mostly like gnutools::Linker::ConstructJob, + // but we never pass through a --sysroot option and various other bits. + // For example, there are no sanitizers (yet) nor gold linker. + + // Eat some arguments that may be present but have no effect. + Args.ClaimAllArgs(options::OPT_g_Group); + Args.ClaimAllArgs(options::OPT_w); + Args.ClaimAllArgs(options::OPT_static_libgcc); + + if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. + CmdArgs.push_back("-s"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (UseStartfiles) { + // If you want startfiles, it means you want the builtin crti and crtbegin, + // but not crt0. Myriad link commands provide their own crt0.o as needed. + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); + } + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_r}); + + TC.AddFilePathLibArgs(Args, CmdArgs); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + + if (UseDefaultLibs) { + if (C.getDriver().CCCIsCXX()) + CmdArgs.push_back("-lstdc++"); + if (T.getOS() == llvm::Triple::RTEMS) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + // You must provide your own "-L" option to enable finding these. + CmdArgs.push_back("-lrtemscpu"); + CmdArgs.push_back("-lrtemsbsp"); + CmdArgs.push_back("--end-group"); + } else { + CmdArgs.push_back("-lc"); + } + CmdArgs.push_back("-lgcc"); + } + if (UseStartfiles) { + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); + } + + std::string Exec = + Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +} + +void PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + assert(Inputs.size() == 1 && "Unexpected number of inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("ps4-as")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + if (SanArgs.needsUbsanRt()) { + CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); + } + if (SanArgs.needsAsanRt()) { + CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); + } +} + +static void ConstructPS4LinkJob(const Tool &T, Compilation &C, + const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(T.getToolChain()); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("--oformat=so"); + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + AddPS4SanitizerArgs(ToolChain, CmdArgs); + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_r); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + + if (Args.hasArg(options::OPT_pthread)) { + CmdArgs.push_back("-lpthread"); + } + + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld")); + + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +static void ConstructGoldLinkJob(const Tool &T, Compilation &C, + const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(T.getToolChain()); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-Bstatic"); + } else { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + CmdArgs.push_back("--eh-frame-hdr"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-Bshareable"); + } else { + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/libexec/ld-elf.so.1"); + } + CmdArgs.push_back("--enable-new-dtags"); + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + AddPS4SanitizerArgs(ToolChain, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + const char *crt1 = nullptr; + if (!Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_pg)) + crt1 = "gcrt1.o"; + else if (Args.hasArg(options::OPT_pie)) + crt1 = "Scrt1.o"; + else + crt1 = "crt1.o"; + } + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + + const char *crtbegin = nullptr; + if (Args.hasArg(options::OPT_static)) + crtbegin = "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_r); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // For PS4, we always want to pass libm, libstdc++ and libkernel + // libraries for both C and C++ compilations. + CmdArgs.push_back("-lkernel"); + if (D.CCCIsCXX()) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding + // the default system libraries. Just mimic this for now. + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lgcc_p"); + else + CmdArgs.push_back("-lcompiler_rt"); + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lstdc++"); + } else if (Args.hasArg(options::OPT_pg)) { + CmdArgs.push_back("-lgcc_eh_p"); + } else { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("--no-as-needed"); + } + + if (Args.hasArg(options::OPT_pthread)) { + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lpthread_p"); + else + CmdArgs.push_back("-lpthread"); + } + + if (Args.hasArg(options::OPT_pg)) { + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lc"); + else { + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc_p"); + CmdArgs.push_back("-lpthread_p"); + CmdArgs.push_back("--end-group"); + } else { + CmdArgs.push_back("-lc_p"); + } + } + CmdArgs.push_back("-lgcc_p"); + } else { + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("--end-group"); + } else { + CmdArgs.push_back("-lc"); + } + CmdArgs.push_back("-lcompiler_rt"); + } + + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lstdc++"); + } else if (Args.hasArg(options::OPT_pg)) { + CmdArgs.push_back("-lgcc_eh_p"); + } else { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("--no-as-needed"); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + else + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + const char *Exec = +#ifdef LLVM_ON_WIN32 + Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld.gold")); +#else + Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld")); +#endif + + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +void PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + bool PS4Linker; + StringRef LinkerOptName; + if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + LinkerOptName = A->getValue(); + if (LinkerOptName != "ps4" && LinkerOptName != "gold") + D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; + } + + if (LinkerOptName == "gold") + PS4Linker = false; + else if (LinkerOptName == "ps4") + PS4Linker = true; + else + PS4Linker = !Args.hasArg(options::OPT_shared); + + if (PS4Linker) + ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); + else + ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); } diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 651ddc8..314315d 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -14,19 +14,20 @@ #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" namespace clang { - class ObjCRuntime; +class ObjCRuntime; namespace driver { - class Command; - class Driver; +class Command; +class Driver; namespace toolchains { - class MachO; +class MachO; } namespace tools { @@ -37,162 +38,161 @@ class Compiler; using llvm::opt::ArgStringList; -SmallString<128> getCompilerRT(const ToolChain &TC, StringRef Component, - bool Shared = false); - - /// \brief Clang compiler tool. - class LLVM_LIBRARY_VISIBILITY Clang : public Tool { - public: - static const char *getBaseInputName(const llvm::opt::ArgList &Args, - const InputInfo &Input); - static const char *getBaseInputStem(const llvm::opt::ArgList &Args, - const InputInfoList &Inputs); - static const char *getDependencyFileName(const llvm::opt::ArgList &Args, - const InputInfoList &Inputs); - - private: - void AddPreprocessingOptions(Compilation &C, const JobAction &JA, - const Driver &D, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - const InputInfo &Output, - const InputInfoList &Inputs) const; - - void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddARMTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - bool KernelOrKext) const; - void AddARM64TargetArgs(const llvm::opt::ArgList &Args, +SmallString<128> getCompilerRT(const ToolChain &TC, + const llvm::opt::ArgList &Args, + StringRef Component, bool Shared = false); + +/// \brief Clang compiler tool. +class LLVM_LIBRARY_VISIBILITY Clang : public Tool { +public: + static const char *getBaseInputName(const llvm::opt::ArgList &Args, + const InputInfo &Input); + static const char *getBaseInputStem(const llvm::opt::ArgList &Args, + const InputInfoList &Inputs); + static const char *getDependencyFileName(const llvm::opt::ArgList &Args, + const InputInfoList &Inputs); + +private: + void AddPreprocessingOptions(Compilation &C, const JobAction &JA, + const Driver &D, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ToolChain *AuxToolChain) const; + + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddPPCTargetArgs(const llvm::opt::ArgList &Args, + void AddARMTargetArgs(const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + bool KernelOrKext) const; + void AddARM64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - void AddR600TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddSparcTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddSystemZTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddX86TargetArgs(const llvm::opt::ArgList &Args, + void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddPPCTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddR600TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddSparcTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; + void AddSystemZTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddX86TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; - enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; + enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; - ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, - llvm::opt::ArgStringList &cmdArgs, - RewriteKind rewrite) const; + ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, + llvm::opt::ArgStringList &cmdArgs, + RewriteKind rewrite) const; - void AddClangCLArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; + void AddClangCLArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + enum CodeGenOptions::DebugInfoKind *DebugInfoKind, + bool *EmitCodeView) const; - visualstudio::Compiler *getCLFallback() const; - - mutable std::unique_ptr<visualstudio::Compiler> CLFallback; - - public: - // CAUTION! The first constructor argument ("clang") is not arbitrary, - // as it is for other tools. Some operations on a Tool actually test - // whether that tool is Clang based on the Tool's Name as a string. - Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC, RF_Full) {} - - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedAssembler() const override { return true; } - bool hasIntegratedCPP() const override { return true; } - bool canEmitIR() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - - /// \brief Clang integrated assembler tool. - class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { - public: - ClangAs(const ToolChain &TC) : Tool("clang::as", - "clang integrated assembler", TC, - RF_Full) {} - void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedAssembler() const override { return false; } - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - - /// \brief Base class for all GNU tools that provide the same behavior when - /// it comes to response files support - class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { - virtual void anchor(); - - public: - GnuTool(const char *Name, const char *ShortName, const ToolChain &TC) - : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {} - }; - - /// gcc - Generic GCC tool implementations. + visualstudio::Compiler *getCLFallback() const; + + mutable std::unique_ptr<visualstudio::Compiler> CLFallback; + +public: + // CAUTION! The first constructor argument ("clang") is not arbitrary, + // as it is for other tools. Some operations on a Tool actually test + // whether that tool is Clang based on the Tool's Name as a string. + Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC, RF_Full) {} + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + bool canEmitIR() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +/// \brief Clang integrated assembler tool. +class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { +public: + ClangAs(const ToolChain &TC) + : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {} + void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return false; } + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +/// \brief Base class for all GNU tools that provide the same behavior when +/// it comes to response files support +class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { + virtual void anchor(); + +public: + GnuTool(const char *Name, const char *ShortName, const ToolChain &TC) + : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {} +}; + +/// gcc - Generic GCC tool implementations. namespace gcc { - class LLVM_LIBRARY_VISIBILITY Common : public GnuTool { - public: - Common(const char *Name, const char *ShortName, - const ToolChain &TC) : GnuTool(Name, ShortName, TC) {} - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - - /// RenderExtraToolArgs - Render any arguments necessary to force - /// the particular tool mode. - virtual void - RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const = 0; - }; - - class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common { - public: - Preprocessor(const ToolChain &TC) - : Common("gcc::Preprocessor", "gcc preprocessor", TC) {} - - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedCPP() const override { return false; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const override; - }; - - class LLVM_LIBRARY_VISIBILITY Compiler : public Common { - public: - Compiler(const ToolChain &TC) - : Common("gcc::Compiler", "gcc frontend", TC) {} - - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedCPP() const override { return true; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const override; - }; - - class LLVM_LIBRARY_VISIBILITY Linker : public Common { - public: - Linker(const ToolChain &TC) - : Common("gcc::Linker", "linker (via gcc)", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const override; - }; +class LLVM_LIBRARY_VISIBILITY Common : public GnuTool { +public: + Common(const char *Name, const char *ShortName, const ToolChain &TC) + : GnuTool(Name, ShortName, TC) {} + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; + + /// RenderExtraToolArgs - Render any arguments necessary to force + /// the particular tool mode. + virtual void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const = 0; +}; + +class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common { +public: + Preprocessor(const ToolChain &TC) + : Common("gcc::Preprocessor", "gcc preprocessor", TC) {} + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedCPP() const override { return false; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Compiler : public Common { +public: + Compiler(const ToolChain &TC) : Common("gcc::Compiler", "gcc frontend", TC) {} + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Common { +public: + Linker(const ToolChain &TC) : Common("gcc::Linker", "linker (via gcc)", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const override; +}; } // end namespace gcc namespace hexagon { @@ -206,12 +206,12 @@ public: bool hasIntegratedCPP() const override { return false; } - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const; - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { @@ -219,50 +219,88 @@ public: Linker(const ToolChain &TC) : GnuTool("hexagon::Linker", "hexagon-ld", TC) {} bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } + bool isLinkJob() const override { return true; } - virtual void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const; - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + virtual void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace hexagon. -namespace arm { - std::string getARMTargetCPU(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple); - const std::string getARMArch(StringRef Arch, - const llvm::Triple &Triple); - const char* getARMCPUForMArch(StringRef Arch, - const llvm::Triple &Triple); - const char* getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch); +namespace amdgpu { - void appendEBLinkFlags(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs, const llvm::Triple &Triple); -} +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "lld", TC) {} + bool isLinkJob() const override { return true; } + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace amdgpu + +namespace wasm { + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + explicit Linker(const ToolChain &TC); + bool isLinkJob() const override; + bool hasIntegratedCPP() const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace wasm + +namespace arm { +std::string getARMTargetCPU(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple); +const std::string getARMArch(StringRef Arch, + const llvm::Triple &Triple); +StringRef getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple); +StringRef getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple); + +void appendEBLinkFlags(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple); +} // end namespace arm namespace mips { - typedef enum { - NanLegacy = 1, - Nan2008 = 2 - } NanEncoding; - NanEncoding getSupportedNanEncoding(StringRef &CPU); - void getMipsCPUAndABI(const llvm::opt::ArgList &Args, - const llvm::Triple &Triple, StringRef &CPUName, - StringRef &ABIName); - 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 isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, - StringRef ABIName, StringRef FloatABI); - bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, - StringRef CPUName, StringRef ABIName, StringRef FloatABI); -} +typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding; + +enum class FloatABI { + Invalid, + Soft, + Hard, +}; + +NanEncoding getSupportedNanEncoding(StringRef &CPU); +void getMipsCPUAndABI(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple, StringRef &CPUName, + StringRef &ABIName); +std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); +bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); +bool isUCLibc(const llvm::opt::ArgList &Args); +bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, + StringRef ABIName, mips::FloatABI FloatABI); +bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, + StringRef CPUName, StringRef ABIName, + mips::FloatABI FloatABI); +} // end namespace mips namespace ppc { - bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value); -} +bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value); +} // end namespace ppc /// cloudabi -- Directly call GNU Binutils linker namespace cloudabi { @@ -281,103 +319,102 @@ public: } // end namespace cloudabi namespace darwin { - llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); - void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); - - class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { - virtual void anchor(); - protected: - void AddMachOArch(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - - const toolchains::MachO &getMachOToolChain() const { - return reinterpret_cast<const toolchains::MachO&>(getToolChain()); - } - - public: - MachOTool( - const char *Name, const char *ShortName, const ToolChain &TC, - ResponseFileSupport ResponseSupport = RF_None, - llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, - const char *ResponseFlag = "@") - : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding, - ResponseFlag) {} - }; - - class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool { - public: - Assembler(const ToolChain &TC) - : MachOTool("darwin::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - - class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool { - bool NeedsTempPath(const InputInfoList &Inputs) const; - void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - const InputInfoList &Inputs) const; - - public: - Linker(const ToolChain &TC) - : MachOTool("darwin::Linker", "linker", TC, RF_FileList, - llvm::sys::WEM_UTF8, "-filelist") {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - - class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { - public: - Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - - class LLVM_LIBRARY_VISIBILITY Dsymutil : public MachOTool { - public: - Dsymutil(const ToolChain &TC) : MachOTool("darwin::Dsymutil", - "dsymutil", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isDsymutilJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - - class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool { - public: - VerifyDebug(const ToolChain &TC) : MachOTool("darwin::VerifyDebug", - "dwarfdump", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; +llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); +void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); -} +class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { + virtual void anchor(); + +protected: + void AddMachOArch(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + const toolchains::MachO &getMachOToolChain() const { + return reinterpret_cast<const toolchains::MachO &>(getToolChain()); + } + +public: + MachOTool( + const char *Name, const char *ShortName, const ToolChain &TC, + ResponseFileSupport ResponseSupport = RF_None, + llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, + const char *ResponseFlag = "@") + : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding, + ResponseFlag) {} +}; + +class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool { +public: + Assembler(const ToolChain &TC) + : MachOTool("darwin::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool { + bool NeedsTempPath(const InputInfoList &Inputs) const; + void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const InputInfoList &Inputs) const; + +public: + Linker(const ToolChain &TC) + : MachOTool("darwin::Linker", "linker", TC, RF_FileList, + llvm::sys::WEM_UTF8, "-filelist") {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { +public: + Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Dsymutil : public MachOTool { +public: + Dsymutil(const ToolChain &TC) + : MachOTool("darwin::Dsymutil", "dsymutil", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isDsymutilJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool { +public: + VerifyDebug(const ToolChain &TC) + : MachOTool("darwin::VerifyDebug", "dwarfdump", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace darwin /// openbsd -- Directly call GNU Binutils assembler and linker namespace openbsd { @@ -393,6 +430,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("openbsd::Linker", "linker", TC) {} @@ -400,11 +438,11 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace openbsd /// bitrig -- Directly call GNU Binutils assembler and linker @@ -421,6 +459,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("bitrig::Linker", "linker", TC) {} @@ -428,11 +467,11 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace bitrig /// freebsd -- Directly call GNU Binutils assembler and linker @@ -449,6 +488,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("freebsd::Linker", "linker", TC) {} @@ -456,17 +496,16 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace freebsd /// netbsd -- Directly call GNU Binutils assembler and linker namespace netbsd { class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { - public: Assembler(const ToolChain &TC) : GnuTool("netbsd::Assembler", "assembler", TC) {} @@ -478,19 +517,19 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("netbsd::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace netbsd /// Directly call GNU Binutils' assembler and linker. @@ -506,6 +545,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("GNU::Linker", "linker", TC) {} @@ -513,38 +553,37 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace gnutools - namespace nacltools { - class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler { - public: - AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {} - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - class LLVM_LIBRARY_VISIBILITY Linker : public Tool { - public: - Linker(const ToolChain &TC) : Tool("NaCl::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; -} +namespace nacltools { +class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler { +public: + AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {} + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("NaCl::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace nacltools /// minix -- Directly call GNU Binutils assembler and linker namespace minix { @@ -560,6 +599,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("minix::Linker", "linker", TC) {} @@ -567,12 +607,11 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace minix /// solaris -- Directly call Solaris assembler and linker @@ -589,6 +628,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {} @@ -596,11 +636,11 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace solaris /// dragonfly -- Directly call GNU Binutils assembler and linker @@ -617,6 +657,7 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { public: Linker(const ToolChain &TC) : GnuTool("dragonfly::Linker", "linker", TC) {} @@ -624,12 +665,11 @@ public: bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; } // end namespace dragonfly /// Visual studio tools. @@ -644,12 +684,12 @@ public: llvm::sys::WEM_UTF16) {} bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } + bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { @@ -659,20 +699,20 @@ public: llvm::sys::WEM_UTF16) {} bool hasIntegratedAssembler() const override { return true; } - bool hasIntegratedCPP() const override { return true; } - bool isLinkJob() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - - std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const; - }; + bool hasIntegratedCPP() const override { return true; } + bool isLinkJob() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; + + std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const; +}; } // end namespace visualstudio /// MinGW -- Directly call GNU Binutils assembler and linker @@ -707,9 +747,26 @@ private: } // end namespace MinGW namespace arm { - StringRef getARMFloatABI(const Driver &D, const llvm::opt::ArgList &Args, - const llvm::Triple &Triple); -} +enum class FloatABI { + Invalid, + Soft, + SoftFP, + Hard, +}; + +FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); +} // end namespace arm + +namespace ppc { +enum class FloatABI { + Invalid, + Soft, + Hard, +}; + +FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); +} // end namespace ppc + namespace XCore { // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and // Compile. @@ -730,42 +787,41 @@ public: Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {} bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; - } // end namespace XCore. + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace XCore. - namespace CrossWindows { - class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { - public: - Assembler(const ToolChain &TC) - : Tool("CrossWindows::Assembler", "as", TC) {} +namespace CrossWindows { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - }; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; - class LLVM_LIBRARY_VISIBILITY Linker : public Tool { - public: - Linker(const ToolChain &TC) - : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {} +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) + : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {} - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; -} +} // end namespace CrossWindows /// SHAVE tools -- Directly call moviCompile and moviAsm namespace SHAVE { @@ -794,8 +850,55 @@ public: }; } // end namespace SHAVE +/// The Myriad toolchain uses tools that are in two different namespaces. +/// The Compiler and Assembler as defined above are in the SHAVE namespace, +/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, +/// is in the Myriad namespace. +namespace Myriad { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", TC) {} + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace Myriad + +namespace PS4cpu { +class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { +public: + Assemble(const ToolChain &TC) + : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Link : public Tool { +public: + Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace PS4cpu + } // end namespace tools } // end namespace driver } // end namespace clang -#endif +#endif // LLVM_CLANG_LIB_DRIVER_TOOLS_H diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 2085b01..c29ce94 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -128,6 +128,19 @@ bool types::isCXX(ID Id) { } } +bool types::isLLVMIR(ID Id) { + switch (Id) { + default: + return false; + + case TY_LLVM_IR: + case TY_LLVM_BC: + case TY_LTO_IR: + case TY_LTO_BC: + return true; + } +} + bool types::isCuda(ID Id) { switch (Id) { default: |