diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib/Driver | |
parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) |
Notes
Diffstat (limited to 'clang/lib/Driver')
49 files changed, 2309 insertions, 647 deletions
diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp index f2a3074d1e701..06707fefc9d08 100644 --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -13,11 +13,28 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/Triple.h" using namespace clang::driver; using namespace clang; -static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { +static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS, + const llvm::Triple &TargetOrHost) { + // If we don't target Linux, no need to check the distro. This saves a few + // OS calls. + if (!TargetOrHost.isOSLinux()) + return Distro::UnknownDistro; + + // If the host is not running Linux, and we're backed by a real file system, + // no need to check the distro. This is the case where someone is + // cross-compiling from BSD or Windows to Linux, and it would be meaningless + // to try to figure out the "distro" of the non-Linux host. + IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS = + llvm::vfs::getRealFileSystem(); + llvm::Triple HostTriple(llvm::sys::getProcessTriple()); + if (!HostTriple.isOSLinux() && &VFS == RealFS.get()) + return Distro::UnknownDistro; + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = VFS.getBufferForFile("/etc/lsb-release"); if (File) { @@ -52,6 +69,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { .Case("cosmic", Distro::UbuntuCosmic) .Case("disco", Distro::UbuntuDisco) .Case("eoan", Distro::UbuntuEoan) + .Case("focal", Distro::UbuntuFocal) .Default(Distro::UnknownDistro); if (Version != Distro::UnknownDistro) return Version; @@ -148,4 +166,5 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { return Distro::UnknownDistro; } -Distro::Distro(llvm::vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {} +Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost) + : DistroVal(DetectDistro(VFS, TargetOrHost)) {} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index f6016b43b6920..e718b8366df0e 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -8,6 +8,7 @@ #include "clang/Driver/Driver.h" #include "InputInfo.h" +#include "ToolChains/AIX.h" #include "ToolChains/AMDGPU.h" #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" @@ -177,6 +178,7 @@ void Driver::setDriverModeFromOption(StringRef Opt) { .Case("g++", GXXMode) .Case("cpp", CPPMode) .Case("cl", CLMode) + .Case("flang", FlangMode) .Default(None)) Mode = *M; else @@ -290,10 +292,6 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; - // clang interface stubs - } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) { - FinalPhase = phases::IfsMerge; - // -S only runs up to the backend. } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; @@ -539,6 +537,17 @@ static llvm::Triple computeTargetTriple(const Driver &D, } } + // If target is RISC-V adjust the target triple according to + // provided architecture name + A = Args.getLastArg(options::OPT_march_EQ); + if (A && Target.isRISCV()) { + StringRef ArchName = A->getValue(); + if (ArchName.startswith_lower("rv32")) + Target.setArch(llvm::Triple::riscv32); + else if (ArchName.startswith_lower("rv64")) + Target.setArch(llvm::Triple::riscv64); + } + return Target; } @@ -735,7 +744,7 @@ static bool searchForFile(SmallVectorImpl<char> &FilePath, ArrayRef<std::string> Dirs, StringRef FileName) { SmallString<128> WPath; - for (const StringRef &Dir : Dirs) { + for (const std::string &Dir : Dirs) { if (Dir.empty()) continue; WPath.clear(); @@ -1981,8 +1990,9 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, // Handle debug info queries. Arg *A = Args.getLastArg(options::OPT_g_Group); - if (A && !A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_gstabs) && + bool enablesDebugInfo = A && !A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_gstabs); + if ((enablesDebugInfo || willEmitRemarks(Args)) && ContainsCompileOrAssembleAction(Actions.back())) { // Add a 'dsymutil' step if necessary, when debug info is enabled and we @@ -3489,6 +3499,68 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back( C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + if (Args.hasArg(options::OPT_emit_interface_stubs)) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList; + if (Args.hasArg(options::OPT_c)) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> CompilePhaseList; + types::getCompilationPhases(types::TY_IFS_CPP, CompilePhaseList); + llvm::copy_if(CompilePhaseList, std::back_inserter(PhaseList), + [&](phases::ID Phase) { return Phase <= phases::Compile; }); + } else { + types::getCompilationPhases(types::TY_IFS_CPP, PhaseList); + } + + ActionList MergerInputs; + + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; + + // Currently clang and the llvm assembler do not support generating symbol + // stubs from assembly, so we skip the input on asm files. For ifs files + // we rely on the normal pipeline setup in the pipeline setup code above. + if (InputType == types::TY_IFS || InputType == types::TY_PP_Asm || + InputType == types::TY_Asm) + continue; + + Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); + + for (auto Phase : PhaseList) { + switch (Phase) { + default: + llvm_unreachable( + "IFS Pipeline can only consist of Compile followed by IfsMerge."); + case phases::Compile: { + // Only IfsMerge (llvm-ifs) can handle .o files by looking for ifs + // files where the .o file is located. The compile action can not + // handle this. + if (InputType == types::TY_Object) + break; + + Current = C.MakeAction<CompileJobAction>(Current, types::TY_IFS_CPP); + break; + } + case phases::IfsMerge: { + assert(Phase == PhaseList.back() && + "merging must be final compilation step."); + MergerInputs.push_back(Current); + Current = nullptr; + break; + } + } + } + + // If we ended with something, add to the output list. + if (Current) + Actions.push_back(Current); + } + + // Add an interface stubs merge action if necessary. + if (!MergerInputs.empty()) + Actions.push_back( + C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + } + // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom // Compile phase that prints out supported cpu models and quits. if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { @@ -3590,8 +3662,6 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); - if (Args.hasArg(options::OPT_emit_interface_stubs)) - return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP); return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); } case phases::Backend: { @@ -3620,11 +3690,29 @@ void Driver::BuildJobs(Compilation &C) const { Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); // It is an error to provide a -o option if we are making multiple output - // files. + // files. There are exceptions: + // + // IfsMergeJob: when generating interface stubs enabled we want to be able to + // generate the stub file at the same time that we generate the real + // library/a.out. So when a .o, .so, etc are the output, with clang interface + // stubs there will also be a .ifs and .ifso at the same location. + // + // CompileJob of type TY_IFS_CPP: when generating interface stubs is enabled + // and -c is passed, we still want to be able to generate a .ifs file while + // we are also generating .o files. So we allow more than one output file in + // this case as well. + // if (FinalOutput) { unsigned NumOutputs = 0; + unsigned NumIfsOutputs = 0; for (const Action *A : C.getActions()) - if (A->getType() != types::TY_Nothing) + if (A->getType() != types::TY_Nothing && + !(A->getKind() == Action::IfsMergeJobClass || + (A->getType() == clang::driver::types::TY_IFS_CPP && + A->getKind() == clang::driver::Action::CompileJobClass && + 0 == NumIfsOutputs++) || + (A->getKind() == Action::BindArchClass && A->getInputs().size() && + A->getInputs().front()->getKind() == Action::IfsMergeJobClass))) ++NumOutputs; if (NumOutputs > 1) { @@ -4699,6 +4787,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, auto &TC = ToolChains[Target.str()]; if (!TC) { switch (Target.getOS()) { + case llvm::Triple::AIX: + TC = std::make_unique<toolchains::AIX>(*this, Target, Args); + break; case llvm::Triple::Haiku: TC = std::make_unique<toolchains::Haiku>(*this, Target, Args); break; @@ -4872,6 +4963,19 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { return true; } +bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const { + // Say "no" if there is not exactly one input of a type flang understands. + if (JA.size() != 1 || + !types::isFortran((*JA.input_begin())->getType())) + return false; + + // And say "no" if this is not a kind of action flang understands. + if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) + return false; + + return true; +} + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the /// grouped values as integers. Numbers which are not provided are set to 0. /// @@ -4957,3 +5061,26 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { bool clang::driver::isOptimizationLevelFast(const ArgList &Args) { return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false); } + +bool clang::driver::willEmitRemarks(const ArgList &Args) { + // -fsave-optimization-record enables it. + if (Args.hasFlag(options::OPT_fsave_optimization_record, + options::OPT_fno_save_optimization_record, false)) + return true; + + // -fsave-optimization-record=<format> enables it as well. + if (Args.hasFlag(options::OPT_fsave_optimization_record_EQ, + options::OPT_fno_save_optimization_record, false)) + return true; + + // -foptimization-record-file alone enables it too. + if (Args.hasFlag(options::OPT_foptimization_record_file_EQ, + options::OPT_fno_save_optimization_record, false)) + return true; + + // -foptimization-record-passes alone enables it too. + if (Args.hasFlag(options::OPT_foptimization_record_passes_EQ, + options::OPT_fno_save_optimization_record, false)) + return true; + return false; +} diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp index 0a95e49694f95..d57c3a1cdbb89 100644 --- a/clang/lib/Driver/Job.cpp +++ b/clang/lib/Driver/Job.cpp @@ -19,8 +19,10 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -313,15 +315,46 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { Environment.push_back(nullptr); } -int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, - std::string *ErrMsg, bool *ExecutionFailed) const { +void Command::PrintFileNames() const { if (PrintInputFilenames) { for (const char *Arg : InputFilenames) llvm::outs() << llvm::sys::path::filename(Arg) << "\n"; llvm::outs().flush(); } +} - SmallVector<const char*, 128> Argv; +int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, + std::string *ErrMsg, bool *ExecutionFailed) const { + PrintFileNames(); + + SmallVector<const char *, 128> Argv; + if (ResponseFile == nullptr) { + Argv.push_back(Executable); + Argv.append(Arguments.begin(), Arguments.end()); + Argv.push_back(nullptr); + } else { + // If the command is too large, we need to put arguments in a response file. + std::string RespContents; + llvm::raw_string_ostream SS(RespContents); + + // Write file contents and build the Argv vector + writeResponseFile(SS); + buildArgvForResponseFile(Argv); + Argv.push_back(nullptr); + SS.flush(); + + // Save the response file in the appropriate encoding + if (std::error_code EC = writeFileWithEncoding( + ResponseFile, RespContents, Creator.getResponseFileEncoding())) { + if (ErrMsg) + *ErrMsg = EC.message(); + if (ExecutionFailed) + *ExecutionFailed = true; + // Return -1 by convention (see llvm/include/llvm/Support/Program.h) to + // indicate the requested executable cannot be started. + return -1; + } + } Optional<ArrayRef<StringRef>> Env; std::vector<StringRef> ArgvVectorStorage; @@ -332,42 +365,51 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, Env = makeArrayRef(ArgvVectorStorage); } - if (ResponseFile == nullptr) { - Argv.push_back(Executable); - Argv.append(Arguments.begin(), Arguments.end()); - Argv.push_back(nullptr); + auto Args = llvm::toStringRefArray(Argv.data()); + return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, + /*secondsToWait*/ 0, + /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +} - auto Args = llvm::toStringRefArray(Argv.data()); - return llvm::sys::ExecuteAndWait( - Executable, Args, Env, Redirects, /*secondsToWait*/ 0, - /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); - } +void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, + CrashReportInfo *CrashInfo) const { + OS << " (in-process)"; + Command::Print(OS, Terminator, Quote, CrashInfo); +} - // We need to put arguments in a response file (command is too large) - // Open stream to store the response file contents - std::string RespContents; - llvm::raw_string_ostream SS(RespContents); +int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> /*Redirects*/, + std::string *ErrMsg, bool *ExecutionFailed) const { + PrintFileNames(); - // Write file contents and build the Argv vector - writeResponseFile(SS); - buildArgvForResponseFile(Argv); + SmallVector<const char *, 128> Argv; + Argv.push_back(getExecutable()); + Argv.append(getArguments().begin(), getArguments().end()); Argv.push_back(nullptr); - SS.flush(); - - // Save the response file in the appropriate encoding - if (std::error_code EC = writeFileWithEncoding( - ResponseFile, RespContents, Creator.getResponseFileEncoding())) { - if (ErrMsg) - *ErrMsg = EC.message(); - if (ExecutionFailed) - *ExecutionFailed = true; - return -1; + + // This flag simply indicates that the program couldn't start, which isn't + // applicable here. + if (ExecutionFailed) + *ExecutionFailed = false; + + llvm::CrashRecoveryContext CRC; + CRC.DumpStackAndCleanupOnFailure = true; + + const void *PrettyState = llvm::SavePrettyStackState(); + const Driver &D = getCreator().getToolChain().getDriver(); + + int R = 0; + // Enter ExecuteCC1Tool() instead of starting up a new process + if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) { + llvm::RestorePrettyStackState(PrettyState); + return CRC.RetCode; } + return R; +} - auto Args = llvm::toStringRefArray(Argv.data()); - return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, - /*secondsToWait*/ 0, - /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { + // We don't support set a new environment when calling into ExecuteCC1Tool() + llvm_unreachable( + "The CC1Command doesn't support changing the environment vars!"); } FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, diff --git a/clang/lib/Driver/OptionUtils.cpp b/clang/lib/Driver/OptionUtils.cpp new file mode 100644 index 0000000000000..1f36ffc03cab3 --- /dev/null +++ b/clang/lib/Driver/OptionUtils.cpp @@ -0,0 +1,47 @@ +//===--- OptionUtils.cpp - Utilities for command line arguments -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "clang/Driver/OptionUtils.h" +#include "llvm/Option/ArgList.h" + +using namespace clang; +using namespace llvm::opt; + +namespace { +template <typename IntTy> +IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, + IntTy Default, DiagnosticsEngine *Diags, + unsigned Base) { + IntTy Res = Default; + if (Arg *A = Args.getLastArg(Id)) { + if (StringRef(A->getValue()).getAsInteger(Base, Res)) { + if (Diags) + Diags->Report(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + } + } + return Res; +} +} // namespace + +namespace clang { + +int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, + DiagnosticsEngine *Diags, unsigned Base) { + return getLastArgIntValueImpl<int>(Args, Id, Default, Diags, Base); +} + +uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, + uint64_t Default, DiagnosticsEngine *Diags, + unsigned Base) { + return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags, Base); +} + +} // namespace clang diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index cc6c5e6ef438d..ac9a294ee3fa4 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -141,7 +141,7 @@ static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds, clang::SmallString<64> Path(D.ResourceDir); llvm::sys::path::append(Path, "share", BL.File); - if (llvm::sys::fs::exists(Path)) + if (D.getVFS().exists(Path)) BlacklistFiles.push_back(Path.str()); else if (BL.Mask == SanitizerKind::CFI) // If cfi_blacklist.txt cannot be found in the resource dir, driver @@ -557,29 +557,35 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Setup blacklist files. // Add default blacklist from resource directory. - addDefaultBlacklists(D, Kinds, BlacklistFiles); + addDefaultBlacklists(D, Kinds, SystemBlacklistFiles); // Parse -f(no-)sanitize-blacklist options. for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { Arg->claim(); std::string BLPath = Arg->getValue(); - if (llvm::sys::fs::exists(BLPath)) { - BlacklistFiles.push_back(BLPath); - ExtraDeps.push_back(BLPath); + if (D.getVFS().exists(BLPath)) { + UserBlacklistFiles.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(); + UserBlacklistFiles.clear(); + SystemBlacklistFiles.clear(); } } // Validate blacklists format. { std::string BLError; std::unique_ptr<llvm::SpecialCaseList> SCL( - llvm::SpecialCaseList::create(BlacklistFiles, BLError)); + llvm::SpecialCaseList::create(UserBlacklistFiles, D.getVFS(), BLError)); + if (!SCL.get()) + D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; + } + { + std::string BLError; + std::unique_ptr<llvm::SpecialCaseList> SCL(llvm::SpecialCaseList::create( + SystemBlacklistFiles, D.getVFS(), BLError)); if (!SCL.get()) D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; } @@ -952,15 +958,15 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back( Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); - for (const auto &BLPath : BlacklistFiles) { + for (const auto &BLPath : UserBlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); BlacklistOpt += BLPath; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } - for (const auto &Dep : ExtraDeps) { - SmallString<64> ExtraDepOpt("-fdepfile-entry="); - ExtraDepOpt += Dep; - CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); + for (const auto &BLPath : SystemBlacklistFiles) { + SmallString<64> BlacklistOpt("-fsanitize-system-blacklist="); + BlacklistOpt += BLPath; + CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } if (MsanTrackOrigins) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 357a5106ab393..3ebbd30195b31 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -11,6 +11,7 @@ #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" #include "ToolChains/InterfaceStubs.h" +#include "ToolChains/Flang.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -67,7 +68,8 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, } // -frtti is default, except for the PS4 CPU. - return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; + return (Triple.isPS4CPU() || Triple.isNVPTX()) ? ToolChain::RM_Disabled + : ToolChain::RM_Enabled; } ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, @@ -151,6 +153,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { {"cpp", "--driver-mode=cpp"}, {"cl", "--driver-mode=cl"}, {"++", "--driver-mode=g++"}, + {"flang", "--driver-mode=flang"}, }; for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { @@ -254,6 +257,12 @@ Tool *ToolChain::getClang() const { return Clang.get(); } +Tool *ToolChain::getFlang() const { + if (!Flang) + Flang.reset(new tools::Flang(*this)); + return Flang.get(); +} + Tool *ToolChain::buildAssembler() const { return new tools::ClangAs(*this); } @@ -493,6 +502,7 @@ bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) { } Tool *ToolChain::SelectTool(const JobAction &JA) const { + if (D.IsFlangMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang(); if (getDriver().ShouldUseClangCompiler(JA)) return getClang(); Action::ActionClass AC = JA.getKind(); if (AC == Action::AssembleJobClass && useIntegratedAs()) @@ -541,7 +551,15 @@ std::string ToolChain::GetLinkerPath() const { } types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const { - return types::lookupTypeForExtension(Ext); + types::ID id = types::lookupTypeForExtension(Ext); + + // Flang always runs the preprocessor and has no notion of "preprocessed + // fortran". Here, TY_PP_Fortran is coerced to TY_Fortran to avoid treating + // them differently. + if (D.IsFlangMode() && id == types::TY_PP_Fortran) + id = types::TY_Fortran; + + return id; } bool ToolChain::HasNativeLLVMSupport() const { @@ -620,6 +638,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, Triple.setArchName("arm64"); return Triple.getTriple(); } + case llvm::Triple::aarch64_32: + return getTripleString(); case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: @@ -831,7 +851,7 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, ArrayRef<StringRef> Paths) { - for (const auto Path : Paths) { + for (const auto &Path : Paths) { CC1Args.push_back("-internal-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(Path)); } diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp new file mode 100644 index 0000000000000..6fbff61f76565 --- /dev/null +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -0,0 +1,159 @@ +//===--- AIX.cpp - AIX ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AIX.h" +#include "Arch/PPC.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" + +using AIX = clang::driver::toolchains::AIX; +using namespace clang::driver; +using namespace clang::driver::tools; + +using namespace llvm::opt; + +void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit(); + const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit(); + // Only support 32 and 64 bit. + if (!IsArch32Bit && !IsArch64Bit) + llvm_unreachable("Unsupported bit width value."); + + // Specify the mode in which the as(1) command operates. + if (IsArch32Bit) { + CmdArgs.push_back("-a32"); + } else { + // Must be 64-bit, otherwise asserted already. + CmdArgs.push_back("-a64"); + } + + // Accept an undefined symbol as an extern so that an error message is not + // displayed. Otherwise, undefined symbols are flagged with error messages. + // FIXME: This should be removed when the assembly generation from the + // compiler is able to write externs properly. + CmdArgs.push_back("-u"); + + // Accept any mixture of instructions. + // On Power for AIX and Linux, this behaviour matches that of GCC for both the + // user-provided assembler source case and the compiler-produced assembler + // source case. Yet XL with user-provided assembler source would not add this. + CmdArgs.push_back("-many"); + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Specify assembler output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Specify assembler input file. + // The system assembler on AIX takes exactly one input file. The driver is + // expected to invoke as(1) separately for each assembler source input file. + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + const InputInfo &II = Inputs[0]; + assert((II.isFilename() || II.isNothing()) && "Invalid input."); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + const AIX &ToolChain = static_cast<const AIX &>(getToolChain()); + ArgStringList CmdArgs; + + const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit(); + const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit(); + // Only support 32 and 64 bit. + if (!(IsArch32Bit || IsArch64Bit)) + llvm_unreachable("Unsupported bit width value."); + + // Force static linking when "-static" is present. + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-bnso"); + + // Specify linker output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Set linking mode (i.e., 32/64-bit) and the address of + // text and data sections based on arch bit width. + if (IsArch32Bit) { + CmdArgs.push_back("-b32"); + CmdArgs.push_back("-bpT:0x10000000"); + CmdArgs.push_back("-bpD:0x20000000"); + } else { + // Must be 64-bit, otherwise asserted already. + CmdArgs.push_back("-b64"); + CmdArgs.push_back("-bpT:0x100000000"); + CmdArgs.push_back("-bpD:0x110000000"); + } + + auto getCrt0Basename = [&Args, IsArch32Bit] { + // Enable gprofiling when "-pg" is specified. + if (Args.hasArg(options::OPT_pg)) + return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o"; + // Enable profiling when "-p" is specified. + else if (Args.hasArg(options::OPT_p)) + return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o"; + else + return IsArch32Bit ? "crt0.o" : "crt0_64.o"; + }; + + if (!Args.hasArg(options::OPT_nostdlib)) { + CmdArgs.push_back( + Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename()))); + } + + // Specify linker input file(s). + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // Add directory to library search path. + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // Support POSIX threads if "-pthreads" or "-pthread" is present. + if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) + CmdArgs.push_back("-lpthreads"); + + CmdArgs.push_back("-lc"); + } + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// AIX - AIX tool chain which can call as(1) and ld(1) directly. +AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : ToolChain(D, Triple, Args) { + getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); } + +auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h new file mode 100644 index 0000000000000..69b948bc0ea82 --- /dev/null +++ b/clang/lib/Driver/ToolChains/AIX.h @@ -0,0 +1,75 @@ +//===--- AIX.h - AIX ToolChain Implementations ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// aix -- Directly call system default assembler and linker. +namespace aix { + +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("aix::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 aix + +} // end namespace tools +} // end namespace driver +} // end namespace clang + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY AIX : public ToolChain { +public: + AIX(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool isPICDefault() const override { return true; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return true; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index 5585cc5348615..f4c78bea5cc97 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -55,7 +55,7 @@ protected: public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - unsigned GetDefaultDwarfVersion() const override { return 5; } + unsigned GetDefaultDwarfVersion() const override { return 4; } bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 3a5fe6ddeaed5..9c27504dccf5b 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -43,10 +43,11 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, else if (CPU.size()) return CPU; - // Make sure we pick "cyclone" if -arch is used or when targetting a Darwin - // OS. + // Make sure we pick the appropriate Apple CPU if -arch is used or when + // targetting a Darwin OS. if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin()) - return "cyclone"; + return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4" + : "apple-a7"; return "generic"; } @@ -139,7 +140,7 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = llvm::sys::getHostCPUName(); - if (MtuneLowerCase == "cyclone") { + if (MtuneLowerCase == "cyclone" || MtuneLowerCase.find("apple") == 0) { Features.push_back("+zcm"); Features.push_back("+zcz"); } diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 68a57310ad402..a1923e731489e 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -63,12 +63,13 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A, } // Handle -mfpu=. -static void getARMFPUFeatures(const Driver &D, const Arg *A, - const ArgList &Args, StringRef FPU, - std::vector<StringRef> &Features) { +static unsigned getARMFPUFeatures(const Driver &D, const Arg *A, + const ArgList &Args, StringRef FPU, + std::vector<StringRef> &Features) { unsigned FPUID = llvm::ARM::parseFPU(FPU); if (!llvm::ARM::getFPUFeatures(FPUID, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return FPUID; } // Decode ARM features from string like +[no]featureA+[no]featureB+... @@ -388,18 +389,20 @@ void arm::getARMTargetFeatures(const ToolChain &TC, checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures, Triple); // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. + unsigned FPUID = llvm::ARM::FK_INVALID; 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); + (void)getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), + Features); } else if (FPUArg) { - getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); + FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { const char *AndroidFPU = "neon"; - if (!llvm::ARM::getFPUFeatures(llvm::ARM::parseFPU(AndroidFPU), Features)) + FPUID = llvm::ARM::parseFPU(AndroidFPU); + if (!llvm::ARM::getFPUFeatures(FPUID, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << std::string("-mfpu=") + AndroidFPU; } @@ -454,21 +457,21 @@ fp16_fml_fallthrough: if (ABI == arm::FloatABI::Soft) { llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); - // Disable all features relating to hardware FP. - // FIXME: Disabling fpregs should be enough all by itself, since all - // the other FP features are dependent on it. However - // there is currently no easy way to test this in clang, so for - // now just be explicit and disable all known dependent features - // as well. - for (std::string Feature : { - "vfp2", "vfp2sp", - "vfp3", "vfp3sp", "vfp3d16", "vfp3d16sp", - "vfp4", "vfp4sp", "vfp4d16", "vfp4d16sp", - "fp-armv8", "fp-armv8sp", "fp-armv8d16", "fp-armv8d16sp", - "fullfp16", "neon", "crypto", "dotprod", "fp16fml", - "mve", "mve.fp", - "fp64", "d32", "fpregs"}) - Features.push_back(Args.MakeArgString("-" + Feature)); + // Disable all features relating to hardware FP, not already disabled by the + // above call. + Features.insert(Features.end(), {"-neon", "-crypto", "-dotprod", "-fp16fml", + "-mve", "-mve.fp", "-fpregs"}); + } else if (FPUID == llvm::ARM::FK_NONE) { + // -mfpu=none is *very* similar to -mfloat-abi=soft, only that it should not + // disable MVE-I. + Features.insert(Features.end(), + {"-neon", "-crypto", "-dotprod", "-fp16fml", "-mve.fp"}); + // Even though we remove MVE-FP, we still need to check if it was originally + // present among the requested extensions, because it implies MVE-I, which + // should not be disabled by -mfpu-none. + if (!llvm::is_contained(Features, "+mve") && + !llvm::is_contained(Features, "+mve.fp")) + Features.emplace_back("-fpregs"); } // En/disable crc code generation. diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp index 3e02e57e0f6c7..f1baadaebf41b 100644 --- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -53,10 +53,12 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { .Case("7450", "7450") .Case("G4+", "g4+") .Case("750", "750") + .Case("8548", "e500") .Case("970", "970") .Case("G5", "g5") .Case("a2", "a2") .Case("a2q", "a2q") + .Case("e500", "e500") .Case("e500mc", "e500mc") .Case("e5500", "e5500") .Case("power3", "pwr3") @@ -68,6 +70,7 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { .Case("power7", "pwr7") .Case("power8", "pwr8") .Case("power9", "pwr9") + .Case("future", "future") .Case("pwr3", "pwr3") .Case("pwr4", "pwr4") .Case("pwr5", "pwr5") @@ -101,6 +104,9 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) { void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { + if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) + Features.push_back("+spe"); + handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 624788a5874e3..8c343b8693f32 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -357,16 +357,75 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { - llvm::Optional<StringRef> MArch; - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) - MArch = A->getValue(); - else if (Triple.getOS() == llvm::Triple::Linux) - // RISC-V Linux defaults to rv{32,64}gc. - MArch = Triple.getArch() == llvm::Triple::riscv32 ? "rv32gc" : "rv64gc"; + StringRef MArch = getRISCVArch(Args, Triple); - if (MArch.hasValue() && !getArchFeatures(D, *MArch, Features, Args)) + if (!getArchFeatures(D, MArch, Features, Args)) return; + // Handle features corresponding to "-ffixed-X" options + if (Args.hasArg(options::OPT_ffixed_x1)) + Features.push_back("+reserve-x1"); + if (Args.hasArg(options::OPT_ffixed_x2)) + Features.push_back("+reserve-x2"); + if (Args.hasArg(options::OPT_ffixed_x3)) + Features.push_back("+reserve-x3"); + if (Args.hasArg(options::OPT_ffixed_x4)) + Features.push_back("+reserve-x4"); + if (Args.hasArg(options::OPT_ffixed_x5)) + Features.push_back("+reserve-x5"); + if (Args.hasArg(options::OPT_ffixed_x6)) + Features.push_back("+reserve-x6"); + if (Args.hasArg(options::OPT_ffixed_x7)) + Features.push_back("+reserve-x7"); + if (Args.hasArg(options::OPT_ffixed_x8)) + Features.push_back("+reserve-x8"); + if (Args.hasArg(options::OPT_ffixed_x9)) + Features.push_back("+reserve-x9"); + if (Args.hasArg(options::OPT_ffixed_x10)) + Features.push_back("+reserve-x10"); + if (Args.hasArg(options::OPT_ffixed_x11)) + Features.push_back("+reserve-x11"); + if (Args.hasArg(options::OPT_ffixed_x12)) + Features.push_back("+reserve-x12"); + if (Args.hasArg(options::OPT_ffixed_x13)) + Features.push_back("+reserve-x13"); + if (Args.hasArg(options::OPT_ffixed_x14)) + Features.push_back("+reserve-x14"); + if (Args.hasArg(options::OPT_ffixed_x15)) + Features.push_back("+reserve-x15"); + if (Args.hasArg(options::OPT_ffixed_x16)) + Features.push_back("+reserve-x16"); + if (Args.hasArg(options::OPT_ffixed_x17)) + Features.push_back("+reserve-x17"); + if (Args.hasArg(options::OPT_ffixed_x18)) + Features.push_back("+reserve-x18"); + if (Args.hasArg(options::OPT_ffixed_x19)) + Features.push_back("+reserve-x19"); + if (Args.hasArg(options::OPT_ffixed_x20)) + Features.push_back("+reserve-x20"); + if (Args.hasArg(options::OPT_ffixed_x21)) + Features.push_back("+reserve-x21"); + if (Args.hasArg(options::OPT_ffixed_x22)) + Features.push_back("+reserve-x22"); + if (Args.hasArg(options::OPT_ffixed_x23)) + Features.push_back("+reserve-x23"); + if (Args.hasArg(options::OPT_ffixed_x24)) + Features.push_back("+reserve-x24"); + if (Args.hasArg(options::OPT_ffixed_x25)) + Features.push_back("+reserve-x25"); + if (Args.hasArg(options::OPT_ffixed_x26)) + Features.push_back("+reserve-x26"); + if (Args.hasArg(options::OPT_ffixed_x27)) + Features.push_back("+reserve-x27"); + if (Args.hasArg(options::OPT_ffixed_x28)) + Features.push_back("+reserve-x28"); + if (Args.hasArg(options::OPT_ffixed_x29)) + Features.push_back("+reserve-x29"); + if (Args.hasArg(options::OPT_ffixed_x30)) + Features.push_back("+reserve-x30"); + if (Args.hasArg(options::OPT_ffixed_x31)) + Features.push_back("+reserve-x31"); + // -mrelax is default, unless -mno-relax is specified. if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) Features.push_back("+relax"); @@ -391,12 +450,132 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { Triple.getArch() == llvm::Triple::riscv64) && "Unexpected triple"); + // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not + // configured using `--with-abi=`, then the logic for the default choice is + // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We + // deviate from GCC's default only on baremetal targets (UnknownOS) where + // neither `-march` nor `-mabi` is specified. + // + // The logic uses the following, in order: + // 1. Explicit choices using `--with-abi=` + // 2. A default based on `--with-arch=`, if provided + // 3. A default based on the target triple's arch + // + // The logic in config.gcc is a little circular but it is not inconsistent. + // + // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` + // and `-mabi=` respectively instead. + + // 1. If `-mabi=` is specified, use it. if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) return A->getValue(); - // RISC-V Linux defaults to ilp32d/lp64d - if (Triple.getOS() == llvm::Triple::Linux) - return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32d" : "lp64d"; - else - return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64"; + // 2. Choose a default based on `-march=` + // + // rv32g | rv32*d -> ilp32d + // rv32e -> ilp32e + // rv32* -> ilp32 + // rv64g | rv64*d -> lp64d + // rv64* -> lp64 + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + StringRef MArch = A->getValue(); + + if (MArch.startswith_lower("rv32")) { + // FIXME: parse `March` to find `D` extension properly + if (MArch.substr(4).contains_lower("d") || + MArch.startswith_lower("rv32g")) + return "ilp32d"; + else if (MArch.startswith_lower("rv32e")) + return "ilp32e"; + else + return "ilp32"; + } else if (MArch.startswith_lower("rv64")) { + // FIXME: parse `March` to find `D` extension properly + if (MArch.substr(4).contains_lower("d") || + MArch.startswith_lower("rv64g")) + return "lp64d"; + else + return "lp64"; + } + } + + // 3. Choose a default based on the triple + // + // We deviate from GCC's defaults here: + // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. + // - On all other OSs we use the double floating point calling convention. + if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "ilp32"; + else + return "ilp32d"; + } else { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "lp64"; + else + return "lp64d"; + } +} + +StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + assert((Triple.getArch() == llvm::Triple::riscv32 || + Triple.getArch() == llvm::Triple::riscv64) && + "Unexpected triple"); + + // GCC's logic around choosing a default `-march=` is complex. If GCC is not + // configured using `--with-arch=`, then the logic for the default choice is + // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We + // deviate from GCC's default only on baremetal targets (UnknownOS) where + // neither `-march` nor `-mabi` is specified. + // + // The logic uses the following, in order: + // 1. Explicit choices using `--with-arch=` + // 2. A default based on `--with-abi=`, if provided + // 3. A default based on the target triple's arch + // + // The logic in config.gcc is a little circular but it is not inconsistent. + // + // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` + // and `-mabi=` respectively instead. + // + // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc` + // instead of `rv{XLEN}gc` though they are (currently) equivalent. + + // 1. If `-march=` is specified, use it. + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + + // 2. Choose a default based on `-mabi=` + // + // ilp32e -> rv32e + // ilp32 | ilp32f | ilp32d -> rv32imafdc + // lp64 | lp64f | lp64d -> rv64imafdc + if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + StringRef MABI = A->getValue(); + + if (MABI.equals_lower("ilp32e")) + return "rv32e"; + else if (MABI.startswith_lower("ilp32")) + return "rv32imafdc"; + else if (MABI.startswith_lower("lp64")) + return "rv64imafdc"; + } + + // 3. Choose a default based on the triple + // + // We deviate from GCC's defaults here: + // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` + // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) + if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "rv32imac"; + else + return "rv32imafdc"; + } else { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "rv64imac"; + else + return "rv64imafdc"; + } } diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.h b/clang/lib/Driver/ToolChains/Arch/RISCV.h index 10eaf3c897b68..d4a519cdab340 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.h +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.h @@ -24,6 +24,8 @@ void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, std::vector<llvm::StringRef> &Features); StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +StringRef getRISCVArch(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); } // end namespace riscv } // namespace tools } // end namespace driver diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index ca60b85cf8a05..2b77d59fdc66b 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -9,15 +9,27 @@ #include "SystemZ.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Host.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -const char *systemz::getSystemZTargetCPU(const ArgList &Args) { - if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) - return A->getValue(); +std::string systemz::getSystemZTargetCPU(const ArgList &Args) { + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { + llvm::StringRef CPUName = A->getValue(); + + if (CPUName == "native") { + std::string CPU = llvm::sys::getHostCPUName(); + if (!CPU.empty() && CPU != "generic") + return CPU; + else + return ""; + } + + return CPUName; + } return "z10"; } diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/clang/lib/Driver/ToolChains/Arch/SystemZ.h index 11d77fa01cc88..77dcbc47be5c0 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.h +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Option/Option.h" +#include <string> #include <vector> namespace clang { @@ -18,7 +19,7 @@ namespace driver { namespace tools { namespace systemz { -const char *getSystemZTargetCPU(const llvm::opt::ArgList &Args); +std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args); void getSystemZTargetFeatures(const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index d2b97bf6ad719..d1e0c8253b799 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -63,8 +63,7 @@ const char *x86::getX86TargetCPU(const ArgList &Args, // Select the default CPU if none was given (or detection failed). - if (Triple.getArch() != llvm::Triple::x86_64 && - Triple.getArch() != llvm::Triple::x86) + if (!Triple.isX86()) return nullptr; // This routine is only handling x86 targets. bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 55d631733add2..9b3055413e9e6 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -302,6 +302,96 @@ static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, } } +static void getWebAssemblyTargetFeatures(const ArgList &Args, + std::vector<StringRef> &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<StringRef> Features; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + mips::getMIPSTargetFeatures(D, Triple, Args, Features); + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); + break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + ppc::getPPCTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + riscv::getRISCVTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::systemz: + systemz::getSystemZTargetFeatures(Args, Features); + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + aarch64::getAArch64TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + x86::getX86TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::hexagon: + hexagon::getHexagonTargetFeatures(D, Args, Features); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + getWebAssemblyTargetFeatures(Args, Features); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + sparc::getSparcTargetFeatures(D, Args, Features); + break; + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + amdgpu::getAMDGPUTargetFeatures(D, Args, Features); + break; + case llvm::Triple::msp430: + msp430::getMSP430TargetFeatures(D, Args, Features); + } + + // Find the last of each feature. + llvm::StringMap<unsigned> LastOpt; + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + StringRef Name = Features[I]; + assert(Name[0] == '-' || Name[0] == '+'); + LastOpt[Name.drop_front(1)] = I; + } + + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + // If this feature was overridden, ignore it. + StringRef Name = Features[I]; + llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); + assert(LastI != LastOpt.end()); + unsigned Last = LastI->second; + if (Last != I) + continue; + + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(Name.data()); + } +} + static bool shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { @@ -378,15 +468,20 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fexceptions"); } -static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) { +static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC, + const JobAction &JA) { bool Default = true; if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support the linker_option directives, // so we disable them if we think the .s file will be passed to it. Default = TC.useIntegratedAs(); } - return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, - Default); + // The linker_option directives are intended for host compilation. + if (JA.isDeviceOffloading(Action::OFK_Cuda) || + JA.isDeviceOffloading(Action::OFK_HIP)) + Default = false; + return Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, + Default); } static bool ShouldDisableDwarfDirectory(const ArgList &Args, @@ -443,6 +538,8 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, case llvm::Triple::ppc64le: case llvm::Triple::riscv32: case llvm::Triple::riscv64: + case llvm::Triple::amdgcn: + case llvm::Triple::r600: return !areOptimizationsEnabled(Args); default: break; @@ -506,9 +603,9 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); bool NoOmitFP = A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); - bool KeepLeaf = - Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, Triple.isPS4CPU()); + bool KeepLeaf = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, + options::OPT_mno_omit_leaf_frame_pointer, + Triple.isAArch64() || Triple.isPS4CPU()); if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { if (KeepLeaf) @@ -533,16 +630,33 @@ static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, /// Add a CC1 and CC1AS option to specify the debug file path prefix map. static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { - for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + 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; + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); else CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); A->claim(); } } +/// Add a CC1 and CC1AS option to specify the macro file path prefix map. +static void addMacroPrefixMapArg(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fmacro_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else + CmdArgs.push_back(Args.MakeArgString("-fmacro-prefix-map=" + Map)); + A->claim(); + } +} + /// Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disabled, while the slp vectorizer is /// enabled. @@ -802,7 +916,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && (EmitCovNotes || EmitCovData) && Output.isFilename()) { SmallString<128> OutputFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_Fo)) + OutputFilename = FinalOutput->getValue(); + else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) OutputFilename = FinalOutput->getValue(); else OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); @@ -883,6 +999,9 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, case codegenoptions::DebugLineTablesOnly: CmdArgs.push_back("-debug-info-kind=line-tables-only"); break; + case codegenoptions::DebugInfoConstructor: + CmdArgs.push_back("-debug-info-kind=constructor"); + break; case codegenoptions::LimitedDebugInfo: CmdArgs.push_back("-debug-info-kind=limited"); break; @@ -1248,6 +1367,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // For IAMCU add special include arguments. getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); } + + addMacroPrefixMapArg(D, Args, CmdArgs); } // FIXME: Move to target hook. @@ -1257,6 +1378,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { return true; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: @@ -1296,6 +1418,116 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) { } } +static bool hasMultipleInvocations(const llvm::Triple &Triple, + const ArgList &Args) { + // Supported only on Darwin where we invoke the compiler multiple times + // followed by an invocation to lipo. + if (!Triple.isOSDarwin()) + return false; + // If more than one "-arch <arch>" is specified, we're targeting multiple + // architectures resulting in a fat binary. + return Args.getAllArgValues(options::OPT_arch).size() > 1; +} + +static bool checkRemarksOptions(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + // When enabling remarks, we need to error if: + // * The remark file is specified but we're targeting multiple architectures, + // which means more than one remark file is being generated. + bool hasMultipleInvocations = ::hasMultipleInvocations(Triple, Args); + bool hasExplicitOutputFile = + Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (hasMultipleInvocations && hasExplicitOutputFile) { + D.Diag(diag::err_drv_invalid_output_with_multiple_archs) + << "-foptimization-record-file"; + return false; + } + return true; +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Input, + const InputInfo &Output, const JobAction &JA) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-opt-record-file"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + bool hasMultipleArchs = + Triple.isOSDarwin() && // Only supported on Darwin platforms. + Args.getAllArgValues(options::OPT_arch).size() > 1; + + SmallString<128> F; + + if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) + F = FinalOutput->getValue(); + } else { + if (Format != "yaml" && // For YAML, keep the original behavior. + Triple.isOSDarwin() && // Enable this only on darwin, since it's the only platform supporting .dSYM bundles. + Output.isFilename()) + F = Output.getFilename(); + } + + if (F.empty()) { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + + // If we're compiling for an offload architecture (i.e. a CUDA device), + // we need to make the file name for the device compilation different + // from the host compilation. + if (!JA.isDeviceOffloading(Action::OFK_None) && + !JA.isDeviceOffloading(Action::OFK_Host)) { + llvm::sys::path::replace_extension(F, ""); + F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), + Triple.normalize()); + F += "-"; + F += JA.getOffloadingArch(); + } + } + + // If we're having more than one "-arch", we should name the files + // differently so that every cc1 invocation writes to a different file. + // We're doing that by appending "-<arch>" with "<arch>" being the arch + // name from the triple. + if (hasMultipleArchs) { + // First, remember the extension. + SmallString<64> OldExtension = llvm::sys::path::extension(F); + // then, remove it. + llvm::sys::path::replace_extension(F, ""); + // attach -<arch> to it. + F += "-"; + F += Triple.getArchName(); + // put back the extension. + llvm::sys::path::replace_extension(F, OldExtension); + } + + SmallString<32> Extension; + Extension += "opt."; + Extension += Format; + + llvm::sys::path::replace_extension(F, Extension); + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-opt-record-passes"); + CmdArgs.push_back(A->getValue()); + } + + if (!Format.empty()) { + CmdArgs.push_back("-opt-record-format"); + CmdArgs.push_back(Format.data()); + } +} + namespace { void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs) { @@ -1379,6 +1611,7 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, break; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: AddAArch64TargetArgs(Args, CmdArgs); CmdArgs.push_back("-fallow-half-arguments-and-returns"); @@ -1432,56 +1665,6 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, } } -// Parse -mbranch-protection=<protection>[+<protection>]* where -// <protection> ::= standard | none | [bti,pac-ret[+b-key,+leaf]*] -// Returns a triple of (return address signing Scope, signing key, require -// landing pads) -static std::tuple<StringRef, StringRef, bool> -ParseAArch64BranchProtection(const Driver &D, const ArgList &Args, - const Arg *A) { - StringRef Scope = "none"; - StringRef Key = "a_key"; - bool IndirectBranches = false; - - StringRef Value = A->getValue(); - // This maps onto -mbranch-protection=<scope>+<key> - - if (Value.equals("standard")) { - Scope = "non-leaf"; - Key = "a_key"; - IndirectBranches = true; - - } else if (!Value.equals("none")) { - SmallVector<StringRef, 4> BranchProtection; - StringRef(A->getValue()).split(BranchProtection, '+'); - - auto Protection = BranchProtection.begin(); - while (Protection != BranchProtection.end()) { - if (Protection->equals("bti")) - IndirectBranches = true; - else if (Protection->equals("pac-ret")) { - Scope = "non-leaf"; - while (++Protection != BranchProtection.end()) { - // Inner loop as "leaf" and "b-key" options must only appear attached - // to pac-ret. - if (Protection->equals("leaf")) - Scope = "all"; - else if (Protection->equals("b-key")) - Key = "b_key"; - else - break; - } - Protection--; - } else - D.Diag(diag::err_invalid_branch_protection) - << *Protection << A->getAsString(Args); - Protection++; - } - } - - return std::make_tuple(Scope, Key, IndirectBranches); -} - namespace { void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs) { @@ -1553,9 +1736,16 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, << Scope << A->getAsString(Args); Key = "a_key"; IndirectBranches = false; - } else - std::tie(Scope, Key, IndirectBranches) = - ParseAArch64BranchProtection(D, Args, A); + } else { + StringRef Err; + llvm::AArch64::ParsedBranchProtection PBP; + if (!llvm::AArch64::parseBranchProtection(A->getValue(), PBP, Err)) + D.Diag(diag::err_invalid_branch_protection) + << Err << A->getAsString(Args); + Scope = PBP.Scope; + Key = PBP.Key; + IndirectBranches = PBP.BranchTargetEnforcement; + } CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address=") + Scope)); @@ -1713,7 +1903,8 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Select the ABI to use. const char *ABIName = nullptr; - if (getToolChain().getTriple().isOSLinux()) + const llvm::Triple &T = getToolChain().getTriple(); + if (T.isOSBinFormatELF()) { switch (getToolChain().getArch()) { case llvm::Triple::ppc64: { // When targeting a processor that supports QPX, or if QPX is @@ -1728,7 +1919,10 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, break; } - ABIName = "elfv1"; + if (T.isMusl() || (T.isOSFreeBSD() && T.getOSMajorVersion() >= 13)) + ABIName = "elfv2"; + else + ABIName = "elfv1"; break; } case llvm::Triple::ppc64le: @@ -1737,6 +1931,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, default: break; } + } bool IEEELongDouble = false; for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) { @@ -1804,12 +1999,75 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, void Clang::AddSystemZTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false)) + bool HasBackchain = Args.hasFlag(options::OPT_mbackchain, + options::OPT_mno_backchain, false); + bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack, + options::OPT_mno_packed_stack, false); + if (HasBackchain && HasPackedStack) { + const Driver &D = getToolChain().getDriver(); + D.Diag(diag::err_drv_unsupported_opt) + << Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) + + " " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args); + } + if (HasBackchain) CmdArgs.push_back("-mbackchain"); + if (HasPackedStack) + CmdArgs.push_back("-mpacked-stack"); +} + +static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-x86-branches-within-32B-boundaries"); + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { + StringRef Value = A->getValue(); + unsigned Boundary; + if (Value.getAsInteger(10, Boundary) || Boundary < 16 || + !llvm::isPowerOf2_64(Boundary)) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString("-x86-align-branch-boundary=" + Twine(Boundary))); + } + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { + std::string AlignBranch; + for (StringRef T : A->getValues()) { + if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" && + T != "ret" && T != "indirect") + D.Diag(diag::err_drv_invalid_malign_branch_EQ) + << T << "fused, jcc, jmp, call, ret, indirect"; + if (!AlignBranch.empty()) + AlignBranch += '+'; + AlignBranch += T; + } + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + AlignBranch)); + } + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) { + StringRef Value = A->getValue(); + unsigned PrefixSize; + if (Value.getAsInteger(10, PrefixSize) || PrefixSize > 5) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=" + + Twine(PrefixSize))); + } + } } void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + addX86AlignBranchArgs(D, Args, CmdArgs); + if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) @@ -1839,10 +2097,10 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); } else { - getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } - } else if (getToolChain().getDriver().IsCLMode()) { + } else if (D.IsCLMode()) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-x86-asm-syntax=intel"); } @@ -2193,6 +2451,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value == "-fdebug-compilation-dir") { CmdArgs.push_back("-fdebug-compilation-dir"); TakeNextArg = true; + } else if (Value.consume_front("-fdebug-compilation-dir=")) { + // The flag is a -Wa / -Xassembler argument and Options doesn't + // parse the argument, so this isn't automatically aliased to + // -fdebug-compilation-dir (without '=') here. + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Value.data()); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -2229,9 +2493,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool AssociativeMath = false; bool ReciprocalMath = false; bool SignedZeros = true; - bool TrappingMath = true; + bool TrappingMath = false; // Implemented via -ffp-exception-behavior + bool TrappingMathPresent = false; // Is trapping-math in args, and not + // overriden by ffp-exception-behavior? + bool RoundingFPMath = false; + bool RoundingMathPresent = false; // Is rounding-math in args? + // -ffp-model values: strict, fast, precise + StringRef FPModel = ""; + // -ffp-exception-behavior options: strict, maytrap, ignore + StringRef FPExceptionBehavior = ""; StringRef DenormalFPMath = ""; StringRef FPContract = ""; + bool StrictFPModel = false; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2239,7 +2512,65 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } for (const Arg *A : Args) { - switch (A->getOption().getID()) { + auto optID = A->getOption().getID(); + bool PreciseFPModel = false; + switch (optID) { + default: + break; + case options::OPT_ffp_model_EQ: { + // If -ffp-model= is seen, reset to fno-fast-math + HonorINFs = true; + HonorNaNs = true; + // Turning *off* -ffast-math restores the toolchain default. + MathErrno = TC.IsMathErrnoDefault(); + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + // -fno_fast_math restores default denormal and fpcontract handling + DenormalFPMath = ""; + FPContract = ""; + StringRef Val = A->getValue(); + if (OFastEnabled && !Val.equals("fast")) { + // Only -ffp-model=fast is compatible with OFast, ignore. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + Val) + << "-Ofast"; + break; + } + StrictFPModel = false; + PreciseFPModel = true; + // ffp-model= is a Driver option, it is entirely rewritten into more + // granular options before being passed into cc1. + // Use the gcc option in the switch below. + if (!FPModel.empty() && !FPModel.equals(Val)) { + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); + FPContract = ""; + } + if (Val.equals("fast")) { + optID = options::OPT_ffast_math; + FPModel = Val; + FPContract = "fast"; + } else if (Val.equals("precise")) { + optID = options::OPT_ffp_contract; + FPModel = Val; + FPContract = "fast"; + PreciseFPModel = true; + } else if (Val.equals("strict")) { + StrictFPModel = true; + optID = options::OPT_frounding_math; + FPExceptionBehavior = "strict"; + FPModel = Val; + TrappingMath = true; + } else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + } + + switch (optID) { // If this isn't an FP option skip the claim below default: continue; @@ -2256,20 +2587,83 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; case options::OPT_fsigned_zeros: SignedZeros = true; break; case options::OPT_fno_signed_zeros: SignedZeros = false; break; - case options::OPT_ftrapping_math: TrappingMath = true; break; - case options::OPT_fno_trapping_math: TrappingMath = false; break; + case options::OPT_ftrapping_math: + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals("strict")) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << "-ftrapping-math"; + TrappingMath = true; + TrappingMathPresent = true; + FPExceptionBehavior = "strict"; + break; + case options::OPT_fno_trapping_math: + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals("ignore")) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << "-fno-trapping-math"; + TrappingMath = false; + TrappingMathPresent = true; + FPExceptionBehavior = "ignore"; + break; + + case options::OPT_frounding_math: + RoundingFPMath = true; + RoundingMathPresent = true; + break; + + case options::OPT_fno_rounding_math: + RoundingFPMath = false; + RoundingMathPresent = false; + break; case options::OPT_fdenormal_fp_math_EQ: DenormalFPMath = A->getValue(); break; - // Validate and pass through -fp-contract option. + // Validate and pass through -ffp-contract option. case options::OPT_ffp_contract: { StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") + if (PreciseFPModel) { + // -ffp-model=precise enables ffp-contract=fast as a side effect + // the FPContract value has already been set to a string literal + // and the Val string isn't a pertinent value. + ; + } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) FPContract = Val; else D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + + // Validate and pass through -ffp-model option. + case options::OPT_ffp_model_EQ: + // This should only occur in the error case + // since the optID has been replaced by a more granular + // floating point option. + break; + + // Validate and pass through -ffp-exception-behavior option. + case options::OPT_ffp_exception_behavior_EQ: { + StringRef Val = A->getValue(); + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals(Val)) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << Args.MakeArgString("-ffp-exception-behavior=" + Val); + TrappingMath = TrappingMathPresent = false; + if (Val.equals("ignore") || Val.equals("maytrap")) + FPExceptionBehavior = Val; + else if (Val.equals("strict")) { + FPExceptionBehavior = Val; + TrappingMath = TrappingMathPresent = true; + } else + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; break; } @@ -2288,12 +2682,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + FPExceptionBehavior = ""; break; case options::OPT_fno_unsafe_math_optimizations: AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; TrappingMath = true; + FPExceptionBehavior = "strict"; // -fno_unsafe_math_optimizations restores default denormal handling DenormalFPMath = ""; break; @@ -2311,6 +2707,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + RoundingFPMath = false; // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; break; @@ -2324,12 +2721,31 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; - TrappingMath = true; + TrappingMath = false; + RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = ""; FPContract = ""; break; } + if (StrictFPModel) { + // If -ffp-model=strict has been specified on command line but + // subsequent options conflict then emit warning diagnostic. + if (HonorINFs && HonorNaNs && + !AssociativeMath && !ReciprocalMath && + SignedZeros && TrappingMath && RoundingFPMath && + DenormalFPMath.empty() && FPContract.empty()) + // OK: Current Arg doesn't conflict with -ffp-model=strict + ; + else { + StrictFPModel = false; + FPModel = ""; + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=strict" << + ((A->getNumValues() == 0) ? A->getSpelling() + : Args.MakeArgString(A->getSpelling() + A->getValue())); + } + } // If we handled this option claim it A->claim(); @@ -2357,7 +2773,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (ReciprocalMath) CmdArgs.push_back("-freciprocal-math"); - if (!TrappingMath) + if (TrappingMath) { + // FP Exception Behavior is also set to strict + assert(FPExceptionBehavior.equals("strict")); + CmdArgs.push_back("-ftrapping-math"); + } else if (TrappingMathPresent) CmdArgs.push_back("-fno-trapping-math"); if (!DenormalFPMath.empty()) @@ -2367,14 +2787,37 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!FPContract.empty()) CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + if (!RoundingFPMath) + CmdArgs.push_back(Args.MakeArgString("-fno-rounding-math")); + + if (RoundingFPMath && RoundingMathPresent) + CmdArgs.push_back(Args.MakeArgString("-frounding-math")); + + if (!FPExceptionBehavior.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the // individual features enabled by -ffast-math instead of the option itself as // that's consistent with gcc's behaviour. if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && - ReciprocalMath && !SignedZeros && !TrappingMath) + ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) { CmdArgs.push_back("-ffast-math"); + if (FPModel.equals("fast")) { + if (FPContract.equals("fast")) + // All set, do nothing. + ; + else if (FPContract.empty()) + // Enable -ffp-contract=fast + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); + else + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=fast" + << Args.MakeArgString("-ffp-contract=" + FPContract); + } + } // Handle __FINITE_MATH_ONLY__ similarly. if (!HonorINFs && !HonorNaNs) @@ -2423,8 +2866,13 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); } - if (Triple.isOSDarwin()) + if (Triple.isOSDarwin()) { CmdArgs.push_back("-analyzer-checker=osx"); + CmdArgs.push_back( + "-analyzer-checker=security.insecureAPI.decodeValueOfObjCType"); + } + else if (Triple.isOSFuchsia()) + CmdArgs.push_back("-analyzer-checker=fuchsia"); CmdArgs.push_back("-analyzer-checker=deadcode"); @@ -3145,12 +3593,11 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // This avoids having to monkey around further in cc1 other than to disable // codeview if not running in a Windows environment. Perhaps even that // decision should be made in the driver as well though. - unsigned DWARFVersion = 0; llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning(); bool SplitDWARFInlining = Args.hasFlag(options::OPT_fsplit_dwarf_inlining, - options::OPT_fno_split_dwarf_inlining, true); + options::OPT_fno_split_dwarf_inlining, false); Args.ClaimAllArgs(options::OPT_g_Group); @@ -3198,11 +3645,16 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, } // If a -gdwarf argument appeared, remember it. - if (const Arg *A = - Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, - options::OPT_gdwarf_4, options::OPT_gdwarf_5)) - if (checkDebugInfoOption(A, Args, D, TC)) - DWARFVersion = DwarfVersionNum(A->getSpelling()); + const Arg *GDwarfN = Args.getLastArg( + options::OPT_gdwarf_2, options::OPT_gdwarf_3, options::OPT_gdwarf_4, + options::OPT_gdwarf_5, options::OPT_gdwarf); + bool EmitDwarf = false; + if (GDwarfN) { + if (checkDebugInfoOption(GDwarfN, Args, D, TC)) + EmitDwarf = true; + else + GDwarfN = nullptr; + } if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { if (checkDebugInfoOption(A, Args, D, TC)) @@ -3211,18 +3663,36 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // If the user asked for debug info but did not explicitly specify -gcodeview // or -gdwarf, ask the toolchain for the default format. - if (!EmitCodeView && DWARFVersion == 0 && + if (!EmitCodeView && !EmitDwarf && DebugInfoKind != codegenoptions::NoDebugInfo) { switch (TC.getDefaultDebugFormat()) { case codegenoptions::DIF_CodeView: EmitCodeView = true; break; case codegenoptions::DIF_DWARF: - DWARFVersion = TC.GetDefaultDwarfVersion(); + EmitDwarf = true; break; } } + unsigned DWARFVersion = 0; + unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args); + if (EmitDwarf) { + // Start with the platform default DWARF version + DWARFVersion = TC.GetDefaultDwarfVersion(); + assert(DWARFVersion && "toolchain default DWARF version must be nonzero"); + + // If the user specified a default DWARF version, that takes precedence + // over the platform default. + if (DefaultDWARFVersion) + DWARFVersion = DefaultDWARFVersion; + + // Override with a user-specified DWARF version + if (GDwarfN) + if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling())) + DWARFVersion = ExplicitVersion; + } + // -gline-directives-only supported only for the DWARF debug info. if (DWARFVersion == 0 && DebugInfoKind == codegenoptions::DebugDirectivesOnly) DebugInfoKind = codegenoptions::NoDebugInfo; @@ -3296,9 +3766,20 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, } } + // Omit inline line tables if requested. + if (Args.hasFlag(options::OPT_gno_inline_line_tables, + options::OPT_ginline_line_tables, false)) { + CmdArgs.push_back("-gno-inline-line-tables"); + } + // Adjust the debug info kind for the given toolchain. TC.adjustDebugInfoKind(DebugInfoKind, Args); + // When emitting remarks, we need at least debug lines in the output. + if (willEmitRemarks(Args) && + DebugInfoKind <= codegenoptions::DebugDirectivesOnly) + DebugInfoKind = codegenoptions::DebugLineTablesOnly; + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, DebuggerTuning); @@ -3339,6 +3820,10 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-generate-arange-section"); } + if (Args.hasFlag(options::OPT_fforce_dwarf_frame, + options::OPT_fno_force_dwarf_frame, false)) + CmdArgs.push_back("-fforce-dwarf-frame"); + if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { if (!T.isOSBinFormatELF()) { @@ -3641,6 +4126,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ); + if (Args.getLastArg(options::OPT_save_temps_EQ)) Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); @@ -3653,7 +4141,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Disable all llvm IR level optimizations. CmdArgs.push_back("-disable-llvm-passes"); - // Render target options such as -fuse-init-array on modern ELF platforms. + // Render target options. TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); // reject options that shouldn't be supported in bitcode @@ -3718,6 +4206,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderARMABI(Triple, Args, CmdArgs); break; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: RenderAArch64ABI(Triple, Args, CmdArgs); break; @@ -4009,8 +4498,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) { - if (TC.getArch() == llvm::Triple::x86 || - TC.getArch() == llvm::Triple::x86_64) + if (TC.getTriple().isX86()) A->render(Args, CmdArgs); else if ((TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) && (A->getOption().getID() != options::OPT_mlong_double_80)) @@ -4097,6 +4585,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) { + StringRef Value = A->getValue(); + unsigned TLSSize = 0; + Value.getAsInteger(10, TLSSize); + if (!Triple.isAArch64() || !Triple.isOSBinFormatELF()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getOption().getName() << TripleStr; + if (TLSSize != 12 && TLSSize != 24 && TLSSize != 32 && TLSSize != 48) + D.Diag(diag::err_drv_invalid_int_value) + << A->getOption().getName() << Value; + Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ); + } + // Add the target cpu std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); if (!CPU.empty()) { @@ -4362,7 +4863,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (ShouldDisableDwarfDirectory(Args, TC)) CmdArgs.push_back("-fno-dwarf-directory-asm"); - if (ShouldDisableAutolink(Args, TC)) + if (!ShouldEnableAutolink(Args, TC, JA)) CmdArgs.push_back("-fno-autolink"); // Add in -fdebug-compilation-dir if necessary. @@ -4394,9 +4895,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) CmdArgs.push_back("-fexperimental-new-constant-interpreter"); - if (Args.hasArg(options::OPT_fforce_experimental_new_constant_interpreter)) - CmdArgs.push_back("-fforce-experimental-new-constant-interpreter"); - if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) { CmdArgs.push_back("-fbracket-depth"); CmdArgs.push_back(A->getValue()); @@ -4532,6 +5030,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fnoopenmp-use-tls"); Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd); + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ); @@ -4576,11 +5075,50 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const XRayArgs &XRay = TC.getXRayArgs(); XRay.addArgs(TC, Args, CmdArgs, InputType); - if (TC.SupportsProfiling()) + if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { + StringRef S0 = A->getValue(), S = S0; + unsigned Size, Start = 0; + if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + else if (S.consumeInteger(10, Size) || + (!S.empty() && (!S.consume_front(",") || + S.consumeInteger(10, Start) || !S.empty()))) + D.Diag(diag::err_drv_invalid_argument_to_option) + << S0 << A->getOption().getName(); + else if (Start) + D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument); + else + CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size))); + } + + if (TC.SupportsProfiling()) { Args.AddLastArg(CmdArgs, options::OPT_pg); - if (TC.SupportsProfiling()) - Args.AddLastArg(CmdArgs, options::OPT_mfentry); + llvm::Triple::ArchType Arch = TC.getArch(); + if (Arg *A = Args.getLastArg(options::OPT_mfentry)) { + if (Arch == llvm::Triple::systemz || TC.getTriple().isX86()) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + if (Arg *A = Args.getLastArg(options::OPT_mnop_mcount)) { + if (Arch == llvm::Triple::systemz) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + if (Arg *A = Args.getLastArg(options::OPT_mrecord_mcount)) { + if (Arch == llvm::Triple::systemz) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } if (Args.getLastArg(options::OPT_fapple_kext) || (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) @@ -4595,6 +5133,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); + Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); @@ -5112,66 +5651,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fapple-pragma-pack"); // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. - if (Args.hasFlag(options::OPT_fsave_optimization_record, - options::OPT_foptimization_record_file_EQ, - options::OPT_fno_save_optimization_record, false) || - Args.hasFlag(options::OPT_fsave_optimization_record_EQ, - options::OPT_fno_save_optimization_record, false) || - Args.hasFlag(options::OPT_foptimization_record_passes_EQ, - options::OPT_fno_save_optimization_record, false)) { - CmdArgs.push_back("-opt-record-file"); - - const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); - if (A) { - CmdArgs.push_back(A->getValue()); - } else { - SmallString<128> F; - - if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { - if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) - F = FinalOutput->getValue(); - } - - if (F.empty()) { - // Use the input filename. - F = llvm::sys::path::stem(Input.getBaseInput()); - - // If we're compiling for an offload architecture (i.e. a CUDA device), - // we need to make the file name for the device compilation different - // from the host compilation. - if (!JA.isDeviceOffloading(Action::OFK_None) && - !JA.isDeviceOffloading(Action::OFK_Host)) { - llvm::sys::path::replace_extension(F, ""); - F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), - Triple.normalize()); - F += "-"; - F += JA.getOffloadingArch(); - } - } - - std::string Extension = "opt."; - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) - Extension += A->getValue(); - else - Extension += "yaml"; - - llvm::sys::path::replace_extension(F, Extension); - CmdArgs.push_back(Args.MakeArgString(F)); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { - CmdArgs.push_back("-opt-record-passes"); - CmdArgs.push_back(A->getValue()); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { - CmdArgs.push_back("-opt-record-format"); - CmdArgs.push_back(A->getValue()); - } - } + if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple)) + renderRemarksOptions(Args, CmdArgs, Triple, Input, Output, JA); bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports, options::OPT_fno_rewrite_imports, false); @@ -5331,6 +5812,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fcuda-short-ptr"); } + if (IsHIP) + CmdArgs.push_back("-fcuda-allow-variadic-functions"); + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path // to specify the result of the compile phase on the host, so the meaningful // device declarations can be identified. Also, -fopenmp-is-device is passed @@ -5395,7 +5879,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fwhole-program-vtables"); } - bool DefaultsSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO(); + bool DefaultsSplitLTOUnit = + (WholeProgramVTables || Sanitize.needsLTO()) && + (D.getLTOMode() == LTOK_Full || TC.canSplitThinLTOUnit()); bool SplitLTOUnit = Args.hasFlag(options::OPT_fsplit_lto_unit, options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit); @@ -5467,11 +5953,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // We only support -moutline in AArch64 right now. If we're not compiling // for AArch64, emit a warning and ignore the flag. Otherwise, add the // proper mllvm flags. - if (Triple.getArch() != llvm::Triple::aarch64) { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_32) { D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); } else { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-enable-machine-outliner"); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-machine-outliner"); } } else { // Disable all outlining behaviour. @@ -5485,7 +5972,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.getTriple().isOSBinFormatCOFF()) && !TC.getTriple().isPS4() && !TC.getTriple().isOSNetBSD() && - !Distro(D.getVFS()).IsGentoo() && + !Distro(D.getVFS(), TC.getTriple()).IsGentoo() && !TC.getTriple().isAndroid() && TC.useIntegratedAs())) CmdArgs.push_back("-faddrsig"); @@ -5503,8 +5990,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. } else if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + if (Output.getType() == clang::driver::types::TY_IFS_CPP || + Output.getType() == clang::driver::types::TY_IFS) { + SmallString<128> OutputFilename(Output.getFilename()); + llvm::sys::path::replace_extension(OutputFilename, "ifs"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Args.MakeArgString(OutputFilename)); + } else { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } } else { assert(Output.isNothing() && "Invalid output."); } @@ -5538,6 +6033,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // fails, so that the main compilation's fallback to cl.exe runs. C.addCommand(std::make_unique<ForceSuccessCommand>(JA, *this, Exec, CmdArgs, Inputs)); + } else if (D.CC1Main && !D.CCGenDiagnostics) { + // Invoke the CC1 directly in this process + C.addCommand( + std::make_unique<CC1Command>(JA, *this, Exec, CmdArgs, Inputs)); } else { C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -5872,8 +6371,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } unsigned VolatileOptionID; - if (getToolChain().getArch() == llvm::Triple::x86_64 || - getToolChain().getArch() == llvm::Triple::x86) + if (getToolChain().getTriple().isX86()) VolatileOptionID = options::OPT__SLASH_volatile_ms; else VolatileOptionID = options::OPT__SLASH_volatile_iso; @@ -5967,26 +6465,19 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { - SmallVector<StringRef, 1> SplitArgs; - StringRef(A->getValue()).split(SplitArgs, ","); - bool Instrument = false; - bool NoChecks = false; - for (StringRef Arg : SplitArgs) { - if (Arg.equals_lower("cf")) - Instrument = true; - else if (Arg.equals_lower("cf-")) - Instrument = false; - else if (Arg.equals_lower("nochecks")) - NoChecks = true; - else if (Arg.equals_lower("nochecks-")) - NoChecks = false; - else - D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg; - } - // Currently there's no support emitting CFG instrumentation; the flag only - // emits the table of address-taken functions. - if (Instrument || NoChecks) + StringRef GuardArgs = A->getValue(); + // The only valid options are "cf", "cf,nochecks", and "cf-". + if (GuardArgs.equals_lower("cf")) { + // Emit CFG instrumentation and the table of address-taken functions. CmdArgs.push_back("-cfguard"); + } else if (GuardArgs.equals_lower("cf,nochecks")) { + // Emit only the table of address-taken functions. + CmdArgs.push_back("-cfguard-no-checks"); + } else if (GuardArgs.equals_lower("cf-")) { + // Do nothing, but we might want to emit a security warning in future. + } else { + D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs; + } } } @@ -6040,6 +6531,8 @@ void ClangAs::AddMIPSTargetArgs(const ArgList &Args, void ClangAs::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + addX86AlignBranchArgs(getToolChain().getDriver(), Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { StringRef Value = A->getValue(); if (Value == "intel" || Value == "att") { @@ -6134,6 +6627,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, if (WantDebug) DwarfVersion = DwarfVersionNum(A->getSpelling()); } + + unsigned DefaultDwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args); + if (DwarfVersion == 0) + DwarfVersion = DefaultDwarfVersion; + if (DwarfVersion == 0) DwarfVersion = getToolChain().GetDefaultDwarfVersion(); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 10743559e0481..37ec734685706 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -11,12 +11,8 @@ #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" -#include "Arch/RISCV.h" -#include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" -#include "AMDGPU.h" -#include "MSP430.h" #include "HIP.h" #include "Hexagon.h" #include "InputInfo.h" @@ -257,6 +253,7 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, return ""; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: return aarch64::getAArch64TargetCPU(Args, T, A); @@ -488,14 +485,6 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (!StatsFile.empty()) CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); - - getTargetFeatures(ToolChain, ToolChain.getTriple(), Args, CmdArgs, - /* ForAS= */ false, /* ForLTOPlugin= */ true); - - StringRef ABIName = tools::getTargetABI(Args, ToolChain.getTriple()); - if (!ABIName.empty()) - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=-target-abi=") + ABIName)); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, @@ -1138,6 +1127,21 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC, return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value; } +unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, + const ArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version); + + if (!A) + return 0; + + unsigned Value = 0; + if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 5 || + Value < 2) + TC.getDriver().Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + return Value; +} + void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; @@ -1205,7 +1209,10 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, break; } case ToolChain::UNW_CompilerRT: - CmdArgs.push_back("-lunwind"); + if (LGT == LibGccType::StaticLibGcc) + CmdArgs.push_back("-l:libunwind.a"); + else + CmdArgs.push_back("-l:libunwind.so"); break; } @@ -1392,111 +1399,3 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags) { Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); } - -static void getWebAssemblyTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); -} - -void tools::getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, bool ForAS, - bool ForLTOPlugin) { - - const Driver &D = TC.getDriver(); - std::vector<StringRef> Features; - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - mips::getMIPSTargetFeatures(D, Triple, Args, Features); - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - ppc::getPPCTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - riscv::getRISCVTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::systemz: - systemz::getSystemZTargetFeatures(Args, Features); - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - x86::getX86TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::hexagon: - hexagon::getHexagonTargetFeatures(D, Args, Features); - break; - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - getWebAssemblyTargetFeatures(Args, Features); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - sparc::getSparcTargetFeatures(D, Args, Features); - break; - case llvm::Triple::r600: - case llvm::Triple::amdgcn: - amdgpu::getAMDGPUTargetFeatures(D, Args, Features); - break; - case llvm::Triple::msp430: - msp430::getMSP430TargetFeatures(D, Args, Features); - } - - // Find the last of each feature. - llvm::StringMap<unsigned> LastOpt; - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - StringRef Name = Features[I]; - assert(Name[0] == '-' || Name[0] == '+'); - LastOpt[Name.drop_front(1)] = I; - } - - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - // If this feature was overridden, ignore it. - StringRef Name = Features[I]; - llvm::StringMap<unsigned>::iterator LastI = - LastOpt.find(Name.drop_front(1)); - assert(LastI != LastOpt.end()); - unsigned Last = LastI->second; - if (Last != I) - continue; - if (!ForLTOPlugin) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Name.data()); - } else { - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=-mattr=") + Name)); - } - } -} - -StringRef tools::getTargetABI(const ArgList &Args, const llvm::Triple &Triple) { - // TODO: Support the other target ABI - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - return tools::riscv::getRISCVABI(Args, Triple); - break; - } - return StringRef(); -} diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 79468e6b89262..84b9d2cf59b49 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -68,6 +68,9 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); unsigned ParseFunctionAlignment(const ToolChain &TC, const llvm::opt::ArgList &Args); +unsigned ParseDebugDefaultVersion(const ToolChain &TC, + const llvm::opt::ArgList &Args); + void AddAssemblerKPIC(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); @@ -118,14 +121,6 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, void addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags); -StringRef getTargetABI(const llvm::opt::ArgList &Args, - const llvm::Triple &Triple); - -void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, bool ForAS, - bool ForLTOPlugin = false); - } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 8c704a3078adc..02871d2ce411f 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -115,7 +115,8 @@ CudaInstallationDetector::CudaInstallationDetector( for (const char *Ver : Versions) Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver); - if (Distro(D.getVFS()).IsDebian() || Distro(D.getVFS()).IsUbuntu()) + Distro Dist(D.getVFS(), llvm::Triple(llvm::sys::getProcessTriple())); + if (Dist.IsDebian() || Dist.IsUbuntu()) // Special case for Debian to have nvidia-cuda-toolkit work // out of the box. More info on http://bugs.debian.org/882505 Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda"); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index ee08b8208d939..344a14fe1ea7c 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -19,6 +19,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" @@ -57,6 +58,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) .Cases("armv7s", "xscale", llvm::Triple::arm) .Case("arm64", llvm::Triple::aarch64) + .Case("arm64_32", llvm::Triple::aarch64_32) .Case("r600", llvm::Triple::r600) .Case("amdgcn", llvm::Triple::amdgcn) .Case("nvptx", llvm::Triple::nvptx) @@ -122,8 +124,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, AddMachOArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. - if (getToolChain().getArch() == llvm::Triple::x86 || - getToolChain().getArch() == llvm::Triple::x86_64 || + if (getToolChain().getTriple().isX86() || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); @@ -334,7 +335,10 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. - MachOTC.addMinVersionArgs(Args, CmdArgs); + if (!Version[0] || Version[0] >= 520) + MachOTC.addPlatformVersionArgs(Args, CmdArgs); + else + MachOTC.addMinVersionArgs(Args, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); Args.AddLastArg(CmdArgs, options::OPT_multi__module); @@ -737,7 +741,7 @@ Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) CudaInstallation(D, Triple, Args) {} types::ID MachO::LookupTypeForExtension(StringRef Ext) const { - types::ID Ty = types::lookupTypeForExtension(Ext); + types::ID Ty = ToolChain::LookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). if (Ty == types::TY_PP_Asm) @@ -831,6 +835,9 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const { default: return getDefaultUniversalArchName(); + case llvm::Triple::aarch64_32: + return "arm64_32"; + case llvm::Triple::aarch64: return "arm64"; @@ -1061,7 +1068,6 @@ StringRef Darwin::getPlatformFamily() const { StringRef Darwin::getSDKName(StringRef isysroot) { // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - llvm::sys::path::const_iterator SDKDir; auto BeginSDK = llvm::sys::path::begin(isysroot); auto EndSDK = llvm::sys::path::end(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { @@ -1110,6 +1116,19 @@ static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) { CmdArgs.push_back(Symbol); } +/// Add a sectalign directive for \p Segment and \p Section to the maximum +/// expected page size for Darwin. +/// +/// On iPhone 6+ the max supported page size is 16K. On macOS, the max is 4K. +/// Use a common alignment constant (16K) for now, and reduce the alignment on +/// macOS if it proves important. +static void addSectalignToPage(const ArgList &Args, ArgStringList &CmdArgs, + StringRef Segment, StringRef Section) { + for (const char *A : {"-sectalign", Args.MakeArgString(Segment), + Args.MakeArgString(Section), "0x4000"}) + CmdArgs.push_back(A); +} + void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; @@ -1117,11 +1136,13 @@ void Darwin::addProfileRTLibs(const ArgList &Args, AddLinkRuntimeLib(Args, CmdArgs, "profile", RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink)); + bool ForGCOV = needsGCovInstrumentation(Args); + // If we have a symbol export directive and we're linking in the profile // runtime, automatically export symbols necessary to implement some of the // runtime's functionality. if (hasExportSymbolDirective(Args)) { - if (needsGCovInstrumentation(Args)) { + if (ForGCOV) { addExportedSymbol(CmdArgs, "___gcov_flush"); addExportedSymbol(CmdArgs, "_flush_fn_list"); addExportedSymbol(CmdArgs, "_writeout_fn_list"); @@ -1131,6 +1152,24 @@ void Darwin::addProfileRTLibs(const ArgList &Args, } addExportedSymbol(CmdArgs, "_lprofDirMode"); } + + // Align __llvm_prf_{cnts,data} sections to the maximum expected page + // alignment. This allows profile counters to be mmap()'d to disk. Note that + // it's not enough to just page-align __llvm_prf_cnts: the following section + // must also be page-aligned so that its data is not clobbered by mmap(). + // + // The section alignment is only needed when continuous profile sync is + // enabled, but this is expected to be the default in Xcode. Specifying the + // extra alignment also allows the same binary to be used with/without sync + // enabled. + if (!ForGCOV) { + for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) { + addSectalignToPage( + Args, CmdArgs, "__DATA", + llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO, + /*AddSegmentInfo=*/false)); + } + } } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, @@ -1493,8 +1532,8 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, Targets[Darwin::TvOS] = ""; } else { // Don't allow conflicts in any other platform. - int FirstTarget = llvm::array_lengthof(Targets); - for (int I = 0; I != llvm::array_lengthof(Targets); ++I) { + unsigned FirstTarget = llvm::array_lengthof(Targets); + for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) { if (Targets[I].empty()) continue; if (FirstTarget == llvm::array_lengthof(Targets)) @@ -1607,7 +1646,7 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, if (MachOArchName == "armv7" || MachOArchName == "armv7s" || MachOArchName == "arm64") OSTy = llvm::Triple::IOS; - else if (MachOArchName == "armv7k") + else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32") OSTy = llvm::Triple::WatchOS; else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && MachOArchName != "armv7em") @@ -1796,9 +1835,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { DarwinEnvironmentKind Environment = OSTarget->getEnvironment(); // Recognize iOS targets with an x86 architecture as the iOS simulator. if (Environment == NativeEnvironment && Platform != MacOS && - OSTarget->canInferSimulatorFromArch() && - (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) + OSTarget->canInferSimulatorFromArch() && getTriple().isX86()) Environment = Simulator; setTarget(Platform, Environment, Major, Minor, Micro); @@ -2194,8 +2231,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, } } - if (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64) + if (getTriple().isX86()) if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), "core2"); @@ -2451,7 +2487,7 @@ bool MachO::isPICDefaultForced() const { bool MachO::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. - return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; + return getTriple().isX86(); } void Darwin::addMinVersionArgs(const ArgList &Args, @@ -2478,6 +2514,45 @@ void Darwin::addMinVersionArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); } +static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, + Darwin::DarwinEnvironmentKind Environment) { + switch (Platform) { + case Darwin::MacOS: + return "macos"; + case Darwin::IPhoneOS: + if (Environment == Darwin::NativeEnvironment || + Environment == Darwin::Simulator) + return "ios"; + // FIXME: Add macCatalyst support here ("\"mac catalyst\""). + llvm_unreachable("macCatalyst isn't yet supported"); + case Darwin::TvOS: + return "tvos"; + case Darwin::WatchOS: + return "watchos"; + } + llvm_unreachable("invalid platform"); +} + +void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + // -platform_version <platform> <target_version> <sdk_version> + // Both the target and SDK version support only up to 3 components. + CmdArgs.push_back("-platform_version"); + std::string PlatformName = getPlatformName(TargetPlatform, TargetEnvironment); + if (TargetEnvironment == Darwin::Simulator) + PlatformName += "-simulator"; + CmdArgs.push_back(Args.MakeArgString(PlatformName)); + VersionTuple TargetVersion = getTargetVersion().withoutBuild(); + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + if (SDKInfo) { + VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); + CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + } else { + // Use a blank SDK version if it's not present. + CmdArgs.push_back("0.0.0"); + } +} + void Darwin::addStartObjectFileArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Derived from startfile spec. diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 2dc7c85880f73..1b193a4c4eb96 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -167,6 +167,10 @@ public: virtual void addMinVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const {} + virtual void addPlatformVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + } + /// On some iOS platforms, kernel and kernel modules were built statically. Is /// this such a target? virtual bool isKernelStatic() const { return false; } @@ -258,6 +262,9 @@ public: return ""; } + // Darwin toolchain uses legacy thin LTO API, which is not + // capable of unit splitting. + bool canSplitThinLTOUnit() const override { return false; } /// } }; @@ -311,6 +318,9 @@ public: void addMinVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void addPlatformVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp new file mode 100644 index 0000000000000..9b9eb81fa111d --- /dev/null +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -0,0 +1,79 @@ +//===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + + +#include "Flang.h" +#include "CommonArgs.h" + +#include "clang/Driver/Options.h" + +#include <cassert> + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void Flang::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const char *LinkingOutput) const { + const auto &TC = getToolChain(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + + ArgStringList CmdArgs; + + CmdArgs.push_back("-fc1"); + + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); + + if (isa<PreprocessJobAction>(JA)) { + CmdArgs.push_back("-E"); + } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { + if (JA.getType() == types::TY_Nothing) { + CmdArgs.push_back("-fsyntax-only"); + } else if (JA.getType() == types::TY_AST) { + CmdArgs.push_back("-emit-ast"); + } else if (JA.getType() == types::TY_LLVM_IR || + JA.getType() == types::TY_LTO_IR) { + CmdArgs.push_back("-emit-llvm"); + } else if (JA.getType() == types::TY_LLVM_BC || + JA.getType() == types::TY_LTO_BC) { + CmdArgs.push_back("-emit-llvm-bc"); + } else if (JA.getType() == types::TY_PP_Asm) { + CmdArgs.push_back("-S"); + } else { + assert(false && "Unexpected output type!"); + } + } else if (isa<AssembleJobAction>(JA)) { + CmdArgs.push_back("-emit-obj"); + } else { + assert(false && "Unexpected action class for Flang tool."); + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + const auto& D = C.getDriver(); + const char* Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +Flang::Flang(const ToolChain &TC) + : Tool("flang", "flang frontend", TC, RF_Full) {} + +Flang::~Flang() {} diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h new file mode 100644 index 0000000000000..19e3a8c28f7e4 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Flang.h @@ -0,0 +1,46 @@ +//===--- Flang.h - Flang Tool and ToolChain Implementations ====-*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace driver { + +namespace tools { + +/// Flang compiler tool. +class LLVM_LIBRARY_VISIBILITY Flang : public Tool { +public: + Flang(const ToolChain &TC); + ~Flang() override; + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + bool canEmitIR() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 7c891a24ba304..c5c6f530f48c0 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -12,6 +12,7 @@ #include "Arch/Sparc.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" @@ -30,6 +31,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; + const auto &D = getToolChain().getDriver(); // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. @@ -103,6 +105,19 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } } + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else { + CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); + CmdArgs.push_back(Args.MakeArgString(Map)); + } + A->claim(); + } + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); @@ -155,11 +170,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } - if (ToolChain.getTriple().getOSMajorVersion() >= 9) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || - Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + const llvm::Triple &T = ToolChain.getTriple(); + if (T.getOSMajorVersion() >= 9) { + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || T.isX86()) CmdArgs.push_back("--hash-style=both"); - } } CmdArgs.push_back("--enable-new-dtags"); } @@ -397,6 +411,11 @@ void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, } } +void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + Tool *FreeBSD::buildAssembler() const { return new tools::freebsd::Assembler(*this); } @@ -420,6 +439,8 @@ llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { bool FreeBSD::HasNativeLLVMSupport() const { return true; } +bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } + bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask FreeBSD::getSupportedSanitizers() const { @@ -445,3 +466,12 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { Res |= SanitizerKind::Memory; return Res; } + +void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind) const { + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, + getTriple().getOSMajorVersion() >= 12)) + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h index d17b3808ffacc..84bdbfd9a3125 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -64,15 +64,22 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; llvm::ExceptionHandling GetExceptionModel( const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override; // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // FreeBSD defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; protected: Tool *buildAssembler() const override; diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index e7d38ff9f227b..808d0408d0d4c 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -46,6 +46,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); + CmdArgs.push_back("-z"); + CmdArgs.push_back("now"); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { @@ -224,7 +227,7 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); - return (Triple.getArchName() + "-" + Triple.getOSName()).str(); + return Triple.str(); } Tool *Fuchsia::buildLinker() const { @@ -258,9 +261,9 @@ Fuchsia::GetCXXStdlibType(const ArgList &Args) const { void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, true)) - CC1Args.push_back("-fuse-init-array"); + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); } void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -343,5 +346,17 @@ SanitizerMask Fuchsia::getSupportedSanitizers() const { } SanitizerMask Fuchsia::getDefaultSanitizers() const { - return SanitizerKind::SafeStack; + SanitizerMask Res; + switch (getTriple().getArch()) { + case llvm::Triple::aarch64: + Res |= SanitizerKind::ShadowCallStack; + break; + case llvm::Triple::x86_64: + Res |= SanitizerKind::SafeStack; + break; + default: + // TODO: Enable SafeStack on RISC-V once tested. + break; + } + return Res; } diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index c302a31cd2e10..da197e476621a 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -709,11 +709,9 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(ABIName.data()); - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - StringRef MArch = A->getValue(); - CmdArgs.push_back("-march"); - CmdArgs.push_back(MArch.data()); - } + StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple()); + CmdArgs.push_back("-march"); + CmdArgs.push_back(MArchName.data()); break; } case llvm::Triple::sparc: @@ -864,12 +862,25 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, case llvm::Triple::systemz: { // Always pass an -march option, since our default of z10 is later // than the GNU assembler's default. - StringRef CPUName = systemz::getSystemZTargetCPU(Args); + std::string CPUName = systemz::getSystemZTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); break; } } + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else { + CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); + CmdArgs.push_back(Args.MakeArgString(Map)); + } + A->claim(); + } + Args.AddAllArgs(CmdArgs, options::OPT_I); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -1393,7 +1404,8 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || - CPUName == "mips64r5" || CPUName == "octeon", + CPUName == "mips64r5" || CPUName == "octeon" || + CPUName == "octeon+", "march=mips64r2", Flags); addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); @@ -1504,9 +1516,65 @@ static bool findMSP430Multilibs(const Driver &D, return false; } +static void findRISCVBareMetalMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + struct RiscvMultilib { + StringRef march; + StringRef mabi; + }; + // currently only support the set of multilibs like riscv-gnu-toolchain does. + // TODO: support MULTILIB_REUSE + SmallVector<RiscvMultilib, 8> RISCVMultilibSet = { + {"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"}, + {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, + {"rv64imafdc", "lp64d"}}; + + std::vector<Multilib> Ms; + for (auto Element : RISCVMultilibSet) { + // multilib path rule is ${march}/${mabi} + Ms.emplace_back( + makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) + .flag(Twine("+march=", Element.march).str()) + .flag(Twine("+mabi=", Element.mabi).str())); + } + MultilibSet RISCVMultilibs = + MultilibSet() + .Either(ArrayRef<Multilib>(Ms)) + .FilterOut(NonExistent) + .setFilePathsCallback([](const Multilib &M) { + return std::vector<std::string>( + {M.gccSuffix(), + "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(), + "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); + }); + + + Multilib::flags_list Flags; + llvm::StringSet<> Added_ABIs; + StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); + StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple); + for (auto Element : RISCVMultilibSet) { + addMultilibFlag(MArch == Element.march, + Twine("march=", Element.march).str().c_str(), Flags); + if (!Added_ABIs.count(Element.mabi)) { + Added_ABIs.insert(Element.mabi); + addMultilibFlag(ABIName == Element.mabi, + Twine("mabi=", Element.mabi).str().c_str(), Flags); + } + } + + if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = RISCVMultilibs; +} + static void findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { + if (TargetTriple.getOS() == llvm::Triple::UnknownOS) + return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result); FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); @@ -2002,7 +2070,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", - "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; + // On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a + // 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux". + "powerpc64-suse-linux", "powerpc-montavista-linuxspe"}; static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64Triples[] = { "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", @@ -2545,9 +2615,6 @@ bool Generic_GCC::isPICDefault() const { switch (getArch()) { case llvm::Triple::x86_64: return getTriple().isOSWindows(); - case llvm::Triple::ppc64: - // Big endian PPC is PIC by default - return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); case llvm::Triple::mips64: case llvm::Triple::mips64el: return true; @@ -2616,19 +2683,49 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -void -Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // FIXME: The Linux behavior would probaby be a better approach here. - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); +static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, + StringRef base) { + std::error_code EC; + int MaxVersion = 0; + std::string MaxVersionString; + for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + int Version; + if (VersionText[0] == 'v' && + !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { + if (Version > MaxVersion) { + MaxVersion = Version; + MaxVersionString = VersionText; + } + } + } + return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } void -Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // By default, we don't assume we know where libstdc++ might be installed. - // FIXME: If we have a valid GCCInstallation, use it. +Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const std::string& SysRoot = getDriver().SysRoot; + auto AddIncludePath = [&](std::string Path) { + std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path); + if (IncludePath.empty() || !getVFS().exists(IncludePath)) + return false; + addSystemInclude(DriverArgs, CC1Args, IncludePath); + return true; + }; + // Android never uses the libc++ headers installed alongside the toolchain, + // which are generally incompatible with the NDK libraries anyway. + if (!getTriple().isAndroid()) + if (AddIncludePath(getDriver().Dir + "/../include/c++")) + return; + // If this is a development, non-installed, clang, libcxx will + // not be found at ../include/c++ but it likely to be found at + // one of the following two locations: + if (AddIncludePath(SysRoot + "/usr/local/include/c++")) + return; + if (AddIncludePath(SysRoot + "/usr/include/c++")) + return; } /// Helper to add the variant paths of a libstdc++ installation. @@ -2664,6 +2761,60 @@ bool Generic_GCC::addLibStdCXXIncludePaths( return true; } +bool +Generic_GCC::addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // Use GCCInstallation to know where libstdc++ headers are installed. + if (!GCCInstallation.isValid()) + return false; + + // By default, look for the C++ headers in an include directory adjacent to + // the lib directory of the GCC installation. Note that this is expect to be + // equivalent to '/usr/include/c++/X.Y' in almost all cases. + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef InstallDir = GCCInstallation.getInstallPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const std::string GCCMultiarchTriple = getMultiarchTriple( + getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string TargetMultiarchTriple = + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); + const GCCVersion &Version = GCCInstallation.getVersion(); + + // The primary search for libstdc++ supports multiarch variants. + if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.Text, TripleStr, + GCCMultiarchTriple, TargetMultiarchTriple, + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return true; + + // Otherwise, fall back on a bunch of options which don't use multiarch + // layouts for simplicity. + const std::string LibStdCXXIncludePathCandidates[] = { + // Gentoo is weird and places its headers inside the GCC install, + // so if the first attempt to find the headers fails, try these patterns. + InstallDir.str() + "/include/g++-v" + Version.Text, + InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + + Version.MinorStr, + InstallDir.str() + "/include/g++-v" + Version.MajorStr, + }; + + for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { + if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, + /*GCCMultiarchTriple*/ "", + /*TargetMultiarchTriple*/ "", + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return true; + } + return false; +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); +} + llvm::opt::DerivedArgList * Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, Action::OffloadKind DeviceOffloadKind) const { @@ -2712,23 +2863,7 @@ void Generic_ELF::anchor() {} void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { - const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); - bool UseInitArrayDefault = - getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::aarch64_be || - (getTriple().isOSFreeBSD() && - getTriple().getOSMajorVersion() >= 12) || - (getTriple().getOS() == llvm::Triple::Linux && - ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || - getTriple().isAndroid())) || - getTriple().getOS() == llvm::Triple::NaCl || - (getTriple().getVendor() == llvm::Triple::MipsTechnologies && - !getTriple().hasEnvironment()) || - getTriple().getOS() == llvm::Triple::Solaris || - getTriple().getArch() == llvm::Triple::riscv32 || - getTriple().getArch() == llvm::Triple::riscv64; - - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, UseInitArrayDefault)) - CC1Args.push_back("-fuse-init-array"); + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); } diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 3bb38c498b35d..083f74c054774 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -300,6 +300,11 @@ protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + virtual std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const + { return TargetTriple.str(); } + /// \name ToolChain Implementation Helper Functions /// @{ @@ -322,6 +327,10 @@ protected: addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + bool + addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index ad9384df6a242..f89e648948aba 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -62,6 +62,34 @@ static const char *getOutputFileName(Compilation &C, StringRef Base, } return OutputFileName; } + +static void addOptLevelArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + bool IsLlc = false) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + StringRef OOpt = "3"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) { + // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3 + // so we map -Os/-Oz to -O2. + // Only clang supports -Og, and maps it to -O1. + // We map anything else to -O2. + OOpt = llvm::StringSwitch<const char *>(A->getValue()) + .Case("1", "1") + .Case("2", "2") + .Case("3", "3") + .Case("s", IsLlc ? "2" : "s") + .Case("z", IsLlc ? "2" : "z") + .Case("g", "1") + .Default("2"); + } + CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); + } +} } // namespace const char *AMDGCN::Linker::constructLLVMLinkCommand( @@ -93,25 +121,7 @@ const char *AMDGCN::Linker::constructOptCommand( // The input to opt is the output from llvm-link. OptArgs.push_back(InputFileName); // Pass optimization arg to opt. - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - StringRef OOpt = "3"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) { - // -Os, -Oz, and -O(anything else) map to -O2 - OOpt = llvm::StringSwitch<const char *>(A->getValue()) - .Case("1", "1") - .Case("2", "2") - .Case("3", "3") - .Case("s", "2") - .Case("z", "2") - .Default("2"); - } - OptArgs.push_back(Args.MakeArgString("-O" + OOpt)); - } + addOptLevelArgs(Args, OptArgs); OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); @@ -136,10 +146,15 @@ const char *AMDGCN::Linker::constructLlcCommand( llvm::StringRef OutputFilePrefix, const char *InputFileName, bool OutputIsAsm) const { // Construct llc command. - ArgStringList LlcArgs{ - InputFileName, "-mtriple=amdgcn-amd-amdhsa", - Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")), - Args.MakeArgString("-mcpu=" + SubArchName)}; + ArgStringList LlcArgs; + // The input to llc is the output from opt. + LlcArgs.push_back(InputFileName); + // Pass optimization arg to llc. + addOptLevelArgs(Args, LlcArgs, /*IsLlc=*/true); + LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); + LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); + LlcArgs.push_back( + Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj"))); // Extract all the -m options std::vector<llvm::StringRef> Features; @@ -292,6 +307,20 @@ void HIPToolChain::addClangTargetOptions( false)) CC1Args.push_back("-fgpu-rdc"); + StringRef MaxThreadsPerBlock = + DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); + if (!MaxThreadsPerBlock.empty()) { + std::string ArgStr = + std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str(); + CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); + } + + if (DriverArgs.hasFlag(options::OPT_fgpu_allow_device_init, + options::OPT_fno_gpu_allow_device_init, false)) + CC1Args.push_back("-fgpu-allow-device-init"); + + CC1Args.push_back("-fcuda-allow-variadic-functions"); + // Default to "hidden" visibility, as object level linking will not be // supported for the foreseeable future. if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, @@ -337,9 +366,8 @@ void HIPToolChain::addClangTargetOptions( else WaveFrontSizeBC = "oclc_wavefrontsize64_off.amdgcn.bc"; - BCLibs.append({"hip.amdgcn.bc", "opencl.amdgcn.bc", "ocml.amdgcn.bc", - "ockl.amdgcn.bc", "oclc_finite_only_off.amdgcn.bc", - FlushDenormalControlBC, + BCLibs.append({"hip.amdgcn.bc", "ocml.amdgcn.bc", "ockl.amdgcn.bc", + "oclc_finite_only_off.amdgcn.bc", FlushDenormalControlBC, "oclc_correctly_rounded_sqrt_on.amdgcn.bc", "oclc_unsafe_math_off.amdgcn.bc", ISAVerBC, WaveFrontSizeBC}); diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h index 2d146ce5cc6fd..c4f944e458bf2 100644 --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -113,7 +113,7 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } + unsigned GetDefaultDwarfVersion() const override { return 4; } const ToolChain &HostTC; diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 96cc084e2821e..e4d9ea8a70f9e 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -209,7 +209,11 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); bool UseG0 = false; + const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); + bool UseLLD = (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || + llvm::sys::path::stem(Exec).equals_lower("ld.lld")); bool UseShared = IsShared && !IsStatic; + StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); //---------------------------------------------------------------------------- // Silence warnings for various options @@ -232,9 +236,10 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, for (const auto &Opt : HTC.ExtraOpts) CmdArgs.push_back(Opt.c_str()); - CmdArgs.push_back("-march=hexagon"); - StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); - CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); + if (!UseLLD) { + CmdArgs.push_back("-march=hexagon"); + CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); + } if (IsShared) { CmdArgs.push_back("-shared"); @@ -574,7 +579,7 @@ const StringRef HexagonToolChain::GetDefaultCPU() { const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { Arg *CpuArg = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) CpuArg = A; StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index 92b0a7f2483f3..72166ca9f3594 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -27,9 +27,9 @@ using tools::addPathIfExists; /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, - const llvm::Triple &TargetTriple, - StringRef SysRoot) { +std::string Hurd::getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const { if (TargetTriple.getArch() == llvm::Triple::x86) { // We use the existence of '/lib/<triple>' as a directory to detect some // common hurd triples that don't quite match the Clang triple for both @@ -70,6 +70,10 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const std::string OSLibDir = getOSLibDir(Triple, Args); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); +#ifdef ENABLE_LINKER_BUILD_ID + ExtraOpts.push_back("--build-id"); +#endif + // If we are currently running Clang inside of the requested system root, add // its parent library paths to those searched. // FIXME: It's not clear whether we should use the driver's installed diff --git a/clang/lib/Driver/ToolChains/Hurd.h b/clang/lib/Driver/ToolChains/Hurd.h index a2c3d074e9f95..86c6c3f734dd9 100644 --- a/clang/lib/Driver/ToolChains/Hurd.h +++ b/clang/lib/Driver/ToolChains/Hurd.h @@ -36,6 +36,10 @@ public: protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp index 6677843b2c533..8f947e79bd1f1 100644 --- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -9,6 +9,7 @@ #include "InterfaceStubs.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" +#include "llvm/Support/Path.h" namespace clang { namespace driver { @@ -21,13 +22,38 @@ void Merger::ConstructJob(Compilation &C, const JobAction &JA, std::string Merger = getToolChain().GetProgramPath(getShortName()); llvm::opt::ArgStringList CmdArgs; CmdArgs.push_back("-action"); - CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) - ? "write-ifs" - : "write-bin"); + const bool WriteBin = !Args.getLastArg(options::OPT_emit_merged_ifs); + CmdArgs.push_back(WriteBin ? "write-bin" : "write-ifs"); CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - for (const auto &Input : Inputs) - CmdArgs.push_back(Input.getFilename()); + + // Normally we want to write to a side-car file ending in ".ifso" so for + // example if `clang -emit-interface-stubs -shared -o libhello.so` were + // invoked then we would like to get libhello.so and libhello.ifso. If the + // stdout stream is given as the output file (ie `-o -`), that is the one + // exception where we will just append to the same filestream as the normal + // output. + SmallString<128> OutputFilename(Output.getFilename()); + if (OutputFilename != "-") { + if (Args.hasArg(options::OPT_shared)) + llvm::sys::path::replace_extension(OutputFilename, + (WriteBin ? "ifso" : "ifs")); + else + OutputFilename += (WriteBin ? ".ifso" : ".ifs"); + } + + CmdArgs.push_back(Args.MakeArgString(OutputFilename.c_str())); + + // Here we append the input files. If the input files are object files, then + // we look for .ifs files present in the same location as the object files. + for (const auto &Input : Inputs) { + if (!Input.isFilename()) + continue; + SmallString<128> InputFilename(Input.getFilename()); + if (Input.getType() == types::TY_Object) + llvm::sys::path::replace_extension(InputFilename, ".ifs"); + CmdArgs.push_back(Args.MakeArgString(InputFilename.c_str())); + } + C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger), CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 087783875ffe2..bff1ab1009be1 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -37,9 +37,9 @@ using tools::addPathIfExists; /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, +std::string Linux::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, - StringRef SysRoot) { + StringRef SysRoot) const { llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment(); bool IsAndroid = TargetTriple.isAndroid(); @@ -240,7 +240,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) .str()); } - Distro Distro(D.getVFS()); + Distro Distro(D.getVFS(), Triple); if (Distro.IsAlpineLinux() || Triple.isAndroid()) { ExtraOpts.push_back("-z"); @@ -511,7 +511,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { const llvm::Triple::ArchType Arch = getArch(); const llvm::Triple &Triple = getTriple(); - const Distro Distro(getDriver().getVFS()); + const Distro Distro(getDriver().getVFS(), Triple); if (Triple.isAndroid()) return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; @@ -865,81 +865,23 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); } -static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, - StringRef base) { - std::error_code EC; - int MaxVersion = 0; - std::string MaxVersionString = ""; - for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - int Version; - if (VersionText[0] == 'v' && - !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { - if (Version > MaxVersion) { - MaxVersion = Version; - MaxVersionString = VersionText; - } - } - } - return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; -} - -void Linux::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - const std::string& SysRoot = computeSysRoot(); - const std::string LibCXXIncludePathCandidates[] = { - DetectLibcxxIncludePath(getVFS(), getDriver().Dir + "/../include/c++"), - // If this is a development, non-installed, clang, libcxx will - // not be found at ../include/c++ but it likely to be found at - // one of the following two locations: - DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/local/include/c++"), - DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/include/c++") }; - for (const auto &IncludePath : LibCXXIncludePathCandidates) { - if (IncludePath.empty() || !getVFS().exists(IncludePath)) - continue; - // Use the first candidate that exists. - addSystemInclude(DriverArgs, CC1Args, IncludePath); - return; - } -} - void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { + // Try generic GCC detection first. + if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args)) + return; + // We need a detected GCC installation on Linux to provide libstdc++'s - // headers. + // headers in odd Linuxish places. if (!GCCInstallation.isValid()) return; - // By default, look for the C++ headers in an include directory adjacent to - // the lib directory of the GCC installation. Note that this is expect to be - // equivalent to '/usr/include/c++/X.Y' in almost all cases. StringRef LibDir = GCCInstallation.getParentLibPath(); - StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); - const std::string GCCMultiarchTriple = getMultiarchTriple( - getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); - const std::string TargetMultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); - // The primary search for libstdc++ supports multiarch variants. - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", - "/c++/" + Version.Text, TripleStr, - GCCMultiarchTriple, TargetMultiarchTriple, - Multilib.includeSuffix(), DriverArgs, CC1Args)) - return; - - // Otherwise, fall back on a bunch of options which don't use multiarch - // layouts for simplicity. const std::string LibStdCXXIncludePathCandidates[] = { - // Gentoo is weird and places its headers inside the GCC install, - // so if the first attempt to find the headers fails, try these patterns. - InstallDir.str() + "/include/g++-v" + Version.Text, - InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + - Version.MinorStr, - InstallDir.str() + "/include/g++-v" + Version.MajorStr, // Android standalone toolchain has C++ headers in yet another place. LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index 4c61994691c73..f5518eac218a4 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -26,9 +26,6 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -52,6 +49,10 @@ public: protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 1d31844bfcc88..4e143f6a5d3fa 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -422,6 +422,17 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); + // Control Flow Guard checks + if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) { + // MSVC doesn't yet support the "nochecks" modifier. + CmdArgs.push_back("-guard:cf"); + } else if (GuardArgs.equals_lower("cf-")) { + CmdArgs.push_back("-guard:cf-"); + } + } + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) { CmdArgs.push_back("-nodefaultlib:vcomp.lib"); @@ -679,6 +690,17 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( : "/Zc:threadSafeInit-"); } + // Control Flow Guard checks + if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) { + // MSVC doesn't yet support the "nochecks" modifier. + CmdArgs.push_back("/guard:cf"); + } else if (GuardArgs.equals_lower("cf-")) { + CmdArgs.push_back("/guard:cf-"); + } + } + // Pass through all unknown arguments so that the fallback command can see // them too. Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 0d851114c225b..8f24384e688b4 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -160,7 +160,19 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + const char *OutputFile = Output.getFilename(); + // GCC implicitly adds an .exe extension if it is given an output file name + // that lacks an extension. However, GCC only does this when actually + // running on windows, not when operating as a cross compiler. As some users + // have come to rely on this behaviour, try to replicate it. +#ifdef _WIN32 + if (!llvm::sys::path::has_extension(OutputFile)) + CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe")); + else + CmdArgs.push_back(OutputFile); +#else + CmdArgs.push_back(OutputFile); +#endif Args.AddAllArgs(CmdArgs, options::OPT_e); // FIXME: add -N, -n flags diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 405142204199d..0100a387d6c35 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -505,7 +505,7 @@ void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::armeb; - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, UseInitArrayDefault)) - CC1Args.push_back("-fuse-init-array"); + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, UseInitArrayDefault)) + CC1Args.push_back("-fno-use-init-array"); } diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index e93f5fcc3d819..80343c0394cb5 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -267,3 +267,12 @@ Tool *OpenBSD::buildAssembler() const { } Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } + +void OpenBSD::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind) const { + // Support for .init_array is still new (Aug 2016). + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, false)) + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h index c92d109b7c16c..9f1ee0f66402b 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -75,6 +75,11 @@ public: SanitizerMask getSupportedSanitizers() const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index e9f0891c11944..18852b2808cbd 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -84,6 +84,10 @@ public: SanitizerMask getSupportedSanitizers() const override; + // PS4 toolchain uses legacy thin LTO API, which is not + // capable of unit splitting. + bool canSplitThinLTOUnit() const override { return false; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 22dc5117f1962..ddc329e3c722b 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "RISCVToolchain.h" -#include "Arch/RISCV.h" #include "CommonArgs.h" #include "InputInfo.h" #include "clang/Driver/Compilation.h" @@ -23,29 +22,60 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, + const Multilib &Multilib, + StringRef InstallPath, + ToolChain::path_list &Paths) { + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(Multilib)) + addPathIfExists(D, InstallPath + Path, Paths); +} + /// RISCV Toolchain RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); - getFilePaths().push_back(computeSysRoot() + "/lib"); if (GCCInstallation.isValid()) { + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilib = GCCInstallation.getMultilib(); + path_list &Paths = getFilePaths(); + // Add toolchain/multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + GCCInstallation.getInstallPath(), Paths); getFilePaths().push_back(GCCInstallation.getInstallPath().str()); - getProgramPaths().push_back( - (GCCInstallation.getParentLibPath() + "/../bin").str()); + ToolChain::path_list &PPaths = getProgramPaths(); + // Multilib cross-compiler GCC installations put ld in a triple-prefixed + // directory off of the parent of the GCC installation. + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str()); + } else { + getProgramPaths().push_back(D.Dir); } + getFilePaths().push_back(computeSysRoot() + "/lib"); } Tool *RISCVToolChain::buildLinker() const { return new tools::RISCV::Linker(*this); } +ToolChain::RuntimeLibType RISCVToolChain::GetDefaultRuntimeLibType() const { + return GCCInstallation.isValid() ? + ToolChain::RLT_Libgcc : ToolChain::RLT_CompilerRT; +} + +ToolChain::UnwindLibType +RISCVToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + return ToolChain::UNW_None; +} + void RISCVToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); - CC1Args.push_back("-fuse-init-array"); } void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -74,17 +104,22 @@ std::string RISCVToolChain::computeSysRoot() const { if (!getDriver().SysRoot.empty()) return getDriver().SysRoot; - if (!GCCInstallation.isValid()) - return std::string(); - - StringRef LibDir = GCCInstallation.getParentLibPath(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - std::string SysRootDir = LibDir.str() + "/../" + TripleStr.str(); + SmallString<128> SysRootDir; + if (GCCInstallation.isValid()) { + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr); + } else { + // Use the triple as provided to the driver. Unlike the parsed triple + // this has not been normalized to always contain every field. + llvm::sys::path::append(SysRootDir, getDriver().Dir, "..", + getDriver().getTargetTriple()); + } if (!llvm::sys::fs::exists(SysRootDir)) return std::string(); - return SysRootDir; + return SysRootDir.str(); } void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -99,20 +134,35 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - std::string Linker = getToolChain().GetProgramPath(getShortName()); - - if (D.isUsingLTO()) { - assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], - D.getLTOMode() == LTOK_Thin); + bool IsRV64 = ToolChain.getArch() == llvm::Triple::riscv64; + CmdArgs.push_back("-m"); + if (IsRV64) { + CmdArgs.push_back("elf64lriscv"); + } else { + CmdArgs.push_back("elf32lriscv"); } + std::string Linker = getToolChain().GetProgramPath(getShortName()); + bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + const char *crtbegin, *crtend; + auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); + if (RuntimeLib == ToolChain::RLT_Libgcc) { + crtbegin = "crtbegin.o"; + crtend = "crtend.o"; + } else { + assert (RuntimeLib == ToolChain::RLT_CompilerRT); + crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", + ToolChain::FT_Object); + crtend = ToolChain.getCompilerRTArgString(Args, "crtend", + ToolChain::FT_Object); + } + if (WantCRTs) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -133,11 +183,11 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgloss"); CmdArgs.push_back("--end-group"); - CmdArgs.push_back("-lgcc"); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } if (WantCRTs) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h index 673d749d76ff7..bb7f64849bcb6 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -25,7 +25,9 @@ public: void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const override; - bool HasNativeLLVMSupport() const override { return true; } + RuntimeLibType GetDefaultRuntimeLibType() const override; + UnwindLibType + GetUnwindLibType(const llvm::opt::ArgList &Args) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 3add913b700fa..907f86b8233c5 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -8,6 +8,7 @@ #include "WebAssembly.h" #include "CommonArgs.h" +#include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -90,6 +91,39 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); + + // When optimizing, if wasm-opt is available, run it. + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt"); + if (WasmOptPath != "wasm-opt") { + StringRef OOpt = "s"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "4"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) + OOpt = A->getValue(); + + if (OOpt != "0") { + const char *WasmOpt = Args.MakeArgString(WasmOptPath); + ArgStringList CmdArgs; + CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(std::make_unique<Command>(JA, *this, WasmOpt, CmdArgs, Inputs)); + } + } + } +} + +/// Given a base library directory, append path components to form the +/// LTO directory. +static std::string AppendLTOLibDir(const std::string &Dir) { + // The version allows the path to be keyed to the specific version of + // LLVM in used, as the bitcode format is not stable. + return Dir + "/llvm-lto/" LLVM_VERSION_STRING; } WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, @@ -100,16 +134,24 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().getInstalledDir()); + auto SysRoot = getDriver().SysRoot; if (getTriple().getOS() == llvm::Triple::UnknownOS) { // Theoretically an "unknown" OS should mean no standard libraries, however // it could also mean that a custom set of libraries is in use, so just add // /lib to the search path. Disable multiarch in this case, to discourage // paths containing "unknown" from acquiring meanings. - getFilePaths().push_back(getDriver().SysRoot + "/lib"); + getFilePaths().push_back(SysRoot + "/lib"); } else { const std::string MultiarchTriple = - getMultiarchTriple(getDriver(), Triple, getDriver().SysRoot); - getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple); + getMultiarchTriple(getDriver(), Triple, SysRoot); + if (D.isUsingLTO()) { + // For LTO, enable use of lto-enabled sysroot libraries too, if available. + // Note that the directory is keyed to the LLVM revision, as LLVM's + // bitcode format is not stable. + auto Dir = AppendLTOLibDir(SysRoot + "/lib/" + MultiarchTriple); + getFilePaths().push_back(Dir); + } + getFilePaths().push_back(SysRoot + "/lib/" + MultiarchTriple); } } @@ -137,9 +179,9 @@ bool WebAssembly::HasNativeLLVMSupport() const { return true; } void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { - if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, true)) - CC1Args.push_back("-fuse-init-array"); + if (!DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread, @@ -181,6 +223,12 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, getDriver().Diag(diag::err_drv_argument_not_allowed_with) << "-fwasm-exceptions" << "-mno-exception-handling"; + // '-fwasm-exceptions' is not compatible with '-mno-reference-types' + if (DriverArgs.hasFlag(options::OPT_mno_reference_types, + options::OPT_mexception_handing, false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-fwasm-exceptions" + << "-mno-reference-types"; // '-fwasm-exceptions' is not compatible with // '-mllvm -enable-emscripten-cxx-exceptions' for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { @@ -189,9 +237,11 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, << "-fwasm-exceptions" << "-mllvm -enable-emscripten-cxx-exceptions"; } - // '-fwasm-exceptions' implies exception-handling + // '-fwasm-exceptions' implies exception-handling and reference-types CC1Args.push_back("-target-feature"); CC1Args.push_back("+exception-handling"); + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+reference-types"); } } diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index a30710645af3a..7d83be2521e73 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -212,6 +212,16 @@ bool types::isHIP(ID Id) { } } +bool types::isFortran(ID Id) { + switch (Id) { + default: + return false; + + case TY_Fortran: case TY_PP_Fortran: + return true; + } +} + bool types::isSrcFile(ID Id) { return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; } @@ -320,22 +330,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::copy_if(PhaseList, std::back_inserter(P), [](phases::ID Phase) { return Phase <= phases::Precompile; }); - // Treat Interface Stubs like its own compilation mode. - else if (DAL.getLastArg(options::OPT_emit_interface_stubs)) { - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList; - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList; - phases::ID LastPhase = phases::IfsMerge; - if (Id != types::TY_IFS) { - if (DAL.hasArg(options::OPT_c)) - LastPhase = phases::Compile; - PL = IfsModePhaseList; - types::getCompilationPhases(types::TY_IFS_CPP, PL); - } - llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) { - return Phase <= LastPhase; - }); - } - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. else if (DAL.getLastArg(options::OPT_fsyntax_only) || DAL.getLastArg(options::OPT_print_supported_cpus) || diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp index 16e7c7ecf36b4..a2dd63f9eb77c 100644 --- a/clang/lib/Driver/XRayArgs.cpp +++ b/clang/lib/Driver/XRayArgs.cpp @@ -70,6 +70,13 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { D.Diag(diag::err_drv_clang_unsupported) << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } + + // Both XRay and -fpatchable-function-entry use + // TargetOpcode::PATCHABLE_FUNCTION_ENTER. + if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fxray-instrument" << A->getSpelling(); + XRayInstrument = true; if (const Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_, @@ -129,7 +136,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { // are treated as actual dependencies. for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_always_instrument)) { - if (llvm::sys::fs::exists(Filename)) { + if (D.getVFS().exists(Filename)) { AlwaysInstrumentFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else @@ -138,7 +145,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_never_instrument)) { - if (llvm::sys::fs::exists(Filename)) { + if (D.getVFS().exists(Filename)) { NeverInstrumentFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else @@ -147,7 +154,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_attr_list)) { - if (llvm::sys::fs::exists(Filename)) { + if (D.getVFS().exists(Filename)) { AttrListFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else |