aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Driver
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Driver')
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Action.cpp66
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Compilation.cpp26
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Distro.cpp25
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Driver.cpp2662
-rw-r--r--contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp44
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Job.cpp81
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Multilib.cpp417
-rw-r--r--contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp197
-rw-r--r--contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp1684
-rw-r--r--contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp349
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChain.cpp431
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp257
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h14
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp456
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h32
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp293
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h49
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp280
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h23
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp144
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h65
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp324
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h1
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp272
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h20
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp169
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h47
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp232
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h37
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp50
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h8
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp23
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp140
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h5
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp127
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h4
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp157
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h3
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp8
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp87
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp414
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h47
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp204
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h63
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp3471
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h26
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp149
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h70
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp1605
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h100
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp27
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h39
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp13
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h8
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp481
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h143
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp1047
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h63
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp154
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h14
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp770
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h63
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp218
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h32
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp213
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h49
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp1463
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h19
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp130
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h8
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h7
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp22
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp259
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h63
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp257
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h40
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp83
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h14
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp24
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h45
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp227
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h4
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp9
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp903
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h51
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h523
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp266
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h21
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp113
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h64
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp16
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h1
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp293
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h103
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp11
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp265
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h14
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp419
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h95
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp155
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h9
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp26
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h2
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp310
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h122
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp33
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h5
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h65
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h8
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp238
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h18
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp21
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h1
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp220
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h14
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h5
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp308
-rw-r--r--contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h58
-rw-r--r--contrib/llvm-project/clang/lib/Driver/Types.cpp179
-rw-r--r--contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp153
129 files changed, 17365 insertions, 9240 deletions
diff --git a/contrib/llvm-project/clang/lib/Driver/Action.cpp b/contrib/llvm-project/clang/lib/Driver/Action.cpp
index eb08bfe9cde5..849bf6035ebd 100644
--- a/contrib/llvm-project/clang/lib/Driver/Action.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Action.cpp
@@ -25,7 +25,8 @@ const char *Action::getClassName(ActionClass AC) {
return "offload";
case PreprocessJobClass: return "preprocessor";
case PrecompileJobClass: return "precompiler";
- case HeaderModulePrecompileJobClass: return "header-module-precompiler";
+ case ExtractAPIJobClass:
+ return "api-extractor";
case AnalyzeJobClass: return "analyzer";
case MigrateJobClass: return "migrator";
case CompileJobClass: return "compiler";
@@ -41,18 +42,21 @@ const char *Action::getClassName(ActionClass AC) {
return "clang-offload-bundler";
case OffloadUnbundlingJobClass:
return "clang-offload-unbundler";
- case OffloadWrapperJobClass:
- return "clang-offload-wrapper";
+ case OffloadPackagerJobClass:
+ return "clang-offload-packager";
case LinkerWrapperJobClass:
return "clang-linker-wrapper";
case StaticLibJobClass:
return "static-lib-linker";
+ case BinaryAnalyzeJobClass:
+ return "binary-analyzer";
}
llvm_unreachable("invalid class");
}
-void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
+void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch,
+ const ToolChain *OToolChain) {
// Offload action set its own kinds on their dependences.
if (Kind == OffloadClass)
return;
@@ -65,9 +69,10 @@ void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");
OffloadingDeviceKind = OKind;
OffloadingArch = OArch;
+ OffloadingToolChain = OToolChain;
for (auto *A : Inputs)
- A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch);
+ A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch, OToolChain);
}
void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {
@@ -89,7 +94,8 @@ void Action::propagateOffloadInfo(const Action *A) {
propagateHostOffloadInfo(HK, A->getOffloadingArch());
else
propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),
- A->getOffloadingArch());
+ A->getOffloadingArch(),
+ A->getOffloadingToolChain());
}
std::string Action::getOffloadingKindPrefix() const {
@@ -190,9 +196,10 @@ OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
DevToolChains(DDeps.getToolChains()) {
auto &OKinds = DDeps.getOffloadKinds();
auto &BArchs = DDeps.getBoundArchs();
+ auto &OTCs = DDeps.getToolChains();
// If all inputs agree on the same kind, use it also for this action.
- if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
+ if (llvm::all_equal(OKinds))
OffloadingDeviceKind = OKinds.front();
// If we have a single dependency, inherit the architecture from it.
@@ -201,7 +208,7 @@ OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
// Propagate info to the dependencies.
for (unsigned i = 0, e = getInputs().size(); i != e; ++i)
- getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]);
+ getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i], OTCs[i]);
}
OffloadAction::OffloadAction(const HostDependence &HDep,
@@ -216,12 +223,17 @@ OffloadAction::OffloadAction(const HostDependence &HDep,
// Add device inputs and propagate info to the device actions. Do work only if
// we have dependencies.
- for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
+ for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) {
if (auto *A = DDeps.getActions()[i]) {
getInputs().push_back(A);
A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
- DDeps.getBoundArchs()[i]);
+ DDeps.getBoundArchs()[i],
+ DDeps.getToolChains()[i]);
+ // If this action is used to forward single dependency, set the toolchain.
+ if (DDeps.getActions().size() == 1)
+ OffloadingToolChain = DDeps.getToolChains()[i];
}
+ }
}
void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
@@ -300,6 +312,19 @@ void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
DeviceOffloadKinds.push_back(OKind);
}
+void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
+ const char *BoundArch,
+ unsigned OffloadKindMask) {
+ DeviceActions.push_back(&A);
+ DeviceToolChains.push_back(&TC);
+ DeviceBoundArchs.push_back(BoundArch);
+
+ // Add each active offloading kind from a mask.
+ for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP})
+ if (OKind & OffloadKindMask)
+ DeviceOffloadKinds.push_back(OKind);
+}
+
OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
const char *BoundArch,
const DeviceDependences &DDeps)
@@ -332,12 +357,10 @@ PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input,
assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind");
}
-void HeaderModulePrecompileJobAction::anchor() {}
+void ExtractAPIJobAction::anchor() {}
-HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction(
- Action *Input, types::ID OutputType, const char *ModuleName)
- : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType),
- ModuleName(ModuleName) {}
+ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType)
+ : JobAction(ExtractAPIJobClass, Inputs, OutputType) {}
void AnalyzeJobAction::anchor() {}
@@ -414,11 +437,11 @@ void OffloadUnbundlingJobAction::anchor() {}
OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
: JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
-void OffloadWrapperJobAction::anchor() {}
+void OffloadPackagerJobAction::anchor() {}
-OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs,
- types::ID Type)
- : JobAction(OffloadWrapperJobClass, Inputs, Type) {}
+OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs,
+ types::ID Type)
+ : JobAction(OffloadPackagerJobClass, Inputs, Type) {}
void LinkerWrapperJobAction::anchor() {}
@@ -430,3 +453,8 @@ void StaticLibJobAction::anchor() {}
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
: JobAction(StaticLibJobClass, Inputs, Type) {}
+
+void BinaryAnalyzeJobAction::anchor() {}
+
+BinaryAnalyzeJobAction::BinaryAnalyzeJobAction(Action *Input, types::ID Type)
+ : JobAction(BinaryAnalyzeJobClass, Input, Type) {}
diff --git a/contrib/llvm-project/clang/lib/Driver/Compilation.cpp b/contrib/llvm-project/clang/lib/Driver/Compilation.cpp
index 67d941c6c2ab..ad077d5bbfa6 100644
--- a/contrib/llvm-project/clang/lib/Driver/Compilation.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Compilation.cpp
@@ -15,15 +15,14 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
#include <cassert>
#include <string>
#include <system_error>
@@ -102,7 +101,7 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
}
// Add allocated arguments to the final DAL.
- for (auto ArgPtr : AllocatedArgs)
+ for (auto *ArgPtr : AllocatedArgs)
Entry->AddSynthesizedArg(ArgPtr);
}
@@ -162,7 +161,8 @@ bool Compilation::CleanupFileMap(const ArgStringMap &Files,
}
int Compilation::ExecuteCommand(const Command &C,
- const Command *&FailingCommand) const {
+ const Command *&FailingCommand,
+ bool LogOnly) const {
if ((getDriver().CCPrintOptions ||
getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
raw_ostream *OS = &llvm::errs();
@@ -191,6 +191,9 @@ int Compilation::ExecuteCommand(const Command &C,
C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
}
+ if (LogOnly)
+ return 0;
+
std::string Error;
bool ExecutionFailed;
int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
@@ -237,7 +240,8 @@ static bool InputsOk(const Command &C,
}
void Compilation::ExecuteJobs(const JobList &Jobs,
- FailingCommandList &FailingCommands) const {
+ FailingCommandList &FailingCommands,
+ bool LogOnly) const {
// According to UNIX standard, driver need to continue compiling all the
// inputs on the command line even one of them failed.
// In all but CLMode, execute all the jobs unless the necessary inputs for the
@@ -246,7 +250,7 @@ void Compilation::ExecuteJobs(const JobList &Jobs,
if (!InputsOk(Job, FailingCommands))
continue;
const Command *FailingCommand = nullptr;
- if (int Res = ExecuteCommand(Job, FailingCommand)) {
+ if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) {
FailingCommands.push_back(std::make_pair(Res, FailingCommand));
// Bail as soon as one command fails in cl driver mode.
if (TheDriver.IsCLMode())
@@ -278,9 +282,9 @@ void Compilation::initCompilationForDiagnostics() {
options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M,
options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ,
options::OPT_MQ, options::OPT_MT, options::OPT_MV};
- for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
- if (TranslatedArgs->hasArg(OutputOpts[i]))
- TranslatedArgs->eraseArg(OutputOpts[i]);
+ for (const auto &Opt : OutputOpts) {
+ if (TranslatedArgs->hasArg(Opt))
+ TranslatedArgs->eraseArg(Opt);
}
TranslatedArgs->ClaimAllArgs();
@@ -292,7 +296,7 @@ void Compilation::initCompilationForDiagnostics() {
TCArgs.clear();
// Redirect stdout/stderr to /dev/null.
- Redirects = {None, {""}, {""}};
+ Redirects = {std::nullopt, {""}, {""}};
// Temporary files added by diagnostics should be kept.
ForceKeepTempFiles = true;
@@ -302,6 +306,6 @@ StringRef Compilation::getSysRoot() const {
return getDriver().SysRoot;
}
-void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
+void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {
this->Redirects = Redirects;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/Distro.cpp b/contrib/llvm-project/clang/lib/Driver/Distro.cpp
index 5ac38c34d112..a7e7f169dc14 100644
--- a/contrib/llvm-project/clang/lib/Driver/Distro.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Distro.cpp
@@ -11,11 +11,11 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Threading.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/Triple.h"
using namespace clang::driver;
using namespace clang;
@@ -34,7 +34,7 @@ static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) {
// Obviously this can be improved a lot.
for (StringRef Line : Lines)
- if (Version == Distro::UnknownDistro && Line.startswith("ID="))
+ if (Version == Distro::UnknownDistro && Line.starts_with("ID="))
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(3))
.Case("alpine", Distro::AlpineLinux)
.Case("fedora", Distro::Fedora)
@@ -60,7 +60,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {
for (StringRef Line : Lines)
if (Version == Distro::UnknownDistro &&
- Line.startswith("DISTRIB_CODENAME="))
+ Line.starts_with("DISTRIB_CODENAME="))
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))
.Case("hardy", Distro::UbuntuHardy)
.Case("intrepid", Distro::UbuntuIntrepid)
@@ -91,6 +91,10 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {
.Case("hirsute", Distro::UbuntuHirsute)
.Case("impish", Distro::UbuntuImpish)
.Case("jammy", Distro::UbuntuJammy)
+ .Case("kinetic", Distro::UbuntuKinetic)
+ .Case("lunar", Distro::UbuntuLunar)
+ .Case("mantic", Distro::UbuntuMantic)
+ .Case("noble", Distro::UbuntuNoble)
.Default(Distro::UnknownDistro);
return Version;
}
@@ -109,16 +113,16 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
if (Version != Distro::UnknownDistro)
return Version;
- // Otherwise try some distro-specific quirks for RedHat...
+ // Otherwise try some distro-specific quirks for Red Hat...
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
VFS.getBufferForFile("/etc/redhat-release");
if (File) {
StringRef Data = File.get()->getBuffer();
- if (Data.startswith("Fedora release"))
+ if (Data.starts_with("Fedora release"))
return Distro::Fedora;
- if (Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS") || Data.startswith("Scientific Linux")) {
+ if (Data.starts_with("Red Hat Enterprise Linux") ||
+ Data.starts_with("CentOS") || Data.starts_with("Scientific Linux")) {
if (Data.contains("release 7"))
return Distro::RHEL7;
else if (Data.contains("release 6"))
@@ -153,6 +157,8 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
return Distro::DebianBullseye;
case 12:
return Distro::DebianBookworm;
+ case 13:
+ return Distro::DebianTrixie;
default:
return Distro::UnknownDistro;
}
@@ -165,6 +171,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
.Case("buster/sid", Distro::DebianBuster)
.Case("bullseye/sid", Distro::DebianBullseye)
.Case("bookworm/sid", Distro::DebianBookworm)
+ .Case("trixie/sid", Distro::DebianTrixie)
.Default(Distro::UnknownDistro);
}
@@ -175,7 +182,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
for (const StringRef &Line : Lines) {
- if (!Line.trim().startswith("VERSION"))
+ if (!Line.trim().starts_with("VERSION"))
continue;
std::pair<StringRef, StringRef> SplitLine = Line.split('=');
// Old versions have split VERSION and PATCHLEVEL
diff --git a/contrib/llvm-project/clang/lib/Driver/Driver.cpp b/contrib/llvm-project/clang/lib/Driver/Driver.cpp
index 3bfddeefc7b2..93cddf742d52 100644
--- a/contrib/llvm-project/clang/lib/Driver/Driver.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Driver.cpp
@@ -11,11 +11,10 @@
#include "ToolChains/AMDGPU.h"
#include "ToolChains/AMDGPUOpenMP.h"
#include "ToolChains/AVR.h"
-#include "ToolChains/Ananas.h"
+#include "ToolChains/Arch/RISCV.h"
#include "ToolChains/BareMetal.h"
+#include "ToolChains/CSKYToolChain.h"
#include "ToolChains/Clang.h"
-#include "ToolChains/CloudABI.h"
-#include "ToolChains/Contiki.h"
#include "ToolChains/CrossWindows.h"
#include "ToolChains/Cuda.h"
#include "ToolChains/Darwin.h"
@@ -25,6 +24,7 @@
#include "ToolChains/Gnu.h"
#include "ToolChains/HIPAMD.h"
#include "ToolChains/HIPSPV.h"
+#include "ToolChains/HLSL.h"
#include "ToolChains/Haiku.h"
#include "ToolChains/Hexagon.h"
#include "ToolChains/Hurd.h"
@@ -33,11 +33,10 @@
#include "ToolChains/MSP430.h"
#include "ToolChains/MSVC.h"
#include "ToolChains/MinGW.h"
-#include "ToolChains/Minix.h"
#include "ToolChains/MipsLinux.h"
-#include "ToolChains/Myriad.h"
#include "ToolChains/NaCl.h"
#include "ToolChains/NetBSD.h"
+#include "ToolChains/OHOS.h"
#include "ToolChains/OpenBSD.h"
#include "ToolChains/PPCFreeBSD.h"
#include "ToolChains/PPCLinux.h"
@@ -59,13 +58,13 @@
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/Phases.h"
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@@ -82,17 +81,21 @@
#include "llvm/Support/ExitCodes.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+#include <cstdlib> // ::getenv
#include <map>
#include <memory>
+#include <optional>
+#include <set>
#include <utility>
#if LLVM_ON_UNIX
#include <unistd.h> // getpid
@@ -102,8 +105,8 @@ using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
-static llvm::Optional<llvm::Triple>
-getOffloadTargetTriple(const Driver &D, const ArgList &Args) {
+static std::optional<llvm::Triple> getOffloadTargetTriple(const Driver &D,
+ const ArgList &Args) {
auto OffloadTargets = Args.getAllArgValues(options::OPT_offload_EQ);
// Offload compilation flow does not support multiple targets for now. We
// need the HIPActionBuilder (and possibly the CudaActionBuilder{,Base}too)
@@ -111,17 +114,17 @@ getOffloadTargetTriple(const Driver &D, const ArgList &Args) {
switch (OffloadTargets.size()) {
default:
D.Diag(diag::err_drv_only_one_offload_target_supported);
- return llvm::None;
+ return std::nullopt;
case 0:
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << "";
- return llvm::None;
+ return std::nullopt;
case 1:
break;
}
return llvm::Triple(OffloadTargets[0]);
}
-static llvm::Optional<llvm::Triple>
+static std::optional<llvm::Triple>
getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args,
const llvm::Triple &HostTriple) {
if (!Args.hasArg(options::OPT_offload_EQ)) {
@@ -134,19 +137,19 @@ getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args,
if (Args.hasArg(options::OPT_emit_llvm))
return TT;
D.Diag(diag::err_drv_cuda_offload_only_emit_bc);
- return llvm::None;
+ return std::nullopt;
}
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
- return llvm::None;
+ return std::nullopt;
}
-static llvm::Optional<llvm::Triple>
+static std::optional<llvm::Triple>
getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
if (!Args.hasArg(options::OPT_offload_EQ)) {
return llvm::Triple("amdgcn-amd-amdhsa"); // Default HIP triple.
}
auto TT = getOffloadTargetTriple(D, Args);
if (!TT)
- return llvm::None;
+ return std::nullopt;
if (TT->getArch() == llvm::Triple::amdgcn &&
TT->getVendor() == llvm::Triple::AMD &&
TT->getOS() == llvm::Triple::AMDHSA)
@@ -154,7 +157,7 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
if (TT->getArch() == llvm::Triple::spirv64)
return TT;
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
- return llvm::None;
+ return std::nullopt;
}
// static
@@ -177,23 +180,28 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath,
// path of the embedding binary, which for LLVM binaries will be in bin/.
// ../lib gets us to lib/ in both cases.
P = llvm::sys::path::parent_path(Dir);
- llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang",
- CLANG_VERSION_STRING);
+ // This search path is also created in the COFF driver of lld, so any
+ // changes here also needs to happen in lld/COFF/Driver.cpp
+ llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
+ CLANG_VERSION_MAJOR_STRING);
}
- return std::string(P.str());
+ return std::string(P);
}
Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
DiagnosticsEngine &Diags, std::string Title,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
- SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
+ SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone),
+ Offload(OffloadHostDevice), CXX20HeaderType(HeaderMode_None),
+ ModulesModeCXX20(false), LTOMode(LTOK_None),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
- CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
- CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
- CheckInputsExist(true), GenReproducer(false),
+ CCLogDiagnostics(false), CCGenDiagnostics(false),
+ CCPrintProcessStats(false), CCPrintInternalStats(false),
+ TargetTriple(TargetTriple), Saver(Alloc), PrependArg(nullptr),
+ CheckInputsExist(true), ProbePrecompiled(true),
SuppressMissingInputWarning(false) {
// Provide a sane fallback if no VFS is specified.
if (!this->VFS)
@@ -214,7 +222,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR;
#endif
#if defined(CLANG_CONFIG_FILE_USER_DIR)
- UserConfigDir = CLANG_CONFIG_FILE_USER_DIR;
+ {
+ SmallString<128> P;
+ llvm::sys::fs::expand_tilde(CLANG_CONFIG_FILE_USER_DIR, P);
+ UserConfigDir = static_cast<std::string>(P);
+ }
#endif
// Compute the path to the resource directory.
@@ -222,40 +234,30 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
}
void Driver::setDriverMode(StringRef Value) {
- static const std::string OptName =
+ static StringRef OptName =
getOpts().getOption(options::OPT_driver_mode).getPrefixedName();
- if (auto M = llvm::StringSwitch<llvm::Optional<DriverMode>>(Value)
+ if (auto M = llvm::StringSwitch<std::optional<DriverMode>>(Value)
.Case("gcc", GCCMode)
.Case("g++", GXXMode)
.Case("cpp", CPPMode)
.Case("cl", CLMode)
.Case("flang", FlangMode)
- .Default(None))
+ .Case("dxc", DXCMode)
+ .Default(std::nullopt))
Mode = *M;
else
Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
}
InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
- bool IsClCompatMode,
- bool &ContainsError) {
+ bool UseDriverMode, bool &ContainsError) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
ContainsError = false;
- unsigned IncludedFlagsBitmask;
- unsigned ExcludedFlagsBitmask;
- std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
- getIncludeExcludeOptionFlagMasks(IsClCompatMode);
-
- // Make sure that Flang-only options don't pollute the Clang output
- // TODO: Make sure that Clang-only options don't pollute Flang output
- if (!IsFlangMode())
- ExcludedFlagsBitmask |= options::FlangOnlyOption;
-
+ llvm::opt::Visibility VisibilityMask = getOptionVisibilityMask(UseDriverMode);
unsigned MissingArgIndex, MissingArgCount;
- InputArgList Args =
- getOpts().ParseArgs(ArgStrings, MissingArgIndex, MissingArgCount,
- IncludedFlagsBitmask, ExcludedFlagsBitmask);
+ InputArgList Args = getOpts().ParseArgs(ArgStrings, MissingArgIndex,
+ MissingArgCount, VisibilityMask);
// Check for missing argument error.
if (MissingArgCount) {
@@ -269,19 +271,9 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
// Check for unsupported options.
for (const Arg *A : Args) {
if (A->getOption().hasFlag(options::Unsupported)) {
- unsigned DiagID;
- auto ArgString = A->getAsString(Args);
- std::string Nearest;
- if (getOpts().findNearest(
- ArgString, Nearest, IncludedFlagsBitmask,
- ExcludedFlagsBitmask | options::Unsupported) > 1) {
- DiagID = diag::err_drv_unsupported_opt;
- Diag(DiagID) << ArgString;
- } else {
- DiagID = diag::err_drv_unsupported_opt_with_suggestion;
- Diag(DiagID) << ArgString << Nearest;
- }
- ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) >
+ Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(diag::err_drv_unsupported_opt,
+ SourceLocation()) >
DiagnosticsEngine::Warning;
continue;
}
@@ -299,11 +291,17 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
unsigned DiagID;
auto ArgString = A->getAsString(Args);
std::string Nearest;
- if (getOpts().findNearest(
- ArgString, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) > 1) {
- DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
- : diag::err_drv_unknown_argument;
- Diags.Report(DiagID) << ArgString;
+ if (getOpts().findNearest(ArgString, Nearest, VisibilityMask) > 1) {
+ if (!IsCLMode() &&
+ getOpts().findExact(ArgString, Nearest,
+ llvm::opt::Visibility(options::CC1Option))) {
+ DiagID = diag::err_drv_unknown_argument_with_suggestion;
+ Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest;
+ } else {
+ DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
+ : diag::err_drv_unknown_argument;
+ Diags.Report(DiagID) << ArgString;
+ }
} else {
DiagID = IsCLMode()
? diag::warn_drv_unknown_argument_clang_cl_with_suggestion
@@ -314,6 +312,18 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
DiagnosticsEngine::Warning;
}
+ for (const Arg *A : Args.filtered(options::OPT_o)) {
+ if (ArgStrings[A->getIndex()] == A->getSpelling())
+ continue;
+
+ // Warn on joined arguments that are similar to a long argument.
+ std::string ArgString = ArgStrings[A->getIndex()];
+ std::string Nearest;
+ if (getOpts().findExact("-" + ArgString, Nearest, VisibilityMask))
+ Diags.Report(diag::warn_drv_potentially_misspelled_joined_argument)
+ << A->getAsString(Args) << Nearest;
+ }
+
return Args;
}
@@ -333,11 +343,15 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
CCGenDiagnostics) {
FinalPhase = phases::Preprocess;
- // --precompile only runs up to precompilation.
- } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) {
+ // --precompile only runs up to precompilation.
+ // Options that cause the output of C++20 compiled module interfaces or
+ // header units have the same effect.
+ } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_extract_api)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_fmodule_header,
+ options::OPT_fmodule_header_EQ))) {
FinalPhase = phases::Precompile;
-
- // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
+ // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
(PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) ||
(PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
@@ -346,8 +360,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
(PhaseArg = DAL.getLastArg(options::OPT__analyze)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_extract_api))) {
+ (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
FinalPhase = phases::Compile;
// -S only runs up to the backend.
@@ -467,6 +480,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
DAL->append(A);
}
+ // DXC mode quits before assembly if an output object file isn't specified.
+ if (IsDXCMode() && !Args.hasArg(options::OPT_dxc_Fo))
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
+
// Enforce -static if -miamcu is present.
if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false))
DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_static));
@@ -509,40 +526,38 @@ static llvm::Triple computeTargetTriple(const Driver &D,
if (Target.isOSBinFormatMachO()) {
// If an explicit Darwin arch name is given, that trumps all.
if (!DarwinArchName.empty()) {
- tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName);
+ tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName,
+ Args);
return Target;
}
// Handle the Darwin '-arch' flag.
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
StringRef ArchName = A->getValue();
- tools::darwin::setTripleTypeForMachOArchName(Target, ArchName);
+ tools::darwin::setTripleTypeForMachOArchName(Target, ArchName, Args);
}
}
// Handle pseudo-target flags '-mlittle-endian'/'-EL' and
// '-mbig-endian'/'-EB'.
- if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
- options::OPT_mbig_endian)) {
- if (A->getOption().matches(options::OPT_mlittle_endian)) {
- llvm::Triple LE = Target.getLittleEndianArchVariant();
- if (LE.getArch() != llvm::Triple::UnknownArch)
- Target = std::move(LE);
- } else {
- llvm::Triple BE = Target.getBigEndianArchVariant();
- if (BE.getArch() != llvm::Triple::UnknownArch)
- Target = std::move(BE);
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian)) {
+ llvm::Triple T = A->getOption().matches(options::OPT_mlittle_endian)
+ ? Target.getLittleEndianArchVariant()
+ : Target.getBigEndianArchVariant();
+ if (T.getArch() != llvm::Triple::UnknownArch) {
+ Target = std::move(T);
+ Args.claimAllArgs(options::OPT_mlittle_endian, options::OPT_mbig_endian);
}
}
// Skip further flag support on OSes which don't support '-m32' or '-m64'.
- if (Target.getArch() == llvm::Triple::tce ||
- Target.getOS() == llvm::Triple::Minix)
+ if (Target.getArch() == llvm::Triple::tce)
return Target;
// On AIX, the env OBJECT_MODE may affect the resulting arch variant.
if (Target.isOSAIX()) {
- if (Optional<std::string> ObjectModeValue =
+ if (std::optional<std::string> ObjectModeValue =
llvm::sys::Process::GetEnv("OBJECT_MODE")) {
StringRef ObjectMode = *ObjectModeValue;
llvm::Triple::ArchType AT = llvm::Triple::UnknownArch;
@@ -560,13 +575,21 @@ static llvm::Triple computeTargetTriple(const Driver &D,
}
}
+ // The `-maix[32|64]` flags are only valid for AIX targets.
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_maix32, options::OPT_maix64);
+ A && !Target.isOSAIX())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << Target.str();
+
// Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'.
Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32,
- options::OPT_m32, options::OPT_m16);
+ options::OPT_m32, options::OPT_m16,
+ options::OPT_maix32, options::OPT_maix64);
if (A) {
llvm::Triple::ArchType AT = llvm::Triple::UnknownArch;
- if (A->getOption().matches(options::OPT_m64)) {
+ if (A->getOption().matches(options::OPT_m64) ||
+ A->getOption().matches(options::OPT_maix64)) {
AT = Target.get64BitArchVariant().getArch();
if (Target.getEnvironment() == llvm::Triple::GNUX32)
Target.setEnvironment(llvm::Triple::GNU);
@@ -579,7 +602,8 @@ static llvm::Triple computeTargetTriple(const Driver &D,
Target.setEnvironment(llvm::Triple::MuslX32);
else
Target.setEnvironment(llvm::Triple::GNUX32);
- } else if (A->getOption().matches(options::OPT_m32)) {
+ } else if (A->getOption().matches(options::OPT_m32) ||
+ A->getOption().matches(options::OPT_maix32)) {
AT = Target.get32BitArchVariant().getArch();
if (Target.getEnvironment() == llvm::Triple::GNUX32)
Target.setEnvironment(llvm::Triple::GNU);
@@ -619,36 +643,44 @@ static llvm::Triple computeTargetTriple(const Driver &D,
// If target is MIPS adjust the target triple
// accordingly to provided ABI name.
- A = Args.getLastArg(options::OPT_mabi_EQ);
- if (A && Target.isMIPS()) {
- StringRef ABIName = A->getValue();
- if (ABIName == "32") {
- Target = Target.get32BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNUABI64 ||
- Target.getEnvironment() == llvm::Triple::GNUABIN32)
- Target.setEnvironment(llvm::Triple::GNU);
- } else if (ABIName == "n32") {
- Target = Target.get64BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNU ||
- Target.getEnvironment() == llvm::Triple::GNUABI64)
- Target.setEnvironment(llvm::Triple::GNUABIN32);
- } else if (ABIName == "64") {
- Target = Target.get64BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNU ||
- Target.getEnvironment() == llvm::Triple::GNUABIN32)
- Target.setEnvironment(llvm::Triple::GNUABI64);
+ if (Target.isMIPS()) {
+ if ((A = Args.getLastArg(options::OPT_mabi_EQ))) {
+ StringRef ABIName = A->getValue();
+ if (ABIName == "32") {
+ Target = Target.get32BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNUABI64 ||
+ Target.getEnvironment() == llvm::Triple::GNUABIN32)
+ Target.setEnvironment(llvm::Triple::GNU);
+ } else if (ABIName == "n32") {
+ Target = Target.get64BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNU ||
+ Target.getEnvironment() == llvm::Triple::GNUABI64)
+ Target.setEnvironment(llvm::Triple::GNUABIN32);
+ } else if (ABIName == "64") {
+ Target = Target.get64BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNU ||
+ Target.getEnvironment() == llvm::Triple::GNUABIN32)
+ Target.setEnvironment(llvm::Triple::GNUABI64);
+ }
}
}
// 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_insensitive("rv32"))
- Target.setArch(llvm::Triple::riscv32);
- else if (ArchName.startswith_insensitive("rv64"))
- Target.setArch(llvm::Triple::riscv64);
+ if (Target.isRISCV()) {
+ if (Args.hasArg(options::OPT_march_EQ) ||
+ Args.hasArg(options::OPT_mcpu_EQ)) {
+ StringRef ArchName = tools::riscv::getRISCVArch(Args, Target);
+ auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
+ ArchName, /*EnableExperimentalExtensions=*/true);
+ if (!llvm::errorToBool(ISAInfo.takeError())) {
+ unsigned XLen = (*ISAInfo)->getXLen();
+ if (XLen == 32)
+ Target.setArch(llvm::Triple::riscv32);
+ else if (XLen == 64)
+ Target.setArch(llvm::Triple::riscv64);
+ }
+ }
}
return Target;
@@ -672,7 +704,7 @@ static driver::LTOKind parseLTOMode(Driver &D, const llvm::opt::ArgList &Args,
if (LTOMode == LTOK_Unknown) {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
return LTOK_None;
}
return LTOMode;
@@ -685,6 +717,17 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) {
OffloadLTOMode = parseLTOMode(*this, Args, options::OPT_foffload_lto_EQ,
options::OPT_fno_offload_lto);
+
+ // Try to enable `-foffload-lto=full` if `-fopenmp-target-jit` is on.
+ if (Args.hasFlag(options::OPT_fopenmp_target_jit,
+ options::OPT_fno_openmp_target_jit, false)) {
+ if (Arg *A = Args.getLastArg(options::OPT_foffload_lto_EQ,
+ options::OPT_fno_offload_lto))
+ if (OffloadLTOMode != LTOK_Full)
+ Diag(diag::err_drv_incompatible_options)
+ << A->getSpelling() << "-fopenmp-target-jit";
+ OffloadLTOMode = LTOK_Full;
+ }
}
/// Compute the desired OpenMP runtime from the flags provided.
@@ -704,7 +747,7 @@ Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const {
if (RT == OMPRT_Unknown) {
if (A)
Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
else
// FIXME: We could use a nicer diagnostic here.
Diag(diag::err_drv_unsupported_opt) << "-fopenmp";
@@ -730,7 +773,8 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
[](std::pair<types::ID, const llvm::opt::Arg *> &I) {
return types::isHIP(I.first);
}) ||
- C.getInputArgs().hasArg(options::OPT_hip_link);
+ C.getInputArgs().hasArg(options::OPT_hip_link) ||
+ C.getInputArgs().hasArg(options::OPT_hipstdpar);
if (IsCuda && IsHIP) {
Diag(clang::diag::err_drv_mix_cuda_hip);
return;
@@ -748,7 +792,13 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
auto &CudaTC = ToolChains[CudaTriple->str() + "/" + HostTriple.str()];
if (!CudaTC) {
CudaTC = std::make_unique<toolchains::CudaToolChain>(
- *this, *CudaTriple, *HostTC, C.getInputArgs(), OFK);
+ *this, *CudaTriple, *HostTC, C.getInputArgs());
+
+ // Emit a warning if the detected CUDA version is too new.
+ CudaInstallationDetector &CudaInstallation =
+ static_cast<toolchains::CudaToolChain &>(*CudaTC).CudaInstallation;
+ if (CudaInstallation.isValid())
+ CudaInstallation.WarnIfUnsupportedVersion();
}
C.addOffloadDeviceToolChain(CudaTC.get(), OFK);
} else if (IsHIP) {
@@ -773,76 +823,146 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
// OpenMP
//
// We need to generate an OpenMP toolchain if the user specified targets with
- // the -fopenmp-targets option.
- if (Arg *OpenMPTargets =
- C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) {
- if (OpenMPTargets->getNumValues()) {
- // We expect that -fopenmp-targets is always used in conjunction with the
- // option -fopenmp specifying a valid runtime with offloading support,
- // i.e. libomp or libiomp.
- bool HasValidOpenMPRuntime = C.getInputArgs().hasFlag(
- options::OPT_fopenmp, options::OPT_fopenmp_EQ,
- options::OPT_fno_openmp, false);
- if (HasValidOpenMPRuntime) {
- OpenMPRuntimeKind OpenMPKind = getOpenMPRuntime(C.getInputArgs());
- HasValidOpenMPRuntime =
- OpenMPKind == OMPRT_OMP || OpenMPKind == OMPRT_IOMP5;
+ // the -fopenmp-targets option or used --offload-arch with OpenMP enabled.
+ bool IsOpenMPOffloading =
+ C.getInputArgs().hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false) &&
+ (C.getInputArgs().hasArg(options::OPT_fopenmp_targets_EQ) ||
+ C.getInputArgs().hasArg(options::OPT_offload_arch_EQ));
+ if (IsOpenMPOffloading) {
+ // We expect that -fopenmp-targets is always used in conjunction with the
+ // option -fopenmp specifying a valid runtime with offloading support, i.e.
+ // libomp or libiomp.
+ OpenMPRuntimeKind RuntimeKind = getOpenMPRuntime(C.getInputArgs());
+ if (RuntimeKind != OMPRT_OMP && RuntimeKind != OMPRT_IOMP5) {
+ Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets);
+ return;
+ }
+
+ llvm::StringMap<llvm::DenseSet<StringRef>> DerivedArchs;
+ llvm::StringMap<StringRef> FoundNormalizedTriples;
+ std::multiset<StringRef> OpenMPTriples;
+
+ // If the user specified -fopenmp-targets= we create a toolchain for each
+ // valid triple. Otherwise, if only --offload-arch= was specified we instead
+ // attempt to derive the appropriate toolchains from the arguments.
+ if (Arg *OpenMPTargets =
+ C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) {
+ if (OpenMPTargets && !OpenMPTargets->getNumValues()) {
+ Diag(clang::diag::warn_drv_empty_joined_argument)
+ << OpenMPTargets->getAsString(C.getInputArgs());
+ return;
+ }
+ for (StringRef T : OpenMPTargets->getValues())
+ OpenMPTriples.insert(T);
+ } else if (C.getInputArgs().hasArg(options::OPT_offload_arch_EQ) &&
+ !IsHIP && !IsCuda) {
+ const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>();
+ auto AMDTriple = getHIPOffloadTargetTriple(*this, C.getInputArgs());
+ auto NVPTXTriple = getNVIDIAOffloadTargetTriple(*this, C.getInputArgs(),
+ HostTC->getTriple());
+
+ // Attempt to deduce the offloading triple from the set of architectures.
+ // We can only correctly deduce NVPTX / AMDGPU triples currently. We need
+ // to temporarily create these toolchains so that we can access tools for
+ // inferring architectures.
+ llvm::DenseSet<StringRef> Archs;
+ if (NVPTXTriple) {
+ auto TempTC = std::make_unique<toolchains::CudaToolChain>(
+ *this, *NVPTXTriple, *HostTC, C.getInputArgs());
+ for (StringRef Arch : getOffloadArchs(
+ C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
+ Archs.insert(Arch);
+ }
+ if (AMDTriple) {
+ auto TempTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
+ *this, *AMDTriple, *HostTC, C.getInputArgs());
+ for (StringRef Arch : getOffloadArchs(
+ C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
+ Archs.insert(Arch);
+ }
+ if (!AMDTriple && !NVPTXTriple) {
+ for (StringRef Arch :
+ getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr, true))
+ Archs.insert(Arch);
}
- if (HasValidOpenMPRuntime) {
- llvm::StringMap<const char *> FoundNormalizedTriples;
- for (const char *Val : OpenMPTargets->getValues()) {
- llvm::Triple TT(ToolChain::getOpenMPTriple(Val));
- std::string NormalizedName = TT.normalize();
-
- // Make sure we don't have a duplicate triple.
- auto Duplicate = FoundNormalizedTriples.find(NormalizedName);
- if (Duplicate != FoundNormalizedTriples.end()) {
- Diag(clang::diag::warn_drv_omp_offload_target_duplicate)
- << Val << Duplicate->second;
- continue;
- }
+ for (StringRef Arch : Archs) {
+ if (NVPTXTriple && IsNVIDIAGpuArch(StringToCudaArch(
+ getProcessorFromTargetID(*NVPTXTriple, Arch)))) {
+ DerivedArchs[NVPTXTriple->getTriple()].insert(Arch);
+ } else if (AMDTriple &&
+ IsAMDGpuArch(StringToCudaArch(
+ getProcessorFromTargetID(*AMDTriple, Arch)))) {
+ DerivedArchs[AMDTriple->getTriple()].insert(Arch);
+ } else {
+ Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch) << Arch;
+ return;
+ }
+ }
- // Store the current triple so that we can check for duplicates in the
- // following iterations.
- FoundNormalizedTriples[NormalizedName] = Val;
-
- // If the specified target is invalid, emit a diagnostic.
- if (TT.getArch() == llvm::Triple::UnknownArch)
- Diag(clang::diag::err_drv_invalid_omp_target) << Val;
- else {
- const ToolChain *TC;
- // Device toolchains have to be selected differently. They pair host
- // and device in their implementation.
- if (TT.isNVPTX() || TT.isAMDGCN()) {
- const ToolChain *HostTC =
- C.getSingleOffloadToolChain<Action::OFK_Host>();
- assert(HostTC && "Host toolchain should be always defined.");
- auto &DeviceTC =
- ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()];
- if (!DeviceTC) {
- if (TT.isNVPTX())
- DeviceTC = std::make_unique<toolchains::CudaToolChain>(
- *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP);
- else if (TT.isAMDGCN())
- DeviceTC =
- std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
- *this, TT, *HostTC, C.getInputArgs());
- else
- assert(DeviceTC && "Device toolchain not defined.");
- }
-
- TC = DeviceTC.get();
- } else
- TC = &getToolChain(C.getInputArgs(), TT);
- C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP);
+ // If the set is empty then we failed to find a native architecture.
+ if (Archs.empty()) {
+ Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch)
+ << "native";
+ return;
+ }
+
+ for (const auto &TripleAndArchs : DerivedArchs)
+ OpenMPTriples.insert(TripleAndArchs.first());
+ }
+
+ for (StringRef Val : OpenMPTriples) {
+ llvm::Triple TT(ToolChain::getOpenMPTriple(Val));
+ std::string NormalizedName = TT.normalize();
+
+ // Make sure we don't have a duplicate triple.
+ auto Duplicate = FoundNormalizedTriples.find(NormalizedName);
+ if (Duplicate != FoundNormalizedTriples.end()) {
+ Diag(clang::diag::warn_drv_omp_offload_target_duplicate)
+ << Val << Duplicate->second;
+ continue;
+ }
+
+ // Store the current triple so that we can check for duplicates in the
+ // following iterations.
+ FoundNormalizedTriples[NormalizedName] = Val;
+
+ // If the specified target is invalid, emit a diagnostic.
+ if (TT.getArch() == llvm::Triple::UnknownArch)
+ Diag(clang::diag::err_drv_invalid_omp_target) << Val;
+ else {
+ const ToolChain *TC;
+ // Device toolchains have to be selected differently. They pair host
+ // and device in their implementation.
+ if (TT.isNVPTX() || TT.isAMDGCN()) {
+ const ToolChain *HostTC =
+ C.getSingleOffloadToolChain<Action::OFK_Host>();
+ assert(HostTC && "Host toolchain should be always defined.");
+ auto &DeviceTC =
+ ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()];
+ if (!DeviceTC) {
+ if (TT.isNVPTX())
+ DeviceTC = std::make_unique<toolchains::CudaToolChain>(
+ *this, TT, *HostTC, C.getInputArgs());
+ else if (TT.isAMDGCN())
+ DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
+ *this, TT, *HostTC, C.getInputArgs());
+ else
+ assert(DeviceTC && "Device toolchain not defined.");
}
- }
- } else
- Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets);
- } else
- Diag(clang::diag::warn_drv_empty_joined_argument)
- << OpenMPTargets->getAsString(C.getInputArgs());
+
+ TC = DeviceTC.get();
+ } else
+ TC = &getToolChain(C.getInputArgs(), TT);
+ C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP);
+ if (DerivedArchs.contains(TT.getTriple()))
+ KnownArchs[TC] = DerivedArchs[TT.getTriple()];
+ }
+ }
+ } else if (C.getInputArgs().hasArg(options::OPT_fopenmp_targets_EQ)) {
+ Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets);
+ return;
}
//
@@ -850,69 +970,78 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
//
}
-/// Looks the given directories for the specified file.
-///
-/// \param[out] FilePath File path, if the file was found.
-/// \param[in] Dirs Directories used for the search.
-/// \param[in] FileName Name of the file to search for.
-/// \return True if file was found.
-///
-/// Looks for file specified by FileName sequentially in directories specified
-/// by Dirs.
-///
-static bool searchForFile(SmallVectorImpl<char> &FilePath,
- ArrayRef<StringRef> Dirs, StringRef FileName) {
- SmallString<128> WPath;
- for (const StringRef &Dir : Dirs) {
- if (Dir.empty())
- continue;
- WPath.clear();
- llvm::sys::path::append(WPath, Dir, FileName);
- llvm::sys::path::native(WPath);
- if (llvm::sys::fs::is_regular_file(WPath)) {
- FilePath = std::move(WPath);
- return true;
- }
- }
- return false;
+static void appendOneArg(InputArgList &Args, const Arg *Opt,
+ const Arg *BaseArg) {
+ // The args for config files or /clang: flags belong to different InputArgList
+ // objects than Args. This copies an Arg from one of those other InputArgLists
+ // to the ownership of Args.
+ unsigned Index = Args.MakeIndex(Opt->getSpelling());
+ Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
+ Index, BaseArg);
+ Copy->getValues() = Opt->getValues();
+ if (Opt->isClaimed())
+ Copy->claim();
+ Copy->setOwnsValues(Opt->getOwnsValues());
+ Opt->setOwnsValues(false);
+ Args.append(Copy);
}
-bool Driver::readConfigFile(StringRef FileName) {
+bool Driver::readConfigFile(StringRef FileName,
+ llvm::cl::ExpansionContext &ExpCtx) {
+ // Try opening the given file.
+ auto Status = getVFS().status(FileName);
+ if (!Status) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << FileName << Status.getError().message();
+ return true;
+ }
+ if (Status->getType() != llvm::sys::fs::file_type::regular_file) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << FileName << "not a regular file";
+ return true;
+ }
+
// Try reading the given file.
SmallVector<const char *, 32> NewCfgArgs;
- if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) {
- Diag(diag::err_drv_cannot_read_config_file) << FileName;
+ if (llvm::Error Err = ExpCtx.readConfigFile(FileName, NewCfgArgs)) {
+ Diag(diag::err_drv_cannot_read_config_file)
+ << FileName << toString(std::move(Err));
return true;
}
// Read options from config file.
llvm::SmallString<128> CfgFileName(FileName);
llvm::sys::path::native(CfgFileName);
- ConfigFile = std::string(CfgFileName);
bool ContainErrors;
- CfgOptions = std::make_unique<InputArgList>(
- ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors));
- if (ContainErrors) {
- CfgOptions.reset();
+ std::unique_ptr<InputArgList> NewOptions = std::make_unique<InputArgList>(
+ ParseArgStrings(NewCfgArgs, /*UseDriverMode=*/true, ContainErrors));
+ if (ContainErrors)
return true;
- }
-
- if (CfgOptions->hasArg(options::OPT_config)) {
- CfgOptions.reset();
- Diag(diag::err_drv_nested_config_file);
- return true;
- }
// Claim all arguments that come from a configuration file so that the driver
// does not warn on any that is unused.
- for (Arg *A : *CfgOptions)
+ for (Arg *A : *NewOptions)
A->claim();
+
+ if (!CfgOptions)
+ CfgOptions = std::move(NewOptions);
+ else {
+ // If this is a subsequent config file, append options to the previous one.
+ for (auto *Opt : *NewOptions) {
+ const Arg *BaseArg = &Opt->getBaseArg();
+ if (BaseArg == Opt)
+ BaseArg = nullptr;
+ appendOneArg(*CfgOptions, Opt, BaseArg);
+ }
+ }
+ ConfigFiles.push_back(std::string(CfgFileName));
return false;
}
-bool Driver::loadConfigFile() {
- std::string CfgFileName;
- bool FileSpecifiedExplicitly = false;
+bool Driver::loadConfigFiles() {
+ llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(),
+ llvm::cl::tokenizeConfigFile);
+ ExpCtx.setVFS(&getVFS());
// Process options that change search path for config files.
if (CLOptions) {
@@ -920,143 +1049,141 @@ bool Driver::loadConfigFile() {
SmallString<128> CfgDir;
CfgDir.append(
CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ));
- if (!CfgDir.empty()) {
- if (llvm::sys::fs::make_absolute(CfgDir).value() != 0)
- SystemConfigDir.clear();
- else
- SystemConfigDir = std::string(CfgDir.begin(), CfgDir.end());
- }
+ if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
+ SystemConfigDir.clear();
+ else
+ SystemConfigDir = static_cast<std::string>(CfgDir);
}
if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) {
SmallString<128> CfgDir;
- CfgDir.append(
- CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ));
- if (!CfgDir.empty()) {
- if (llvm::sys::fs::make_absolute(CfgDir).value() != 0)
- UserConfigDir.clear();
- else
- UserConfigDir = std::string(CfgDir.begin(), CfgDir.end());
- }
+ llvm::sys::fs::expand_tilde(
+ CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ), CfgDir);
+ if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
+ UserConfigDir.clear();
+ else
+ UserConfigDir = static_cast<std::string>(CfgDir);
}
}
- // First try to find config file specified in command line.
- if (CLOptions) {
- std::vector<std::string> ConfigFiles =
- CLOptions->getAllArgValues(options::OPT_config);
- if (ConfigFiles.size() > 1) {
- if (!llvm::all_of(ConfigFiles, [ConfigFiles](const std::string &s) {
- return s == ConfigFiles[0];
- })) {
- Diag(diag::err_drv_duplicate_config);
- return true;
- }
- }
+ // Prepare list of directories where config file is searched for.
+ StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
+ ExpCtx.setSearchDirs(CfgFileSearchDirs);
- if (!ConfigFiles.empty()) {
- CfgFileName = ConfigFiles.front();
- assert(!CfgFileName.empty());
+ // First try to load configuration from the default files, return on error.
+ if (loadDefaultConfigFiles(ExpCtx))
+ return true;
+ // Then load configuration files specified explicitly.
+ SmallString<128> CfgFilePath;
+ if (CLOptions) {
+ for (auto CfgFileName : CLOptions->getAllArgValues(options::OPT_config)) {
// If argument contains directory separator, treat it as a path to
// configuration file.
if (llvm::sys::path::has_parent_path(CfgFileName)) {
- SmallString<128> CfgFilePath;
- if (llvm::sys::path::is_relative(CfgFileName))
- llvm::sys::fs::current_path(CfgFilePath);
- llvm::sys::path::append(CfgFilePath, CfgFileName);
- if (!llvm::sys::fs::is_regular_file(CfgFilePath)) {
- Diag(diag::err_drv_config_file_not_exist) << CfgFilePath;
- return true;
+ CfgFilePath.assign(CfgFileName);
+ if (llvm::sys::path::is_relative(CfgFilePath)) {
+ if (getVFS().makeAbsolute(CfgFilePath)) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << CfgFilePath << "cannot get absolute path";
+ return true;
+ }
}
- return readConfigFile(CfgFilePath);
+ } else if (!ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) {
+ // Report an error that the config file could not be found.
+ Diag(diag::err_drv_config_file_not_found) << CfgFileName;
+ for (const StringRef &SearchDir : CfgFileSearchDirs)
+ if (!SearchDir.empty())
+ Diag(diag::note_drv_config_file_searched_in) << SearchDir;
+ return true;
}
- FileSpecifiedExplicitly = true;
+ // Try to read the config file, return on error.
+ if (readConfigFile(CfgFilePath, ExpCtx))
+ return true;
}
}
- // If config file is not specified explicitly, try to deduce configuration
- // from executable name. For instance, an executable 'armv7l-clang' will
- // search for config file 'armv7l-clang.cfg'.
- if (CfgFileName.empty() && !ClangNameParts.TargetPrefix.empty())
- CfgFileName = ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix;
+ // No error occurred.
+ return false;
+}
- if (CfgFileName.empty())
+bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) {
+ // Disable default config if CLANG_NO_DEFAULT_CONFIG is set to a non-empty
+ // value.
+ if (const char *NoConfigEnv = ::getenv("CLANG_NO_DEFAULT_CONFIG")) {
+ if (*NoConfigEnv)
+ return false;
+ }
+ if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config))
return false;
- // Determine architecture part of the file name, if it is present.
- StringRef CfgFileArch = CfgFileName;
- size_t ArchPrefixLen = CfgFileArch.find('-');
- if (ArchPrefixLen == StringRef::npos)
- ArchPrefixLen = CfgFileArch.size();
- llvm::Triple CfgTriple;
- CfgFileArch = CfgFileArch.take_front(ArchPrefixLen);
- CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch));
- if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch)
- ArchPrefixLen = 0;
-
- if (!StringRef(CfgFileName).endswith(".cfg"))
- CfgFileName += ".cfg";
-
- // If config file starts with architecture name and command line options
- // redefine architecture (with options like -m32 -LE etc), try finding new
- // config file with that architecture.
- SmallString<128> FixedConfigFile;
- size_t FixedArchPrefixLen = 0;
- if (ArchPrefixLen) {
- // Get architecture name from config file name like 'i386.cfg' or
- // 'armv7l-clang.cfg'.
- // Check if command line options changes effective triple.
- llvm::Triple EffectiveTriple = computeTargetTriple(*this,
- CfgTriple.getTriple(), *CLOptions);
- if (CfgTriple.getArch() != EffectiveTriple.getArch()) {
- FixedConfigFile = EffectiveTriple.getArchName();
- FixedArchPrefixLen = FixedConfigFile.size();
- // Append the rest of original file name so that file name transforms
- // like: i386-clang.cfg -> x86_64-clang.cfg.
- if (ArchPrefixLen < CfgFileName.size())
- FixedConfigFile += CfgFileName.substr(ArchPrefixLen);
- }
+ std::string RealMode = getExecutableForDriverMode(Mode);
+ std::string Triple;
+
+ // If name prefix is present, no --target= override was passed via CLOptions
+ // and the name prefix is not a valid triple, force it for backwards
+ // compatibility.
+ if (!ClangNameParts.TargetPrefix.empty() &&
+ computeTargetTriple(*this, "/invalid/", *CLOptions).str() ==
+ "/invalid/") {
+ llvm::Triple PrefixTriple{ClangNameParts.TargetPrefix};
+ if (PrefixTriple.getArch() == llvm::Triple::UnknownArch ||
+ PrefixTriple.isOSUnknown())
+ Triple = PrefixTriple.str();
+ }
+
+ // Otherwise, use the real triple as used by the driver.
+ if (Triple.empty()) {
+ llvm::Triple RealTriple =
+ computeTargetTriple(*this, TargetTriple, *CLOptions);
+ Triple = RealTriple.str();
+ assert(!Triple.empty());
+ }
+
+ // Search for config files in the following order:
+ // 1. <triple>-<mode>.cfg using real driver mode
+ // (e.g. i386-pc-linux-gnu-clang++.cfg).
+ // 2. <triple>-<mode>.cfg using executable suffix
+ // (e.g. i386-pc-linux-gnu-clang-g++.cfg for *clang-g++).
+ // 3. <triple>.cfg + <mode>.cfg using real driver mode
+ // (e.g. i386-pc-linux-gnu.cfg + clang++.cfg).
+ // 4. <triple>.cfg + <mode>.cfg using executable suffix
+ // (e.g. i386-pc-linux-gnu.cfg + clang-g++.cfg for *clang-g++).
+
+ // Try loading <triple>-<mode>.cfg, and return if we find a match.
+ SmallString<128> CfgFilePath;
+ std::string CfgFileName = Triple + '-' + RealMode + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+
+ bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() &&
+ ClangNameParts.ModeSuffix != RealMode;
+ if (TryModeSuffix) {
+ CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+ }
+
+ // Try loading <mode>.cfg, and return if loading failed. If a matching file
+ // was not found, still proceed on to try <triple>.cfg.
+ CfgFileName = RealMode + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) {
+ if (readConfigFile(CfgFilePath, ExpCtx))
+ return true;
+ } else if (TryModeSuffix) {
+ CfgFileName = ClangNameParts.ModeSuffix + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath) &&
+ readConfigFile(CfgFilePath, ExpCtx))
+ return true;
}
- // Prepare list of directories where config file is searched for.
- StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
-
- // Try to find config file. First try file with corrected architecture.
- llvm::SmallString<128> CfgFilePath;
- if (!FixedConfigFile.empty()) {
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
- return readConfigFile(CfgFilePath);
- // If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'.
- FixedConfigFile.resize(FixedArchPrefixLen);
- FixedConfigFile.append(".cfg");
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
- return readConfigFile(CfgFilePath);
- }
-
- // Then try original file name.
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
- return readConfigFile(CfgFilePath);
-
- // Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'.
- if (!ClangNameParts.ModeSuffix.empty() &&
- !ClangNameParts.TargetPrefix.empty()) {
- CfgFileName.assign(ClangNameParts.TargetPrefix);
- CfgFileName.append(".cfg");
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
- return readConfigFile(CfgFilePath);
- }
-
- // Report error but only if config file was specified explicitly, by option
- // --config. If it was deduced from executable name, it is not an error.
- if (FileSpecifiedExplicitly) {
- Diag(diag::err_drv_config_file_not_found) << CfgFileName;
- for (const StringRef &SearchDir : CfgFileSearchDirs)
- if (!SearchDir.empty())
- Diag(diag::note_drv_config_file_searched_in) << SearchDir;
- return true;
- }
+ // Try loading <triple>.cfg and return if we find a match.
+ CfgFileName = Triple + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+ // If we were unable to find a config file deduced from executable name,
+ // that is not an error.
return false;
}
@@ -1078,32 +1205,17 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// Arguments specified in command line.
bool ContainsError;
CLOptions = std::make_unique<InputArgList>(
- ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError));
+ ParseArgStrings(ArgList.slice(1), /*UseDriverMode=*/true, ContainsError));
// Try parsing configuration file.
if (!ContainsError)
- ContainsError = loadConfigFile();
+ ContainsError = loadConfigFiles();
bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr);
// All arguments, from both config file and command line.
InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions)
: std::move(*CLOptions));
- // The args for config files or /clang: flags belong to different InputArgList
- // objects than Args. This copies an Arg from one of those other InputArgLists
- // to the ownership of Args.
- auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) {
- unsigned Index = Args.MakeIndex(Opt->getSpelling());
- Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
- Index, BaseArg);
- Copy->getValues() = Opt->getValues();
- if (Opt->isClaimed())
- Copy->claim();
- Copy->setOwnsValues(Opt->getOwnsValues());
- Opt->setOwnsValues(false);
- Args.append(Copy);
- };
-
if (HasConfigFile)
for (auto *Opt : *CLOptions) {
if (Opt->getOption().matches(options::OPT_config))
@@ -1111,7 +1223,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const Arg *BaseArg = &Opt->getBaseArg();
if (BaseArg == Opt)
BaseArg = nullptr;
- appendOneArg(Opt, BaseArg);
+ appendOneArg(Args, Opt, BaseArg);
}
// In CL mode, look for any pass-through arguments
@@ -1126,11 +1238,12 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// Parse any pass through args using default clang processing rather
// than clang-cl processing.
auto CLModePassThroughOptions = std::make_unique<InputArgList>(
- ParseArgStrings(CLModePassThroughArgList, false, ContainsError));
+ ParseArgStrings(CLModePassThroughArgList, /*UseDriverMode=*/false,
+ ContainsError));
if (!ContainsError)
for (auto *Opt : *CLModePassThroughOptions) {
- appendOneArg(Opt, nullptr);
+ appendOneArg(Args, Opt, nullptr);
}
}
}
@@ -1143,9 +1256,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
- // Silence driver warnings if requested
- Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
-
// -canonical-prefixes, -no-canonical-prefixes are used very early in main.
Args.ClaimAllArgs(options::OPT_canonical_prefixes);
Args.ClaimAllArgs(options::OPT_no_canonical_prefixes);
@@ -1167,9 +1277,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings);
if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name))
CCCGenericGCCName = A->getValue();
- GenReproducer = Args.hasFlag(options::OPT_gen_reproducer,
- options::OPT_fno_crash_diagnostics,
- !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"));
// Process -fproc-stat-report options.
if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) {
@@ -1188,8 +1295,45 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
T.setVendor(llvm::Triple::PC);
T.setEnvironment(llvm::Triple::MSVC);
T.setObjectFormat(llvm::Triple::COFF);
+ if (Args.hasArg(options::OPT__SLASH_arm64EC))
+ T.setArch(llvm::Triple::aarch64, llvm::Triple::AArch64SubArch_arm64ec);
TargetTriple = T.str();
+ } else if (IsDXCMode()) {
+ // Build TargetTriple from target_profile option for clang-dxc.
+ if (const Arg *A = Args.getLastArg(options::OPT_target_profile)) {
+ StringRef TargetProfile = A->getValue();
+ if (auto Triple =
+ toolchains::HLSLToolChain::parseTargetProfile(TargetProfile))
+ TargetTriple = *Triple;
+ else
+ Diag(diag::err_drv_invalid_directx_shader_module) << TargetProfile;
+
+ A->claim();
+
+ if (Args.hasArg(options::OPT_spirv)) {
+ llvm::Triple T(TargetTriple);
+ T.setArch(llvm::Triple::spirv);
+ T.setOS(llvm::Triple::Vulkan);
+
+ // Set specific Vulkan version if applicable.
+ if (const Arg *A = Args.getLastArg(options::OPT_fspv_target_env_EQ)) {
+ const llvm::StringSet<> ValidValues = {"vulkan1.2", "vulkan1.3"};
+ if (ValidValues.contains(A->getValue())) {
+ T.setOSName(A->getValue());
+ } else {
+ Diag(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ A->claim();
+ }
+
+ TargetTriple = T.str();
+ }
+ } else {
+ Diag(diag::err_drv_dxc_missing_target_profile);
+ }
}
+
if (const Arg *A = Args.getLastArg(options::OPT_target))
TargetTriple = A->getValue();
if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir))
@@ -1198,7 +1342,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
A->claim();
PrefixDirs.push_back(A->getValue(0));
}
- if (Optional<std::string> CompilerPathValue =
+ if (std::optional<std::string> CompilerPathValue =
llvm::sys::Process::GetEnv("COMPILER_PATH")) {
StringRef CompilerPath = *CompilerPathValue;
while (!CompilerPath.empty()) {
@@ -1223,6 +1367,17 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
.Default(SaveTempsCwd);
}
+ if (const Arg *A = Args.getLastArg(options::OPT_offload_host_only,
+ options::OPT_offload_device_only,
+ options::OPT_offload_host_device)) {
+ if (A->getOption().matches(options::OPT_offload_host_only))
+ Offload = OffloadHost;
+ else if (A->getOption().matches(options::OPT_offload_device_only))
+ Offload = OffloadDevice;
+ else
+ Offload = OffloadHostDevice;
+ }
+
setLTOMode(Args);
// Process -fembed-bitcode= flags.
@@ -1241,6 +1396,43 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model);
}
+ // Remove existing compilation database so that each job can append to it.
+ if (Arg *A = Args.getLastArg(options::OPT_MJ))
+ llvm::sys::fs::remove(A->getValue());
+
+ // Setting up the jobs for some precompile cases depends on whether we are
+ // treating them as PCH, implicit modules or C++20 ones.
+ // TODO: inferring the mode like this seems fragile (it meets the objective
+ // of not requiring anything new for operation, however).
+ const Arg *Std = Args.getLastArg(options::OPT_std_EQ);
+ ModulesModeCXX20 =
+ !Args.hasArg(options::OPT_fmodules) && Std &&
+ (Std->containsValue("c++20") || Std->containsValue("c++2a") ||
+ Std->containsValue("c++23") || Std->containsValue("c++2b") ||
+ Std->containsValue("c++26") || Std->containsValue("c++2c") ||
+ Std->containsValue("c++latest"));
+
+ // Process -fmodule-header{=} flags.
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_header_EQ,
+ options::OPT_fmodule_header)) {
+ // These flags force C++20 handling of headers.
+ ModulesModeCXX20 = true;
+ if (A->getOption().matches(options::OPT_fmodule_header))
+ CXX20HeaderType = HeaderMode_Default;
+ else {
+ StringRef ArgName = A->getValue();
+ unsigned Kind = llvm::StringSwitch<unsigned>(ArgName)
+ .Case("user", HeaderMode_User)
+ .Case("system", HeaderMode_System)
+ .Default(~0U);
+ if (Kind == ~0U) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << ArgName;
+ } else
+ CXX20HeaderType = static_cast<ModuleHeaderMode>(Kind);
+ }
+ }
+
std::unique_ptr<llvm::opt::InputArgList> UArgs =
std::make_unique<InputArgList>(std::move(Args));
@@ -1251,6 +1443,55 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const ToolChain &TC = getToolChain(
*UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));
+ if (TC.getTriple().isAndroid()) {
+ llvm::Triple Triple = TC.getTriple();
+ StringRef TripleVersionName = Triple.getEnvironmentVersionString();
+
+ if (Triple.getEnvironmentVersion().empty() && TripleVersionName != "") {
+ Diags.Report(diag::err_drv_triple_version_invalid)
+ << TripleVersionName << TC.getTripleString();
+ ContainsError = true;
+ }
+ }
+
+ // Report warning when arm64EC option is overridden by specified target
+ if ((TC.getTriple().getArch() != llvm::Triple::aarch64 ||
+ TC.getTriple().getSubArch() != llvm::Triple::AArch64SubArch_arm64ec) &&
+ UArgs->hasArg(options::OPT__SLASH_arm64EC)) {
+ getDiags().Report(clang::diag::warn_target_override_arm64ec)
+ << TC.getTriple().str();
+ }
+
+ // A common user mistake is specifying a target of aarch64-none-eabi or
+ // arm-none-elf whereas the correct names are aarch64-none-elf &
+ // arm-none-eabi. Detect these cases and issue a warning.
+ if (TC.getTriple().getOS() == llvm::Triple::UnknownOS &&
+ TC.getTriple().getVendor() == llvm::Triple::UnknownVendor) {
+ switch (TC.getTriple().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ if (TC.getTriple().getEnvironmentName() == "elf") {
+ Diag(diag::warn_target_unrecognized_env)
+ << TargetTriple
+ << (TC.getTriple().getArchName().str() + "-none-eabi");
+ }
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::aarch64_32:
+ if (TC.getTriple().getEnvironmentName().starts_with("eabi")) {
+ Diag(diag::warn_target_unrecognized_env)
+ << TargetTriple
+ << (TC.getTriple().getArchName().str() + "-none-elf");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
// The compilation takes ownership of Args.
Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
ContainsError);
@@ -1311,7 +1552,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
// (or /Library/Logs/DiagnosticReports for root) and has the filename pattern
// clang-<VERSION>_<YYYY-MM-DD-HHMMSS>_<hostname>.crash.
path::home_directory(CrashDiagDir);
- if (CrashDiagDir.startswith("/var/root"))
+ if (CrashDiagDir.starts_with("/var/root"))
CrashDiagDir = "/";
path::append(CrashDiagDir, "Library/Logs/DiagnosticReports");
int PID =
@@ -1329,7 +1570,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
StringRef FileName = path::filename(File->path());
- if (!FileName.startswith(Name))
+ if (!FileName.starts_with(Name))
continue;
if (fs::status(File->path(), FileStatus))
continue;
@@ -1340,7 +1581,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
// The first line should start with "Process:", otherwise this isn't a real
// .crash file.
StringRef Data = CrashFile.get()->getBuffer();
- if (!Data.startswith("Process:"))
+ if (!Data.starts_with("Process:"))
continue;
// Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]"
size_t ParentProcPos = Data.find("Parent Process:");
@@ -1390,6 +1631,11 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
return false;
}
+static const char BugReporMsg[] =
+ "\n********************\n\n"
+ "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
+ "Preprocessed source(s) and associated run script(s) are located at:";
+
// When clang crashes, produce diagnostic information including the fully
// preprocessed source file(s). Request that the developer attach the
// diagnostic information to a bug report.
@@ -1399,11 +1645,36 @@ void Driver::generateCompilationDiagnostics(
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
- // Don't try to generate diagnostics for link or dsymutil jobs.
- if (FailingCommand.getCreator().isLinkJob() ||
- FailingCommand.getCreator().isDsymutilJob())
+ unsigned Level = 1;
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_EQ)) {
+ Level = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("off", 0)
+ .Case("compiler", 1)
+ .Case("all", 2)
+ .Default(1);
+ }
+ if (!Level)
+ return;
+
+ // Don't try to generate diagnostics for dsymutil jobs.
+ if (FailingCommand.getCreator().isDsymutilJob())
return;
+ bool IsLLD = false;
+ ArgStringList SavedTemps;
+ if (FailingCommand.getCreator().isLinkJob()) {
+ C.getDefaultToolChain().GetLinkerPath(&IsLLD);
+ if (!IsLLD || Level < 2)
+ return;
+
+ // If lld crashed, we will re-run the same command with the input it used
+ // to have. In that case we should not remove temp files in
+ // initCompilationForDiagnostics yet. They will be added back and removed
+ // later.
+ SavedTemps = std::move(C.getTempFiles());
+ assert(!C.getTempFiles().size());
+ }
+
// Print the version of the compiler.
PrintVersion(C, llvm::errs());
@@ -1420,6 +1691,29 @@ void Driver::generateCompilationDiagnostics(
// Suppress tool output.
C.initCompilationForDiagnostics();
+ // If lld failed, rerun it again with --reproduce.
+ if (IsLLD) {
+ const char *TmpName = CreateTempFile(C, "linker-crash", "tar");
+ Command NewLLDInvocation = Cmd;
+ llvm::opt::ArgStringList ArgList = NewLLDInvocation.getArguments();
+ StringRef ReproduceOption =
+ C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment()
+ ? "/reproduce:"
+ : "--reproduce=";
+ ArgList.push_back(Saver.save(Twine(ReproduceOption) + TmpName).data());
+ NewLLDInvocation.replaceArguments(std::move(ArgList));
+
+ // Redirect stdout/stderr to /dev/null.
+ NewLLDInvocation.Execute({std::nullopt, {""}, {""}}, nullptr, nullptr);
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << TmpName;
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "\n\n********************";
+ if (Report)
+ Report->TemporaryFiles.push_back(TmpName);
+ return;
+ }
+
// Construct the list of inputs.
InputList Inputs;
BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs);
@@ -1504,10 +1798,7 @@ void Driver::generateCompilationDiagnostics(
return;
}
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "\n********************\n\n"
- "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
- "Preprocessed source(s) and associated run script(s) are located at:";
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
SmallString<128> VFS;
SmallString<128> ReproCrashFilename;
@@ -1519,7 +1810,7 @@ void Driver::generateCompilationDiagnostics(
ReproCrashFilename = TempFile;
llvm::sys::path::replace_extension(ReproCrashFilename, ".crash");
}
- if (StringRef(TempFile).endswith(".cache")) {
+ if (StringRef(TempFile).ends_with(".cache")) {
// In some cases (modules) we'll dump extra data to help with reproducing
// the crash into a directory next to the output.
VFS = llvm::sys::path::filename(TempFile);
@@ -1527,6 +1818,9 @@ void Driver::generateCompilationDiagnostics(
}
}
+ for (const char *TempFile : SavedTemps)
+ C.addTempFile(TempFile);
+
// Assume associated files are based off of the first temporary file.
CrashReportInfo CrashInfo(TempFiles[0], VFS);
@@ -1550,7 +1844,7 @@ void Driver::generateCompilationDiagnostics(
ScriptOS << "\n# Additional information: " << AdditionalInformation
<< "\n";
if (Report)
- Report->TemporaryFiles.push_back(std::string(Script.str()));
+ Report->TemporaryFiles.push_back(std::string(Script));
Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
}
@@ -1572,9 +1866,6 @@ void Driver::generateCompilationDiagnostics(
}
}
- for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file_EQ))
- Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue();
-
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "\n\n********************";
}
@@ -1597,10 +1888,23 @@ void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) {
int Driver::ExecuteCompilation(
Compilation &C,
SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) {
+ if (C.getArgs().hasArg(options::OPT_fdriver_only)) {
+ if (C.getArgs().hasArg(options::OPT_v))
+ C.getJobs().Print(llvm::errs(), "\n", true);
+
+ C.ExecuteJobs(C.getJobs(), FailingCommands, /*LogOnly=*/true);
+
+ // If there were errors building the compilation, quit now.
+ if (!FailingCommands.empty() || Diags.hasErrorOccurred())
+ return 1;
+
+ return 0;
+ }
+
// Just print if -### was present.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
C.getJobs().Print(llvm::errs(), "\n", true);
- return 0;
+ return Diags.hasErrorOccurred() ? 1 : 0;
}
// If there were errors building the compilation, quit now.
@@ -1634,14 +1938,12 @@ int Driver::ExecuteCompilation(
C.CleanupFileMap(C.getFailureResultFiles(), JA, true);
}
-#if LLVM_ON_UNIX
- // llvm/lib/Support/Unix/Signals.inc will exit with a special return code
+ // llvm/lib/Support/*/Signals.inc will exit with a special return code
// for SIGPIPE. Do not print diagnostics for this case.
if (CommandRes == EX_IOERR) {
Res = CommandRes;
continue;
}
-#endif
// Print extra information about abnormal failures, if possible.
//
@@ -1666,24 +1968,12 @@ int Driver::ExecuteCompilation(
}
void Driver::PrintHelp(bool ShowHidden) const {
- unsigned IncludedFlagsBitmask;
- unsigned ExcludedFlagsBitmask;
- std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
- getIncludeExcludeOptionFlagMasks(IsCLMode());
-
- ExcludedFlagsBitmask |= options::NoDriverOption;
- if (!ShowHidden)
- ExcludedFlagsBitmask |= HelpHidden;
-
- if (IsFlangMode())
- IncludedFlagsBitmask |= options::FlangOption;
- else
- ExcludedFlagsBitmask |= options::FlangOnlyOption;
+ llvm::opt::Visibility VisibilityMask = getOptionVisibilityMask();
std::string Usage = llvm::formatv("{0} [options] file...", Name).str();
getOpts().printHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(),
- IncludedFlagsBitmask, ExcludedFlagsBitmask,
- /*ShowAllAliases=*/false);
+ ShowHidden, /*ShowAllAliases=*/false,
+ VisibilityMask);
}
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -1709,8 +1999,8 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
// Print out the install directory.
OS << "InstalledDir: " << InstalledDir << '\n';
- // If configuration file was used, print its path.
- if (!ConfigFile.empty())
+ // If configuration files were used, print their paths.
+ for (auto ConfigFile : ConfigFiles)
OS << "Configuration file: " << ConfigFile << '\n';
}
@@ -1731,18 +2021,17 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
std::vector<std::string> SuggestedCompletions;
std::vector<std::string> Flags;
- unsigned int DisableFlags =
- options::NoDriverOption | options::Unsupported | options::Ignored;
+ llvm::opt::Visibility VisibilityMask(options::ClangOption);
// Make sure that Flang-only options don't pollute the Clang output
// TODO: Make sure that Clang-only options don't pollute Flang output
- if (!IsFlangMode())
- DisableFlags |= options::FlangOnlyOption;
+ if (IsFlangMode())
+ VisibilityMask = llvm::opt::Visibility(options::FlangOption);
// Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag,"
// because the latter indicates that the user put space before pushing tab
// which should end up in a file completion.
- const bool HasSpace = PassedFlags.endswith(",");
+ const bool HasSpace = PassedFlags.ends_with(",");
// Parse PassedFlags by "," as all the command-line flags are passed to this
// function separated by ","
@@ -1756,7 +2045,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
// We want to show cc1-only options only when clang is invoked with -cc1 or
// -Xclang.
if (llvm::is_contained(Flags, "-Xclang") || llvm::is_contained(Flags, "-cc1"))
- DisableFlags &= ~options::NoDriverOption;
+ VisibilityMask = llvm::opt::Visibility(options::CC1Option);
const llvm::opt::OptTable &Opts = getOpts();
StringRef Cur;
@@ -1782,17 +2071,19 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
// When flag ends with '=' and there was no value completion, return empty
// string and fall back to the file autocompletion.
- if (SuggestedCompletions.empty() && !Cur.endswith("=")) {
+ if (SuggestedCompletions.empty() && !Cur.ends_with("=")) {
// If the flag is in the form of "--autocomplete=-foo",
// we were requested to print out all option names that start with "-foo".
// For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only".
- SuggestedCompletions = Opts.findByPrefix(Cur, DisableFlags);
+ SuggestedCompletions = Opts.findByPrefix(
+ Cur, VisibilityMask,
+ /*DisableFlags=*/options::Unsupported | options::Ignored);
// We have to query the -W flags manually as they're not in the OptTable.
// TODO: Find a good way to add them to OptTable instead and them remove
// this code.
for (StringRef S : DiagnosticIDs::getDiagnosticFlags())
- if (S.startswith(Cur))
+ if (S.starts_with(Cur))
SuggestedCompletions.push_back(std::string(S));
}
@@ -1844,7 +2135,8 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
if (C.getArgs().hasArg(options::OPT_v) ||
C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) ||
- C.getArgs().hasArg(options::OPT_print_supported_cpus)) {
+ C.getArgs().hasArg(options::OPT_print_supported_cpus) ||
+ C.getArgs().hasArg(options::OPT_print_supported_extensions)) {
PrintVersion(C, llvm::errs());
SuppressMissingInputWarning = true;
}
@@ -1903,21 +2195,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
}
if (C.getArgs().hasArg(options::OPT_print_runtime_dir)) {
- std::string RuntimePath;
- // Get the first existing path, if any.
- for (auto Path : TC.getRuntimePaths()) {
- if (getVFS().exists(Path)) {
- RuntimePath = Path;
- break;
- }
- }
- if (!RuntimePath.empty())
- llvm::outs() << RuntimePath << '\n';
+ if (std::optional<std::string> RuntimePath = TC.getRuntimePath())
+ llvm::outs() << *RuntimePath << '\n';
else
llvm::outs() << TC.getCompilerRTPath() << '\n';
return false;
}
+ if (C.getArgs().hasArg(options::OPT_print_diagnostic_options)) {
+ std::vector<std::string> Flags = DiagnosticIDs::getDiagnosticFlags();
+ for (std::size_t I = 0; I != Flags.size(); I += 2)
+ llvm::outs() << " " << Flags[I] << "\n " << Flags[I + 1] << "\n\n";
+ return false;
+ }
+
// FIXME: The following handlers should use a callback mechanism, we don't
// know what the client would like to do.
if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) {
@@ -1963,14 +2254,26 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}
+ if (C.getArgs().hasArg(options::OPT_print_multi_flags)) {
+ Multilib::flags_list ArgFlags = TC.getMultilibFlags(C.getArgs());
+ llvm::StringSet<> ExpandedFlags = TC.getMultilibs().expandFlags(ArgFlags);
+ std::set<llvm::StringRef> SortedFlags;
+ for (const auto &FlagEntry : ExpandedFlags)
+ SortedFlags.insert(FlagEntry.getKey());
+ for (auto Flag : SortedFlags)
+ llvm::outs() << Flag << '\n';
+ return false;
+ }
+
if (C.getArgs().hasArg(options::OPT_print_multi_directory)) {
- const Multilib &Multilib = TC.getMultilib();
- if (Multilib.gccSuffix().empty())
- llvm::outs() << ".\n";
- else {
- StringRef Suffix(Multilib.gccSuffix());
- assert(Suffix.front() == '/');
- llvm::outs() << Suffix.substr(1) << "\n";
+ for (const Multilib &Multilib : TC.getSelectedMultilibs()) {
+ if (Multilib.gccSuffix().empty())
+ llvm::outs() << ".\n";
+ else {
+ StringRef Suffix(Multilib.gccSuffix());
+ assert(Suffix.front() == '/');
+ llvm::outs() << Suffix.substr(1) << "\n";
+ }
}
return false;
}
@@ -1986,12 +2289,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}
- if (C.getArgs().hasArg(options::OPT_print_multiarch)) {
- llvm::outs() << TC.getMultiarchTriple(*this, TC.getTriple(), SysRoot)
- << "\n";
- return false;
- }
-
if (C.getArgs().hasArg(options::OPT_print_targets)) {
llvm::TargetRegistry::printRegisteredTargetsForVersion(llvm::outs());
return false;
@@ -2209,6 +2506,14 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
if (Value == "-")
return true;
+ // If it's a header to be found in the system or user search path, then defer
+ // complaints about its absence until those searches can be done. When we
+ // are definitely processing headers for C++20 header units, extend this to
+ // allow the user to put "-fmodule-header -xc++-header vector" for example.
+ if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader ||
+ (ModulesModeCXX20 && Ty == types::TY_CXXHeader))
+ return true;
+
if (getVFS().exists(Value))
return true;
@@ -2218,13 +2523,8 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// filenames, but e.g. `/diagnostic:caret` is more likely a typo for
// the option `/diagnostics:caret` than a reference to a file in the root
// directory.
- unsigned IncludedFlagsBitmask;
- unsigned ExcludedFlagsBitmask;
- std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
- getIncludeExcludeOptionFlagMasks(IsCLMode());
std::string Nearest;
- if (getOpts().findNearest(Value, Nearest, IncludedFlagsBitmask,
- ExcludedFlagsBitmask) <= 1) {
+ if (getOpts().findNearest(Value, Nearest, getOptionVisibilityMask()) <= 1) {
Diag(clang::diag::err_drv_no_such_file_with_suggestion)
<< Value << Nearest;
return false;
@@ -2235,7 +2535,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// they can be influenced by linker flags the clang driver might not
// understand.
// Examples:
- // - `clang-cl main.cc ole32.lib` in a a non-MSVC shell will make the driver
+ // - `clang-cl main.cc ole32.lib` in a non-MSVC shell will make the driver
// module look for an MSVC installation in the registry. (We could ask
// the MSVCToolChain object if it can find `ole32.lib`, but the logic to
// look in the registry might move into lld-link in the future so that
@@ -2265,13 +2565,28 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// so we can't downgrade diagnostics for `/GR-` from an error to a warning
// in cc mode. (We can in cl mode because cl.exe itself only warns on
// unknown flags.)
- if (IsCLMode() && Ty == types::TY_Object && !Value.startswith("/"))
+ if (IsCLMode() && Ty == types::TY_Object && !Value.starts_with("/"))
return true;
Diag(clang::diag::err_drv_no_such_file) << Value;
return false;
}
+// Get the C++20 Header Unit type corresponding to the input type.
+static types::ID CXXHeaderUnitType(ModuleHeaderMode HM) {
+ switch (HM) {
+ case HeaderMode_User:
+ return types::TY_CXXUHeader;
+ case HeaderMode_System:
+ return types::TY_CXXSHeader;
+ case HeaderMode_Default:
+ break;
+ case HeaderMode_None:
+ llvm_unreachable("should not be called in this case");
+ }
+ return types::TY_CXXHUHeader;
+}
+
// Construct a the list of inputs and their types.
void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
InputList &Inputs) const {
@@ -2295,17 +2610,32 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
for (Arg *A :
Args.filtered(options::OPT__SLASH_TC, options::OPT__SLASH_TP)) {
if (Previous) {
- Diag(clang::diag::warn_drv_overriding_flag_option)
- << Previous->getSpelling() << A->getSpelling();
+ Diag(clang::diag::warn_drv_overriding_option)
+ << Previous->getSpelling() << A->getSpelling();
ShowNote = true;
}
Previous = A;
}
if (ShowNote)
Diag(clang::diag::note_drv_t_option_is_global);
+ }
- // No driver mode exposes -x and /TC or /TP; we don't support mixing them.
- assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed");
+ // CUDA/HIP and their preprocessor expansions can be accepted by CL mode.
+ // Warn -x after last input file has no effect
+ auto LastXArg = Args.getLastArgValue(options::OPT_x);
+ const llvm::StringSet<> ValidXArgs = {"cuda", "hip", "cui", "hipi"};
+ if (!IsCLMode() || ValidXArgs.contains(LastXArg)) {
+ Arg *LastXArg = Args.getLastArgNoClaim(options::OPT_x);
+ Arg *LastInputArg = Args.getLastArgNoClaim(options::OPT_INPUT);
+ if (LastXArg && LastInputArg &&
+ LastInputArg->getIndex() < LastXArg->getIndex())
+ Diag(clang::diag::warn_drv_unused_x) << LastXArg->getValue();
+ } else {
+ // In CL mode suggest /TC or /TP since -x doesn't make sense if passed via
+ // /clang:.
+ if (auto *A = Args.getLastArg(options::OPT_x))
+ Diag(diag::err_drv_unsupported_opt_with_suggestion)
+ << A->getAsString(Args) << "/TC' or '/TP";
}
for (Arg *A : Args) {
@@ -2323,6 +2653,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
if (memcmp(Value, "-", 2) == 0) {
if (IsFlangMode()) {
Ty = types::TY_Fortran;
+ } else if (IsDXCMode()) {
+ Ty = types::TY_HLSL;
} else {
// If running with -E, treat as a C input (this changes the
// builtin macros, for example). This may be overridden by -ObjC
@@ -2360,7 +2692,9 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
types::ID OldTy = Ty;
Ty = types::lookupCXXTypeForCType(Ty);
- if (Ty != OldTy)
+ // Do not complain about foo.h, when we are known to be processing
+ // it as a C++20 header unit.
+ if (Ty != OldTy && !(OldTy == types::TY_CHeader && hasHeaderMode()))
Diag(clang::diag::warn_drv_treating_input_as_cxx)
<< getTypeName(OldTy) << getTypeName(Ty);
}
@@ -2383,6 +2717,14 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
else if (Args.hasArg(options::OPT_ObjCXX))
Ty = types::TY_ObjCXX;
}
+
+ // Disambiguate headers that are meant to be header units from those
+ // intended to be PCH. Avoid missing '.h' cases that are counted as
+ // C headers by default - we know we are in C++ mode and we do not
+ // want to issue a complaint about compiling things in the wrong mode.
+ if ((Ty == types::TY_CXXHeader || Ty == types::TY_CHeader) &&
+ hasHeaderMode())
+ Ty = CXXHeaderUnitType(CXX20HeaderType);
} else {
assert(InputTypeArg && "InputType set w/o InputTypeArg");
if (!InputTypeArg->getOption().matches(options::OPT_x)) {
@@ -2398,6 +2740,10 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
}
}
+ if ((Ty == types::TY_C || Ty == types::TY_CXX) &&
+ Args.hasArgNoClaim(options::OPT_hipstdpar))
+ Ty = types::TY_HIP;
+
if (DiagnoseInputExistence(Args, Value, Ty, /*TypoCorrect=*/true))
Inputs.push_back(std::make_pair(Ty, A));
@@ -2434,6 +2780,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
Diag(clang::diag::err_drv_unknown_language) << A->getValue();
InputType = types::TY_Object;
}
+
+ // If the user has put -fmodule-header{,=} then we treat C++ headers as
+ // header unit inputs. So we 'promote' -xc++-header appropriately.
+ if (InputType == types::TY_CXXHeader && hasHeaderMode())
+ InputType = CXXHeaderUnitType(CXX20HeaderType);
} else if (A->getOption().getID() == options::OPT_U) {
assert(A->getNumValues() == 1 && "The /U option has one value.");
StringRef Val = A->getValue(0);
@@ -2465,6 +2816,9 @@ class OffloadingActionBuilder final {
/// Map between an input argument and the offload kinds used to process it.
std::map<const Arg *, unsigned> InputArgToOffloadKindMap;
+ /// Map between a host action and its originating input argument.
+ std::map<Action *, const Arg *> HostActionToInputArgMap;
+
/// Builder interface. It doesn't build anything or keep any state.
class DeviceActionBuilder {
public:
@@ -2517,7 +2871,7 @@ class OffloadingActionBuilder final {
/// Update the state to include the provided host action \a HostAction as a
/// dependency of the current device action. By default it is inactive.
- virtual ActionBuilderReturnCode addDeviceDepences(Action *HostAction) {
+ virtual ActionBuilderReturnCode addDeviceDependences(Action *HostAction) {
return ABRT_Inactive;
}
@@ -2603,9 +2957,14 @@ class OffloadingActionBuilder final {
CudaActionBuilderBase(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs,
Action::OffloadKind OFKind)
- : DeviceActionBuilder(C, Args, Inputs, OFKind) {}
+ : DeviceActionBuilder(C, Args, Inputs, OFKind) {
- ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override {
+ CompileDeviceOnly = C.getDriver().offloadDeviceOnly();
+ Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
+ options::OPT_fno_gpu_rdc, /*Default=*/false);
+ }
+
+ ActionBuilderReturnCode addDeviceDependences(Action *HostAction) override {
// While generating code for CUDA, we only depend on the host input action
// to trigger the creation of all the CUDA device actions.
@@ -2679,12 +3038,16 @@ class OffloadingActionBuilder final {
std::string FileName = IA->getInputArg().getAsString(Args);
// Check if the type of the file is the same as the action. Do not
// unbundle it if it is not. Do not unbundle .so files, for example,
- // which are not object files.
+ // which are not object files. Files with extension ".lib" is classified
+ // as TY_Object but they are actually archives, therefore should not be
+ // unbundled here as objects. They will be handled at other places.
+ const StringRef LibFileExt = ".lib";
if (IA->getType() == types::TY_Object &&
(!llvm::sys::path::has_extension(FileName) ||
types::lookupTypeForExtension(
llvm::sys::path::extension(FileName).drop_front()) !=
- types::TY_Object))
+ types::TY_Object ||
+ llvm::sys::path::extension(FileName) == LibFileExt))
return ABRT_Inactive;
for (auto Arch : GpuArchList) {
@@ -2692,6 +3055,7 @@ class OffloadingActionBuilder final {
UA->registerDependentActionInfo(ToolChains[0], Arch,
AssociatedOffloadKind);
}
+ IsActive = true;
return ABRT_Success;
}
@@ -2734,7 +3098,7 @@ class OffloadingActionBuilder final {
/// option is invalid.
virtual StringRef getCanonicalOffloadArch(StringRef Arch) = 0;
- virtual llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ virtual std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(const std::set<StringRef> &GpuArchs) = 0;
bool initialize() override {
@@ -2751,9 +3115,6 @@ class OffloadingActionBuilder final {
!C.hasOffloadToolChain<Action::OFK_HIP>())
return false;
- Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
- options::OPT_fno_gpu_rdc, /*Default=*/false);
-
const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>();
assert(HostTC && "No toolchain for host compilation.");
if (HostTC->getTriple().isNVPTX() ||
@@ -2771,15 +3132,7 @@ class OffloadingActionBuilder final {
? C.getSingleOffloadToolChain<Action::OFK_Cuda>()
: C.getSingleOffloadToolChain<Action::OFK_HIP>());
- Arg *PartialCompilationArg = Args.getLastArg(
- options::OPT_cuda_host_only, options::OPT_cuda_device_only,
- options::OPT_cuda_compile_host_device);
- CompileHostOnly = PartialCompilationArg &&
- PartialCompilationArg->getOption().matches(
- options::OPT_cuda_host_only);
- CompileDeviceOnly = PartialCompilationArg &&
- PartialCompilationArg->getOption().matches(
- options::OPT_cuda_device_only);
+ CompileHostOnly = C.getDriver().offloadHostOnly();
EmitLLVM = Args.getLastArg(options::OPT_emit_llvm);
EmitAsm = Args.getLastArg(options::OPT_S);
FixedCUID = Args.getLastArgValue(options::OPT_cuid_EQ);
@@ -2806,7 +3159,7 @@ class OffloadingActionBuilder final {
<< "--offload";
}
- // Collect all cuda_gpu_arch parameters, removing duplicates.
+ // Collect all offload arch parameters, removing duplicates.
std::set<StringRef> GpuArchs;
bool Error = false;
for (Arg *A : Args) {
@@ -2815,28 +3168,41 @@ class OffloadingActionBuilder final {
continue;
A->claim();
- StringRef ArchStr = A->getValue();
- if (A->getOption().matches(options::OPT_no_offload_arch_EQ) &&
- ArchStr == "all") {
- GpuArchs.clear();
- continue;
+ for (StringRef ArchStr : llvm::split(A->getValue(), ",")) {
+ if (A->getOption().matches(options::OPT_no_offload_arch_EQ) &&
+ ArchStr == "all") {
+ GpuArchs.clear();
+ } else if (ArchStr == "native") {
+ const ToolChain &TC = *ToolChains.front();
+ auto GPUsOrErr = ToolChains.front()->getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ TC.getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(TC.getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch";
+ continue;
+ }
+
+ for (auto GPU : *GPUsOrErr) {
+ GpuArchs.insert(Args.MakeArgString(GPU));
+ }
+ } else {
+ ArchStr = getCanonicalOffloadArch(ArchStr);
+ if (ArchStr.empty()) {
+ Error = true;
+ } else if (A->getOption().matches(options::OPT_offload_arch_EQ))
+ GpuArchs.insert(ArchStr);
+ else if (A->getOption().matches(options::OPT_no_offload_arch_EQ))
+ GpuArchs.erase(ArchStr);
+ else
+ llvm_unreachable("Unexpected option.");
+ }
}
- ArchStr = getCanonicalOffloadArch(ArchStr);
- if (ArchStr.empty()) {
- Error = true;
- } else if (A->getOption().matches(options::OPT_offload_arch_EQ))
- GpuArchs.insert(ArchStr);
- else if (A->getOption().matches(options::OPT_no_offload_arch_EQ))
- GpuArchs.erase(ArchStr);
- else
- llvm_unreachable("Unexpected option.");
}
auto &&ConflictingArchs = getConflictOffloadArchCombination(GpuArchs);
if (ConflictingArchs) {
C.getDriver().Diag(clang::diag::err_drv_bad_offload_arch_combo)
- << ConflictingArchs.getValue().first
- << ConflictingArchs.getValue().second;
+ << ConflictingArchs->first << ConflictingArchs->second;
C.setContainsError();
return true;
}
@@ -2878,10 +3244,10 @@ class OffloadingActionBuilder final {
return CudaArchToString(Arch);
}
- llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(
const std::set<StringRef> &GpuArchs) override {
- return llvm::None;
+ return std::nullopt;
}
ActionBuilderReturnCode
@@ -2997,17 +3363,41 @@ class OffloadingActionBuilder final {
// Bundle code objects except --no-gpu-output is specified for device
// only compilation. Bundle other type of output files only if
// --gpu-bundle-output is specified for device only compilation.
- Optional<bool> BundleOutput;
+ std::optional<bool> BundleOutput;
+ std::optional<bool> EmitReloc;
public:
HIPActionBuilder(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs)
: CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {
- DefaultCudaArch = CudaArch::GFX803;
+
+ DefaultCudaArch = CudaArch::GFX906;
+
+ if (Args.hasArg(options::OPT_fhip_emit_relocatable,
+ options::OPT_fno_hip_emit_relocatable)) {
+ EmitReloc = Args.hasFlag(options::OPT_fhip_emit_relocatable,
+ options::OPT_fno_hip_emit_relocatable, false);
+
+ if (*EmitReloc) {
+ if (Relocatable) {
+ C.getDriver().Diag(diag::err_opt_not_valid_with_opt)
+ << "-fhip-emit-relocatable"
+ << "-fgpu-rdc";
+ }
+
+ if (!CompileDeviceOnly) {
+ C.getDriver().Diag(diag::err_opt_not_valid_without_opt)
+ << "-fhip-emit-relocatable"
+ << "--cuda-device-only";
+ }
+ }
+ }
+
if (Args.hasArg(options::OPT_gpu_bundle_output,
options::OPT_no_gpu_bundle_output))
BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output,
- options::OPT_no_gpu_bundle_output);
+ options::OPT_no_gpu_bundle_output, true) &&
+ (!EmitReloc || !*EmitReloc);
}
bool canUseBundlerUnbundler() const override { return true; }
@@ -3024,11 +3414,11 @@ class OffloadingActionBuilder final {
C.setContainsError();
return StringRef();
}
- auto CanId = getCanonicalTargetID(ArchStr.getValue(), Features);
+ auto CanId = getCanonicalTargetID(*ArchStr, Features);
return Args.MakeArgStringRef(CanId);
};
- llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(
const std::set<StringRef> &GpuArchs) override {
return getConflictTargetIDCombination(GpuArchs);
@@ -3038,9 +3428,12 @@ class OffloadingActionBuilder final {
getDeviceDependences(OffloadAction::DeviceDependences &DA,
phases::ID CurPhase, phases::ID FinalPhase,
PhasesTy &Phases) override {
+ if (!IsActive)
+ return ABRT_Inactive;
+
// amdgcn does not support linking of object files, therefore we skip
// backend and assemble phases to output LLVM IR. Except for generating
- // non-relocatable device coee, where we generate fat binary for device
+ // non-relocatable device code, where we generate fat binary for device
// code and pass to host in Backend phase.
if (CudaDeviceActions.empty())
return ABRT_Success;
@@ -3049,10 +3442,12 @@ class OffloadingActionBuilder final {
CudaDeviceActions.size() == GpuArchList.size()) &&
"Expecting one action per GPU architecture.");
assert(!CompileHostOnly &&
- "Not expecting CUDA actions in host-only compilation.");
+ "Not expecting HIP actions in host-only compilation.");
+
+ bool ShouldLink = !EmitReloc || !*EmitReloc;
if (!Relocatable && CurPhase == phases::Backend && !EmitLLVM &&
- !EmitAsm) {
+ !EmitAsm && ShouldLink) {
// If we are in backend phase, we attempt to generate the fat binary.
// We compile each arch to IR and use a link action to generate code
// object containing ISA. Then we use a special "link" action to create
@@ -3108,8 +3503,7 @@ class OffloadingActionBuilder final {
DDep, CudaDeviceActions[I]->getType());
}
- if (!CompileDeviceOnly || !BundleOutput.hasValue() ||
- BundleOutput.getValue()) {
+ if (!CompileDeviceOnly || !BundleOutput || *BundleOutput) {
// Create HIP fat binary with a special "link" action.
CudaFatBinary = C.MakeAction<LinkJobAction>(CudaDeviceActions,
types::TY_HIP_FATBIN);
@@ -3129,6 +3523,8 @@ class OffloadingActionBuilder final {
return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success;
} else if (CurPhase == phases::Link) {
+ if (!ShouldLink)
+ return ABRT_Success;
// Save CudaDeviceActions to DeviceLinkerInputs for each GPU subarch.
// This happens to each device action originated from each input file.
// Later on, device actions in DeviceLinkerInputs are used to create
@@ -3152,8 +3548,8 @@ class OffloadingActionBuilder final {
A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A,
AssociatedOffloadKind);
- if (CompileDeviceOnly && CurPhase == FinalPhase &&
- BundleOutput.hasValue() && BundleOutput.getValue()) {
+ if (CompileDeviceOnly && CurPhase == FinalPhase && BundleOutput &&
+ *BundleOutput) {
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
OffloadAction::DeviceDependences DDep;
DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I],
@@ -3166,8 +3562,11 @@ class OffloadingActionBuilder final {
CudaDeviceActions.clear();
}
- return (CompileDeviceOnly && CurPhase == FinalPhase) ? ABRT_Ignore_Host
- : ABRT_Success;
+ return (CompileDeviceOnly &&
+ (CurPhase == FinalPhase ||
+ (!ShouldLink && CurPhase == phases::Assemble)))
+ ? ABRT_Ignore_Host
+ : ABRT_Success;
}
void appendLinkDeviceActions(ActionList &AL) override {
@@ -3178,12 +3577,16 @@ class OffloadingActionBuilder final {
"Linker inputs and GPU arch list sizes do not match.");
ActionList Actions;
- // Append a new link action for each device.
unsigned I = 0;
+ // Append a new link action for each device.
+ // Each entry in DeviceLinkerInputs corresponds to a GPU arch.
for (auto &LI : DeviceLinkerInputs) {
- // Each entry in DeviceLinkerInputs corresponds to a GPU arch.
- auto *DeviceLinkAction =
- C.MakeAction<LinkJobAction>(LI, types::TY_Image);
+
+ types::ID Output = Args.hasArg(options::OPT_emit_llvm)
+ ? types::TY_LLVM_BC
+ : types::TY_Image;
+
+ auto *DeviceLinkAction = C.MakeAction<LinkJobAction>(LI, Output);
// Linking all inputs for the current GPU arch.
// LI contains all the inputs for the linker.
OffloadAction::DeviceDependences DeviceLinkDeps;
@@ -3195,12 +3598,17 @@ class OffloadingActionBuilder final {
}
DeviceLinkerInputs.clear();
+ // If emitting LLVM, do not generate final host/device compilation action
+ if (Args.hasArg(options::OPT_emit_llvm)) {
+ AL.append(Actions);
+ return;
+ }
+
// Create a host object from all the device images by embedding them
// in a fat binary for mixed host-device compilation. For device-only
// compilation, creates a fat binary.
OffloadAction::DeviceDependences DDeps;
- if (!CompileDeviceOnly || !BundleOutput.hasValue() ||
- BundleOutput.getValue()) {
+ if (!CompileDeviceOnly || !BundleOutput || *BundleOutput) {
auto *TopDeviceLinkAction = C.MakeAction<LinkJobAction>(
Actions,
CompileDeviceOnly ? types::TY_HIP_FATBIN : types::TY_Object);
@@ -3219,178 +3627,6 @@ class OffloadingActionBuilder final {
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {}
};
- /// OpenMP action builder. The host bitcode is passed to the device frontend
- /// and all the device linked images are passed to the host link phase.
- class OpenMPActionBuilder final : public DeviceActionBuilder {
- /// The OpenMP actions for the current input.
- ActionList OpenMPDeviceActions;
-
- /// The linker inputs obtained for each toolchain.
- SmallVector<ActionList, 8> DeviceLinkerInputs;
-
- public:
- OpenMPActionBuilder(Compilation &C, DerivedArgList &Args,
- const Driver::InputList &Inputs)
- : DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {}
-
- ActionBuilderReturnCode
- getDeviceDependences(OffloadAction::DeviceDependences &DA,
- phases::ID CurPhase, phases::ID FinalPhase,
- PhasesTy &Phases) override {
- if (OpenMPDeviceActions.empty())
- return ABRT_Inactive;
-
- // We should always have an action for each input.
- assert(OpenMPDeviceActions.size() == ToolChains.size() &&
- "Number of OpenMP actions and toolchains do not match.");
-
- // The host only depends on device action in the linking phase, when all
- // the device images have to be embedded in the host image.
- if (CurPhase == phases::Link) {
- assert(ToolChains.size() == DeviceLinkerInputs.size() &&
- "Toolchains and linker inputs sizes do not match.");
- auto LI = DeviceLinkerInputs.begin();
- for (auto *A : OpenMPDeviceActions) {
- LI->push_back(A);
- ++LI;
- }
-
- // We passed the device action as a host dependence, so we don't need to
- // do anything else with them.
- OpenMPDeviceActions.clear();
- return ABRT_Success;
- }
-
- // By default, we produce an action for each device arch.
- for (Action *&A : OpenMPDeviceActions)
- A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A);
-
- return ABRT_Success;
- }
-
- ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override {
-
- // If this is an input action replicate it for each OpenMP toolchain.
- if (auto *IA = dyn_cast<InputAction>(HostAction)) {
- OpenMPDeviceActions.clear();
- for (unsigned I = 0; I < ToolChains.size(); ++I)
- OpenMPDeviceActions.push_back(
- C.MakeAction<InputAction>(IA->getInputArg(), IA->getType()));
- return ABRT_Success;
- }
-
- // If this is an unbundling action use it as is for each OpenMP toolchain.
- if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) {
- OpenMPDeviceActions.clear();
- auto *IA = cast<InputAction>(UA->getInputs().back());
- std::string FileName = IA->getInputArg().getAsString(Args);
- // Check if the type of the file is the same as the action. Do not
- // unbundle it if it is not. Do not unbundle .so files, for example,
- // which are not object files.
- if (IA->getType() == types::TY_Object &&
- (!llvm::sys::path::has_extension(FileName) ||
- types::lookupTypeForExtension(
- llvm::sys::path::extension(FileName).drop_front()) !=
- types::TY_Object))
- return ABRT_Inactive;
- for (unsigned I = 0; I < ToolChains.size(); ++I) {
- OpenMPDeviceActions.push_back(UA);
- UA->registerDependentActionInfo(
- ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP);
- }
- return ABRT_Success;
- }
-
- // When generating code for OpenMP we use the host compile phase result as
- // a dependence to the device compile phase so that it can learn what
- // declarations should be emitted. However, this is not the only use for
- // the host action, so we prevent it from being collapsed.
- if (isa<CompileJobAction>(HostAction)) {
- HostAction->setCannotBeCollapsedWithNextDependentAction();
- assert(ToolChains.size() == OpenMPDeviceActions.size() &&
- "Toolchains and device action sizes do not match.");
- OffloadAction::HostDependence HDep(
- *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- auto TC = ToolChains.begin();
- for (Action *&A : OpenMPDeviceActions) {
- assert(isa<CompileJobAction>(A));
- OffloadAction::DeviceDependences DDep;
- DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- A = C.MakeAction<OffloadAction>(HDep, DDep);
- ++TC;
- }
- }
- return ABRT_Success;
- }
-
- void appendTopLevelActions(ActionList &AL) override {
- if (OpenMPDeviceActions.empty())
- return;
-
- // We should always have an action for each input.
- assert(OpenMPDeviceActions.size() == ToolChains.size() &&
- "Number of OpenMP actions and toolchains do not match.");
-
- // Append all device actions followed by the proper offload action.
- auto TI = ToolChains.begin();
- for (auto *A : OpenMPDeviceActions) {
- OffloadAction::DeviceDependences Dep;
- Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType()));
- ++TI;
- }
- // We no longer need the action stored in this builder.
- OpenMPDeviceActions.clear();
- }
-
- void appendLinkDeviceActions(ActionList &AL) override {
- assert(ToolChains.size() == DeviceLinkerInputs.size() &&
- "Toolchains and linker inputs sizes do not match.");
-
- // Append a new link action for each device.
- auto TC = ToolChains.begin();
- for (auto &LI : DeviceLinkerInputs) {
- auto *DeviceLinkAction =
- C.MakeAction<LinkJobAction>(LI, types::TY_Image);
- OffloadAction::DeviceDependences DeviceLinkDeps;
- DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr,
- Action::OFK_OpenMP);
- AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps,
- DeviceLinkAction->getType()));
- ++TC;
- }
- DeviceLinkerInputs.clear();
- }
-
- Action* appendLinkHostActions(ActionList &AL) override {
- // Create wrapper bitcode from the result of device link actions and compile
- // it to an object which will be added to the host link command.
- auto *BC = C.MakeAction<OffloadWrapperJobAction>(AL, types::TY_LLVM_BC);
- auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm);
- return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object);
- }
-
- void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {}
-
- bool initialize() override {
- // Get the OpenMP toolchains. If we don't get any, the action builder will
- // know there is nothing to do related to OpenMP offloading.
- auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
- for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE;
- ++TI)
- ToolChains.push_back(TI->second);
-
- DeviceLinkerInputs.resize(ToolChains.size());
- return false;
- }
-
- bool canUseBundlerUnbundler() const override {
- // OpenMP should use bundled files whenever possible.
- return true;
- }
- };
-
///
/// TODO: Add the implementation for other specialized builders here.
///
@@ -3415,9 +3651,6 @@ public:
// Create a specialized builder for HIP.
SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs));
- // Create a specialized builder for OpenMP.
- SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs));
-
//
// TODO: Build other specialized builders here.
//
@@ -3445,6 +3678,17 @@ public:
delete SB;
}
+ /// Record a host action and its originating input argument.
+ void recordHostAction(Action *HostAction, const Arg *InputArg) {
+ assert(HostAction && "Invalid host action");
+ assert(InputArg && "Invalid input argument");
+ auto Loc = HostActionToInputArgMap.find(HostAction);
+ if (Loc == HostActionToInputArgMap.end())
+ HostActionToInputArgMap[HostAction] = InputArg;
+ assert(HostActionToInputArgMap[HostAction] == InputArg &&
+ "host action mapped to multiple input arguments");
+ }
+
/// Generate an action that adds device dependences (if any) to a host action.
/// If no device dependence actions exist, just return the host action \a
/// HostAction. If an error is found or if no builder requires the host action
@@ -3460,6 +3704,7 @@ public:
return HostAction;
assert(HostAction && "Invalid host action!");
+ recordHostAction(HostAction, InputArg);
OffloadAction::DeviceDependences DDeps;
// Check if all the programming models agree we should not emit the host
@@ -3472,7 +3717,6 @@ public:
++InactiveBuilders;
continue;
}
-
auto RetCode =
SB->getDeviceDependences(DDeps, CurPhase, FinalPhase, Phases);
@@ -3513,6 +3757,8 @@ public:
if (!IsValid)
return true;
+ recordHostAction(HostAction, InputArg);
+
// If we are supporting bundling/unbundling and the current action is an
// input action of non-source file, we replace the host action by the
// unbundling action. The bundler tool has the logic to detect if an input
@@ -3529,6 +3775,7 @@ public:
C.getSingleOffloadToolChain<Action::OFK_Host>(),
/*BoundArch=*/StringRef(), Action::OFK_Host);
HostAction = UnbundlingHostAction;
+ recordHostAction(HostAction, InputArg);
}
assert(HostAction && "Invalid host action!");
@@ -3539,7 +3786,7 @@ public:
if (!SB->isValid())
continue;
- auto RetCode = SB->addDeviceDepences(HostAction);
+ auto RetCode = SB->addDeviceDependences(HostAction);
// Host dependences for device actions are not compatible with that same
// action being ignored.
@@ -3565,6 +3812,9 @@ public:
/// programming models allow it.
bool appendTopLevelActions(ActionList &AL, Action *HostAction,
const Arg *InputArg) {
+ if (HostAction)
+ recordHostAction(HostAction, InputArg);
+
// Get the device actions to be appended.
ActionList OffloadAL;
for (auto *SB : SpecializedBuilders) {
@@ -3586,6 +3836,7 @@ public:
// before this method was called.
assert(HostAction == AL.back() && "Host action not in the list??");
HostAction = C.MakeAction<OffloadBundlingJobAction>(OffloadAL);
+ recordHostAction(HostAction, InputArg);
AL.back() = HostAction;
} else
AL.append(OffloadAL.begin(), OffloadAL.end());
@@ -3619,6 +3870,11 @@ public:
if (!SB->isValid())
continue;
HA = SB->appendLinkHostActions(DeviceAL);
+ // This created host action has no originating input argument, therefore
+ // needs to set its offloading kind directly.
+ if (HA)
+ HA->propagateHostOffloadInfo(SB->getAssociatedOffloadKind(),
+ /*BoundArch=*/nullptr);
}
return HA;
}
@@ -3645,10 +3901,22 @@ public:
// If we don't have device dependencies, we don't have to create an offload
// action.
if (DDeps.getActions().empty()) {
- // Propagate all the active kinds to host action. Given that it is a link
- // action it is assumed to depend on all actions generated so far.
- HostAction->propagateHostOffloadInfo(ActiveOffloadKinds,
- /*BoundArch=*/nullptr);
+ // Set all the active offloading kinds to the link action. Given that it
+ // is a link action it is assumed to depend on all actions generated so
+ // far.
+ HostAction->setHostOffloadInfo(ActiveOffloadKinds,
+ /*BoundArch=*/nullptr);
+ // Propagate active offloading kinds for each input to the link action.
+ // Each input may have different active offloading kind.
+ for (auto *A : HostAction->inputs()) {
+ auto ArgLoc = HostActionToInputArgMap.find(A);
+ if (ArgLoc == HostActionToInputArgMap.end())
+ continue;
+ auto OFKLoc = InputArgToOffloadKindMap.find(ArgLoc->second);
+ if (OFKLoc == InputArgToOffloadKindMap.end())
+ continue;
+ A->propagateHostOffloadInfo(OFKLoc->second, /*BoundArch=*/nullptr);
+ }
return HostAction;
}
@@ -3686,12 +3954,34 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
if (FinalPhase == phases::Link) {
- if (Args.hasArg(options::OPT_emit_llvm))
+ if (Args.hasArgNoClaim(options::OPT_hipstdpar)) {
+ Args.AddFlagArg(nullptr, getOpts().getOption(options::OPT_hip_link));
+ Args.AddFlagArg(nullptr,
+ getOpts().getOption(options::OPT_frtlib_add_rpath));
+ }
+ // Emitting LLVM while linking disabled except in HIPAMD Toolchain
+ if (Args.hasArg(options::OPT_emit_llvm) && !Args.hasArg(options::OPT_hip_link))
Diag(clang::diag::err_drv_emit_llvm_link);
if (IsCLMode() && LTOMode != LTOK_None &&
!Args.getLastArgValue(options::OPT_fuse_ld_EQ)
.equals_insensitive("lld"))
Diag(clang::diag::err_drv_lto_without_lld);
+
+ // If -dumpdir is not specified, give a default prefix derived from the link
+ // output filename. For example, `clang -g -gsplit-dwarf a.c -o x` passes
+ // `-dumpdir x-` to cc1. If -o is unspecified, use
+ // stem(getDefaultImageName()) (usually stem("a.out") = "a").
+ if (!Args.hasArg(options::OPT_dumpdir)) {
+ Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o);
+ Arg *Arg = Args.MakeSeparateArg(
+ nullptr, getOpts().getOption(options::OPT_dumpdir),
+ Args.MakeArgString(
+ (FinalOutput ? FinalOutput->getValue()
+ : llvm::sys::path::stem(getDefaultImageName())) +
+ "-"));
+ Arg->claim();
+ Args.append(Arg);
+ }
}
if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) {
@@ -3787,11 +4077,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
return;
}
- // Reject -Z* at the top level, these options should never have been exposed
- // by gcc.
- if (Arg *A = Args.getLastArg(options::OPT_Z_Joined))
- Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args);
-
// Diagnose misuse of /Fo.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) {
StringRef V = A->getValue();
@@ -3827,16 +4112,19 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
handleArguments(C, Args, Inputs, Actions);
- // Builder to be used to build offloading actions.
- OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);
+ bool UseNewOffloadingDriver =
+ C.isOffloadingHostKind(Action::OFK_OpenMP) ||
+ Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false);
- // Offload kinds active for this compilation.
- unsigned OffloadKinds = Action::OFK_None;
- if (C.hasOffloadToolChain<Action::OFK_OpenMP>())
- OffloadKinds |= Action::OFK_OpenMP;
+ // Builder to be used to build offloading actions.
+ std::unique_ptr<OffloadingActionBuilder> OffloadBuilder =
+ !UseNewOffloadingDriver
+ ? std::make_unique<OffloadingActionBuilder>(C, Args, Inputs)
+ : nullptr;
// Construct the actions to perform.
- HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
+ ExtractAPIJobAction *ExtractAPIAction = nullptr;
ActionList LinkerInputs;
ActionList MergerInputs;
@@ -3855,15 +4143,15 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Use the current host action in any of the offloading actions, if
// required.
- if (!Args.hasArg(options::OPT_fopenmp_new_driver))
- if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
+ if (!UseNewOffloadingDriver)
+ if (OffloadBuilder->addHostDependenceToDeviceActions(Current, InputArg))
break;
for (phases::ID Phase : PL) {
// Add any offload action the host action depends on.
- if (!Args.hasArg(options::OPT_fopenmp_new_driver))
- Current = OffloadBuilder.addDeviceDependencesToHostAction(
+ if (!UseNewOffloadingDriver)
+ Current = OffloadBuilder->addDeviceDependencesToHostAction(
Current, InputArg, Phase, PL.back(), FullPL);
if (!Current)
break;
@@ -3871,7 +4159,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Queue linker inputs.
if (Phase == phases::Link) {
assert(Phase == PL.back() && "linking must be final compilation step.");
- LinkerInputs.push_back(Current);
+ // We don't need to generate additional link commands if emitting AMD
+ // bitcode or compiling only for the offload device
+ if (!(C.getInputArgs().hasArg(options::OPT_hip_link) &&
+ (C.getInputArgs().hasArg(options::OPT_emit_llvm))) &&
+ !offloadDeviceOnly())
+ LinkerInputs.push_back(Current);
Current = nullptr;
break;
}
@@ -3887,21 +4180,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
break;
}
- // Each precompiled header file after a module file action is a module
- // header of that same module file, rather than being compiled to a
- // separate PCH.
- if (Phase == phases::Precompile && HeaderModuleAction &&
- getPrecompiledType(InputType) == types::TY_PCH) {
- HeaderModuleAction->addModuleHeaderInput(Current);
+ if (Phase == phases::Precompile && ExtractAPIAction) {
+ ExtractAPIAction->addHeaderInput(Current);
Current = nullptr;
break;
}
- // Try to build the offloading actions and add the result as a dependency
- // to the host.
- if (Args.hasArg(options::OPT_fopenmp_new_driver))
- Current = BuildOffloadingActions(C, Args, I, Current);
-
// FIXME: Should we include any prior module file outputs as inputs of
// later actions in the same command line?
@@ -3912,16 +4196,20 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (NewCurrent == Current)
continue;
- if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent))
- HeaderModuleAction = HMA;
+ if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent))
+ ExtractAPIAction = EAA;
Current = NewCurrent;
+ // Try to build the offloading actions and add the result as a dependency
+ // to the host.
+ if (UseNewOffloadingDriver)
+ Current = BuildOffloadingActions(C, Args, I, Current);
// Use the current host action in any of the offloading actions, if
// required.
- if (!Args.hasArg(options::OPT_fopenmp_new_driver))
- if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
- break;
+ else if (OffloadBuilder->addHostDependenceToDeviceActions(Current,
+ InputArg))
+ break;
if (Current->getType() == types::TY_Nothing)
break;
@@ -3932,10 +4220,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Actions.push_back(Current);
// Add any top level actions generated for offloading.
- if (!Args.hasArg(options::OPT_fopenmp_new_driver))
- OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg);
+ if (!UseNewOffloadingDriver)
+ OffloadBuilder->appendTopLevelActions(Actions, Current, InputArg);
else if (Current)
- Current->propagateHostOffloadInfo(OffloadKinds,
+ Current->propagateHostOffloadInfo(C.getActiveOffloadKinds(),
/*BoundArch=*/nullptr);
}
@@ -3944,27 +4232,28 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (LinkerInputs.empty()) {
Arg *FinalPhaseArg;
if (getFinalPhase(Args, &FinalPhaseArg) == phases::Link)
- OffloadBuilder.appendDeviceLinkActions(Actions);
+ if (!UseNewOffloadingDriver)
+ OffloadBuilder->appendDeviceLinkActions(Actions);
}
if (!LinkerInputs.empty()) {
- if (!Args.hasArg(options::OPT_fopenmp_new_driver))
- if (Action *Wrapper = OffloadBuilder.makeHostLinkAction())
+ if (!UseNewOffloadingDriver)
+ if (Action *Wrapper = OffloadBuilder->makeHostLinkAction())
LinkerInputs.push_back(Wrapper);
Action *LA;
// Check if this Linker Job should emit a static library.
if (ShouldEmitStaticLibrary(Args)) {
LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image);
- } else if (Args.hasArg(options::OPT_fopenmp_new_driver) &&
- OffloadKinds != Action::OFK_None) {
+ } else if (UseNewOffloadingDriver ||
+ Args.hasArg(options::OPT_offload_link)) {
LA = C.MakeAction<LinkerWrapperJobAction>(LinkerInputs, types::TY_Image);
- LA->propagateHostOffloadInfo(OffloadKinds,
+ LA->propagateHostOffloadInfo(C.getActiveOffloadKinds(),
/*BoundArch=*/nullptr);
} else {
LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
}
- if (!Args.hasArg(options::OPT_fopenmp_new_driver))
- LA = OffloadBuilder.processHostLinkAction(LA);
+ if (!UseNewOffloadingDriver)
+ LA = OffloadBuilder->processHostLinkAction(LA);
Actions.push_back(LA);
}
@@ -4029,87 +4318,358 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
}
- // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom
- // Compile phase that prints out supported cpu models and quits.
- if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) {
- // Use the -mcpu=? flag as the dummy input to cc1.
- Actions.clear();
- Action *InputAc = C.MakeAction<InputAction>(*A, types::TY_C);
- Actions.push_back(
- C.MakeAction<PrecompileJobAction>(InputAc, types::TY_Nothing));
- for (auto &I : Inputs)
- I.second->claim();
+ for (auto Opt : {options::OPT_print_supported_cpus,
+ options::OPT_print_supported_extensions}) {
+ // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a
+ // custom Compile phase that prints out supported cpu models and quits.
+ //
+ // If --print-supported-extensions is specified, call the helper function
+ // RISCVMarchHelp in RISCVISAInfo.cpp that prints out supported extensions
+ // and quits.
+ if (Arg *A = Args.getLastArg(Opt)) {
+ if (Opt == options::OPT_print_supported_extensions &&
+ !C.getDefaultToolChain().getTriple().isRISCV() &&
+ !C.getDefaultToolChain().getTriple().isAArch64() &&
+ !C.getDefaultToolChain().getTriple().isARM()) {
+ C.getDriver().Diag(diag::err_opt_not_valid_on_target)
+ << "--print-supported-extensions";
+ return;
+ }
+
+ // Use the -mcpu=? flag as the dummy input to cc1.
+ Actions.clear();
+ Action *InputAc = C.MakeAction<InputAction>(*A, types::TY_C);
+ Actions.push_back(
+ C.MakeAction<PrecompileJobAction>(InputAc, types::TY_Nothing));
+ for (auto &I : Inputs)
+ I.second->claim();
+ }
+ }
+
+ // Call validator for dxil when -Vd not in Args.
+ if (C.getDefaultToolChain().getTriple().isDXIL()) {
+ // Only add action when needValidation.
+ const auto &TC =
+ static_cast<const toolchains::HLSLToolChain &>(C.getDefaultToolChain());
+ if (TC.requiresValidation(Args)) {
+ Action *LastAction = Actions.back();
+ Actions.push_back(C.MakeAction<BinaryAnalyzeJobAction>(
+ LastAction, types::TY_DX_CONTAINER));
+ }
}
// Claim ignored clang-cl options.
Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
+}
+
+/// Returns the canonical name for the offloading architecture when using a HIP
+/// or CUDA architecture.
+static StringRef getCanonicalArchString(Compilation &C,
+ const llvm::opt::DerivedArgList &Args,
+ StringRef ArchStr,
+ const llvm::Triple &Triple,
+ bool SuppressError = false) {
+ // Lookup the CUDA / HIP architecture string. Only report an error if we were
+ // expecting the triple to be only NVPTX / AMDGPU.
+ CudaArch Arch = StringToCudaArch(getProcessorFromTargetID(Triple, ArchStr));
+ if (!SuppressError && Triple.isNVPTX() &&
+ (Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch))) {
+ C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
+ << "CUDA" << ArchStr;
+ return StringRef();
+ } else if (!SuppressError && Triple.isAMDGPU() &&
+ (Arch == CudaArch::UNKNOWN || !IsAMDGpuArch(Arch))) {
+ C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
+ << "HIP" << ArchStr;
+ return StringRef();
+ }
+
+ if (IsNVIDIAGpuArch(Arch))
+ return Args.MakeArgStringRef(CudaArchToString(Arch));
+
+ if (IsAMDGpuArch(Arch)) {
+ llvm::StringMap<bool> Features;
+ auto HIPTriple = getHIPOffloadTargetTriple(C.getDriver(), C.getInputArgs());
+ if (!HIPTriple)
+ return StringRef();
+ auto Arch = parseTargetID(*HIPTriple, ArchStr, &Features);
+ if (!Arch) {
+ C.getDriver().Diag(clang::diag::err_drv_bad_target_id) << ArchStr;
+ C.setContainsError();
+ return StringRef();
+ }
+ return Args.MakeArgStringRef(getCanonicalTargetID(*Arch, Features));
+ }
+
+ // If the input isn't CUDA or HIP just return the architecture.
+ return ArchStr;
+}
+
+/// Checks if the set offloading architectures does not conflict. Returns the
+/// incompatible pair if a conflict occurs.
+static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
+getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs,
+ llvm::Triple Triple) {
+ if (!Triple.isAMDGPU())
+ return std::nullopt;
+
+ std::set<StringRef> ArchSet;
+ llvm::copy(Archs, std::inserter(ArchSet, ArchSet.begin()));
+ return getConflictTargetIDCombination(ArchSet);
+}
+
+llvm::DenseSet<StringRef>
+Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
+ Action::OffloadKind Kind, const ToolChain *TC,
+ bool SuppressError) const {
+ if (!TC)
+ TC = &C.getDefaultToolChain();
+
+ // --offload and --offload-arch options are mutually exclusive.
+ if (Args.hasArgNoClaim(options::OPT_offload_EQ) &&
+ Args.hasArgNoClaim(options::OPT_offload_arch_EQ,
+ options::OPT_no_offload_arch_EQ)) {
+ C.getDriver().Diag(diag::err_opt_not_valid_with_opt)
+ << "--offload"
+ << (Args.hasArgNoClaim(options::OPT_offload_arch_EQ)
+ ? "--offload-arch"
+ : "--no-offload-arch");
+ }
+
+ if (KnownArchs.contains(TC))
+ return KnownArchs.lookup(TC);
+
+ llvm::DenseSet<StringRef> Archs;
+ for (auto *Arg : Args) {
+ // Extract any '--[no-]offload-arch' arguments intended for this toolchain.
+ std::unique_ptr<llvm::opt::Arg> ExtractedArg = nullptr;
+ if (Arg->getOption().matches(options::OPT_Xopenmp_target_EQ) &&
+ ToolChain::getOpenMPTriple(Arg->getValue(0)) == TC->getTriple()) {
+ Arg->claim();
+ unsigned Index = Args.getBaseArgs().MakeIndex(Arg->getValue(1));
+ ExtractedArg = getOpts().ParseOneArg(Args, Index);
+ Arg = ExtractedArg.get();
+ }
+
+ // Add or remove the seen architectures in order of appearance. If an
+ // invalid architecture is given we simply exit.
+ if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) {
+ for (StringRef Arch : llvm::split(Arg->getValue(), ",")) {
+ if (Arch == "native" || Arch.empty()) {
+ auto GPUsOrErr = TC->getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ if (SuppressError)
+ llvm::consumeError(GPUsOrErr.takeError());
+ else
+ TC->getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(TC->getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch";
+ continue;
+ }
+
+ for (auto ArchStr : *GPUsOrErr) {
+ Archs.insert(
+ getCanonicalArchString(C, Args, Args.MakeArgString(ArchStr),
+ TC->getTriple(), SuppressError));
+ }
+ } else {
+ StringRef ArchStr = getCanonicalArchString(
+ C, Args, Arch, TC->getTriple(), SuppressError);
+ if (ArchStr.empty())
+ return Archs;
+ Archs.insert(ArchStr);
+ }
+ }
+ } else if (Arg->getOption().matches(options::OPT_no_offload_arch_EQ)) {
+ for (StringRef Arch : llvm::split(Arg->getValue(), ",")) {
+ if (Arch == "all") {
+ Archs.clear();
+ } else {
+ StringRef ArchStr = getCanonicalArchString(
+ C, Args, Arch, TC->getTriple(), SuppressError);
+ if (ArchStr.empty())
+ return Archs;
+ Archs.erase(ArchStr);
+ }
+ }
+ }
+ }
+
+ if (auto ConflictingArchs =
+ getConflictOffloadArchCombination(Archs, TC->getTriple())) {
+ C.getDriver().Diag(clang::diag::err_drv_bad_offload_arch_combo)
+ << ConflictingArchs->first << ConflictingArchs->second;
+ C.setContainsError();
+ }
+
+ // Skip filling defaults if we're just querying what is availible.
+ if (SuppressError)
+ return Archs;
+
+ if (Archs.empty()) {
+ if (Kind == Action::OFK_Cuda)
+ Archs.insert(CudaArchToString(CudaArch::CudaDefault));
+ else if (Kind == Action::OFK_HIP)
+ Archs.insert(CudaArchToString(CudaArch::HIPDefault));
+ else if (Kind == Action::OFK_OpenMP)
+ Archs.insert(StringRef());
+ } else {
+ Args.ClaimAllArgs(options::OPT_offload_arch_EQ);
+ Args.ClaimAllArgs(options::OPT_no_offload_arch_EQ);
+ }
- // Claim --cuda-host-only and --cuda-compile-host-device, which may be passed
- // to non-CUDA compilations and should not trigger warnings there.
- Args.ClaimAllArgs(options::OPT_cuda_host_only);
- Args.ClaimAllArgs(options::OPT_cuda_compile_host_device);
+ return Archs;
}
Action *Driver::BuildOffloadingActions(Compilation &C,
llvm::opt::DerivedArgList &Args,
const InputTy &Input,
Action *HostAction) const {
- if (!isa<CompileJobAction>(HostAction))
+ // Don't build offloading actions if explicitly disabled or we do not have a
+ // valid source input and compile action to embed it in. If preprocessing only
+ // ignore embedding.
+ if (offloadHostOnly() || !types::isSrcFile(Input.first) ||
+ !(isa<CompileJobAction>(HostAction) ||
+ getFinalPhase(Args) == phases::Preprocess))
return HostAction;
- SmallVector<const ToolChain *, 2> ToolChains;
- ActionList DeviceActions;
+ ActionList OffloadActions;
+ OffloadAction::DeviceDependences DDeps;
- types::ID InputType = Input.first;
- const Arg *InputArg = Input.second;
+ const Action::OffloadKind OffloadKinds[] = {
+ Action::OFK_OpenMP, Action::OFK_Cuda, Action::OFK_HIP};
- auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
- for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE; ++TI)
- ToolChains.push_back(TI->second);
+ for (Action::OffloadKind Kind : OffloadKinds) {
+ SmallVector<const ToolChain *, 2> ToolChains;
+ ActionList DeviceActions;
- for (unsigned I = 0; I < ToolChains.size(); ++I)
- DeviceActions.push_back(C.MakeAction<InputAction>(*InputArg, InputType));
+ auto TCRange = C.getOffloadToolChains(Kind);
+ for (auto TI = TCRange.first, TE = TCRange.second; TI != TE; ++TI)
+ ToolChains.push_back(TI->second);
- if (DeviceActions.empty())
- return HostAction;
+ if (ToolChains.empty())
+ continue;
- auto PL = types::getCompilationPhases(*this, Args, InputType);
+ types::ID InputType = Input.first;
+ const Arg *InputArg = Input.second;
- for (phases::ID Phase : PL) {
- if (Phase == phases::Link) {
- assert(Phase == PL.back() && "linking must be final compilation step.");
- break;
+ // The toolchain can be active for unsupported file types.
+ if ((Kind == Action::OFK_Cuda && !types::isCuda(InputType)) ||
+ (Kind == Action::OFK_HIP && !types::isHIP(InputType)))
+ continue;
+
+ // Get the product of all bound architectures and toolchains.
+ SmallVector<std::pair<const ToolChain *, StringRef>> TCAndArchs;
+ for (const ToolChain *TC : ToolChains)
+ for (StringRef Arch : getOffloadArchs(C, Args, Kind, TC))
+ TCAndArchs.push_back(std::make_pair(TC, Arch));
+
+ for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I)
+ DeviceActions.push_back(C.MakeAction<InputAction>(*InputArg, InputType));
+
+ if (DeviceActions.empty())
+ return HostAction;
+
+ auto PL = types::getCompilationPhases(*this, Args, InputType);
+
+ for (phases::ID Phase : PL) {
+ if (Phase == phases::Link) {
+ assert(Phase == PL.back() && "linking must be final compilation step.");
+ break;
+ }
+
+ auto TCAndArch = TCAndArchs.begin();
+ for (Action *&A : DeviceActions) {
+ if (A->getType() == types::TY_Nothing)
+ continue;
+
+ // Propagate the ToolChain so we can use it in ConstructPhaseAction.
+ A->propagateDeviceOffloadInfo(Kind, TCAndArch->second.data(),
+ TCAndArch->first);
+ A = ConstructPhaseAction(C, Args, Phase, A, Kind);
+
+ if (isa<CompileJobAction>(A) && isa<CompileJobAction>(HostAction) &&
+ Kind == Action::OFK_OpenMP &&
+ HostAction->getType() != types::TY_Nothing) {
+ // OpenMP offloading has a dependency on the host compile action to
+ // identify which declarations need to be emitted. This shouldn't be
+ // collapsed with any other actions so we can use it in the device.
+ HostAction->setCannotBeCollapsedWithNextDependentAction();
+ OffloadAction::HostDependence HDep(
+ *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
+ TCAndArch->second.data(), Kind);
+ OffloadAction::DeviceDependences DDep;
+ DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);
+ A = C.MakeAction<OffloadAction>(HDep, DDep);
+ }
+
+ ++TCAndArch;
+ }
}
- auto TC = ToolChains.begin();
+ // Compiling HIP in non-RDC mode requires linking each action individually.
for (Action *&A : DeviceActions) {
- A = ConstructPhaseAction(C, Args, Phase, A, Action::OFK_OpenMP);
-
- if (isa<CompileJobAction>(A)) {
- HostAction->setCannotBeCollapsedWithNextDependentAction();
- OffloadAction::HostDependence HDep(
- *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BourdArch=*/nullptr, Action::OFK_OpenMP);
- OffloadAction::DeviceDependences DDep;
- DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- A = C.MakeAction<OffloadAction>(HDep, DDep);
- }
- ++TC;
+ if ((A->getType() != types::TY_Object &&
+ A->getType() != types::TY_LTO_BC) ||
+ Kind != Action::OFK_HIP ||
+ Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
+ continue;
+ ActionList LinkerInput = {A};
+ A = C.MakeAction<LinkJobAction>(LinkerInput, types::TY_Image);
+ }
+
+ auto TCAndArch = TCAndArchs.begin();
+ for (Action *A : DeviceActions) {
+ DDeps.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);
+ OffloadAction::DeviceDependences DDep;
+ DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);
+ OffloadActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType()));
+ ++TCAndArch;
}
}
- OffloadAction::DeviceDependences DDeps;
+ if (offloadDeviceOnly())
+ return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing);
- auto TC = ToolChains.begin();
- for (Action *A : DeviceActions) {
- DDeps.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- TC++;
- }
+ if (OffloadActions.empty())
+ return HostAction;
+ OffloadAction::DeviceDependences DDep;
+ if (C.isOffloadingHostKind(Action::OFK_Cuda) &&
+ !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) {
+ // If we are not in RDC-mode we just emit the final CUDA fatbinary for
+ // each translation unit without requiring any linking.
+ Action *FatbinAction =
+ C.MakeAction<LinkJobAction>(OffloadActions, types::TY_CUDA_FATBIN);
+ DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_Cuda>(),
+ nullptr, Action::OFK_Cuda);
+ } else if (C.isOffloadingHostKind(Action::OFK_HIP) &&
+ !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false)) {
+ // If we are not in RDC-mode we just emit the final HIP fatbinary for each
+ // translation unit, linking each input individually.
+ Action *FatbinAction =
+ C.MakeAction<LinkJobAction>(OffloadActions, types::TY_HIP_FATBIN);
+ DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_HIP>(),
+ nullptr, Action::OFK_HIP);
+ } else {
+ // Package all the offloading actions into a single output that can be
+ // embedded in the host and linked.
+ Action *PackagerAction =
+ C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
+ DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
+ nullptr, C.getActiveOffloadKinds());
+ }
+
+ // If we are unable to embed a single device output into the host, we need to
+ // add each device output as a host dependency to ensure they are still built.
+ bool SingleDeviceOutput = !llvm::any_of(OffloadActions, [](Action *A) {
+ return A->getType() == types::TY_Nothing;
+ }) && isa<CompileJobAction>(HostAction);
OffloadAction::HostDependence HDep(
*HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BoundArch=*/nullptr, DDeps);
- return C.MakeAction<OffloadAction>(HDep, DDeps);
+ /*BoundArch=*/nullptr, SingleDeviceOutput ? DDep : DDeps);
+ return C.MakeAction<OffloadAction>(HDep, SingleDeviceOutput ? DDep : DDeps);
}
Action *Driver::ConstructPhaseAction(
@@ -4138,10 +4698,14 @@ Action *Driver::ConstructPhaseAction(
OutputTy = types::TY_Dependencies;
} else {
OutputTy = Input->getType();
+ // For these cases, the preprocessor is only translating forms, the Output
+ // still needs preprocessing.
if (!Args.hasFlag(options::OPT_frewrite_includes,
options::OPT_fno_rewrite_includes, false) &&
!Args.hasFlag(options::OPT_frewrite_imports,
options::OPT_fno_rewrite_imports, false) &&
+ !Args.hasFlag(options::OPT_fdirectives_only,
+ options::OPT_fno_directives_only, false) &&
!CCGenDiagnostics)
OutputTy = types::getPreprocessedType(OutputTy);
assert(OutputTy != types::TY_INVALID &&
@@ -4150,6 +4714,10 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<PreprocessJobAction>(Input, OutputTy);
}
case phases::Precompile: {
+ // API extraction should not generate an actual precompilation action.
+ if (Args.hasArg(options::OPT_extract_api))
+ return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
+
types::ID OutputTy = getPrecompiledType(Input->getType());
assert(OutputTy != types::TY_INVALID &&
"Cannot precompile this input type!");
@@ -4164,15 +4732,11 @@ Action *Driver::ConstructPhaseAction(
OutputTy = types::TY_ModuleFile;
}
- if (Args.hasArg(options::OPT_fsyntax_only) ||
- Args.hasArg(options::OPT_extract_api)) {
+ if (Args.hasArg(options::OPT_fsyntax_only)) {
// Syntax checks should not emit a PCH file
OutputTy = types::TY_Nothing;
}
- if (ModName)
- return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy,
- ModName);
return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
}
case phases::Compile: {
@@ -4194,27 +4758,43 @@ Action *Driver::ConstructPhaseAction(
if (Args.hasArg(options::OPT_verify_pch))
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
if (Args.hasArg(options::OPT_extract_api))
- return C.MakeAction<CompileJobAction>(Input, types::TY_API_INFO);
+ return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) {
- types::ID Output =
- Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
+ types::ID Output;
+ if (Args.hasArg(options::OPT_ffat_lto_objects) &&
+ !Args.hasArg(options::OPT_emit_llvm))
+ Output = types::TY_PP_Asm;
+ else if (Args.hasArg(options::OPT_S))
+ Output = types::TY_LTO_IR;
+ else
+ Output = types::TY_LTO_BC;
return C.MakeAction<BackendJobAction>(Input, Output);
}
if (isUsingLTO(/* IsOffload */ true) &&
- TargetDeviceOffloadKind == Action::OFK_OpenMP) {
+ TargetDeviceOffloadKind != Action::OFK_None) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
return C.MakeAction<BackendJobAction>(Input, Output);
}
if (Args.hasArg(options::OPT_emit_llvm) ||
- (TargetDeviceOffloadKind == Action::OFK_HIP &&
- Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
- false))) {
+ (((Input->getOffloadingToolChain() &&
+ Input->getOffloadingToolChain()->getTriple().isAMDGPU()) ||
+ TargetDeviceOffloadKind == Action::OFK_HIP) &&
+ (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false) ||
+ TargetDeviceOffloadKind == Action::OFK_OpenMP))) {
types::ID Output =
- Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
+ Args.hasArg(options::OPT_S) &&
+ (TargetDeviceOffloadKind == Action::OFK_None ||
+ offloadDeviceOnly() ||
+ (TargetDeviceOffloadKind == Action::OFK_HIP &&
+ !Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false)))
+ ? types::TY_LLVM_IR
+ : types::TY_LLVM_BC;
return C.MakeAction<BackendJobAction>(Input, Output);
}
return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
@@ -4244,11 +4824,16 @@ void Driver::BuildJobs(Compilation &C) const {
// we are also generating .o files. So we allow more than one output file in
// this case as well.
//
+ // OffloadClass of type TY_Nothing: device-only output will place many outputs
+ // into a single offloading action. We should count all inputs to the action
+ // as outputs. Also ignore device-only outputs if we're compiling with
+ // -fsyntax-only.
if (FinalOutput) {
unsigned NumOutputs = 0;
unsigned NumIfsOutputs = 0;
- for (const Action *A : C.getActions())
+ for (const Action *A : C.getActions()) {
if (A->getType() != types::TY_Nothing &&
+ A->getType() != types::TY_DX_CONTAINER &&
!(A->getKind() == Action::IfsMergeJobClass ||
(A->getType() == clang::driver::types::TY_IFS_CPP &&
A->getKind() == clang::driver::Action::CompileJobClass &&
@@ -4256,6 +4841,11 @@ void Driver::BuildJobs(Compilation &C) const {
(A->getKind() == Action::BindArchClass && A->getInputs().size() &&
A->getInputs().front()->getKind() == Action::IfsMergeJobClass)))
++NumOutputs;
+ else if (A->getKind() == Action::OffloadClass &&
+ A->getType() == types::TY_Nothing &&
+ !C.getArgs().hasArg(options::OPT_fsyntax_only))
+ NumOutputs += A->size();
+ }
if (NumOutputs > 1) {
Diag(clang::diag::err_drv_output_argument_with_multiple_files);
@@ -4264,13 +4854,6 @@ void Driver::BuildJobs(Compilation &C) const {
}
const llvm::Triple &RawTriple = C.getDefaultToolChain().getTriple();
- if (RawTriple.isOSAIX()) {
- if (Arg *A = C.getArgs().getLastArg(options::OPT_G))
- Diag(diag::err_drv_unsupported_opt_for_target)
- << A->getSpelling() << RawTriple.str();
- if (LTOMode == LTOK_Thin)
- Diag(diag::err_drv_clang_unsupported) << "thinLTO on AIX";
- }
// Collect the list of architectures.
llvm::StringSet<> ArchNames;
@@ -4312,7 +4895,7 @@ void Driver::BuildJobs(Compilation &C) const {
if (CCPrintProcessStats) {
C.setPostCallback([=](const Command &Cmd, int Res) {
- Optional<llvm::sys::ProcessStatistics> ProcStat =
+ std::optional<llvm::sys::ProcessStatistics> ProcStat =
Cmd.getProcessStatistics();
if (!ProcStat)
return;
@@ -4372,6 +4955,8 @@ void Driver::BuildJobs(Compilation &C) const {
C.getArgs().hasArg(options::OPT_Qunused_arguments))
return;
+ // Claim -fdriver-only here.
+ (void)C.getArgs().hasArg(options::OPT_fdriver_only);
// Claim -### here.
(void)C.getArgs().hasArg(options::OPT__HASH_HASH_HASH);
@@ -4379,6 +4964,12 @@ void Driver::BuildJobs(Compilation &C) const {
(void)C.getArgs().hasArg(options::OPT_driver_mode);
(void)C.getArgs().hasArg(options::OPT_rsp_quoting);
+ bool HasAssembleJob = llvm::any_of(C.getJobs(), [](auto &J) {
+ // Match ClangAs and other derived assemblers of Tool. ClangAs uses a
+ // longer ShortName "clang integrated assembler" while other assemblers just
+ // use "assembler".
+ return strstr(J.getCreator().getShortName(), "assembler");
+ });
for (Arg *A : C.getArgs()) {
// FIXME: It would be nice to be able to send the argument to the
// DiagnosticsEngine, so that extra values, position, and so on could be
@@ -4406,9 +4997,21 @@ void Driver::BuildJobs(Compilation &C) const {
// In clang-cl, don't mention unknown arguments here since they have
// already been warned about.
- if (!IsCLMode() || !A->getOption().matches(options::OPT_UNKNOWN))
- Diag(clang::diag::warn_drv_unused_argument)
- << A->getAsString(C.getArgs());
+ if (!IsCLMode() || !A->getOption().matches(options::OPT_UNKNOWN)) {
+ if (A->getOption().hasFlag(options::TargetSpecific) &&
+ !A->isIgnoredTargetSpecific() && !HasAssembleJob &&
+ // When for example -### or -v is used
+ // without a file, target specific options are not
+ // consumed/validated.
+ // Instead emitting an error emit a warning instead.
+ !C.getActions().empty()) {
+ Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << getTargetTriple();
+ } else {
+ Diag(clang::diag::warn_drv_unused_argument)
+ << A->getAsString(C.getArgs());
+ }
+ }
}
}
}
@@ -4483,7 +5086,8 @@ class ToolSelector final {
return TC.useIntegratedAs() && !SaveTemps &&
!C.getArgs().hasArg(options::OPT_via_file_asm) &&
!C.getArgs().hasArg(options::OPT__SLASH_FA) &&
- !C.getArgs().hasArg(options::OPT__SLASH_Fa);
+ !C.getArgs().hasArg(options::OPT__SLASH_Fa) &&
+ !C.getArgs().hasArg(options::OPT_dxc_Fc);
}
/// Return true if a preprocessor action can be collapsed.
@@ -4756,6 +5360,37 @@ InputInfoList Driver::BuildJobsForAction(
return Result;
}
+static void handleTimeTrace(Compilation &C, const ArgList &Args,
+ const JobAction *JA, const char *BaseInput,
+ const InputInfo &Result) {
+ Arg *A =
+ Args.getLastArg(options::OPT_ftime_trace, options::OPT_ftime_trace_EQ);
+ if (!A)
+ return;
+ SmallString<128> Path;
+ if (A->getOption().matches(options::OPT_ftime_trace_EQ)) {
+ Path = A->getValue();
+ if (llvm::sys::fs::is_directory(Path)) {
+ SmallString<128> Tmp(Result.getFilename());
+ llvm::sys::path::replace_extension(Tmp, "json");
+ llvm::sys::path::append(Path, llvm::sys::path::filename(Tmp));
+ }
+ } else {
+ if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) {
+ // The trace file is ${dumpdir}${basename}.json. Note that dumpdir may not
+ // end with a path separator.
+ Path = DumpDir->getValue();
+ Path += llvm::sys::path::filename(BaseInput);
+ } else {
+ Path = Result.getFilename();
+ }
+ llvm::sys::path::replace_extension(Path, "json");
+ }
+ const char *ResultFile = C.getArgs().MakeArgString(Path);
+ C.addTimeTraceFile(ResultFile, JA);
+ C.addResultFile(ResultFile, JA);
+}
+
InputInfoList Driver::BuildJobsForActionNoCache(
Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch,
bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput,
@@ -4791,20 +5426,21 @@ InputInfoList Driver::BuildJobsForActionNoCache(
// \
// Device Action 1 ---> OffloadAction -> Device Action 2
//
- // For a) and b), we just return the job generated for the dependence. For
+ // For a) and b), we just return the job generated for the dependences. For
// c) and d) we override the current action with the host/device dependence
// if the current toolchain is host/device and set the offload dependences
// info with the jobs obtained from the device/host dependence(s).
- // If there is a single device option, just generate the job for it.
- if (OA->hasSingleDeviceDependence()) {
+ // If there is a single device option or has no host action, just generate
+ // the job for it.
+ if (OA->hasSingleDeviceDependence() || !OA->hasHostDependence()) {
InputInfoList DevA;
OA->doOnEachDeviceDependence([&](Action *DepA, const ToolChain *DepTC,
const char *DepBoundArch) {
- DevA =
- BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel,
- /*MultipleArchs*/ !!DepBoundArch, LinkingOutput,
- CachedResults, DepA->getOffloadingDeviceKind());
+ DevA.append(BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel,
+ /*MultipleArchs*/ !!DepBoundArch,
+ LinkingOutput, CachedResults,
+ DepA->getOffloadingDeviceKind()));
});
return DevA;
}
@@ -4879,25 +5515,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
if (!T)
return {InputInfo()};
- if (BuildingForOffloadDevice &&
- A->getOffloadingDeviceKind() == Action::OFK_OpenMP) {
- if (TC->getTriple().isAMDGCN()) {
- // AMDGCN treats backend and assemble actions as no-op because
- // linker does not support object files.
- if (const BackendJobAction *BA = dyn_cast<BackendJobAction>(A)) {
- return BuildJobsForAction(C, *BA->input_begin(), TC, BoundArch,
- AtTopLevel, MultipleArchs, LinkingOutput,
- CachedResults, TargetDeviceOffloadKind);
- }
-
- if (const AssembleJobAction *AA = dyn_cast<AssembleJobAction>(A)) {
- return BuildJobsForAction(C, *AA->input_begin(), TC, BoundArch,
- AtTopLevel, MultipleArchs, LinkingOutput,
- CachedResults, TargetDeviceOffloadKind);
- }
- }
- }
-
// If we've collapsed action list that contained OffloadAction we
// need to build jobs for host/device-side inputs it may have held.
for (const auto *OA : CollapsedOffloadActions)
@@ -4937,10 +5554,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
if (JA->getType() == types::TY_dSYM)
BaseInput = InputInfos[0].getFilename();
- // ... and in header module compilations, which use the module name.
- if (auto *ModuleJA = dyn_cast<HeaderModulePrecompileJobAction>(JA))
- BaseInput = ModuleJA->getModuleName();
-
// Append outputs of offload device jobs to the input list
if (!OffloadDependencesInputInfo.empty())
InputInfos.append(OffloadDependencesInputInfo.begin(),
@@ -5020,20 +5633,15 @@ InputInfoList Driver::BuildJobsForActionNoCache(
// action.
std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix(
A->getOffloadingDeviceKind(), TC->getTriple().normalize(),
- /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() &&
- !AtTopLevel);
- if (isa<OffloadWrapperJobAction>(JA)) {
- if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- BaseInput = FinalOutput->getValue();
- else
- BaseInput = getDefaultImageName();
- BaseInput =
- C.getArgs().MakeArgString(std::string(BaseInput) + "-wrapper");
- }
+ /*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) ||
+ !(A->getOffloadingHostActiveKinds() == Action::OFK_None ||
+ AtTopLevel));
Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
AtTopLevel, MultipleArchs,
OffloadingPrefix),
BaseInput);
+ if (T->canEmitIR() && OffloadingPrefix.empty())
+ handleTimeTrace(C, Args, JA, BaseInput, Result);
}
if (CCCPrintBindings && !CCGenDiagnostics) {
@@ -5119,6 +5727,78 @@ static bool HasPreprocessOutput(const Action &JA) {
return false;
}
+const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix,
+ StringRef Suffix, bool MultipleArchs,
+ StringRef BoundArch,
+ bool NeedUniqueDirectory) const {
+ SmallString<128> TmpName;
+ Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
+ std::optional<std::string> CrashDirectory =
+ CCGenDiagnostics && A
+ ? std::string(A->getValue())
+ : llvm::sys::Process::GetEnv("CLANG_CRASH_DIAGNOSTICS_DIR");
+ if (CrashDirectory) {
+ if (!getVFS().exists(*CrashDirectory))
+ llvm::sys::fs::create_directories(*CrashDirectory);
+ SmallString<128> Path(*CrashDirectory);
+ llvm::sys::path::append(Path, Prefix);
+ const char *Middle = !Suffix.empty() ? "-%%%%%%." : "-%%%%%%";
+ if (std::error_code EC =
+ llvm::sys::fs::createUniqueFile(Path + Middle + Suffix, TmpName)) {
+ Diag(clang::diag::err_unable_to_make_temp) << EC.message();
+ return "";
+ }
+ } else {
+ if (MultipleArchs && !BoundArch.empty()) {
+ if (NeedUniqueDirectory) {
+ TmpName = GetTemporaryDirectory(Prefix);
+ llvm::sys::path::append(TmpName,
+ Twine(Prefix) + "-" + BoundArch + "." + Suffix);
+ } else {
+ TmpName =
+ GetTemporaryPath((Twine(Prefix) + "-" + BoundArch).str(), Suffix);
+ }
+
+ } else {
+ TmpName = GetTemporaryPath(Prefix, Suffix);
+ }
+ }
+ return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+}
+
+// Calculate the output path of the module file when compiling a module unit
+// with the `-fmodule-output` option or `-fmodule-output=` option specified.
+// The behavior is:
+// - If `-fmodule-output=` is specfied, then the module file is
+// writing to the value.
+// - Otherwise if the output object file of the module unit is specified, the
+// output path
+// of the module file should be the same with the output object file except
+// the corresponding suffix. This requires both `-o` and `-c` are specified.
+// - Otherwise, the output path of the module file will be the same with the
+// input with the corresponding suffix.
+static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA,
+ const char *BaseInput) {
+ assert(isa<PrecompileJobAction>(JA) && JA.getType() == types::TY_ModuleFile &&
+ (C.getArgs().hasArg(options::OPT_fmodule_output) ||
+ C.getArgs().hasArg(options::OPT_fmodule_output_EQ)));
+
+ if (Arg *ModuleOutputEQ =
+ C.getArgs().getLastArg(options::OPT_fmodule_output_EQ))
+ return C.addResultFile(ModuleOutputEQ->getValue(), &JA);
+
+ SmallString<64> OutputPath;
+ Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+ if (FinalOutput && C.getArgs().hasArg(options::OPT_c))
+ OutputPath = FinalOutput->getValue();
+ else
+ OutputPath = BaseInput;
+
+ const char *Extension = types::getTypeTempSuffix(JA.getType());
+ llvm::sys::path::replace_extension(OutputPath, Extension);
+ return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA);
+}
+
const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
const char *BaseInput,
StringRef OrigBoundArch, bool AtTopLevel,
@@ -5160,6 +5840,22 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
return "-";
}
+ if (JA.getType() == types::TY_PP_Asm &&
+ C.getArgs().hasArg(options::OPT_dxc_Fc)) {
+ StringRef FcValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fc);
+ // TODO: Should we use `MakeCLOutputFilename` here? If so, we can probably
+ // handle this as part of the SLASH_Fa handling below.
+ return C.addResultFile(C.getArgs().MakeArgString(FcValue.str()), &JA);
+ }
+
+ if (JA.getType() == types::TY_Object &&
+ C.getArgs().hasArg(options::OPT_dxc_Fo)) {
+ StringRef FoValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fo);
+ // TODO: Should we use `MakeCLOutputFilename` here? If so, we can probably
+ // handle this as part of the SLASH_Fo handling below.
+ return C.addResultFile(C.getArgs().MakeArgString(FoValue.str()), &JA);
+ }
+
// Is this the assembly listing for /FA?
if (JA.getType() == types::TY_PP_Asm &&
(C.getArgs().hasArg(options::OPT__SLASH_FA) ||
@@ -5172,37 +5868,41 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
&JA);
}
+ // DXC defaults to standard out when generating assembly. We check this after
+ // any DXC flags that might specify a file.
+ if (AtTopLevel && JA.getType() == types::TY_PP_Asm && IsDXCMode())
+ return "-";
+
+ bool SpecifiedModuleOutput =
+ C.getArgs().hasArg(options::OPT_fmodule_output) ||
+ C.getArgs().hasArg(options::OPT_fmodule_output_EQ);
+ if (MultipleArchs && SpecifiedModuleOutput)
+ Diag(clang::diag::err_drv_module_output_with_multiple_arch);
+
+ // If we're emitting a module output with the specified option
+ // `-fmodule-output`.
+ if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
+ JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
+ return GetModuleOutputPath(C, JA, BaseInput);
+
// Output to a temporary file?
if ((!AtTopLevel && !isSaveTempsEnabled() &&
!C.getArgs().hasArg(options::OPT__SLASH_Fo)) ||
CCGenDiagnostics) {
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
- SmallString<128> TmpName;
- const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
- Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
- if (CCGenDiagnostics && A) {
- SmallString<128> CrashDirectory(A->getValue());
- if (!getVFS().exists(CrashDirectory))
- llvm::sys::fs::create_directories(CrashDirectory);
- llvm::sys::path::append(CrashDirectory, Split.first);
- const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%";
- std::error_code EC = llvm::sys::fs::createUniqueFile(
- CrashDirectory + Middle + Suffix, TmpName);
- if (EC) {
- Diag(clang::diag::err_unable_to_make_temp) << EC.message();
- return "";
- }
- } else {
- if (MultipleArchs && !BoundArch.empty()) {
- TmpName = GetTemporaryDirectory(Split.first);
- llvm::sys::path::append(TmpName,
- Split.first + "-" + BoundArch + "." + Suffix);
- } else {
- TmpName = GetTemporaryPath(Split.first, Suffix);
- }
- }
- return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ const char *Suffix =
+ types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode());
+ // The non-offloading toolchain on Darwin requires deterministic input
+ // file name for binaries to be deterministic, therefore it needs unique
+ // directory.
+ llvm::Triple Triple(C.getDriver().getTargetTriple());
+ bool NeedUniqueDirectory =
+ (JA.getOffloadingDeviceKind() == Action::OFK_None ||
+ JA.getOffloadingDeviceKind() == Action::OFK_Host) &&
+ Triple.isOSDarwin();
+ return CreateTempFile(C, Split.first, Suffix, MultipleArchs, BoundArch,
+ NeedUniqueDirectory);
}
SmallString<128> BasePath(BaseInput);
@@ -5258,7 +5958,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
bool IsHIPNoRDC = JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
!C.getArgs().hasFlag(options::OPT_fgpu_rdc,
options::OPT_fno_gpu_rdc, false);
- if (IsHIPNoRDC) {
+ bool UseOutExtension = IsHIPNoRDC || isa<OffloadPackagerJobAction>(JA);
+ if (UseOutExtension) {
Output = BaseName;
llvm::sys::path::replace_extension(Output, "");
}
@@ -5267,14 +5968,23 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
Output += "-";
Output.append(BoundArch);
}
- if (IsHIPNoRDC)
+ if (UseOutExtension)
Output += ".out";
NamedOutput = C.getArgs().MakeArgString(Output.c_str());
}
} else if (JA.getType() == types::TY_PCH && IsCLMode()) {
NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName));
+ } else if ((JA.getType() == types::TY_Plist || JA.getType() == types::TY_AST) &&
+ C.getArgs().hasArg(options::OPT__SLASH_o)) {
+ StringRef Val =
+ C.getArgs()
+ .getLastArg(options::OPT__SLASH_o)
+ ->getValue();
+ NamedOutput =
+ MakeCLOutputFilename(C.getArgs(), Val, BaseName, types::TY_Object);
} else {
- const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
+ const char *Suffix =
+ types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode());
assert(Suffix && "All types used for output should have a suffix.");
std::string::size_type End = std::string::npos;
@@ -5289,19 +5999,22 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
// When using both -save-temps and -emit-llvm, use a ".tmp.bc" suffix for
// the unoptimized bitcode so that it does not get overwritten by the ".bc"
// optimized bitcode output.
- auto IsHIPRDCInCompilePhase = [](const JobAction &JA,
+ auto IsAMDRDCInCompilePhase = [](const JobAction &JA,
const llvm::opt::DerivedArgList &Args) {
- // The relocatable compilation in HIP implies -emit-llvm. Similarly, use a
- // ".tmp.bc" suffix for the unoptimized bitcode (generated in the compile
- // phase.)
+ // The relocatable compilation in HIP and OpenMP implies -emit-llvm.
+ // Similarly, use a ".tmp.bc" suffix for the unoptimized bitcode
+ // (generated in the compile phase.)
+ const ToolChain *TC = JA.getOffloadingToolChain();
return isa<CompileJobAction>(JA) &&
- JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
- Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
- false);
+ ((JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
+ Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false)) ||
+ (JA.getOffloadingDeviceKind() == Action::OFK_OpenMP && TC &&
+ TC->getTriple().isAMDGPU()));
};
if (!AtTopLevel && JA.getType() == types::TY_LLVM_BC &&
(C.getArgs().hasArg(options::OPT_emit_llvm) ||
- IsHIPRDCInCompilePhase(JA, C.getArgs())))
+ IsAMDRDCInCompilePhase(JA, C.getArgs())))
Suffixed += ".tmp";
Suffixed += '.';
Suffixed += Suffix;
@@ -5332,7 +6045,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
std::string TmpName = GetTemporaryPath(
- Split.first, types::getTypeTempSuffix(JA.getType(), IsCLMode()));
+ Split.first,
+ types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode()));
return C.addTempFile(C.getArgs().MakeArgString(TmpName));
}
}
@@ -5345,15 +6059,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
else
llvm::sys::path::append(BasePath, NamedOutput);
return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA);
- } else {
- return C.addResultFile(NamedOutput, &JA);
}
+
+ return C.addResultFile(NamedOutput, &JA);
}
std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
// Search for Name in a list of paths.
auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P)
- -> llvm::Optional<std::string> {
+ -> std::optional<std::string> {
// Respect a limited subset of the '-Bprefix' functionality in GCC by
// attempting to use this prefix when looking for file paths.
for (const auto &Dir : P) {
@@ -5364,7 +6078,7 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
if (llvm::sys::fs::exists(Twine(P)))
return std::string(P);
}
- return None;
+ return std::nullopt;
};
if (auto P = SearchPaths(PrefixDirs))
@@ -5373,17 +6087,17 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
SmallString<128> R(ResourceDir);
llvm::sys::path::append(R, Name);
if (llvm::sys::fs::exists(Twine(R)))
- return std::string(R.str());
+ return std::string(R);
SmallString<128> P(TC.getCompilerRTPath());
llvm::sys::path::append(P, Name);
if (llvm::sys::fs::exists(Twine(P)))
- return std::string(P.str());
+ return std::string(P);
SmallString<128> D(Dir);
llvm::sys::path::append(D, "..", Name);
if (llvm::sys::fs::exists(Twine(D)))
- return std::string(D.str());
+ return std::string(D);
if (auto P = SearchPaths(TC.getLibraryPaths()))
return *P;
@@ -5420,11 +6134,11 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const {
if (llvm::sys::fs::is_directory(PrefixDir)) {
SmallString<128> P(PrefixDir);
if (ScanDirForExecutable(P, Name))
- return std::string(P.str());
+ return std::string(P);
} else {
SmallString<128> P((PrefixDir + Name).str());
if (llvm::sys::fs::can_execute(Twine(P)))
- return std::string(P.str());
+ return std::string(P);
}
}
@@ -5440,7 +6154,7 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const {
for (const auto &Path : List) {
SmallString<128> P(Path);
if (ScanDirForExecutable(P, TargetSpecificExecutable))
- return std::string(P.str());
+ return std::string(P);
}
// Fall back to the path
@@ -5460,7 +6174,7 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const {
return "";
}
- return std::string(Path.str());
+ return std::string(Path);
}
std::string Driver::GetTemporaryDirectory(StringRef Prefix) const {
@@ -5471,7 +6185,7 @@ std::string Driver::GetTemporaryDirectory(StringRef Prefix) const {
return "";
}
- return std::string(Path.str());
+ return std::string(Path);
}
std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const {
@@ -5493,7 +6207,7 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const {
Output = BaseName;
llvm::sys::path::replace_extension(Output, ".pch");
}
- return std::string(Output.str());
+ return std::string(Output);
}
const ToolChain &Driver::getToolChain(const ArgList &Args,
@@ -5508,17 +6222,13 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Haiku:
TC = std::make_unique<toolchains::Haiku>(*this, Target, Args);
break;
- case llvm::Triple::Ananas:
- TC = std::make_unique<toolchains::Ananas>(*this, Target, Args);
- break;
- case llvm::Triple::CloudABI:
- TC = std::make_unique<toolchains::CloudABI>(*this, Target, Args);
- break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
case llvm::Triple::WatchOS:
+ case llvm::Triple::XROS:
+ case llvm::Triple::DriverKit:
TC = std::make_unique<toolchains::DarwinClang>(*this, Target, Args);
break;
case llvm::Triple::DragonFly:
@@ -5537,9 +6247,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
else
TC = std::make_unique<toolchains::FreeBSD>(*this, Target, Args);
break;
- case llvm::Triple::Minix:
- TC = std::make_unique<toolchains::Minix>(*this, Target, Args);
- break;
case llvm::Triple::Linux:
case llvm::Triple::ELFIAMCU:
if (Target.getArch() == llvm::Triple::hexagon)
@@ -5554,7 +6261,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
Args);
else if (Target.getArch() == llvm::Triple::ve)
TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args);
-
+ else if (Target.isOHOSFamily())
+ TC = std::make_unique<toolchains::OHOS>(*this, Target, Args);
else
TC = std::make_unique<toolchains::Linux>(*this, Target, Args);
break;
@@ -5567,6 +6275,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Solaris:
TC = std::make_unique<toolchains::Solaris>(*this, Target, Args);
break;
+ case llvm::Triple::CUDA:
+ TC = std::make_unique<toolchains::NVPTXToolChain>(*this, Target, Args);
+ break;
case llvm::Triple::AMDHSA:
TC = std::make_unique<toolchains::ROCMToolChain>(*this, Target, Args);
break;
@@ -5594,7 +6305,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::MSVC:
case llvm::Triple::UnknownEnvironment:
if (Args.getLastArgValue(options::OPT_fuse_ld_EQ)
- .startswith_insensitive("bfd"))
+ .starts_with_insensitive("bfd"))
TC = std::make_unique<toolchains::CrossWindowsToolChain>(
*this, Target, Args);
else
@@ -5606,15 +6317,21 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::PS4:
TC = std::make_unique<toolchains::PS4CPU>(*this, Target, Args);
break;
- case llvm::Triple::Contiki:
- TC = std::make_unique<toolchains::Contiki>(*this, Target, Args);
+ case llvm::Triple::PS5:
+ TC = std::make_unique<toolchains::PS5CPU>(*this, Target, Args);
break;
case llvm::Triple::Hurd:
TC = std::make_unique<toolchains::Hurd>(*this, Target, Args);
break;
+ case llvm::Triple::LiteOS:
+ TC = std::make_unique<toolchains::OHOS>(*this, Target, Args);
+ break;
case llvm::Triple::ZOS:
TC = std::make_unique<toolchains::ZOS>(*this, Target, Args);
break;
+ case llvm::Triple::ShaderModel:
+ TC = std::make_unique<toolchains::HLSLToolChain>(*this, Target, Args);
+ break;
default:
// Of these targets, Hexagon is the only one that might have
// an OS of Linux, in which case it got handled above already.
@@ -5661,11 +6378,11 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::spirv64:
TC = std::make_unique<toolchains::SPIRVToolChain>(*this, Target, Args);
break;
+ case llvm::Triple::csky:
+ TC = std::make_unique<toolchains::CSKYToolChain>(*this, Target, Args);
+ break;
default:
- if (Target.getVendor() == llvm::Triple::Myriad)
- TC = std::make_unique<toolchains::MyriadToolChain>(*this, Target,
- Args);
- else if (toolchains::BareMetal::handlesTarget(Target))
+ if (toolchains::BareMetal::handlesTarget(Target))
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
else if (Target.isOSBinFormatELF())
TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
@@ -5677,11 +6394,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
}
}
- // Intentionally omitted from the switch above: llvm::Triple::CUDA. CUDA
- // compiles always need two toolchains, the CUDA toolchain and the host
- // toolchain. So the only valid way to create a CUDA toolchain is via
- // CreateOffloadingDeviceToolChains.
-
return *TC;
}
@@ -5725,7 +6437,8 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
// And say "no" if this is not a kind of action clang understands.
if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) &&
- !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA))
+ !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA) &&
+ !isa<ExtractAPIJobAction>(JA))
return false;
return true;
@@ -5734,11 +6447,12 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
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()))
+ !types::isAcceptedByFlang((*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))
+ if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) &&
+ !isa<BackendJobAction>(JA))
return false;
return true;
@@ -5817,20 +6531,37 @@ bool Driver::GetReleaseVersion(StringRef Str,
return false;
}
-std::pair<unsigned, unsigned>
-Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const {
- unsigned IncludedFlagsBitmask = 0;
- unsigned ExcludedFlagsBitmask = options::NoDriverOption;
-
- if (IsClCompatMode) {
- // Include CL and Core options.
- IncludedFlagsBitmask |= options::CLOption;
- IncludedFlagsBitmask |= options::CoreOption;
- } else {
- ExcludedFlagsBitmask |= options::CLOption;
- }
+llvm::opt::Visibility
+Driver::getOptionVisibilityMask(bool UseDriverMode) const {
+ if (!UseDriverMode)
+ return llvm::opt::Visibility(options::ClangOption);
+ if (IsCLMode())
+ return llvm::opt::Visibility(options::CLOption);
+ if (IsDXCMode())
+ return llvm::opt::Visibility(options::DXCOption);
+ if (IsFlangMode()) {
+ return llvm::opt::Visibility(options::FlangOption);
+ }
+ return llvm::opt::Visibility(options::ClangOption);
+}
- return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
+const char *Driver::getExecutableForDriverMode(DriverMode Mode) {
+ switch (Mode) {
+ case GCCMode:
+ return "clang";
+ case GXXMode:
+ return "clang++";
+ case CPPMode:
+ return "clang-cpp";
+ case CLMode:
+ return "clang-cl";
+ case FlangMode:
+ return "flang";
+ case DXCMode:
+ return "clang-dxc";
+ }
+
+ llvm_unreachable("Unhandled Mode");
}
bool clang::driver::isOptimizationLevelFast(const ArgList &Args) {
@@ -5862,11 +6593,11 @@ bool clang::driver::willEmitRemarks(const ArgList &Args) {
llvm::StringRef clang::driver::getDriverMode(StringRef ProgName,
ArrayRef<const char *> Args) {
- static const std::string OptName =
+ static StringRef OptName =
getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName();
llvm::StringRef Opt;
for (StringRef Arg : Args) {
- if (!Arg.startswith(OptName))
+ if (!Arg.starts_with(OptName))
continue;
Opt = Arg;
}
@@ -5876,3 +6607,58 @@ llvm::StringRef clang::driver::getDriverMode(StringRef ProgName,
}
bool driver::IsClangCL(StringRef DriverMode) { return DriverMode.equals("cl"); }
+
+llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,
+ bool ClangCLMode,
+ llvm::BumpPtrAllocator &Alloc,
+ llvm::vfs::FileSystem *FS) {
+ // Parse response files using the GNU syntax, unless we're in CL mode. There
+ // are two ways to put clang in CL compatibility mode: ProgName is either
+ // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
+ // command line parsing can't happen until after response file parsing, so we
+ // have to manually search for a --driver-mode=cl argument the hard way.
+ // Finally, our -cc1 tools don't care which tokenization mode we use because
+ // response files written by clang will tokenize the same way in either mode.
+ enum { Default, POSIX, Windows } RSPQuoting = Default;
+ for (const char *F : Args) {
+ if (strcmp(F, "--rsp-quoting=posix") == 0)
+ RSPQuoting = POSIX;
+ else if (strcmp(F, "--rsp-quoting=windows") == 0)
+ RSPQuoting = Windows;
+ }
+
+ // Determines whether we want nullptr markers in Args to indicate response
+ // files end-of-lines. We only use this for the /LINK driver argument with
+ // clang-cl.exe on Windows.
+ bool MarkEOLs = ClangCLMode;
+
+ llvm::cl::TokenizerCallback Tokenizer;
+ if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
+ Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
+ else
+ Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
+
+ if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).starts_with("-cc1"))
+ MarkEOLs = false;
+
+ llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
+ ECtx.setMarkEOLs(MarkEOLs);
+ if (FS)
+ ECtx.setVFS(FS);
+
+ if (llvm::Error Err = ECtx.expandResponseFiles(Args))
+ return Err;
+
+ // If -cc1 came from a response file, remove the EOL sentinels.
+ auto FirstArg = llvm::find_if(llvm::drop_begin(Args),
+ [](const char *A) { return A != nullptr; });
+ if (FirstArg != Args.end() && StringRef(*FirstArg).starts_with("-cc1")) {
+ // If -cc1 came from a response file, remove the EOL sentinels.
+ if (MarkEOLs) {
+ auto newEnd = std::remove(Args.begin(), Args.end(), nullptr);
+ Args.resize(newEnd - Args.begin());
+ }
+ }
+
+ return llvm::Error::success();
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp
index 67d4198d222a..b25801a8f3f4 100644
--- a/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp
@@ -16,40 +16,40 @@ using namespace clang::driver;
using namespace clang::driver::options;
using namespace llvm::opt;
-#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
+#define OPTTABLE_VALUES_CODE
+#include "clang/Driver/Options.inc"
+#undef OPTTABLE_VALUES_CODE
+
+#define PREFIX(NAME, VALUE) \
+ static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
#include "clang/Driver/Options.inc"
#undef PREFIX
-static const OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
+static constexpr const llvm::StringLiteral PrefixTable_init[] =
+#define PREFIX_UNION(VALUES) VALUES
+#include "clang/Driver/Options.inc"
+#undef PREFIX_UNION
+ ;
+static constexpr const llvm::ArrayRef<llvm::StringLiteral>
+ PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
+
+static constexpr OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
#include "clang/Driver/Options.inc"
#undef OPTION
};
namespace {
-class DriverOptTable : public OptTable {
+class DriverOptTable : public PrecomputedOptTable {
public:
- DriverOptTable()
- : OptTable(InfoTable) {}
+ DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
};
-
}
const llvm::opt::OptTable &clang::driver::getDriverOptTable() {
- static const DriverOptTable *Table = []() {
- auto Result = std::make_unique<DriverOptTable>();
- // Options.inc is included in DriverOptions.cpp, and calls OptTable's
- // addValues function.
- // Opt is a variable used in the code fragment in Options.inc.
- OptTable &Opt = *Result;
-#define OPTTABLE_ARG_INIT
-#include "clang/Driver/Options.inc"
-#undef OPTTABLE_ARG_INIT
- return Result.release();
- }();
- return *Table;
+ static DriverOptTable Table;
+ return Table;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/Job.cpp b/contrib/llvm-project/clang/lib/Driver/Job.cpp
index f63763effaff..a6c1581be796 100644
--- a/contrib/llvm-project/clang/lib/Driver/Job.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Job.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
@@ -38,9 +39,10 @@ using namespace driver;
Command::Command(const Action &Source, const Tool &Creator,
ResponseFileSupport ResponseSupport, const char *Executable,
const llvm::opt::ArgStringList &Arguments,
- ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs)
+ ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs,
+ const char *PrependArg)
: Source(Source), Creator(Creator), ResponseSupport(ResponseSupport),
- Executable(Executable), Arguments(Arguments) {
+ Executable(Executable), PrependArg(PrependArg), Arguments(Arguments) {
for (const auto &II : Inputs)
if (II.isFilename())
InputInfoList.push_back(II);
@@ -93,10 +95,10 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
// These flags are treated as a single argument (e.g., -F<Dir>).
StringRef FlagRef(Flag);
- IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I");
+ IsInclude = FlagRef.starts_with("-F") || FlagRef.starts_with("-I");
if (IsInclude)
return !HaveCrashVFS;
- if (FlagRef.startswith("-fmodules-cache-path="))
+ if (FlagRef.starts_with("-fmodules-cache-path="))
return true;
SkipNum = 0;
@@ -144,6 +146,10 @@ void Command::buildArgvForResponseFile(
for (const auto *InputName : InputFileList)
Inputs.insert(InputName);
Out.push_back(Executable);
+
+ if (PrependArg)
+ Out.push_back(PrependArg);
+
// In a file list, build args vector ignoring parameters that will go in the
// response file (elements of the InputFileList vector)
bool FirstInput = true;
@@ -179,8 +185,8 @@ rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx,
SmallString<128> NewInc;
if (NumArgs == 1) {
StringRef FlagRef(Args[Idx + NumArgs - 1]);
- assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) &&
- "Expecting -I or -F");
+ assert((FlagRef.starts_with("-F") || FlagRef.starts_with("-I")) &&
+ "Expecting -I or -F");
StringRef Inc = FlagRef.slice(2, StringRef::npos);
if (getAbsPath(Inc, NewInc)) {
SmallString<128> NewArg(FlagRef.slice(0, 2));
@@ -209,6 +215,9 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
if (ResponseFile != nullptr) {
buildArgvForResponseFile(ArgsRespFile);
Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
+ } else if (PrependArg) {
+ OS << ' ';
+ llvm::sys::printArg(OS, PrependArg, /*Quote=*/true);
}
bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
@@ -301,6 +310,11 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
Environment.push_back(nullptr);
}
+void Command::setRedirectFiles(
+ const std::vector<std::optional<std::string>> &Redirects) {
+ RedirectFiles = Redirects;
+}
+
void Command::PrintFileNames() const {
if (PrintInputFilenames) {
for (const auto &Arg : InputInfoList)
@@ -309,13 +323,15 @@ void Command::PrintFileNames() const {
}
}
-int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+int Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
std::string *ErrMsg, bool *ExecutionFailed) const {
PrintFileNames();
SmallVector<const char *, 128> Argv;
if (ResponseFile == nullptr) {
Argv.push_back(Executable);
+ if (PrependArg)
+ Argv.push_back(PrependArg);
Argv.append(Arguments.begin(), Arguments.end());
Argv.push_back(nullptr);
} else {
@@ -342,16 +358,32 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
}
}
- Optional<ArrayRef<StringRef>> Env;
+ std::optional<ArrayRef<StringRef>> Env;
std::vector<StringRef> ArgvVectorStorage;
if (!Environment.empty()) {
assert(Environment.back() == nullptr &&
"Environment vector should be null-terminated by now");
ArgvVectorStorage = llvm::toStringRefArray(Environment.data());
- Env = makeArrayRef(ArgvVectorStorage);
+ Env = ArrayRef(ArgvVectorStorage);
}
auto Args = llvm::toStringRefArray(Argv.data());
+
+ // Use Job-specific redirect files if they are present.
+ if (!RedirectFiles.empty()) {
+ std::vector<std::optional<StringRef>> RedirectFilesOptional;
+ for (const auto &Ele : RedirectFiles)
+ if (Ele)
+ RedirectFilesOptional.push_back(std::optional<StringRef>(*Ele));
+ else
+ RedirectFilesOptional.push_back(std::nullopt);
+
+ return llvm::sys::ExecuteAndWait(Executable, Args, Env,
+ ArrayRef(RedirectFilesOptional),
+ /*secondsToWait=*/0, /*memoryLimit=*/0,
+ ErrMsg, ExecutionFailed, &ProcStat);
+ }
+
return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
/*secondsToWait*/ 0, /*memoryLimit*/ 0,
ErrMsg, ExecutionFailed, &ProcStat);
@@ -361,9 +393,10 @@ CC1Command::CC1Command(const Action &Source, const Tool &Creator,
ResponseFileSupport ResponseSupport,
const char *Executable,
const llvm::opt::ArgStringList &Arguments,
- ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs)
+ ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs,
+ const char *PrependArg)
: Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs,
- Outputs) {
+ Outputs, PrependArg) {
InProcess = true;
}
@@ -374,7 +407,7 @@ void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
Command::Print(OS, Terminator, Quote, CrashInfo);
}
-int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
std::string *ErrMsg, bool *ExecutionFailed) const {
// FIXME: Currently, if there're more than one job, we disable
// -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to
@@ -417,30 +450,6 @@ void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
"The CC1Command doesn't support changing the environment vars!");
}
-ForceSuccessCommand::ForceSuccessCommand(
- const Action &Source_, const Tool &Creator_,
- ResponseFileSupport ResponseSupport, const char *Executable_,
- const llvm::opt::ArgStringList &Arguments_, ArrayRef<InputInfo> Inputs,
- ArrayRef<InputInfo> Outputs)
- : Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_,
- Inputs, Outputs) {}
-
-void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
- bool Quote, CrashReportInfo *CrashInfo) const {
- Command::Print(OS, "", Quote, CrashInfo);
- OS << " || (exit 0)" << Terminator;
-}
-
-int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
- std::string *ErrMsg,
- bool *ExecutionFailed) const {
- int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
- (void)Status;
- if (ExecutionFailed)
- *ExecutionFailed = false;
- return 0;
-}
-
void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo) const {
for (const auto &Job : *this)
diff --git a/contrib/llvm-project/clang/lib/Driver/Multilib.cpp b/contrib/llvm-project/clang/lib/Driver/Multilib.cpp
index ab44ba50b5d5..9c091bbfdaba 100644
--- a/contrib/llvm-project/clang/lib/Driver/Multilib.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Multilib.cpp
@@ -8,14 +8,18 @@
#include "clang/Driver/Multilib.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -25,56 +29,17 @@ using namespace clang;
using namespace driver;
using namespace llvm::sys;
-/// normalize Segment to "/foo/bar" or "".
-static void normalizePathSegment(std::string &Segment) {
- StringRef seg = Segment;
-
- // Prune trailing "/" or "./"
- while (true) {
- StringRef last = path::filename(seg);
- if (last != ".")
- break;
- seg = path::parent_path(seg);
- }
-
- if (seg.empty() || seg == "/") {
- Segment.clear();
- return;
- }
-
- // Add leading '/'
- if (seg.front() != '/') {
- Segment = "/" + seg.str();
- } else {
- Segment = std::string(seg);
- }
-}
-
Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
- StringRef IncludeSuffix, int Priority)
+ StringRef IncludeSuffix, const flags_list &Flags,
+ StringRef ExclusiveGroup)
: GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
- Priority(Priority) {
- normalizePathSegment(this->GCCSuffix);
- normalizePathSegment(this->OSSuffix);
- normalizePathSegment(this->IncludeSuffix);
-}
-
-Multilib &Multilib::gccSuffix(StringRef S) {
- GCCSuffix = std::string(S);
- normalizePathSegment(GCCSuffix);
- return *this;
-}
-
-Multilib &Multilib::osSuffix(StringRef S) {
- OSSuffix = std::string(S);
- normalizePathSegment(OSSuffix);
- return *this;
-}
-
-Multilib &Multilib::includeSuffix(StringRef S) {
- IncludeSuffix = std::string(S);
- normalizePathSegment(IncludeSuffix);
- return *this;
+ Flags(Flags), ExclusiveGroup(ExclusiveGroup) {
+ assert(GCCSuffix.empty() ||
+ (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
+ assert(OSSuffix.empty() ||
+ (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));
+ assert(IncludeSuffix.empty() ||
+ (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1));
}
LLVM_DUMP_METHOD void Multilib::dump() const {
@@ -82,7 +47,6 @@ LLVM_DUMP_METHOD void Multilib::dump() const {
}
void Multilib::print(raw_ostream &OS) const {
- assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
if (GCCSuffix.empty())
OS << ".";
else {
@@ -90,27 +54,11 @@ void Multilib::print(raw_ostream &OS) const {
}
OS << ";";
for (StringRef Flag : Flags) {
- if (Flag.front() == '+')
+ if (Flag.front() == '-')
OS << "@" << Flag.substr(1);
}
}
-bool Multilib::isValid() const {
- llvm::StringMap<int> FlagSet;
- for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
- StringRef Flag(Flags[I]);
- llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
-
- assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
-
- if (SI == FlagSet.end())
- FlagSet[Flag.substr(1)] = I;
- else if (Flags[I] != Flags[SI->getValue()])
- return false;
- }
- return true;
-}
-
bool Multilib::operator==(const Multilib &Other) const {
// Check whether the flags sets match
// allowing for the match to be order invariant
@@ -119,7 +67,7 @@ bool Multilib::operator==(const Multilib &Other) const {
MyFlags.insert(Flag);
for (const auto &Flag : Other.Flags)
- if (MyFlags.find(Flag) == MyFlags.end())
+ if (!MyFlags.contains(Flag))
return false;
if (osSuffix() != Other.osSuffix())
@@ -139,147 +87,225 @@ raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
return OS;
}
-MultilibSet &MultilibSet::Maybe(const Multilib &M) {
- Multilib Opposite;
- // Negate any '+' flags
- for (StringRef Flag : M.flags()) {
- if (Flag.front() == '+')
- Opposite.flags().push_back(("-" + Flag.substr(1)).str());
- }
- return Either(M, Opposite);
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
- return Either({M1, M2});
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
- const Multilib &M3) {
- return Either({M1, M2, M3});
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
- const Multilib &M3, const Multilib &M4) {
- return Either({M1, M2, M3, M4});
-}
-
-MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
- const Multilib &M3, const Multilib &M4,
- const Multilib &M5) {
- return Either({M1, M2, M3, M4, M5});
-}
-
-static Multilib compose(const Multilib &Base, const Multilib &New) {
- SmallString<128> GCCSuffix;
- llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
- SmallString<128> OSSuffix;
- llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
- SmallString<128> IncludeSuffix;
- llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
- New.includeSuffix());
-
- Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix);
-
- Multilib::flags_list &Flags = Composed.flags();
-
- Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
- Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
-
- return Composed;
+MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
+ llvm::erase_if(Multilibs, F);
+ return *this;
}
-MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) {
- multilib_list Composed;
+void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
- if (Multilibs.empty())
- Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
- MultilibSegments.end());
- else {
- for (const auto &New : MultilibSegments) {
- for (const auto &Base : *this) {
- Multilib MO = compose(Base, New);
- if (MO.isValid())
- Composed.push_back(MO);
- }
+bool MultilibSet::select(const Multilib::flags_list &Flags,
+ llvm::SmallVectorImpl<Multilib> &Selected) const {
+ llvm::StringSet<> FlagSet(expandFlags(Flags));
+ Selected.clear();
+
+ // Decide which multilibs we're going to select at all.
+ llvm::DenseSet<StringRef> ExclusiveGroupsSelected;
+ for (const Multilib &M : llvm::reverse(Multilibs)) {
+ // If this multilib doesn't match all our flags, don't select it.
+ if (!llvm::all_of(M.flags(), [&FlagSet](const std::string &F) {
+ return FlagSet.contains(F);
+ }))
+ continue;
+
+ const std::string &group = M.exclusiveGroup();
+ if (!group.empty()) {
+ // If this multilib has the same ExclusiveGroup as one we've already
+ // selected, skip it. We're iterating in reverse order, so the group
+ // member we've selected already is preferred.
+ //
+ // Otherwise, add the group name to the set of groups we've already
+ // selected a member of.
+ auto [It, Inserted] = ExclusiveGroupsSelected.insert(group);
+ if (!Inserted)
+ continue;
}
- Multilibs = Composed;
+ // Select this multilib.
+ Selected.push_back(M);
}
- return *this;
-}
+ // We iterated in reverse order, so now put Selected back the right way
+ // round.
+ std::reverse(Selected.begin(), Selected.end());
-MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
- filterInPlace(F, Multilibs);
- return *this;
+ return !Selected.empty();
}
-MultilibSet &MultilibSet::FilterOut(const char *Regex) {
- llvm::Regex R(Regex);
-#ifndef NDEBUG
- std::string Error;
- if (!R.isValid(Error)) {
- llvm::errs() << Error;
- llvm_unreachable("Invalid regex!");
+llvm::StringSet<>
+MultilibSet::expandFlags(const Multilib::flags_list &InFlags) const {
+ llvm::StringSet<> Result;
+ for (const auto &F : InFlags)
+ Result.insert(F);
+ for (const FlagMatcher &M : FlagMatchers) {
+ std::string RegexString(M.Match);
+
+ // Make the regular expression match the whole string.
+ if (!StringRef(M.Match).starts_with("^"))
+ RegexString.insert(RegexString.begin(), '^');
+ if (!StringRef(M.Match).ends_with("$"))
+ RegexString.push_back('$');
+
+ const llvm::Regex Regex(RegexString);
+ assert(Regex.isValid());
+ if (llvm::any_of(InFlags,
+ [&Regex](StringRef F) { return Regex.match(F); })) {
+ Result.insert(M.Flags.begin(), M.Flags.end());
+ }
}
-#endif
-
- filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); },
- Multilibs);
- return *this;
-}
-
-void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
-
-void MultilibSet::combineWith(const MultilibSet &Other) {
- Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
+ return Result;
}
-static bool isFlagEnabled(StringRef Flag) {
- char Indicator = Flag.front();
- assert(Indicator == '+' || Indicator == '-');
- return Indicator == '+';
-}
+namespace {
+
+// When updating this also update MULTILIB_VERSION in MultilibTest.cpp
+static const VersionTuple MultilibVersionCurrent(1, 0);
+
+struct MultilibSerialization {
+ std::string Dir;
+ std::vector<std::string> Flags;
+ std::string Group;
+};
+
+enum class MultilibGroupType {
+ /*
+ * The only group type currently supported is 'Exclusive', which indicates a
+ * group of multilibs of which at most one may be selected.
+ */
+ Exclusive,
+
+ /*
+ * Future possibility: a second group type indicating a set of library
+ * directories that are mutually _dependent_ rather than mutually exclusive:
+ * if you include one you must include them all.
+ *
+ * It might also be useful to allow groups to be members of other groups, so
+ * that a mutually exclusive group could contain a mutually dependent set of
+ * library directories, or vice versa.
+ *
+ * These additional features would need changes in the implementation, but
+ * the YAML schema is set up so they can be added without requiring changes
+ * in existing users' multilib.yaml files.
+ */
+};
+
+struct MultilibGroupSerialization {
+ std::string Name;
+ MultilibGroupType Type;
+};
+
+struct MultilibSetSerialization {
+ llvm::VersionTuple MultilibVersion;
+ std::vector<MultilibGroupSerialization> Groups;
+ std::vector<MultilibSerialization> Multilibs;
+ std::vector<MultilibSet::FlagMatcher> FlagMatchers;
+};
+
+} // end anonymous namespace
+
+template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
+ static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
+ io.mapRequired("Dir", V.Dir);
+ io.mapRequired("Flags", V.Flags);
+ io.mapOptional("Group", V.Group);
+ }
+ static std::string validate(IO &io, MultilibSerialization &V) {
+ if (StringRef(V.Dir).starts_with("/"))
+ return "paths must be relative but \"" + V.Dir + "\" starts with \"/\"";
+ return std::string{};
+ }
+};
-bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
- llvm::StringMap<bool> FlagSet;
+template <> struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> {
+ static void enumeration(IO &io, MultilibGroupType &Val) {
+ io.enumCase(Val, "Exclusive", MultilibGroupType::Exclusive);
+ }
+};
- // Stuff all of the flags into the FlagSet such that a true mappend indicates
- // the flag was enabled, and a false mappend indicates the flag was disabled.
- for (StringRef Flag : Flags)
- FlagSet[Flag.substr(1)] = isFlagEnabled(Flag);
+template <> struct llvm::yaml::MappingTraits<MultilibGroupSerialization> {
+ static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V) {
+ io.mapRequired("Name", V.Name);
+ io.mapRequired("Type", V.Type);
+ }
+};
- multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) {
- for (StringRef Flag : M.flags()) {
- llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
- if (SI != FlagSet.end())
- if (SI->getValue() != isFlagEnabled(Flag))
- return true;
+template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {
+ static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M) {
+ io.mapRequired("Match", M.Match);
+ io.mapRequired("Flags", M.Flags);
+ }
+ static std::string validate(IO &io, MultilibSet::FlagMatcher &M) {
+ llvm::Regex Regex(M.Match);
+ std::string RegexError;
+ if (!Regex.isValid(RegexError))
+ return RegexError;
+ if (M.Flags.empty())
+ return "value required for 'Flags'";
+ return std::string{};
+ }
+};
+
+template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
+ static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
+ io.mapRequired("MultilibVersion", M.MultilibVersion);
+ io.mapRequired("Variants", M.Multilibs);
+ io.mapOptional("Groups", M.Groups);
+ io.mapOptional("Mappings", M.FlagMatchers);
+ }
+ static std::string validate(IO &io, MultilibSetSerialization &M) {
+ if (M.MultilibVersion.empty())
+ return "missing required key 'MultilibVersion'";
+ if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())
+ return "multilib version " + M.MultilibVersion.getAsString() +
+ " is unsupported";
+ if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())
+ return "multilib version " + M.MultilibVersion.getAsString() +
+ " is unsupported";
+ for (const MultilibSerialization &Lib : M.Multilibs) {
+ if (!Lib.Group.empty()) {
+ bool Found = false;
+ for (const MultilibGroupSerialization &Group : M.Groups)
+ if (Group.Name == Lib.Group) {
+ Found = true;
+ break;
+ }
+ if (!Found)
+ return "multilib \"" + Lib.Dir +
+ "\" specifies undefined group name \"" + Lib.Group + "\"";
+ }
}
- return false;
- }, Multilibs);
-
- if (Filtered.empty())
- return false;
- if (Filtered.size() == 1) {
- M = Filtered[0];
- return true;
+ return std::string{};
}
-
- // Sort multilibs by priority and select the one with the highest priority.
- llvm::sort(Filtered.begin(), Filtered.end(),
- [](const Multilib &a, const Multilib &b) -> bool {
- return a.priority() > b.priority();
- });
-
- if (Filtered[0].priority() > Filtered[1].priority()) {
- M = Filtered[0];
- return true;
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher)
+
+llvm::ErrorOr<MultilibSet>
+MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
+ llvm::SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagHandlerCtxt) {
+ MultilibSetSerialization MS;
+ llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt);
+ YamlInput >> MS;
+ if (YamlInput.error())
+ return YamlInput.error();
+
+ multilib_list Multilibs;
+ Multilibs.reserve(MS.Multilibs.size());
+ for (const auto &M : MS.Multilibs) {
+ std::string Dir;
+ if (M.Dir != ".")
+ Dir = "/" + M.Dir;
+ // We transfer M.Group straight into the ExclusiveGroup parameter for the
+ // Multilib constructor. If we later support more than one type of group,
+ // we'll have to look up the group name in MS.Groups, check its type, and
+ // decide what to do here.
+ Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);
}
- // TODO: We should consider returning llvm::Error rather than aborting.
- assert(false && "More than one multilib with the same priority");
- return false;
+ return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers));
}
LLVM_DUMP_METHOD void MultilibSet::dump() const {
@@ -291,17 +317,6 @@ void MultilibSet::print(raw_ostream &OS) const {
OS << M << "\n";
}
-MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F,
- const multilib_list &Ms) {
- multilib_list Copy(Ms);
- filterInPlace(F, Copy);
- return Copy;
-}
-
-void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) {
- llvm::erase_if(Ms, F);
-}
-
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
MS.print(OS);
return OS;
diff --git a/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp b/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp
new file mode 100644
index 000000000000..15adf5017780
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp
@@ -0,0 +1,197 @@
+//===- MultilibBuilder.cpp - MultilibBuilder Implementation -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/MultilibBuilder.h"
+#include "ToolChains/CommonArgs.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace driver;
+
+/// normalize Segment to "/foo/bar" or "".
+static void normalizePathSegment(std::string &Segment) {
+ StringRef seg = Segment;
+
+ // Prune trailing "/" or "./"
+ while (true) {
+ StringRef last = llvm::sys::path::filename(seg);
+ if (last != ".")
+ break;
+ seg = llvm::sys::path::parent_path(seg);
+ }
+
+ if (seg.empty() || seg == "/") {
+ Segment.clear();
+ return;
+ }
+
+ // Add leading '/'
+ if (seg.front() != '/') {
+ Segment = "/" + seg.str();
+ } else {
+ Segment = std::string(seg);
+ }
+}
+
+MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include)
+ : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) {
+ normalizePathSegment(GCCSuffix);
+ normalizePathSegment(OSSuffix);
+ normalizePathSegment(IncludeSuffix);
+}
+
+MultilibBuilder::MultilibBuilder(StringRef Suffix)
+ : MultilibBuilder(Suffix, Suffix, Suffix) {}
+
+MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) {
+ GCCSuffix = std::string(S);
+ normalizePathSegment(GCCSuffix);
+ return *this;
+}
+
+MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {
+ OSSuffix = std::string(S);
+ normalizePathSegment(OSSuffix);
+ return *this;
+}
+
+MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {
+ IncludeSuffix = std::string(S);
+ normalizePathSegment(IncludeSuffix);
+ return *this;
+}
+
+bool MultilibBuilder::isValid() const {
+ llvm::StringMap<int> FlagSet;
+ for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
+ StringRef Flag(Flags[I]);
+ llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
+
+ assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!');
+
+ if (SI == FlagSet.end())
+ FlagSet[Flag.substr(1)] = I;
+ else if (Flags[I] != Flags[SI->getValue()])
+ return false;
+ }
+ return true;
+}
+
+MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) {
+ tools::addMultilibFlag(!Disallow, Flag, Flags);
+ return *this;
+}
+
+Multilib MultilibBuilder::makeMultilib() const {
+ return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags);
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) {
+ MultilibBuilder Opposite;
+ // Negate positive flags
+ for (StringRef Flag : M.flags()) {
+ if (Flag.front() == '-')
+ Opposite.flag(Flag, /*Disallow=*/true);
+ }
+ return Either(M, Opposite);
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+ const MultilibBuilder &M2) {
+ return Either({M1, M2});
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+ const MultilibBuilder &M2,
+ const MultilibBuilder &M3) {
+ return Either({M1, M2, M3});
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+ const MultilibBuilder &M2,
+ const MultilibBuilder &M3,
+ const MultilibBuilder &M4) {
+ return Either({M1, M2, M3, M4});
+}
+
+MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
+ const MultilibBuilder &M2,
+ const MultilibBuilder &M3,
+ const MultilibBuilder &M4,
+ const MultilibBuilder &M5) {
+ return Either({M1, M2, M3, M4, M5});
+}
+
+static MultilibBuilder compose(const MultilibBuilder &Base,
+ const MultilibBuilder &New) {
+ SmallString<128> GCCSuffix;
+ llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
+ SmallString<128> OSSuffix;
+ llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
+ SmallString<128> IncludeSuffix;
+ llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
+ New.includeSuffix());
+
+ MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix);
+
+ MultilibBuilder::flags_list &Flags = Composed.flags();
+
+ Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
+ Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
+
+ return Composed;
+}
+
+MultilibSetBuilder &
+MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) {
+ multilib_list Composed;
+
+ if (Multilibs.empty())
+ Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
+ MultilibSegments.end());
+ else {
+ for (const auto &New : MultilibSegments) {
+ for (const auto &Base : Multilibs) {
+ MultilibBuilder MO = compose(Base, New);
+ if (MO.isValid())
+ Composed.push_back(MO);
+ }
+ }
+
+ Multilibs = Composed;
+ }
+
+ return *this;
+}
+
+MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) {
+ llvm::Regex R(Regex);
+#ifndef NDEBUG
+ std::string Error;
+ if (!R.isValid(Error)) {
+ llvm::errs() << Error;
+ llvm_unreachable("Invalid regex!");
+ }
+#endif
+ llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {
+ return R.match(M.gccSuffix());
+ });
+ return *this;
+}
+
+MultilibSet MultilibSetBuilder::makeMultilibSet() const {
+ MultilibSet Result;
+ for (const auto &M : Multilibs) {
+ Result.push_back(M.makeMultilib());
+ }
+ return Result;
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp b/contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp
new file mode 100644
index 000000000000..b1091aca5616
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp
@@ -0,0 +1,1684 @@
+//===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements an offload bundling API that bundles different files
+/// that relate with the same source code but different targets into a single
+/// one. Also the implements the opposite functionality, i.e. unbundle files
+/// previous created by this API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/OffloadBundler.h"
+#include "clang/Basic/Cuda.h"
+#include "clang/Basic/TargetID.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/Triple.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <forward_list>
+#include <llvm/Support/Process.h>
+#include <memory>
+#include <set>
+#include <string>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace clang;
+
+static llvm::TimerGroup
+ ClangOffloadBundlerTimerGroup("Clang Offload Bundler Timer Group",
+ "Timer group for clang offload bundler");
+
+/// Magic string that marks the existence of offloading data.
+#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
+
+OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
+ const OffloadBundlerConfig &BC)
+ : BundlerConfig(BC) {
+
+ // TODO: Add error checking from ClangOffloadBundler.cpp
+ auto TargetFeatures = Target.split(':');
+ auto TripleOrGPU = TargetFeatures.first.rsplit('-');
+
+ if (clang::StringToCudaArch(TripleOrGPU.second) != clang::CudaArch::UNKNOWN) {
+ auto KindTriple = TripleOrGPU.first.split('-');
+ this->OffloadKind = KindTriple.first;
+
+ // Enforce optional env field to standardize bundles
+ llvm::Triple t = llvm::Triple(KindTriple.second);
+ this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
+ t.getOSName(), t.getEnvironmentName());
+
+ this->TargetID = Target.substr(Target.find(TripleOrGPU.second));
+ } else {
+ auto KindTriple = TargetFeatures.first.split('-');
+ this->OffloadKind = KindTriple.first;
+
+ // Enforce optional env field to standardize bundles
+ llvm::Triple t = llvm::Triple(KindTriple.second);
+ this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
+ t.getOSName(), t.getEnvironmentName());
+
+ this->TargetID = "";
+ }
+}
+
+bool OffloadTargetInfo::hasHostKind() const {
+ return this->OffloadKind == "host";
+}
+
+bool OffloadTargetInfo::isOffloadKindValid() const {
+ return OffloadKind == "host" || OffloadKind == "openmp" ||
+ OffloadKind == "hip" || OffloadKind == "hipv4";
+}
+
+bool OffloadTargetInfo::isOffloadKindCompatible(
+ const StringRef TargetOffloadKind) const {
+ if (OffloadKind == TargetOffloadKind)
+ return true;
+ if (BundlerConfig.HipOpenmpCompatible) {
+ bool HIPCompatibleWithOpenMP = OffloadKind.starts_with_insensitive("hip") &&
+ TargetOffloadKind == "openmp";
+ bool OpenMPCompatibleWithHIP =
+ OffloadKind == "openmp" &&
+ TargetOffloadKind.starts_with_insensitive("hip");
+ return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
+ }
+ return false;
+}
+
+bool OffloadTargetInfo::isTripleValid() const {
+ return !Triple.str().empty() && Triple.getArch() != Triple::UnknownArch;
+}
+
+bool OffloadTargetInfo::operator==(const OffloadTargetInfo &Target) const {
+ return OffloadKind == Target.OffloadKind &&
+ Triple.isCompatibleWith(Target.Triple) && TargetID == Target.TargetID;
+}
+
+std::string OffloadTargetInfo::str() const {
+ return Twine(OffloadKind + "-" + Triple.str() + "-" + TargetID).str();
+}
+
+static StringRef getDeviceFileExtension(StringRef Device,
+ StringRef BundleFileName) {
+ if (Device.contains("gfx"))
+ return ".bc";
+ if (Device.contains("sm_"))
+ return ".cubin";
+ return sys::path::extension(BundleFileName);
+}
+
+static std::string getDeviceLibraryFileName(StringRef BundleFileName,
+ StringRef Device) {
+ StringRef LibName = sys::path::stem(BundleFileName);
+ StringRef Extension = getDeviceFileExtension(Device, BundleFileName);
+
+ std::string Result;
+ Result += LibName;
+ Result += Extension;
+ return Result;
+}
+
+namespace {
+/// Generic file handler interface.
+class FileHandler {
+public:
+ struct BundleInfo {
+ StringRef BundleID;
+ };
+
+ FileHandler() {}
+
+ virtual ~FileHandler() {}
+
+ /// Update the file handler with information from the header of the bundled
+ /// file.
+ virtual Error ReadHeader(MemoryBuffer &Input) = 0;
+
+ /// Read the marker of the next bundled to be read in the file. The bundle
+ /// name is returned if there is one in the file, or `std::nullopt` if there
+ /// are no more bundles to be read.
+ virtual Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) = 0;
+
+ /// Read the marker that closes the current bundle.
+ virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
+
+ /// Read the current bundle and write the result into the stream \a OS.
+ virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
+
+ /// Write the header of the bundled file to \a OS based on the information
+ /// gathered from \a Inputs.
+ virtual Error WriteHeader(raw_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
+
+ /// Write the marker that initiates a bundle for the triple \a TargetTriple to
+ /// \a OS.
+ virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
+
+ /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
+ /// OS.
+ virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
+
+ /// Write the bundle from \a Input into \a OS.
+ virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
+
+ /// Finalize output file.
+ virtual Error finalizeOutputFile() { return Error::success(); }
+
+ /// List bundle IDs in \a Input.
+ virtual Error listBundleIDs(MemoryBuffer &Input) {
+ if (Error Err = ReadHeader(Input))
+ return Err;
+ return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
+ llvm::outs() << Info.BundleID << '\n';
+ Error Err = listBundleIDsCallback(Input, Info);
+ if (Err)
+ return Err;
+ return Error::success();
+ });
+ }
+
+ /// Get bundle IDs in \a Input in \a BundleIds.
+ virtual Error getBundleIDs(MemoryBuffer &Input,
+ std::set<StringRef> &BundleIds) {
+ if (Error Err = ReadHeader(Input))
+ return Err;
+ return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
+ BundleIds.insert(Info.BundleID);
+ Error Err = listBundleIDsCallback(Input, Info);
+ if (Err)
+ return Err;
+ return Error::success();
+ });
+ }
+
+ /// For each bundle in \a Input, do \a Func.
+ Error forEachBundle(MemoryBuffer &Input,
+ std::function<Error(const BundleInfo &)> Func) {
+ while (true) {
+ Expected<std::optional<StringRef>> CurTripleOrErr =
+ ReadBundleStart(Input);
+ if (!CurTripleOrErr)
+ return CurTripleOrErr.takeError();
+
+ // No more bundles.
+ if (!*CurTripleOrErr)
+ break;
+
+ StringRef CurTriple = **CurTripleOrErr;
+ assert(!CurTriple.empty());
+
+ BundleInfo Info{CurTriple};
+ if (Error Err = Func(Info))
+ return Err;
+ }
+ return Error::success();
+ }
+
+protected:
+ virtual Error listBundleIDsCallback(MemoryBuffer &Input,
+ const BundleInfo &Info) {
+ return Error::success();
+ }
+};
+
+/// Handler for binary files. The bundled file will have the following format
+/// (all integers are stored in little-endian format):
+///
+/// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
+///
+/// NumberOfOffloadBundles (8-byte integer)
+///
+/// OffsetOfBundle1 (8-byte integer)
+/// SizeOfBundle1 (8-byte integer)
+/// NumberOfBytesInTripleOfBundle1 (8-byte integer)
+/// TripleOfBundle1 (byte length defined before)
+///
+/// ...
+///
+/// OffsetOfBundleN (8-byte integer)
+/// SizeOfBundleN (8-byte integer)
+/// NumberOfBytesInTripleOfBundleN (8-byte integer)
+/// TripleOfBundleN (byte length defined before)
+///
+/// Bundle1
+/// ...
+/// BundleN
+
+/// Read 8-byte integers from a buffer in little-endian format.
+static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
+ return llvm::support::endian::read64le(Buffer.data() + pos);
+}
+
+/// Write 8-byte integers to a buffer in little-endian format.
+static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
+ llvm::support::endian::write(OS, Val, llvm::endianness::little);
+}
+
+class BinaryFileHandler final : public FileHandler {
+ /// Information about the bundles extracted from the header.
+ struct BinaryBundleInfo final : public BundleInfo {
+ /// Size of the bundle.
+ uint64_t Size = 0u;
+ /// Offset at which the bundle starts in the bundled file.
+ uint64_t Offset = 0u;
+
+ BinaryBundleInfo() {}
+ BinaryBundleInfo(uint64_t Size, uint64_t Offset)
+ : Size(Size), Offset(Offset) {}
+ };
+
+ /// Map between a triple and the corresponding bundle information.
+ StringMap<BinaryBundleInfo> BundlesInfo;
+
+ /// Iterator for the bundle information that is being read.
+ StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
+ StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
+
+ /// Current bundle target to be written.
+ std::string CurWriteBundleTarget;
+
+ /// Configuration options and arrays for this bundler job
+ const OffloadBundlerConfig &BundlerConfig;
+
+public:
+ // TODO: Add error checking from ClangOffloadBundler.cpp
+ BinaryFileHandler(const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
+
+ ~BinaryFileHandler() final {}
+
+ Error ReadHeader(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Initialize the current bundle with the end of the container.
+ CurBundleInfo = BundlesInfo.end();
+
+ // Check if buffer is smaller than magic string.
+ size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
+ if (ReadChars > FC.size())
+ return Error::success();
+
+ // Check if no magic was found.
+ if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
+ return Error::success();
+
+ // Read number of bundles.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read bundle offsets, sizes and triples.
+ for (uint64_t i = 0; i < NumberOfBundles; ++i) {
+
+ // Read offset.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read size.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read triple size.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read triple.
+ if (ReadChars + TripleSize > FC.size())
+ return Error::success();
+
+ StringRef Triple(&FC.data()[ReadChars], TripleSize);
+ ReadChars += TripleSize;
+
+ // Check if the offset and size make sense.
+ if (!Offset || Offset + Size > FC.size())
+ return Error::success();
+
+ assert(!BundlesInfo.contains(Triple) && "Triple is duplicated??");
+ BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
+ }
+ // Set the iterator to where we will start to read.
+ CurBundleInfo = BundlesInfo.end();
+ NextBundleInfo = BundlesInfo.begin();
+ return Error::success();
+ }
+
+ Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) final {
+ if (NextBundleInfo == BundlesInfo.end())
+ return std::nullopt;
+ CurBundleInfo = NextBundleInfo++;
+ return CurBundleInfo->first();
+ }
+
+ Error ReadBundleEnd(MemoryBuffer &Input) final {
+ assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+ return Error::success();
+ }
+
+ Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+ StringRef FC = Input.getBuffer();
+ OS.write(FC.data() + CurBundleInfo->second.Offset,
+ CurBundleInfo->second.Size);
+ return Error::success();
+ }
+
+ Error WriteHeader(raw_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+
+ // Compute size of the header.
+ uint64_t HeaderSize = 0;
+
+ HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
+ HeaderSize += 8; // Number of Bundles
+
+ for (auto &T : BundlerConfig.TargetNames) {
+ HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
+ HeaderSize += T.size(); // The triple.
+ }
+
+ // Write to the buffer the header.
+ OS << OFFLOAD_BUNDLER_MAGIC_STR;
+
+ Write8byteIntegerToBuffer(OS, BundlerConfig.TargetNames.size());
+
+ unsigned Idx = 0;
+ for (auto &T : BundlerConfig.TargetNames) {
+ MemoryBuffer &MB = *Inputs[Idx++];
+ HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);
+ // Bundle offset.
+ Write8byteIntegerToBuffer(OS, HeaderSize);
+ // Size of the bundle (adds to the next bundle's offset)
+ Write8byteIntegerToBuffer(OS, MB.getBufferSize());
+ BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
+ HeaderSize += MB.getBufferSize();
+ // Size of the triple
+ Write8byteIntegerToBuffer(OS, T.size());
+ // Triple
+ OS << T;
+ }
+ return Error::success();
+ }
+
+ Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final {
+ CurWriteBundleTarget = TargetTriple.str();
+ return Error::success();
+ }
+
+ Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final {
+ return Error::success();
+ }
+
+ Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ auto BI = BundlesInfo[CurWriteBundleTarget];
+
+ // Pad with 0 to reach specified offset.
+ size_t CurrentPos = OS.tell();
+ size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
+ for (size_t I = 0; I < PaddingSize; ++I)
+ OS.write('\0');
+ assert(OS.tell() == BI.Offset);
+
+ OS.write(Input.getBufferStart(), Input.getBufferSize());
+
+ return Error::success();
+ }
+};
+
+// This class implements a list of temporary files that are removed upon
+// object destruction.
+class TempFileHandlerRAII {
+public:
+ ~TempFileHandlerRAII() {
+ for (const auto &File : Files)
+ sys::fs::remove(File);
+ }
+
+ // Creates temporary file with given contents.
+ Expected<StringRef> Create(std::optional<ArrayRef<char>> Contents) {
+ SmallString<128u> File;
+ if (std::error_code EC =
+ sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))
+ return createFileError(File, EC);
+ Files.push_front(File);
+
+ if (Contents) {
+ std::error_code EC;
+ raw_fd_ostream OS(File, EC);
+ if (EC)
+ return createFileError(File, EC);
+ OS.write(Contents->data(), Contents->size());
+ }
+ return Files.front().str();
+ }
+
+private:
+ std::forward_list<SmallString<128u>> Files;
+};
+
+/// Handler for object files. The bundles are organized by sections with a
+/// designated name.
+///
+/// To unbundle, we just copy the contents of the designated section.
+class ObjectFileHandler final : public FileHandler {
+
+ /// The object file we are currently dealing with.
+ std::unique_ptr<ObjectFile> Obj;
+
+ /// Return the input file contents.
+ StringRef getInputFileContents() const { return Obj->getData(); }
+
+ /// Return bundle name (<kind>-<triple>) if the provided section is an offload
+ /// section.
+ static Expected<std::optional<StringRef>>
+ IsOffloadSection(SectionRef CurSection) {
+ Expected<StringRef> NameOrErr = CurSection.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ // If it does not start with the reserved suffix, just skip this section.
+ if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
+ return std::nullopt;
+
+ // Return the triple that is right after the reserved prefix.
+ return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
+ }
+
+ /// Total number of inputs.
+ unsigned NumberOfInputs = 0;
+
+ /// Total number of processed inputs, i.e, inputs that were already
+ /// read from the buffers.
+ unsigned NumberOfProcessedInputs = 0;
+
+ /// Iterator of the current and next section.
+ section_iterator CurrentSection;
+ section_iterator NextSection;
+
+ /// Configuration options and arrays for this bundler job
+ const OffloadBundlerConfig &BundlerConfig;
+
+public:
+ // TODO: Add error checking from ClangOffloadBundler.cpp
+ ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
+ const OffloadBundlerConfig &BC)
+ : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
+ NextSection(Obj->section_begin()), BundlerConfig(BC) {}
+
+ ~ObjectFileHandler() final {}
+
+ Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
+
+ Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) final {
+ while (NextSection != Obj->section_end()) {
+ CurrentSection = NextSection;
+ ++NextSection;
+
+ // Check if the current section name starts with the reserved prefix. If
+ // so, return the triple.
+ Expected<std::optional<StringRef>> TripleOrErr =
+ IsOffloadSection(*CurrentSection);
+ if (!TripleOrErr)
+ return TripleOrErr.takeError();
+ if (*TripleOrErr)
+ return **TripleOrErr;
+ }
+ return std::nullopt;
+ }
+
+ Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
+
+ Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ Expected<StringRef> ContentOrErr = CurrentSection->getContents();
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+ StringRef Content = *ContentOrErr;
+
+ // Copy fat object contents to the output when extracting host bundle.
+ if (Content.size() == 1u && Content.front() == 0)
+ Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
+
+ OS.write(Content.data(), Content.size());
+ return Error::success();
+ }
+
+ Error WriteHeader(raw_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+ assert(BundlerConfig.HostInputIndex != ~0u &&
+ "Host input index not defined.");
+
+ // Record number of inputs.
+ NumberOfInputs = Inputs.size();
+ return Error::success();
+ }
+
+ Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final {
+ ++NumberOfProcessedInputs;
+ return Error::success();
+ }
+
+ Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final {
+ return Error::success();
+ }
+
+ Error finalizeOutputFile() final {
+ assert(NumberOfProcessedInputs <= NumberOfInputs &&
+ "Processing more inputs that actually exist!");
+ assert(BundlerConfig.HostInputIndex != ~0u &&
+ "Host input index not defined.");
+
+ // If this is not the last output, we don't have to do anything.
+ if (NumberOfProcessedInputs != NumberOfInputs)
+ return Error::success();
+
+ // We will use llvm-objcopy to add target objects sections to the output
+ // fat object. These sections should have 'exclude' flag set which tells
+ // link editor to remove them from linker inputs when linking executable or
+ // shared library.
+
+ assert(BundlerConfig.ObjcopyPath != "" &&
+ "llvm-objcopy path not specified");
+
+ // Temporary files that need to be removed.
+ TempFileHandlerRAII TempFiles;
+
+ // Compose llvm-objcopy command line for add target objects' sections with
+ // appropriate flags.
+ BumpPtrAllocator Alloc;
+ StringSaver SS{Alloc};
+ SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
+
+ for (unsigned I = 0; I < NumberOfInputs; ++I) {
+ StringRef InputFile = BundlerConfig.InputFileNames[I];
+ if (I == BundlerConfig.HostInputIndex) {
+ // Special handling for the host bundle. We do not need to add a
+ // standard bundle for the host object since we are going to use fat
+ // object as a host object. Therefore use dummy contents (one zero byte)
+ // when creating section for the host bundle.
+ Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+ InputFile = *TempFileOrErr;
+ }
+
+ ObjcopyArgs.push_back(
+ SS.save(Twine("--add-section=") + OFFLOAD_BUNDLER_MAGIC_STR +
+ BundlerConfig.TargetNames[I] + "=" + InputFile));
+ ObjcopyArgs.push_back(
+ SS.save(Twine("--set-section-flags=") + OFFLOAD_BUNDLER_MAGIC_STR +
+ BundlerConfig.TargetNames[I] + "=readonly,exclude"));
+ }
+ ObjcopyArgs.push_back("--");
+ ObjcopyArgs.push_back(
+ BundlerConfig.InputFileNames[BundlerConfig.HostInputIndex]);
+ ObjcopyArgs.push_back(BundlerConfig.OutputFileNames.front());
+
+ if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
+ return Err;
+
+ return Error::success();
+ }
+
+ Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ return Error::success();
+ }
+
+private:
+ Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
+ // If the user asked for the commands to be printed out, we do that
+ // instead of executing it.
+ if (BundlerConfig.PrintExternalCommands) {
+ errs() << "\"" << Objcopy << "\"";
+ for (StringRef Arg : drop_begin(Args, 1))
+ errs() << " \"" << Arg << "\"";
+ errs() << "\n";
+ } else {
+ if (sys::ExecuteAndWait(Objcopy, Args))
+ return createStringError(inconvertibleErrorCode(),
+ "'llvm-objcopy' tool failed");
+ }
+ return Error::success();
+ }
+};
+
+/// Handler for text files. The bundled file will have the following format.
+///
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
+/// Bundle 1
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
+/// ...
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
+/// Bundle N
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
+class TextFileHandler final : public FileHandler {
+ /// String that begins a line comment.
+ StringRef Comment;
+
+ /// String that initiates a bundle.
+ std::string BundleStartString;
+
+ /// String that closes a bundle.
+ std::string BundleEndString;
+
+ /// Number of chars read from input.
+ size_t ReadChars = 0u;
+
+protected:
+ Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
+
+ Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Find start of the bundle.
+ ReadChars = FC.find(BundleStartString, ReadChars);
+ if (ReadChars == FC.npos)
+ return std::nullopt;
+
+ // Get position of the triple.
+ size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
+
+ // Get position that closes the triple.
+ size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
+ if (TripleEnd == FC.npos)
+ return std::nullopt;
+
+ // Next time we read after the new line.
+ ++ReadChars;
+
+ return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
+ }
+
+ Error ReadBundleEnd(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Read up to the next new line.
+ assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
+
+ size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
+ if (TripleEnd != FC.npos)
+ // Next time we read after the new line.
+ ++ReadChars;
+
+ return Error::success();
+ }
+
+ Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+ size_t BundleStart = ReadChars;
+
+ // Find end of the bundle.
+ size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
+
+ StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
+ OS << Bundle;
+
+ return Error::success();
+ }
+
+ Error WriteHeader(raw_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+ return Error::success();
+ }
+
+ Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final {
+ OS << BundleStartString << TargetTriple << "\n";
+ return Error::success();
+ }
+
+ Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final {
+ OS << BundleEndString << TargetTriple << "\n";
+ return Error::success();
+ }
+
+ Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ OS << Input.getBuffer();
+ return Error::success();
+ }
+
+public:
+ TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
+ BundleStartString =
+ "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
+ BundleEndString =
+ "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
+ }
+
+ Error listBundleIDsCallback(MemoryBuffer &Input,
+ const BundleInfo &Info) final {
+ // TODO: To list bundle IDs in a bundled text file we need to go through
+ // all bundles. The format of bundled text file may need to include a
+ // header if the performance of listing bundle IDs of bundled text file is
+ // important.
+ ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
+ if (Error Err = ReadBundleEnd(Input))
+ return Err;
+ return Error::success();
+ }
+};
+} // namespace
+
+/// Return an appropriate object file handler. We use the specific object
+/// handler if we know how to deal with that format, otherwise we use a default
+/// binary file handler.
+static std::unique_ptr<FileHandler>
+CreateObjectFileHandler(MemoryBuffer &FirstInput,
+ const OffloadBundlerConfig &BundlerConfig) {
+ // Check if the input file format is one that we know how to deal with.
+ Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
+
+ // We only support regular object files. If failed to open the input as a
+ // known binary or this is not an object file use the default binary handler.
+ if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+
+ // Otherwise create an object file handler. The handler will be owned by the
+ // client of this function.
+ return std::make_unique<ObjectFileHandler>(
+ std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
+ BundlerConfig);
+}
+
+/// Return an appropriate handler given the input files and options.
+static Expected<std::unique_ptr<FileHandler>>
+CreateFileHandler(MemoryBuffer &FirstInput,
+ const OffloadBundlerConfig &BundlerConfig) {
+ std::string FilesType = BundlerConfig.FilesType;
+
+ if (FilesType == "i")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ if (FilesType == "ii")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ if (FilesType == "cui")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ if (FilesType == "hipi")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ // TODO: `.d` should be eventually removed once `-M` and its variants are
+ // handled properly in offload compilation.
+ if (FilesType == "d")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"#");
+ if (FilesType == "ll")
+ return std::make_unique<TextFileHandler>(/*Comment=*/";");
+ if (FilesType == "bc")
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+ if (FilesType == "s")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"#");
+ if (FilesType == "o")
+ return CreateObjectFileHandler(FirstInput, BundlerConfig);
+ if (FilesType == "a")
+ return CreateObjectFileHandler(FirstInput, BundlerConfig);
+ if (FilesType == "gch")
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+ if (FilesType == "ast")
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+
+ return createStringError(errc::invalid_argument,
+ "'" + FilesType + "': invalid file type specified");
+}
+
+OffloadBundlerConfig::OffloadBundlerConfig() {
+ auto IgnoreEnvVarOpt =
+ llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
+ if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() == "1")
+ return;
+
+ auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_VERBOSE");
+ if (VerboseEnvVarOpt.has_value())
+ Verbose = VerboseEnvVarOpt.value() == "1";
+
+ auto CompressEnvVarOpt =
+ llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESS");
+ if (CompressEnvVarOpt.has_value())
+ Compress = CompressEnvVarOpt.value() == "1";
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+CompressedOffloadBundle::compress(const llvm::MemoryBuffer &Input,
+ bool Verbose) {
+ llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
+ ClangOffloadBundlerTimerGroup);
+ if (Verbose)
+ HashTimer.startTimer();
+ llvm::MD5 Hash;
+ llvm::MD5::MD5Result Result;
+ Hash.update(Input.getBuffer());
+ Hash.final(Result);
+ uint64_t TruncatedHash = Result.low();
+ if (Verbose)
+ HashTimer.stopTimer();
+
+ SmallVector<uint8_t, 0> CompressedBuffer;
+ auto BufferUint8 = llvm::ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),
+ Input.getBuffer().size());
+
+ llvm::compression::Format CompressionFormat;
+
+ if (llvm::compression::zstd::isAvailable())
+ CompressionFormat = llvm::compression::Format::Zstd;
+ else if (llvm::compression::zlib::isAvailable())
+ CompressionFormat = llvm::compression::Format::Zlib;
+ else
+ return createStringError(llvm::inconvertibleErrorCode(),
+ "Compression not supported");
+
+ llvm::Timer CompressTimer("Compression Timer", "Compression time",
+ ClangOffloadBundlerTimerGroup);
+ if (Verbose)
+ CompressTimer.startTimer();
+ llvm::compression::compress(CompressionFormat, BufferUint8, CompressedBuffer);
+ if (Verbose)
+ CompressTimer.stopTimer();
+
+ uint16_t CompressionMethod = static_cast<uint16_t>(CompressionFormat);
+ uint32_t UncompressedSize = Input.getBuffer().size();
+
+ SmallVector<char, 0> FinalBuffer;
+ llvm::raw_svector_ostream OS(FinalBuffer);
+ OS << MagicNumber;
+ OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
+ OS.write(reinterpret_cast<const char *>(&CompressionMethod),
+ sizeof(CompressionMethod));
+ OS.write(reinterpret_cast<const char *>(&UncompressedSize),
+ sizeof(UncompressedSize));
+ OS.write(reinterpret_cast<const char *>(&TruncatedHash),
+ sizeof(TruncatedHash));
+ OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()),
+ CompressedBuffer.size());
+
+ if (Verbose) {
+ auto MethodUsed =
+ CompressionFormat == llvm::compression::Format::Zstd ? "zstd" : "zlib";
+ llvm::errs() << "Compressed bundle format version: " << Version << "\n"
+ << "Compression method used: " << MethodUsed << "\n"
+ << "Binary size before compression: " << UncompressedSize
+ << " bytes\n"
+ << "Binary size after compression: " << CompressedBuffer.size()
+ << " bytes\n"
+ << "Truncated MD5 hash: "
+ << llvm::format_hex(TruncatedHash, 16) << "\n";
+ }
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
+ bool Verbose) {
+
+ StringRef Blob = Input.getBuffer();
+
+ if (Blob.size() < HeaderSize) {
+ return llvm::MemoryBuffer::getMemBufferCopy(Blob);
+ }
+ if (llvm::identify_magic(Blob) !=
+ llvm::file_magic::offload_bundle_compressed) {
+ if (Verbose)
+ llvm::errs() << "Uncompressed bundle.\n";
+ return llvm::MemoryBuffer::getMemBufferCopy(Blob);
+ }
+
+ uint16_t ThisVersion;
+ uint16_t CompressionMethod;
+ uint32_t UncompressedSize;
+ uint64_t StoredHash;
+ memcpy(&ThisVersion, Input.getBuffer().data() + MagicNumber.size(),
+ sizeof(uint16_t));
+ memcpy(&CompressionMethod, Blob.data() + MagicSize + VersionFieldSize,
+ sizeof(uint16_t));
+ memcpy(&UncompressedSize,
+ Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize,
+ sizeof(uint32_t));
+ memcpy(&StoredHash,
+ Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize +
+ SizeFieldSize,
+ sizeof(uint64_t));
+
+ llvm::compression::Format CompressionFormat;
+ if (CompressionMethod ==
+ static_cast<uint16_t>(llvm::compression::Format::Zlib))
+ CompressionFormat = llvm::compression::Format::Zlib;
+ else if (CompressionMethod ==
+ static_cast<uint16_t>(llvm::compression::Format::Zstd))
+ CompressionFormat = llvm::compression::Format::Zstd;
+ else
+ return createStringError(inconvertibleErrorCode(),
+ "Unknown compressing method");
+
+ llvm::Timer DecompressTimer("Decompression Timer", "Decompression time",
+ ClangOffloadBundlerTimerGroup);
+ if (Verbose)
+ DecompressTimer.startTimer();
+
+ SmallVector<uint8_t, 0> DecompressedData;
+ StringRef CompressedData = Blob.substr(HeaderSize);
+ if (llvm::Error DecompressionError = llvm::compression::decompress(
+ CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
+ DecompressedData, UncompressedSize))
+ return createStringError(inconvertibleErrorCode(),
+ "Could not decompress embedded file contents: " +
+ llvm::toString(std::move(DecompressionError)));
+
+ if (Verbose) {
+ DecompressTimer.stopTimer();
+
+ // Recalculate MD5 hash
+ llvm::Timer HashRecalcTimer("Hash Recalculation Timer",
+ "Hash recalculation time",
+ ClangOffloadBundlerTimerGroup);
+ HashRecalcTimer.startTimer();
+ llvm::MD5 Hash;
+ llvm::MD5::MD5Result Result;
+ Hash.update(llvm::ArrayRef<uint8_t>(DecompressedData.data(),
+ DecompressedData.size()));
+ Hash.final(Result);
+ uint64_t RecalculatedHash = Result.low();
+ HashRecalcTimer.stopTimer();
+ bool HashMatch = (StoredHash == RecalculatedHash);
+
+ llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n"
+ << "Decompression method: "
+ << (CompressionFormat == llvm::compression::Format::Zlib
+ ? "zlib"
+ : "zstd")
+ << "\n"
+ << "Size before decompression: " << CompressedData.size()
+ << " bytes\n"
+ << "Size after decompression: " << UncompressedSize
+ << " bytes\n"
+ << "Stored hash: " << llvm::format_hex(StoredHash, 16) << "\n"
+ << "Recalculated hash: "
+ << llvm::format_hex(RecalculatedHash, 16) << "\n"
+ << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";
+ }
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::toStringRef(DecompressedData));
+}
+
+// List bundle IDs. Return true if an error was found.
+Error OffloadBundler::ListBundleIDsInFile(
+ StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig) {
+ // Open Input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(InputFileName);
+ if (std::error_code EC = CodeOrErr.getError())
+ return createFileError(InputFileName, EC);
+
+ // Decompress the input if necessary.
+ Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
+ CompressedOffloadBundle::decompress(**CodeOrErr, BundlerConfig.Verbose);
+ if (!DecompressedBufferOrErr)
+ return createStringError(
+ inconvertibleErrorCode(),
+ "Failed to decompress input: " +
+ llvm::toString(DecompressedBufferOrErr.takeError()));
+
+ MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
+
+ // Select the right files handler.
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(DecompressedInput, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+ assert(FH);
+ return FH->listBundleIDs(DecompressedInput);
+}
+
+/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
+/// target \p TargetInfo.
+/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
+bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
+ const OffloadTargetInfo &TargetInfo) {
+
+ // Compatible in case of exact match.
+ if (CodeObjectInfo == TargetInfo) {
+ DEBUG_WITH_TYPE("CodeObjectCompatibility",
+ dbgs() << "Compatible: Exact match: \t[CodeObject: "
+ << CodeObjectInfo.str()
+ << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
+ return true;
+ }
+
+ // Incompatible if Kinds or Triples mismatch.
+ if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
+ !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
+ << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
+ << "]\n");
+ return false;
+ }
+
+ // Incompatible if Processors mismatch.
+ llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
+ std::optional<StringRef> CodeObjectProc = clang::parseTargetID(
+ CodeObjectInfo.Triple, CodeObjectInfo.TargetID, &CodeObjectFeatureMap);
+ std::optional<StringRef> TargetProc = clang::parseTargetID(
+ TargetInfo.Triple, TargetInfo.TargetID, &TargetFeatureMap);
+
+ // Both TargetProc and CodeObjectProc can't be empty here.
+ if (!TargetProc || !CodeObjectProc ||
+ CodeObjectProc.value() != TargetProc.value()) {
+ DEBUG_WITH_TYPE("CodeObjectCompatibility",
+ dbgs() << "Incompatible: Processor mismatch \t[CodeObject: "
+ << CodeObjectInfo.str()
+ << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
+ return false;
+ }
+
+ // Incompatible if CodeObject has more features than Target, irrespective of
+ // type or sign of features.
+ if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
+ DEBUG_WITH_TYPE("CodeObjectCompatibility",
+ dbgs() << "Incompatible: CodeObject has more features "
+ "than target \t[CodeObject: "
+ << CodeObjectInfo.str()
+ << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
+ return false;
+ }
+
+ // Compatible if each target feature specified by target is compatible with
+ // target feature of code object. The target feature is compatible if the
+ // code object does not specify it (meaning Any), or if it specifies it
+ // with the same value (meaning On or Off).
+ for (const auto &CodeObjectFeature : CodeObjectFeatureMap) {
+ auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
+ if (TargetFeature == TargetFeatureMap.end()) {
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs()
+ << "Incompatible: Value of CodeObject's non-ANY feature is "
+ "not matching with Target feature's ANY value \t[CodeObject: "
+ << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
+ << "]\n");
+ return false;
+ } else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs() << "Incompatible: Value of CodeObject's non-ANY feature is "
+ "not matching with Target feature's non-ANY value "
+ "\t[CodeObject: "
+ << CodeObjectInfo.str()
+ << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
+ return false;
+ }
+ }
+
+ // CodeObject is compatible if all features of Target are:
+ // - either, present in the Code Object's features map with the same sign,
+ // - or, the feature is missing from CodeObjects's features map i.e. it is
+ // set to ANY
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs() << "Compatible: Target IDs are compatible \t[CodeObject: "
+ << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
+ << "]\n");
+ return true;
+}
+
+/// Bundle the files. Return true if an error was found.
+Error OffloadBundler::BundleFiles() {
+ std::error_code EC;
+
+ // Create a buffer to hold the content before compressing.
+ SmallVector<char, 0> Buffer;
+ llvm::raw_svector_ostream BufferStream(Buffer);
+
+ // Open input files.
+ SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
+ InputBuffers.reserve(BundlerConfig.InputFileNames.size());
+ for (auto &I : BundlerConfig.InputFileNames) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(I);
+ if (std::error_code EC = CodeOrErr.getError())
+ return createFileError(I, EC);
+ InputBuffers.emplace_back(std::move(*CodeOrErr));
+ }
+
+ // Get the file handler. We use the host buffer as reference.
+ assert((BundlerConfig.HostInputIndex != ~0u || BundlerConfig.AllowNoHost) &&
+ "Host input index undefined??");
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = CreateFileHandler(
+ *InputBuffers[BundlerConfig.AllowNoHost ? 0
+ : BundlerConfig.HostInputIndex],
+ BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+ assert(FH);
+
+ // Write header.
+ if (Error Err = FH->WriteHeader(BufferStream, InputBuffers))
+ return Err;
+
+ // Write all bundles along with the start/end markers. If an error was found
+ // writing the end of the bundle component, abort the bundle writing.
+ auto Input = InputBuffers.begin();
+ for (auto &Triple : BundlerConfig.TargetNames) {
+ if (Error Err = FH->WriteBundleStart(BufferStream, Triple))
+ return Err;
+ if (Error Err = FH->WriteBundle(BufferStream, **Input))
+ return Err;
+ if (Error Err = FH->WriteBundleEnd(BufferStream, Triple))
+ return Err;
+ ++Input;
+ }
+
+ raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC,
+ sys::fs::OF_None);
+ if (EC)
+ return createFileError(BundlerConfig.OutputFileNames.front(), EC);
+
+ SmallVector<char, 0> CompressedBuffer;
+ if (BundlerConfig.Compress) {
+ std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
+ llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(Buffer.data(), Buffer.size()));
+ auto CompressionResult =
+ CompressedOffloadBundle::compress(*BufferMemory, BundlerConfig.Verbose);
+ if (auto Error = CompressionResult.takeError())
+ return Error;
+
+ auto CompressedMemBuffer = std::move(CompressionResult.get());
+ CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
+ CompressedMemBuffer->getBufferEnd());
+ } else
+ CompressedBuffer = Buffer;
+
+ OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
+
+ return FH->finalizeOutputFile();
+}
+
+// Unbundle the files. Return true if an error was found.
+Error OffloadBundler::UnbundleFiles() {
+ // Open Input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(BundlerConfig.InputFileNames.front());
+ if (std::error_code EC = CodeOrErr.getError())
+ return createFileError(BundlerConfig.InputFileNames.front(), EC);
+
+ // Decompress the input if necessary.
+ Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
+ CompressedOffloadBundle::decompress(**CodeOrErr, BundlerConfig.Verbose);
+ if (!DecompressedBufferOrErr)
+ return createStringError(
+ inconvertibleErrorCode(),
+ "Failed to decompress input: " +
+ llvm::toString(DecompressedBufferOrErr.takeError()));
+
+ MemoryBuffer &Input = **DecompressedBufferOrErr;
+
+ // Select the right files handler.
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(Input, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+ assert(FH);
+
+ // Read the header of the bundled file.
+ if (Error Err = FH->ReadHeader(Input))
+ return Err;
+
+ // Create a work list that consist of the map triple/output file.
+ StringMap<StringRef> Worklist;
+ auto Output = BundlerConfig.OutputFileNames.begin();
+ for (auto &Triple : BundlerConfig.TargetNames) {
+ Worklist[Triple] = *Output;
+ ++Output;
+ }
+
+ // Read all the bundles that are in the work list. If we find no bundles we
+ // assume the file is meant for the host target.
+ bool FoundHostBundle = false;
+ while (!Worklist.empty()) {
+ Expected<std::optional<StringRef>> CurTripleOrErr =
+ FH->ReadBundleStart(Input);
+ if (!CurTripleOrErr)
+ return CurTripleOrErr.takeError();
+
+ // We don't have more bundles.
+ if (!*CurTripleOrErr)
+ break;
+
+ StringRef CurTriple = **CurTripleOrErr;
+ assert(!CurTriple.empty());
+
+ auto Output = Worklist.begin();
+ for (auto E = Worklist.end(); Output != E; Output++) {
+ if (isCodeObjectCompatible(
+ OffloadTargetInfo(CurTriple, BundlerConfig),
+ OffloadTargetInfo((*Output).first(), BundlerConfig))) {
+ break;
+ }
+ }
+
+ if (Output == Worklist.end())
+ continue;
+ // Check if the output file can be opened and copy the bundle to it.
+ std::error_code EC;
+ raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
+ if (EC)
+ return createFileError((*Output).second, EC);
+ if (Error Err = FH->ReadBundle(OutputFile, Input))
+ return Err;
+ if (Error Err = FH->ReadBundleEnd(Input))
+ return Err;
+ Worklist.erase(Output);
+
+ // Record if we found the host bundle.
+ auto OffloadInfo = OffloadTargetInfo(CurTriple, BundlerConfig);
+ if (OffloadInfo.hasHostKind())
+ FoundHostBundle = true;
+ }
+
+ if (!BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
+ std::string ErrMsg = "Can't find bundles for";
+ std::set<StringRef> Sorted;
+ for (auto &E : Worklist)
+ Sorted.insert(E.first());
+ unsigned I = 0;
+ unsigned Last = Sorted.size() - 1;
+ for (auto &E : Sorted) {
+ if (I != 0 && Last > 1)
+ ErrMsg += ",";
+ ErrMsg += " ";
+ if (I == Last && I != 0)
+ ErrMsg += "and ";
+ ErrMsg += E.str();
+ ++I;
+ }
+ return createStringError(inconvertibleErrorCode(), ErrMsg);
+ }
+
+ // If no bundles were found, assume the input file is the host bundle and
+ // create empty files for the remaining targets.
+ if (Worklist.size() == BundlerConfig.TargetNames.size()) {
+ for (auto &E : Worklist) {
+ std::error_code EC;
+ raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
+ if (EC)
+ return createFileError(E.second, EC);
+
+ // If this entry has a host kind, copy the input file to the output file.
+ auto OffloadInfo = OffloadTargetInfo(E.getKey(), BundlerConfig);
+ if (OffloadInfo.hasHostKind())
+ OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
+ }
+ return Error::success();
+ }
+
+ // If we found elements, we emit an error if none of those were for the host
+ // in case host bundle name was provided in command line.
+ if (!(FoundHostBundle || BundlerConfig.HostInputIndex == ~0u ||
+ BundlerConfig.AllowMissingBundles))
+ return createStringError(inconvertibleErrorCode(),
+ "Can't find bundle for the host target");
+
+ // If we still have any elements in the worklist, create empty files for them.
+ for (auto &E : Worklist) {
+ std::error_code EC;
+ raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
+ if (EC)
+ return createFileError(E.second, EC);
+ }
+
+ return Error::success();
+}
+
+static Archive::Kind getDefaultArchiveKindForHost() {
+ return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
+ : Archive::K_GNU;
+}
+
+/// @brief Computes a list of targets among all given targets which are
+/// compatible with this code object
+/// @param [in] CodeObjectInfo Code Object
+/// @param [out] CompatibleTargets List of all compatible targets among all
+/// given targets
+/// @return false, if no compatible target is found.
+static bool
+getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
+ SmallVectorImpl<StringRef> &CompatibleTargets,
+ const OffloadBundlerConfig &BundlerConfig) {
+ if (!CompatibleTargets.empty()) {
+ DEBUG_WITH_TYPE("CodeObjectCompatibility",
+ dbgs() << "CompatibleTargets list should be empty\n");
+ return false;
+ }
+ for (auto &Target : BundlerConfig.TargetNames) {
+ auto TargetInfo = OffloadTargetInfo(Target, BundlerConfig);
+ if (isCodeObjectCompatible(CodeObjectInfo, TargetInfo))
+ CompatibleTargets.push_back(Target);
+ }
+ return !CompatibleTargets.empty();
+}
+
+// Check that each code object file in the input archive conforms to following
+// rule: for a specific processor, a feature either shows up in all target IDs,
+// or does not show up in any target IDs. Otherwise the target ID combination is
+// invalid.
+static Error
+CheckHeterogeneousArchive(StringRef ArchiveName,
+ const OffloadBundlerConfig &BundlerConfig) {
+ std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFileOrSTDIN(ArchiveName, true, false);
+ if (std::error_code EC = BufOrErr.getError())
+ return createFileError(ArchiveName, EC);
+
+ ArchiveBuffers.push_back(std::move(*BufOrErr));
+ Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
+ Archive::create(ArchiveBuffers.back()->getMemBufferRef());
+ if (!LibOrErr)
+ return LibOrErr.takeError();
+
+ auto Archive = std::move(*LibOrErr);
+
+ Error ArchiveErr = Error::success();
+ auto ChildEnd = Archive->child_end();
+
+ /// Iterate over all bundled code object files in the input archive.
+ for (auto ArchiveIter = Archive->child_begin(ArchiveErr);
+ ArchiveIter != ChildEnd; ++ArchiveIter) {
+ if (ArchiveErr)
+ return ArchiveErr;
+ auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
+ if (!ArchiveChildNameOrErr)
+ return ArchiveChildNameOrErr.takeError();
+
+ auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
+ if (!CodeObjectBufferRefOrErr)
+ return CodeObjectBufferRefOrErr.takeError();
+
+ auto CodeObjectBuffer =
+ MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);
+
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(*CodeObjectBuffer, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
+ assert(FileHandler);
+
+ std::set<StringRef> BundleIds;
+ auto CodeObjectFileError =
+ FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
+ if (CodeObjectFileError)
+ return CodeObjectFileError;
+
+ auto &&ConflictingArchs = clang::getConflictTargetIDCombination(BundleIds);
+ if (ConflictingArchs) {
+ std::string ErrMsg =
+ Twine("conflicting TargetIDs [" + ConflictingArchs.value().first +
+ ", " + ConflictingArchs.value().second + "] found in " +
+ ArchiveChildNameOrErr.get() + " of " + ArchiveName)
+ .str();
+ return createStringError(inconvertibleErrorCode(), ErrMsg);
+ }
+ }
+
+ return ArchiveErr;
+}
+
+/// UnbundleArchive takes an archive file (".a") as input containing bundled
+/// code object files, and a list of offload targets (not host), and extracts
+/// the code objects into a new archive file for each offload target. Each
+/// resulting archive file contains all code object files corresponding to that
+/// particular offload target. The created archive file does not
+/// contain an index of the symbols and code object files are named as
+/// <<Parent Bundle Name>-<CodeObject's TargetID>>, with ':' replaced with '_'.
+Error OffloadBundler::UnbundleArchive() {
+ std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
+
+ /// Map of target names with list of object files that will form the device
+ /// specific archive for that target
+ StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
+
+ // Map of target names and output archive filenames
+ StringMap<StringRef> TargetOutputFileNameMap;
+
+ auto Output = BundlerConfig.OutputFileNames.begin();
+ for (auto &Target : BundlerConfig.TargetNames) {
+ TargetOutputFileNameMap[Target] = *Output;
+ ++Output;
+ }
+
+ StringRef IFName = BundlerConfig.InputFileNames.front();
+
+ if (BundlerConfig.CheckInputArchive) {
+ // For a specific processor, a feature either shows up in all target IDs, or
+ // does not show up in any target IDs. Otherwise the target ID combination
+ // is invalid.
+ auto ArchiveError = CheckHeterogeneousArchive(IFName, BundlerConfig);
+ if (ArchiveError) {
+ return ArchiveError;
+ }
+ }
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFileOrSTDIN(IFName, true, false);
+ if (std::error_code EC = BufOrErr.getError())
+ return createFileError(BundlerConfig.InputFileNames.front(), EC);
+
+ ArchiveBuffers.push_back(std::move(*BufOrErr));
+ Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
+ Archive::create(ArchiveBuffers.back()->getMemBufferRef());
+ if (!LibOrErr)
+ return LibOrErr.takeError();
+
+ auto Archive = std::move(*LibOrErr);
+
+ Error ArchiveErr = Error::success();
+ auto ChildEnd = Archive->child_end();
+
+ /// Iterate over all bundled code object files in the input archive.
+ for (auto ArchiveIter = Archive->child_begin(ArchiveErr);
+ ArchiveIter != ChildEnd; ++ArchiveIter) {
+ if (ArchiveErr)
+ return ArchiveErr;
+ auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
+ if (!ArchiveChildNameOrErr)
+ return ArchiveChildNameOrErr.takeError();
+
+ StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
+
+ auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
+ if (!CodeObjectBufferRefOrErr)
+ return CodeObjectBufferRefOrErr.takeError();
+
+ auto TempCodeObjectBuffer =
+ MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);
+
+ // Decompress the buffer if necessary.
+ Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr =
+ CompressedOffloadBundle::decompress(*TempCodeObjectBuffer,
+ BundlerConfig.Verbose);
+ if (!DecompressedBufferOrErr)
+ return createStringError(
+ inconvertibleErrorCode(),
+ "Failed to decompress code object: " +
+ llvm::toString(DecompressedBufferOrErr.takeError()));
+
+ MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
+
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(CodeObjectBuffer, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
+ assert(FileHandler &&
+ "FileHandle creation failed for file in the archive!");
+
+ if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer))
+ return ReadErr;
+
+ Expected<std::optional<StringRef>> CurBundleIDOrErr =
+ FileHandler->ReadBundleStart(CodeObjectBuffer);
+ if (!CurBundleIDOrErr)
+ return CurBundleIDOrErr.takeError();
+
+ std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
+ // No device code in this child, skip.
+ if (!OptionalCurBundleID)
+ continue;
+ StringRef CodeObject = *OptionalCurBundleID;
+
+ // Process all bundle entries (CodeObjects) found in this child of input
+ // archive.
+ while (!CodeObject.empty()) {
+ SmallVector<StringRef> CompatibleTargets;
+ auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig);
+ if (CodeObjectInfo.hasHostKind()) {
+ // Do nothing, we don't extract host code yet.
+ } else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
+ BundlerConfig)) {
+ std::string BundleData;
+ raw_string_ostream DataStream(BundleData);
+ if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
+ return Err;
+
+ for (auto &CompatibleTarget : CompatibleTargets) {
+ SmallString<128> BundledObjectFileName;
+ BundledObjectFileName.assign(BundledObjectFile);
+ auto OutputBundleName =
+ Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
+ CodeObject +
+ getDeviceLibraryFileName(BundledObjectFileName,
+ CodeObjectInfo.TargetID))
+ .str();
+ // Replace ':' in optional target feature list with '_' to ensure
+ // cross-platform validity.
+ std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
+ '_');
+
+ std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
+ DataStream.str(), OutputBundleName);
+ ArchiveBuffers.push_back(std::move(MemBuf));
+ llvm::MemoryBufferRef MemBufRef =
+ MemoryBufferRef(*(ArchiveBuffers.back()));
+
+ // For inserting <CompatibleTarget, list<CodeObject>> entry in
+ // OutputArchivesMap.
+ if (!OutputArchivesMap.contains(CompatibleTarget)) {
+
+ std::vector<NewArchiveMember> ArchiveMembers;
+ ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
+ OutputArchivesMap.insert_or_assign(CompatibleTarget,
+ std::move(ArchiveMembers));
+ } else {
+ OutputArchivesMap[CompatibleTarget].push_back(
+ NewArchiveMember(MemBufRef));
+ }
+ }
+ }
+
+ if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
+ return Err;
+
+ Expected<std::optional<StringRef>> NextTripleOrErr =
+ FileHandler->ReadBundleStart(CodeObjectBuffer);
+ if (!NextTripleOrErr)
+ return NextTripleOrErr.takeError();
+
+ CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr : "";
+ } // End of processing of all bundle entries of this child of input archive.
+ } // End of while over children of input archive.
+
+ assert(!ArchiveErr && "Error occurred while reading archive!");
+
+ /// Write out an archive for each target
+ for (auto &Target : BundlerConfig.TargetNames) {
+ StringRef FileName = TargetOutputFileNameMap[Target];
+ StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
+ OutputArchivesMap.find(Target);
+ if (CurArchiveMembers != OutputArchivesMap.end()) {
+ if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
+ SymtabWritingMode::NormalSymtab,
+ getDefaultArchiveKindForHost(), true,
+ false, nullptr))
+ return WriteErr;
+ } else if (!BundlerConfig.AllowMissingBundles) {
+ std::string ErrMsg =
+ Twine("no compatible code object found for the target '" + Target +
+ "' in heterogeneous archive library: " + IFName)
+ .str();
+ return createStringError(inconvertibleErrorCode(), ErrMsg);
+ } else { // Create an empty archive file if no compatible code object is
+ // found and "allow-missing-bundles" is enabled. It ensures that
+ // the linker using output of this step doesn't complain about
+ // the missing input file.
+ std::vector<llvm::NewArchiveMember> EmptyArchive;
+ EmptyArchive.clear();
+ if (Error WriteErr = writeArchive(
+ FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
+ getDefaultArchiveKindForHost(), true, false, nullptr))
+ return WriteErr;
+ }
+ }
+
+ return Error::success();
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
index 403fac76f060..56d497eb4c32 100644
--- a/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp
@@ -13,12 +13,14 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SpecialCaseList.h"
-#include "llvm/Support/AArch64TargetParser.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
+#include "llvm/TargetParser/TargetParser.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
#include <memory>
@@ -34,32 +36,33 @@ static const SanitizerMask NeedsUbsanRt =
static const SanitizerMask NeedsUbsanCxxRt =
SanitizerKind::Vptr | SanitizerKind::CFI;
static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
-static const SanitizerMask NotAllowedWithMinimalRuntime =
- SanitizerKind::Function | SanitizerKind::Vptr;
-static const SanitizerMask RequiresPIE =
- SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo;
+static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
+static const SanitizerMask NotAllowedWithExecuteOnly =
+ SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask NeedsUnwindTables =
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow;
static const SanitizerMask SupportsCoverage =
SanitizerKind::Address | SanitizerKind::HWAddress |
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
- SanitizerKind::MemTag | SanitizerKind::Memory |
+ SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
+ SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
SanitizerKind::KernelMemory | SanitizerKind::Leak |
SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
- SanitizerKind::Thread | SanitizerKind::ObjCCast;
+ SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
static const SanitizerMask RecoverableByDefault =
SanitizerKind::Undefined | SanitizerKind::Integer |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
static const SanitizerMask Unrecoverable =
SanitizerKind::Unreachable | SanitizerKind::Return;
-static const SanitizerMask AlwaysRecoverable =
- SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress;
+static const SanitizerMask AlwaysRecoverable = SanitizerKind::KernelAddress |
+ SanitizerKind::KernelHWAddress |
+ SanitizerKind::KCFI;
static const SanitizerMask NeedsLTO = SanitizerKind::CFI;
static const SanitizerMask TrappingSupported =
(SanitizerKind::Undefined & ~SanitizerKind::Vptr) | SanitizerKind::Integer |
@@ -73,7 +76,8 @@ static const SanitizerMask CFIClasses =
SanitizerKind::CFIUnrelatedCast;
static const SanitizerMask CompatibleWithMinimalRuntime =
TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack |
- SanitizerKind::MemTag;
+ SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
+ SanitizerKind::MemtagGlobals | SanitizerKind::KCFI;
enum CoverageFeature {
CoverageFunc = 1 << 0,
@@ -94,6 +98,13 @@ enum CoverageFeature {
CoverageInlineBoolFlag = 1 << 15,
CoverageTraceLoads = 1 << 16,
CoverageTraceStores = 1 << 17,
+ CoverageControlFlow = 1 << 18,
+};
+
+enum BinaryMetadataFeature {
+ BinaryMetadataCovered = 1 << 0,
+ BinaryMetadataAtomics = 1 << 1,
+ BinaryMetadataUAR = 1 << 2,
};
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -106,6 +117,11 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors);
+/// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid
+/// components. Returns OR of members of \c BinaryMetadataFeature enumeration.
+static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors);
+
/// Produce an argument string from ArgList \p Args, which shows how it
/// provides some sanitizer kind from \p Mask. For example, the argument list
/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
@@ -125,6 +141,16 @@ static std::string describeSanitizeArg(const llvm::opt::Arg *A,
/// Sanitizers set.
static std::string toString(const clang::SanitizerSet &Sanitizers);
+/// Return true if an execute-only target disallows data access to code
+/// sections.
+static bool isExecuteOnlyTarget(const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args) {
+ if (Triple.isPS5())
+ return true;
+ return Args.hasFlagNoClaim(options::OPT_mexecute_only,
+ options::OPT_mno_execute_only, false);
+}
+
static void validateSpecialCaseListFormat(const Driver &D,
std::vector<std::string> &SCLFiles,
unsigned MalformedSCLErrorDiagID,
@@ -164,18 +190,18 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
clang::SmallString<64> Path(D.ResourceDir);
llvm::sys::path::append(Path, "share", BL.File);
if (D.getVFS().exists(Path))
- IgnorelistFiles.push_back(std::string(Path.str()));
+ IgnorelistFiles.push_back(std::string(Path));
else if (BL.Mask == SanitizerKind::CFI && DiagnoseErrors)
// If cfi_ignorelist.txt cannot be found in the resource dir, driver
// should fail.
- D.Diag(clang::diag::err_drv_no_such_file) << Path;
+ D.Diag(clang::diag::err_drv_missing_sanitizer_ignorelist) << Path;
}
validateSpecialCaseListFormat(
D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist,
DiagnoseErrors);
}
-/// Parse -f(no-)?sanitize-(coverage-)?(white|ignore)list argument's values,
+/// Parse -f(no-)?sanitize-(coverage-)?(allow|ignore)list argument's values,
/// diagnosing any invalid file paths and validating special case list format.
static void parseSpecialCaseListArg(const Driver &D,
const llvm::opt::ArgList &Args,
@@ -185,7 +211,7 @@ static void parseSpecialCaseListArg(const Driver &D,
unsigned MalformedSCLErrorDiagID,
bool DiagnoseErrors) {
for (const auto *Arg : Args) {
- // Match -fsanitize-(coverage-)?(white|ignore)list.
+ // Match -fsanitize-(coverage-)?(allow|ignore)list.
if (Arg->getOption().matches(SCLOptionID)) {
Arg->claim();
std::string SCLPath = Arg->getValue();
@@ -218,9 +244,9 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
const llvm::opt::ArgList &Args,
bool DiagnoseErrors) {
- SanitizerMask TrapRemove; // During the loop below, the accumulated set of
- // sanitizers disabled by the current sanitizer
- // argument or any argument after it.
+ SanitizerMask TrapRemove; // During the loop below, the accumulated set of
+ // sanitizers disabled by the current sanitizer
+ // argument or any argument after it.
SanitizerMask TrappingKinds;
SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
@@ -233,8 +259,8 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
if (InvalidValues && DiagnoseErrors) {
SanitizerSet S;
S.Mask = InvalidValues;
- D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap"
- << toString(S);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << Arg->getSpelling() << toString(S);
}
TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
@@ -275,9 +301,7 @@ bool SanitizerArgs::needsCfiDiagRt() const {
CfiCrossDso && !ImplicitCfiRuntime;
}
-bool SanitizerArgs::requiresPIE() const {
- return NeedPIE || (Sanitizers.Mask & RequiresPIE);
-}
+bool SanitizerArgs::requiresPIE() const { return NeedPIE; }
bool SanitizerArgs::needsUnwindTables() const {
return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables);
@@ -293,13 +317,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask AllRemove; // During the loop below, the accumulated set of
// sanitizers disabled by the current sanitizer
// argument or any argument after it.
- SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by
- // -fsanitize= flags (directly or via group
- // expansion), some of which may be disabled
- // later. Used to carefully prune
- // unused-argument diagnostics.
- SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
- // Used to deduplicate diagnostics.
+ SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by
+ // -fsanitize= flags (directly or via group
+ // expansion), some of which may be disabled
+ // later. Used to carefully prune
+ // unused-argument diagnostics.
+ SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
+ // Used to deduplicate diagnostics.
SanitizerMask Kinds;
const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
@@ -367,6 +391,35 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Add &= ~NotAllowedWithMinimalRuntime;
}
+ if (llvm::opt::Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+ StringRef CM = A->getValue();
+ if (CM != "small" &&
+ (Add & SanitizerKind::Function & ~DiagnosedKinds)) {
+ if (DiagnoseErrors)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fsanitize=function"
+ << "-mcmodel=small";
+ Add &= ~SanitizerKind::Function;
+ DiagnosedKinds |= SanitizerKind::Function;
+ }
+ }
+ // -fsanitize=function and -fsanitize=kcfi instrument indirect function
+ // calls to load a type hash before the function label. Therefore, an
+ // execute-only target doesn't support the function and kcfi sanitizers.
+ const llvm::Triple &Triple = TC.getTriple();
+ if (isExecuteOnlyTarget(Triple, Args)) {
+ if (SanitizerMask KindsToDiagnose =
+ Add & NotAllowedWithExecuteOnly & ~DiagnosedKinds) {
+ if (DiagnoseErrors) {
+ std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << Desc << Triple.str();
+ }
+ DiagnosedKinds |= KindsToDiagnose;
+ }
+ Add &= ~NotAllowedWithExecuteOnly;
+ }
+
// FIXME: Make CFI on member function calls compatible with cross-DSO CFI.
// There are currently two problems:
// - Virtual function call checks need to pass a pointer to the function
@@ -402,7 +455,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if ((Add & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) {
if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) {
assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) &&
- "RTTI disabled without -fno-rtti option?");
+ "RTTI disabled without -fno-rtti option?");
// The user explicitly passed -fno-rtti with -fsanitize=vptr, but
// the vptr sanitizer requires RTTI, so this is a user error.
if (DiagnoseErrors)
@@ -428,6 +481,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (MinimalRuntime) {
Add &= ~NotAllowedWithMinimalRuntime;
}
+ // NotAllowedWithExecuteOnly is silently discarded on an execute-only
+ // target if implicitly enabled through group expansion.
+ if (isExecuteOnlyTarget(Triple, Args))
+ Add &= ~NotAllowedWithExecuteOnly;
if (CfiCrossDso)
Add &= ~SanitizerKind::CFIMFCall;
Add &= Supported;
@@ -487,7 +544,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
std::make_pair(SanitizerKind::MemTag,
SanitizerKind::Address | SanitizerKind::KernelAddress |
SanitizerKind::HWAddress |
- SanitizerKind::KernelHWAddress)};
+ SanitizerKind::KernelHWAddress),
+ std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)};
// Enable toolchain specific default sanitizers if not explicitly disabled.
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
@@ -513,10 +571,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
<< lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
}
- if ((Kinds & SanitizerKind::ShadowCallStack) &&
- ((TC.getTriple().isAArch64() &&
- !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) ||
- TC.getTriple().isRISCV()) &&
+ if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() &&
+ !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) &&
!Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) {
D.Diag(diag::err_drv_argument_only_allowed_with)
<< lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack)
@@ -576,7 +632,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SetToDiagnose.Mask |= KindsToDiagnose;
if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(SetToDiagnose);
+ << Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedUnrecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds |= expandSanitizerGroups(Add);
@@ -591,7 +647,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SetToDiagnose.Mask |= KindsToDiagnose;
if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(SetToDiagnose);
+ << Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds &= ~expandSanitizerGroups(Remove);
@@ -621,14 +677,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (AllAddedKinds & SanitizerKind::Memory) {
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
- options::OPT_fsanitize_memory_track_origins,
options::OPT_fno_sanitize_memory_track_origins)) {
- if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
- MsanTrackOrigins = 2;
- } else if (A->getOption().matches(
- options::OPT_fno_sanitize_memory_track_origins)) {
- MsanTrackOrigins = 0;
- } else {
+ if (!A->getOption().matches(
+ options::OPT_fno_sanitize_memory_track_origins)) {
StringRef S = A->getValue();
if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
MsanTrackOrigins > 2) {
@@ -638,20 +689,34 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
}
}
- MsanUseAfterDtor =
- Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor,
- options::OPT_fno_sanitize_memory_use_after_dtor,
- MsanUseAfterDtor);
+ MsanUseAfterDtor = Args.hasFlag(
+ options::OPT_fsanitize_memory_use_after_dtor,
+ options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor);
+ MsanParamRetval = Args.hasFlag(
+ options::OPT_fsanitize_memory_param_retval,
+ options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
+ } else if (AllAddedKinds & SanitizerKind::KernelMemory) {
+ MsanUseAfterDtor = false;
MsanParamRetval = Args.hasFlag(
options::OPT_fsanitize_memory_param_retval,
options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
- NeedPIE |= !(TC.getTriple().isOSLinux() &&
- TC.getTriple().getArch() == llvm::Triple::x86_64);
} else {
MsanUseAfterDtor = false;
MsanParamRetval = false;
}
+ if (AllAddedKinds & SanitizerKind::MemTag) {
+ StringRef S =
+ Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ, "sync");
+ if (S == "async" || S == "sync") {
+ MemtagMode = S.str();
+ } else {
+ D.Diag(clang::diag::err_drv_invalid_value_with_suggestion)
+ << "-fsanitize-memtag-mode=" << S << "{async, sync}";
+ MemtagMode = "sync";
+ }
+ }
+
if (AllAddedKinds & SanitizerKind::Thread) {
TsanMemoryAccess = Args.hasFlag(
options::OPT_fsanitize_thread_memory_access,
@@ -671,6 +736,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
CfiICallGeneralizePointers =
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
+ CfiICallNormalizeIntegers =
+ Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
+
if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fsanitize-cfi-cross-dso"
@@ -681,6 +749,16 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
options::OPT_fno_sanitize_cfi_canonical_jump_tables, true);
}
+ if (AllAddedKinds & SanitizerKind::KCFI) {
+ CfiICallNormalizeIntegers =
+ Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
+
+ if (AllAddedKinds & SanitizerKind::CFI && DiagnoseErrors)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=kcfi"
+ << lastArgumentForMask(D, Args, SanitizerKind::CFI);
+ }
+
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
options::OPT_fno_sanitize_stats, false);
@@ -758,26 +836,28 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard |
CoverageInline8bitCounters | CoverageTraceLoads |
- CoverageTraceStores | CoverageInlineBoolFlag;
+ CoverageTraceStores | CoverageInlineBoolFlag |
+ CoverageControlFlow;
if ((CoverageFeatures & InsertionPointTypes) &&
!(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) {
D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=[func|bb|edge]"
- << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
+ << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],["
+ "control-flow]";
}
// trace-pc w/o func/bb/edge implies edge.
if (!(CoverageFeatures & InsertionPointTypes)) {
if (CoverageFeatures &
(CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters |
- CoverageInlineBoolFlag))
+ CoverageInlineBoolFlag | CoverageControlFlow))
CoverageFeatures |= CoverageEdge;
if (CoverageFeatures & CoverageStackDepth)
CoverageFeatures |= CoverageFunc;
}
- // Parse -fsanitize-coverage-(ignore|white)list options if coverage enabled.
+ // Parse -fsanitize-coverage-(allow|ignore)list options if coverage enabled.
// This also validates special case lists format.
// Here, OptSpecifier() acts as a never-matching command-line argument.
// So, there is no way to clear coverage lists but you can append to them.
@@ -794,6 +874,32 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
DiagnoseErrors);
}
+ // Parse -f(no-)?sanitize-metadata.
+ for (const auto *Arg :
+ Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ,
+ options::OPT_fno_experimental_sanitize_metadata_EQ)) {
+ if (Arg->getOption().matches(
+ options::OPT_fexperimental_sanitize_metadata_EQ)) {
+ Arg->claim();
+ BinaryMetadataFeatures |=
+ parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+ } else {
+ Arg->claim();
+ BinaryMetadataFeatures &=
+ ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+ }
+ }
+
+ // Parse -fsanitize-metadata-ignorelist option if enabled.
+ if (BinaryMetadataFeatures) {
+ parseSpecialCaseListArg(
+ D, Args, BinaryMetadataIgnorelistFiles,
+ options::OPT_fexperimental_sanitize_metadata_ignorelist_EQ,
+ OptSpecifier(), // Cannot clear ignore list, only append.
+ clang::diag::err_drv_malformed_sanitizer_metadata_ignorelist,
+ DiagnoseErrors);
+ }
+
SharedRuntime =
Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
@@ -805,13 +911,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
NeedPIE |= TC.getTriple().isOSFuchsia();
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
- StringRef S = A->getValue();
- // Legal values are 0 and 1, 2, but in future we may add more levels.
- if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
- AsanFieldPadding > 2) &&
- DiagnoseErrors) {
- D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
- }
+ StringRef S = A->getValue();
+ // Legal values are 0 and 1, 2, but in future we may add more levels.
+ if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
+ AsanFieldPadding > 2) &&
+ DiagnoseErrors) {
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
}
if (Arg *WindowsDebugRTArg =
@@ -831,6 +937,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
}
+ StableABI = Args.hasFlag(options::OPT_fsanitize_stable_abi,
+ options::OPT_fno_sanitize_stable_abi, false);
+
AsanUseAfterScope = Args.hasFlag(
options::OPT_fsanitize_address_use_after_scope,
options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
@@ -845,18 +954,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
options::OPT_fno_sanitize_address_outline_instrumentation,
AsanOutlineInstrumentation);
- // As a workaround for a bug in gold 2.26 and earlier, dead stripping of
- // globals in ASan is disabled by default on ELF targets.
- // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
- AsanGlobalsDeadStripping =
- !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() ||
- TC.getTriple().isPS4() ||
- Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
+ AsanGlobalsDeadStripping = Args.hasFlag(
+ options::OPT_fsanitize_address_globals_dead_stripping,
+ options::OPT_fno_sanitize_address_globals_dead_stripping, true);
+ // Enable ODR indicators which allow better handling of mixed instrumented
+ // and uninstrumented globals. Disable them for Windows where weak odr
+ // indicators (.weak.__odr_asan_gen*) may cause multiple definition linker
+ // errors in the absence of -lldmingw.
AsanUseOdrIndicator =
Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator,
options::OPT_fno_sanitize_address_use_odr_indicator,
- AsanUseOdrIndicator);
+ !TC.getTriple().isOSWindows());
if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) {
AsanInvalidPointerCmp = true;
@@ -877,7 +986,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue());
if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
}
AsanDtorKind = parsedAsanDtorKind;
}
@@ -890,7 +999,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
llvm::AsanDetectStackUseAfterReturnMode::Invalid &&
DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
}
AsanUseAfterReturn = parsedAsanUseAfterReturn;
}
@@ -994,7 +1103,8 @@ static void addIncludeLinkerOption(const ToolChain &TC,
}
static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs) {
- for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End; ++Start) {
+ for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End;
+ ++Start) {
auto It = std::find(Start, End, StringRef("+mte"));
if (It == End)
break;
@@ -1011,13 +1121,16 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
// NVPTX doesn't currently support sanitizers. Bailing out here means
// that e.g. -fsanitize=address applies only to host code, which is what we
// want for now.
- //
- // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize.
- if (TC.getTriple().isNVPTX() ||
- (TC.getTriple().isAMDGPU() &&
- !Args.hasFlag(options::OPT_fgpu_sanitize,
- options::OPT_fno_gpu_sanitize)))
+ if (TC.getTriple().isNVPTX())
return;
+ // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize.
+ bool GPUSanitize = false;
+ if (TC.getTriple().isAMDGPU()) {
+ if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
+ true))
+ return;
+ GPUSanitize = true;
+ }
// Translate available CoverageFeatures to corresponding clang-cc1 flags.
// Do it even if Sanitizers.empty() since some forms of coverage don't require
@@ -1043,7 +1156,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"),
std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"),
- std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores")};
+ std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"),
+ std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
CmdArgs.push_back(F.second);
@@ -1053,6 +1167,23 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=",
CoverageIgnorelistFiles);
+ if (!GPUSanitize) {
+ // Translate available BinaryMetadataFeatures to corresponding clang-cc1
+ // flags. Does not depend on any other sanitizers. Unsupported on GPUs.
+ const std::pair<int, std::string> BinaryMetadataFlags[] = {
+ std::make_pair(BinaryMetadataCovered, "covered"),
+ std::make_pair(BinaryMetadataAtomics, "atomics"),
+ std::make_pair(BinaryMetadataUAR, "uar")};
+ for (const auto &F : BinaryMetadataFlags) {
+ if (BinaryMetadataFeatures & F.first)
+ CmdArgs.push_back(
+ Args.MakeArgString("-fexperimental-sanitize-metadata=" + F.second));
+ }
+ addSpecialCaseListOpt(Args, CmdArgs,
+ "-fexperimental-sanitize-metadata-ignorelist=",
+ BinaryMetadataIgnorelistFiles);
+ }
+
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
// Instruct the code generator to embed linker directives in the object file
// that cause the required runtime libraries to be linked.
@@ -1101,8 +1232,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (MsanUseAfterDtor)
CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
- if (MsanParamRetval)
- CmdArgs.push_back("-fsanitize-memory-param-retval");
+ if (!MsanParamRetval)
+ CmdArgs.push_back("-fno-sanitize-memory-param-retval");
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
if (!TsanMemoryAccess) {
@@ -1131,6 +1262,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (CfiICallGeneralizePointers)
CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
+ if (CfiICallNormalizeIntegers)
+ CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers");
+
if (CfiCanonicalJumpTables)
CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
@@ -1153,8 +1287,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (AsanGlobalsDeadStripping)
CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
- if (AsanUseOdrIndicator)
- CmdArgs.push_back("-fsanitize-address-use-odr-indicator");
+ if (!AsanUseOdrIndicator)
+ CmdArgs.push_back("-fno-sanitize-address-use-odr-indicator");
if (AsanInvalidPointerCmp) {
CmdArgs.push_back("-mllvm");
@@ -1171,6 +1305,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0");
}
+ // When emitting Stable ABI instrumentation, force outlining calls and avoid
+ // inlining shadow memory poisoning. While this is a big performance burden
+ // for now it allows full abstraction from implementation details.
+ if (StableABI) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-asan-max-inline-poisoning-size=0");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-asan-guard-against-version-mismatch=0");
+ }
+
// Only pass the option to the frontend if the user requested,
// otherwise the frontend will just use the codegen default.
if (AsanDtorKind != llvm::AsanDtorKind::Invalid) {
@@ -1230,7 +1376,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
<< "-fvisibility=";
}
- if (Sanitizers.has(SanitizerKind::MemTag) && !hasTargetFeatureMTE(CmdArgs))
+ if (Sanitizers.has(SanitizerKind::MemtagStack) &&
+ !hasTargetFeatureMTE(CmdArgs))
TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature);
}
@@ -1258,7 +1405,7 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
Kinds |= Kind;
else if (DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
return Kinds;
}
@@ -1289,10 +1436,34 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
.Case("stack-depth", CoverageStackDepth)
.Case("trace-loads", CoverageTraceLoads)
.Case("trace-stores", CoverageTraceStores)
+ .Case("control-flow", CoverageControlFlow)
+ .Default(0);
+ if (F == 0 && DiagnoseErrors)
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Value;
+ Features |= F;
+ }
+ return Features;
+}
+
+int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors) {
+ assert(
+ A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) ||
+ A->getOption().matches(
+ options::OPT_fno_experimental_sanitize_metadata_EQ));
+ int Features = 0;
+ for (int i = 0, n = A->getNumValues(); i != n; ++i) {
+ const char *Value = A->getValue(i);
+ int F = llvm::StringSwitch<int>(Value)
+ .Case("covered", BinaryMetadataCovered)
+ .Case("atomics", BinaryMetadataAtomics)
+ .Case("uar", BinaryMetadataUAR)
+ .Case("all", ~0)
.Default(0);
if (F == 0 && DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
Features |= F;
}
return Features;
@@ -1319,8 +1490,8 @@ std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
}
std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) {
- assert(A->getOption().matches(options::OPT_fsanitize_EQ)
- && "Invalid argument in describeSanitizerArg!");
+ assert(A->getOption().matches(options::OPT_fsanitize_EQ) &&
+ "Invalid argument in describeSanitizerArg!");
std::string Sanitizers;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp
index d657d21bfcdb..388030592b48 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp
@@ -7,8 +7,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/ToolChain.h"
+#include "ToolChains/Arch/AArch64.h"
#include "ToolChains/Arch/ARM.h"
#include "ToolChains/Clang.h"
+#include "ToolChains/CommonArgs.h"
#include "ToolChains/Flang.h"
#include "ToolChains/InterfaceStubs.h"
#include "clang/Basic/ObjCRuntime.h"
@@ -24,8 +26,8 @@
#include "clang/Driver/XRayArgs.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/MC/MCTargetOptions.h"
@@ -36,10 +38,13 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/TargetParser.h"
+#include "llvm/TargetParser/Triple.h"
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -67,8 +72,9 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args,
return ToolChain::RM_Disabled;
}
- // -frtti is default, except for the PS4 CPU.
- return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled;
+ // -frtti is default, except for the PS4/PS5 and DriverKit.
+ bool NoRTTI = Triple.isPS() || Triple.isDriverKit();
+ return NoRTTI ? ToolChain::RM_Disabled : ToolChain::RM_Enabled;
}
ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
@@ -80,11 +86,39 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
List.push_back(Path);
};
- for (const auto &Path : getRuntimePaths())
- addIfExists(getLibraryPaths(), Path);
- for (const auto &Path : getStdlibPaths())
+ if (std::optional<std::string> Path = getRuntimePath())
+ getLibraryPaths().push_back(*Path);
+ if (std::optional<std::string> Path = getStdlibPath())
+ getFilePaths().push_back(*Path);
+ for (const auto &Path : getArchSpecificLibPaths())
addIfExists(getFilePaths(), Path);
- addIfExists(getFilePaths(), getArchSpecificLibPath());
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ToolChain::executeToolChainProgram(StringRef Executable) const {
+ llvm::SmallString<64> OutputFile;
+ llvm::sys::fs::createTemporaryFile("toolchain-program", "txt", OutputFile);
+ llvm::FileRemover OutputRemover(OutputFile.c_str());
+ std::optional<llvm::StringRef> Redirects[] = {
+ {""},
+ OutputFile.str(),
+ {""},
+ };
+
+ std::string ErrorMessage;
+ if (llvm::sys::ExecuteAndWait(Executable, {}, {}, Redirects,
+ /* SecondsToWait */ 0,
+ /*MemoryLimit*/ 0, &ErrorMessage))
+ return llvm::createStringError(std::error_code(),
+ Executable + ": " + ErrorMessage);
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
+ llvm::MemoryBuffer::getFile(OutputFile.c_str());
+ if (!OutputBuf)
+ return llvm::createStringError(OutputBuf.getError(),
+ "Failed to read stdout of " + Executable +
+ ": " + OutputBuf.getError().message());
+ return std::move(*OutputBuf);
}
void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) {
@@ -105,6 +139,34 @@ bool ToolChain::useIntegratedAs() const {
IsIntegratedAssemblerDefault());
}
+bool ToolChain::useIntegratedBackend() const {
+ assert(
+ ((IsIntegratedBackendDefault() && IsIntegratedBackendSupported()) ||
+ (!IsIntegratedBackendDefault() || IsNonIntegratedBackendSupported())) &&
+ "(Non-)integrated backend set incorrectly!");
+
+ bool IBackend = Args.hasFlag(options::OPT_fintegrated_objemitter,
+ options::OPT_fno_integrated_objemitter,
+ IsIntegratedBackendDefault());
+
+ // Diagnose when integrated-objemitter options are not supported by this
+ // toolchain.
+ unsigned DiagID;
+ if ((IBackend && !IsIntegratedBackendSupported()) ||
+ (!IBackend && !IsNonIntegratedBackendSupported()))
+ DiagID = clang::diag::err_drv_unsupported_opt_for_target;
+ else
+ DiagID = clang::diag::warn_drv_unsupported_opt_for_target;
+ Arg *A = Args.getLastArg(options::OPT_fno_integrated_objemitter);
+ if (A && !IsNonIntegratedBackendSupported())
+ D.Diag(DiagID) << A->getAsString(Args) << Triple.getTriple();
+ A = Args.getLastArg(options::OPT_fintegrated_objemitter);
+ if (A && !IsIntegratedBackendSupported())
+ D.Diag(DiagID) << A->getAsString(Args) << Triple.getTriple();
+
+ return IBackend;
+}
+
bool ToolChain::useRelaxRelocations() const {
return ENABLE_X86_RELAX_RELOCATIONS;
}
@@ -113,6 +175,101 @@ bool ToolChain::defaultToIEEELongDouble() const {
return PPC_LINUX_DEFAULT_IEEELONGDOUBLE && getTriple().isOSLinux();
}
+static void getAArch64MultilibFlags(const Driver &D,
+ const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ Multilib::flags_list &Result) {
+ std::vector<StringRef> Features;
+ tools::aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, false);
+ const auto UnifiedFeatures = tools::unifyTargetFeatures(Features);
+ llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(),
+ UnifiedFeatures.end());
+ std::vector<std::string> MArch;
+ for (const auto &Ext : AArch64::Extensions)
+ if (FeatureSet.contains(Ext.Feature))
+ MArch.push_back(Ext.Name.str());
+ for (const auto &Ext : AArch64::Extensions)
+ if (FeatureSet.contains(Ext.NegFeature))
+ MArch.push_back(("no" + Ext.Name).str());
+ MArch.insert(MArch.begin(), ("-march=" + Triple.getArchName()).str());
+ Result.push_back(llvm::join(MArch, "+"));
+}
+
+static void getARMMultilibFlags(const Driver &D,
+ const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ Multilib::flags_list &Result) {
+ std::vector<StringRef> Features;
+ llvm::ARM::FPUKind FPUKind = tools::arm::getARMTargetFeatures(
+ D, Triple, Args, Features, false /*ForAs*/, true /*ForMultilib*/);
+ const auto UnifiedFeatures = tools::unifyTargetFeatures(Features);
+ llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(),
+ UnifiedFeatures.end());
+ std::vector<std::string> MArch;
+ for (const auto &Ext : ARM::ARCHExtNames)
+ if (FeatureSet.contains(Ext.Feature))
+ MArch.push_back(Ext.Name.str());
+ for (const auto &Ext : ARM::ARCHExtNames)
+ if (FeatureSet.contains(Ext.NegFeature))
+ MArch.push_back(("no" + Ext.Name).str());
+ MArch.insert(MArch.begin(), ("-march=" + Triple.getArchName()).str());
+ Result.push_back(llvm::join(MArch, "+"));
+
+ switch (FPUKind) {
+#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) \
+ case llvm::ARM::KIND: \
+ Result.push_back("-mfpu=" NAME); \
+ break;
+#include "llvm/TargetParser/ARMTargetParser.def"
+ default:
+ llvm_unreachable("Invalid FPUKind");
+ }
+
+ switch (arm::getARMFloatABI(D, Triple, Args)) {
+ case arm::FloatABI::Soft:
+ Result.push_back("-mfloat-abi=soft");
+ break;
+ case arm::FloatABI::SoftFP:
+ Result.push_back("-mfloat-abi=softfp");
+ break;
+ case arm::FloatABI::Hard:
+ Result.push_back("-mfloat-abi=hard");
+ break;
+ case arm::FloatABI::Invalid:
+ llvm_unreachable("Invalid float ABI");
+ }
+}
+
+Multilib::flags_list
+ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const {
+ using namespace clang::driver::options;
+
+ std::vector<std::string> Result;
+ const llvm::Triple Triple(ComputeEffectiveClangTriple(Args));
+ Result.push_back("--target=" + Triple.str());
+
+ switch (Triple.getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64_be:
+ getAArch64MultilibFlags(D, Triple, Args, Result);
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ getARMMultilibFlags(D, Triple, Args, Result);
+ break;
+ default:
+ break;
+ }
+
+ // Sort and remove duplicates.
+ std::sort(Result.begin(), Result.end());
+ Result.erase(std::unique(Result.begin(), Result.end()), Result.end());
+ return Result;
+}
+
SanitizerArgs
ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const {
SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked);
@@ -121,9 +278,9 @@ ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const {
}
const XRayArgs& ToolChain::getXRayArgs() const {
- if (!XRayArguments.get())
+ if (!XRayArguments)
XRayArguments.reset(new XRayArgs(*this, Args));
- return *XRayArguments.get();
+ return *XRayArguments;
}
namespace {
@@ -153,13 +310,14 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
{"cl", "--driver-mode=cl"},
{"++", "--driver-mode=g++"},
{"flang", "--driver-mode=flang"},
+ {"clang-dxc", "--driver-mode=dxc"},
};
- for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) {
- StringRef Suffix(DriverSuffixes[i].Suffix);
- if (ProgName.endswith(Suffix)) {
+ for (const auto &DS : DriverSuffixes) {
+ StringRef Suffix(DS.Suffix);
+ if (ProgName.ends_with(Suffix)) {
Pos = ProgName.size() - Suffix.size();
- return &DriverSuffixes[i];
+ return &DS;
}
}
return nullptr;
@@ -168,7 +326,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
/// Normalize the program name from argv[0] by stripping the file extension if
/// present and lower-casing the string on Windows.
static std::string normalizeProgramName(llvm::StringRef Argv0) {
- std::string ProgName = std::string(llvm::sys::path::stem(Argv0));
+ std::string ProgName = std::string(llvm::sys::path::filename(Argv0));
if (is_style_windows(llvm::sys::path::Style::native)) {
// Transform to lowercase for case insensitive file systems.
std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
@@ -187,6 +345,13 @@ static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
// added via -target as implicit first argument.
const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
+ if (!DS && ProgName.ends_with(".exe")) {
+ // Try again after stripping the executable suffix:
+ // clang++.exe -> clang++
+ ProgName = ProgName.drop_back(StringRef(".exe").size());
+ DS = FindDriverSuffix(ProgName, Pos);
+ }
+
if (!DS) {
// Try again after stripping any trailing version number:
// clang++3.5 -> clang++
@@ -257,8 +422,15 @@ std::string ToolChain::getInputFilename(const InputInfo &Input) const {
return Input.getFilename();
}
-bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
- return false;
+ToolChain::UnwindTableLevel
+ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
+ return UnwindTableLevel::None;
+}
+
+unsigned ToolChain::GetDefaultDwarfVersion() const {
+ // TODO: Remove the RISC-V special case when R_RISCV_SET_ULEB128 linker
+ // support becomes more widely available.
+ return getTriple().isRISCV() ? 4 : 5;
}
Tool *ToolChain::getClang() const {
@@ -321,10 +493,10 @@ Tool *ToolChain::getOffloadBundler() const {
return OffloadBundler.get();
}
-Tool *ToolChain::getOffloadWrapper() const {
- if (!OffloadWrapper)
- OffloadWrapper.reset(new tools::OffloadWrapper(*this));
- return OffloadWrapper.get();
+Tool *ToolChain::getOffloadPackager() const {
+ if (!OffloadPackager)
+ OffloadPackager.reset(new tools::OffloadPackager(*this));
+ return OffloadPackager.get();
}
Tool *ToolChain::getLinkerWrapper() const {
@@ -353,12 +525,13 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::LipoJobClass:
case Action::DsymutilJobClass:
case Action::VerifyDebugInfoJobClass:
+ case Action::BinaryAnalyzeJobClass:
llvm_unreachable("Invalid tool kind.");
case Action::CompileJobClass:
case Action::PrecompileJobClass:
- case Action::HeaderModulePrecompileJobClass:
case Action::PreprocessJobClass:
+ case Action::ExtractAPIJobClass:
case Action::AnalyzeJobClass:
case Action::MigrateJobClass:
case Action::VerifyPCHJobClass:
@@ -369,8 +542,8 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::OffloadUnbundlingJobClass:
return getOffloadBundler();
- case Action::OffloadWrapperJobClass:
- return getOffloadWrapper();
+ case Action::OffloadPackagerJobClass:
+ return getOffloadPackager();
case Action::LinkerWrapperJobClass:
return getLinkerWrapper();
}
@@ -383,6 +556,9 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
const llvm::Triple &Triple = TC.getTriple();
bool IsWindows = Triple.isOSWindows();
+ if (TC.isBareMetal())
+ return Triple.getArchName();
+
if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb)
return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows)
? "armhf"
@@ -420,12 +596,17 @@ StringRef ToolChain::getOSLibName() const {
std::string ToolChain::getCompilerRTPath() const {
SmallString<128> Path(getDriver().ResourceDir);
- if (Triple.isOSUnknown()) {
+ if (isBareMetal()) {
+ llvm::sys::path::append(Path, "lib", getOSLibName());
+ if (!SelectedMultilibs.empty()) {
+ Path += SelectedMultilibs.back().gccSuffix();
+ }
+ } else if (Triple.isOSUnknown()) {
llvm::sys::path::append(Path, "lib");
} else {
llvm::sys::path::append(Path, "lib", getOSLibName());
}
- return std::string(Path.str());
+ return std::string(Path);
}
std::string ToolChain::getCompilerRTBasename(const ArgList &Args,
@@ -478,7 +659,7 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
SmallString<128> P(LibPath);
llvm::sys::path::append(P, CRTBasename);
if (getVFS().exists(P))
- return std::string(P.str());
+ return std::string(P);
}
// Fall back to the old expected compiler-rt name if the new one does not
@@ -487,7 +668,7 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/true);
SmallString<128> Path(getCompilerRTPath());
llvm::sys::path::append(Path, CRTBasename);
- return std::string(Path.str());
+ return std::string(Path);
}
const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args,
@@ -496,42 +677,118 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args,
return Args.MakeArgString(getCompilerRT(Args, Component, Type));
}
-ToolChain::path_list ToolChain::getRuntimePaths() const {
- path_list Paths;
- auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "lib", Triple.str());
- Paths.push_back(std::string(P.str()));
+// Android target triples contain a target version. If we don't have libraries
+// for the exact target version, we should fall back to the next newest version
+// or a versionless path, if any.
+std::optional<std::string>
+ToolChain::getFallbackAndroidTargetPath(StringRef BaseDir) const {
+ llvm::Triple TripleWithoutLevel(getTriple());
+ TripleWithoutLevel.setEnvironmentName("android"); // remove any version number
+ const std::string &TripleWithoutLevelStr = TripleWithoutLevel.str();
+ unsigned TripleVersion = getTriple().getEnvironmentVersion().getMajor();
+ unsigned BestVersion = 0;
+
+ SmallString<32> TripleDir;
+ bool UsingUnversionedDir = false;
+ std::error_code EC;
+ for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(BaseDir, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef DirName = llvm::sys::path::filename(LI->path());
+ StringRef DirNameSuffix = DirName;
+ if (DirNameSuffix.consume_front(TripleWithoutLevelStr)) {
+ if (DirNameSuffix.empty() && TripleDir.empty()) {
+ TripleDir = DirName;
+ UsingUnversionedDir = true;
+ } else {
+ unsigned Version;
+ if (!DirNameSuffix.getAsInteger(10, Version) && Version > BestVersion &&
+ Version < TripleVersion) {
+ BestVersion = Version;
+ TripleDir = DirName;
+ UsingUnversionedDir = false;
+ }
+ }
+ }
+ }
+
+ if (TripleDir.empty())
+ return {};
+
+ SmallString<128> P(BaseDir);
+ llvm::sys::path::append(P, TripleDir);
+ if (UsingUnversionedDir)
+ D.Diag(diag::warn_android_unversioned_fallback) << P << getTripleString();
+ return std::string(P);
+}
+
+std::optional<std::string>
+ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
+ auto getPathForTriple =
+ [&](const llvm::Triple &Triple) -> std::optional<std::string> {
+ SmallString<128> P(BaseDir);
+ llvm::sys::path::append(P, Triple.str());
+ if (getVFS().exists(P))
+ return std::string(P);
+ return {};
};
- addPathForTriple(getTriple());
+ if (auto Path = getPathForTriple(getTriple()))
+ return *Path;
- // Android targets may include an API level at the end. We still want to fall
- // back on a path without the API level.
- if (getTriple().isAndroid() &&
- getTriple().getEnvironmentName() != "android") {
- llvm::Triple TripleWithoutLevel = getTriple();
- TripleWithoutLevel.setEnvironmentName("android");
- addPathForTriple(TripleWithoutLevel);
+ // When building with per target runtime directories, various ways of naming
+ // the Arm architecture may have been normalised to simply "arm".
+ // For example "armv8l" (Armv8 AArch32 little endian) is replaced with "arm".
+ // Since an armv8l system can use libraries built for earlier architecture
+ // versions assuming endian and float ABI match.
+ //
+ // Original triple: armv8l-unknown-linux-gnueabihf
+ // Runtime triple: arm-unknown-linux-gnueabihf
+ //
+ // We do not do this for armeb (big endian) because doing so could make us
+ // select little endian libraries. In addition, all known armeb triples only
+ // use the "armeb" architecture name.
+ //
+ // M profile Arm is bare metal and we know they will not be using the per
+ // target runtime directory layout.
+ if (getTriple().getArch() == Triple::arm && !getTriple().isArmMClass()) {
+ llvm::Triple ArmTriple = getTriple();
+ ArmTriple.setArch(Triple::arm);
+ if (auto Path = getPathForTriple(ArmTriple))
+ return *Path;
}
- return Paths;
+ if (getTriple().isAndroid())
+ return getFallbackAndroidTargetPath(BaseDir);
+
+ return {};
}
-ToolChain::path_list ToolChain::getStdlibPaths() const {
- path_list Paths;
- SmallString<128> P(D.Dir);
- llvm::sys::path::append(P, "..", "lib", getTripleString());
- Paths.push_back(std::string(P.str()));
+std::optional<std::string> ToolChain::getRuntimePath() const {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "lib");
+ return getTargetSubDirPath(P);
+}
- return Paths;
+std::optional<std::string> ToolChain::getStdlibPath() const {
+ SmallString<128> P(D.Dir);
+ llvm::sys::path::append(P, "..", "lib");
+ return getTargetSubDirPath(P);
}
-std::string ToolChain::getArchSpecificLibPath() const {
- SmallString<128> Path(getDriver().ResourceDir);
- llvm::sys::path::append(Path, "lib", getOSLibName(),
- llvm::Triple::getArchTypeName(getArch()));
- return std::string(Path.str());
+ToolChain::path_list ToolChain::getArchSpecificLibPaths() const {
+ path_list Paths;
+
+ auto AddPath = [&](const ArrayRef<StringRef> &SS) {
+ SmallString<128> Path(getDriver().ResourceDir);
+ llvm::sys::path::append(Path, "lib");
+ for (auto &S : SS)
+ llvm::sys::path::append(Path, S);
+ Paths.push_back(std::string(Path));
+ };
+
+ AddPath({getTriple().str()});
+ AddPath({getOSLibName(), llvm::Triple::getArchTypeName(getArch())});
+ return Paths;
}
bool ToolChain::needsProfileRT(const ArgList &Args) {
@@ -558,7 +815,8 @@ 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())
+ if (AC == Action::AssembleJobClass && useIntegratedAs() &&
+ !getTriple().isOSAIX())
return getClangAs();
return getTool(AC);
}
@@ -583,13 +841,18 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const {
// --ld-path= takes precedence over -fuse-ld= and specifies the executable
// name. -B, COMPILER_PATH and PATH and consulted if the value does not
// contain a path component separator.
+ // -fuse-ld=lld can be used with --ld-path= to inform clang that the binary
+ // that --ld-path= points to is lld.
if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) {
std::string Path(A->getValue());
if (!Path.empty()) {
if (llvm::sys::path::parent_path(Path).empty())
Path = GetProgramPath(A->getValue());
- if (llvm::sys::fs::can_execute(Path))
+ if (llvm::sys::fs::can_execute(Path)) {
+ if (LinkerIsLLD)
+ *LinkerIsLLD = UseLinker == "lld";
return std::string(Path);
+ }
}
getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args);
return GetProgramPath(getDefaultLinker());
@@ -766,6 +1029,9 @@ void ToolChain::addClangTargetOptions(
const ArgList &DriverArgs, ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const {}
+void ToolChain::addClangCC1ASTargetOptions(const ArgList &Args,
+ ArgStringList &CC1ASArgs) const {}
+
void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {}
void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args,
@@ -903,6 +1169,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
}
}
+/*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A,
+ const Twine &B, const Twine &C,
+ const Twine &D) {
+ SmallString<128> Result(Path);
+ llvm::sys::path::append(Result, llvm::sys::path::Style::posix, A, B, C, D);
+ return std::string(Result);
+}
+
std::string ToolChain::detectLibcxxVersion(StringRef IncludePath) const {
std::error_code EC;
int MaxVersion = 0;
@@ -944,8 +1218,15 @@ void ToolChain::AddClangCXXStdlibIsystemArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
DriverArgs.ClaimAllArgs(options::OPT_stdlibxx_isystem);
- if (!DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdincxx,
- options::OPT_nostdlibinc))
+ // This intentionally only looks at -nostdinc++, and not -nostdinc or
+ // -nostdlibinc. The purpose of -stdlib++-isystem is to support toolchain
+ // setups with non-standard search logic for the C++ headers, while still
+ // allowing users of the toolchain to bring their own C++ headers. Such a
+ // toolchain likely also has non-standard search logic for the C headers and
+ // uses -nostdinc to suppress the default logic, but -stdlib++-isystem should
+ // still work in that case and only be suppressed by an explicit -nostdinc++
+ // in a project using the toolchain.
+ if (!DriverArgs.hasArg(options::OPT_nostdincxx))
for (const auto &P :
DriverArgs.getAllArgValues(options::OPT_stdlibxx_isystem))
addSystemInclude(DriverArgs, CC1Args, P);
@@ -966,6 +1247,8 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
break;
case ToolChain::CST_Libstdcxx:
@@ -1017,22 +1300,27 @@ bool ToolChain::addFastMathRuntimeIfAvailable(const ArgList &Args,
return false;
}
+Expected<SmallVector<std::string>>
+ToolChain::getSystemGPUArchs(const llvm::opt::ArgList &Args) const {
+ return SmallVector<std::string>();
+}
+
SanitizerMask ToolChain::getSupportedSanitizers() const {
// Return sanitizers which don't require runtime support and are not
// platform dependent.
SanitizerMask Res =
- (SanitizerKind::Undefined & ~SanitizerKind::Vptr &
- ~SanitizerKind::Function) |
+ (SanitizerKind::Undefined & ~SanitizerKind::Vptr) |
(SanitizerKind::CFI & ~SanitizerKind::CFIICall) |
SanitizerKind::CFICastStrict | SanitizerKind::FloatDivideByZero |
- SanitizerKind::UnsignedIntegerOverflow |
+ SanitizerKind::KCFI | SanitizerKind::UnsignedIntegerOverflow |
SanitizerKind::UnsignedShiftBase | SanitizerKind::ImplicitConversion |
SanitizerKind::Nullability | SanitizerKind::LocalBounds;
if (getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64 ||
getTriple().getArch() == llvm::Triple::arm || getTriple().isWasm() ||
- getTriple().isAArch64())
+ getTriple().isAArch64() || getTriple().isRISCV() ||
+ getTriple().isLoongArch64())
Res |= SanitizerKind::CFIICall;
if (getTriple().getArch() == llvm::Triple::x86_64 ||
getTriple().isAArch64(64) || getTriple().isRISCV())
@@ -1049,7 +1337,7 @@ void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {}
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
-ToolChain::getHIPDeviceLibs(const ArgList &DriverArgs) const {
+ToolChain::getDeviceLibs(const ArgList &DriverArgs) const {
return {};
}
@@ -1124,7 +1412,10 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs(
// matches the current toolchain triple. If it is not present
// at all, target and host share a toolchain.
if (A->getOption().matches(options::OPT_m_Group)) {
- if (SameTripleAsHost)
+ // Pass code object version to device toolchain
+ // to correctly set metadata in intermediate files.
+ if (SameTripleAsHost ||
+ A->getOption().matches(options::OPT_mcode_object_version_EQ))
DAL->append(A);
else
Modified = true;
@@ -1231,17 +1522,17 @@ llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs(
DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
bool Modified = false;
- bool IsGPU = OFK == Action::OFK_Cuda || OFK == Action::OFK_HIP;
+ bool IsDevice = OFK != Action::OFK_None && OFK != Action::OFK_Host;
for (Arg *A : Args) {
bool NeedTrans = false;
bool Skip = false;
if (A->getOption().matches(options::OPT_Xarch_device)) {
- NeedTrans = IsGPU;
- Skip = !IsGPU;
+ NeedTrans = IsDevice;
+ Skip = !IsDevice;
} else if (A->getOption().matches(options::OPT_Xarch_host)) {
- NeedTrans = !IsGPU;
- Skip = IsGPU;
- } else if (A->getOption().matches(options::OPT_Xarch__) && IsGPU) {
+ NeedTrans = !IsDevice;
+ Skip = IsDevice;
+ } else if (A->getOption().matches(options::OPT_Xarch__) && IsDevice) {
// Do not translate -Xarch_ options for non CUDA/HIP toolchain since
// they may need special translation.
// Skip this argument unless the architecture matches BoundArch
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp
index e4bbf498b9cd..e6126ff62db3 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp
@@ -12,7 +12,9 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Path.h"
using AIX = clang::driver::toolchains::AIX;
@@ -28,6 +30,7 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit();
@@ -36,6 +39,11 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
if (!IsArch32Bit && !IsArch64Bit)
llvm_unreachable("Unsupported bit width value.");
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << D.getTargetTriple();
+ }
+
// Specify the mode in which the as(1) command operates.
if (IsArch32Bit) {
CmdArgs.push_back("-a32");
@@ -74,6 +82,29 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
+// Determine whether there are any linker options that supply an export list
+// (or equivalent information about what to export) being sent to the linker.
+static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) {
+ for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) {
+ llvm::StringRef ArgString(CmdArgs[i]);
+
+ if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") ||
+ ArgString == "-bexpall" || ArgString == "-bexpfull")
+ return true;
+
+ // If we split -b option, check the next opt.
+ if (ArgString == "-b" && i + 1 < Size) {
+ ++i;
+ llvm::StringRef ArgNextString(CmdArgs[i]);
+ if (ArgNextString.starts_with("E:") ||
+ ArgNextString.starts_with("export:") || ArgNextString == "expall" ||
+ ArgNextString == "expfull")
+ return true;
+ }
+ }
+ return false;
+}
+
void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs, const ArgList &Args,
@@ -88,6 +119,11 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!(IsArch32Bit || IsArch64Bit))
llvm_unreachable("Unsupported bit width value.");
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << D.getTargetTriple();
+ }
+
// Force static linking when "-static" is present.
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("-bnso");
@@ -98,9 +134,21 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-bnoentry");
}
- // Specify PGO linker option without LTO
- if (!D.isUsingLTO() &&
- (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr,
+ false)) {
+ if (Args.hasArg(options::OPT_shared))
+ D.Diag(diag::err_roptr_cannot_build_shared);
+
+ // The `-mxcoff-roptr` option places constants in RO sections as much as
+ // possible. Then `-bforceimprw` changes such sections to RW if they contain
+ // imported symbols that need to be resolved.
+ CmdArgs.push_back("-bforceimprw");
+ }
+
+ // PGO instrumentation generates symbols belonging to special sections, and
+ // the linker needs to place all symbols in a particular section together in
+ // memory; the AIX linker does that under an option.
+ if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
false) ||
Args.hasFlag(options::OPT_fprofile_generate,
options::OPT_fno_profile_generate, false) ||
@@ -115,8 +163,24 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
options::OPT_fno_profile_generate, false) ||
Args.hasArg(options::OPT_fcreate_profile) ||
- Args.hasArg(options::OPT_coverage)))
- CmdArgs.push_back("-bdbg:namedsects");
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-bdbg:namedsects:ss");
+
+ if (Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_mxcoff_build_id_EQ)) {
+ StringRef BuildId = A->getValue();
+ if (BuildId[0] != '0' || BuildId[1] != 'x' ||
+ BuildId.find_if_not(llvm::isHexDigit, 2) != StringRef::npos)
+ ToolChain.getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << BuildId;
+ else {
+ std::string LinkerFlag = "-bdbg:ldrinfo:xcoff_binary_id:0x";
+ if (BuildId.size() % 2) // Prepend a 0 if odd number of digits.
+ LinkerFlag += "0";
+ LinkerFlag += BuildId.drop_front(2).lower();
+ CmdArgs.push_back(Args.MakeArgString(LinkerFlag));
+ }
+ }
// Specify linker output file.
assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
@@ -138,19 +202,19 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_shared, options::OPT_r)) {
+ auto getCrt0Basename = [&Args, IsArch32Bit] {
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) {
+ // Enable gprofiling when "-pg" is specified.
+ if (A->getOption().matches(options::OPT_pg))
+ return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o";
+ // Enable profiling when "-p" is specified.
+ return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o";
+ }
return IsArch32Bit ? "crt0.o" : "crt0_64.o";
- };
+ };
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
- options::OPT_shared)) {
CmdArgs.push_back(
Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
@@ -167,27 +231,109 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// 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);
- ToolChain.addProfileRTLibs(Args, CmdArgs);
-
- if (getToolChain().ShouldLinkCXXStdlib(Args))
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
-
- // Support POSIX threads if "-pthreads" or "-pthread" is present.
- if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
- CmdArgs.push_back("-lpthreads");
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
+ D.getLTOMode() == LTOK_Thin);
+ }
- if (D.CCCIsCXX())
- CmdArgs.push_back("-lm");
+ if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {
+
+ const char *CreateExportListExec = Args.MakeArgString(
+ path::parent_path(ToolChain.getDriver().ClangExecutable) +
+ "/llvm-nm");
+ ArgStringList CreateExportCmdArgs;
+
+ std::string CreateExportListPath =
+ C.getDriver().GetTemporaryPath("CreateExportList", "exp");
+ const char *ExportList =
+ C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath));
+
+ for (const auto &II : Inputs)
+ if (II.isFilename())
+ CreateExportCmdArgs.push_back(II.getFilename());
+
+ CreateExportCmdArgs.push_back("--export-symbols");
+ CreateExportCmdArgs.push_back("-X");
+ if (IsArch32Bit) {
+ CreateExportCmdArgs.push_back("32");
+ } else {
+ // Must be 64-bit, otherwise asserted already.
+ CreateExportCmdArgs.push_back("64");
+ }
+
+ auto ExpCommand = std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::None(), CreateExportListExec,
+ CreateExportCmdArgs, Inputs, Output);
+ ExpCommand->setRedirectFiles(
+ {std::nullopt, std::string(ExportList), std::nullopt});
+ C.addCommand(std::move(ExpCommand));
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList));
+ }
- CmdArgs.push_back("-lc");
+ // Add directory to library search path.
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ if (!Args.hasArg(options::OPT_r)) {
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ ToolChain.addProfileRTLibs(Args, CmdArgs);
+
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
+
+ // Add OpenMP runtime if -fopenmp is specified.
+ if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false)) {
+ switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
+ CmdArgs.push_back("-lomp");
+ break;
+ case Driver::OMPRT_IOMP5:
+ CmdArgs.push_back("-liomp5");
+ break;
+ case Driver::OMPRT_GOMP:
+ CmdArgs.push_back("-lgomp");
+ break;
+ case Driver::OMPRT_Unknown:
+ // Already diagnosed.
+ break;
+ }
+ }
+
+ // Support POSIX threads if "-pthreads" or "-pthread" is present.
+ if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
+ CmdArgs.push_back("-lpthreads");
+
+ if (D.CCCIsCXX())
+ CmdArgs.push_back("-lm");
+
+ CmdArgs.push_back("-lc");
+
+ if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) {
+ CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
+ "/lib/profiled"));
+ CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
+ "/usr/lib/profiled"));
+ }
+ }
}
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ CmdArgs.push_back("-lpthread");
+ }
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Exec, CmdArgs, Inputs, Output));
@@ -196,6 +342,10 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
/// 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) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+
ParseInlineAsmUsingAsmParser = Args.hasFlag(
options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true);
getLibraryPaths().push_back(getDriver().SysRoot + "/usr/lib");
@@ -221,11 +371,13 @@ void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
const Driver &D = getDriver();
- // Add the Clang builtin headers (<resource>/include).
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> P(D.ResourceDir);
- path::append(P, "/include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
+ // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers)
+ path::append(P, "include", "ppc_wrappers");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ // Add the Clang builtin headers (<resource>/include)
+ addSystemInclude(DriverArgs, CC1Args, path::parent_path(P.str()));
}
// Return if -nostdlibinc is specified as a driver option.
@@ -274,6 +426,8 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::report_fatal_error("linking libstdc++ unimplemented on AIX");
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
return;
}
@@ -281,6 +435,37 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
}
+void AIX::addClangTargetOptions(
+ const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const {
+ Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility);
+ Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
+ Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);
+
+ if (Args.hasFlag(options::OPT_fxl_pragma_pack,
+ options::OPT_fno_xl_pragma_pack, true))
+ CC1Args.push_back("-fxl-pragma-pack");
+}
+
+void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ if (needsProfileRT(Args)) {
+ // Add linker option -u__llvm_profile_runtime to cause runtime
+ // initialization to occur.
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
+
+ if (const auto *A =
+ Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) {
+ StringRef Val = A->getValue();
+ if (Val == "atomic" || Val == "prefer-atomic")
+ CmdArgs.push_back("-latomic");
+ }
+ }
+
+ ToolChain::addProfileRTLibs(Args, CmdArgs);
+}
+
ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
return ToolChain::CST_Libcxx;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h
index e7ec3a5ece4d..755d87e07ec5 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h
@@ -16,10 +16,10 @@ namespace clang {
namespace driver {
namespace tools {
-/// aix -- Directly call system default assembler and linker.
+/// Directly call system default assembler and linker.
namespace aix {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", TC) {}
@@ -31,7 +31,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("aix::Linker", "linker", TC) {}
@@ -67,6 +67,7 @@ public:
return false;
}
bool isPICDefaultForced() const override { return true; }
+ bool HasNativeLLVMSupport() const override { return true; }
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -79,6 +80,13 @@ public:
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ void addClangTargetOptions(
+ const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const override;
+
+ void addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
CXXStdlibType GetDefaultCXXStdlibType() const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp
index 43ce33750eba..b3c9d5908654 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -9,20 +9,22 @@
#include "AMDGPU.h"
#include "CommonArgs.h"
#include "clang/Basic/TargetID.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/Host.h"
+#include <optional>
#include <system_error>
-#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch"
-
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
@@ -47,7 +49,7 @@ RocmInstallationDetector::findSPACKPackage(const Candidate &Cand,
FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
llvm::StringRef FileName = llvm::sys::path::filename(File->path());
- if (FileName.startswith(Prefix)) {
+ if (FileName.starts_with(Prefix)) {
SubDirs.push_back(FileName);
if (SubDirs.size() > 1)
break;
@@ -82,15 +84,16 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef FilePath = LI->path();
StringRef FileName = llvm::sys::path::filename(FilePath);
- if (!FileName.endswith(Suffix))
+ if (!FileName.ends_with(Suffix))
continue;
StringRef BaseName;
- if (FileName.endswith(Suffix2))
+ if (FileName.ends_with(Suffix2))
BaseName = FileName.drop_back(Suffix2.size());
- else if (FileName.endswith(Suffix))
+ else if (FileName.ends_with(Suffix))
BaseName = FileName.drop_back(Suffix.size());
+ const StringRef ABIVersionPrefix = "oclc_abi_version_";
if (BaseName == "ocml") {
OCML = FilePath;
} else if (BaseName == "ockl") {
@@ -121,11 +124,17 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
WavefrontSize64.On = FilePath;
} else if (BaseName == "oclc_wavefrontsize64_off") {
WavefrontSize64.Off = FilePath;
+ } else if (BaseName.starts_with(ABIVersionPrefix)) {
+ unsigned ABIVersionNumber;
+ if (BaseName.drop_front(ABIVersionPrefix.size())
+ .getAsInteger(/*Redex=*/0, ABIVersionNumber))
+ continue;
+ ABIVersionMap[ABIVersionNumber] = FilePath.str();
} else {
// Process all bitcode filenames that look like
// ocl_isa_version_XXX.amdgcn.bc
const StringRef DeviceLibPrefix = "oclc_isa_version_";
- if (!BaseName.startswith(DeviceLibPrefix))
+ if (!BaseName.starts_with(DeviceLibPrefix))
continue;
StringRef IsaVersionNumber =
@@ -190,9 +199,10 @@ RocmInstallationDetector::getInstallationPathCandidates() {
ROCmSearchDirs.emplace_back(RocmPathArg.str());
DoPrintROCmSearchDirs();
return ROCmSearchDirs;
- } else if (const char *RocmPathEnv = ::getenv("ROCM_PATH")) {
- if (!StringRef(RocmPathEnv).empty()) {
- ROCmSearchDirs.emplace_back(RocmPathEnv);
+ } else if (std::optional<std::string> RocmPathEnv =
+ llvm::sys::Process::GetEnv("ROCM_PATH")) {
+ if (!RocmPathEnv->empty()) {
+ ROCmSearchDirs.emplace_back(std::move(*RocmPathEnv));
DoPrintROCmSearchDirs();
return ROCmSearchDirs;
}
@@ -220,7 +230,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
// <rocm_root>/llvm-amdgpu-<rocm_release_string>-<hash>/bin directory.
// We only consider the parent directory of llvm-amdgpu package as ROCm
// installation candidate for SPACK.
- if (ParentName.startswith("llvm-amdgpu-")) {
+ if (ParentName.starts_with("llvm-amdgpu-")) {
auto SPACKPostfix =
ParentName.drop_front(strlen("llvm-amdgpu-")).split('-');
auto SPACKReleaseStr = SPACKPostfix.first;
@@ -233,7 +243,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
// Some versions of the rocm llvm package install to /opt/rocm/llvm/bin
// Some versions of the aomp package install to /opt/rocm/aomp/bin
- if (ParentName == "llvm" || ParentName.startswith("aomp"))
+ if (ParentName == "llvm" || ParentName.starts_with("aomp"))
ParentDir = llvm::sys::path::parent_path(ParentDir);
return Candidate(ParentDir.str(), /*StrictChecking=*/true);
@@ -282,7 +292,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
llvm::StringRef FileName = llvm::sys::path::filename(File->path());
- if (!FileName.startswith("rocm-"))
+ if (!FileName.starts_with("rocm-"))
continue;
if (LatestROCm.empty()) {
LatestROCm = FileName.str();
@@ -299,6 +309,11 @@ RocmInstallationDetector::getInstallationPathCandidates() {
ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm,
/*StrictChecking=*/true);
+ ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local",
+ /*StrictChecking=*/true);
+ ROCmSearchDirs.emplace_back(D.SysRoot + "/usr",
+ /*StrictChecking=*/true);
+
DoPrintROCmSearchDirs();
return ROCmSearchDirs;
}
@@ -314,6 +329,20 @@ RocmInstallationDetector::RocmInstallationDetector(
RocmDeviceLibPathArg =
Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ);
HIPPathArg = Args.getLastArgValue(clang::driver::options::OPT_hip_path_EQ);
+ HIPStdParPathArg =
+ Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_path_EQ);
+ HasHIPStdParLibrary =
+ !HIPStdParPathArg.empty() && D.getVFS().exists(HIPStdParPathArg +
+ "/hipstdpar_lib.hpp");
+ HIPRocThrustPathArg =
+ Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_thrust_path_EQ);
+ HasRocThrustLibrary = !HIPRocThrustPathArg.empty() &&
+ D.getVFS().exists(HIPRocThrustPathArg + "/thrust");
+ HIPRocPrimPathArg =
+ Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_prim_path_EQ);
+ HasRocPrimLibrary = !HIPRocPrimPathArg.empty() &&
+ D.getVFS().exists(HIPRocPrimPathArg + "/rocprim");
+
if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) {
HIPVersionArg = A->getValue();
unsigned Major = ~0U;
@@ -357,8 +386,9 @@ void RocmInstallationDetector::detectDeviceLibrary() {
if (!RocmDeviceLibPathArg.empty())
LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1];
- else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH"))
- LibDevicePath = LibPathEnv;
+ else if (std::optional<std::string> LibPathEnv =
+ llvm::sys::Process::GetEnv("HIP_DEVICE_LIB_PATH"))
+ LibDevicePath = std::move(*LibPathEnv);
auto &FS = D.getVFS();
if (!LibDevicePath.empty()) {
@@ -373,69 +403,57 @@ void RocmInstallationDetector::detectDeviceLibrary() {
return;
}
- // The install path situation in old versions of ROCm is a real mess, and
- // use a different install layout. Multiple copies of the device libraries
- // exist for each frontend project, and differ depending on which build
- // system produced the packages. Standalone OpenCL builds also have a
- // different directory structure from the ROCm OpenCL package.
- auto &ROCmDirs = getInstallationPathCandidates();
- for (const auto &Candidate : ROCmDirs) {
- auto CandidatePath = Candidate.Path;
-
- // Check device library exists at the given path.
- auto CheckDeviceLib = [&](StringRef Path) {
- bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking);
- if (CheckLibDevice && !FS.exists(Path))
- return false;
-
- scanLibDevicePath(Path);
+ // Check device library exists at the given path.
+ auto CheckDeviceLib = [&](StringRef Path, bool StrictChecking) {
+ bool CheckLibDevice = (!NoBuiltinLibs || StrictChecking);
+ if (CheckLibDevice && !FS.exists(Path))
+ return false;
- if (!NoBuiltinLibs) {
- // Check that the required non-target libraries are all available.
- if (!allGenericLibsValid())
- return false;
+ scanLibDevicePath(Path);
- // Check that we have found at least one libdevice that we can link in
- // if -nobuiltinlib hasn't been specified.
- if (LibDeviceMap.empty())
- return false;
- }
- return true;
- };
+ if (!NoBuiltinLibs) {
+ // Check that the required non-target libraries are all available.
+ if (!allGenericLibsValid())
+ return false;
- // The possible structures are:
- // - ${ROCM_ROOT}/amdgcn/bitcode/*
- // - ${ROCM_ROOT}/lib/*
- // - ${ROCM_ROOT}/lib/bitcode/*
- // so try to detect these layouts.
- static constexpr std::array<const char *, 2> SubDirsList[] = {
- {"amdgcn", "bitcode"},
- {"lib", ""},
- {"lib", "bitcode"},
- };
+ // Check that we have found at least one libdevice that we can link in
+ // if -nobuiltinlib hasn't been specified.
+ if (LibDeviceMap.empty())
+ return false;
+ }
+ return true;
+ };
- // Make a path by appending sub-directories to InstallPath.
- auto MakePath = [&](const llvm::ArrayRef<const char *> &SubDirs) {
- auto Path = CandidatePath;
- for (auto SubDir : SubDirs)
- llvm::sys::path::append(Path, SubDir);
- return Path;
- };
+ // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/amdgcn/bitcode
+ LibDevicePath = D.ResourceDir;
+ llvm::sys::path::append(LibDevicePath, CLANG_INSTALL_LIBDIR_BASENAME,
+ "amdgcn", "bitcode");
+ HasDeviceLibrary = CheckDeviceLib(LibDevicePath, true);
+ if (HasDeviceLibrary)
+ return;
- for (auto SubDirs : SubDirsList) {
- LibDevicePath = MakePath(SubDirs);
- HasDeviceLibrary = CheckDeviceLib(LibDevicePath);
- if (HasDeviceLibrary)
- return;
- }
+ // Find device libraries in a legacy ROCm directory structure
+ // ${ROCM_ROOT}/amdgcn/bitcode/*
+ auto &ROCmDirs = getInstallationPathCandidates();
+ for (const auto &Candidate : ROCmDirs) {
+ LibDevicePath = Candidate.Path;
+ llvm::sys::path::append(LibDevicePath, "amdgcn", "bitcode");
+ HasDeviceLibrary = CheckDeviceLib(LibDevicePath, Candidate.StrictChecking);
+ if (HasDeviceLibrary)
+ return;
}
}
void RocmInstallationDetector::detectHIPRuntime() {
SmallVector<Candidate, 4> HIPSearchDirs;
if (!HIPPathArg.empty())
- HIPSearchDirs.emplace_back(HIPPathArg.str(), /*StrictChecking=*/true);
- else
+ HIPSearchDirs.emplace_back(HIPPathArg.str());
+ else if (std::optional<std::string> HIPPathEnv =
+ llvm::sys::Process::GetEnv("HIP_PATH")) {
+ if (!HIPPathEnv->empty())
+ HIPSearchDirs.emplace_back(std::move(*HIPPathEnv));
+ }
+ if (HIPSearchDirs.empty())
HIPSearchDirs.append(getInstallationPathCandidates());
auto &FS = D.getVFS();
@@ -454,18 +472,41 @@ void RocmInstallationDetector::detectHIPRuntime() {
llvm::sys::path::append(IncludePath, "include");
LibPath = InstallPath;
llvm::sys::path::append(LibPath, "lib");
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
- FS.getBufferForFile(BinPath + "/.hipVersion");
- if (!VersionFile && Candidate.StrictChecking)
- continue;
-
- if (HIPVersionArg.empty() && VersionFile)
- if (parseHIPVersionFile((*VersionFile)->getBuffer()))
+ SharePath = InstallPath;
+ llvm::sys::path::append(SharePath, "share");
+
+ // Get parent of InstallPath and append "share"
+ SmallString<0> ParentSharePath = llvm::sys::path::parent_path(InstallPath);
+ llvm::sys::path::append(ParentSharePath, "share");
+
+ auto Append = [](SmallString<0> &path, const Twine &a, const Twine &b = "",
+ const Twine &c = "", const Twine &d = "") {
+ SmallString<0> newpath = path;
+ llvm::sys::path::append(newpath, a, b, c, d);
+ return newpath;
+ };
+ // If HIP version file can be found and parsed, use HIP version from there.
+ for (const auto &VersionFilePath :
+ {Append(SharePath, "hip", "version"),
+ Append(ParentSharePath, "hip", "version"),
+ Append(BinPath, ".hipVersion")}) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
+ FS.getBufferForFile(VersionFilePath);
+ if (!VersionFile)
continue;
+ if (HIPVersionArg.empty() && VersionFile)
+ if (parseHIPVersionFile((*VersionFile)->getBuffer()))
+ continue;
- HasHIPRuntime = true;
- return;
+ HasHIPRuntime = true;
+ return;
+ }
+ // Otherwise, if -rocm-path is specified (no strict checking), use the
+ // default HIP version or specified by --hip-version.
+ if (!Candidate.StrictChecking) {
+ HasHIPRuntime = true;
+ return;
+ }
}
HasHIPRuntime = false;
}
@@ -480,6 +521,7 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5) &&
!DriverArgs.hasArg(options::OPT_nohipwrapperinc);
+ bool HasHipStdPar = DriverArgs.hasArg(options::OPT_hipstdpar);
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
// HIP header includes standard library wrapper headers under clang
@@ -502,18 +544,66 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,
CC1Args.push_back(DriverArgs.MakeArgString(P));
}
- if (DriverArgs.hasArg(options::OPT_nogpuinc))
+ const auto HandleHipStdPar = [=, &DriverArgs, &CC1Args]() {
+ StringRef Inc = getIncludePath();
+ auto &FS = D.getVFS();
+
+ if (!hasHIPStdParLibrary())
+ if (!HIPStdParPathArg.empty() ||
+ !FS.exists(Inc + "/thrust/system/hip/hipstdpar/hipstdpar_lib.hpp")) {
+ D.Diag(diag::err_drv_no_hipstdpar_lib);
+ return;
+ }
+ if (!HasRocThrustLibrary && !FS.exists(Inc + "/thrust")) {
+ D.Diag(diag::err_drv_no_hipstdpar_thrust_lib);
+ return;
+ }
+ if (!HasRocPrimLibrary && !FS.exists(Inc + "/rocprim")) {
+ D.Diag(diag::err_drv_no_hipstdpar_prim_lib);
+ return;
+ }
+ const char *ThrustPath;
+ if (HasRocThrustLibrary)
+ ThrustPath = DriverArgs.MakeArgString(HIPRocThrustPathArg);
+ else
+ ThrustPath = DriverArgs.MakeArgString(Inc + "/thrust");
+
+ const char *HIPStdParPath;
+ if (hasHIPStdParLibrary())
+ HIPStdParPath = DriverArgs.MakeArgString(HIPStdParPathArg);
+ else
+ HIPStdParPath = DriverArgs.MakeArgString(StringRef(ThrustPath) +
+ "/system/hip/hipstdpar");
+
+ const char *PrimPath;
+ if (HasRocPrimLibrary)
+ PrimPath = DriverArgs.MakeArgString(HIPRocPrimPathArg);
+ else
+ PrimPath = DriverArgs.MakeArgString(getIncludePath() + "/rocprim");
+
+ CC1Args.append({"-idirafter", ThrustPath, "-idirafter", PrimPath,
+ "-idirafter", HIPStdParPath, "-include",
+ "hipstdpar_lib.hpp"});
+ };
+
+ if (DriverArgs.hasArg(options::OPT_nogpuinc)) {
+ if (HasHipStdPar)
+ HandleHipStdPar();
+
return;
+ }
if (!hasHIPRuntime()) {
D.Diag(diag::err_drv_no_hip_runtime);
return;
}
- CC1Args.push_back("-internal-isystem");
+ CC1Args.push_back("-idirafter");
CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath()));
if (UsesRuntimeWrapper)
CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"});
+ if (HasHipStdPar)
+ HandleHipStdPar();
}
void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -524,9 +614,18 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
std::string Linker = getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
+ CmdArgs.push_back("--no-undefined");
+ CmdArgs.push_back("-shared");
+
addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
- CmdArgs.push_back("-shared");
+ if (C.getDriver().isUsingLTO())
+ addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
+ C.getDriver().getLTOMode() == LTOK_Thin);
+ else if (Args.hasArg(options::OPT_mcpu_EQ))
+ CmdArgs.push_back(Args.MakeArgString(
+ "-plugin-opt=mcpu=" + Args.getLastArgValue(options::OPT_mcpu_EQ)));
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(
@@ -545,7 +644,7 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
llvm::StringMap<bool> FeatureMap;
auto OptionalGpuArch = parseTargetID(Triple, TargetID, &FeatureMap);
if (OptionalGpuArch) {
- StringRef GpuArch = OptionalGpuArch.getValue();
+ StringRef GpuArch = *OptionalGpuArch;
// Iterate through all possible target ID features for the given GPU.
// If it is mapped to true, add +feature.
// If it is mapped to false, add -feature.
@@ -564,8 +663,8 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
options::OPT_mno_wavefrontsize64, false))
Features.push_back("+wavefrontsize64");
- handleTargetFeaturesGroup(
- Args, Features, options::OPT_m_amdgpu_Features_Group);
+ handleTargetFeaturesGroup(D, Triple, Args, Features,
+ options::OPT_m_amdgpu_Features_Group);
}
/// AMDGPU Toolchain
@@ -597,9 +696,28 @@ AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
if (!DAL)
DAL = new DerivedArgList(Args.getBaseArgs());
- for (Arg *A : Args) {
- if (!shouldSkipArgument(A))
- DAL->append(A);
+ for (Arg *A : Args)
+ DAL->append(A);
+
+ // Replace -mcpu=native with detected GPU.
+ Arg *LastMCPUArg = DAL->getLastArg(options::OPT_mcpu_EQ);
+ if (LastMCPUArg && StringRef(LastMCPUArg->getValue()) == "native") {
+ DAL->eraseArg(options::OPT_mcpu_EQ);
+ auto GPUsOrErr = getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "-mcpu";
+ } else {
+ auto &GPUs = *GPUsOrErr;
+ if (GPUs.size() > 1) {
+ getDriver().Diag(diag::warn_drv_multi_gpu_arch)
+ << llvm::Triple::getArchTypeName(getArch())
+ << llvm::join(GPUs, ", ") << "-mcpu";
+ }
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ),
+ Args.MakeArgString(GPUs.front()));
+ }
}
checkTargetID(*DAL);
@@ -689,7 +807,7 @@ bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs,
ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: AMDGPUToolChain(D, Triple, Args) {
- RocmInstallation.detectDeviceLibrary();
+ RocmInstallation->detectDeviceLibrary();
}
void AMDGPUToolChain::addClangTargetOptions(
@@ -700,8 +818,7 @@ void AMDGPUToolChain::addClangTargetOptions(
// supported for the foreseeable future.
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
- CC1Args.push_back("-fvisibility");
- CC1Args.push_back("hidden");
+ CC1Args.push_back("-fvisibility=hidden");
CC1Args.push_back("-fapply-global-visibility-to-externs");
}
}
@@ -716,14 +833,14 @@ AMDGPUToolChain::ParsedTargetIDType
AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const {
StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
if (TargetID.empty())
- return {None, None, None};
+ return {std::nullopt, std::nullopt, std::nullopt};
llvm::StringMap<bool> FeatureMap;
auto OptionalGpuArch = parseTargetID(getTriple(), TargetID, &FeatureMap);
if (!OptionalGpuArch)
- return {TargetID.str(), None, None};
+ return {TargetID.str(), std::nullopt, std::nullopt};
- return {TargetID.str(), OptionalGpuArch.getValue().str(), FeatureMap};
+ return {TargetID.str(), OptionalGpuArch->str(), FeatureMap};
}
void AMDGPUToolChain::checkTargetID(
@@ -731,80 +848,33 @@ void AMDGPUToolChain::checkTargetID(
auto PTID = getParsedTargetID(DriverArgs);
if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {
getDriver().Diag(clang::diag::err_drv_bad_target_id)
- << PTID.OptionalTargetID.getValue();
+ << *PTID.OptionalTargetID;
}
}
-llvm::Error
-AMDGPUToolChain::detectSystemGPUs(const ArgList &Args,
- SmallVector<std::string, 1> &GPUArchs) const {
+Expected<SmallVector<std::string>>
+AMDGPUToolChain::getSystemGPUArchs(const ArgList &Args) const {
+ // Detect AMD GPUs availible on the system.
std::string Program;
if (Arg *A = Args.getLastArg(options::OPT_amdgpu_arch_tool_EQ))
Program = A->getValue();
else
- Program = GetProgramPath(AMDGPU_ARCH_PROGRAM_NAME);
- llvm::SmallString<64> OutputFile;
- llvm::sys::fs::createTemporaryFile("print-system-gpus", "" /* No Suffix */,
- OutputFile);
- llvm::FileRemover OutputRemover(OutputFile.c_str());
- llvm::Optional<llvm::StringRef> Redirects[] = {
- {""},
- OutputFile.str(),
- {""},
- };
+ Program = GetProgramPath("amdgpu-arch");
- std::string ErrorMessage;
- if (int Result = llvm::sys::ExecuteAndWait(
- Program, {}, {}, Redirects, /* SecondsToWait */ 0,
- /*MemoryLimit*/ 0, &ErrorMessage)) {
- if (Result > 0) {
- ErrorMessage = "Exited with error code " + std::to_string(Result);
- } else if (Result == -1) {
- ErrorMessage = "Execute failed: " + ErrorMessage;
- } else {
- ErrorMessage = "Crashed: " + ErrorMessage;
- }
+ auto StdoutOrErr = executeToolChainProgram(Program);
+ if (!StdoutOrErr)
+ return StdoutOrErr.takeError();
- return llvm::createStringError(std::error_code(),
- Program + ": " + ErrorMessage);
- }
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
- llvm::MemoryBuffer::getFile(OutputFile.c_str());
- if (!OutputBuf) {
- return llvm::createStringError(OutputBuf.getError(),
- "Failed to read stdout of " + Program +
- ": " + OutputBuf.getError().message());
- }
-
- for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) {
- GPUArchs.push_back(LineIt->str());
- }
- return llvm::Error::success();
-}
-
-llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args,
- std::string &GPUArch) const {
- // detect the AMDGPU installed in system
SmallVector<std::string, 1> GPUArchs;
- auto Err = detectSystemGPUs(Args, GPUArchs);
- if (Err) {
- return Err;
- }
- if (GPUArchs.empty()) {
+ for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n"))
+ if (!Arch.empty())
+ GPUArchs.push_back(Arch.str());
+
+ if (GPUArchs.empty())
return llvm::createStringError(std::error_code(),
"No AMD GPU detected in the system");
- }
- GPUArch = GPUArchs[0];
- if (GPUArchs.size() > 1) {
- bool AllSame = llvm::all_of(GPUArchs, [&](const StringRef &GPUArch) {
- return GPUArch == GPUArchs.front();
- });
- if (!AllSame)
- return llvm::createStringError(
- std::error_code(), "Multiple AMD GPUs found with different archs");
- }
- return llvm::Error::success();
+
+ return std::move(GPUArchs);
}
void ROCMToolChain::addClangTargetOptions(
@@ -822,20 +892,16 @@ void ROCMToolChain::addClangTargetOptions(
if (DriverArgs.hasArg(options::OPT_nogpulib))
return;
- if (!RocmInstallation.hasDeviceLibrary()) {
- getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
- return;
- }
-
// Get the device name and canonicalize it
const StringRef GpuArch = getGPUArch(DriverArgs);
auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
- std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
- if (LibDeviceFile.empty()) {
- getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch;
+ StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch);
+ auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion(
+ getAMDGPUCodeObjectVersion(getDriver(), DriverArgs));
+ if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile,
+ ABIVer))
return;
- }
bool Wave64 = isWave64(DriverArgs, Kind);
@@ -853,59 +919,75 @@ void ROCMToolChain::addClangTargetOptions(
// Add the OpenCL specific bitcode library.
llvm::SmallVector<std::string, 12> BCLibs;
- BCLibs.push_back(RocmInstallation.getOpenCLPath().str());
+ BCLibs.push_back(RocmInstallation->getOpenCLPath().str());
// Add the generic set of libraries.
- BCLibs.append(RocmInstallation.getCommonBitcodeLibs(
+ BCLibs.append(RocmInstallation->getCommonBitcodeLibs(
DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt,
- FastRelaxedMath, CorrectSqrt));
+ FastRelaxedMath, CorrectSqrt, ABIVer, false));
- llvm::for_each(BCLibs, [&](StringRef BCFile) {
+ for (StringRef BCFile : BCLibs) {
CC1Args.push_back("-mlink-builtin-bitcode");
CC1Args.push_back(DriverArgs.MakeArgString(BCFile));
- });
+ }
+}
+
+bool RocmInstallationDetector::checkCommonBitcodeLibs(
+ StringRef GPUArch, StringRef LibDeviceFile,
+ DeviceLibABIVersion ABIVer) const {
+ if (!hasDeviceLibrary()) {
+ D.Diag(diag::err_drv_no_rocm_device_lib) << 0;
+ return false;
+ }
+ if (LibDeviceFile.empty()) {
+ D.Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch;
+ return false;
+ }
+ if (ABIVer.requiresLibrary() && getABIVersionPath(ABIVer).empty()) {
+ D.Diag(diag::err_drv_no_rocm_device_lib) << 2 << ABIVer.toString();
+ return false;
+ }
+ return true;
}
llvm::SmallVector<std::string, 12>
RocmInstallationDetector::getCommonBitcodeLibs(
const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64,
bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath,
- bool CorrectSqrt) const {
-
+ bool CorrectSqrt, DeviceLibABIVersion ABIVer, bool isOpenMP = false) const {
llvm::SmallVector<std::string, 12> BCLibs;
auto AddBCLib = [&](StringRef BCFile) { BCLibs.push_back(BCFile.str()); };
AddBCLib(getOCMLPath());
- AddBCLib(getOCKLPath());
+ if (!isOpenMP)
+ AddBCLib(getOCKLPath());
AddBCLib(getDenormalsAreZeroPath(DAZ));
AddBCLib(getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath));
AddBCLib(getFiniteOnlyPath(FiniteOnly || FastRelaxedMath));
AddBCLib(getCorrectlyRoundedSqrtPath(CorrectSqrt));
AddBCLib(getWavefrontSize64Path(Wave64));
AddBCLib(LibDeviceFile);
+ auto ABIVerPath = getABIVersionPath(ABIVer);
+ if (!ABIVerPath.empty())
+ AddBCLib(ABIVerPath);
return BCLibs;
}
-bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const {
- Option O = A->getOption();
- if (O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie))
- return true;
- return false;
-}
-
llvm::SmallVector<std::string, 12>
ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs,
- const std::string &GPUArch) const {
+ const std::string &GPUArch,
+ bool isOpenMP) const {
auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch);
const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
- std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
- if (LibDeviceFile.empty()) {
- getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch;
+ StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch);
+ auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion(
+ getAMDGPUCodeObjectVersion(getDriver(), DriverArgs));
+ if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile,
+ ABIVer))
return {};
- }
// If --hip-device-lib is not set, add the default bitcode libraries.
// TODO: There are way too many flags that change this. Do we need to check
@@ -922,10 +1004,10 @@ ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs,
options::OPT_fno_fast_math, false);
bool CorrectSqrt = DriverArgs.hasFlag(
options::OPT_fhip_fp32_correctly_rounded_divide_sqrt,
- options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt);
+ options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt, true);
bool Wave64 = isWave64(DriverArgs, Kind);
- return RocmInstallation.getCommonBitcodeLibs(
+ return RocmInstallation->getCommonBitcodeLibs(
DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt,
- FastRelaxedMath, CorrectSqrt);
+ FastRelaxedMath, CorrectSqrt, ABIVer, isOpenMP);
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h
index 156bfd1fbdb2..b3361b1e3607 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h
@@ -16,7 +16,7 @@
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/TargetParser.h"
+#include "llvm/TargetParser/TargetParser.h"
#include <map>
@@ -26,7 +26,7 @@ namespace driver {
namespace tools {
namespace amdgpu {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("amdgpu::Linker", "ld.lld", TC) {}
bool isLinkJob() const override { return true; }
@@ -61,16 +61,14 @@ public:
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
unsigned GetDefaultDwarfVersion() const override { return 5; }
- bool IsIntegratedAssemblerDefault() const override { return true; }
- bool IsMathErrnoDefault() const override { return false; }
- bool useIntegratedAs() const override { return true; }
+ bool IsMathErrnoDefault() const override { return false; }
bool isCrossCompiling() const override { return true; }
- bool isPICDefault() const override { return false; }
+ bool isPICDefault() const override { return true; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
- bool isPICDefaultForced() const override { return false; }
+ bool isPICDefaultForced() const override { return true; }
bool SupportsProfiling() const override { return false; }
llvm::opt::DerivedArgList *
@@ -99,13 +97,10 @@ public:
/// Needed for translating LTO options.
const char *getDefaultLinker() const override { return "ld.lld"; }
- /// Should skip argument.
- bool shouldSkipArgument(const llvm::opt::Arg *Arg) const;
-
- /// Uses amdgpu_arch tool to get arch of the system GPU. Will return error
+ /// Uses amdgpu-arch tool to get arch of the system GPU. Will return error
/// if unable to find one.
- llvm::Error getSystemGPUArch(const llvm::opt::ArgList &Args,
- std::string &GPUArch) const;
+ virtual Expected<SmallVector<std::string>>
+ getSystemGPUArchs(const llvm::opt::ArgList &Args) const override;
protected:
/// Check and diagnose invalid target ID specified by -mcpu.
@@ -113,9 +108,9 @@ protected:
/// The struct type returned by getParsedTargetID.
struct ParsedTargetIDType {
- Optional<std::string> OptionalTargetID;
- Optional<std::string> OptionalGPUArch;
- Optional<llvm::StringMap<bool>> OptionalFeatures;
+ std::optional<std::string> OptionalTargetID;
+ std::optional<std::string> OptionalGPUArch;
+ std::optional<llvm::StringMap<bool>> OptionalFeatures;
};
/// Get target ID, GPU arch, and target ID features if the target ID is
@@ -126,8 +121,6 @@ protected:
/// Get GPU arch from -mcpu without checking.
StringRef getGPUArch(const llvm::opt::ArgList &DriverArgs) const;
- llvm::Error detectSystemGPUs(const llvm::opt::ArgList &Args,
- SmallVector<std::string, 1> &GPUArchs) const;
};
class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain {
@@ -142,7 +135,8 @@ public:
// Returns a list of device library names shared by different languages
llvm::SmallVector<std::string, 12>
getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs,
- const std::string &GPUArch) const;
+ const std::string &GPUArch,
+ bool isOpenMP = false) const;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
index d7cf41e4b660..b012b7cb7293 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
@@ -29,238 +29,13 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-namespace {
-
-static const char *getOutputFileName(Compilation &C, StringRef Base,
- const char *Postfix,
- const char *Extension) {
- const char *OutputFileName;
- if (C.getDriver().isSaveTempsEnabled()) {
- OutputFileName =
- C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension);
- } else {
- std::string TmpName =
- C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension);
- OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName));
- }
- return OutputFileName;
-}
-
-static void addLLCOptArg(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) {
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- StringRef OOpt = "0";
- 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", "2")
- .Case("z", "2")
- .Case("g", "1")
- .Default("0");
- }
- CmdArgs.push_back(Args.MakeArgString("-O" + OOpt));
- }
-}
-
-static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC,
- std::string &GPUArch) {
- if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) {
- std::string ErrMsg =
- llvm::formatv("{0}", llvm::fmt_consume(std::move(Err)));
- TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg;
- return false;
- }
-
- return true;
-}
-} // namespace
-
-const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
- const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C,
- const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args,
- StringRef SubArchName, StringRef OutputFilePrefix) const {
- ArgStringList CmdArgs;
-
- for (const auto &II : Inputs)
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
-
- bool HasLibm = false;
- if (Args.hasArg(options::OPT_l)) {
- auto Lm = Args.getAllArgValues(options::OPT_l);
- for (auto &Lib : Lm) {
- if (Lib == "m") {
- HasLibm = true;
- break;
- }
- }
-
- if (HasLibm) {
- // This is not certain to work. The device libs added here, and passed to
- // llvm-link, are missing attributes that they expect to be inserted when
- // passed to mlink-builtin-bitcode. The amdgpu backend does not generate
- // conservatively correct code when attributes are missing, so this may
- // be the root cause of miscompilations. Passing via mlink-builtin-bitcode
- // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes
- // on each function, see D28538 for context.
- // Potential workarounds:
- // - unconditionally link all of the device libs to every translation
- // unit in clang via mlink-builtin-bitcode
- // - build a libm bitcode file as part of the DeviceRTL and explictly
- // mlink-builtin-bitcode the rocm device libs components at build time
- // - drop this llvm-link fork in favour or some calls into LLVM, chosen
- // to do basically the same work as llvm-link but with that call first
- // - write an opt pass that sets that on every function it sees and pipe
- // the device-libs bitcode through that on the way to this llvm-link
- SmallVector<std::string, 12> BCLibs =
- AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str());
- llvm::for_each(BCLibs, [&](StringRef BCFile) {
- CmdArgs.push_back(Args.MakeArgString(BCFile));
- });
- }
- }
-
- AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn",
- SubArchName, /*isBitCodeSDL=*/true,
- /*postClangLink=*/false);
- // Add an intermediate output file.
- CmdArgs.push_back("-o");
- const char *OutputFileName =
- getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
- CmdArgs.push_back(OutputFileName);
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs,
- InputInfo(&JA, Args.MakeArgString(OutputFileName))));
-
- // If we linked in libm definitions late we run another round of optimizations
- // to inline the definitions and fold what is foldable.
- if (HasLibm) {
- ArgStringList OptCmdArgs;
- const char *OptOutputFileName =
- getOutputFileName(C, OutputFilePrefix, "-linked-opt", "bc");
- addLLCOptArg(Args, OptCmdArgs);
- OptCmdArgs.push_back(OutputFileName);
- OptCmdArgs.push_back("-o");
- OptCmdArgs.push_back(OptOutputFileName);
- const char *OptExec =
- Args.MakeArgString(getToolChain().GetProgramPath("opt"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), OptExec, OptCmdArgs,
- InputInfo(&JA, Args.MakeArgString(OutputFileName)),
- InputInfo(&JA, Args.MakeArgString(OptOutputFileName))));
- OutputFileName = OptOutputFileName;
- }
-
- return OutputFileName;
-}
-
-const char *AMDGCN::OpenMPLinker::constructLlcCommand(
- Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix, const char *InputFileName,
- bool OutputIsAsm) const {
- // Construct llc command.
- ArgStringList LlcArgs;
- // The input to llc is the output from opt.
- LlcArgs.push_back(InputFileName);
- // Pass optimization arg to llc.
- addLLCOptArg(Args, LlcArgs);
- LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
- LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
- LlcArgs.push_back(
- Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")));
-
- for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
- LlcArgs.push_back(A->getValue(0));
- }
-
- // Add output filename
- LlcArgs.push_back("-o");
- const char *LlcOutputFile =
- getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");
- LlcArgs.push_back(LlcOutputFile);
- const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs,
- InputInfo(&JA, Args.MakeArgString(LlcOutputFile))));
- return LlcOutputFile;
-}
-
-void AMDGCN::OpenMPLinker::constructLldCommand(
- Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
- const InputInfo &Output, const llvm::opt::ArgList &Args,
- const char *InputFileName) const {
- // Construct lld command.
- // The output from ld.lld is an HSA code object file.
- ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined",
- "-shared", "-o", Output.getFilename(),
- InputFileName};
-
- const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs,
- InputInfo(&JA, Args.MakeArgString(Output.getFilename()))));
-}
-
-// For amdgcn the inputs of the linker job are device bitcode and output is
-// object file. It calls llvm-link, opt, llc, then lld steps.
-void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const ToolChain &TC = getToolChain();
- assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target");
-
- const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC =
- static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC);
-
- std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str();
- if (GPUArch.empty()) {
- if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch))
- return;
- }
-
- // Prefix for temporary file name.
- std::string Prefix;
- for (const auto &II : Inputs)
- if (II.isFilename())
- Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch;
- assert(Prefix.length() && "no linker inputs are files ");
-
- // Each command outputs different files.
- const char *LLVMLinkCommand = constructLLVMLinkCommand(
- AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix);
-
- // Produce readable assembly if save-temps is enabled.
- if (C.getDriver().isSaveTempsEnabled())
- constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand,
- /*OutputIsAsm=*/true);
- const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch,
- Prefix, LLVMLinkCommand);
- constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand);
-}
-
AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D,
const llvm::Triple &Triple,
const ToolChain &HostTC,
const ArgList &Args)
: ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
// Lookup binaries into the driver directory, this is used to
- // discover the clang-offload-bundler executable.
+ // discover the 'amdgpu-arch' executable.
getProgramPaths().push_back(getDriver().Dir);
}
@@ -269,11 +44,8 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions(
Action::OffloadKind DeviceOffloadingKind) const {
HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
- std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str();
- if (GPUArch.empty()) {
- if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch))
- return;
- }
+ StringRef GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
+ assert(!GPUArch.empty() && "Must have an explicit GPU arch.");
assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
"Only OpenMP offloading kinds are supported.");
@@ -285,19 +57,15 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions(
if (DriverArgs.hasArg(options::OPT_nogpulib))
return;
+ for (auto BCFile : getDeviceLibs(DriverArgs)) {
+ CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
+ : "-mlink-bitcode-file");
+ CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
+ }
+
// Link the bitcode library late if we're using device LTO.
if (getDriver().isUsingLTO(/* IsOffload */ true))
return;
-
- std::string BitcodeSuffix;
- if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime,
- options::OPT_fno_openmp_target_new_runtime, true))
- BitcodeSuffix = "new-amdgpu-" + GPUArch;
- else
- BitcodeSuffix = "amdgcn-" + GPUArch;
-
- addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix,
- getTriple());
}
llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
@@ -315,9 +83,20 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
if (!llvm::is_contained(*DAL, A))
DAL->append(A);
- std::string Arch = DAL->getLastArgValue(options::OPT_march_EQ).str();
- if (Arch.empty()) {
- checkSystemForAMDGPU(Args, *this, Arch);
+ if (!DAL->hasArg(options::OPT_march_EQ)) {
+ StringRef Arch = BoundArch;
+ if (Arch.empty()) {
+ auto ArchsOrErr = getSystemGPUArchs(Args);
+ if (!ArchsOrErr) {
+ std::string ErrMsg =
+ llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError()));
+ getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march";
+ Arch = CudaArchToString(CudaArch::HIPDefault);
+ } else {
+ Arch = Args.MakeArgString(ArchsOrErr->front());
+ }
+ }
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
}
@@ -337,11 +116,6 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
return DAL;
}
-Tool *AMDGPUOpenMPToolChain::buildLinker() const {
- assert(getTriple().isAMDGCN());
- return new tools::AMDGCN::OpenMPLinker(*this);
-}
-
void AMDGPUOpenMPToolChain::addClangWarningOptions(
ArgStringList &CC1Args) const {
HostTC.addClangWarningOptions(CC1Args);
@@ -380,3 +154,24 @@ AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D,
const ArgList &Args) const {
return HostTC.computeMSVCVersion(D, Args);
}
+
+llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
+AMDGPUOpenMPToolChain::getDeviceLibs(const llvm::opt::ArgList &Args) const {
+ if (Args.hasArg(options::OPT_nogpulib))
+ return {};
+
+ if (!RocmInstallation->hasDeviceLibrary()) {
+ getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
+ return {};
+ }
+
+ StringRef GpuArch = getProcessorFromTargetID(
+ getTriple(), Args.getLastArgValue(options::OPT_march_EQ));
+
+ SmallVector<BitCodeLibraryInfo, 12> BCLibs;
+ for (auto BCLib : getCommonDeviceLibNames(Args, GpuArch.str(),
+ /*IsOpenMP=*/true))
+ BCLibs.emplace_back(BCLib);
+
+ return BCLibs;
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h
index 233256bf7378..2be444a42c55 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h
@@ -20,49 +20,6 @@ namespace toolchains {
class AMDGPUOpenMPToolChain;
}
-namespace tools {
-
-namespace AMDGCN {
-// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with
-// device library, then compiles it to ISA in a shared object.
-class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool {
-public:
- OpenMPLinker(const ToolChain &TC)
- : Tool("AMDGCN::OpenMPLinker", "amdgcn-link", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-
-private:
- /// \return llvm-link output file name.
- const char *constructLLVMLinkCommand(
- const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C,
- const JobAction &JA, const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix) const;
-
- /// \return llc output file name.
- const char *constructLlcCommand(Compilation &C, const JobAction &JA,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args,
- llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix,
- const char *InputFileName,
- bool OutputIsAsm = false) const;
-
- void constructLldCommand(Compilation &C, const JobAction &JA,
- const InputInfoList &Inputs, const InputInfo &Output,
- const llvm::opt::ArgList &Args,
- const char *InputFileName) const;
-};
-
-} // end namespace AMDGCN
-} // end namespace tools
-
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY AMDGPUOpenMPToolChain final
@@ -97,10 +54,10 @@ public:
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
- const ToolChain &HostTC;
+ llvm::SmallVector<BitCodeLibraryInfo, 12>
+ getDeviceLibs(const llvm::opt::ArgList &Args) const override;
-protected:
- Tool *buildLinker() const override;
+ const ToolChain &HostTC;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp
index 2cf16cf9fdb4..bb5c0e6db997 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp
@@ -12,13 +12,12 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
using namespace clang::driver;
using namespace clang::driver::toolchains;
@@ -28,6 +27,7 @@ using namespace llvm::opt;
namespace {
+// NOTE: This list has been synchronized with gcc-avr 7.3.0 and avr-libc 2.0.0.
constexpr struct {
StringRef Name;
StringRef SubPath;
@@ -62,6 +62,7 @@ constexpr struct {
{"attiny261a", "avr25/tiny-stack", "avr25", 0x800060},
{"at86rf401", "avr25", "avr25", 0x800060},
{"ata5272", "avr25", "avr25", 0x800100},
+ {"ata6616c", "avr25", "avr25", 0x800100},
{"attiny4313", "avr25", "avr25", 0x800060},
{"attiny44", "avr25", "avr25", 0x800060},
{"attiny44a", "avr25", "avr25", 0x800060},
@@ -88,6 +89,8 @@ constexpr struct {
{"at90usb82", "avr35", "avr35", 0x800100},
{"at90usb162", "avr35", "avr35", 0x800100},
{"ata5505", "avr35", "avr35", 0x800100},
+ {"ata6617c", "avr35", "avr35", 0x800100},
+ {"ata664251", "avr35", "avr35", 0x800100},
{"atmega8u2", "avr35", "avr35", 0x800100},
{"atmega16u2", "avr35", "avr35", 0x800100},
{"atmega32u2", "avr35", "avr35", 0x800100},
@@ -97,6 +100,7 @@ constexpr struct {
{"atmega8a", "avr4", "avr4", 0x800060},
{"ata6285", "avr4", "avr4", 0x800100},
{"ata6286", "avr4", "avr4", 0x800100},
+ {"ata6612c", "avr4", "avr4", 0x800100},
{"atmega48", "avr4", "avr4", 0x800100},
{"atmega48a", "avr4", "avr4", 0x800100},
{"atmega48pa", "avr4", "avr4", 0x800100},
@@ -116,8 +120,17 @@ constexpr struct {
{"at90pwm3", "avr4", "avr4", 0x800100},
{"at90pwm3b", "avr4", "avr4", 0x800100},
{"at90pwm81", "avr4", "avr4", 0x800100},
+ {"ata5702m322", "avr5", "avr5", 0x800200},
+ {"ata5782", "avr5", "avr5", 0x800200},
{"ata5790", "avr5", "avr5", 0x800100},
+ {"ata5790n", "avr5", "avr5", 0x800100},
+ {"ata5791", "avr5", "avr5", 0x800100},
{"ata5795", "avr5", "avr5", 0x800100},
+ {"ata5831", "avr5", "avr5", 0x800200},
+ {"ata6613c", "avr5", "avr5", 0x800100},
+ {"ata6614q", "avr5", "avr5", 0x800100},
+ {"ata8210", "avr5", "avr5", 0x800200},
+ {"ata8510", "avr5", "avr5", 0x800200},
{"atmega16", "avr5", "avr5", 0x800060},
{"atmega16a", "avr5", "avr5", 0x800060},
{"atmega161", "avr5", "avr5", 0x800060},
@@ -145,6 +158,7 @@ constexpr struct {
{"atmega324a", "avr5", "avr5", 0x800100},
{"atmega324p", "avr5", "avr5", 0x800100},
{"atmega324pa", "avr5", "avr5", 0x800100},
+ {"atmega324pb", "avr5", "avr5", 0x800100},
{"atmega325", "avr5", "avr5", 0x800100},
{"atmega325a", "avr5", "avr5", 0x800100},
{"atmega325p", "avr5", "avr5", 0x800100},
@@ -155,6 +169,7 @@ constexpr struct {
{"atmega3250pa", "avr5", "avr5", 0x800100},
{"atmega328", "avr5", "avr5", 0x800100},
{"atmega328p", "avr5", "avr5", 0x800100},
+ {"atmega328pb", "avr5", "avr5", 0x800100},
{"atmega329", "avr5", "avr5", 0x800100},
{"atmega329a", "avr5", "avr5", 0x800100},
{"atmega329p", "avr5", "avr5", 0x800100},
@@ -192,6 +207,7 @@ constexpr struct {
{"atmega32hvb", "avr5", "avr5", 0x800100},
{"atmega32hvbrevb", "avr5", "avr5", 0x800100},
{"atmega64hve", "avr5", "avr5", 0x800100},
+ {"atmega64hve2", "avr5", "avr5", 0x800100},
{"at90can32", "avr5", "avr5", 0x800100},
{"at90can64", "avr5", "avr5", 0x800100},
{"at90pwm161", "avr5", "avr5", 0x800100},
@@ -232,17 +248,22 @@ constexpr struct {
{"attiny10", "avrtiny", "avrtiny", 0x800040},
{"attiny20", "avrtiny", "avrtiny", 0x800040},
{"attiny40", "avrtiny", "avrtiny", 0x800040},
+ {"attiny102", "avrtiny", "avrtiny", 0x800040},
+ {"attiny104", "avrtiny", "avrtiny", 0x800040},
{"atxmega16a4", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega16a4u", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega16c4", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega16d4", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega32a4", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega32a4u", "avrxmega2", "avrxmega2", 0x802000},
+ {"atxmega32c3", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega32c4", "avrxmega2", "avrxmega2", 0x802000},
+ {"atxmega32d3", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega32d4", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega32e5", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega16e5", "avrxmega2", "avrxmega2", 0x802000},
{"atxmega8e5", "avrxmega2", "avrxmega2", 0x802000},
+ {"atxmega64a3", "avrxmega4", "avrxmega4", 0x802000},
{"atxmega64a3u", "avrxmega4", "avrxmega4", 0x802000},
{"atxmega64a4u", "avrxmega4", "avrxmega4", 0x802000},
{"atxmega64b1", "avrxmega4", "avrxmega4", 0x802000},
@@ -274,6 +295,42 @@ constexpr struct {
{"atxmega128a1", "avrxmega7", "avrxmega7", 0x802000},
{"atxmega128a1u", "avrxmega7", "avrxmega7", 0x802000},
{"atxmega128a4u", "avrxmega7", "avrxmega7", 0x802000},
+ {"attiny202", "avrxmega3/short-calls", "avrxmega3", 0x803F80},
+ {"attiny204", "avrxmega3/short-calls", "avrxmega3", 0x803F80},
+ {"attiny212", "avrxmega3/short-calls", "avrxmega3", 0x803F80},
+ {"attiny214", "avrxmega3/short-calls", "avrxmega3", 0x803F80},
+ {"attiny402", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny404", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny406", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny412", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny414", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny416", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny417", "avrxmega3/short-calls", "avrxmega3", 0x803F00},
+ {"attiny804", "avrxmega3/short-calls", "avrxmega3", 0x803E00},
+ {"attiny806", "avrxmega3/short-calls", "avrxmega3", 0x803E00},
+ {"attiny807", "avrxmega3/short-calls", "avrxmega3", 0x803E00},
+ {"attiny814", "avrxmega3/short-calls", "avrxmega3", 0x803E00},
+ {"attiny816", "avrxmega3/short-calls", "avrxmega3", 0x803E00},
+ {"attiny817", "avrxmega3/short-calls", "avrxmega3", 0x803E00},
+ {"atmega808", "avrxmega3/short-calls", "avrxmega3", 0x803C00},
+ {"atmega809", "avrxmega3/short-calls", "avrxmega3", 0x803C00},
+ {"atmega1608", "avrxmega3", "avrxmega3", 0x803800},
+ {"atmega1609", "avrxmega3", "avrxmega3", 0x803800},
+ {"atmega3208", "avrxmega3", "avrxmega3", 0x803000},
+ {"atmega3209", "avrxmega3", "avrxmega3", 0x803000},
+ {"atmega4808", "avrxmega3", "avrxmega3", 0x802800},
+ {"atmega4809", "avrxmega3", "avrxmega3", 0x802800},
+ {"attiny1604", "avrxmega3", "avrxmega3", 0x803C00},
+ {"attiny1606", "avrxmega3", "avrxmega3", 0x803C00},
+ {"attiny1607", "avrxmega3", "avrxmega3", 0x803C00},
+ {"attiny1614", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny1616", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny1617", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny1624", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny1626", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny1627", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny3216", "avrxmega3", "avrxmega3", 0x803800},
+ {"attiny3217", "avrxmega3", "avrxmega3", 0x803800},
};
std::string GetMCUSubPath(StringRef MCUName) {
@@ -283,18 +340,18 @@ std::string GetMCUSubPath(StringRef MCUName) {
return "";
}
-llvm::Optional<StringRef> GetMCUFamilyName(StringRef MCUName) {
+std::optional<StringRef> GetMCUFamilyName(StringRef MCUName) {
for (const auto &MCU : MCUInfo)
if (MCU.Name == MCUName)
- return Optional<StringRef>(MCU.Family);
- return Optional<StringRef>();
+ return std::optional<StringRef>(MCU.Family);
+ return std::nullopt;
}
-llvm::Optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) {
+std::optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) {
for (const auto &MCU : MCUInfo)
if (MCU.Name == MCUName && MCU.DataAddr > 0)
- return Optional<unsigned>(MCU.DataAddr);
- return Optional<unsigned>();
+ return std::optional<unsigned>(MCU.DataAddr);
+ return std::nullopt;
}
const StringRef PossibleAVRLibcLocations[] = {
@@ -308,49 +365,18 @@ const StringRef PossibleAVRLibcLocations[] = {
/// AVR Toolchain
AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
- : Generic_ELF(D, Triple, Args), LinkStdlib(false) {
+ : Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
+ if (getCPUName(D, Args, Triple).empty())
+ D.Diag(diag::warn_drv_avr_mcu_not_specified);
+
// Only add default libraries if the user hasn't explicitly opted out.
if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs) &&
- !Args.hasArg(options::OPT_c /* does not apply when not linking */)) {
- std::string CPU = getCPUName(D, Args, Triple);
-
- if (CPU.empty()) {
- // We cannot link any standard libraries without an MCU specified.
- D.Diag(diag::warn_drv_avr_mcu_not_specified);
- } else {
- Optional<StringRef> FamilyName = GetMCUFamilyName(CPU);
- Optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
-
- if (!FamilyName.hasValue()) {
- // We do not have an entry for this CPU in the family
- // mapping table yet.
- D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented)
- << CPU;
- } else if (!GCCInstallation.isValid()) {
- // No avr-gcc found and so no runtime linked.
- D.Diag(diag::warn_drv_avr_gcc_not_found);
- } else if (!AVRLibcRoot.hasValue()) {
- // No avr-libc found and so no runtime linked.
- D.Diag(diag::warn_drv_avr_libc_not_found);
- } else { // We have enough information to link stdlibs
- std::string GCCRoot(GCCInstallation.getInstallPath());
- std::string GCCParentPath(GCCInstallation.getParentLibPath());
- std::string LibcRoot = AVRLibcRoot.getValue();
- std::string SubPath = GetMCUSubPath(CPU);
-
- getProgramPaths().push_back(GCCParentPath + "/../bin");
- getFilePaths().push_back(LibcRoot + std::string("/lib/") + SubPath);
- getFilePaths().push_back(GCCRoot + std::string("/") + SubPath);
-
- LinkStdlib = true;
- }
- }
-
- if (!LinkStdlib)
- D.Diag(diag::warn_drv_avr_stdlib_not_linked);
+ !Args.hasArg(options::OPT_nodefaultlibs) && GCCInstallation.isValid()) {
+ GCCInstallPath = GCCInstallation.getInstallPath();
+ std::string GCCParentPath(GCCInstallation.getParentLibPath());
+ getProgramPaths().push_back(GCCParentPath + "/../bin");
}
}
@@ -361,12 +387,12 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return;
// Omit if there is no avr-libc installed.
- Optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
- if (!AVRLibcRoot.hasValue())
+ std::optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
+ if (!AVRLibcRoot)
return;
// Add 'avr-libc/include' to clang system include paths if applicable.
- std::string AVRInc = AVRLibcRoot.getValue() + "/include";
+ std::string AVRInc = *AVRLibcRoot + "/include";
if (llvm::sys::fs::is_directory(AVRInc))
addSystemInclude(DriverArgs, CC1Args, AVRInc);
}
@@ -387,41 +413,116 @@ void AVRToolChain::addClangTargetOptions(
}
Tool *AVRToolChain::buildLinker() const {
- return new tools::AVR::Linker(getTriple(), *this, LinkStdlib);
+ return new tools::AVR::Linker(getTriple(), *this);
+}
+
+std::string
+AVRToolChain::getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ FileType Type = ToolChain::FT_Static) const {
+ assert(Type == ToolChain::FT_Static && "AVR only supports static libraries");
+ // Since AVR can never be a host environment, its compiler-rt library files
+ // should always have ".a" suffix, even on windows.
+ SmallString<32> File("/libclang_rt.");
+ File += Component.str();
+ File += ".a";
+ // Return the default compiler-rt path appended with
+ // "avr/libclang_rt.$COMPONENT.a".
+ SmallString<256> Path(ToolChain::getCompilerRTPath());
+ llvm::sys::path::append(Path, "avr");
+ llvm::sys::path::append(Path, File.str());
+ return std::string(Path);
}
void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs, const ArgList &Args,
const char *LinkingOutput) const {
+ const auto &TC = static_cast<const AVRToolChain &>(getToolChain());
const Driver &D = getToolChain().getDriver();
// Compute information about the target AVR.
std::string CPU = getCPUName(D, Args, getToolChain().getTriple());
- llvm::Optional<StringRef> FamilyName = GetMCUFamilyName(CPU);
- llvm::Optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU);
+ std::optional<StringRef> FamilyName = GetMCUFamilyName(CPU);
+ std::optional<std::string> AVRLibcRoot = TC.findAVRLibcInstallation();
+ std::optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU);
+
+ // Compute the linker program path, and use GNU "avr-ld" as default.
+ const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ);
+ std::string Linker = A ? getToolChain().GetLinkerPath(nullptr)
+ : getToolChain().GetProgramPath(getShortName());
- std::string Linker = getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
// Enable garbage collection of unused sections.
- CmdArgs.push_back("--gc-sections");
+ if (!Args.hasArg(options::OPT_r))
+ CmdArgs.push_back("--gc-sections");
// Add library search paths before we specify libraries.
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
- if (SectionAddressData.hasValue()) {
- std::string DataSectionArg = std::string("-Tdata=0x") +
- llvm::utohexstr(SectionAddressData.getValue());
- CmdArgs.push_back(Args.MakeArgString(DataSectionArg));
- } else {
- // We do not have an entry for this CPU in the address mapping table yet.
- D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) << CPU;
+ // Currently we only support libgcc and compiler-rt.
+ auto RtLib = TC.GetRuntimeLibType(Args);
+ assert(
+ (RtLib == ToolChain::RLT_Libgcc || RtLib == ToolChain::RLT_CompilerRT) &&
+ "unknown runtime library");
+
+ // Only add default libraries if the user hasn't explicitly opted out.
+ bool LinkStdlib = false;
+ if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_r) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!CPU.empty()) {
+ if (!FamilyName) {
+ // We do not have an entry for this CPU in the family
+ // mapping table yet.
+ D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented)
+ << CPU;
+ } else if (!AVRLibcRoot) {
+ // No avr-libc found and so no runtime linked.
+ D.Diag(diag::warn_drv_avr_libc_not_found);
+ } else {
+ std::string SubPath = GetMCUSubPath(CPU);
+ // Add path of avr-libc.
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath));
+ if (RtLib == ToolChain::RLT_Libgcc)
+ CmdArgs.push_back(Args.MakeArgString("-L" + TC.getGCCInstallPath() +
+ "/" + SubPath));
+ LinkStdlib = true;
+ }
+ }
+ if (!LinkStdlib)
+ D.Diag(diag::warn_drv_avr_stdlib_not_linked);
+ }
+
+ if (!Args.hasArg(options::OPT_r)) {
+ if (SectionAddressData) {
+ CmdArgs.push_back(
+ Args.MakeArgString("--defsym=__DATA_REGION_ORIGIN__=0x" +
+ Twine::utohexstr(*SectionAddressData)));
+ } else {
+ // We do not have an entry for this CPU in the address mapping table
+ // yet.
+ D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented)
+ << CPU;
+ }
+ }
+
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(TC, Args, CmdArgs, Output, *Input,
+ D.getLTOMode() == LTOK_Thin);
}
// If the family name is known, we can link with the device-specific libgcc.
@@ -436,28 +537,63 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o");
CmdArgs.push_back(Args.MakeArgString(CrtFileName));
- CmdArgs.push_back("-lgcc");
+ // Link to libgcc.
+ if (RtLib == ToolChain::RLT_Libgcc)
+ CmdArgs.push_back("-lgcc");
+
+ // Link to generic libraries of avr-libc.
CmdArgs.push_back("-lm");
CmdArgs.push_back("-lc");
// Add the link library specific to the MCU.
CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU));
+ // Add the relocatable inputs.
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ // We directly use libclang_rt.builtins.a as input file, instead of using
+ // '-lclang_rt.builtins'.
+ if (RtLib == ToolChain::RLT_CompilerRT) {
+ std::string RtLib =
+ getToolChain().getCompilerRT(Args, "builtins", ToolChain::FT_Static);
+ if (llvm::sys::fs::exists(RtLib))
+ CmdArgs.push_back(Args.MakeArgString(RtLib));
+ }
+
CmdArgs.push_back("--end-group");
- // Specify the family name as the emulation mode to use.
- // This is almost always required because otherwise avr-ld
- // will assume 'avr2' and warn about the program being larger
- // than the bare minimum supports.
- CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
+ // Add avr-libc's linker script to lld by default, if it exists.
+ if (!Args.hasArg(options::OPT_T) &&
+ Linker.find("avr-ld") == std::string::npos) {
+ std::string Path(*AVRLibcRoot + "/lib/ldscripts/");
+ Path += *FamilyName;
+ Path += ".x";
+ if (llvm::sys::fs::exists(Path))
+ CmdArgs.push_back(Args.MakeArgString("-T" + Path));
+ }
+ // Otherwise add user specified linker script to either avr-ld or lld.
+ else
+ Args.AddAllArgs(CmdArgs, options::OPT_T);
+
+ if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
+ CmdArgs.push_back("--relax");
+ } else {
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
}
+ // Specify the family name as the emulation mode to use.
+ // This is almost always required because otherwise avr-ld
+ // will assume 'avr2' and warn about the program being larger
+ // than the bare minimum supports.
+ if (Linker.find("avr-ld") != std::string::npos && FamilyName)
+ CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
+
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker),
CmdArgs, Inputs, Output));
}
-llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
+std::optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
// Search avr-libc installation according to avr-gcc installation.
std::string GCCParent(GCCInstallation.getParentLibPath());
std::string Path(GCCParent + "/avr");
@@ -475,5 +611,5 @@ llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
return Path;
}
- return llvm::None;
+ return std::nullopt;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h
index 2d027957ed76..247188b7eaad 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h
@@ -31,28 +31,28 @@ public:
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const override;
+ std::optional<std::string> findAVRLibcInstallation() const;
+ StringRef getGCCInstallPath() const { return GCCInstallPath; }
+ std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ FileType Type) const override;
+
+ bool HasNativeLLVMSupport() const override { return true; }
+
protected:
Tool *buildLinker() const override;
private:
- /// Whether libgcc, libct, and friends should be linked.
- ///
- /// This is not done if the user does not specify a
- /// microcontroller on the command line.
- bool LinkStdlib;
-
- llvm::Optional<std::string> findAVRLibcInstallation() const;
+ StringRef GCCInstallPath;
};
} // end namespace toolchains
namespace tools {
namespace AVR {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
- Linker(const llvm::Triple &Triple, const ToolChain &TC, bool LinkStdlib)
- : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple),
- LinkStdlib(LinkStdlib) {}
+ Linker(const llvm::Triple &Triple, const ToolChain &TC)
+ : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -63,7 +63,6 @@ public:
protected:
const llvm::Triple &Triple;
- bool LinkStdlib;
};
} // end namespace AVR
} // end namespace tools
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp
deleted file mode 100644
index be1476a7636c..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Ananas.h"
-#include "CommonArgs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/InputInfo.h"
-#include "clang/Driver/Options.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Path.h"
-
-using namespace clang::driver;
-using namespace clang::driver::tools;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileCurCP(),
- Exec, CmdArgs, Inputs, Output));
-}
-
-void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const ToolChain &ToolChain = getToolChain();
- const Driver &D = ToolChain.getDriver();
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
- } else {
- Args.AddAllArgs(CmdArgs, options::OPT_pie);
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/lib/ld-ananas.so");
- }
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
- }
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) {
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
- } else {
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
- }
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
-
- if (D.isUsingLTO()) {
- assert(!Inputs.empty() && "Must have at least one input.");
- addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
- D.getLTOMode() == LTOK_Thin);
- }
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (ToolChain.ShouldLinkCXXStdlib(Args))
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
- CmdArgs.push_back("-lc");
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
- else
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
- }
-
- const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileCurCP(),
- Exec, CmdArgs, Inputs, Output));
-}
-
-// Ananas - Ananas tool chain which can call as(1) and ld(1) directly.
-
-Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
-}
-
-Tool *Ananas::buildAssembler() const {
- return new tools::ananas::Assembler(*this);
-}
-
-Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h
deleted file mode 100644
index 72ad3edcf056..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
-
-#include "Gnu.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Driver/ToolChain.h"
-
-namespace clang {
-namespace driver {
-namespace tools {
-
-/// ananas -- Directly call GNU Binutils assembler and linker
-namespace ananas {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("ananas::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("ananas::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace ananas
-} // end namespace tools
-
-namespace toolchains {
-
-class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF {
-public:
- Ananas(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-} // end namespace toolchains
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index 53610f0909a2..0cf96bb5c9cb 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -7,13 +7,13 @@
//===----------------------------------------------------------------------===//
#include "AArch64.h"
+#include "../CommonArgs.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Support/AArch64TargetParser.h"
-#include "llvm/Support/TargetParser.h"
-#include "llvm/Support/Host.h"
+#include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -38,6 +38,8 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
CPU = Mcpu.split("+").first.lower();
}
+ CPU = llvm::AArch64::resolveCPUAlias(CPU);
+
// Handle CPU name is 'native'.
if (CPU == "native")
return std::string(llvm::sys::getHostCPUName());
@@ -51,13 +53,17 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
return "apple-m1";
}
+ if (Triple.isXROS()) {
+ // The xrOS simulator runs on M1 as well, it should have been covered above.
+ assert(!Triple.isSimulatorEnvironment() && "xrossim should be mac-like");
+ return "apple-a12";
+ }
// arm64e requires v8.3a and only runs on apple-a12 and later CPUs.
if (Triple.isArm64e())
return "apple-a12";
- // 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())
+ // Make sure we pick the appropriate Apple CPU when targetting a Darwin OS.
+ if (Triple.isOSDarwin())
return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4"
: "apple-a7";
@@ -66,107 +72,68 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
static bool DecodeAArch64Features(const Driver &D, StringRef text,
- std::vector<StringRef> &Features,
- llvm::AArch64::ArchKind ArchKind) {
+ llvm::AArch64::ExtensionSet &Extensions) {
SmallVector<StringRef, 8> Split;
text.split(Split, StringRef("+"), -1, false);
for (StringRef Feature : Split) {
- StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
- if (!FeatureName.empty())
- Features.push_back(FeatureName);
- else if (Feature == "neon" || Feature == "noneon")
+ if (Feature == "neon" || Feature == "noneon") {
D.Diag(clang::diag::err_drv_no_neon_modifier);
- else
- return false;
-
- if (Feature == "sve2")
- Features.push_back("+sve");
- else if (Feature == "sve2-bitperm" || Feature == "sve2-sha3" ||
- Feature == "sve2-aes" || Feature == "sve2-sm4") {
- Features.push_back("+sve");
- Features.push_back("+sve2");
- } else if (Feature == "nosve") {
- Features.push_back("-sve2");
- Features.push_back("-sve2-bitperm");
- Features.push_back("-sve2-sha3");
- Features.push_back("-sve2-aes");
- Features.push_back("-sve2-sm4");
- } else if (Feature == "nosve2") {
- Features.push_back("-sve2-bitperm");
- Features.push_back("-sve2-sha3");
- Features.push_back("-sve2-aes");
- Features.push_back("-sve2-sm4");
+ continue;
}
-
- // +sve implies +f32mm if the base architecture is >= v8.6A (except v9A)
- // It isn't the case in general that sve implies both f64mm and f32mm
- if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV8_7A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV8_8A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_1A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_2A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_3A) &&
- Feature == "sve")
- Features.push_back("+f32mm");
+ if (!Extensions.parseModifier(Feature))
+ return false;
}
+
return true;
}
// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
// decode CPU and feature.
static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
- std::vector<StringRef> &Features) {
+ llvm::AArch64::ExtensionSet &Extensions) {
std::pair<StringRef, StringRef> Split = Mcpu.split("+");
CPU = Split.first;
- llvm::AArch64::ArchKind ArchKind = llvm::AArch64::ArchKind::ARMV8A;
if (CPU == "native")
CPU = llvm::sys::getHostCPUName();
if (CPU == "generic") {
- Features.push_back("+neon");
+ Extensions.enable(llvm::AArch64::AEK_SIMD);
} else {
- ArchKind = llvm::AArch64::parseCPUArch(CPU);
- if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
+ const std::optional<llvm::AArch64::CpuInfo> CpuInfo =
+ llvm::AArch64::parseCpu(CPU);
+ if (!CpuInfo)
return false;
- uint64_t Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind);
- if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
- return false;
- }
+ Extensions.addCPUDefaults(*CpuInfo);
+ }
- if (Split.second.size() &&
- !DecodeAArch64Features(D, Split.second, Features, ArchKind))
- return false;
+ if (Split.second.size() &&
+ !DecodeAArch64Features(D, Split.second, Extensions))
+ return false;
- return true;
+ return true;
}
static bool
getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
const ArgList &Args,
- std::vector<StringRef> &Features) {
+ llvm::AArch64::ExtensionSet &Extensions) {
std::string MarchLowerCase = March.lower();
std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
- llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first);
- if (ArchKind == llvm::AArch64::ArchKind::INVALID ||
- !llvm::AArch64::getArchFeatures(ArchKind, Features))
+ const llvm::AArch64::ArchInfo *ArchInfo =
+ llvm::AArch64::parseArch(Split.first);
+ if (Split.first == "native")
+ ArchInfo = llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str());
+ if (!ArchInfo)
return false;
- // Enable SVE2 by default on Armv9-A.
- // It can still be disabled if +nosve2 is present.
- // We must do this early so that DecodeAArch64Features has the correct state
- if ((ArchKind == llvm::AArch64::ArchKind::ARMV9A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_1A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_2A)) {
- Features.push_back("+sve");
- Features.push_back("+sve2");
- }
+ Extensions.addArchDefaults(*ArchInfo);
if ((Split.second.size() &&
- !DecodeAArch64Features(D, Split.second, Features, ArchKind)))
+ !DecodeAArch64Features(D, Split.second, Extensions)))
return false;
return true;
@@ -175,10 +142,10 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
static bool
getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
const ArgList &Args,
- std::vector<StringRef> &Features) {
+ llvm::AArch64::ExtensionSet &Extensions) {
StringRef CPU;
std::string McpuLowerCase = Mcpu.lower();
- if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
+ if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Extensions))
return false;
return true;
@@ -189,17 +156,17 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
const ArgList &Args,
std::vector<StringRef> &Features) {
std::string MtuneLowerCase = Mtune.lower();
- // Check CPU name is valid
- std::vector<StringRef> MtuneFeatures;
+ // Check CPU name is valid, but ignore any extensions on it.
+ llvm::AArch64::ExtensionSet Extensions;
StringRef Tune;
- if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures))
+ if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, Extensions))
return false;
// Handle CPU name is 'native'.
if (MtuneLowerCase == "native")
MtuneLowerCase = std::string(llvm::sys::getHostCPUName());
if (MtuneLowerCase == "cyclone" ||
- StringRef(MtuneLowerCase).startswith("apple")) {
+ StringRef(MtuneLowerCase).starts_with("apple")) {
Features.push_back("+zcm");
Features.push_back("+zcz");
}
@@ -211,7 +178,8 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
const ArgList &Args,
std::vector<StringRef> &Features) {
StringRef CPU;
- std::vector<StringRef> DecodedFeature;
+ // Check CPU name is valid, but ignore any extensions on it.
+ llvm::AArch64::ExtensionSet DecodedFeature;
std::string McpuLowerCase = Mcpu.lower();
if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
return false;
@@ -222,35 +190,35 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
void aarch64::getAArch64TargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
std::vector<StringRef> &Features,
bool ForAS) {
Arg *A;
bool success = true;
- // Enable NEON by default.
- Features.push_back("+neon");
llvm::StringRef WaMArch;
+ llvm::AArch64::ExtensionSet Extensions;
if (ForAS)
for (const auto *A :
Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler))
for (StringRef Value : A->getValues())
- if (Value.startswith("-march="))
+ if (Value.starts_with("-march="))
WaMArch = Value.substr(7);
// Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or
// "-Xassembler -march" is detected. Otherwise it may return false
// and causes Clang to error out.
if (!WaMArch.empty())
- success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Features);
+ success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Extensions);
else if ((A = Args.getLastArg(options::OPT_march_EQ)))
- success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
+ success =
+ getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Extensions);
else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
- success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
- else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))
+ success =
+ getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions);
+ else if (isCPUDeterminedByTriple(Triple))
success = getAArch64ArchFeaturesFromMcpu(
- D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
+ D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions);
else
// Default to 'A' profile if the architecture is not specified.
- success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Features);
+ success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Extensions);
if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
success =
@@ -258,36 +226,48 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
success =
getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
- else if (success &&
- (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)))
+ else if (success && isCPUDeterminedByTriple(Triple))
success = getAArch64MicroArchFeaturesFromMcpu(
D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
if (!success) {
- auto Diag = D.Diag(diag::err_drv_clang_unsupported);
+ auto Diag = D.Diag(diag::err_drv_unsupported_option_argument);
// If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value,
// while 'A' is uninitialized. Only dereference 'A' in the other case.
if (!WaMArch.empty())
- Diag << "-march=" + WaMArch.str();
+ Diag << "-march=" << WaMArch;
else
- Diag << A->getAsString(Args);
+ Diag << A->getSpelling() << A->getValue();
}
+ // -mgeneral-regs-only disables all floating-point features.
if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
- Features.push_back("-fp-armv8");
- Features.push_back("-crypto");
- Features.push_back("-neon");
+ Extensions.disable(llvm::AArch64::AEK_FP);
+ }
+
+ // En/disable crc
+ if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
+ if (A->getOption().matches(options::OPT_mcrc))
+ Extensions.enable(llvm::AArch64::AEK_CRC);
+ else
+ Extensions.disable(llvm::AArch64::AEK_CRC);
}
+ // At this point all hardware features are decided, so convert the extensions
+ // set to a feature list.
+ Extensions.toLLVMFeatureList(Features);
+
if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
StringRef Mtp = A->getValue();
- if (Mtp == "el3")
+ if (Mtp == "el3" || Mtp == "tpidr_el3")
Features.push_back("+tpidr-el3");
- else if (Mtp == "el2")
+ else if (Mtp == "el2" || Mtp == "tpidr_el2")
Features.push_back("+tpidr-el2");
- else if (Mtp == "el1")
+ else if (Mtp == "el1" || Mtp == "tpidr_el1")
Features.push_back("+tpidr-el1");
- else if (Mtp != "el0")
+ else if (Mtp == "tpidrro_el0")
+ Features.push_back("+tpidrro-el0");
+ else if (Mtp != "el0" && Mtp != "tpidr_el0")
D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
}
@@ -323,8 +303,8 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
DisableComdat = true;
continue;
}
- D.Diag(diag::err_invalid_sls_hardening)
- << Scope << A->getAsString(Args);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Scope;
break;
}
}
@@ -338,144 +318,12 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
}
}
- // En/disable crc
- if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
- if (A->getOption().matches(options::OPT_mcrc))
- Features.push_back("+crc");
- else
- Features.push_back("-crc");
- }
-
- // Handle (arch-dependent) fp16fml/fullfp16 relationship.
- // FIXME: this fp16fml option handling will be reimplemented after the
- // TargetParser rewrite.
- const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16");
- const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml");
- if (llvm::is_contained(Features, "+v8.4a")) {
- const auto ItRFullFP16 = std::find(Features.rbegin(), Features.rend(), "+fullfp16");
- if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) {
- // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml.
- // Only append the +fp16fml if there is no -fp16fml after the +fullfp16.
- if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16)
- Features.push_back("+fp16fml");
- }
- else
- goto fp16_fml_fallthrough;
- } else {
-fp16_fml_fallthrough:
- // In both of these cases, putting the 'other' feature on the end of the vector will
- // result in the same effect as placing it immediately after the current feature.
- if (ItRNoFullFP16 < ItRFP16FML)
- Features.push_back("-fp16fml");
- else if (ItRNoFullFP16 > ItRFP16FML)
- Features.push_back("+fullfp16");
- }
-
- // FIXME: this needs reimplementation too after the TargetParser rewrite
- //
- // Context sensitive meaning of Crypto:
- // 1) For Arch >= ARMv8.4a: crypto = sm4 + sha3 + sha2 + aes
- // 2) For Arch <= ARMv8.3a: crypto = sha2 + aes
- const auto ItBegin = Features.begin();
- const auto ItEnd = Features.end();
- const auto ItRBegin = Features.rbegin();
- const auto ItREnd = Features.rend();
- const auto ItRCrypto = std::find(ItRBegin, ItREnd, "+crypto");
- const auto ItRNoCrypto = std::find(ItRBegin, ItREnd, "-crypto");
- const auto HasCrypto = ItRCrypto != ItREnd;
- const auto HasNoCrypto = ItRNoCrypto != ItREnd;
- const ptrdiff_t PosCrypto = ItRCrypto - ItRBegin;
- const ptrdiff_t PosNoCrypto = ItRNoCrypto - ItRBegin;
-
- bool NoCrypto = false;
- if (HasCrypto && HasNoCrypto) {
- if (PosNoCrypto < PosCrypto)
- NoCrypto = true;
- }
-
- if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd ||
- std::find(ItBegin, ItEnd, "+v8.8a") != ItEnd ||
- std::find(ItBegin, ItEnd, "+v9a") != ItEnd ||
- std::find(ItBegin, ItEnd, "+v9.1a") != ItEnd ||
- std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd ||
- std::find(ItBegin, ItEnd, "+v9.3a") != ItEnd) {
- if (HasCrypto && !NoCrypto) {
- // Check if we have NOT disabled an algorithm with something like:
- // +crypto, -algorithm
- // And if "-algorithm" does not occur, we enable that crypto algorithm.
- const bool HasSM4 = (std::find(ItBegin, ItEnd, "-sm4") == ItEnd);
- const bool HasSHA3 = (std::find(ItBegin, ItEnd, "-sha3") == ItEnd);
- const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd);
- const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd);
- if (HasSM4)
- Features.push_back("+sm4");
- if (HasSHA3)
- Features.push_back("+sha3");
- if (HasSHA2)
- Features.push_back("+sha2");
- if (HasAES)
- Features.push_back("+aes");
- } else if (HasNoCrypto) {
- // Check if we have NOT enabled a crypto algorithm with something like:
- // -crypto, +algorithm
- // And if "+algorithm" does not occur, we disable that crypto algorithm.
- const bool HasSM4 = (std::find(ItBegin, ItEnd, "+sm4") != ItEnd);
- const bool HasSHA3 = (std::find(ItBegin, ItEnd, "+sha3") != ItEnd);
- const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd);
- const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd);
- if (!HasSM4)
- Features.push_back("-sm4");
- if (!HasSHA3)
- Features.push_back("-sha3");
- if (!HasSHA2)
- Features.push_back("-sha2");
- if (!HasAES)
- Features.push_back("-aes");
- }
- } else {
- if (HasCrypto && !NoCrypto) {
- const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd);
- const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd);
- if (HasSHA2)
- Features.push_back("+sha2");
- if (HasAES)
- Features.push_back("+aes");
- } else if (HasNoCrypto) {
- const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd);
- const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd);
- const bool HasV82a = (std::find(ItBegin, ItEnd, "+v8.2a") != ItEnd);
- const bool HasV83a = (std::find(ItBegin, ItEnd, "+v8.3a") != ItEnd);
- const bool HasV84a = (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd);
- if (!HasSHA2)
- Features.push_back("-sha2");
- if (!HasAES)
- Features.push_back("-aes");
- if (HasV82a || HasV83a || HasV84a) {
- Features.push_back("-sm4");
- Features.push_back("-sha3");
- }
- }
- }
-
- const char *Archs[] = {"+v8.6a", "+v8.7a", "+v8.8a",
- "+v9.1a", "+v9.2a", "+v9.3a"};
- auto Pos = std::find_first_of(Features.begin(), Features.end(),
- std::begin(Archs), std::end(Archs));
- if (Pos != std::end(Features))
- Pos = Features.insert(std::next(Pos), {"+i8mm", "+bf16"});
-
if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access)) {
- if (A->getOption().matches(options::OPT_mno_unaligned_access)) {
+ if (A->getOption().matches(options::OPT_mno_unaligned_access))
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
- }
- } else if (Triple.isOSOpenBSD()) {
+ } else if (Triple.isOSOpenBSD())
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
- }
if (Args.hasArg(options::OPT_ffixed_x1))
Features.push_back("+reserve-x1");
@@ -588,9 +436,13 @@ fp16_fml_fallthrough:
Features.push_back("+fix-cortex-a53-835769");
else
Features.push_back("-fix-cortex-a53-835769");
- } else if (Triple.isAndroid()) {
+ } else if (Triple.isAndroid() || Triple.isOHOSFamily()) {
// Enabled A53 errata (835769) workaround by default on android
Features.push_back("+fix-cortex-a53-835769");
+ } else if (Triple.isOSFuchsia()) {
+ std::string CPU = getCPUName(D, Args, Triple);
+ if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
+ Features.push_back("+fix-cortex-a53-835769");
}
if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h
index 0cdc2ec725e0..d47c402d4a42 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h
@@ -22,7 +22,6 @@ namespace aarch64 {
void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
std::vector<llvm::StringRef> &Features,
bool ForAS);
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index 16af9f6d7129..e6ee2f88a84e 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -12,9 +12,8 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Support/ARMTargetParser.h"
-#include "llvm/Support/TargetParser.h"
-#include "llvm/Support/Host.h"
+#include "llvm/TargetParser/ARMTargetParser.h"
+#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -33,6 +32,20 @@ bool arm::isARMMProfile(const llvm::Triple &Triple) {
return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M;
}
+// On Arm the endianness of the output file is determined by the target and
+// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and
+// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a
+// normalized triple so we must handle the flag here.
+bool arm::isARMBigEndian(const llvm::Triple &Triple, const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian)) {
+ return !A->getOption().matches(options::OPT_mlittle_endian);
+ }
+
+ return Triple.getArch() == llvm::Triple::armeb ||
+ Triple.getArch() == llvm::Triple::thumbeb;
+}
+
// True if A-profile.
bool arm::isARMAProfile(const llvm::Triple &Triple) {
llvm::StringRef Arch = Triple.getArchName();
@@ -54,9 +67,9 @@ void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
// Use getValues because -Wa can have multiple arguments
// e.g. -Wa,-mcpu=foo,-mcpu=bar
for (StringRef Value : A->getValues()) {
- if (Value.startswith("-mcpu="))
+ if (Value.starts_with("-mcpu="))
CPU = Value.substr(6);
- if (Value.startswith("-march="))
+ if (Value.starts_with("-march="))
Arch = Value.substr(7);
}
}
@@ -73,25 +86,25 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A,
}
// Handle -mfpu=.
-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))
+static llvm::ARM::FPUKind getARMFPUFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args, StringRef FPU,
+ std::vector<StringRef> &Features) {
+ llvm::ARM::FPUKind FPUKind = llvm::ARM::parseFPU(FPU);
+ if (!llvm::ARM::getFPUFeatures(FPUKind, Features))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
- return FPUID;
+ return FPUKind;
}
// Decode ARM features from string like +[no]featureA+[no]featureB+...
static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU,
llvm::ARM::ArchKind ArchKind,
std::vector<StringRef> &Features,
- unsigned &ArgFPUID) {
+ llvm::ARM::FPUKind &ArgFPUKind) {
SmallVector<StringRef, 8> Split;
text.split(Split, StringRef("+"), -1, false);
for (StringRef Feature : Split) {
- if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUID))
+ if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUKind))
return false;
}
return true;
@@ -113,31 +126,52 @@ static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU,
static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
llvm::StringRef ArchName, llvm::StringRef CPUName,
std::vector<StringRef> &Features,
- const llvm::Triple &Triple, unsigned &ArgFPUID) {
+ const llvm::Triple &Triple,
+ llvm::ARM::FPUKind &ArgFPUKind) {
std::pair<StringRef, StringRef> Split = ArchName.split("+");
std::string MArch = arm::getARMArch(ArchName, Triple);
llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch);
if (ArchKind == llvm::ARM::ArchKind::INVALID ||
- (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPUName,
- ArchKind, Features, ArgFPUID)))
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ (Split.second.size() &&
+ !DecodeARMFeatures(D, Split.second, CPUName, ArchKind, Features,
+ ArgFPUKind)))
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << A->getValue();
}
// Check -mcpu=. Needs ArchName to handle -mcpu=generic.
static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
llvm::StringRef CPUName, llvm::StringRef ArchName,
std::vector<StringRef> &Features,
- const llvm::Triple &Triple, unsigned &ArgFPUID) {
+ const llvm::Triple &Triple,
+ llvm::ARM::FPUKind &ArgFPUKind) {
std::pair<StringRef, StringRef> Split = CPUName.split("+");
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
llvm::ARM::ArchKind ArchKind =
arm::getLLVMArchKindForARM(CPU, ArchName, Triple);
if (ArchKind == llvm::ARM::ArchKind::INVALID ||
- (Split.second.size() &&
- !DecodeARMFeatures(D, Split.second, CPU, ArchKind, Features, ArgFPUID)))
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPU, ArchKind,
+ Features, ArgFPUKind)))
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << A->getValue();
+}
+
+// If -mfloat-abi=hard or -mhard-float are specified explicitly then check that
+// floating point registers are available on the target CPU.
+static void checkARMFloatABI(const Driver &D, const ArgList &Args,
+ bool HasFPRegs) {
+ if (HasFPRegs)
+ return;
+ const Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ);
+ if (A && (A->getOption().matches(options::OPT_mhard_float) ||
+ (A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
+ A->getValue() == StringRef("hard"))))
+ D.Diag(clang::diag::warn_drv_no_floating_point_registers)
+ << A->getAsString(Args);
}
bool arm::useAAPCSForMachO(const llvm::Triple &T) {
@@ -164,11 +198,16 @@ arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
arm::ReadTPMode ThreadPointer =
llvm::StringSwitch<arm::ReadTPMode>(A->getValue())
- .Case("cp15", ReadTPMode::Cp15)
+ .Case("cp15", ReadTPMode::TPIDRURO)
+ .Case("tpidrurw", ReadTPMode::TPIDRURW)
+ .Case("tpidruro", ReadTPMode::TPIDRURO)
+ .Case("tpidrprw", ReadTPMode::TPIDRPRW)
.Case("soft", ReadTPMode::Soft)
.Default(ReadTPMode::Invalid);
- if (ThreadPointer == ReadTPMode::Cp15 && !isHardTPSupported(Triple) &&
- !ForAS) {
+ if ((ThreadPointer == ReadTPMode::TPIDRURW ||
+ ThreadPointer == ReadTPMode::TPIDRURO ||
+ ThreadPointer == ReadTPMode::TPIDRPRW) &&
+ !isHardTPSupported(Triple) && !ForAS) {
D.Diag(diag::err_target_unsupported_tp_hard) << Triple.getArchName();
return ReadTPMode::Invalid;
}
@@ -246,9 +285,9 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args,
// There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm.
if (Value == "-mthumb")
IsThumb = true;
- else if (Value.startswith("-march="))
+ else if (Value.starts_with("-march="))
WaMArch = Value.substr(7);
- else if (Value.startswith("-mcpu="))
+ else if (Value.starts_with("-mcpu="))
WaMCPU = Value.substr(6);
}
}
@@ -274,6 +313,11 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args,
void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args,
llvm::Triple &Triple) {
+ if (Triple.isOSLiteOS()) {
+ Triple.setEnvironment(llvm::Triple::OpenHOS);
+ return;
+ }
+
bool isHardFloat =
(arm::getARMFloatABI(D, Triple, Args) == arm::FloatABI::Hard);
@@ -293,6 +337,8 @@ void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args,
Triple.setEnvironment(isHardFloat ? llvm::Triple::MuslEABIHF
: llvm::Triple::MuslEABI);
break;
+ case llvm::Triple::OpenHOS:
+ break;
default: {
arm::FloatABI DefaultABI = arm::getDefaultFloatABI(Triple);
if (DefaultABI != arm::FloatABI::Invalid &&
@@ -320,6 +366,8 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) {
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
+ case llvm::Triple::DriverKit:
+ case llvm::Triple::XROS:
// Darwin defaults to "softfp" for v6 and v7.
if (Triple.isWatchABI())
return FloatABI::Hard;
@@ -357,10 +405,13 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) {
}
break;
+ case llvm::Triple::Haiku:
case llvm::Triple::OpenBSD:
return FloatABI::SoftFP;
default:
+ if (Triple.isOHOSFamily())
+ return FloatABI::Soft;
switch (Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
case llvm::Triple::MuslEABIHF:
@@ -433,14 +484,15 @@ static bool hasIntegerMVE(const std::vector<StringRef> &F) {
(NoMVE == F.rend() || std::distance(MVE, NoMVE) > 0);
}
-void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs,
- std::vector<StringRef> &Features, bool ForAS) {
+llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features,
+ bool ForAS, bool ForMultilib) {
bool KernelOrKext =
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args);
- llvm::Optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv,
- WaArch;
+ std::optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch;
// This vector will accumulate features from the architecture
// extension suffixes on -mcpu and -march (e.g. the 'bar' in
@@ -477,28 +529,38 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// We use getValues here because you can have many options per -Wa
// We will keep the last one we find for each of these
for (StringRef Value : A->getValues()) {
- if (Value.startswith("-mfpu=")) {
+ if (Value.starts_with("-mfpu=")) {
WaFPU = std::make_pair(A, Value.substr(6));
- } else if (Value.startswith("-mcpu=")) {
+ } else if (Value.starts_with("-mcpu=")) {
WaCPU = std::make_pair(A, Value.substr(6));
- } else if (Value.startswith("-mhwdiv=")) {
+ } else if (Value.starts_with("-mhwdiv=")) {
WaHDiv = std::make_pair(A, Value.substr(8));
- } else if (Value.startswith("-march=")) {
+ } else if (Value.starts_with("-march=")) {
WaArch = std::make_pair(A, Value.substr(7));
}
}
}
+
+ // The integrated assembler doesn't implement e_flags setting behavior for
+ // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For
+ // compatibility we accept but warn.
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
+ A->ignoreTargetSpecific();
}
- if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::Cp15)
- Features.push_back("+read-tp-hard");
+ if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURW)
+ Features.push_back("+read-tp-tpidrurw");
+ if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURO)
+ Features.push_back("+read-tp-tpidruro");
+ if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRPRW)
+ Features.push_back("+read-tp-tpidrprw");
const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
StringRef ArchName;
StringRef CPUName;
- unsigned ArchArgFPUID = llvm::ARM::FK_INVALID;
- unsigned CPUArgFPUID = llvm::ARM::FK_INVALID;
+ llvm::ARM::FPUKind ArchArgFPUKind = llvm::ARM::FK_INVALID;
+ llvm::ARM::FPUKind CPUArgFPUKind = llvm::ARM::FK_INVALID;
// Check -mcpu. ClangAs gives preference to -Wa,-mcpu=.
if (WaCPU) {
@@ -518,13 +580,13 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
ArchName = WaArch->second;
// This will set any features after the base architecture.
checkARMArchName(D, WaArch->first, Args, ArchName, CPUName,
- ExtensionFeatures, Triple, ArchArgFPUID);
+ ExtensionFeatures, Triple, ArchArgFPUKind);
// The base architecture was handled in ToolChain::ComputeLLVMTriple because
// triple is read only by this point.
} else if (ArchArg) {
ArchName = ArchArg->getValue();
checkARMArchName(D, ArchArg, Args, ArchName, CPUName, ExtensionFeatures,
- Triple, ArchArgFPUID);
+ Triple, ArchArgFPUKind);
}
// Add CPU features for generic CPUs
@@ -544,9 +606,14 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (CPUArg)
checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures,
- Triple, CPUArgFPUID);
+ Triple, CPUArgFPUKind);
+
+ // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
+ // longstanding behavior.
+ (void)Args.getLastArg(options::OPT_mtune_EQ);
+
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
- unsigned FPUID = llvm::ARM::FK_INVALID;
+ llvm::ARM::FPUKind FPUKind = llvm::ARM::FK_INVALID;
const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
if (WaFPU) {
if (FPUArg)
@@ -554,20 +621,25 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
<< FPUArg->getAsString(Args);
(void)getARMFPUFeatures(D, WaFPU->first, Args, WaFPU->second, Features);
} else if (FPUArg) {
- FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
+ FPUKind = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
} else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) {
const char *AndroidFPU = "neon";
- FPUID = llvm::ARM::parseFPU(AndroidFPU);
- if (!llvm::ARM::getFPUFeatures(FPUID, Features))
+ FPUKind = llvm::ARM::parseFPU(AndroidFPU);
+ if (!llvm::ARM::getFPUFeatures(FPUKind, Features))
D.Diag(clang::diag::err_drv_clang_unsupported)
<< std::string("-mfpu=") + AndroidFPU;
+ } else if (ArchArgFPUKind != llvm::ARM::FK_INVALID ||
+ CPUArgFPUKind != llvm::ARM::FK_INVALID) {
+ FPUKind =
+ CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind;
+ (void)llvm::ARM::getFPUFeatures(FPUKind, Features);
} else {
if (!ForAS) {
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
llvm::ARM::ArchKind ArchKind =
arm::getLLVMArchKindForARM(CPU, ArchName, Triple);
- FPUID = llvm::ARM::getDefaultFPU(CPU, ArchKind);
- (void)llvm::ARM::getFPUFeatures(FPUID, Features);
+ FPUKind = llvm::ARM::getDefaultFPU(CPU, ArchKind);
+ (void)llvm::ARM::getFPUFeatures(FPUKind, Features);
}
}
@@ -618,25 +690,30 @@ fp16_fml_fallthrough:
// -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in
// this case). Note that the ABI can also be set implicitly by the target
// selected.
+ bool HasFPRegs = true;
if (ABI == arm::FloatABI::Soft) {
llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features);
// Disable all features relating to hardware FP, not already disabled by the
// above call.
- Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve",
- "-mve.fp", "-fpregs"});
- } else if (FPUID == llvm::ARM::FK_NONE ||
- ArchArgFPUID == llvm::ARM::FK_NONE ||
- CPUArgFPUID == llvm::ARM::FK_NONE) {
+ Features.insert(Features.end(),
+ {"-dotprod", "-fp16fml", "-bf16", "-mve", "-mve.fp"});
+ HasFPRegs = false;
+ FPUKind = llvm::ARM::FK_NONE;
+ } else if (FPUKind == llvm::ARM::FK_NONE ||
+ ArchArgFPUKind == llvm::ARM::FK_NONE ||
+ CPUArgFPUKind == llvm::ARM::FK_NONE) {
// -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to
// -mfloat-abi=soft, only that it should not disable MVE-I. They disable the
// FPU, but not the FPU registers, thus MVE-I, which depends only on the
// latter, is still supported.
Features.insert(Features.end(),
{"-dotprod", "-fp16fml", "-bf16", "-mve.fp"});
- if (!hasIntegerMVE(Features))
- Features.emplace_back("-fpregs");
+ HasFPRegs = hasIntegerMVE(Features);
+ FPUKind = llvm::ARM::FK_NONE;
}
+ if (!HasFPRegs)
+ Features.emplace_back("-fpregs");
// En/disable crc code generation.
if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
@@ -717,6 +794,15 @@ fp16_fml_fallthrough:
}
}
+ // Propagate frame-chain model selection
+ if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
+ StringRef FrameChainOption = A->getValue();
+ if (FrameChainOption.starts_with("aapcs"))
+ Features.push_back("+aapcs-frame-chain");
+ if (FrameChainOption == "aapcs+leaf")
+ Features.push_back("+aapcs-frame-chain-leaf");
+ }
+
// CMSE: Check for target 8M (for -mcmse to be applicable) is performed later.
if (Args.getLastArg(options::OPT_mcmse))
Features.push_back("+8msecext");
@@ -733,6 +819,16 @@ fp16_fml_fallthrough:
Features.push_back("-fix-cmse-cve-2021-35465");
}
+ // This also handles the -m(no-)fix-cortex-a72-1655431 arguments via aliases.
+ if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a57_aes_1742098,
+ options::OPT_mno_fix_cortex_a57_aes_1742098)) {
+ if (A->getOption().matches(options::OPT_mfix_cortex_a57_aes_1742098)) {
+ Features.push_back("+fix-cortex-a57-aes-1742098");
+ } else {
+ Features.push_back("-fix-cortex-a57-aes-1742098");
+ }
+ }
+
// Look for the last occurrence of -mlong-calls or -mno-long-calls. If
// neither options are specified, see if we are compiling for kernel/kext and
// decide whether to pass "+long-calls" based on the OS and its version.
@@ -741,29 +837,32 @@ fp16_fml_fallthrough:
if (A->getOption().matches(options::OPT_mlong_calls))
Features.push_back("+long-calls");
} else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) &&
- !Triple.isWatchOS()) {
- Features.push_back("+long-calls");
+ !Triple.isWatchOS() && !Triple.isXROS()) {
+ Features.push_back("+long-calls");
}
// Generate execute-only output (no data access to code sections).
// This only makes sense for the compiler, not for the assembler.
- if (!ForAS) {
+ // It's not needed for multilib selection and may hide an unused
+ // argument diagnostic if the code is always run.
+ if (!ForAS && !ForMultilib) {
// Supported only on ARMv6T2 and ARMv7 and above.
- // Cannot be combined with -mno-movt or -mlong-calls
+ // Cannot be combined with -mno-movt.
if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) {
if (A->getOption().matches(options::OPT_mexecute_only)) {
if (getARMSubArchVersionNumber(Triple) < 7 &&
- llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2)
+ llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2 &&
+ llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6M)
D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName();
- else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- // Long calls create constant pool entries and have not yet been fixed up
- // to play nicely with execute-only. Hence, they cannot be used in
- // execute-only code for now
- else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) {
- if (B->getOption().matches(options::OPT_mlong_calls))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- }
+ else if (llvm::ARM::parseArch(Triple.getArchName()) == llvm::ARM::ArchKind::ARMV6M) {
+ if (Arg *PIArg = Args.getLastArg(options::OPT_fropi, options::OPT_frwpi,
+ options::OPT_fpic, options::OPT_fpie,
+ options::OPT_fPIC, options::OPT_fPIE))
+ D.Diag(diag::err_opt_not_valid_with_opt_on_target)
+ << A->getAsString(Args) << PIArg->getAsString(Args) << Triple.getArchName();
+ } else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
+ D.Diag(diag::err_opt_not_valid_with_opt)
+ << A->getAsString(Args) << B->getAsString(Args);
Features.push_back("+execute-only");
}
}
@@ -772,8 +871,6 @@ fp16_fml_fallthrough:
// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
} else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_munaligned_access)) {
@@ -784,11 +881,8 @@ fp16_fml_fallthrough:
// access either.
else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline)
D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base";
- } else {
+ } else
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
- }
} else {
// Assume pre-ARMv6 doesn't support unaligned accesses.
//
@@ -807,23 +901,14 @@ fp16_fml_fallthrough:
int VersionNum = getARMSubArchVersionNumber(Triple);
if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
if (VersionNum < 6 ||
- Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) {
+ Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
- }
} else if (Triple.isOSLinux() || Triple.isOSNaCl() ||
Triple.isOSWindows()) {
- if (VersionNum < 7) {
+ if (VersionNum < 7)
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
- }
- } else {
+ } else
Features.push_back("+strict-align");
- if (!ForAS)
- CmdArgs.push_back("-Wunaligned-access");
- }
}
// llvm does not support reserving registers in general. There is support
@@ -871,8 +956,8 @@ fp16_fml_fallthrough:
DisableComdat = true;
continue;
}
- D.Diag(diag::err_invalid_sls_hardening)
- << Scope << A->getAsString(Args);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Scope;
break;
}
}
@@ -893,6 +978,10 @@ fp16_fml_fallthrough:
if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
Features.push_back("+no-bti-at-return-twice");
+
+ checkARMFloatABI(D, Args, HasFPRegs);
+
+ return FPUKind;
}
std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
@@ -931,7 +1020,7 @@ StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) {
// We need to return an empty string here on invalid MArch values as the
// various places that call this function can't cope with a null result.
- return Triple.getARMCPUForArch(MArch);
+ return llvm::ARM::getARMCPUForArch(Triple, MArch);
}
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
@@ -964,7 +1053,8 @@ llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch,
if (ArchKind == llvm::ARM::ArchKind::INVALID)
// In case of generic Arch, i.e. "arm",
// extract arch from default cpu of the Triple
- ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch));
+ ArchKind =
+ llvm::ARM::parseCPUArch(llvm::ARM::getARMCPUForArch(Triple, ARMArch));
} else {
// FIXME: horrible hack to get around the fact that Cortex-A7 is only an
// armv7k triple if it's actually been specified via "-arch armv7k".
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h
index 862a2f2796be..fa62ac89e3a1 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h
@@ -11,10 +11,10 @@
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
+#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
-#include "llvm/Support/ARMTargetParser.h"
-#include "llvm/Support/TargetParser.h"
+#include "llvm/TargetParser/ARMTargetParser.h"
+#include "llvm/TargetParser/Triple.h"
#include <string>
#include <vector>
@@ -38,7 +38,9 @@ void appendBE8LinkFlag(const llvm::opt::ArgList &Args,
enum class ReadTPMode {
Invalid,
Soft,
- Cp15,
+ TPIDRURW,
+ TPIDRURO,
+ TPIDRPRW,
};
enum class FloatABI {
@@ -64,13 +66,15 @@ bool useAAPCSForMachO(const llvm::Triple &T);
void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args,
llvm::StringRef &Arch, llvm::StringRef &CPU,
bool FromAs = false);
-void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- std::vector<llvm::StringRef> &Features, bool ForAS);
+llvm::ARM::FPUKind getARMTargetFeatures(const Driver &D,
+ const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features,
+ bool ForAS, bool ForMultilib = false);
int getARMSubArchVersionNumber(const llvm::Triple &Triple);
bool isARMMProfile(const llvm::Triple &Triple);
bool isARMAProfile(const llvm::Triple &Triple);
+bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args);
} // end namespace arm
} // end namespace tools
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp
new file mode 100644
index 000000000000..e94ea12f46dc
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp
@@ -0,0 +1,169 @@
+//===--- CSKY.cpp - CSKY Helpers for Tools --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CSKY.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/CSKYTargetParser.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/TargetParser.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+std::optional<llvm::StringRef>
+csky::getCSKYArchName(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseArch(A->getValue());
+
+ if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
+ D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
+ return std::nullopt;
+ }
+ return std::optional<llvm::StringRef>(A->getValue());
+ }
+
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
+ llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(A->getValue());
+ if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ return std::nullopt;
+ }
+ return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind));
+ }
+
+ return std::optional<llvm::StringRef>("ck810");
+}
+
+csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) {
+ csky::FloatABI ABI = FloatABI::Soft;
+ if (Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(options::OPT_msoft_float)) {
+ ABI = FloatABI::Soft;
+ } else if (A->getOption().matches(options::OPT_mhard_float)) {
+ ABI = FloatABI::Hard;
+ } else {
+ ABI = llvm::StringSwitch<csky::FloatABI>(A->getValue())
+ .Case("soft", FloatABI::Soft)
+ .Case("softfp", FloatABI::SoftFP)
+ .Case("hard", FloatABI::Hard)
+ .Default(FloatABI::Invalid);
+ if (ABI == FloatABI::Invalid) {
+ D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
+ ABI = FloatABI::Soft;
+ }
+ }
+ }
+
+ return ABI;
+}
+
+// Handle -mfpu=.
+static llvm::CSKY::CSKYFPUKind
+getCSKYFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args,
+ StringRef FPU, std::vector<StringRef> &Features) {
+
+ llvm::CSKY::CSKYFPUKind FPUID =
+ llvm::StringSwitch<llvm::CSKY::CSKYFPUKind>(FPU)
+ .Case("auto", llvm::CSKY::FK_AUTO)
+ .Case("fpv2", llvm::CSKY::FK_FPV2)
+ .Case("fpv2_divd", llvm::CSKY::FK_FPV2_DIVD)
+ .Case("fpv2_sf", llvm::CSKY::FK_FPV2_SF)
+ .Case("fpv3", llvm::CSKY::FK_FPV3)
+ .Case("fpv3_hf", llvm::CSKY::FK_FPV3_HF)
+ .Case("fpv3_hsf", llvm::CSKY::FK_FPV3_HSF)
+ .Case("fpv3_sdf", llvm::CSKY::FK_FPV3_SDF)
+ .Default(llvm::CSKY::FK_INVALID);
+ if (FPUID == llvm::CSKY::FK_INVALID) {
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ return llvm::CSKY::FK_INVALID;
+ }
+
+ auto RemoveTargetFPUFeature =
+ [&Features](ArrayRef<const char *> FPUFeatures) {
+ for (auto FPUFeature : FPUFeatures) {
+ auto it = llvm::find(Features, FPUFeature);
+ if (it != Features.end())
+ Features.erase(it);
+ }
+ };
+
+ RemoveTargetFPUFeature({"+fpuv2_sf", "+fpuv2_df", "+fdivdu", "+fpuv3_hi",
+ "+fpuv3_hf", "+fpuv3_sf", "+fpuv3_df"});
+
+ if (!llvm::CSKY::getFPUFeatures(FPUID, Features)) {
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ return llvm::CSKY::FK_INVALID;
+ }
+
+ return FPUID;
+}
+
+void csky::getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ std::vector<llvm::StringRef> &Features) {
+ llvm::StringRef archName;
+ llvm::StringRef cpuName;
+ llvm::CSKY::ArchKind ArchKind = llvm::CSKY::ArchKind::INVALID;
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ ArchKind = llvm::CSKY::parseArch(A->getValue());
+ if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
+ D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
+ return;
+ }
+ archName = A->getValue();
+ }
+
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
+ llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(A->getValue());
+ if (Kind == llvm::CSKY::ArchKind::INVALID) {
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ return;
+ }
+ if (!archName.empty() && Kind != ArchKind) {
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ return;
+ }
+ cpuName = A->getValue();
+ if (archName.empty())
+ archName = llvm::CSKY::getArchName(Kind);
+ }
+
+ if (archName.empty() && cpuName.empty()) {
+ archName = "ck810";
+ cpuName = "ck810";
+ } else if (!archName.empty() && cpuName.empty()) {
+ cpuName = archName;
+ }
+
+ csky::FloatABI FloatABI = csky::getCSKYFloatABI(D, Args);
+
+ if (FloatABI == csky::FloatABI::Hard) {
+ Features.push_back("+hard-float-abi");
+ Features.push_back("+hard-float");
+ } else if (FloatABI == csky::FloatABI::SoftFP) {
+ Features.push_back("+hard-float");
+ }
+
+ uint64_t Extension = llvm::CSKY::getDefaultExtensions(cpuName);
+ llvm::CSKY::getExtensionFeatures(Extension, Features);
+
+ if (const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ))
+ getCSKYFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h
new file mode 100644
index 000000000000..f3730d2cf4a1
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h
@@ -0,0 +1,47 @@
+//===--- CSKY.h - CSKY-specific Tool Helpers ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace csky {
+
+enum class FloatABI {
+ Invalid,
+ Soft,
+ SoftFP,
+ Hard,
+};
+
+FloatABI getCSKYFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+
+void getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ std::vector<llvm::StringRef> &Features);
+
+std::optional<llvm::StringRef> getCSKYArchName(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+
+} // end namespace csky
+} // namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
new file mode 100644
index 000000000000..31153a67ad28
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
@@ -0,0 +1,232 @@
+//===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LoongArch.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/LoongArchTargetParser.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
+ assert((Triple.getArch() == llvm::Triple::loongarch32 ||
+ Triple.getArch() == llvm::Triple::loongarch64) &&
+ "Unexpected triple");
+ bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
+
+ // Record -mabi value for later use.
+ const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ);
+ StringRef MABIValue;
+ if (MABIArg) {
+ MABIValue = MABIArg->getValue();
+ }
+
+ // Parse -mfpu value for later use.
+ const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
+ int FPU = -1;
+ if (MFPUArg) {
+ StringRef V = MFPUArg->getValue();
+ if (V == "64")
+ FPU = 64;
+ else if (V == "32")
+ FPU = 32;
+ else if (V == "0" || V == "none")
+ FPU = 0;
+ else
+ D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V;
+ }
+
+ // Check -m*-float firstly since they have highest priority.
+ if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
+ options::OPT_msingle_float,
+ options::OPT_msoft_float)) {
+ StringRef ImpliedABI;
+ int ImpliedFPU = -1;
+ if (A->getOption().matches(options::OPT_mdouble_float)) {
+ ImpliedABI = IsLA32 ? "ilp32d" : "lp64d";
+ ImpliedFPU = 64;
+ }
+ if (A->getOption().matches(options::OPT_msingle_float)) {
+ ImpliedABI = IsLA32 ? "ilp32f" : "lp64f";
+ ImpliedFPU = 32;
+ }
+ if (A->getOption().matches(options::OPT_msoft_float)) {
+ ImpliedABI = IsLA32 ? "ilp32s" : "lp64s";
+ ImpliedFPU = 0;
+ }
+
+ // Check `-mabi=` and `-mfpu=` settings and report if they conflict with
+ // the higher-priority settings implied by -m*-float.
+ //
+ // ImpliedABI and ImpliedFPU are guaranteed to have valid values because
+ // one of the match arms must match if execution can arrive here at all.
+ if (!MABIValue.empty() && ImpliedABI != MABIValue)
+ D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
+ << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI;
+
+ if (FPU != -1 && ImpliedFPU != FPU)
+ D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
+ << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU;
+
+ return ImpliedABI;
+ }
+
+ // If `-mabi=` is specified, use it.
+ if (!MABIValue.empty())
+ return MABIValue;
+
+ // Select abi based on -mfpu=xx.
+ switch (FPU) {
+ case 64:
+ return IsLA32 ? "ilp32d" : "lp64d";
+ case 32:
+ return IsLA32 ? "ilp32f" : "lp64f";
+ case 0:
+ return IsLA32 ? "ilp32s" : "lp64s";
+ }
+
+ // Choose a default based on the triple.
+ // Honor the explicit ABI modifier suffix in triple's environment part if
+ // present, falling back to {ILP32,LP64}D otherwise.
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::GNUSF:
+ return IsLA32 ? "ilp32s" : "lp64s";
+ case llvm::Triple::GNUF32:
+ return IsLA32 ? "ilp32f" : "lp64f";
+ case llvm::Triple::GNUF64:
+ // This was originally permitted (and indeed the canonical way) to
+ // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to
+ // drop the explicit suffix in favor of unmarked `-gnu` for the
+ // "general-purpose" ABIs, among other non-technical reasons.
+ //
+ // The spec change did not mention whether existing usages of "gnuf64"
+ // shall remain valid or not, so we are going to continue recognizing it
+ // for some time, until it is clear that everyone else has migrated away
+ // from it.
+ [[fallthrough]];
+ case llvm::Triple::GNU:
+ default:
+ return IsLA32 ? "ilp32d" : "lp64d";
+ }
+}
+
+void loongarch::getLoongArchTargetFeatures(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ std::string ArchName;
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ ArchName = A->getValue();
+ ArchName = postProcessTargetCPUString(ArchName, Triple);
+ llvm::LoongArch::getArchFeatures(ArchName, Features);
+
+ // Select floating-point features determined by -mdouble-float,
+ // -msingle-float, -msoft-float and -mfpu.
+ // Note: -m*-float wins any other options.
+ if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
+ options::OPT_msingle_float,
+ options::OPT_msoft_float)) {
+ if (A->getOption().matches(options::OPT_mdouble_float)) {
+ Features.push_back("+f");
+ Features.push_back("+d");
+ } else if (A->getOption().matches(options::OPT_msingle_float)) {
+ Features.push_back("+f");
+ Features.push_back("-d");
+ } else /*Soft-float*/ {
+ Features.push_back("-f");
+ Features.push_back("-d");
+ }
+ } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
+ StringRef FPU = A->getValue();
+ if (FPU == "64") {
+ Features.push_back("+f");
+ Features.push_back("+d");
+ } else if (FPU == "32") {
+ Features.push_back("+f");
+ Features.push_back("-d");
+ } else if (FPU == "0" || FPU == "none") {
+ Features.push_back("-f");
+ Features.push_back("-d");
+ } else {
+ D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
+ }
+ }
+
+ // Select the `ual` feature determined by -m[no-]unaligned-access
+ // or the alias -m[no-]strict-align.
+ AddTargetFeature(Args, Features, options::OPT_munaligned_access,
+ options::OPT_mno_unaligned_access, "ual");
+
+ // Accept but warn about these TargetSpecific options.
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
+ A->ignoreTargetSpecific();
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
+ A->ignoreTargetSpecific();
+
+ // Select lsx feature determined by -m[no-]lsx.
+ if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
+ // LSX depends on 64-bit FPU.
+ // -m*-float and -mfpu=none/0/32 conflict with -mlsx.
+ if (A->getOption().matches(options::OPT_mlsx)) {
+ if (llvm::find(Features, "-d") != Features.end())
+ D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lsx);
+ else /*-mlsx*/
+ Features.push_back("+lsx");
+ } else /*-mno-lsx*/ {
+ Features.push_back("-lsx");
+ }
+ }
+
+ // Select lasx feature determined by -m[no-]lasx.
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) {
+ // LASX depends on 64-bit FPU and LSX.
+ // -mno-lsx conflicts with -mlasx.
+ if (A->getOption().matches(options::OPT_mlasx)) {
+ if (llvm::find(Features, "-d") != Features.end())
+ D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lasx);
+ else if (llvm::find(Features, "-lsx") != Features.end())
+ D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
+ else { /*-mlasx*/
+ Features.push_back("+lsx");
+ Features.push_back("+lasx");
+ }
+ } else /*-mno-lasx*/
+ Features.push_back("-lasx");
+ }
+}
+
+std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
+ const llvm::Triple &Triple) {
+ std::string CPUString = CPU;
+ if (CPUString == "native") {
+ CPUString = llvm::sys::getHostCPUName();
+ if (CPUString == "generic")
+ CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
+ }
+ if (CPUString.empty())
+ CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
+ return CPUString;
+}
+
+std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ std::string CPU;
+ // If we have -march, use that.
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ CPU = A->getValue();
+ return postProcessTargetCPUString(CPU, Triple);
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h
new file mode 100644
index 000000000000..d8280cd836f8
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h
@@ -0,0 +1,37 @@
+//===--- LoongArch.h - LoongArch-specific Tool Helpers ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace loongarch {
+void getLoongArchTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+
+StringRef getLoongArchABI(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+
+std::string postProcessTargetCPUString(const std::string &CPU,
+ const llvm::Triple &Triple);
+
+std::string getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+} // end namespace loongarch
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp
index 119e24cedbab..963f7a187d63 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp
@@ -14,8 +14,8 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/Regex.h"
+#include "llvm/TargetParser/Host.h"
#include <sstream>
using namespace clang::driver;
@@ -65,13 +65,35 @@ std::string m68k::getM68kTargetCPU(const ArgList &Args) {
return "";
}
+static void addFloatABIFeatures(const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features) {
+ Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_m68881);
+ // Opt out FPU even for newer CPUs.
+ if (A && A->getOption().matches(options::OPT_msoft_float)) {
+ Features.push_back("-isa-68881");
+ Features.push_back("-isa-68882");
+ return;
+ }
+
+ std::string CPU = m68k::getM68kTargetCPU(Args);
+ // Only enable M68881 for CPU < 68020 if the related flags are present.
+ if ((A && (CPU == "M68000" || CPU == "M68010")) ||
+ // Otherwise, by default we assume newer CPUs have M68881/2.
+ CPU == "M68020")
+ Features.push_back("+isa-68881");
+ else if (CPU == "M68030" || CPU == "M68040" || CPU == "M68060")
+ // Note that although CPU >= M68040 imply M68882, we still add `isa-68882`
+ // anyway so that it's easier to add or not add the corresponding macro
+ // definitions later, in case we want to disable 68881/2 in newer CPUs
+ // (with -msoft-float, for instance).
+ Features.push_back("+isa-68882");
+}
+
void m68k::getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
-
- m68k::FloatABI FloatABI = m68k::getM68kFloatABI(D, Args);
- if (FloatABI == m68k::FloatABI::Soft)
- Features.push_back("-hard-float");
+ addFloatABIFeatures(Args, Features);
// Handle '-ffixed-<register>' flags
if (Args.hasArg(options::OPT_ffixed_a0))
@@ -105,21 +127,3 @@ void m68k::getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (Args.hasArg(options::OPT_ffixed_d7))
Features.push_back("+reserve-d7");
}
-
-m68k::FloatABI m68k::getM68kFloatABI(const Driver &D, const ArgList &Args) {
- m68k::FloatABI ABI = m68k::FloatABI::Invalid;
- if (Arg *A =
- Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) {
-
- if (A->getOption().matches(options::OPT_msoft_float))
- ABI = m68k::FloatABI::Soft;
- else if (A->getOption().matches(options::OPT_mhard_float))
- ABI = m68k::FloatABI::Hard;
- }
-
- // If unspecified, choose the default based on the platform.
- if (ABI == m68k::FloatABI::Invalid)
- ABI = m68k::FloatABI::Hard;
-
- return ABI;
-}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h
index 41d53efb940b..051e7e1af103 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h
@@ -20,14 +20,6 @@ namespace driver {
namespace tools {
namespace m68k {
-enum class FloatABI {
- Invalid,
- Soft,
- Hard,
-};
-
-FloatABI getM68kFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
-
std::string getM68kTargetCPU(const llvm::opt::ArgList &Args);
void getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple,
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp
index c374d745da38..fe9d112b8800 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -39,12 +39,6 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
DefMips64CPU = "mips64r6";
}
- // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android).
- if (Triple.isAndroid()) {
- DefMips32CPU = "mips32";
- DefMips64CPU = "mips64r6";
- }
-
// MIPS3 is the default for mips64*-unknown-openbsd.
if (Triple.isOSOpenBSD())
DefMips64CPU = "mips3";
@@ -227,6 +221,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
bool IsN64 = ABIName == "64";
bool IsPIC = false;
bool NonPIC = false;
+ bool HasNaN2008Opt = false;
Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
options::OPT_fpic, options::OPT_fno_pic,
@@ -291,9 +286,10 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
StringRef Val = StringRef(A->getValue());
if (Val == "2008") {
- if (mips::getIEEE754Standard(CPUName) & mips::Std2008)
+ if (mips::getIEEE754Standard(CPUName) & mips::Std2008) {
Features.push_back("+nan2008");
- else {
+ HasNaN2008Opt = true;
+ } else {
Features.push_back("-nan2008");
D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
}
@@ -306,7 +302,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
}
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) {
@@ -327,8 +323,10 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
}
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
+ } else if (HasNaN2008Opt) {
+ Features.push_back("+abs2008");
}
AddTargetFeature(Args, Features, options::OPT_msingle_float,
@@ -467,11 +465,6 @@ bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) {
bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
StringRef ABIName, mips::FloatABI FloatABI) {
- if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies &&
- Triple.getVendor() != llvm::Triple::MipsTechnologies &&
- !Triple.isAndroid())
- return false;
-
if (ABIName != "32")
return false;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h
index f4c11a7e3188..62211c711420 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h
@@ -11,8 +11,8 @@
#include "clang/Driver/Driver.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
+#include "llvm/TargetParser/Triple.h"
#include <string>
#include <vector>
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp
index bcaecf4b2d98..ab24d14992cd 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -13,81 +13,83 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Host.h"
+#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
-std::string ppc::getPPCTargetCPU(const ArgList &Args) {
- if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
- StringRef CPUName = A->getValue();
-
- if (CPUName == "native") {
- std::string CPU = std::string(llvm::sys::getHostCPUName());
- if (!CPU.empty() && CPU != "generic")
- return CPU;
- else
- return "";
- }
+static std::string getPPCGenericTargetCPU(const llvm::Triple &T) {
+ // LLVM may default to generating code for the native CPU,
+ // but, like gcc, we default to a more generic option for
+ // each architecture. (except on AIX)
+ if (T.isOSAIX())
+ return "pwr7";
+ else if (T.getArch() == llvm::Triple::ppc64le)
+ return "ppc64le";
+ else if (T.getArch() == llvm::Triple::ppc64)
+ return "ppc64";
+ else
+ return "ppc";
+}
- return llvm::StringSwitch<const char *>(CPUName)
- .Case("common", "generic")
- .Case("440", "440")
- .Case("440fp", "440")
- .Case("450", "450")
- .Case("601", "601")
- .Case("602", "602")
- .Case("603", "603")
- .Case("603e", "603e")
- .Case("603ev", "603ev")
- .Case("604", "604")
- .Case("604e", "604e")
- .Case("620", "620")
- .Case("630", "pwr3")
- .Case("G3", "g3")
- .Case("7400", "7400")
- .Case("G4", "g4")
- .Case("7450", "7450")
- .Case("G4+", "g4+")
- .Case("750", "750")
- .Case("8548", "e500")
- .Case("970", "970")
- .Case("G5", "g5")
- .Case("a2", "a2")
- .Case("e500", "e500")
- .Case("e500mc", "e500mc")
- .Case("e5500", "e5500")
- .Case("power3", "pwr3")
- .Case("power4", "pwr4")
- .Case("power5", "pwr5")
- .Case("power5x", "pwr5x")
- .Case("power6", "pwr6")
- .Case("power6x", "pwr6x")
- .Case("power7", "pwr7")
- .Case("power8", "pwr8")
- .Case("power9", "pwr9")
- .Case("power10", "pwr10")
- .Case("future", "future")
- .Case("pwr3", "pwr3")
- .Case("pwr4", "pwr4")
- .Case("pwr5", "pwr5")
- .Case("pwr5x", "pwr5x")
- .Case("pwr6", "pwr6")
- .Case("pwr6x", "pwr6x")
- .Case("pwr7", "pwr7")
- .Case("pwr8", "pwr8")
- .Case("pwr9", "pwr9")
- .Case("pwr10", "pwr10")
- .Case("powerpc", "ppc")
- .Case("powerpc64", "ppc64")
- .Case("powerpc64le", "ppc64le")
- .Default("");
+static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) {
+ // Clang/LLVM does not actually support code generation
+ // for the 405 CPU. However, there are uses of this CPU ID
+ // in projects that previously used GCC and rely on Clang
+ // accepting it. Clang has always ignored it and passed the
+ // generic CPU ID to the back end.
+ if (CPUName == "generic" || CPUName == "405")
+ return getPPCGenericTargetCPU(T);
+
+ if (CPUName == "native") {
+ std::string CPU = std::string(llvm::sys::getHostCPUName());
+ if (!CPU.empty() && CPU != "generic")
+ return CPU;
+ else
+ return getPPCGenericTargetCPU(T);
}
- return "";
+ return llvm::StringSwitch<const char *>(CPUName)
+ .Case("common", "generic")
+ .Case("440fp", "440")
+ .Case("630", "pwr3")
+ .Case("G3", "g3")
+ .Case("G4", "g4")
+ .Case("G4+", "g4+")
+ .Case("8548", "e500")
+ .Case("G5", "g5")
+ .Case("power3", "pwr3")
+ .Case("power4", "pwr4")
+ .Case("power5", "pwr5")
+ .Case("power5x", "pwr5x")
+ .Case("power6", "pwr6")
+ .Case("power6x", "pwr6x")
+ .Case("power7", "pwr7")
+ .Case("power8", "pwr8")
+ .Case("power9", "pwr9")
+ .Case("power10", "pwr10")
+ .Case("future", "future")
+ .Case("powerpc", "ppc")
+ .Case("powerpc64", "ppc64")
+ .Case("powerpc64le", "ppc64le")
+ .Default(CPUName.data());
+}
+
+/// Get the (LLVM) name of the PowerPC cpu we are tuning for.
+std::string ppc::getPPCTuneCPU(const ArgList &Args, const llvm::Triple &T) {
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))
+ return normalizeCPUName(A->getValue(), T);
+ return getPPCGenericTargetCPU(T);
+}
+
+/// Get the (LLVM) name of the PowerPC cpu we are targeting.
+std::string ppc::getPPCTargetCPU(const Driver &D, const ArgList &Args,
+ const llvm::Triple &T) {
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ))
+ return normalizeCPUName(A->getValue(), T);
+ return getPPCGenericTargetCPU(T);
}
const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
@@ -110,7 +112,8 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe)
Features.push_back("+spe");
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
+ handleTargetFeaturesGroup(D, Triple, Args, Features,
+ options::OPT_m_ppc_Features_Group);
ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
if (FloatABI == ppc::FloatABI::Soft)
@@ -125,8 +128,7 @@ ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Tripl
const ArgList &Args) {
if (Args.getLastArg(options::OPT_msecure_plt))
return ppc::ReadGOTPtrMode::SecurePlt;
- if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) ||
- Triple.isOSNetBSD() || Triple.isOSOpenBSD() || Triple.isMusl())
+ if (Triple.isPPC32SecurePlt())
return ppc::ReadGOTPtrMode::SecurePlt;
else
return ppc::ReadGOTPtrMode::Bss;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h
index e1c943955e81..ec5b3c8140b6 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h
@@ -35,7 +35,10 @@ enum class ReadGOTPtrMode {
FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
-std::string getPPCTargetCPU(const llvm::opt::ArgList &Args);
+std::string getPPCTargetCPU(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &T);
+std::string getPPCTuneCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &T);
const char *getPPCAsmModeForCPU(StringRef Name);
ReadGOTPtrMode getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 94b179636e4f..47b29e1577c2 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -1,4 +1,4 @@
-//===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===//
+//===--- RISCV.cpp - RISC-V Helpers for Tools -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,17 +7,18 @@
//===----------------------------------------------------------------------===//
#include "RISCV.h"
+#include "../Clang.h"
#include "ToolChains/CommonArgs.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/RISCVISAInfo.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -41,22 +42,34 @@ static bool getArchFeatures(const Driver &D, StringRef Arch,
return false;
}
- (*ISAInfo)->toFeatures(
- Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); });
+ for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,
+ /*IgnoreUnknown=*/false))
+ Features.push_back(Args.MakeArgString(Str));
+
+ if (EnableExperimentalExtensions)
+ Features.push_back(Args.MakeArgString("+experimental"));
+
return true;
}
// Get features except standard extension feature
-static void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A, StringRef Mcpu,
+static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A,
+ const llvm::Triple &Triple,
+ StringRef Mcpu,
std::vector<StringRef> &Features) {
- bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64);
- llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu);
- if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) ||
- !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) {
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ bool Is64Bit = Triple.isRISCV64();
+ if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {
+ // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.
+ if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))
+ D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)
+ << Mcpu << Is64Bit;
+ else
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Mcpu;
}
+
+ if (llvm::RISCV::hasFastUnalignedAccess(Mcpu))
+ Features.push_back("+fast-unaligned-access");
}
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
@@ -69,8 +82,13 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// If users give march and mcpu, get std extension feature from MArch
// and other features (ex. mirco architecture feature) from mcpu
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features);
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ StringRef CPU = A->getValue();
+ if (CPU == "native")
+ CPU = llvm::sys::getHostCPUName();
+
+ getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);
+ }
// Handle features corresponding to "-ffixed-X" options
if (Args.hasArg(options::OPT_ffixed_x1))
@@ -138,27 +156,30 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// FreeBSD local, because ld.lld doesn't support relaxations
// -mno-relax is default, unless -mrelax is specified.
- if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false))
+ if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) {
Features.push_back("+relax");
- else
+ // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
+ // into .debug_addr, which is currently not implemented.
+ Arg *A;
+ if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)
+ D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
+ << A->getAsString(Args);
+ } else {
Features.push_back("-relax");
+ }
- // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
- // specified.
- if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false))
- Features.push_back("+save-restore");
- else
- Features.push_back("-save-restore");
+ // -mno-unaligned-access is default, unless -munaligned-access is specified.
+ AddTargetFeature(Args, Features, options::OPT_munaligned_access,
+ options::OPT_mno_unaligned_access, "fast-unaligned-access");
// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
+ handleTargetFeaturesGroup(D, Triple, Args, Features,
+ options::OPT_m_riscv_Features_Group);
}
StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
- assert((Triple.getArch() == llvm::Triple::riscv32 ||
- Triple.getArch() == llvm::Triple::riscv64) &&
- "Unexpected triple");
+ assert(Triple.isRISCV() && "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
@@ -190,23 +211,22 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
// rv32e -> ilp32e
// rv32* -> ilp32
// rv64g | rv64*d -> lp64d
+ // rv64e -> lp64e
// rv64* -> lp64
StringRef Arch = getRISCVArch(Args, Triple);
auto ParseResult = llvm::RISCVISAInfo::parseArchString(
Arch, /* EnableExperimentalExtension */ true);
- if (!ParseResult)
- // Ignore parsing error, just go 3rd step.
- consumeError(ParseResult.takeError());
- else
- return llvm::RISCV::computeDefaultABIFromArch(**ParseResult);
+ // Ignore parsing error, just go 3rd step.
+ if (!llvm::errorToBool(ParseResult.takeError()))
+ return (*ParseResult)->computeDefaultABI();
// 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.isRISCV32()) {
if (Triple.getOS() == llvm::Triple::UnknownOS)
return "ilp32";
else
@@ -221,9 +241,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
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");
+ assert(Triple.isRISCV() && "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
@@ -257,7 +275,10 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// 2. Get march (isa string) based on `-mcpu=`
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue());
+ StringRef CPU = A->getValue();
+ if (CPU == "native")
+ CPU = llvm::sys::getHostCPUName();
+ StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
// Bypass if target cpu's default march is empty.
if (MArch != "")
return MArch;
@@ -266,6 +287,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// 3. Choose a default based on `-mabi=`
//
// ilp32e -> rv32e
+ // lp64e -> rv64e
// ilp32 | ilp32f | ilp32d -> rv32imafdc
// lp64 | lp64f | lp64d -> rv64imafdc
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
@@ -273,10 +295,16 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
if (MABI.equals_insensitive("ilp32e"))
return "rv32e";
- else if (MABI.startswith_insensitive("ilp32"))
+ else if (MABI.equals_insensitive("lp64e"))
+ return "rv64e";
+ else if (MABI.starts_with_insensitive("ilp32"))
return "rv32imafdc";
- else if (MABI.startswith_insensitive("lp64"))
+ else if (MABI.starts_with_insensitive("lp64")) {
+ if (Triple.isAndroid())
+ return "rv64imafdcv_zba_zbb_zbs";
+
return "rv64imafdc";
+ }
}
// 4. Choose a default based on the triple
@@ -284,7 +312,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// 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.isRISCV32()) {
if (Triple.getOS() == llvm::Triple::UnknownOS)
return "rv32imac";
else
@@ -292,7 +320,26 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
} else {
if (Triple.getOS() == llvm::Triple::UnknownOS)
return "rv64imac";
+ else if (Triple.isAndroid())
+ return "rv64imafdcv_zba_zbb_zbs";
else
return "rv64imafdc";
}
}
+
+std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ std::string CPU;
+ // If we have -mcpu, use that.
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ CPU = A->getValue();
+
+ // Handle CPU name is 'native'.
+ if (CPU == "native")
+ CPU = llvm::sys::getHostCPUName();
+
+ if (!CPU.empty())
+ return CPU;
+
+ return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h
index d4a519cdab34..fcaf9d57ad13 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h
@@ -1,4 +1,4 @@
-//===--- RISCV.h - RISCV-specific Tool Helpers ------------------*- C++ -*-===//
+//===--- RISCV.h - RISC-V-specific Tool Helpers -----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -26,6 +26,8 @@ StringRef getRISCVABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
StringRef getRISCVArch(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
+std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
} // end namespace riscv
} // namespace tools
} // end namespace driver
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
index 70ba8eb2a7d0..ae1a4ba78826 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -62,10 +63,6 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name,
.Case("ma2480", "-Aleon")
.Case("ma2485", "-Aleon")
.Case("ma2x8x", "-Aleon")
- .Case("myriad2", "-Aleon")
- .Case("myriad2.1", "-Aleon")
- .Case("myriad2.2", "-Aleon")
- .Case("myriad2.3", "-Aleon")
.Case("leon2", "-Av8")
.Case("at697e", "-Av8")
.Case("at697f", "-Av8")
@@ -81,12 +78,14 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name,
sparc::FloatABI sparc::getSparcFloatABI(const Driver &D,
const ArgList &Args) {
sparc::FloatABI ABI = sparc::FloatABI::Invalid;
- if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float,
- options::OPT_mhard_float,
+ if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_fpu,
+ options::OPT_mhard_float, options::OPT_mfpu,
options::OPT_mfloat_abi_EQ)) {
- if (A->getOption().matches(clang::driver::options::OPT_msoft_float))
+ if (A->getOption().matches(options::OPT_msoft_float) ||
+ A->getOption().matches(options::OPT_mno_fpu))
ABI = sparc::FloatABI::Soft;
- else if (A->getOption().matches(options::OPT_mhard_float))
+ else if (A->getOption().matches(options::OPT_mhard_float) ||
+ A->getOption().matches(options::OPT_mfpu))
ABI = sparc::FloatABI::Hard;
else {
ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue())
@@ -113,9 +112,151 @@ sparc::FloatABI sparc::getSparcFloatABI(const Driver &D,
return ABI;
}
+std::string sparc::getSparcTargetCPU(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
+ StringRef CPUName = A->getValue();
+ if (CPUName == "native") {
+ std::string CPU = std::string(llvm::sys::getHostCPUName());
+ if (!CPU.empty() && CPU != "generic")
+ return CPU;
+ return "";
+ }
+ return std::string(CPUName);
+ }
+
+ if (Triple.getArch() == llvm::Triple::sparc && Triple.isOSSolaris())
+ return "v9";
+ return "";
+}
+
void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args,
std::vector<StringRef> &Features) {
sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args);
if (FloatABI == sparc::FloatABI::Soft)
Features.push_back("+soft-float");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mfsmuld, options::OPT_mno_fsmuld)) {
+ if (A->getOption().matches(options::OPT_mfsmuld))
+ Features.push_back("+fsmuld");
+ else
+ Features.push_back("-fsmuld");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mpopc, options::OPT_mno_popc)) {
+ if (A->getOption().matches(options::OPT_mpopc))
+ Features.push_back("+popc");
+ else
+ Features.push_back("-popc");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mvis, options::OPT_mno_vis)) {
+ if (A->getOption().matches(options::OPT_mvis))
+ Features.push_back("+vis");
+ else
+ Features.push_back("-vis");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mvis2, options::OPT_mno_vis2)) {
+ if (A->getOption().matches(options::OPT_mvis2))
+ Features.push_back("+vis2");
+ else
+ Features.push_back("-vis2");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mvis3, options::OPT_mno_vis3)) {
+ if (A->getOption().matches(options::OPT_mvis3))
+ Features.push_back("+vis3");
+ else
+ Features.push_back("-vis3");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mhard_quad_float,
+ options::OPT_msoft_quad_float)) {
+ if (A->getOption().matches(options::OPT_mhard_quad_float))
+ Features.push_back("+hard-quad-float");
+ else
+ Features.push_back("-hard-quad-float");
+ }
+
+ if (Args.hasArg(options::OPT_ffixed_g1))
+ Features.push_back("+reserve-g1");
+
+ if (Args.hasArg(options::OPT_ffixed_g2))
+ Features.push_back("+reserve-g2");
+
+ if (Args.hasArg(options::OPT_ffixed_g3))
+ Features.push_back("+reserve-g3");
+
+ if (Args.hasArg(options::OPT_ffixed_g4))
+ Features.push_back("+reserve-g4");
+
+ if (Args.hasArg(options::OPT_ffixed_g5))
+ Features.push_back("+reserve-g5");
+
+ if (Args.hasArg(options::OPT_ffixed_g6))
+ Features.push_back("+reserve-g6");
+
+ if (Args.hasArg(options::OPT_ffixed_g7))
+ Features.push_back("+reserve-g7");
+
+ if (Args.hasArg(options::OPT_ffixed_o0))
+ Features.push_back("+reserve-o0");
+
+ if (Args.hasArg(options::OPT_ffixed_o1))
+ Features.push_back("+reserve-o1");
+
+ if (Args.hasArg(options::OPT_ffixed_o2))
+ Features.push_back("+reserve-o2");
+
+ if (Args.hasArg(options::OPT_ffixed_o3))
+ Features.push_back("+reserve-o3");
+
+ if (Args.hasArg(options::OPT_ffixed_o4))
+ Features.push_back("+reserve-o4");
+
+ if (Args.hasArg(options::OPT_ffixed_o5))
+ Features.push_back("+reserve-o5");
+
+ if (Args.hasArg(options::OPT_ffixed_l0))
+ Features.push_back("+reserve-l0");
+
+ if (Args.hasArg(options::OPT_ffixed_l1))
+ Features.push_back("+reserve-l1");
+
+ if (Args.hasArg(options::OPT_ffixed_l2))
+ Features.push_back("+reserve-l2");
+
+ if (Args.hasArg(options::OPT_ffixed_l3))
+ Features.push_back("+reserve-l3");
+
+ if (Args.hasArg(options::OPT_ffixed_l4))
+ Features.push_back("+reserve-l4");
+
+ if (Args.hasArg(options::OPT_ffixed_l5))
+ Features.push_back("+reserve-l5");
+
+ if (Args.hasArg(options::OPT_ffixed_l6))
+ Features.push_back("+reserve-l6");
+
+ if (Args.hasArg(options::OPT_ffixed_l7))
+ Features.push_back("+reserve-l7");
+
+ if (Args.hasArg(options::OPT_ffixed_i0))
+ Features.push_back("+reserve-i0");
+
+ if (Args.hasArg(options::OPT_ffixed_i1))
+ Features.push_back("+reserve-i1");
+
+ if (Args.hasArg(options::OPT_ffixed_i2))
+ Features.push_back("+reserve-i2");
+
+ if (Args.hasArg(options::OPT_ffixed_i3))
+ Features.push_back("+reserve-i3");
+
+ if (Args.hasArg(options::OPT_ffixed_i4))
+ Features.push_back("+reserve-i4");
+
+ if (Args.hasArg(options::OPT_ffixed_i5))
+ Features.push_back("+reserve-i5");
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h
index d12a9a70e264..44658c4259c6 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h
@@ -28,6 +28,9 @@ enum class FloatABI {
FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+std::string getSparcTargetCPU(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+
void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
const char *getSparcAsmModeForCPU(llvm::StringRef Name,
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
index f81bf68172de..588bc3176d73 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
@@ -11,7 +11,7 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Host.h"
+#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp
index 9dfd37c2106d..b19760898c64 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp
@@ -10,7 +10,6 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
@@ -19,4 +18,9 @@ using namespace clang;
using namespace llvm::opt;
void ve::getVETargetFeatures(const Driver &D, const ArgList &Args,
- std::vector<StringRef> &Features) {}
+ std::vector<StringRef> &Features) {
+ if (Args.hasFlag(options::OPT_mvevpu, options::OPT_mno_vevpu, true))
+ Features.push_back("+vpu");
+ else
+ Features.push_back("-vpu");
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h
index 531433534914..c47a41df25bc 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h
@@ -24,7 +24,7 @@ void getVETargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
} // end namespace ve
-} // namespace tools
+} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp
index bfa008f964e1..53e26a9f8e22 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -13,9 +13,8 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Host.h"
+#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -31,9 +30,6 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
// FIXME: Reject attempts to use -march=native unless the target matches
// the host.
- //
- // FIXME: We should also incorporate the detected target features for use
- // with -native.
CPU = llvm::sys::getHostCPUName();
if (!CPU.empty() && CPU != "generic")
return std::string(CPU);
@@ -84,13 +80,19 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
// Simulators can still run on 10.11 though, like Xcode.
if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))
return "penryn";
+
+ if (Triple.isDriverKit())
+ return "nehalem";
+
// The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah.
return Is64Bit ? "core2" : "yonah";
}
- // Set up default CPU name for PS4 compilers.
- if (Triple.isPS4CPU())
+ // Set up default CPU name for PS4/PS5 compilers.
+ if (Triple.isPS4())
return "btver2";
+ if (Triple.isPS5())
+ return "znver2";
// On Android use targets compatible with gcc
if (Triple.isAndroid())
@@ -117,6 +119,15 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
+ // Claim and report unsupported -mabi=. Note: we don't support "sysv_abi" or
+ // "ms_abi" as default function attributes.
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mabi_EQ)) {
+ StringRef DefaultAbi = Triple.isOSWindows() ? "ms" : "sysv";
+ if (A->getValue() != DefaultAbi)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << Triple.getTriple();
+ }
+
// If -march=native, autodetect the feature list.
if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
if (StringRef(A->getValue()) == "native") {
@@ -218,6 +229,27 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
<< D.getOpts().getOptionName(LVIOpt);
}
+ for (const Arg *A : Args.filtered(options::OPT_m_x86_AVX10_Features_Group)) {
+ StringRef Name = A->getOption().getName();
+ A->claim();
+
+ // Skip over "-m".
+ assert(Name.starts_with("m") && "Invalid feature name.");
+ Name = Name.substr(1);
+
+ bool IsNegative = Name.consume_front("no-");
+
+#ifndef NDEBUG
+ assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name.");
+ StringRef Version, Width;
+ std::tie(Version, Width) = Name.substr(6).split('-');
+ assert(Version == "1" && "Invalid AVX10 feature name.");
+ assert((Width == "256" || Width == "512") && "Invalid AVX10 feature name.");
+#endif
+
+ Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ }
+
// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group,
@@ -226,7 +258,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
A->claim();
// Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
+ assert(Name.starts_with("m") && "Invalid feature name.");
Name = Name.substr(1);
// Replace -mgeneral-regs-only with -x87, -mmx, -sse
@@ -235,9 +267,46 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
continue;
}
- bool IsNegative = Name.startswith("no-");
+ bool IsNegative = Name.starts_with("no-");
+ if (A->getOption().matches(options::OPT_mapx_features_EQ) ||
+ A->getOption().matches(options::OPT_mno_apx_features_EQ)) {
+
+ for (StringRef Value : A->getValues()) {
+ if (Value == "egpr" || Value == "push2pop2" || Value == "ppx" ||
+ Value == "ndd" || Value == "ccmp" || Value == "cf") {
+ Features.push_back(
+ Args.MakeArgString((IsNegative ? "-" : "+") + Value));
+ continue;
+ }
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Value;
+ }
+ continue;
+ }
if (IsNegative)
Name = Name.substr(3);
Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
+
+ // Enable/disable straight line speculation hardening.
+ if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
+ StringRef Scope = A->getValue();
+ if (Scope == "all") {
+ Features.push_back("+harden-sls-ijmp");
+ Features.push_back("+harden-sls-ret");
+ } else if (Scope == "return") {
+ Features.push_back("+harden-sls-ret");
+ } else if (Scope == "indirect-jmp") {
+ Features.push_back("+harden-sls-ijmp");
+ } else if (Scope != "none") {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Scope;
+ }
+ }
+
+ // -mno-gather, -mno-scatter support
+ if (Args.hasArg(options::OPT_mno_gather))
+ Features.push_back("+prefer-no-gather");
+ if (Args.hasArg(options::OPT_mno_scatter))
+ Features.push_back("+prefer-no-scatter");
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h
index 36a2ab52899d..e07387f3ece3 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h
@@ -11,8 +11,8 @@
#include "clang/Driver/Driver.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
+#include "llvm/TargetParser/Triple.h"
#include <string>
#include <vector>
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp
index cd07692be358..391c47f88bde 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -12,26 +12,27 @@
#include "Gnu.h"
#include "clang/Driver/InputInfo.h"
+#include "Arch/ARM.h"
#include "Arch/RISCV.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/MultilibBuilder.h"
#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
+#include <sstream>
+
using namespace llvm::opt;
using namespace clang;
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
-static Multilib makeMultilib(StringRef commonSuffix) {
- return Multilib(commonSuffix, commonSuffix, commonSuffix);
-}
-
static bool findRISCVMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
const ArgList &Args, DetectedMultilibs &Result) {
@@ -39,37 +40,41 @@ static bool findRISCVMultilibs(const Driver &D,
StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
- if (TargetTriple.getArch() == llvm::Triple::riscv64) {
- Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
- Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
- .flag("+march=rv64imafdc")
- .flag("+mabi=lp64d");
+ if (TargetTriple.isRISCV64()) {
+ MultilibBuilder Imac =
+ MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64");
+ MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
+ .flag("-march=rv64imafdc")
+ .flag("-mabi=lp64d");
// Multilib reuse
bool UseImafdc =
(Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
- addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
- addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
- addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
- addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
+ addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags);
+ addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags);
+ addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags);
+ addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags);
- Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
- return Result.Multilibs.select(Flags, Result.SelectedMultilib);
+ Result.Multilibs =
+ MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet();
+ return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
}
- if (TargetTriple.getArch() == llvm::Triple::riscv32) {
- Multilib Imac =
- makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
- Multilib I =
- makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
- Multilib Im =
- makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
- Multilib Iac = makeMultilib("/rv32iac/ilp32")
- .flag("+march=rv32iac")
- .flag("+mabi=ilp32");
- Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
- .flag("+march=rv32imafc")
- .flag("+mabi=ilp32f");
+ if (TargetTriple.isRISCV32()) {
+ MultilibBuilder Imac =
+ MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32");
+ MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
+ .flag("-march=rv32i")
+ .flag("-mabi=ilp32");
+ MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
+ .flag("-march=rv32im")
+ .flag("-mabi=ilp32");
+ MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
+ .flag("-march=rv32iac")
+ .flag("-mabi=ilp32");
+ MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
+ .flag("-march=rv32imafc")
+ .flag("-mabi=ilp32f");
// Multilib reuse
bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
@@ -77,22 +82,23 @@ static bool findRISCVMultilibs(const Driver &D,
bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
(Arch == "rv32gc"); // imafdc,gc => imafc
- addMultilibFlag(UseI, "march=rv32i", Flags);
- addMultilibFlag(UseIm, "march=rv32im", Flags);
- addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
- addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
- addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
- addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
- addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
-
- Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
- return Result.Multilibs.select(Flags, Result.SelectedMultilib);
+ addMultilibFlag(UseI, "-march=rv32i", Flags);
+ addMultilibFlag(UseIm, "-march=rv32im", Flags);
+ addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags);
+ addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags);
+ addMultilibFlag(UseImafc, "-march=rv32imafc", Flags);
+ addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags);
+ addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags);
+
+ Result.Multilibs =
+ MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();
+ return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
}
return false;
}
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
+ const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
@@ -101,15 +107,21 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
findMultilibs(D, Triple, Args);
SmallString<128> SysRoot(computeSysRoot());
if (!SysRoot.empty()) {
- llvm::sys::path::append(SysRoot, "lib");
- getFilePaths().push_back(std::string(SysRoot));
+ for (const Multilib &M : getOrderedMultilibs()) {
+ SmallString<128> Dir(SysRoot);
+ llvm::sys::path::append(Dir, M.osSuffix(), "lib");
+ getFilePaths().push_back(std::string(Dir));
+ getLibraryPaths().push_back(std::string(Dir));
+ }
}
}
-/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
+/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
static bool isARMBareMetal(const llvm::Triple &Triple) {
if (Triple.getArch() != llvm::Triple::arm &&
- Triple.getArch() != llvm::Triple::thumb)
+ Triple.getArch() != llvm::Triple::thumb &&
+ Triple.getArch() != llvm::Triple::armeb &&
+ Triple.getArch() != llvm::Triple::thumbeb)
return false;
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
@@ -125,9 +137,10 @@ static bool isARMBareMetal(const llvm::Triple &Triple) {
return true;
}
-/// Is the triple aarch64-none-elf?
+/// Is the triple {aarch64.aarch64_be}-none-elf?
static bool isAArch64BareMetal(const llvm::Triple &Triple) {
- if (Triple.getArch() != llvm::Triple::aarch64)
+ if (Triple.getArch() != llvm::Triple::aarch64 &&
+ Triple.getArch() != llvm::Triple::aarch64_be)
return false;
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
@@ -140,8 +153,7 @@ static bool isAArch64BareMetal(const llvm::Triple &Triple) {
}
static bool isRISCVBareMetal(const llvm::Triple &Triple) {
- if (Triple.getArch() != llvm::Triple::riscv32 &&
- Triple.getArch() != llvm::Triple::riscv64)
+ if (!Triple.isRISCV())
return false;
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
@@ -153,51 +165,100 @@ static bool isRISCVBareMetal(const llvm::Triple &Triple) {
return Triple.getEnvironmentName() == "elf";
}
+/// Is the triple powerpc[64][le]-*-none-eabi?
+static bool isPPCBareMetal(const llvm::Triple &Triple) {
+ return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
+ Triple.getEnvironment() == llvm::Triple::EABI;
+}
+
+static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
+ StringRef MultilibPath, const ArgList &Args,
+ DetectedMultilibs &Result) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
+ D.getVFS().getBufferForFile(MultilibPath);
+ if (!MB)
+ return;
+ Multilib::flags_list Flags = TC.getMultilibFlags(Args);
+ llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
+ MultilibSet::parseYaml(*MB.get());
+ if (ErrorOrMultilibSet.getError())
+ return;
+ Result.Multilibs = ErrorOrMultilibSet.get();
+ if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
+ return;
+ D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
+ std::stringstream ss;
+ for (const Multilib &Multilib : Result.Multilibs)
+ ss << "\n" << llvm::join(Multilib.flags(), " ");
+ D.Diag(clang::diag::note_drv_available_multilibs) << ss.str();
+}
+
+static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
+
+// Get the sysroot, before multilib takes effect.
+static std::string computeBaseSysRoot(const Driver &D,
+ const llvm::Triple &Triple) {
+ if (!D.SysRoot.empty())
+ return D.SysRoot;
+
+ SmallString<128> SysRootDir(D.Dir);
+ llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");
+
+ SmallString<128> MultilibPath(SysRootDir);
+ llvm::sys::path::append(MultilibPath, MultilibFilename);
+
+ // New behaviour: if multilib.yaml is found then use clang-runtimes as the
+ // sysroot.
+ if (D.getVFS().exists(MultilibPath))
+ return std::string(SysRootDir);
+
+ // Otherwise fall back to the old behaviour of appending the target triple.
+ llvm::sys::path::append(SysRootDir, D.getTargetTriple());
+ return std::string(SysRootDir);
+}
+
void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args) {
DetectedMultilibs Result;
if (isRISCVBareMetal(Triple)) {
if (findRISCVMultilibs(D, Triple, Args, Result)) {
- SelectedMultilib = Result.SelectedMultilib;
+ SelectedMultilibs = Result.SelectedMultilibs;
Multilibs = Result.Multilibs;
}
+ } else {
+ llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple));
+ llvm::sys::path::append(MultilibPath, MultilibFilename);
+ findMultilibsFromYAML(*this, D, MultilibPath, Args, Result);
+ SelectedMultilibs = Result.SelectedMultilibs;
+ Multilibs = Result.Multilibs;
}
}
bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
- isRISCVBareMetal(Triple);
+ isRISCVBareMetal(Triple) || isPPCBareMetal(Triple);
}
Tool *BareMetal::buildLinker() const {
return new tools::baremetal::Linker(*this);
}
-std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); }
-
-std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &,
- StringRef, FileType,
- bool) const {
- return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str();
-}
-
-std::string BareMetal::getRuntimesDir() const {
- SmallString<128> Dir(getDriver().ResourceDir);
- llvm::sys::path::append(Dir, "lib", "baremetal");
- Dir += SelectedMultilib.gccSuffix();
- return std::string(Dir.str());
+Tool *BareMetal::buildStaticLibTool() const {
+ return new tools::baremetal::StaticLibTool(*this);
}
std::string BareMetal::computeSysRoot() const {
- if (!getDriver().SysRoot.empty())
- return getDriver().SysRoot + SelectedMultilib.osSuffix();
+ return computeBaseSysRoot(getDriver(), getTriple());
+}
- SmallString<128> SysRootDir;
- llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
- getDriver().getTargetTriple());
+BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
+ // Get multilibs in reverse order because they're ordered most-specific last.
+ if (!SelectedMultilibs.empty())
+ return llvm::reverse(SelectedMultilibs);
- SysRootDir += SelectedMultilib.osSuffix();
- return std::string(SysRootDir);
+ // No multilibs selected so return a single default multilib.
+ static const llvm::SmallVector<Multilib> Default = {Multilib()};
+ return llvm::reverse(Default);
}
void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -212,10 +273,14 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
}
if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
- SmallString<128> Dir(computeSysRoot());
- if (!Dir.empty()) {
- llvm::sys::path::append(Dir, "include");
- addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ const SmallString<128> SysRoot(computeSysRoot());
+ if (!SysRoot.empty()) {
+ for (const Multilib &M : getOrderedMultilibs()) {
+ SmallString<128> Dir(SysRoot);
+ llvm::sys::path::append(Dir, M.includeSuffix());
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
}
}
}
@@ -226,48 +291,58 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
CC1Args.push_back("-nostdsysteminc");
}
-void BareMetal::AddClangCXXStdlibIncludeArgs(
- const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
+ const Driver &D = getDriver();
std::string SysRoot(computeSysRoot());
if (SysRoot.empty())
return;
- switch (GetCXXStdlibType(DriverArgs)) {
- case ToolChain::CST_Libcxx: {
- SmallString<128> Dir(SysRoot);
- llvm::sys::path::append(Dir, "include", "c++", "v1");
- addSystemInclude(DriverArgs, CC1Args, Dir.str());
- break;
- }
- case ToolChain::CST_Libstdcxx: {
+ for (const Multilib &M : getOrderedMultilibs()) {
SmallString<128> Dir(SysRoot);
- llvm::sys::path::append(Dir, "include", "c++");
- std::error_code EC;
- Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
- // Walk the subdirs, and find the one with the newest gcc version:
- for (llvm::vfs::directory_iterator
- LI = getDriver().getVFS().dir_begin(Dir.str(), EC),
- LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->path());
- auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
- if (CandidateVersion.Major == -1)
- continue;
- if (CandidateVersion <= Version)
- continue;
- Version = CandidateVersion;
+ llvm::sys::path::append(Dir, M.gccSuffix());
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx: {
+ // First check sysroot/usr/include/c++/v1 if it exists.
+ SmallString<128> TargetDir(Dir);
+ llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
+ if (D.getVFS().exists(TargetDir)) {
+ addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
+ break;
+ }
+ // Add generic path if nothing else succeeded so far.
+ llvm::sys::path::append(Dir, "include", "c++", "v1");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ break;
+ }
+ case ToolChain::CST_Libstdcxx: {
+ llvm::sys::path::append(Dir, "include", "c++");
+ std::error_code EC;
+ Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
+ // Walk the subdirs, and find the one with the newest gcc version:
+ for (llvm::vfs::directory_iterator
+ LI = D.getVFS().dir_begin(Dir.str(), EC),
+ LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
+ if (CandidateVersion.Major == -1)
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+ Version = CandidateVersion;
+ }
+ if (Version.Major != -1) {
+ llvm::sys::path::append(Dir, Version.Text);
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+ break;
+ }
}
- if (Version.Major == -1)
- return;
- llvm::sys::path::append(Dir, Version.Text);
- addSystemInclude(DriverArgs, CC1Args, Dir.str());
- break;
- }
}
}
@@ -276,6 +351,8 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
break;
case ToolChain::CST_Libstdcxx:
@@ -290,10 +367,14 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
ArgStringList &CmdArgs) const {
ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
switch (RLT) {
- case ToolChain::RLT_CompilerRT:
- CmdArgs.push_back(
- Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName()));
+ case ToolChain::RLT_CompilerRT: {
+ const std::string FileName = getCompilerRT(Args, "builtins");
+ llvm::StringRef BaseName = llvm::sys::path::filename(FileName);
+ BaseName.consume_front("lib");
+ BaseName.consume_back(".a");
+ CmdArgs.push_back(Args.MakeArgString("-l" + BaseName));
return;
+ }
case ToolChain::RLT_Libgcc:
CmdArgs.push_back("-lgcc");
return;
@@ -301,6 +382,51 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
llvm_unreachable("Unhandled RuntimeLibType.");
}
+void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // ar tool command "llvm-ar <options> <output_file> <input_files>".
+ ArgStringList CmdArgs;
+ // Create and insert file members with a deterministic index.
+ CmdArgs.push_back("rcsD");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs) {
+ if (II.isFilename()) {
+ CmdArgs.push_back(II.getFilename());
+ }
+ }
+
+ // Delete old output archive file if it already exists before generating a new
+ // archive file.
+ const char *OutputFileName = Output.getFilename();
+ if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
+ if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
+ D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
+ return;
+ }
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::AtFileCurCP(),
+ Exec, CmdArgs, Inputs, Output));
+}
+
void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -308,22 +434,39 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
- auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
+ auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
+ const llvm::Triple::ArchType Arch = TC.getArch();
+ const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
CmdArgs.push_back("-Bstatic");
- Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
- options::OPT_e, options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_r});
+ if (Triple.isARM() || Triple.isThumb()) {
+ bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
+ if (IsBigEndian)
+ arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
+ CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
+ } else if (Triple.isAArch64()) {
+ CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
+ }
+
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_s, options::OPT_t, options::OPT_r});
TC.AddFilePathLibArgs(Args, CmdArgs);
- CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
+ for (const auto &LibPath : TC.getLibraryPaths())
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
+
+ const std::string FileName = TC.getCompilerRT(Args, "builtins");
+ llvm::SmallString<128> PathBuf{FileName};
+ llvm::sys::path::remove_filename(PathBuf);
+ CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf));
if (TC.ShouldLinkCXXStdlib(Args))
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lm");
@@ -331,10 +474,45 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
TC.AddLinkRuntimeLib(Args, CmdArgs);
}
+ if (TC.getTriple().isRISCV())
+ CmdArgs.push_back("-X");
+
+ // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
+ // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
+ // arm*-*-*bsd).
+ if (isARMBareMetal(TC.getTriple()))
+ CmdArgs.push_back("--target2=rel");
+
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
- Args.MakeArgString(TC.GetLinkerPath()),
- CmdArgs, Inputs, Output));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(),
+ Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));
+}
+
+// BareMetal toolchain allows all sanitizers where the compiler generates valid
+// code, ignoring all runtime library support issues on the assumption that
+// baremetal targets typically implement their own runtime support.
+SanitizerMask BareMetal::getSupportedSanitizers() const {
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
+ const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be;
+ const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::KernelAddress;
+ Res |= SanitizerKind::PointerCompare;
+ Res |= SanitizerKind::PointerSubtract;
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::FuzzerNoLink;
+ Res |= SanitizerKind::Vptr;
+ Res |= SanitizerKind::SafeStack;
+ Res |= SanitizerKind::Thread;
+ Res |= SanitizerKind::Scudo;
+ if (IsX86_64 || IsAArch64 || IsRISCV64) {
+ Res |= SanitizerKind::HWAddress;
+ Res |= SanitizerKind::KernelHWAddress;
+ }
+ return Res;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h
index dc718e09ad43..67b5aa5998fc 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h
@@ -1,4 +1,4 @@
-//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===//
+//===--- BareMetal.h - Bare Metal Tool and ToolChain ------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -32,15 +32,13 @@ public:
protected:
Tool *buildLinker() const override;
-
- std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args,
- StringRef Component,
- FileType Type = ToolChain::FT_Static,
- bool AddArch = true) const override;
+ Tool *buildStaticLibTool() const override;
public:
bool useIntegratedAs() const override { return true; }
+ bool isBareMetal() const override { return true; }
bool isCrossCompiling() const override { return true; }
+ bool HasNativeLLVMSupport() const override { return true; }
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
@@ -50,8 +48,6 @@ public:
StringRef getOSLibName() const override { return "baremetal"; }
- std::string getCompilerRTPath() const override;
-
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;
}
@@ -61,12 +57,13 @@ public:
const char *getDefaultLinker() const override { return "ld.lld"; }
- std::string getRuntimesDir() const;
- void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -75,6 +72,12 @@ public:
void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
std::string computeSysRoot() const override;
+ SanitizerMask getSupportedSanitizers() const override;
+
+private:
+ using OrderedMultilibs =
+ llvm::iterator_range<llvm::SmallVector<Multilib>::const_reverse_iterator>;
+ OrderedMultilibs getOrderedMultilibs() const;
};
} // namespace toolchains
@@ -82,7 +85,21 @@ public:
namespace tools {
namespace baremetal {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool {
+public:
+ StaticLibTool(const ToolChain &TC)
+ : Tool("baremetal::StaticLibTool", "llvm-ar", 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;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {}
bool isLinkJob() const override { return true; }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp
new file mode 100644
index 000000000000..feb3bc922920
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp
@@ -0,0 +1,204 @@
+//===--- CSKYToolchain.cpp - CSKY 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 "CSKYToolChain.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/InputInfo.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+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);
+}
+
+/// CSKY Toolchain
+CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(Triple, Args);
+ if (GCCInstallation.isValid()) {
+ Multilibs = GCCInstallation.getMultilibs();
+ SelectedMultilibs.assign({GCCInstallation.getMultilib()});
+ path_list &Paths = getFilePaths();
+ // Add toolchain/multilib specific file paths.
+ addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
+ GCCInstallation.getInstallPath(), Paths);
+ getFilePaths().push_back(GCCInstallation.getInstallPath().str() +
+ SelectedMultilibs.back().osSuffix());
+ 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());
+ getFilePaths().push_back(computeSysRoot() + "/lib" +
+ SelectedMultilibs.back().osSuffix());
+ } else {
+ getProgramPaths().push_back(D.Dir);
+ getFilePaths().push_back(computeSysRoot() + "/lib");
+ }
+}
+
+Tool *CSKYToolChain::buildLinker() const {
+ return new tools::CSKY::Linker(*this);
+}
+
+ToolChain::RuntimeLibType CSKYToolChain::GetDefaultRuntimeLibType() const {
+ return GCCInstallation.isValid() ? ToolChain::RLT_Libgcc
+ : ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::UnwindLibType
+CSKYToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
+ return ToolChain::UNW_None;
+}
+
+void CSKYToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ CC1Args.push_back("-nostdsysteminc");
+}
+
+void CSKYToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
+ SmallString<128> Dir(computeSysRoot());
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ SmallString<128> Dir2(computeSysRoot());
+ llvm::sys::path::append(Dir2, "sys-include");
+ addSystemInclude(DriverArgs, CC1Args, Dir2.str());
+ }
+}
+
+void CSKYToolChain::addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const GCCVersion &Version = GCCInstallation.getVersion();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
+ TripleStr, Multilib.includeSuffix(), DriverArgs,
+ CC1Args);
+}
+
+std::string CSKYToolChain::computeSysRoot() const {
+ if (!getDriver().SysRoot.empty())
+ return getDriver().SysRoot;
+
+ 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 std::string(SysRootDir);
+}
+
+void CSKY::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &ToolChain = getToolChain();
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("cskyelf");
+
+ std::string Linker = getToolChain().GetLinkerPath();
+
+ 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("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_r});
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ // TODO: add C++ includes and libs if compiling C++.
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc");
+ if (Args.hasArg(options::OPT_msim))
+ CmdArgs.push_back("-lsemi");
+ else
+ CmdArgs.push_back("-lnosys");
+ CmdArgs.push_back("--end-group");
+ AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
+ }
+
+ if (WantCRTs) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker),
+ CmdArgs, Inputs, Output));
+}
+// CSKY tools end.
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h
new file mode 100644
index 000000000000..a57324a42641
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h
@@ -0,0 +1,63 @@
+//===--- CSKYToolchain.h - CSKY 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_CSKYTOOLCHAIN_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H
+
+#include "Gnu.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY CSKYToolChain : public Generic_ELF {
+public:
+ CSKYToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind) const override;
+ 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;
+ void
+ addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+protected:
+ Tool *buildLinker() const override;
+
+private:
+ std::string computeSysRoot() const override;
+};
+
+} // end namespace toolchains
+
+namespace tools {
+namespace CSKY {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("CSKY::Linker", "ld", TC) {}
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace CSKY
+} // end namespace tools
+
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp
index f2f18e901ab0..aa344b3465ab 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp
@@ -10,6 +10,8 @@
#include "AMDGPU.h"
#include "Arch/AArch64.h"
#include "Arch/ARM.h"
+#include "Arch/CSKY.h"
+#include "Arch/LoongArch.h"
#include "Arch/M68k.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
@@ -25,9 +27,13 @@
#include "clang/Basic/CLWarnings.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/HeaderInclude.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MakeSupport.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Action.h"
#include "clang/Driver/Distro.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
@@ -35,18 +41,26 @@
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/XRayArgs.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/Object/ObjectFile.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
-#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/YAMLParser.h"
+#include "llvm/TargetParser/ARMTargetParserCommon.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/LoongArchTargetParser.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
+#include <cctype>
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -56,7 +70,9 @@ using namespace llvm::opt;
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC,
options::OPT_fminimize_whitespace,
- options::OPT_fno_minimize_whitespace)) {
+ options::OPT_fno_minimize_whitespace,
+ options::OPT_fkeep_system_includes,
+ options::OPT_fno_keep_system_includes)) {
if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
!Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
@@ -93,34 +109,6 @@ static void EscapeSpacesAndBackslashes(const char *Arg,
}
}
-// Quote target names for inclusion in GNU Make dependency files.
-// Only the characters '$', '#', ' ', '\t' are quoted.
-static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
- for (unsigned i = 0, e = Target.size(); i != e; ++i) {
- switch (Target[i]) {
- case ' ':
- case '\t':
- // Escape the preceding backslashes
- for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
- Res.push_back('\\');
-
- // Escape the space/tab
- Res.push_back('\\');
- break;
- case '$':
- Res.push_back('$');
- break;
- case '#':
- Res.push_back('\\');
- break;
- default:
- break;
- }
-
- Res.push_back(Target[i]);
- }
-}
-
/// Apply \a Work on the current tool chain \a RegularToolChain and any other
/// offloading tool chain that is associated with the current action \a JA.
static void
@@ -223,17 +211,21 @@ static void ParseMRecip(const Driver &D, const ArgList &Args,
llvm::StringMap<bool> OptionStrings;
OptionStrings.insert(std::make_pair("divd", false));
OptionStrings.insert(std::make_pair("divf", false));
+ OptionStrings.insert(std::make_pair("divh", false));
OptionStrings.insert(std::make_pair("vec-divd", false));
OptionStrings.insert(std::make_pair("vec-divf", false));
+ OptionStrings.insert(std::make_pair("vec-divh", false));
OptionStrings.insert(std::make_pair("sqrtd", false));
OptionStrings.insert(std::make_pair("sqrtf", false));
+ OptionStrings.insert(std::make_pair("sqrth", false));
OptionStrings.insert(std::make_pair("vec-sqrtd", false));
OptionStrings.insert(std::make_pair("vec-sqrtf", false));
+ OptionStrings.insert(std::make_pair("vec-sqrth", false));
for (unsigned i = 0; i != NumOptions; ++i) {
StringRef Val = A->getValue(i);
- bool IsDisabled = Val.startswith(DisabledPrefixIn);
+ bool IsDisabled = Val.starts_with(DisabledPrefixIn);
// Ignore the disablement token for string matching.
if (IsDisabled)
Val = Val.substr(1);
@@ -252,10 +244,11 @@ static void ParseMRecip(const Driver &D, const ArgList &Args,
D.Diag(diag::err_drv_unknown_argument) << Val;
return;
}
- // The option was specified without a float or double suffix.
- // Make sure that the double entry was not already specified.
+ // The option was specified without a half or float or double suffix.
+ // Make sure that the double or half entry was not already specified.
// The float entry will be checked below.
- if (OptionStrings[ValBase.str() + 'd']) {
+ if (OptionStrings[ValBase.str() + 'd'] ||
+ OptionStrings[ValBase.str() + 'h']) {
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
return;
}
@@ -270,9 +263,12 @@ static void ParseMRecip(const Driver &D, const ArgList &Args,
// Mark the matched option as found. Do not allow duplicate specifiers.
OptionIter->second = true;
- // If the precision was not specified, also mark the double entry as found.
- if (ValBase.back() != 'f' && ValBase.back() != 'd')
+ // If the precision was not specified, also mark the double and half entry
+ // as found.
+ if (ValBase.back() != 'f' && ValBase.back() != 'd' && ValBase.back() != 'h') {
OptionStrings[ValBase.str() + 'd'] = true;
+ OptionStrings[ValBase.str() + 'h'] = true;
+ }
// Build the output string.
StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
@@ -305,88 +301,6 @@ 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 Driver &D, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs,
- bool ForAS, bool IsAux = false) {
- 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(D, Triple, Args, CmdArgs, Features, ForAS);
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppcle:
- 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(D, Args, Features);
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- case llvm::Triple::aarch64_be:
- aarch64::getAArch64TargetFeatures(D, Triple, Args, CmdArgs, Features,
- ForAS);
- 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, Triple, Args, Features);
- break;
- case llvm::Triple::m68k:
- m68k::getM68kTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::msp430:
- msp430::getMSP430TargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::ve:
- ve::getVETargetFeatures(D, Args, Features);
- break;
- }
-
- for (auto Feature : unifyTargetFeatures(Features)) {
- CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature");
- CmdArgs.push_back(Feature.data());
- }
-}
-
static bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
@@ -450,9 +364,9 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType,
}
if (types::isCXX(InputType)) {
- // Disable C++ EH by default on XCore and PS4.
- bool CXXExceptionsEnabled =
- Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU();
+ // Disable C++ EH by default on XCore and PS4/PS5.
+ bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore &&
+ !Triple.isPS() && !Triple.isDriverKit();
Arg *ExceptionArg = Args.getLastArg(
options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
options::OPT_fexceptions, options::OPT_fno_exceptions);
@@ -473,6 +387,9 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType,
// So we do not set EH to false.
Args.AddLastArg(CmdArgs, options::OPT_fignore_exceptions);
+ Args.addOptInFlag(CmdArgs, options::OPT_fassume_nothrow_exception_dtor,
+ options::OPT_fno_assume_nothrow_exception_dtor);
+
if (EH)
CmdArgs.push_back("-fexceptions");
return EH;
@@ -494,138 +411,6 @@ static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC,
Default);
}
-// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
-// to the corresponding DebugInfoKind.
-static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
- assert(A.getOption().matches(options::OPT_gN_Group) &&
- "Not a -g option that specifies a debug-info level");
- if (A.getOption().matches(options::OPT_g0) ||
- A.getOption().matches(options::OPT_ggdb0))
- return codegenoptions::NoDebugInfo;
- if (A.getOption().matches(options::OPT_gline_tables_only) ||
- A.getOption().matches(options::OPT_ggdb1))
- return codegenoptions::DebugLineTablesOnly;
- if (A.getOption().matches(options::OPT_gline_directives_only))
- return codegenoptions::DebugDirectivesOnly;
- return codegenoptions::DebugInfoConstructor;
-}
-
-static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
- switch (Triple.getArch()){
- default:
- return false;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // ARM Darwin targets require a frame pointer to be always present to aid
- // offline debugging via backtraces.
- return Triple.isOSDarwin();
- }
-}
-
-static bool useFramePointerForTargetByDefault(const ArgList &Args,
- const llvm::Triple &Triple) {
- if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry))
- return true;
-
- switch (Triple.getArch()) {
- case llvm::Triple::xcore:
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- case llvm::Triple::msp430:
- // XCore never wants frame pointers, regardless of OS.
- // WebAssembly never wants frame pointers.
- return false;
- case llvm::Triple::ppc:
- case llvm::Triple::ppcle:
- case llvm::Triple::ppc64:
- 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;
- }
-
- if (Triple.isOSNetBSD()) {
- return !areOptimizationsEnabled(Args);
- }
-
- if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI ||
- Triple.isOSHurd()) {
- switch (Triple.getArch()) {
- // Don't use a frame pointer on linux if optimizing for certain targets.
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- if (Triple.isAndroid())
- return true;
- LLVM_FALLTHROUGH;
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::systemz:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return !areOptimizationsEnabled(Args);
- default:
- return true;
- }
- }
-
- if (Triple.isOSWindows()) {
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- return !areOptimizationsEnabled(Args);
- case llvm::Triple::x86_64:
- return Triple.isOSBinFormatMachO();
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // Windows on ARM builds with FPO disabled to aid fast stack walking
- return true;
- default:
- // All other supported Windows ISAs use xdata unwind information, so frame
- // pointers are not generally useful.
- return false;
- }
- }
-
- return true;
-}
-
-static CodeGenOptions::FramePointerKind
-getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) {
- // We have 4 states:
- //
- // 00) leaf retained, non-leaf retained
- // 01) leaf retained, non-leaf omitted (this is invalid)
- // 10) leaf omitted, non-leaf retained
- // (what -momit-leaf-frame-pointer was designed for)
- // 11) leaf omitted, non-leaf omitted
- //
- // "omit" options taking precedence over "no-omit" options is the only way
- // to make 3 valid states representable
- Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer,
- options::OPT_fno_omit_frame_pointer);
- bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer);
- bool NoOmitFP =
- A && A->getOption().matches(options::OPT_fno_omit_frame_pointer);
- bool OmitLeafFP = Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer,
- Triple.isAArch64() || Triple.isPS4CPU() ||
- Triple.isVE());
- if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
- (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
- if (OmitLeafFP)
- return CodeGenOptions::FramePointerKind::NonLeaf;
- return CodeGenOptions::FramePointerKind::All;
- }
- return CodeGenOptions::FramePointerKind::None;
-}
-
/// Add a CC1 option to specify the debug compilation directory.
static const char *addDebugCompDirArg(const ArgList &Args,
ArgStringList &CmdArgs,
@@ -650,7 +435,7 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs,
const char *OutputFileName) {
// No need to generate a value for -object-file-name if it was provided.
for (auto *Arg : Args.filtered(options::OPT_Xclang))
- if (StringRef(Arg->getValue()).startswith("-object-file-name"))
+ if (StringRef(Arg->getValue()).starts_with("-object-file-name"))
return;
if (Args.hasArg(options::OPT_object_file_name_EQ))
@@ -664,22 +449,39 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs,
// Make the path absolute in the debug infos like MSVC does.
llvm::sys::fs::make_absolute(ObjFileNameForDebug);
}
+ // If the object file name is a relative path, then always use Windows
+ // backslash style as -object-file-name is used for embedding object file path
+ // in codeview and it can only be generated when targeting on Windows.
+ // Otherwise, just use native absolute path.
+ llvm::sys::path::Style Style =
+ llvm::sys::path::is_absolute(ObjFileNameForDebug)
+ ? llvm::sys::path::Style::native
+ : llvm::sys::path::Style::windows_backslash;
+ llvm::sys::path::remove_dots(ObjFileNameForDebug, /*remove_dot_dot=*/true,
+ Style);
CmdArgs.push_back(
Args.MakeArgString(Twine("-object-file-name=") + ObjFileNameForDebug));
}
/// 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_ffile_prefix_map_EQ,
- options::OPT_fdebug_prefix_map_EQ)) {
- StringRef Map = A->getValue();
+static void addDebugPrefixMapArg(const Driver &D, const ToolChain &TC,
+ const ArgList &Args, ArgStringList &CmdArgs) {
+ auto AddOneArg = [&](StringRef Map, StringRef Name) {
if (!Map.contains('='))
- D.Diag(diag::err_drv_invalid_argument_to_option)
- << Map << A->getOption().getName();
+ D.Diag(diag::err_drv_invalid_argument_to_option) << Map << Name;
else
CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map));
+ };
+
+ for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
+ options::OPT_fdebug_prefix_map_EQ)) {
+ AddOneArg(A->getValue(), A->getOption().getName());
A->claim();
}
+ std::string GlobalRemapEntry = TC.GetGlobalDebugPathRemapping();
+ if (GlobalRemapEntry.empty())
+ return;
+ AddOneArg(GlobalRemapEntry, "environment");
}
/// Add a CC1 and CC1AS option to specify the macro file path prefix map.
@@ -777,10 +579,10 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
}
static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
- const Driver &D, const InputInfo &Output,
+ const JobAction &JA, const InputInfo &Output,
const ArgList &Args, SanitizerArgs &SanArgs,
ArgStringList &CmdArgs) {
-
+ const Driver &D = TC.getDriver();
auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
options::OPT_fprofile_generate_EQ,
options::OPT_fno_profile_generate);
@@ -788,12 +590,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
PGOGenerateArg = nullptr;
- auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
- options::OPT_fcs_profile_generate_EQ,
- options::OPT_fno_profile_generate);
- if (CSPGOGenerateArg &&
- CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
- CSPGOGenerateArg = nullptr;
+ auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args);
auto *ProfileGenerateArg = Args.getLastArg(
options::OPT_fprofile_instr_generate,
@@ -825,9 +622,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
}
if (TC.getTriple().isOSAIX()) {
- if (ProfileGenerateArg)
- D.Diag(diag::err_drv_unsupported_opt_for_target)
- << ProfileGenerateArg->getSpelling() << TC.getTriple().str();
if (Arg *ProfileSampleUseArg = getLastProfileSampleUseArg(Args))
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< ProfileSampleUseArg->getSpelling() << TC.getTriple().str();
@@ -895,10 +689,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
options::OPT_fno_test_coverage, false) ||
Args.hasArg(options::OPT_coverage);
bool EmitCovData = TC.needsGCovInstrumentation(Args);
- if (EmitCovNotes)
- CmdArgs.push_back("-ftest-coverage");
- if (EmitCovData)
- CmdArgs.push_back("-fprofile-arcs");
if (Args.hasFlag(options::OPT_fcoverage_mapping,
options::OPT_fno_coverage_mapping, false)) {
@@ -910,6 +700,17 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
CmdArgs.push_back("-fcoverage-mapping");
}
+ if (Args.hasFlag(options::OPT_fmcdc_coverage, options::OPT_fno_mcdc_coverage,
+ false)) {
+ if (!Args.hasFlag(options::OPT_fcoverage_mapping,
+ options::OPT_fno_coverage_mapping, false))
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << "-fcoverage-mcdc"
+ << "-fcoverage-mapping";
+
+ CmdArgs.push_back("-fcoverage-mcdc");
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
options::OPT_fcoverage_compilation_dir_EQ)) {
if (A->getOption().matches(options::OPT_ffile_compilation_dir_EQ))
@@ -951,11 +752,30 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
CmdArgs.push_back("-fprofile-update=atomic");
else if (Val != "single")
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
- } else if (SanArgs.needsTsanRt()) {
- CmdArgs.push_back("-fprofile-update=atomic");
+ << A->getSpelling() << Val;
}
+ int FunctionGroups = 1;
+ int SelectedFunctionGroup = 0;
+ if (const auto *A = Args.getLastArg(options::OPT_fprofile_function_groups)) {
+ StringRef Val = A->getValue();
+ if (Val.getAsInteger(0, FunctionGroups) || FunctionGroups < 1)
+ D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val;
+ }
+ if (const auto *A =
+ Args.getLastArg(options::OPT_fprofile_selected_function_group)) {
+ StringRef Val = A->getValue();
+ if (Val.getAsInteger(0, SelectedFunctionGroup) ||
+ SelectedFunctionGroup < 0 || SelectedFunctionGroup >= FunctionGroups)
+ D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val;
+ }
+ if (FunctionGroups != 1)
+ CmdArgs.push_back(Args.MakeArgString("-fprofile-function-groups=" +
+ Twine(FunctionGroups)));
+ if (SelectedFunctionGroup != 0)
+ CmdArgs.push_back(Args.MakeArgString("-fprofile-selected-function-group=" +
+ Twine(SelectedFunctionGroup)));
+
// Leave -fprofile-dir= an unused argument unless .gcda emission is
// enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
// the flag used. There is no -fno-profile-dir, so the user has no
@@ -965,36 +785,45 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
Args.hasArg(options::OPT_coverage))
FProfileDir = Args.getLastArg(options::OPT_fprofile_dir);
- // Put the .gcno and .gcda files (if needed) next to the object file or
- // bitcode file in the case of LTO.
- // FIXME: There should be a simpler way to find the object file for this
- // input, and this code probably does the wrong thing for commands that
- // compile and link all at once.
- if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
- (EmitCovNotes || EmitCovData) && Output.isFilename()) {
- SmallString<128> OutputFilename;
- if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__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());
- SmallString<128> CoverageFilename = OutputFilename;
+ // TODO: Don't claim -c/-S to warn about -fsyntax-only -c/-S, -E -c/-S,
+ // like we warn about -fsyntax-only -E.
+ (void)(Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S));
+
+ // Put the .gcno and .gcda files (if needed) next to the primary output file,
+ // or fall back to a file in the current directory for `clang -c --coverage
+ // d/a.c` in the absence of -o.
+ if (EmitCovNotes || EmitCovData) {
+ SmallString<128> CoverageFilename;
+ if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) {
+ // Form ${dumpdir}${basename}.gcno. Note that dumpdir may not end with a
+ // path separator.
+ CoverageFilename = DumpDir->getValue();
+ CoverageFilename += llvm::sys::path::filename(Output.getBaseInput());
+ } else if (Arg *FinalOutput =
+ C.getArgs().getLastArg(options::OPT__SLASH_Fo)) {
+ CoverageFilename = FinalOutput->getValue();
+ } else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) {
+ CoverageFilename = FinalOutput->getValue();
+ } else {
+ CoverageFilename = llvm::sys::path::filename(Output.getBaseInput());
+ }
if (llvm::sys::path::is_relative(CoverageFilename))
(void)D.getVFS().makeAbsolute(CoverageFilename);
llvm::sys::path::replace_extension(CoverageFilename, "gcno");
-
- CmdArgs.push_back("-coverage-notes-file");
- CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
+ if (EmitCovNotes) {
+ CmdArgs.push_back(
+ Args.MakeArgString("-coverage-notes-file=" + CoverageFilename));
+ }
if (EmitCovData) {
if (FProfileDir) {
+ SmallString<128> Gcno = std::move(CoverageFilename);
CoverageFilename = FProfileDir->getValue();
- llvm::sys::path::append(CoverageFilename, OutputFilename);
+ llvm::sys::path::append(CoverageFilename, Gcno);
}
llvm::sys::path::replace_extension(CoverageFilename, "gcda");
- CmdArgs.push_back("-coverage-data-file");
- CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
+ CmdArgs.push_back(
+ Args.MakeArgString("-coverage-data-file=" + CoverageFilename));
}
}
}
@@ -1029,52 +858,12 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
-// Extract the integer N from a string spelled "-dwarf-N", returning 0
-// on mismatch. The StringRef input (rather than an Arg) allows
-// for use by the "-Xassembler" option parser.
-static unsigned DwarfVersionNum(StringRef ArgValue) {
- return llvm::StringSwitch<unsigned>(ArgValue)
- .Case("-gdwarf-2", 2)
- .Case("-gdwarf-3", 3)
- .Case("-gdwarf-4", 4)
- .Case("-gdwarf-5", 5)
- .Default(0);
-}
-
-// Find a DWARF format version option.
-// This function is a complementary for DwarfVersionNum().
-static const Arg *getDwarfNArg(const ArgList &Args) {
- return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
- options::OPT_gdwarf_4, options::OPT_gdwarf_5,
- options::OPT_gdwarf);
-}
-
-static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind DebugInfoKind,
- unsigned DwarfVersion,
- llvm::DebuggerKind DebuggerTuning) {
- switch (DebugInfoKind) {
- case codegenoptions::DebugDirectivesOnly:
- CmdArgs.push_back("-debug-info-kind=line-directives-only");
- break;
- case codegenoptions::DebugLineTablesOnly:
- CmdArgs.push_back("-debug-info-kind=line-tables-only");
- break;
- case codegenoptions::DebugInfoConstructor:
- CmdArgs.push_back("-debug-info-kind=constructor");
- break;
- case codegenoptions::LimitedDebugInfo:
- CmdArgs.push_back("-debug-info-kind=limited");
- break;
- case codegenoptions::FullDebugInfo:
- CmdArgs.push_back("-debug-info-kind=standalone");
- break;
- case codegenoptions::UnusedTypeInfo:
- CmdArgs.push_back("-debug-info-kind=unused-types");
- break;
- default:
- break;
- }
+static void
+RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ llvm::codegenoptions::DebugInfoKind DebugInfoKind,
+ unsigned DwarfVersion,
+ llvm::DebuggerKind DebuggerTuning) {
+ addDebugInfoKind(CmdArgs, DebugInfoKind);
if (DwarfVersion > 0)
CmdArgs.push_back(
Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion)));
@@ -1118,39 +907,30 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args,
if (Value == "none") {
CmdArgs.push_back("--compress-debug-sections=none");
} else if (Value == "zlib") {
- if (llvm::zlib::isAvailable()) {
+ if (llvm::compression::zlib::isAvailable()) {
+ CmdArgs.push_back(
+ Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
+ } else {
+ D.Diag(diag::warn_debug_compression_unavailable) << "zlib";
+ }
+ } else if (Value == "zstd") {
+ if (llvm::compression::zstd::isAvailable()) {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
- D.Diag(diag::warn_debug_compression_unavailable);
+ D.Diag(diag::warn_debug_compression_unavailable) << "zstd";
}
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
-static const char *RelocationModelName(llvm::Reloc::Model Model) {
- switch (Model) {
- case llvm::Reloc::Static:
- return "static";
- case llvm::Reloc::PIC_:
- return "pic";
- case llvm::Reloc::DynamicNoPIC:
- return "dynamic-no-pic";
- case llvm::Reloc::ROPI:
- return "ropi";
- case llvm::Reloc::RWPI:
- return "rwpi";
- case llvm::Reloc::ROPI_RWPI:
- return "ropi-rwpi";
- }
- llvm_unreachable("Unknown Reloc::Model kind");
-}
static void handleAMDGPUCodeObjectVersionOptions(const Driver &D,
const ArgList &Args,
- ArgStringList &CmdArgs) {
+ ArgStringList &CmdArgs,
+ bool IsCC1As = false) {
// If no version was requested by the user, use the default value from the
// back end. This is consistent with the value returned from
// getAMDGPUCodeObjectVersion. This lets clang emit IR for amdgpu without
@@ -1162,7 +942,51 @@ static void handleAMDGPUCodeObjectVersionOptions(const Driver &D,
Args.MakeArgString(Twine("--amdhsa-code-object-version=") +
Twine(CodeObjVer)));
CmdArgs.insert(CmdArgs.begin() + 1, "-mllvm");
+ // -cc1as does not accept -mcode-object-version option.
+ if (!IsCC1As)
+ CmdArgs.insert(CmdArgs.begin() + 1,
+ Args.MakeArgString(Twine("-mcode-object-version=") +
+ Twine(CodeObjVer)));
+ }
+}
+
+static bool maybeHasClangPchSignature(const Driver &D, StringRef Path) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MemBuf =
+ D.getVFS().getBufferForFile(Path);
+ if (!MemBuf)
+ return false;
+ llvm::file_magic Magic = llvm::identify_magic((*MemBuf)->getBuffer());
+ if (Magic == llvm::file_magic::unknown)
+ return false;
+ // Return true for both raw Clang AST files and object files which may
+ // contain a __clangast section.
+ if (Magic == llvm::file_magic::clang_ast)
+ return true;
+ Expected<std::unique_ptr<llvm::object::ObjectFile>> Obj =
+ llvm::object::ObjectFile::createObjectFile(**MemBuf, Magic);
+ return !Obj.takeError();
+}
+
+static bool gchProbe(const Driver &D, StringRef Path) {
+ llvm::ErrorOr<llvm::vfs::Status> Status = D.getVFS().status(Path);
+ if (!Status)
+ return false;
+
+ if (Status->isDirectory()) {
+ std::error_code EC;
+ for (llvm::vfs::directory_iterator DI = D.getVFS().dir_begin(Path, EC), DE;
+ !EC && DI != DE; DI = DI.increment(EC)) {
+ if (maybeHasClangPchSignature(D, DI->path()))
+ return true;
+ }
+ D.Diag(diag::warn_drv_pch_ignoring_gch_dir) << Path;
+ return false;
}
+
+ if (maybeHasClangPchSignature(D, Path))
+ return true;
+ D.Diag(diag::warn_drv_pch_ignoring_gch_file) << Path;
+ return false;
}
void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
@@ -1217,7 +1041,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
} else {
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(A->getValue(), Quoted);
+ quoteMakeTarget(A->getValue(), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
}
@@ -1242,7 +1066,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(DepTarget, Quoted);
+ quoteMakeTarget(DepTarget, Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
@@ -1274,9 +1098,38 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
if (JA.isOffloading(Action::OFK_HIP))
getToolChain().AddHIPIncludeArgs(Args, CmdArgs);
+ // If we are compiling for a GPU target we want to override the system headers
+ // with ones created by the 'libc' project if present.
+ if (!Args.hasArg(options::OPT_nostdinc) &&
+ !Args.hasArg(options::OPT_nogpuinc) &&
+ !Args.hasArg(options::OPT_nobuiltininc)) {
+ // Without an offloading language we will include these headers directly.
+ // Offloading languages will instead only use the declarations stored in
+ // the resource directory at clang/lib/Headers/llvm_libc_wrappers.
+ if ((getToolChain().getTriple().isNVPTX() ||
+ getToolChain().getTriple().isAMDGCN()) &&
+ C.getActiveOffloadKinds() == Action::OFK_None) {
+ SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir));
+ llvm::sys::path::append(P, "include");
+ llvm::sys::path::append(P, "gpu-none-llvm");
+ CmdArgs.push_back("-c-isystem");
+ CmdArgs.push_back(Args.MakeArgString(P));
+ } else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) {
+ // TODO: CUDA / HIP include their own headers for some common functions
+ // implemented here. We'll need to clean those up so they do not conflict.
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ llvm::sys::path::append(P, "llvm_libc_wrappers");
+ CmdArgs.push_back("-internal-isystem");
+ CmdArgs.push_back(Args.MakeArgString(P));
+ }
+ }
+
// If we are offloading to a target via OpenMP we need to include the
// openmp_wrappers folder which contains alternative system headers.
if (JA.isDeviceOffloading(Action::OFK_OpenMP) &&
+ !Args.hasArg(options::OPT_nostdinc) &&
+ !Args.hasArg(options::OPT_nogpuinc) &&
(getToolChain().getTriple().isNVPTX() ||
getToolChain().getTriple().isAMDGCN())) {
if (!Args.hasArg(options::OPT_nobuiltininc)) {
@@ -1333,7 +1186,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
bool RenderedImplicitInclude = false;
for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
- if (A->getOption().matches(options::OPT_include)) {
+ if (A->getOption().matches(options::OPT_include) &&
+ D.getProbePrecompiled()) {
// Handling of gcc-style gch precompiled headers.
bool IsFirstImplicitInclude = !RenderedImplicitInclude;
RenderedImplicitInclude = true;
@@ -1344,14 +1198,13 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
// so that replace_extension does the right thing.
P += ".dummy";
llvm::sys::path::replace_extension(P, "pch");
- if (llvm::sys::fs::exists(P))
+ if (D.getVFS().exists(P))
FoundPCH = true;
if (!FoundPCH) {
+ // For GCC compat, probe for a file or directory ending in .gch instead.
llvm::sys::path::replace_extension(P, "gch");
- if (llvm::sys::fs::exists(P)) {
- FoundPCH = true;
- }
+ FoundPCH = gchProbe(D, P.str());
}
if (FoundPCH) {
@@ -1376,6 +1229,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
} else if (A->getOption().matches(options::OPT_stdlibxx_isystem)) {
// Translated to -internal-isystem by the driver, no need to pass to cc1.
continue;
+ } else if (A->getOption().matches(options::OPT_ibuiltininc)) {
+ // This is used only by the driver. No need to pass to cc1.
+ continue;
}
// Not translated, render as usual.
@@ -1383,7 +1239,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
}
- Args.AddAllArgs(CmdArgs,
+ Args.addAllArgs(CmdArgs,
{options::OPT_D, options::OPT_U, options::OPT_I_Group,
options::OPT_F, options::OPT_index_header_map});
@@ -1453,6 +1309,17 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
addMacroPrefixMapArg(D, Args, CmdArgs);
addCoveragePrefixMapArg(D, Args, CmdArgs);
+
+ Args.AddLastArg(CmdArgs, options::OPT_ffile_reproducible,
+ options::OPT_fno_file_reproducible);
+
+ if (const char *Epoch = std::getenv("SOURCE_DATE_EPOCH")) {
+ CmdArgs.push_back("-source-date-epoch");
+ CmdArgs.push_back(Args.MakeArgString(Epoch));
+ }
+
+ Args.addOptInFlag(CmdArgs, options::OPT_fdefine_target_os_macros,
+ options::OPT_fno_define_target_os_macros);
}
// FIXME: Move to target hook.
@@ -1625,6 +1492,16 @@ void RenderARMABI(const Driver &D, const llvm::Triple &Triple,
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
}
+
+void AddUnalignedAccessWarning(ArgStringList &CmdArgs) {
+ auto StrictAlignIter =
+ llvm::find_if(llvm::reverse(CmdArgs), [](StringRef Arg) {
+ return Arg == "+strict-align" || Arg == "-strict-align";
+ });
+ if (StrictAlignIter != CmdArgs.rend() &&
+ StringRef(*StrictAlignIter) == "+strict-align")
+ CmdArgs.push_back("-Wunaligned-access");
+}
}
static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
@@ -1643,28 +1520,31 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< Triple.getArchName();
StringRef Scope, Key;
- bool IndirectBranches;
+ bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack;
if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
Scope = A->getValue();
- if (!Scope.equals("none") && !Scope.equals("non-leaf") &&
- !Scope.equals("all"))
- D.Diag(diag::err_invalid_branch_protection)
- << Scope << A->getAsString(Args);
+ if (Scope != "none" && Scope != "non-leaf" && Scope != "all")
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Scope;
Key = "a_key";
IndirectBranches = false;
+ BranchProtectionPAuthLR = false;
+ GuardedControlStack = false;
} else {
StringRef DiagMsg;
llvm::ARM::ParsedBranchProtection PBP;
if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg))
- D.Diag(diag::err_invalid_branch_protection)
- << DiagMsg << A->getAsString(Args);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << DiagMsg;
if (!isAArch64 && PBP.Key == "b_key")
D.Diag(diag::warn_unsupported_branch_protection)
<< "b-key" << A->getAsString(Args);
Scope = PBP.Scope;
Key = PBP.Key;
+ BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
IndirectBranches = PBP.BranchTargetEnforcement;
+ GuardedControlStack = PBP.GuardedControlStack;
}
CmdArgs.push_back(
@@ -1672,8 +1552,13 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
if (!Scope.equals("none"))
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
+ if (BranchProtectionPAuthLR)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
+ if (GuardedControlStack)
+ CmdArgs.push_back("-mguarded-control-stack");
}
void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
@@ -1720,6 +1605,8 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
// Enable/disable return address signing and indirect branch targets.
CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, false /*isAArch64*/);
+
+ AddUnalignedAccessWarning(CmdArgs);
}
void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
@@ -1741,14 +1628,17 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
case llvm::Triple::thumbeb:
// Use the effective triple, which takes into account the deployment target.
AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext);
- CmdArgs.push_back("-fallow-half-arguments-and-returns");
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
AddAArch64TargetArgs(Args, CmdArgs);
- CmdArgs.push_back("-fallow-half-arguments-and-returns");
+ break;
+
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ AddLoongArchTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::mips:
@@ -1857,7 +1747,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") ||
Val.equals("2048+")) {
unsigned Bits = 0;
- if (Val.endswith("+"))
+ if (Val.ends_with("+"))
Val = Val.substr(0, Val.size() - 1);
else {
bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid;
@@ -1874,24 +1764,37 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
} else if (!Val.equals("scalable"))
// Handle the unsupported values passed to msve-vector-bits.
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
AddAAPCSVolatileBitfieldArgs(Args, CmdArgs);
if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) {
- StringRef Name = A->getValue();
-
- std::string TuneCPU;
- if (Name == "native")
- TuneCPU = std::string(llvm::sys::getHostCPUName());
+ CmdArgs.push_back("-tune-cpu");
+ if (strcmp(A->getValue(), "native") == 0)
+ CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
else
- TuneCPU = std::string(Name);
+ CmdArgs.push_back(A->getValue());
+ }
- if (!TuneCPU.empty()) {
- CmdArgs.push_back("-tune-cpu");
- CmdArgs.push_back(Args.MakeArgString(TuneCPU));
- }
+ AddUnalignedAccessWarning(CmdArgs);
+}
+
+void Clang::AddLoongArchTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const llvm::Triple &Triple = getToolChain().getTriple();
+
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(
+ loongarch::getLoongArchABI(getToolChain().getDriver(), Args, Triple)
+ .data());
+
+ // Handle -mtune.
+ if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+ std::string TuneCPU = A->getValue();
+ TuneCPU = loongarch::postProcessTargetCPUString(TuneCPU, Triple);
+ CmdArgs.push_back("-tune-cpu");
+ CmdArgs.push_back(Args.MakeArgString(TuneCPU));
}
}
@@ -2029,7 +1932,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val));
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
} else
D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName;
}
@@ -2045,14 +1948,20 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+ const llvm::Triple &T = getToolChain().getTriple();
+ if (Args.getLastArg(options::OPT_mtune_EQ)) {
+ CmdArgs.push_back("-tune-cpu");
+ std::string CPU = ppc::getPPCTuneCPU(Args, T);
+ CmdArgs.push_back(Args.MakeArgString(CPU));
+ }
+
// Select the ABI to use.
const char *ABIName = nullptr;
- const llvm::Triple &T = getToolChain().getTriple();
if (T.isOSBinFormatELF()) {
switch (getToolChain().getArch()) {
case llvm::Triple::ppc64: {
- if ((T.isOSFreeBSD() && T.getOSMajorVersion() >= 13) ||
- T.isOSOpenBSD() || T.isMusl())
+ if (T.isPPC64ELFv2ABI())
ABIName = "elfv2";
else
ABIName = "elfv1";
@@ -2067,13 +1976,28 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
}
bool IEEELongDouble = getToolChain().defaultToIEEELongDouble();
+ bool VecExtabi = false;
for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) {
StringRef V = A->getValue();
- if (V == "ieeelongdouble")
+ if (V == "ieeelongdouble") {
IEEELongDouble = true;
- else if (V == "ibmlongdouble")
+ A->claim();
+ } else if (V == "ibmlongdouble") {
IEEELongDouble = false;
- else if (V != "altivec")
+ A->claim();
+ } else if (V == "vec-default") {
+ VecExtabi = false;
+ A->claim();
+ } else if (V == "vec-extabi") {
+ VecExtabi = true;
+ A->claim();
+ } else if (V == "elfv1") {
+ ABIName = "elfv1";
+ A->claim();
+ } else if (V == "elfv2") {
+ ABIName = "elfv2";
+ A->claim();
+ } else if (V != "altivec")
// The ppc64 linux abis are all "altivec" abis by default. Accept and ignore
// the option if given as we don't have backend support for any targets
// that don't use the altivec abi.
@@ -2081,10 +2005,14 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
}
if (IEEELongDouble)
CmdArgs.push_back("-mabi=ieeelongdouble");
+ if (VecExtabi) {
+ if (!T.isOSAIX())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << "-mabi=vec-extabi" << T.str();
+ CmdArgs.push_back("-mabi=vec-extabi");
+ }
- ppc::FloatABI FloatABI =
- ppc::getPPCFloatABI(getToolChain().getDriver(), Args);
-
+ ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
if (FloatABI == ppc::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
@@ -2125,6 +2053,12 @@ static void SetRISCVSmallDataLimit(const ToolChain &TC, const ArgList &Args,
if (Args.hasArg(options::OPT_G)) {
D.Diag(diag::warn_drv_unsupported_sdata);
}
+ } else if (Triple.isAndroid()) {
+ // GP relaxation is not supported on Android.
+ SmallDataLimit = "0";
+ if (Args.hasArg(options::OPT_G)) {
+ D.Diag(diag::warn_drv_unsupported_sdata);
+ }
} else if (Arg *A = Args.getLastArg(options::OPT_G)) {
SmallDataLimit = A->getValue();
}
@@ -2143,18 +2077,57 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args,
SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs);
- std::string TuneCPU;
-
- if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) {
- StringRef Name = A->getValue();
+ if (!Args.hasFlag(options::OPT_mimplicit_float,
+ options::OPT_mno_implicit_float, true))
+ CmdArgs.push_back("-no-implicit-float");
- Name = llvm::RISCV::resolveTuneCPUAlias(Name, Triple.isArch64Bit());
- TuneCPU = std::string(Name);
+ if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+ CmdArgs.push_back("-tune-cpu");
+ if (strcmp(A->getValue(), "native") == 0)
+ CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
+ else
+ CmdArgs.push_back(A->getValue());
}
- if (!TuneCPU.empty()) {
- CmdArgs.push_back("-tune-cpu");
- CmdArgs.push_back(Args.MakeArgString(TuneCPU));
+ // Handle -mrvv-vector-bits=<bits>
+ if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) {
+ StringRef Val = A->getValue();
+ const Driver &D = getToolChain().getDriver();
+
+ // Get minimum VLen from march.
+ unsigned MinVLen = 0;
+ StringRef Arch = riscv::getRISCVArch(Args, Triple);
+ auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
+ Arch, /*EnableExperimentalExtensions*/ true);
+ // Ignore parsing error.
+ if (!errorToBool(ISAInfo.takeError()))
+ MinVLen = (*ISAInfo)->getMinVLen();
+
+ // If the value is "zvl", use MinVLen from march. Otherwise, try to parse
+ // as integer as long as we have a MinVLen.
+ unsigned Bits = 0;
+ if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
+ Bits = MinVLen;
+ } else if (!Val.getAsInteger(10, Bits)) {
+ // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
+ // at least MinVLen.
+ if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock ||
+ Bits > 65536 || !llvm::isPowerOf2_32(Bits))
+ Bits = 0;
+ }
+
+ // If we got a valid value try to use it.
+ if (Bits != 0) {
+ unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock;
+ CmdArgs.push_back(
+ Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin)));
+ CmdArgs.push_back(
+ Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin)));
+ } else if (!Val.equals("scalable")) {
+ // Handle the unsupported values passed to mrvv-vector-bits.
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
}
}
@@ -2174,12 +2147,32 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
+
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) {
+ StringRef Name = A->getValue();
+ std::string TuneCPU;
+ if (Name == "native")
+ TuneCPU = std::string(llvm::sys::getHostCPUName());
+ else
+ TuneCPU = std::string(Name);
+
+ CmdArgs.push_back("-tune-cpu");
+ CmdArgs.push_back(Args.MakeArgString(TuneCPU));
+ }
}
void Clang::AddSystemZTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- bool HasBackchain = Args.hasFlag(options::OPT_mbackchain,
- options::OPT_mno_backchain, false);
+ if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+ CmdArgs.push_back("-tune-cpu");
+ if (strcmp(A->getValue(), "native") == 0)
+ CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
+ else
+ CmdArgs.push_back(A->getValue());
+ }
+
+ 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);
systemz::FloatABI FloatABI =
@@ -2238,7 +2231,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-inline-asm=" + Value));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
} else if (D.IsCLMode()) {
CmdArgs.push_back("-mllvm");
@@ -2259,10 +2252,10 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
// Handle -mtune.
- // Default to "generic" unless -march is present or targetting the PS4.
+ // Default to "generic" unless -march is present or targetting the PS4/PS5.
std::string TuneCPU;
if (!Args.hasArg(clang::driver::options::OPT_march_EQ) &&
- !getToolChain().getTriple().isPS4CPU())
+ !getToolChain().getTriple().isPS())
TuneCPU = "generic";
// Override based on -mtune.
@@ -2290,8 +2283,8 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" +
- Twine(G.getValue())));
+ CmdArgs.push_back(
+ Args.MakeArgString("-hexagon-small-data-threshold=" + Twine(*G)));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -2321,7 +2314,7 @@ void Clang::AddLanaiTargetArgs(const ArgList &Args,
if (Mregparm != 4) {
getToolChain().getDriver().Diag(
diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
@@ -2331,10 +2324,8 @@ void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Default to "hidden" visibility.
if (!Args.hasArg(options::OPT_fvisibility_EQ,
- options::OPT_fvisibility_ms_compat)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("hidden");
- }
+ options::OPT_fvisibility_ms_compat))
+ CmdArgs.push_back("-fvisibility=hidden");
}
void Clang::AddVETargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
@@ -2356,7 +2347,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
if (!CompilationDatabase) {
std::error_code EC;
auto File = std::make_unique<llvm::raw_fd_ostream>(
- Filename, EC, llvm::sys::fs::OF_TextWithCRLF);
+ Filename, EC,
+ llvm::sys::fs::OF_TextWithCRLF | llvm::sys::fs::OF_Append);
if (EC) {
D.Diag(clang::diag::err_drv_compilationdatabase) << Filename
<< EC.message();
@@ -2370,7 +2362,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
CWD = ".";
CDB << "{ \"directory\": \"" << escape(*CWD) << "\"";
CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
- CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
+ if (Output.isFilename())
+ CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
SmallString<128> Buf;
Buf = "-x";
@@ -2382,6 +2375,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
CDB << ", \"" << escape(Buf) << "\"";
}
CDB << ", \"" << escape(Input.getFilename()) << "\"";
+ if (Output.isFilename())
+ CDB << ", \"-o\", \"" << escape(Output.getFilename()) << "\"";
for (auto &A: Args) {
auto &O = A->getOption();
// Skip language selection, which is positional.
@@ -2395,6 +2390,9 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
// Skip inputs.
if (O.getKind() == Option::InputClass)
continue;
+ // Skip output.
+ if (O.getID() == options::OPT_o)
+ continue;
// All other arguments are quoted and appended.
ArgStringList ASL;
A->render(Args, ASL);
@@ -2468,6 +2466,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
DefaultIncrementalLinkerCompatible))
CmdArgs.push_back("-mincremental-linker-compatible");
+ Args.AddLastArg(CmdArgs, options::OPT_femit_dwarf_unwind_EQ);
+
+ Args.addOptInFlag(CmdArgs, options::OPT_femit_compact_unwind_non_canonical,
+ options::OPT_fno_emit_compact_unwind_non_canonical);
+
// If you add more args here, also add them to the block below that
// starts with "// If CollectArgsForIntegratedAssembler() isn't called below".
@@ -2497,7 +2500,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
ImplicitIt = A->getValue();
if (!CheckARMImplicitITArg(ImplicitIt))
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << ImplicitIt;
+ << A->getSpelling() << ImplicitIt;
continue;
default:
break;
@@ -2518,11 +2521,18 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
switch (C.getDefaultToolChain().getArch()) {
default:
break;
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ if (Value == "--no-type-check") {
+ CmdArgs.push_back("-mno-type-check");
+ continue;
+ }
+ break;
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
case llvm::Triple::arm:
case llvm::Triple::armeb:
- if (Value.startswith("-mimplicit-it=")) {
+ if (Value.starts_with("-mimplicit-it=")) {
// Only store the value; the last value set takes effect.
ImplicitIt = Value.split("=").second;
if (CheckARMImplicitITArg(ImplicitIt))
@@ -2547,12 +2557,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
CmdArgs.push_back("-use-tcc-in-div");
continue;
}
- if (Value.startswith("-msoft-float")) {
+ if (Value.starts_with("-msoft-float")) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+soft-float");
continue;
}
- if (Value.startswith("-mhard-float")) {
+ if (Value.starts_with("-mhard-float")) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-soft-float");
continue;
@@ -2589,8 +2599,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
CmdArgs.push_back("-massembler-no-warn");
} else if (Value == "--noexecstack") {
UseNoExecStack = true;
- } else if (Value.startswith("-compress-debug-sections") ||
- Value.startswith("--compress-debug-sections") ||
+ } else if (Value.starts_with("-compress-debug-sections") ||
+ Value.starts_with("--compress-debug-sections") ||
Value == "-nocompress-debug-sections" ||
Value == "--nocompress-debug-sections") {
CmdArgs.push_back(Value.data());
@@ -2600,46 +2610,46 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
} else if (Value == "-mrelax-relocations=no" ||
Value == "--mrelax-relocations=no") {
UseRelaxRelocations = false;
- } else if (Value.startswith("-I")) {
+ } else if (Value.starts_with("-I")) {
CmdArgs.push_back(Value.data());
// We need to consume the next argument if the current arg is a plain
// -I. The next arg will be the include directory.
if (Value == "-I")
TakeNextArg = true;
- } else if (Value.startswith("-gdwarf-")) {
+ } else if (Value.starts_with("-gdwarf-")) {
// "-gdwarf-N" options are not cc1as options.
unsigned DwarfVersion = DwarfVersionNum(Value);
if (DwarfVersion == 0) { // Send it onward, and let cc1as complain.
CmdArgs.push_back(Value.data());
} else {
RenderDebugEnablingArgs(Args, CmdArgs,
- codegenoptions::DebugInfoConstructor,
+ llvm::codegenoptions::DebugInfoConstructor,
DwarfVersion, llvm::DebuggerKind::Default);
}
- } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
- Value.startswith("-mhwdiv") || Value.startswith("-march")) {
+ } else if (Value.starts_with("-mcpu") || Value.starts_with("-mfpu") ||
+ Value.starts_with("-mhwdiv") || Value.starts_with("-march")) {
// Do nothing, we'll validate it later.
} else if (Value == "-defsym") {
- if (A->getNumValues() != 2) {
- D.Diag(diag::err_drv_defsym_invalid_format) << Value;
- break;
- }
- const char *S = A->getValue(1);
- auto Pair = StringRef(S).split('=');
- auto Sym = Pair.first;
- auto SVal = Pair.second;
-
- if (Sym.empty() || SVal.empty()) {
- D.Diag(diag::err_drv_defsym_invalid_format) << S;
- break;
- }
- int64_t IVal;
- if (SVal.getAsInteger(0, IVal)) {
- D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
- break;
- }
- CmdArgs.push_back(Value.data());
- TakeNextArg = true;
+ if (A->getNumValues() != 2) {
+ D.Diag(diag::err_drv_defsym_invalid_format) << Value;
+ break;
+ }
+ const char *S = A->getValue(1);
+ auto Pair = StringRef(S).split('=');
+ auto Sym = Pair.first;
+ auto SVal = Pair.second;
+
+ if (Sym.empty() || SVal.empty()) {
+ D.Diag(diag::err_drv_defsym_invalid_format) << S;
+ break;
+ }
+ int64_t IVal;
+ if (SVal.getAsInteger(0, IVal)) {
+ D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
+ break;
+ }
+ CmdArgs.push_back(Value.data());
+ TakeNextArg = true;
} else if (Value == "-fdebug-compilation-dir") {
CmdArgs.push_back("-fdebug-compilation-dir");
TakeNextArg = true;
@@ -2653,14 +2663,14 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
D.PrintVersion(C, llvm::outs());
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
if (ImplicitIt.size())
AddARMImplicitITArgs(Args, CmdArgs, ImplicitIt);
- if (UseRelaxRelocations)
- CmdArgs.push_back("--mrelax-relocations");
+ if (!UseRelaxRelocations)
+ CmdArgs.push_back("-mrelax-relocations=no");
if (UseNoExecStack)
CmdArgs.push_back("-mnoexecstack");
if (MipsTargetFeature != nullptr) {
@@ -2672,6 +2682,53 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
if (C.getDriver().embedBitcodeEnabled() ||
C.getDriver().embedBitcodeMarkerOnly())
Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
+
+ if (const char *AsSecureLogFile = getenv("AS_SECURE_LOG_FILE")) {
+ CmdArgs.push_back("-as-secure-log-file");
+ CmdArgs.push_back(Args.MakeArgString(AsSecureLogFile));
+ }
+}
+
+static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) {
+ StringRef RangeStr = "";
+ switch (Range) {
+ case LangOptions::ComplexRangeKind::CX_Limited:
+ return "-fcx-limited-range";
+ break;
+ case LangOptions::ComplexRangeKind::CX_Fortran:
+ return "-fcx-fortran-rules";
+ break;
+ default:
+ return RangeStr;
+ break;
+ }
+}
+
+static void EmitComplexRangeDiag(const Driver &D,
+ LangOptions::ComplexRangeKind Range1,
+ LangOptions::ComplexRangeKind Range2) {
+ if (Range1 != LangOptions::ComplexRangeKind::CX_Full)
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2);
+}
+
+static std::string
+RenderComplexRangeOption(LangOptions::ComplexRangeKind Range) {
+ std::string ComplexRangeStr = "-complex-range=";
+ switch (Range) {
+ case LangOptions::ComplexRangeKind::CX_Full:
+ ComplexRangeStr += "full";
+ break;
+ case LangOptions::ComplexRangeKind::CX_Limited:
+ ComplexRangeStr += "limited";
+ break;
+ case LangOptions::ComplexRangeKind::CX_Fortran:
+ ComplexRangeStr += "fortran";
+ break;
+ default:
+ assert(0 && "Unexpected range option");
+ }
+ return ComplexRangeStr;
}
static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
@@ -2700,6 +2757,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
StringRef FPModel = "";
// -ffp-exception-behavior options: strict, maytrap, ignore
StringRef FPExceptionBehavior = "";
+ // -ffp-eval-method options: double, extended, source
+ StringRef FPEvalMethod = "";
const llvm::DenormalMode DefaultDenormalFPMath =
TC.getDefaultDenormalModeForType(Args, JA);
const llvm::DenormalMode DefaultDenormalFP32Math =
@@ -2710,10 +2769,16 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// CUDA and HIP don't rely on the frontend to pass an ffp-contract option.
// If one wasn't given by the user, don't pass it here.
StringRef FPContract;
+ StringRef LastSeenFfpContractOption;
+ bool SeenUnsafeMathModeOption = false;
if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
!JA.isOffloading(Action::OFK_HIP))
FPContract = "on";
bool StrictFPModel = false;
+ StringRef Float16ExcessPrecision = "";
+ StringRef BFloat16ExcessPrecision = "";
+ LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None;
+ std::string ComplexRangeStr = "";
if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2726,10 +2791,29 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
switch (optID) {
default:
break;
+ case options::OPT_fcx_limited_range: {
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited);
+ Range = LangOptions::ComplexRangeKind::CX_Limited;
+ break;
+ }
+ case options::OPT_fno_cx_limited_range:
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full);
+ Range = LangOptions::ComplexRangeKind::CX_Full;
+ break;
+ case options::OPT_fcx_fortran_rules: {
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran);
+ Range = LangOptions::ComplexRangeKind::CX_Fortran;
+ break;
+ }
+ case options::OPT_fno_cx_fortran_rules:
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full);
+ Range = LangOptions::ComplexRangeKind::CX_Full;
+ break;
case options::OPT_ffp_model_EQ: {
// If -ffp-model= is seen, reset to fno-fast-math
HonorINFs = true;
HonorNaNs = true;
+ ApproxFunc = false;
// Turning *off* -ffast-math restores the toolchain default.
MathErrno = TC.IsMathErrnoDefault();
AssociativeMath = false;
@@ -2746,9 +2830,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
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";
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << Args.MakeArgString("-ffp-model=" + Val) << "-Ofast";
break;
}
StrictFPModel = false;
@@ -2757,7 +2840,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// 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)
+ D.Diag(clang::diag::warn_drv_overriding_option)
<< Args.MakeArgString("-ffp-model=" + FPModel)
<< Args.MakeArgString("-ffp-model=" + Val);
if (Val.equals("fast")) {
@@ -2778,9 +2861,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
TrappingMath = true;
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
- }
+ }
}
switch (optID) {
@@ -2806,9 +2889,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
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";
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << Args.MakeArgString("-ffp-exception-behavior=" +
+ FPExceptionBehavior)
+ << "-ftrapping-math";
TrappingMath = true;
TrappingMathPresent = true;
FPExceptionBehavior = "strict";
@@ -2817,9 +2901,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
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";
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << Args.MakeArgString("-ffp-exception-behavior=" +
+ FPExceptionBehavior)
+ << "-fno-trapping-math";
TrappingMath = false;
TrappingMathPresent = true;
FPExceptionBehavior = "ignore";
@@ -2837,6 +2922,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
case options::OPT_fdenormal_fp_math_EQ:
DenormalFPMath = llvm::parseDenormalFPAttribute(A->getValue());
+ DenormalFP32Math = DenormalFPMath;
if (!DenormalFPMath.isValid()) {
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
@@ -2859,11 +2945,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// -ffp-model=precise sets PreciseFPModel to on and Val to
// "precise". FPContract is set.
;
- } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off"))
+ } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off") ||
+ Val.equals("fast-honor-pragmas")) {
FPContract = Val;
- else
+ LastSeenFfpContractOption = Val;
+ } else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
@@ -2880,9 +2968,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
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);
+ D.Diag(clang::diag::warn_drv_overriding_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;
@@ -2891,10 +2980,44 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
TrappingMath = TrappingMathPresent = true;
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
+ break;
+ }
+
+ // Validate and pass through -ffp-eval-method option.
+ case options::OPT_ffp_eval_method_EQ: {
+ StringRef Val = A->getValue();
+ if (Val.equals("double") || Val.equals("extended") ||
+ Val.equals("source"))
+ FPEvalMethod = Val;
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
break;
}
+ case options::OPT_fexcess_precision_EQ: {
+ StringRef Val = A->getValue();
+ const llvm::Triple::ArchType Arch = TC.getArch();
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ if (Val.equals("standard") || Val.equals("fast"))
+ Float16ExcessPrecision = Val;
+ // To make it GCC compatible, allow the value of "16" which
+ // means disable excess precision, the same meaning than clang's
+ // equivalent value "none".
+ else if (Val.equals("16"))
+ Float16ExcessPrecision = "none";
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ } else {
+ if (!(Val.equals("standard") || Val.equals("fast")))
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
+ BFloat16ExcessPrecision = Float16ExcessPrecision;
+ break;
+ }
case options::OPT_ffinite_math_only:
HonorINFs = false;
HonorNaNs = false;
@@ -2911,6 +3034,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
ApproxFunc = true;
TrappingMath = false;
FPExceptionBehavior = "";
+ FPContract = "fast";
+ SeenUnsafeMathModeOption = true;
break;
case options::OPT_fno_unsafe_math_optimizations:
AssociativeMath = false;
@@ -2923,14 +3048,21 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// The target may have opted to flush by default, so force IEEE.
DenormalFPMath = llvm::DenormalMode::getIEEE();
DenormalFP32Math = llvm::DenormalMode::getIEEE();
+ if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
+ !JA.isOffloading(Action::OFK_HIP)) {
+ if (LastSeenFfpContractOption != "") {
+ FPContract = LastSeenFfpContractOption;
+ } else if (SeenUnsafeMathModeOption)
+ FPContract = "on";
+ }
break;
case options::OPT_Ofast:
// If -Ofast is the optimization level, then -ffast-math should be enabled
if (!OFastEnabled)
continue;
- LLVM_FALLTHROUGH;
- case options::OPT_ffast_math:
+ [[fallthrough]];
+ case options::OPT_ffast_math: {
HonorINFs = false;
HonorNaNs = false;
MathErrno = false;
@@ -2940,9 +3072,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
SignedZeros = false;
TrappingMath = false;
RoundingFPMath = false;
+ FPExceptionBehavior = "";
// If fast-math is set then set the fp-contract mode to fast.
FPContract = "fast";
+ SeenUnsafeMathModeOption = true;
+ // ffast-math enables fortran rules for complex multiplication and
+ // division.
+ Range = LangOptions::ComplexRangeKind::CX_Limited;
break;
+ }
case options::OPT_fno_fast_math:
HonorINFs = true;
HonorNaNs = true;
@@ -2958,13 +3096,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
DenormalFPMath = DefaultDenormalFPMath;
DenormalFP32Math = llvm::DenormalMode::getIEEE();
if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
- !JA.isOffloading(Action::OFK_HIP))
- if (FPContract == "fast") {
+ !JA.isOffloading(Action::OFK_HIP)) {
+ if (LastSeenFfpContractOption != "") {
+ FPContract = LastSeenFfpContractOption;
+ } else if (SeenUnsafeMathModeOption)
FPContract = "on";
- D.Diag(clang::diag::warn_drv_overriding_flag_option)
- << "-ffp-contract=fast"
- << "-ffp-contract=on";
- }
+ }
break;
}
if (StrictFPModel) {
@@ -2980,10 +3117,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
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()));
+ auto RHS = (A->getNumValues() == 0)
+ ? A->getSpelling()
+ : Args.MakeArgString(A->getSpelling() + A->getValue());
+ if (RHS != "-ffp-model=strict")
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << "-ffp-model=strict" << RHS;
}
}
@@ -3003,9 +3142,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (MathErrno)
CmdArgs.push_back("-fmath-errno");
- if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
- ApproxFunc && !TrappingMath)
- CmdArgs.push_back("-menable-unsafe-fp-math");
+ if (AssociativeMath && ReciprocalMath && !SignedZeros && ApproxFunc &&
+ !TrappingMath)
+ CmdArgs.push_back("-funsafe-math-optimizations");
if (!SignedZeros)
CmdArgs.push_back("-fno-signed-zeros");
@@ -3050,6 +3189,16 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" +
FPExceptionBehavior));
+ if (!FPEvalMethod.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + FPEvalMethod));
+
+ if (!Float16ExcessPrecision.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffloat16-excess-precision=" +
+ Float16ExcessPrecision));
+ if (!BFloat16ExcessPrecision.empty())
+ CmdArgs.push_back(Args.MakeArgString("-fbfloat16-excess-precision=" +
+ BFloat16ExcessPrecision));
+
ParseMRecip(D, Args, CmdArgs);
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
@@ -3066,9 +3215,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// 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);
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << "-ffp-model=fast"
+ << Args.MakeArgString("-ffp-contract=" + FPContract);
}
}
@@ -3085,17 +3234,24 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow,
options::OPT_fstrict_float_cast_overflow, false))
CmdArgs.push_back("-fno-strict-float-cast-overflow");
+
+ if (Range != LangOptions::ComplexRangeKind::CX_None)
+ ComplexRangeStr = RenderComplexRangeOption(Range);
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
+ if (Args.hasArg(options::OPT_fcx_limited_range))
+ CmdArgs.push_back("-fcx-limited-range");
+ if (Args.hasArg(options::OPT_fcx_fortran_rules))
+ CmdArgs.push_back("-fcx-fortran-rules");
+ if (Args.hasArg(options::OPT_fno_cx_limited_range))
+ CmdArgs.push_back("-fno-cx-limited-range");
+ if (Args.hasArg(options::OPT_fno_cx_fortran_rules))
+ CmdArgs.push_back("-fno-cx-fortran-rules");
}
static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
const llvm::Triple &Triple,
const InputInfo &Input) {
- // Enable region store model by default.
- CmdArgs.push_back("-analyzer-store=region");
-
- // Treat blocks as analysis entry points.
- CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks");
-
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
@@ -3113,8 +3269,8 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg");
}
- // Disable some unix checkers for PS4.
- if (Triple.isPS4CPU()) {
+ // Disable some unix checkers for PS4/PS5.
+ if (Triple.isPS()) {
CmdArgs.push_back("-analyzer-disable-checker=unix.API");
CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
}
@@ -3132,7 +3288,7 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
if (types::isCXX(Input.getType()))
CmdArgs.push_back("-analyzer-checker=cplusplus");
- if (!Triple.isPS4CPU()) {
+ if (!Triple.isPS()) {
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
@@ -3162,6 +3318,16 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
}
+static bool isValidSymbolName(StringRef S) {
+ if (S.empty())
+ return false;
+
+ if (std::isdigit(S[0]))
+ return false;
+
+ return llvm::all_of(S, [](char C) { return std::isalnum(C) || C == '_'; });
+}
+
static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
const ArgList &Args, ArgStringList &CmdArgs,
bool KernelOrKext) {
@@ -3188,6 +3354,12 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
StackProtectorLevel = LangOptions::SSPStrong;
else if (A->getOption().matches(options::OPT_fstack_protector_all))
StackProtectorLevel = LangOptions::SSPReq;
+
+ if (EffectiveTriple.isBPF() && StackProtectorLevel != LangOptions::SSPOff) {
+ D.Diag(diag::warn_drv_unsupported_option_for_target)
+ << A->getSpelling() << EffectiveTriple.getTriple();
+ StackProtectorLevel = DefaultStackProtectorLevel;
+ }
} else {
StackProtectorLevel = DefaultStackProtectorLevel;
}
@@ -3200,7 +3372,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
// --param ssp-buffer-size=
for (const Arg *A : Args.filtered(options::OPT__param)) {
StringRef Str(A->getValue());
- if (Str.startswith("ssp-buffer-size=")) {
+ if (Str.starts_with("ssp-buffer-size=")) {
if (StackProtectorLevel) {
CmdArgs.push_back("-stack-protector-buffer-size");
// FIXME: Verify the argument is a valid integer.
@@ -3247,7 +3419,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
}
}
CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+read-tp-hard");
+ CmdArgs.push_back("+read-tp-tpidruro");
}
if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") {
D.Diag(diag::err_drv_invalid_value_with_suggestion)
@@ -3293,6 +3465,16 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
}
A->render(Args, CmdArgs);
}
+
+ if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_symbol_EQ)) {
+ StringRef Value = A->getValue();
+ if (!isValidSymbolName(Value)) {
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << A->getOption().getName() << "legal symbol name";
+ return;
+ }
+ A->render(Args, CmdArgs);
+ }
}
static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
@@ -3303,12 +3485,11 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
return;
if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() &&
- !EffectiveTriple.isPPC64())
+ !EffectiveTriple.isPPC64() && !EffectiveTriple.isAArch64())
return;
- if (Args.hasFlag(options::OPT_fstack_clash_protection,
- options::OPT_fno_stack_clash_protection, false))
- CmdArgs.push_back("-fstack-clash-protection");
+ Args.addOptInFlag(CmdArgs, options::OPT_fstack_clash_protection,
+ options::OPT_fno_stack_clash_protection);
}
static void RenderTrivialAutoVarInitOptions(const Driver &D,
@@ -3329,7 +3510,7 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D,
TrivialAutoVarInit = Val;
else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
}
@@ -3348,8 +3529,6 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D,
}
if (!TrivialAutoVarInit.empty()) {
- if (TrivialAutoVarInit == "zero" && !Args.hasArg(options::OPT_enable_trivial_var_init_zero))
- D.Diag(diag::err_drv_trivial_auto_var_init_zero_disabled);
CmdArgs.push_back(
Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit));
}
@@ -3368,6 +3547,20 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D,
CmdArgs.push_back(
Args.MakeArgString("-ftrivial-auto-var-init-stop-after=" + Val));
}
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftrivial_auto_var_init_max_size)) {
+ if (!Args.hasArg(options::OPT_ftrivial_auto_var_init) ||
+ StringRef(
+ Args.getLastArg(options::OPT_ftrivial_auto_var_init)->getValue()) ==
+ "uninitialized")
+ D.Diag(diag::err_drv_trivial_auto_var_init_max_size_missing_dependency);
+ A->claim();
+ StringRef Val = A->getValue();
+ if (std::stoi(Val.str()) <= 0)
+ D.Diag(diag::err_drv_trivial_auto_var_init_max_size_invalid_value);
+ CmdArgs.push_back(
+ Args.MakeArgString("-ftrivial-auto-var-init-max-size=" + Val));
+ }
}
static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs,
@@ -3391,6 +3584,9 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs,
if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) {
std::string CLStdStr = std::string("-cl-std=") + A->getValue();
CmdArgs.push_back(Args.MakeArgString(CLStdStr));
+ } else if (Arg *A = Args.getLastArg(options::OPT_cl_ext_EQ)) {
+ std::string CLExtStr = std::string("-cl-ext=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(CLExtStr));
}
for (const auto &Arg : ForwardedArguments)
@@ -3406,6 +3602,46 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs,
}
}
+static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
+ types::ID InputType) {
+ const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version,
+ options::OPT_D,
+ options::OPT_I,
+ options::OPT_S,
+ options::OPT_O,
+ options::OPT_emit_llvm,
+ options::OPT_emit_obj,
+ options::OPT_disable_llvm_passes,
+ options::OPT_fnative_half_type,
+ options::OPT_hlsl_entrypoint};
+ if (!types::isHLSL(InputType))
+ return;
+ for (const auto &Arg : ForwardedArguments)
+ if (const auto *A = Args.getLastArg(Arg))
+ A->renderAsInput(Args, CmdArgs);
+ // Add the default headers if dxc_no_stdinc is not set.
+ if (!Args.hasArg(options::OPT_dxc_no_stdinc) &&
+ !Args.hasArg(options::OPT_nostdinc))
+ CmdArgs.push_back("-finclude-default-header");
+}
+
+static void RenderOpenACCOptions(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs, types::ID InputType) {
+ if (!Args.hasArg(options::OPT_fopenacc))
+ return;
+
+ CmdArgs.push_back("-fopenacc");
+
+ if (Arg *A = Args.getLastArg(options::OPT_openacc_macro_override)) {
+ StringRef Value = A->getValue();
+ int Version;
+ if (!Value.getAsInteger(10, Version))
+ A->renderAsInput(Args, CmdArgs);
+ else
+ D.Diag(diag::err_drv_clang_unsupported) << Value;
+ }
+}
+
static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs) {
bool ARCMTEnabled = false;
@@ -3492,20 +3728,13 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T,
UseBuiltins = false;
// Process the -fno-builtin-* options.
- for (const auto &Arg : Args) {
- const Option &O = Arg->getOption();
- if (!O.matches(options::OPT_fno_builtin_))
- continue;
-
- Arg->claim();
+ for (const Arg *A : Args.filtered(options::OPT_fno_builtin_)) {
+ A->claim();
// If -fno-builtin is specified, then there's no need to pass the option to
// the frontend.
- if (!UseBuiltins)
- continue;
-
- StringRef FuncName = Arg->getValue();
- CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName));
+ if (UseBuiltins)
+ A->render(Args, CmdArgs);
}
// le32-specific flags:
@@ -3516,6 +3745,11 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T,
}
bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) {
+ if (const char *Str = std::getenv("CLANG_MODULE_CACHE_PATH")) {
+ Twine Path{Str};
+ Path.toVector(Result);
+ return Path.getSingleStringRef() != "";
+ }
if (llvm::sys::path::cache_directory(Result)) {
llvm::sys::path::append(Result, "clang");
llvm::sys::path::append(Result, "ModuleCache");
@@ -3524,10 +3758,14 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) {
return false;
}
-static void RenderModulesOptions(Compilation &C, const Driver &D,
+static bool RenderModulesOptions(Compilation &C, const Driver &D,
const ArgList &Args, const InputInfo &Input,
- const InputInfo &Output,
- ArgStringList &CmdArgs, bool &HaveModules) {
+ const InputInfo &Output, bool HaveStd20,
+ ArgStringList &CmdArgs) {
+ bool IsCXX = types::isCXX(Input.getType());
+ bool HaveStdCXXModules = IsCXX && HaveStd20;
+ bool HaveModules = HaveStdCXXModules;
+
// -fmodules enables the use of precompiled modules (off by default).
// Users can pass -fno-cxx-modules to turn off modules support for
// C++/Objective-C++ programs.
@@ -3535,17 +3773,13 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules, true);
- if (AllowedInCXX || !types::isCXX(Input.getType())) {
+ if (AllowedInCXX || !IsCXX) {
CmdArgs.push_back("-fmodules");
HaveClangModules = true;
}
}
HaveModules |= HaveClangModules;
- if (Args.hasArg(options::OPT_fmodules_ts)) {
- CmdArgs.push_back("-fmodules-ts");
- HaveModules = true;
- }
// -fmodule-maps enables implicit reading of module map files. By default,
// this is enabled if we are using Clang's flavor of precompiled modules.
@@ -3554,9 +3788,8 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
CmdArgs.push_back("-fimplicit-module-maps");
// -fmodules-decluse checks that modules used are declared so (off by default)
- if (Args.hasFlag(options::OPT_fmodules_decluse,
- options::OPT_fno_modules_decluse, false))
- CmdArgs.push_back("-fmodules-decluse");
+ Args.addOptInFlag(CmdArgs, options::OPT_fmodules_decluse,
+ options::OPT_fno_modules_decluse);
// -fmodules-strict-decluse is like -fmodule-decluse, but also checks that
// all #included headers are part of modules.
@@ -3600,12 +3833,6 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
}
if (HaveModules) {
- // -fprebuilt-module-path specifies where to load the prebuilt module files.
- for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) {
- CmdArgs.push_back(Args.MakeArgString(
- std::string("-fprebuilt-module-path=") + A->getValue()));
- A->claim();
- }
if (Args.hasFlag(options::OPT_fprebuilt_implicit_modules,
options::OPT_fno_prebuilt_implicit_modules, false))
CmdArgs.push_back("-fprebuilt-implicit-modules");
@@ -3638,9 +3865,16 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
// names to precompiled module files (the module is loaded only if used).
// The -fmodule-file=<file> form can be used to unconditionally load
// precompiled module files (whether used or not).
- if (HaveModules)
+ if (HaveModules || Input.getType() == clang::driver::types::TY_ModuleFile) {
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
- else
+
+ // -fprebuilt-module-path specifies where to load the prebuilt module files.
+ for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) {
+ CmdArgs.push_back(Args.MakeArgString(
+ std::string("-fprebuilt-module-path=") + A->getValue()));
+ A->claim();
+ }
+ } else
Args.ClaimAllArgs(options::OPT_fmodule_file);
// When building modules and generating crashdumps, we need to dump a module
@@ -3664,38 +3898,59 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
- Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
+ if (HaveClangModules) {
+ Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
- if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
- if (Args.hasArg(options::OPT_fbuild_session_timestamp))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "-fbuild-session-timestamp";
+ if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
+ if (Args.hasArg(options::OPT_fbuild_session_timestamp))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-fbuild-session-timestamp";
- llvm::sys::fs::file_status Status;
- if (llvm::sys::fs::status(A->getValue(), Status))
- D.Diag(diag::err_drv_no_such_file) << A->getValue();
- CmdArgs.push_back(Args.MakeArgString(
- "-fbuild-session-timestamp=" +
- Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>(
- Status.getLastModificationTime().time_since_epoch())
- .count())));
- }
+ llvm::sys::fs::file_status Status;
+ if (llvm::sys::fs::status(A->getValue(), Status))
+ D.Diag(diag::err_drv_no_such_file) << A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(
+ "-fbuild-session-timestamp=" +
+ Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>(
+ Status.getLastModificationTime().time_since_epoch())
+ .count())));
+ }
+
+ if (Args.getLastArg(
+ options::OPT_fmodules_validate_once_per_build_session)) {
+ if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
+ options::OPT_fbuild_session_file))
+ D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
- if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
- if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
- options::OPT_fbuild_session_file))
- D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
+ Args.AddLastArg(CmdArgs,
+ options::OPT_fmodules_validate_once_per_build_session);
+ }
+
+ if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
+ options::OPT_fno_modules_validate_system_headers,
+ ImplicitModules))
+ CmdArgs.push_back("-fmodules-validate-system-headers");
Args.AddLastArg(CmdArgs,
- options::OPT_fmodules_validate_once_per_build_session);
+ options::OPT_fmodules_disable_diagnostic_validation);
+ } else {
+ Args.ClaimAllArgs(options::OPT_fbuild_session_timestamp);
+ Args.ClaimAllArgs(options::OPT_fbuild_session_file);
+ Args.ClaimAllArgs(options::OPT_fmodules_validate_once_per_build_session);
+ Args.ClaimAllArgs(options::OPT_fmodules_validate_system_headers);
+ Args.ClaimAllArgs(options::OPT_fno_modules_validate_system_headers);
+ Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation);
}
- if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
- options::OPT_fno_modules_validate_system_headers,
- ImplicitModules))
- CmdArgs.push_back("-fmodules-validate-system-headers");
+ // FIXME: We provisionally don't check ODR violations for decls in the global
+ // module fragment.
+ CmdArgs.push_back("-fskip-odr-check-in-gmf");
+
+ // Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings.
+ Args.ClaimAllArgs(options::OPT_fmodule_output);
+ Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation);
+ return HaveModules;
}
static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
@@ -3730,7 +3985,8 @@ static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
else
CmdArgs.push_back("-fsigned-wchar");
}
- }
+ } else if (T.isOSzOS())
+ CmdArgs.push_back("-fno-signed-wchar");
}
static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
@@ -3855,15 +4111,10 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
options::OPT_fno_caret_diagnostics, CaretDefault))
CmdArgs.push_back("-fno-caret-diagnostics");
- // -fdiagnostics-fixit-info is default, only pass non-default.
- if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
- options::OPT_fno_diagnostics_fixit_info))
- CmdArgs.push_back("-fno-diagnostics-fixit-info");
-
- // Enable -fdiagnostics-show-option by default.
- if (!Args.hasFlag(options::OPT_fdiagnostics_show_option,
- options::OPT_fno_diagnostics_show_option, true))
- CmdArgs.push_back("-fno-diagnostics-show-option");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_fixit_info,
+ options::OPT_fno_diagnostics_fixit_info);
+ Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_option,
+ options::OPT_fno_diagnostics_show_option);
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
@@ -3871,9 +4122,8 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
CmdArgs.push_back(A->getValue());
}
- if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
- options::OPT_fno_diagnostics_show_hotness, false))
- CmdArgs.push_back("-fdiagnostics-show-hotness");
+ Args.addOptInFlag(CmdArgs, options::OPT_fdiagnostics_show_hotness,
+ options::OPT_fno_diagnostics_show_hotness);
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
@@ -3882,9 +4132,19 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(Opt));
}
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_misexpect_tolerance_EQ)) {
+ std::string Opt =
+ std::string("-fdiagnostics-misexpect-tolerance=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(Opt));
+ }
+
if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
CmdArgs.push_back(A->getValue());
+ if (StringRef(A->getValue()) == "sarif" ||
+ StringRef(A->getValue()) == "SARIF")
+ D.Diag(diag::warn_drv_sarif_format_unstable);
}
if (const Arg *A = Args.getLastArg(
@@ -3901,22 +4161,13 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
// re-parsed to construct this job; claim any possible color diagnostic here
// to avoid warn_drv_unused_argument and diagnose bad
// OPT_fdiagnostics_color_EQ values.
- for (const Arg *A : Args) {
- const Option &O = A->getOption();
- if (!O.matches(options::OPT_fcolor_diagnostics) &&
- !O.matches(options::OPT_fdiagnostics_color) &&
- !O.matches(options::OPT_fno_color_diagnostics) &&
- !O.matches(options::OPT_fno_diagnostics_color) &&
- !O.matches(options::OPT_fdiagnostics_color_EQ))
- continue;
-
- if (O.matches(options::OPT_fdiagnostics_color_EQ)) {
- StringRef Value(A->getValue());
- if (Value != "always" && Value != "never" && Value != "auto")
- D.Diag(diag::err_drv_clang_unsupported)
- << ("-fdiagnostics-color=" + Value).str();
- }
- A->claim();
+ Args.getLastArg(options::OPT_fcolor_diagnostics,
+ options::OPT_fno_color_diagnostics);
+ if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_color_EQ)) {
+ StringRef Value(A->getValue());
+ if (Value != "always" && Value != "never" && Value != "auto")
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << Value << A->getOption().getName();
}
if (D.getDiags().getDiagnosticOptions().ShowColors)
@@ -3925,9 +4176,11 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
if (Args.hasArg(options::OPT_fansi_escape_codes))
CmdArgs.push_back("-fansi-escape-codes");
- if (!Args.hasFlag(options::OPT_fshow_source_location,
- options::OPT_fno_show_source_location))
- CmdArgs.push_back("-fno-show-source-location");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fshow_source_location,
+ options::OPT_fno_show_source_location);
+
+ Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_line_numbers,
+ options::OPT_fno_diagnostics_show_line_numbers);
if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths))
CmdArgs.push_back("-fdiagnostics-absolute-paths");
@@ -3936,14 +4189,11 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
ColumnDefault))
CmdArgs.push_back("-fno-show-column");
- if (!Args.hasFlag(options::OPT_fspell_checking,
- options::OPT_fno_spell_checking))
- CmdArgs.push_back("-fno-spell-checking");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fspell_checking,
+ options::OPT_fno_spell_checking);
}
-enum class DwarfFissionKind { None, Split, Single };
-
-static DwarfFissionKind getDebugFissionKind(const Driver &D,
+DwarfFissionKind tools::getDebugFissionKind(const Driver &D,
const ArgList &Args, Arg *&Arg) {
Arg = Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ,
options::OPT_gno_split_dwarf);
@@ -3960,7 +4210,7 @@ static DwarfFissionKind getDebugFissionKind(const Driver &D,
return DwarfFissionKind::Single;
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
return DwarfFissionKind::None;
}
@@ -3987,12 +4237,12 @@ static void renderDwarfFormat(const Driver &D, const llvm::Triple &T,
DwarfFormatArg->render(Args, CmdArgs);
}
-static void renderDebugOptions(const ToolChain &TC, const Driver &D,
- const llvm::Triple &T, const ArgList &Args,
- bool EmitCodeView, bool IRInput,
- ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind &DebugInfoKind,
- DwarfFissionKind &DwarfFission) {
+static void
+renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
+ const ArgList &Args, bool IRInput, ArgStringList &CmdArgs,
+ const InputInfo &Output,
+ llvm::codegenoptions::DebugInfoKind &DebugInfoKind,
+ DwarfFissionKind &DwarfFission) {
if (Args.hasFlag(options::OPT_fdebug_info_for_profiling,
options::OPT_fno_debug_info_for_profiling, false) &&
checkDebugInfoOption(
@@ -4027,27 +4277,29 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
}
}
if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- DebugInfoKind = codegenoptions::DebugInfoConstructor;
+ DebugInfoKind = llvm::codegenoptions::DebugInfoConstructor;
// If the last option explicitly specified a debug-info level, use it.
if (checkDebugInfoOption(A, Args, D, TC) &&
A->getOption().matches(options::OPT_gN_Group)) {
- DebugInfoKind = DebugLevelToInfoKind(*A);
+ DebugInfoKind = debugLevelToInfoKind(*A);
// For -g0 or -gline-tables-only, drop -gsplit-dwarf. This gets a bit more
// complicated if you've disabled inline info in the skeleton CUs
// (SplitDWARFInlining) - then there's value in composing split-dwarf and
// line-tables-only, so let those compose naturally in that case.
- if (DebugInfoKind == codegenoptions::NoDebugInfo ||
- DebugInfoKind == codegenoptions::DebugDirectivesOnly ||
- (DebugInfoKind == codegenoptions::DebugLineTablesOnly &&
+ if (DebugInfoKind == llvm::codegenoptions::NoDebugInfo ||
+ DebugInfoKind == llvm::codegenoptions::DebugDirectivesOnly ||
+ (DebugInfoKind == llvm::codegenoptions::DebugLineTablesOnly &&
SplitDWARFInlining))
DwarfFission = DwarfFissionKind::None;
}
}
// If a debugger tuning argument appeared, remember it.
+ bool HasDebuggerTuning = false;
if (const Arg *A =
Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
+ HasDebuggerTuning = true;
if (checkDebugInfoOption(A, Args, D, TC)) {
if (A->getOption().matches(options::OPT_glldb))
DebuggerTuning = llvm::DebuggerKind::LLDB;
@@ -4061,29 +4313,23 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
}
// If a -gdwarf argument appeared, remember it.
- const Arg *GDwarfN = getDwarfNArg(Args);
bool EmitDwarf = false;
- if (GDwarfN) {
- if (checkDebugInfoOption(GDwarfN, Args, D, TC))
- EmitDwarf = true;
- else
- GDwarfN = nullptr;
- }
+ if (const Arg *A = getDwarfNArg(Args))
+ EmitDwarf = checkDebugInfoOption(A, Args, D, TC);
- if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) {
- if (checkDebugInfoOption(A, Args, D, TC))
- EmitCodeView = true;
- }
+ bool EmitCodeView = false;
+ if (const Arg *A = Args.getLastArg(options::OPT_gcodeview))
+ EmitCodeView = checkDebugInfoOption(A, Args, D, TC);
// If the user asked for debug info but did not explicitly specify -gcodeview
// or -gdwarf, ask the toolchain for the default format.
if (!EmitCodeView && !EmitDwarf &&
- DebugInfoKind != codegenoptions::NoDebugInfo) {
+ DebugInfoKind != llvm::codegenoptions::NoDebugInfo) {
switch (TC.getDefaultDebugFormat()) {
- case codegenoptions::DIF_CodeView:
+ case llvm::codegenoptions::DIF_CodeView:
EmitCodeView = true;
break;
- case codegenoptions::DIF_DWARF:
+ case llvm::codegenoptions::DIF_DWARF:
EmitDwarf = true;
break;
}
@@ -4092,31 +4338,19 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
unsigned RequestedDWARFVersion = 0; // DWARF version requested by the user
unsigned EffectiveDWARFVersion = 0; // DWARF version TC can generate. It may
// be lower than what the user wanted.
- unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args);
if (EmitDwarf) {
- // Start with the platform default DWARF version
- RequestedDWARFVersion = TC.GetDefaultDwarfVersion();
- assert(RequestedDWARFVersion &&
- "toolchain default DWARF version must be nonzero");
-
- // If the user specified a default DWARF version, that takes precedence
- // over the platform default.
- if (DefaultDWARFVersion)
- RequestedDWARFVersion = DefaultDWARFVersion;
-
- // Override with a user-specified DWARF version
- if (GDwarfN)
- if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling()))
- RequestedDWARFVersion = ExplicitVersion;
+ RequestedDWARFVersion = getDwarfVersion(TC, Args);
// Clamp effective DWARF version to the max supported by the toolchain.
EffectiveDWARFVersion =
std::min(RequestedDWARFVersion, TC.getMaxDwarfVersion());
+ } else {
+ Args.ClaimAllArgs(options::OPT_fdebug_default_version);
}
// -gline-directives-only supported only for the DWARF debug info.
if (RequestedDWARFVersion == 0 &&
- DebugInfoKind == codegenoptions::DebugDirectivesOnly)
- DebugInfoKind = codegenoptions::NoDebugInfo;
+ DebugInfoKind == llvm::codegenoptions::DebugDirectivesOnly)
+ DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
// strict DWARF is set to false by default. But for DBX, we need it to be set
// as true by default.
@@ -4144,16 +4378,19 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back("-gno-column-info");
// FIXME: Move backend command line options to the module.
- // If -gline-tables-only or -gline-directives-only is the last option it wins.
- if (const Arg *A = Args.getLastArg(options::OPT_gmodules))
- if (checkDebugInfoOption(A, Args, D, TC)) {
- if (DebugInfoKind != codegenoptions::DebugLineTablesOnly &&
- DebugInfoKind != codegenoptions::DebugDirectivesOnly) {
- DebugInfoKind = codegenoptions::DebugInfoConstructor;
+ if (Args.hasFlag(options::OPT_gmodules, options::OPT_gno_modules, false)) {
+ // If -gline-tables-only or -gline-directives-only is the last option it
+ // wins.
+ if (checkDebugInfoOption(Args.getLastArg(options::OPT_gmodules), Args, D,
+ TC)) {
+ if (DebugInfoKind != llvm::codegenoptions::DebugLineTablesOnly &&
+ DebugInfoKind != llvm::codegenoptions::DebugDirectivesOnly) {
+ DebugInfoKind = llvm::codegenoptions::DebugInfoConstructor;
CmdArgs.push_back("-dwarf-ext-refs");
CmdArgs.push_back("-fmodule-format=obj");
}
}
+ }
if (T.isOSBinFormatELF() && SplitDWARFInlining)
CmdArgs.push_back("-fsplit-dwarf-inlining");
@@ -4170,13 +4407,13 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug))
(void)checkDebugInfoOption(A, Args, D, TC);
- if (DebugInfoKind == codegenoptions::LimitedDebugInfo ||
- DebugInfoKind == codegenoptions::DebugInfoConstructor) {
+ if (DebugInfoKind == llvm::codegenoptions::LimitedDebugInfo ||
+ DebugInfoKind == llvm::codegenoptions::DebugInfoConstructor) {
if (Args.hasFlag(options::OPT_fno_eliminate_unused_debug_types,
options::OPT_feliminate_unused_debug_types, false))
- DebugInfoKind = codegenoptions::UnusedTypeInfo;
+ DebugInfoKind = llvm::codegenoptions::UnusedTypeInfo;
else if (NeedFullDebug)
- DebugInfoKind = codegenoptions::FullDebugInfo;
+ DebugInfoKind = llvm::codegenoptions::FullDebugInfo;
}
if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source,
@@ -4202,29 +4439,30 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
if (EmitCodeView) {
CmdArgs.push_back("-gcodeview");
- // Emit codeview type hashes if requested.
- if (Args.hasFlag(options::OPT_gcodeview_ghash,
- options::OPT_gno_codeview_ghash, false)) {
- CmdArgs.push_back("-gcodeview-ghash");
- }
- }
+ Args.addOptInFlag(CmdArgs, options::OPT_gcodeview_ghash,
+ options::OPT_gno_codeview_ghash);
- // 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");
+ Args.addOptOutFlag(CmdArgs, options::OPT_gcodeview_command_line,
+ options::OPT_gno_codeview_command_line);
}
+ Args.addOptOutFlag(CmdArgs, options::OPT_ginline_line_tables,
+ options::OPT_gno_inline_line_tables);
+
// When emitting remarks, we need at least debug lines in the output.
if (willEmitRemarks(Args) &&
- DebugInfoKind <= codegenoptions::DebugDirectivesOnly)
- DebugInfoKind = codegenoptions::DebugLineTablesOnly;
+ DebugInfoKind <= llvm::codegenoptions::DebugDirectivesOnly)
+ DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly;
// Adjust the debug info kind for the given toolchain.
TC.adjustDebugInfoKind(DebugInfoKind, Args);
+ // On AIX, the debugger tuning option can be omitted if it is not explicitly
+ // set.
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, EffectiveDWARFVersion,
- DebuggerTuning);
+ T.isOSAIX() && !HasDebuggerTuning
+ ? llvm::DebuggerKind::Default
+ : DebuggerTuning);
// -fdebug-macro turns on macro debug info generation.
if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro,
@@ -4247,8 +4485,8 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
? "-gpubnames"
: "-ggnu-pubnames");
const auto *SimpleTemplateNamesArg =
- Args.getLastArg(options::OPT_gsimple_template_names, options::OPT_gno_simple_template_names,
- options::OPT_gsimple_template_names_EQ);
+ Args.getLastArg(options::OPT_gsimple_template_names,
+ options::OPT_gno_simple_template_names);
bool ForwardTemplateParams = DebuggerTuning == llvm::DebuggerKind::SCE;
if (SimpleTemplateNamesArg &&
checkDebugInfoOption(SimpleTemplateNamesArg, Args, D, TC)) {
@@ -4256,25 +4494,17 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
if (Opt.matches(options::OPT_gsimple_template_names)) {
ForwardTemplateParams = true;
CmdArgs.push_back("-gsimple-template-names=simple");
- } else if (Opt.matches(options::OPT_gsimple_template_names_EQ)) {
- ForwardTemplateParams = true;
- StringRef Value = SimpleTemplateNamesArg->getValue();
- if (Value == "simple") {
- CmdArgs.push_back("-gsimple-template-names=simple");
- } else if (Value == "mangled") {
- CmdArgs.push_back("-gsimple-template-names=mangled");
- } else {
- D.Diag(diag::err_drv_unsupported_option_argument)
- << Opt.getName() << SimpleTemplateNamesArg->getValue();
- }
}
}
- if (Args.hasFlag(options::OPT_fdebug_ranges_base_address,
- options::OPT_fno_debug_ranges_base_address, false)) {
- CmdArgs.push_back("-fdebug-ranges-base-address");
+ if (const Arg *A = Args.getLastArg(options::OPT_gsrc_hash_EQ)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-gsrc-hash=" + v));
}
+ Args.addOptInFlag(CmdArgs, options::OPT_fdebug_ranges_base_address,
+ options::OPT_fno_debug_ranges_base_address);
+
// -gdwarf-aranges turns on the emission of the aranges section in the
// backend.
// Always enabled for SCE tuning.
@@ -4286,9 +4516,8 @@ 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");
+ Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame,
+ options::OPT_fno_force_dwarf_frame);
if (Args.hasFlag(options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section, false)) {
@@ -4325,6 +4554,98 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
renderDwarfFormat(D, T, Args, CmdArgs, EffectiveDWARFVersion);
RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC);
+
+ // This controls whether or not we perform JustMyCode instrumentation.
+ if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) {
+ if (TC.getTriple().isOSBinFormatELF() || D.IsCLMode()) {
+ if (DebugInfoKind >= llvm::codegenoptions::DebugInfoConstructor)
+ CmdArgs.push_back("-fjmc");
+ else if (D.IsCLMode())
+ D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "/JMC"
+ << "'/Zi', '/Z7'";
+ else
+ D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "-fjmc"
+ << "-g";
+ } else {
+ D.Diag(clang::diag::warn_drv_fjmc_for_elf_only);
+ }
+ }
+
+ // Add in -fdebug-compilation-dir if necessary.
+ const char *DebugCompilationDir =
+ addDebugCompDirArg(Args, CmdArgs, D.getVFS());
+
+ addDebugPrefixMapArg(D, TC, Args, CmdArgs);
+
+ // Add the output path to the object file for CodeView debug infos.
+ if (EmitCodeView && Output.isFilename())
+ addDebugObjectName(Args, CmdArgs, DebugCompilationDir,
+ Output.getFilename());
+}
+
+static void ProcessVSRuntimeLibrary(const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ // The /LDd option implies /MTd. The dependent lib part can be overridden,
+ // but defining _DEBUG is sticky.
+ RTOptionID = options::OPT__SLASH_MTd;
+
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
+ RTOptionID = A->getOption().getID();
+
+ if (Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
+ RTOptionID = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("static", options::OPT__SLASH_MT)
+ .Case("static_dbg", options::OPT__SLASH_MTd)
+ .Case("dll", options::OPT__SLASH_MD)
+ .Case("dll_dbg", options::OPT__SLASH_MDd)
+ .Default(options::OPT__SLASH_MT);
+ }
+
+ StringRef FlagForCRT;
+ switch (RTOptionID) {
+ case options::OPT__SLASH_MD:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ FlagForCRT = "--dependent-lib=msvcrt";
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ FlagForCRT = "--dependent-lib=msvcrtd";
+ break;
+ case options::OPT__SLASH_MT:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
+ FlagForCRT = "--dependent-lib=libcmt";
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
+ FlagForCRT = "--dependent-lib=libcmtd";
+ break;
+ default:
+ llvm_unreachable("Unexpected option ID.");
+ }
+
+ if (Args.hasArg(options::OPT_fms_omit_default_lib)) {
+ CmdArgs.push_back("-D_VC_NODEFAULTLIB");
+ } else {
+ CmdArgs.push_back(FlagForCRT.data());
+
+ // This provides POSIX compatibility (maps 'open' to '_open'), which most
+ // users want. The /Za flag to cl.exe turns this off, but it's not
+ // implemented in clang.
+ CmdArgs.push_back("--dependent-lib=oldnames");
+ }
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
@@ -4344,53 +4665,57 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// CUDA/HIP compilation may have multiple inputs (source file + results of
// device-side compilations). OpenMP device jobs also take the host IR as a
// second input. Module precompilation accepts a list of header files to
- // include as part of the module. All other jobs are expected to have exactly
- // one input.
+ // include as part of the module. API extraction accepts a list of header
+ // files whose API information is emitted in the output. All other jobs are
+ // expected to have exactly one input.
bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
bool IsCudaDevice = JA.isDeviceOffloading(Action::OFK_Cuda);
bool IsHIP = JA.isOffloading(Action::OFK_HIP);
bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP);
bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
- bool IsOpenMPHost = JA.isHostOffloading(Action::OFK_OpenMP);
- bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA);
+ bool IsExtractAPI = isa<ExtractAPIJobAction>(JA);
bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_Host));
+ bool IsHostOffloadingAction =
+ JA.isHostOffloading(Action::OFK_OpenMP) ||
+ (JA.isHostOffloading(C.getActiveOffloadKinds()) &&
+ Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false));
+
+ bool IsRDCMode =
+ Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false);
bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction);
auto LTOMode = D.getLTOMode(IsDeviceOffloadAction);
- // A header module compilation doesn't have a main input file, so invent a
- // fake one as a placeholder.
- const char *ModuleName = [&]{
- auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
- return ModuleNameArg ? ModuleNameArg->getValue() : "";
- }();
- InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName);
+ // Extract API doesn't have a main input file, so invent a fake one as a
+ // placeholder.
+ InputInfo ExtractAPIPlaceholderInput(Inputs[0].getType(), "extract-api",
+ "extract-api");
const InputInfo &Input =
- IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0];
+ IsExtractAPI ? ExtractAPIPlaceholderInput : Inputs[0];
- InputInfoList ModuleHeaderInputs;
- InputInfoList OpenMPHostInputs;
+ InputInfoList ExtractAPIInputs;
+ InputInfoList HostOffloadingInputs;
const InputInfo *CudaDeviceInput = nullptr;
const InputInfo *OpenMPDeviceInput = nullptr;
for (const InputInfo &I : Inputs) {
- if (&I == &Input) {
- // This is the primary input.
- } else if (IsHeaderModulePrecompile &&
- types::getPrecompiledType(I.getType()) == types::TY_PCH) {
- types::ID Expected = HeaderModuleInput.getType();
- if (I.getType() != Expected) {
- D.Diag(diag::err_drv_module_header_wrong_kind)
+ if (&I == &Input || I.getType() == types::TY_Nothing) {
+ // This is the primary input or contains nothing.
+ } else if (IsExtractAPI) {
+ auto ExpectedInputType = ExtractAPIPlaceholderInput.getType();
+ if (I.getType() != ExpectedInputType) {
+ D.Diag(diag::err_drv_extract_api_wrong_kind)
<< I.getFilename() << types::getTypeName(I.getType())
- << types::getTypeName(Expected);
+ << types::getTypeName(ExpectedInputType);
}
- ModuleHeaderInputs.push_back(I);
+ ExtractAPIInputs.push_back(I);
+ } else if (IsHostOffloadingAction) {
+ HostOffloadingInputs.push_back(I);
} else if ((IsCuda || IsHIP) && !CudaDeviceInput) {
CudaDeviceInput = &I;
} else if (IsOpenMPDevice && !OpenMPDeviceInput) {
OpenMPDeviceInput = &I;
- } else if (IsOpenMPHost) {
- OpenMPHostInputs.push_back(I);
} else {
llvm_unreachable("unexpectedly given multiple inputs");
}
@@ -4456,12 +4781,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(
Twine("-target-sdk-version=") +
CudaVersionToString(CTC->CudaInstallation.version())));
+ // Unsized function arguments used for variadics were introduced in
+ // CUDA-9.0. We still do not support generating code that actually uses
+ // variadic arguments yet, but we do need to allow parsing them as
+ // recent CUDA headers rely on that.
+ // https://github.com/llvm/llvm-project/issues/58410
+ if (CTC->CudaInstallation.version() >= CudaVersion::CUDA_90)
+ CmdArgs.push_back("-fcuda-allow-variadic-functions");
}
}
CmdArgs.push_back("-aux-triple");
CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
+
+ if (JA.isDeviceOffloading(Action::OFK_HIP) &&
+ getToolChain().getTriple().isAMDGPU()) {
+ // Device side compilation printf
+ if (Args.getLastArg(options::OPT_mprintf_kind_EQ)) {
+ CmdArgs.push_back(Args.MakeArgString(
+ "-mprintf-kind=" +
+ Args.getLastArgValue(options::OPT_mprintf_kind_EQ)));
+ // Force compiler error on invalid conversion specifiers
+ CmdArgs.push_back(
+ Args.MakeArgString("-Werror=format-invalid-specifier"));
+ }
+ }
}
+ // Unconditionally claim the printf option now to avoid unused diagnostic.
+ if (const Arg *PF = Args.getLastArg(options::OPT_mprintf_kind_EQ))
+ PF->claim();
+
if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) {
CmdArgs.push_back("-fsycl-is-device");
@@ -4506,6 +4855,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Select the appropriate action.
RewriteKind rewriteKind = RK_None;
+ bool UnifiedLTO = false;
+ if (IsUsingLTO) {
+ UnifiedLTO = Args.hasFlag(options::OPT_funified_lto,
+ options::OPT_fno_unified_lto, Triple.isPS());
+ if (UnifiedLTO)
+ CmdArgs.push_back("-funified-lto");
+ }
+
// If CollectArgsForIntegratedAssembler() isn't called below, claim the args
// it claims when not running an assembler. Otherwise, clang would emit
// "argument unused" warnings for assembler flags when e.g. adding "-E" to
@@ -4534,6 +4891,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.ClaimAllArgs(options::OPT_Wa_COMMA);
Args.ClaimAllArgs(options::OPT_Xassembler);
+ Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ);
}
if (isa<AnalyzeJobAction>(JA)) {
@@ -4549,6 +4907,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_rewrite_objc) &&
!Args.hasArg(options::OPT_g_Group))
CmdArgs.push_back("-P");
+ else if (JA.getType() == types::TY_PP_CXXHeaderUnit)
+ CmdArgs.push_back("-fdirectives-only");
}
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
@@ -4561,13 +4921,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (JA.getType() == types::TY_Nothing)
CmdArgs.push_back("-fsyntax-only");
else if (JA.getType() == types::TY_ModuleFile)
- CmdArgs.push_back(IsHeaderModulePrecompile
- ? "-emit-header-module"
- : "-emit-module-interface");
+ CmdArgs.push_back("-emit-module-interface");
+ else if (JA.getType() == types::TY_HeaderUnit)
+ CmdArgs.push_back("-emit-header-unit");
else
CmdArgs.push_back("-emit-pch");
} else if (isa<VerifyPCHJobAction>(JA)) {
CmdArgs.push_back("-verify-pch");
+ } else if (isa<ExtractAPIJobAction>(JA)) {
+ assert(JA.getType() == types::TY_API_INFO &&
+ "Extract API actions must generate a API information.");
+ CmdArgs.push_back("-extract-api");
+ if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ))
+ ProductNameArg->render(Args, CmdArgs);
+ if (Arg *ExtractAPIIgnoresFileArg =
+ Args.getLastArg(options::OPT_extract_api_ignores_EQ))
+ ExtractAPIIgnoresFileArg->render(Args, CmdArgs);
} else {
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
"Invalid action for clang tool.");
@@ -4606,8 +4975,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_Fragile;
- } else if (JA.getType() == types::TY_API_INFO) {
- CmdArgs.push_back("-extract-api");
} else {
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
}
@@ -4619,29 +4986,48 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (JA.getType() == types::TY_LLVM_BC)
CmdArgs.push_back("-emit-llvm-uselists");
- if (IsUsingLTO && !Args.hasArg(options::OPT_fopenmp_new_driver)) {
- // Only AMDGPU supports device-side LTO.
- if (IsDeviceOffloadAction && !Triple.isAMDGPU()) {
+ if (IsUsingLTO) {
+ if (IsDeviceOffloadAction && !JA.isDeviceOffloading(Action::OFK_OpenMP) &&
+ !Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false) &&
+ !Triple.isAMDGPU()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Args.getLastArg(options::OPT_foffload_lto,
options::OPT_foffload_lto_EQ)
->getAsString(Args)
<< Triple.getTriple();
+ } else if (Triple.isNVPTX() && !IsRDCMode &&
+ JA.isDeviceOffloading(Action::OFK_Cuda)) {
+ D.Diag(diag::err_drv_unsupported_opt_for_language_mode)
+ << Args.getLastArg(options::OPT_foffload_lto,
+ options::OPT_foffload_lto_EQ)
+ ->getAsString(Args)
+ << "-fno-gpu-rdc";
} else {
assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin);
CmdArgs.push_back(Args.MakeArgString(
Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full")));
- CmdArgs.push_back("-flto-unit");
+ // PS4 uses the legacy LTO API, which does not support some of the
+ // features enabled by -flto-unit.
+ if (!RawTriple.isPS4() ||
+ (D.getLTOMode() == LTOK_Full) || !UnifiedLTO)
+ CmdArgs.push_back("-flto-unit");
}
}
}
+ Args.AddLastArg(CmdArgs, options::OPT_dumpdir);
+
if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
if (!types::isLLVMIR(Input.getType()))
D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args);
Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
}
+ if (Triple.isPPC())
+ Args.addOptInFlag(CmdArgs, options::OPT_mregnames,
+ options::OPT_mno_regnames);
+
if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ))
Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ);
@@ -4655,6 +5041,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
!MemProfArg->getOption().matches(options::OPT_fno_memory_profile))
MemProfArg->render(Args, CmdArgs);
+ if (auto *MemProfUseArg =
+ Args.getLastArg(options::OPT_fmemory_profile_use_EQ)) {
+ if (MemProfArg)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << MemProfUseArg->getAsString(Args) << MemProfArg->getAsString(Args);
+ if (auto *PGOInstrArg = Args.getLastArg(options::OPT_fprofile_generate,
+ options::OPT_fprofile_generate_EQ))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << MemProfUseArg->getAsString(Args) << PGOInstrArg->getAsString(Args);
+ MemProfUseArg->render(Args, CmdArgs);
+ }
+
// Embed-bitcode option.
// Only white-listed flags below are allowed to be embedded.
if (C.getDriver().embedBitcodeInObject() && !IsUsingLTO &&
@@ -4717,9 +5115,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling();
// Render the CodeGen options that need to be passed.
- if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
- options::OPT_fno_optimize_sibling_calls))
- CmdArgs.push_back("-mdisable-tail-calls");
+ Args.addOptOutFlag(CmdArgs, options::OPT_foptimize_sibling_calls,
+ options::OPT_fno_optimize_sibling_calls);
RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args,
CmdArgs, JA);
@@ -4769,7 +5166,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(),
- CmdArgs, Inputs, Output));
+ CmdArgs, Inputs, Output, D.getPrependArg()));
return;
}
@@ -4789,9 +5186,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const bool IsAssertBuild = true;
#endif
- // Disable the verification pass in -asserts builds.
- if (!IsAssertBuild)
+ // Disable the verification pass in asserts builds unless otherwise specified.
+ if (Args.hasFlag(options::OPT_fno_verify_intermediate_code,
+ options::OPT_fverify_intermediate_code, !IsAssertBuild)) {
CmdArgs.push_back("-disable-llvm-verifier");
+ }
// Discard value names in assert builds unless otherwise specified.
if (Args.hasFlag(options::OPT_fdiscard_value_names,
@@ -4829,13 +5228,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Since we can't access frontend flags through hasArg, let's manually iterate
// through them.
bool FoundAnalyzerConfig = false;
- for (auto Arg : Args.filtered(options::OPT_Xclang))
+ for (auto *Arg : Args.filtered(options::OPT_Xclang))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
}
if (!FoundAnalyzerConfig)
- for (auto Arg : Args.filtered(options::OPT_Xanalyzer))
+ for (auto *Arg : Args.filtered(options::OPT_Xanalyzer))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
@@ -4868,10 +5267,58 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Twine(std::min(Value, 65536u))));
}
+ if (Triple.isOSzOS()) {
+ // On z/OS some of the system header feature macros need to
+ // be defined to enable most cross platform projects to build
+ // successfully. Ths include the libc++ library. A
+ // complicating factor is that users can define these
+ // macros to the same or different values. We need to add
+ // the definition for these macros to the compilation command
+ // if the user hasn't already defined them.
+
+ auto findMacroDefinition = [&](const std::string &Macro) {
+ auto MacroDefs = Args.getAllArgValues(options::OPT_D);
+ return llvm::any_of(MacroDefs, [&](const std::string &M) {
+ return M == Macro || M.find(Macro + '=') != std::string::npos;
+ });
+ };
+
+ // _UNIX03_WITHDRAWN is required for libcxx & porting.
+ if (!findMacroDefinition("_UNIX03_WITHDRAWN"))
+ CmdArgs.push_back("-D_UNIX03_WITHDRAWN");
+ // _OPEN_DEFAULT is required for XL compat
+ if (!findMacroDefinition("_OPEN_DEFAULT"))
+ CmdArgs.push_back("-D_OPEN_DEFAULT");
+ if (D.CCCIsCXX() || types::isCXX(Input.getType())) {
+ // _XOPEN_SOURCE=600 is required for libcxx.
+ if (!findMacroDefinition("_XOPEN_SOURCE"))
+ CmdArgs.push_back("-D_XOPEN_SOURCE=600");
+ }
+ }
+
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args);
+ Arg *LastPICDataRelArg =
+ Args.getLastArg(options::OPT_mno_pic_data_is_text_relative,
+ options::OPT_mpic_data_is_text_relative);
+ bool NoPICDataIsTextRelative = false;
+ if (LastPICDataRelArg) {
+ if (LastPICDataRelArg->getOption().matches(
+ options::OPT_mno_pic_data_is_text_relative)) {
+ NoPICDataIsTextRelative = true;
+ if (!PICLevel)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-mno-pic-data-is-text-relative"
+ << "-fpic/-fpie";
+ }
+ if (!Triple.isSystemZ())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << (NoPICDataIsTextRelative ? "-mno-pic-data-is-text-relative"
+ : "-mpic-data-is-text-relative")
+ << RawTriple.str();
+ }
bool IsROPI = RelocationModel == llvm::Reloc::ROPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI;
@@ -4900,6 +5347,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
if (IsPIE)
CmdArgs.push_back("-pic-is-pie");
+ if (NoPICDataIsTextRelative)
+ CmdArgs.push_back("-mcmodel=medium");
}
if (RelocationModel == llvm::Reloc::ROPI ||
@@ -4956,37 +5405,41 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- Args.AddLastArg(CmdArgs, options::OPT_fveclib);
+ if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
+ StringRef Name = A->getValue();
+ if (Name == "SVML") {
+ if (Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ } else if (Name == "LIBMVEC-X86") {
+ if (Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ } else if (Name == "SLEEF" || Name == "ArmPL") {
+ if (Triple.getArch() != llvm::Triple::aarch64 &&
+ Triple.getArch() != llvm::Triple::aarch64_be)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ }
+ A->render(Args, CmdArgs);
+ }
if (Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants, false))
CmdArgs.push_back("-fmerge-all-constants");
- if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks,
- options::OPT_fdelete_null_pointer_checks, false))
- CmdArgs.push_back("-fno-delete-null-pointer-checks");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fdelete_null_pointer_checks,
+ options::OPT_fno_delete_null_pointer_checks);
// LLVM Code Generator Options.
- for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file_EQ)) {
- StringRef Map = A->getValue();
- if (!llvm::sys::fs::exists(Map)) {
- D.Diag(diag::err_drv_no_such_file) << Map;
- } else {
- A->render(Args, CmdArgs);
- A->claim();
- }
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_vec_extabi,
- options::OPT_mabi_EQ_vec_default)) {
- if (!Triple.isOSAIX())
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_quadword_atomics)) {
+ if (!Triple.isOSAIX() || Triple.isPPC32())
D.Diag(diag::err_drv_unsupported_opt_for_target)
- << A->getSpelling() << RawTriple.str();
- if (A->getOption().getID() == options::OPT_mabi_EQ_vec_extabi)
- CmdArgs.push_back("-mabi=vec-extabi");
- else
- CmdArgs.push_back("-mabi=vec-default");
+ << A->getSpelling() << RawTriple.str();
+ CmdArgs.push_back("-mabi=quadword-atomics");
}
if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) {
@@ -4998,27 +5451,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
- StringRef v = A->getValue();
- // FIXME: Validate the argument here so we don't produce meaningless errors
- // about -fwarn-stack-size=.
- if (v.empty())
- D.Diag(diag::err_drv_missing_argument) << A->getSpelling() << 1;
+ StringRef V = A->getValue(), V1 = V;
+ unsigned Size;
+ if (V1.consumeInteger(10, Size) || !V1.empty())
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << V << A->getOption().getName();
else
- CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + v));
- A->claim();
+ CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + V));
}
- if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables,
- true))
- CmdArgs.push_back("-fno-jump-tables");
-
- if (Args.hasFlag(options::OPT_fprofile_sample_accurate,
- options::OPT_fno_profile_sample_accurate, false))
- CmdArgs.push_back("-fprofile-sample-accurate");
-
- if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
- options::OPT_fno_preserve_as_comments, true))
- CmdArgs.push_back("-fno-preserve-as-comments");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fjump_tables,
+ options::OPT_fno_jump_tables);
+ Args.addOptInFlag(CmdArgs, options::OPT_fprofile_sample_accurate,
+ options::OPT_fno_profile_sample_accurate);
+ Args.addOptOutFlag(CmdArgs, options::OPT_fpreserve_as_comments,
+ options::OPT_fno_preserve_as_comments);
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
CmdArgs.push_back("-mregparm");
@@ -5051,8 +5498,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
- CmdArgs.push_back("-fdefault-calling-conv=stdcall");
+ if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) {
+ if (Triple.getArch() == llvm::Triple::m68k)
+ CmdArgs.push_back("-fdefault-calling-conv=rtdcall");
+ else
+ CmdArgs.push_back("-fdefault-calling-conv=stdcall");
+ }
if (Args.hasArg(options::OPT_fenable_matrix)) {
// enable-matrix is needed by both the LangOpts and by LLVM.
@@ -5078,9 +5529,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
assert(FPKeepKindStr && "unknown FramePointerKind");
CmdArgs.push_back(FPKeepKindStr);
- if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
- options::OPT_fno_zero_initialized_in_bss, true))
- CmdArgs.push_back("-fno-zero-initialized-in-bss");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fzero_initialized_in_bss,
+ options::OPT_fno_zero_initialized_in_bss);
bool OFastEnabled = isOptimizationLevelFast(Args);
// If -Ofast is the optimization level, then -fstrict-aliasing should be
@@ -5094,31 +5544,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_strict_aliasing, TBAAOnByDefault))
CmdArgs.push_back("-relaxed-aliasing");
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
- options::OPT_fno_struct_path_tbaa))
+ options::OPT_fno_struct_path_tbaa, true))
CmdArgs.push_back("-no-struct-path-tbaa");
- if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
- false))
- CmdArgs.push_back("-fstrict-enums");
- if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
- true))
- CmdArgs.push_back("-fno-strict-return");
- if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
- options::OPT_fno_allow_editor_placeholders, false))
- CmdArgs.push_back("-fallow-editor-placeholders");
- if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
- options::OPT_fno_strict_vtable_pointers,
- false))
- CmdArgs.push_back("-fstrict-vtable-pointers");
- if (Args.hasFlag(options::OPT_fforce_emit_vtables,
- options::OPT_fno_force_emit_vtables,
- false))
- CmdArgs.push_back("-fforce-emit-vtables");
- if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
- options::OPT_fno_optimize_sibling_calls))
- CmdArgs.push_back("-mdisable-tail-calls");
- if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls,
- options::OPT_fescaping_block_tail_calls, false))
- CmdArgs.push_back("-fno-escaping-block-tail-calls");
+ Args.addOptInFlag(CmdArgs, options::OPT_fstrict_enums,
+ options::OPT_fno_strict_enums);
+ Args.addOptOutFlag(CmdArgs, options::OPT_fstrict_return,
+ options::OPT_fno_strict_return);
+ Args.addOptInFlag(CmdArgs, options::OPT_fallow_editor_placeholders,
+ options::OPT_fno_allow_editor_placeholders);
+ Args.addOptInFlag(CmdArgs, options::OPT_fstrict_vtable_pointers,
+ options::OPT_fno_strict_vtable_pointers);
+ Args.addOptInFlag(CmdArgs, options::OPT_fforce_emit_vtables,
+ options::OPT_fno_force_emit_vtables);
+ Args.addOptOutFlag(CmdArgs, options::OPT_foptimize_sibling_calls,
+ options::OPT_fno_optimize_sibling_calls);
+ Args.addOptOutFlag(CmdArgs, options::OPT_fescaping_block_tail_calls,
+ options::OPT_fno_escaping_block_tail_calls);
Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses,
options::OPT_fno_fine_grained_bitfield_accesses);
@@ -5126,10 +5567,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
options::OPT_fno_experimental_relative_cxx_abi_vtables);
+ Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
+ options::OPT_fno_experimental_omit_vtable_rtti);
+
// Handle segmented stacks.
- if (Args.hasFlag(options::OPT_fsplit_stack, options::OPT_fno_split_stack,
- false))
- CmdArgs.push_back("-fsplit-stack");
+ Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
+ options::OPT_fno_split_stack);
// -fprotect-parens=0 is default.
if (Args.hasFlag(options::OPT_fprotect_parens,
@@ -5209,8 +5652,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Enable -mconstructor-aliases except on darwin, where we have to work around
- // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where
- // aliases aren't supported.
+ // a linker bug (see https://openradar.appspot.com/7198997), and CUDA device
+ // code, where aliases aren't supported.
if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX())
CmdArgs.push_back("-mconstructor-aliases");
@@ -5224,14 +5667,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mms-bitfields");
}
+ if (Triple.isWindowsGNUEnvironment()) {
+ Args.addOptOutFlag(CmdArgs, options::OPT_fauto_import,
+ options::OPT_fno_auto_import);
+ }
+
+ if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile,
+ Triple.isX86() && D.IsCLMode()))
+ CmdArgs.push_back("-fms-volatile");
+
// Non-PIC code defaults to -fdirect-access-external-data while PIC code
// defaults to -fno-direct-access-external-data. Pass the option if different
// from the default.
if (Arg *A = Args.getLastArg(options::OPT_fdirect_access_external_data,
- options::OPT_fno_direct_access_external_data))
+ options::OPT_fno_direct_access_external_data)) {
if (A->getOption().matches(options::OPT_fdirect_access_external_data) !=
(PICLevel == 0))
A->render(Args, CmdArgs);
+ } else if (PICLevel == 0 && Triple.isLoongArch()) {
+ // Some targets default to -fno-direct-access-external-data even for
+ // -fno-pic.
+ CmdArgs.push_back("-fno-direct-access-external-data");
+ }
if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) {
CmdArgs.push_back("-fno-plt");
@@ -5246,21 +5703,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Freestanding)
CmdArgs.push_back("-ffreestanding");
+ Args.AddLastArg(CmdArgs, options::OPT_fno_knr_functions);
+
// This is a coarse approximation of what llvm-gcc actually does, both
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
// complicated ways.
auto SanitizeArgs = TC.getSanitizerArgs(Args);
+
+ bool IsAsyncUnwindTablesDefault =
+ TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Asynchronous;
+ bool IsSyncUnwindTablesDefault =
+ TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Synchronous;
+
bool AsyncUnwindTables = Args.hasFlag(
options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
- (TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) &&
+ (IsAsyncUnwindTablesDefault || SanitizeArgs.needsUnwindTables()) &&
!Freestanding);
- bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables,
- options::OPT_fno_unwind_tables, false);
+ bool UnwindTables =
+ Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
+ IsSyncUnwindTablesDefault && !Freestanding);
if (AsyncUnwindTables)
CmdArgs.push_back("-funwind-tables=2");
else if (UnwindTables)
- CmdArgs.push_back("-funwind-tables=1");
+ CmdArgs.push_back("-funwind-tables=1");
// Prepare `-aux-target-cpu` and `-aux-target-feature` unless
// `--gpu-use-aux-triple-only` is specified.
@@ -5280,20 +5746,78 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());
- // FIXME: Handle -mtune=.
- (void)Args.hasArg(options::OPT_mtune_EQ);
-
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
StringRef CM = A->getValue();
- if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" ||
- CM == "tiny") {
- if (Triple.isOSAIX() && CM == "medium")
- CmdArgs.push_back("-mcmodel=large");
- else
- A->render(Args, CmdArgs);
+ bool Ok = false;
+ if (Triple.isOSAIX() && CM == "medium")
+ CM = "large";
+ if (Triple.isAArch64(64)) {
+ Ok = CM == "tiny" || CM == "small" || CM == "large";
+ if (CM == "large" && RelocationModel != llvm::Reloc::Static)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-fno-pic";
+ } else if (Triple.isLoongArch()) {
+ if (CM == "extreme" &&
+ Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-fplt";
+ Ok = CM == "normal" || CM == "medium" || CM == "extreme";
+ // Convert to LLVM recognizable names.
+ if (Ok)
+ CM = llvm::StringSwitch<StringRef>(CM)
+ .Case("normal", "small")
+ .Case("extreme", "large")
+ .Default(CM);
+ } else if (Triple.isPPC64() || Triple.isOSAIX()) {
+ Ok = CM == "small" || CM == "medium" || CM == "large";
+ } else if (Triple.isRISCV()) {
+ if (CM == "medlow")
+ CM = "small";
+ else if (CM == "medany")
+ CM = "medium";
+ Ok = CM == "small" || CM == "medium";
+ } else if (Triple.getArch() == llvm::Triple::x86_64) {
+ Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"},
+ CM);
+ } else if (Triple.isNVPTX() || Triple.isAMDGPU()) {
+ // NVPTX/AMDGPU does not care about the code model and will accept
+ // whatever works for the host.
+ Ok = true;
+ } else if (Triple.isSPARC64()) {
+ if (CM == "medlow")
+ CM = "small";
+ else if (CM == "medmid")
+ CM = "medium";
+ else if (CM == "medany")
+ CM = "large";
+ Ok = CM == "small" || CM == "medium" || CM == "large";
+ }
+ if (Ok) {
+ CmdArgs.push_back(Args.MakeArgString("-mcmodel=" + CM));
} else {
- D.Diag(diag::err_drv_invalid_argument_to_option)
- << CM << A->getOption().getName();
+ D.Diag(diag::err_drv_unsupported_option_argument_for_target)
+ << A->getSpelling() << CM << TripleStr;
+ }
+ }
+
+ if (Triple.getArch() == llvm::Triple::x86_64) {
+ bool IsMediumCM = false;
+ bool IsLargeCM = false;
+ if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+ IsMediumCM = StringRef(A->getValue()) == "medium";
+ IsLargeCM = StringRef(A->getValue()) == "large";
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
+ if (!IsMediumCM && !IsLargeCM) {
+ D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model)
+ << A->getOption().getRenderName();
+ } else {
+ A->render(Args, CmdArgs);
+ }
+ } else if (IsMediumCM) {
+ CmdArgs.push_back("-mlarge-data-threshold=65536");
+ } else if (IsLargeCM) {
+ CmdArgs.push_back("-mlarge-data-threshold=0");
}
}
@@ -5310,6 +5834,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ);
}
+ if (isTLSDESCEnabled(TC, Args))
+ CmdArgs.push_back("-enable-tlsdesc");
+
// Add the target cpu
std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false);
if (!CPU.empty()) {
@@ -5319,41 +5846,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs);
- // FIXME: For now we want to demote any errors to warnings, when they have
- // been raised for asking the wrong question of scalable vectors, such as
- // asking for the fixed number of elements. This may happen because code that
- // is not yet ported to work for scalable vectors uses the wrong interfaces,
- // whereas the behaviour is actually correct. Emitting a warning helps bring
- // up scalable vector support in an incremental way. When scalable vector
- // support is stable enough, all uses of wrong interfaces should be considered
- // as errors, but until then, we can live with a warning being emitted by the
- // compiler. This way, Clang can be used to compile code with scalable vectors
- // and identify possible issues.
- if (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
- isa<BackendJobAction>(JA)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-treat-scalable-fixed-error-as-warning");
- }
-
- // These two are potentially updated by AddClangCLArgs.
- codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
- bool EmitCodeView = false;
-
// Add clang-cl arguments.
types::ID InputType = Input.getType();
if (D.IsCLMode())
- AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);
+ AddClangCLArgs(Args, InputType, CmdArgs);
+ llvm::codegenoptions::DebugInfoKind DebugInfoKind =
+ llvm::codegenoptions::NoDebugInfo;
DwarfFissionKind DwarfFission = DwarfFissionKind::None;
- renderDebugOptions(TC, D, RawTriple, Args, EmitCodeView,
- types::isLLVMIR(InputType), CmdArgs, DebugInfoKind,
- DwarfFission);
+ renderDebugOptions(TC, D, RawTriple, Args, types::isLLVMIR(InputType),
+ CmdArgs, Output, DebugInfoKind, DwarfFission);
// Add the split debug info name to the command lines here so we
// can propagate it to the backend.
bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) &&
(TC.getTriple().isOSBinFormatELF() ||
- TC.getTriple().isOSBinFormatWasm()) &&
+ TC.getTriple().isOSBinFormatWasm() ||
+ TC.getTriple().isOSBinFormatCOFF()) &&
(isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
isa<BackendJobAction>(JA));
if (SplitDWARF) {
@@ -5401,12 +5910,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes);
- if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
+ if (D.CCPrintHeadersFormat && !D.CCGenDiagnostics) {
CmdArgs.push_back("-header-include-file");
CmdArgs.push_back(!D.CCPrintHeadersFilename.empty()
? D.CCPrintHeadersFilename.c_str()
: "-");
CmdArgs.push_back("-sys-header-deps");
+ CmdArgs.push_back(Args.MakeArgString(
+ "-header-include-format=" +
+ std::string(headerIncludeFormatKindToString(D.CCPrintHeadersFormat))));
+ CmdArgs.push_back(
+ Args.MakeArgString("-header-include-filtering=" +
+ std::string(headerIncludeFilteringKindToString(
+ D.CCPrintHeadersFiltering))));
}
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
@@ -5442,7 +5958,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef Val = A->getValue();
if (Triple.isX86() && Triple.isOSBinFormatELF()) {
if (Val != "all" && Val != "labels" && Val != "none" &&
- !Val.startswith("list="))
+ !Val.starts_with("list="))
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else
@@ -5464,27 +5980,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fdata-sections");
}
- if (!Args.hasFlag(options::OPT_funique_section_names,
- options::OPT_fno_unique_section_names, true))
- CmdArgs.push_back("-fno-unique-section-names");
-
- if (Args.hasFlag(options::OPT_funique_internal_linkage_names,
- options::OPT_fno_unique_internal_linkage_names, false))
- CmdArgs.push_back("-funique-internal-linkage-names");
-
- if (Args.hasFlag(options::OPT_funique_basic_block_section_names,
- options::OPT_fno_unique_basic_block_section_names, false))
- CmdArgs.push_back("-funique-basic-block-section-names");
+ Args.addOptOutFlag(CmdArgs, options::OPT_funique_section_names,
+ options::OPT_fno_unique_section_names);
+ Args.addOptInFlag(CmdArgs, options::OPT_funique_internal_linkage_names,
+ options::OPT_fno_unique_internal_linkage_names);
+ Args.addOptInFlag(CmdArgs, options::OPT_funique_basic_block_section_names,
+ options::OPT_fno_unique_basic_block_section_names);
+ Args.addOptInFlag(CmdArgs, options::OPT_fconvergent_functions,
+ options::OPT_fno_convergent_functions);
if (Arg *A = Args.getLastArg(options::OPT_fsplit_machine_functions,
options::OPT_fno_split_machine_functions)) {
- // This codegen pass is only available on x86-elf targets.
- if (Triple.isX86() && Triple.isOSBinFormatELF()) {
- if (A->getOption().matches(options::OPT_fsplit_machine_functions))
+ if (!A->getOption().matches(options::OPT_fno_split_machine_functions)) {
+ // This codegen pass is only available on x86 and AArch64 ELF targets.
+ if ((Triple.isX86() || Triple.isAArch64()) && Triple.isOSBinFormatELF())
A->render(Args, CmdArgs);
- } else {
- D.Diag(diag::err_drv_unsupported_opt_for_target)
- << A->getAsString(Args) << TripleStr;
+ else
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
}
}
@@ -5496,15 +6009,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// for sampling, overhead of call arc collection is way too high and there's
// no way to collect the output.
if (!Triple.isNVPTX() && !Triple.isAMDGCN())
- addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs);
+ addPGOAndCoverageFlags(TC, C, JA, Output, Args, SanitizeArgs, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);
- // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled.
- if (RawTriple.isPS4CPU() &&
+ if (getLastProfileSampleUseArg(Args) &&
+ Args.hasArg(options::OPT_fsample_profile_use_profi)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-sample-profile-use-profi");
+ }
+
+ // Add runtime flag for PS4/PS5 when PGO, coverage, or sanitizers are enabled.
+ if (RawTriple.isPS() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- PS4cpu::addProfileRTArgs(TC, Args, CmdArgs);
- PS4cpu::addSanitizerArgs(TC, Args, CmdArgs);
+ PScpu::addProfileRTArgs(TC, Args, CmdArgs);
+ PScpu::addSanitizerArgs(TC, Args, CmdArgs);
}
// Pass options for controlling the default header search paths.
@@ -5586,15 +6105,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
}
+ Args.AddAllArgs(CmdArgs, options::OPT_Wsystem_headers_in_module_EQ);
+
if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
CmdArgs.push_back("-pedantic");
Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
Args.AddLastArg(CmdArgs, options::OPT_w);
- // Fixed point flags
- if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point,
- /*Default=*/false))
- Args.AddLastArg(CmdArgs, options::OPT_ffixed_point);
+ Args.addOptInFlag(CmdArgs, options::OPT_ffixed_point,
+ options::OPT_fno_fixed_point);
if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ))
A->render(Args, CmdArgs);
@@ -5602,6 +6121,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
options::OPT_fno_experimental_relative_cxx_abi_vtables);
+ Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
+ options::OPT_fno_experimental_omit_vtable_rtti);
+
if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ))
A->render(Args, CmdArgs);
@@ -5647,11 +6169,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
options::OPT_fno_trigraphs);
-
- // HIP headers has minimum C++ standard requirements. Therefore set the
- // default language standard.
- if (IsHIP)
- CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11");
}
// GCC's behavior for -Wwrite-strings is a bit strange:
@@ -5694,32 +6211,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!ShouldEnableAutolink(Args, TC, JA))
CmdArgs.push_back("-fno-autolink");
- // Add in -fdebug-compilation-dir if necessary.
- const char *DebugCompilationDir =
- addDebugCompDirArg(Args, CmdArgs, D.getVFS());
-
- addDebugPrefixMapArg(D, Args, CmdArgs);
-
- if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
- options::OPT_ftemplate_depth_EQ)) {
- CmdArgs.push_back("-ftemplate-depth");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
- CmdArgs.push_back("-foperator-arrow-depth");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
- CmdArgs.push_back("-fconstexpr-depth");
- CmdArgs.push_back(A->getValue());
- }
+ Args.AddLastArg(CmdArgs, options::OPT_ftemplate_depth_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
- if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
- CmdArgs.push_back("-fconstexpr-steps");
- CmdArgs.push_back(A->getValue());
- }
+ Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))
CmdArgs.push_back("-fexperimental-new-constant-interpreter");
@@ -5746,7 +6243,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
"standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1",
};
- if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs))
+ if (!llvm::is_contained(kCFABIs, StringRef(A->getValue())))
D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue();
else
A->render(Args, CmdArgs);
@@ -5762,9 +6259,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
- if (Args.hasFlag(options::OPT_fstack_size_section,
- options::OPT_fno_stack_size_section, RawTriple.isPS4()))
- CmdArgs.push_back("-fstack-size-section");
+ Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section,
+ options::OPT_fno_stack_size_section);
if (Args.hasArg(options::OPT_fstack_usage)) {
CmdArgs.push_back("-stack-usage-file");
@@ -5784,25 +6280,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("19");
- if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
- CmdArgs.push_back("-fmacro-backtrace-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
- CmdArgs.push_back("-ftemplate-backtrace-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
- CmdArgs.push_back("-fconstexpr-backtrace-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
- CmdArgs.push_back("-fspell-checking-limit");
- CmdArgs.push_back(A->getValue());
- }
+ Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_backtrace_limit_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fmacro_backtrace_limit_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_ftemplate_backtrace_limit_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fspell_checking_limit_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fcaret_diagnostics_max_lines_EQ);
// Pass -fmessage-length=.
unsigned MessageLength = 0;
@@ -5820,28 +6302,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(
Args.MakeArgString("-fmessage-length=" + Twine(MessageLength)));
+ if (Arg *A = Args.getLastArg(options::OPT_frandomize_layout_seed_EQ))
+ CmdArgs.push_back(
+ Args.MakeArgString("-frandomize-layout-seed=" + Twine(A->getValue(0))));
+
+ if (Arg *A = Args.getLastArg(options::OPT_frandomize_layout_seed_file_EQ))
+ CmdArgs.push_back(Args.MakeArgString("-frandomize-layout-seed-file=" +
+ Twine(A->getValue(0))));
+
// -fvisibility= and -fvisibility-ms-compat are of a piece.
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue());
+ A->render(Args, CmdArgs);
} else {
assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("hidden");
- CmdArgs.push_back("-ftype-visibility");
- CmdArgs.push_back("default");
+ CmdArgs.push_back("-fvisibility=hidden");
+ CmdArgs.push_back("-ftype-visibility=default");
}
} else if (IsOpenMPDevice) {
// When compiling for the OpenMP device we want protected visibility by
- // default. This prevents the device from accidenally preempting code on the
- // host, makes the system more robust, and improves performance.
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("protected");
+ // default. This prevents the device from accidentally preempting code on
+ // the host, makes the system more robust, and improves performance.
+ CmdArgs.push_back("-fvisibility=protected");
}
- if (!RawTriple.isPS4())
+ // PS4/PS5 process these options in addClangTargetOptions.
+ if (!RawTriple.isPS()) {
if (const Arg *A =
Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
options::OPT_fno_visibility_from_dllstorageclass)) {
@@ -5855,23 +6342,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fvisibility_externs_nodllstorageclass_EQ);
}
}
-
- if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) {
- if (Triple.isOSAIX())
- CmdArgs.push_back("-mignore-xcoff-visibility");
- else
- D.Diag(diag::err_drv_unsupported_opt_for_target)
- << A->getAsString(Args) << TripleStr;
}
-
if (Args.hasFlag(options::OPT_fvisibility_inlines_hidden,
options::OPT_fno_visibility_inlines_hidden, false))
CmdArgs.push_back("-fvisibility-inlines-hidden");
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var,
options::OPT_fno_visibility_inlines_hidden_static_local_var);
- Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
+
+ // -fvisibility-global-new-delete-hidden is a deprecated spelling of
+ // -fvisibility-global-new-delete=force-hidden.
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden)) {
+ D.Diag(diag::warn_drv_deprecated_arg)
+ << A->getAsString(Args)
+ << "-fvisibility-global-new-delete=force-hidden";
+ }
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fvisibility_global_new_delete_EQ,
+ options::OPT_fvisibility_global_new_delete_hidden)) {
+ if (A->getOption().matches(options::OPT_fvisibility_global_new_delete_EQ)) {
+ A->render(Args, CmdArgs);
+ } else {
+ assert(A->getOption().matches(
+ options::OPT_fvisibility_global_new_delete_hidden));
+ CmdArgs.push_back("-fvisibility-global-new-delete=force-hidden");
+ }
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
if (Args.hasFlag(options::OPT_fnew_infallible,
@@ -5886,8 +6386,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs);
- Args.AddLastArg(CmdArgs, options::OPT_femulated_tls,
- options::OPT_fno_emulated_tls);
+ Args.AddLastArg(CmdArgs, options::OPT_fzero_call_used_regs_EQ);
+
+ if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
+ Triple.hasDefaultEmulatedTLS()))
+ CmdArgs.push_back("-femulated-tls");
+
+ Args.addOptInFlag(CmdArgs, options::OPT_fcheck_new,
+ options::OPT_fno_check_new);
+
+ if (Arg *A = Args.getLastArg(options::OPT_fzero_call_used_regs_EQ)) {
+ // FIXME: There's no reason for this to be restricted to X86. The backend
+ // code needs to be changed to include the appropriate function calls
+ // automatically.
+ if (!Triple.isX86() && !Triple.isAArch64())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ }
// AltiVec-like language extensions aren't relevant for assembling.
if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm)
@@ -5936,26 +6451,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_openmp_cuda_mode, /*Default=*/false))
CmdArgs.push_back("-fopenmp-cuda-mode");
- // When in OpenMP offloading mode, enable or disable the new device
- // runtime.
- if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime,
- options::OPT_fno_openmp_target_new_runtime,
- /*Default=*/true))
- CmdArgs.push_back("-fopenmp-target-new-runtime");
-
// When in OpenMP offloading mode, enable debugging on the device.
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);
if (Args.hasFlag(options::OPT_fopenmp_target_debug,
options::OPT_fno_openmp_target_debug, /*Default=*/false))
CmdArgs.push_back("-fopenmp-target-debug");
- // When in OpenMP offloading mode with NVPTX target, check if full runtime
- // is required.
- if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime,
- options::OPT_fno_openmp_cuda_force_full_runtime,
- /*Default=*/false))
- CmdArgs.push_back("-fopenmp-cuda-force-full-runtime");
-
// When in OpenMP offloading mode, forward assumptions information about
// thread and team counts in the device.
if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
@@ -5966,6 +6467,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_openmp_assume_threads_oversubscription,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
+ if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state))
+ CmdArgs.push_back("-fopenmp-assume-no-thread-state");
+ if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))
+ CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");
+ if (Args.hasArg(options::OPT_fopenmp_offload_mandatory))
+ CmdArgs.push_back("-fopenmp-offload-mandatory");
+ if (Args.hasArg(options::OPT_fopenmp_force_usm))
+ CmdArgs.push_back("-fopenmp-force-usm");
break;
default:
// By default, if Clang doesn't know how to generate useful OpenMP code
@@ -5980,11 +6489,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
options::OPT_fno_openmp_simd);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
- if (!Args.hasFlag(options::OPT_fopenmp_extensions,
- options::OPT_fno_openmp_extensions, /*Default=*/true))
- CmdArgs.push_back("-fno-openmp-extensions");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fopenmp_extensions,
+ options::OPT_fno_openmp_extensions);
}
+ // Forward the new driver to change offloading code generation.
+ if (Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false))
+ CmdArgs.push_back("--offload-new-driver");
+
SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType);
const XRayArgs &XRay = TC.getXRayArgs();
@@ -6001,7 +6514,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {
StringRef S0 = A->getValue(), S = S0;
unsigned Size, Offset = 0;
- if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86())
+ if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() &&
+ !Triple.isX86())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
@@ -6047,6 +6561,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_pg)) {
+ if (TC.getTriple().isOSzOS()) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ }
+ }
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_p)) {
+ if (!(TC.getTriple().isOSAIX() || TC.getTriple().isOSOpenBSD())) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ }
+ }
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) {
+ if (A->getOption().matches(options::OPT_p)) {
+ A->claim();
+ if (TC.getTriple().isOSAIX() && !Args.hasArgNoClaim(options::OPT_pg))
+ CmdArgs.push_back("-pg");
+ }
+ }
+
+ // Reject AIX-specific link options on other targets.
+ if (!TC.getTriple().isOSAIX()) {
+ for (const Arg *A : Args.filtered(options::OPT_b, options::OPT_K,
+ options::OPT_mxcoff_build_id_EQ)) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << TripleStr;
+ }
+ }
+
if (Args.getLastArg(options::OPT_fapple_kext) ||
(Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
CmdArgs.push_back("-fapple-kext");
@@ -6058,12 +6601,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
- Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
- Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
Args.AddLastArg(CmdArgs, options::OPT_malign_double);
Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);
+ if (const char *Name = C.getTimeTraceFile(&JA)) {
+ CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name)));
+ Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
CmdArgs.push_back("-ftrapv-handler");
CmdArgs.push_back(A->getValue());
@@ -6094,11 +6640,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
options::OPT_fno_unroll_loops);
+ Args.AddLastArg(CmdArgs, options::OPT_fstrict_flex_arrays_EQ);
+
Args.AddLastArg(CmdArgs, options::OPT_pthread);
- if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
- options::OPT_mno_speculative_load_hardening, false))
- CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));
+ Args.addOptInFlag(CmdArgs, options::OPT_mspeculative_load_hardening,
+ options::OPT_mno_speculative_load_hardening);
RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
RenderSCPOptions(TC, Args, CmdArgs);
@@ -6106,10 +6653,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ);
- // Translate -mstackrealign
- if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
- false))
- CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
+ Args.addOptInFlag(CmdArgs, options::OPT_mstackrealign,
+ options::OPT_mno_stackrealign);
if (Args.hasArg(options::OPT_mstack_alignment)) {
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
@@ -6125,9 +6670,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mstack-probe-size=0");
}
- if (!Args.hasFlag(options::OPT_mstack_arg_probe,
- options::OPT_mno_stack_arg_probe, true))
- CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe"));
+ Args.addOptOutFlag(CmdArgs, options::OPT_mstack_arg_probe,
+ options::OPT_mno_stack_arg_probe);
if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
options::OPT_mno_restrict_it)) {
@@ -6136,34 +6680,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-arm-restrict-it");
} else {
CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-arm-no-restrict-it");
+ CmdArgs.push_back("-arm-default-it");
}
- } else if (Triple.isOSWindows() &&
- (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb)) {
- // Windows on ARM expects restricted IT blocks
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-arm-restrict-it");
}
// Forward -cl options to -cc1
RenderOpenCLOptions(Args, CmdArgs, InputType);
+ // Forward hlsl options to -cc1
+ RenderHLSLOptions(Args, CmdArgs, InputType);
+
+ // Forward OpenACC options to -cc1
+ RenderOpenACCOptions(D, Args, CmdArgs, InputType);
+
if (IsHIP) {
if (Args.hasFlag(options::OPT_fhip_new_launch_api,
options::OPT_fno_hip_new_launch_api, true))
CmdArgs.push_back("-fhip-new-launch-api");
- if (Args.hasFlag(options::OPT_fgpu_allow_device_init,
- options::OPT_fno_gpu_allow_device_init, false))
- CmdArgs.push_back("-fgpu-allow-device-init");
+ Args.addOptInFlag(CmdArgs, options::OPT_fgpu_allow_device_init,
+ options::OPT_fno_gpu_allow_device_init);
+ Args.AddLastArg(CmdArgs, options::OPT_hipstdpar);
+ Args.AddLastArg(CmdArgs, options::OPT_hipstdpar_interpose_alloc);
+ Args.addOptInFlag(CmdArgs, options::OPT_fhip_kernel_arg_name,
+ options::OPT_fno_hip_kernel_arg_name);
}
if (IsCuda || IsHIP) {
- if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
+ if (IsRDCMode)
CmdArgs.push_back("-fgpu-rdc");
- if (Args.hasFlag(options::OPT_fgpu_defer_diag,
- options::OPT_fno_gpu_defer_diag, false))
- CmdArgs.push_back("-fgpu-defer-diag");
+ Args.addOptInFlag(CmdArgs, options::OPT_fgpu_defer_diag,
+ options::OPT_fno_gpu_defer_diag);
if (Args.hasFlag(options::OPT_fgpu_exclude_wrong_side_overloads,
options::OPT_fno_gpu_exclude_wrong_side_overloads,
false)) {
@@ -6172,13 +6718,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // Forward -nogpulib to -cc1.
+ if (Args.hasArg(options::OPT_nogpulib))
+ CmdArgs.push_back("-nogpulib");
+
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
}
- if (IsUsingLTO)
- Args.AddLastArg(CmdArgs, options::OPT_mibt_seal);
+ if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-mfunction-return=") + A->getValue()));
+
+ Args.AddLastArg(CmdArgs, options::OPT_mindirect_branch_cs_prefix);
// Forward -f options with positive and negative forms; we translate these by
// hand. Do not propagate PGO options to the GPU-side compilations as the
@@ -6214,9 +6767,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs);
- if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
- options::OPT_fno_assume_sane_operator_new))
- CmdArgs.push_back("-fno-assume-sane-operator-new");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new);
+
+ if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false))
+ CmdArgs.push_back("-fapinotes");
+ if (Args.hasFlag(options::OPT_fapinotes_modules,
+ options::OPT_fno_apinotes_modules, false))
+ CmdArgs.push_back("-fapinotes-modules");
+ Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version);
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
@@ -6234,24 +6793,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (TC.IsEncodeExtendedBlockSignatureDefault())
CmdArgs.push_back("-fencode-extended-block-signature");
- if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
- false) &&
- types::isCXX(InputType)) {
- CmdArgs.push_back("-fcoroutines-ts");
- }
+ if (Args.hasFlag(options::OPT_fcoro_aligned_allocation,
+ options::OPT_fno_coro_aligned_allocation, false) &&
+ types::isCXX(InputType))
+ CmdArgs.push_back("-fcoro-aligned-allocation");
Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes,
options::OPT_fno_double_square_bracket_attributes);
- // -faccess-control is default.
- if (Args.hasFlag(options::OPT_fno_access_control,
- options::OPT_faccess_control, false))
- CmdArgs.push_back("-fno-access-control");
-
- // -felide-constructors is the default.
- if (Args.hasFlag(options::OPT_fno_elide_constructors,
- options::OPT_felide_constructors, false))
- CmdArgs.push_back("-fno-elide-constructors");
+ Args.addOptOutFlag(CmdArgs, options::OPT_faccess_control,
+ options::OPT_fno_access_control);
+ Args.addOptOutFlag(CmdArgs, options::OPT_felide_constructors,
+ options::OPT_fno_elide_constructors);
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
@@ -6280,21 +6833,29 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RawTriple.isOSDarwin() && !KernelOrKext))
CmdArgs.push_back("-fregister-global-dtors-with-atexit");
- // -fno-use-line-directives is default.
- if (Args.hasFlag(options::OPT_fuse_line_directives,
- options::OPT_fno_use_line_directives, false))
- CmdArgs.push_back("-fuse-line-directives");
+ Args.addOptInFlag(CmdArgs, options::OPT_fuse_line_directives,
+ options::OPT_fno_use_line_directives);
// -fno-minimize-whitespace is default.
if (Args.hasFlag(options::OPT_fminimize_whitespace,
options::OPT_fno_minimize_whitespace, false)) {
types::ID InputType = Inputs[0].getType();
if (!isDerivedFromC(InputType))
- D.Diag(diag::err_drv_minws_unsupported_input_type)
- << types::getTypeName(InputType);
+ D.Diag(diag::err_drv_opt_unsupported_input_type)
+ << "-fminimize-whitespace" << types::getTypeName(InputType);
CmdArgs.push_back("-fminimize-whitespace");
}
+ // -fno-keep-system-includes is default.
+ if (Args.hasFlag(options::OPT_fkeep_system_includes,
+ options::OPT_fno_keep_system_includes, false)) {
+ types::ID InputType = Inputs[0].getType();
+ if (!isDerivedFromC(InputType))
+ D.Diag(diag::err_drv_opt_unsupported_input_type)
+ << "-fkeep-system-includes" << types::getTypeName(InputType);
+ CmdArgs.push_back("-fkeep-system-includes");
+ }
+
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC))
@@ -6308,6 +6869,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (IsMSVCCompat)
CmdArgs.push_back("-fms-compatibility");
+ if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() &&
+ Args.hasArg(options::OPT_fms_runtime_lib_EQ))
+ ProcessVSRuntimeLibrary(Args, CmdArgs);
+
// Handle -fgcc-version, if present.
VersionTuple GNUCVer;
if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
@@ -6316,8 +6881,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef Val = A->getValue();
Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable.
bool Invalid = GNUCVer.tryParse(Val);
- unsigned Minor = GNUCVer.getMinor().getValueOr(0);
- unsigned Patch = GNUCVer.getSubminor().getValueOr(0);
+ unsigned Minor = GNUCVer.getMinor().value_or(0);
+ unsigned Patch = GNUCVer.getSubminor().value_or(0);
if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) {
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
@@ -6359,7 +6924,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
.Case("c++14", "-std=c++14")
.Case("c++17", "-std=c++17")
.Case("c++20", "-std=c++20")
- .Case("c++latest", "-std=c++2b")
+ // TODO add c++23 and c++26 when MSVC supports it.
+ .Case("c++latest", "-std=c++26")
.Default("");
if (LanguageStandard.empty())
D.Diag(clang::diag::warn_drv_unused_argument)
@@ -6376,14 +6942,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(LanguageStandard.data());
}
- // -fno-borland-extensions is default.
- if (Args.hasFlag(options::OPT_fborland_extensions,
- options::OPT_fno_borland_extensions, false))
- CmdArgs.push_back("-fborland-extensions");
+ Args.addOptInFlag(CmdArgs, options::OPT_fborland_extensions,
+ options::OPT_fno_borland_extensions);
- // -fno-declspec is default, except for PS4.
+ // -fno-declspec is default, except for PS4/PS5.
if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
- RawTriple.isPS4()))
+ RawTriple.isPS()))
CmdArgs.push_back("-fdeclspec");
else if (Args.hasArg(options::OPT_fno_declspec))
CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.
@@ -6396,36 +6960,58 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
(!IsWindowsMSVC || IsMSVC2015Compatible)))
CmdArgs.push_back("-fno-threadsafe-statics");
- // -fno-delayed-template-parsing is default, except when targeting MSVC.
- // Many old Windows SDK versions require this to parse.
- // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their
- // compiler. We should be able to disable this by default at some point.
- if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
- options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
- CmdArgs.push_back("-fdelayed-template-parsing");
-
// -fgnu-keywords default varies depending on language; only pass if
// specified.
Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords,
options::OPT_fno_gnu_keywords);
- if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline,
- false))
- CmdArgs.push_back("-fgnu89-inline");
+ Args.addOptInFlag(CmdArgs, options::OPT_fgnu89_inline,
+ options::OPT_fno_gnu89_inline);
- if (Args.hasArg(options::OPT_fno_inline))
- CmdArgs.push_back("-fno-inline");
+ const Arg *InlineArg = Args.getLastArg(options::OPT_finline_functions,
+ options::OPT_finline_hint_functions,
+ options::OPT_fno_inline_functions);
+ if (Arg *A = Args.getLastArg(options::OPT_finline, options::OPT_fno_inline)) {
+ if (A->getOption().matches(options::OPT_fno_inline))
+ A->render(Args, CmdArgs);
+ } else if (InlineArg) {
+ InlineArg->render(Args, CmdArgs);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_finline_max_stacksize_EQ);
+
+ // FIXME: Find a better way to determine whether we are in C++20.
+ bool HaveCxx20 =
+ Std &&
+ (Std->containsValue("c++2a") || Std->containsValue("gnu++2a") ||
+ Std->containsValue("c++20") || Std->containsValue("gnu++20") ||
+ Std->containsValue("c++2b") || Std->containsValue("gnu++2b") ||
+ Std->containsValue("c++23") || Std->containsValue("gnu++23") ||
+ Std->containsValue("c++2c") || Std->containsValue("gnu++2c") ||
+ Std->containsValue("c++26") || Std->containsValue("gnu++26") ||
+ Std->containsValue("c++latest") || Std->containsValue("gnu++latest"));
+ bool HaveModules =
+ RenderModulesOptions(C, D, Args, Input, Output, HaveCxx20, CmdArgs);
- Args.AddLastArg(CmdArgs, options::OPT_finline_functions,
- options::OPT_finline_hint_functions,
- options::OPT_fno_inline_functions);
+ // -fdelayed-template-parsing is default when targeting MSVC.
+ // Many old Windows SDK versions require this to parse.
+ //
+ // According to
+ // https://learn.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=msvc-170,
+ // MSVC actually defaults to -fno-delayed-template-parsing (/Zc:twoPhase-
+ // with MSVC CLI) if using C++20. So we match the behavior with MSVC here to
+ // not enable -fdelayed-template-parsing by default after C++20.
+ //
+ // FIXME: Given -fdelayed-template-parsing is a source of bugs, we should be
+ // able to disable this by default at some point.
+ if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
+ options::OPT_fno_delayed_template_parsing,
+ IsWindowsMSVC && !HaveCxx20)) {
+ if (HaveCxx20)
+ D.Diag(clang::diag::warn_drv_delayed_template_parsing_after_cxx20);
- // FIXME: Find a better way to determine whether the language has modules
- // support by default, or just assume that all languages do.
- bool HaveModules =
- Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") ||
- Std->containsValue("c++latest"));
- RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
+ CmdArgs.push_back("-fdelayed-template-parsing");
+ }
if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
options::OPT_fno_pch_validate_input_files_content, false))
@@ -6440,9 +7026,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fmodules-debuginfo");
- Args.AddLastArg(CmdArgs, options::OPT_flegacy_pass_manager,
- options::OPT_fno_legacy_pass_manager);
-
ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind);
RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None,
Input, CmdArgs);
@@ -6493,22 +7076,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// C++ "sane" operator new.
- if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
- options::OPT_fno_assume_sane_operator_new))
- CmdArgs.push_back("-fno-assume-sane-operator-new");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new);
+
+ // -fassume-unique-vtables is on by default.
+ Args.addOptOutFlag(CmdArgs, options::OPT_fassume_unique_vtables,
+ options::OPT_fno_assume_unique_vtables);
// -frelaxed-template-template-args is off by default, as it is a severe
// breaking change until a corresponding change to template partial ordering
// is provided.
- if (Args.hasFlag(options::OPT_frelaxed_template_template_args,
- options::OPT_fno_relaxed_template_template_args, false))
- CmdArgs.push_back("-frelaxed-template-template-args");
+ Args.addOptInFlag(CmdArgs, options::OPT_frelaxed_template_template_args,
+ options::OPT_fno_relaxed_template_template_args);
// -fsized-deallocation is off by default, as it is an ABI-breaking change for
// most platforms.
- if (Args.hasFlag(options::OPT_fsized_deallocation,
- options::OPT_fno_sized_deallocation, false))
- CmdArgs.push_back("-fsized-deallocation");
+ Args.addOptInFlag(CmdArgs, options::OPT_fsized_deallocation,
+ options::OPT_fno_sized_deallocation);
// -faligned-allocation is on by default in C++17 onwards and otherwise off
// by default.
@@ -6531,15 +7115,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fconstant-cfstrings is default, and may be subject to argument translation
// on Darwin.
if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
- options::OPT_fno_constant_cfstrings) ||
+ options::OPT_fno_constant_cfstrings, true) ||
!Args.hasFlag(options::OPT_mconstant_cfstrings,
- options::OPT_mno_constant_cfstrings))
+ options::OPT_mno_constant_cfstrings, true))
CmdArgs.push_back("-fno-constant-cfstrings");
- // -fno-pascal-strings is default, only pass non-default.
- if (Args.hasFlag(options::OPT_fpascal_strings,
- options::OPT_fno_pascal_strings, false))
- CmdArgs.push_back("-fpascal-strings");
+ Args.addOptInFlag(CmdArgs, options::OPT_fpascal_strings,
+ options::OPT_fno_pascal_strings);
// Honor -fpack-struct= and -fpack-struct, if given. Note that
// -fno-pack-struct doesn't apply to -fpack-struct=.
@@ -6571,18 +7153,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-Qn");
// -fno-common is the default, set -fcommon only when that flag is set.
- if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false))
- CmdArgs.push_back("-fcommon");
+ Args.addOptInFlag(CmdArgs, options::OPT_fcommon, options::OPT_fno_common);
// -fsigned-bitfields is default, and clang doesn't yet support
// -funsigned-bitfields.
if (!Args.hasFlag(options::OPT_fsigned_bitfields,
- options::OPT_funsigned_bitfields))
+ options::OPT_funsigned_bitfields, true))
D.Diag(diag::warn_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
// -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
- if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope))
+ if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope, true))
D.Diag(diag::err_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
@@ -6604,15 +7185,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RenderDiagnosticsOptions(D, Args, CmdArgs);
- // -fno-asm-blocks is default.
- if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
- false))
- CmdArgs.push_back("-fasm-blocks");
+ Args.addOptInFlag(CmdArgs, options::OPT_fasm_blocks,
+ options::OPT_fno_asm_blocks);
- // -fgnu-inline-asm is default.
- if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
- options::OPT_fno_gnu_inline_asm, true))
- CmdArgs.push_back("-fno-gnu-inline-asm");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fgnu_inline_asm,
+ options::OPT_fno_gnu_inline_asm);
// Enable vectorization per default according to the optimization level
// selected. For optimization levels that want vectorization we use the alias
@@ -6648,21 +7225,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-dollars-in-identifiers");
}
- // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
- // practical purposes.
- if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
- options::OPT_fno_unit_at_a_time)) {
- if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
- D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
- }
-
- if (Args.hasFlag(options::OPT_fapple_pragma_pack,
- options::OPT_fno_apple_pragma_pack, false))
- CmdArgs.push_back("-fapple-pragma-pack");
-
- if (Args.hasFlag(options::OPT_fxl_pragma_pack,
- options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX()))
- CmdArgs.push_back("-fxl-pragma-pack");
+ Args.addOptInFlag(CmdArgs, options::OPT_fapple_pragma_pack,
+ options::OPT_fno_apple_pragma_pack);
// Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple))
@@ -6673,6 +7237,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (RewriteImports)
CmdArgs.push_back("-frewrite-imports");
+ Args.addOptInFlag(CmdArgs, options::OPT_fdirectives_only,
+ options::OPT_fno_directives_only);
+
// Enable rewrite includes if the user's asked for it or if we're generating
// diagnostics.
// TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
@@ -6754,25 +7321,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
}
+ // Forward --vfsoverlay to -cc1.
+ for (const Arg *A : Args.filtered(options::OPT_vfsoverlay)) {
+ CmdArgs.push_back("--vfsoverlay");
+ CmdArgs.push_back(A->getValue());
+ A->claim();
+ }
+
+ Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions,
+ options::OPT_fno_safe_buffer_usage_suggestions);
+
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
- if (!StatsFile.empty())
+ if (!StatsFile.empty()) {
CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile));
+ if (D.CCPrintInternalStats)
+ CmdArgs.push_back("-stats-file-append");
+ }
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
- // -finclude-default-header flag is for preprocessor,
- // do not pass it to other cc1 commands when save-temps is enabled
- if (C.getDriver().isSaveTempsEnabled() &&
- !isa<PreprocessJobAction>(JA)) {
- for (auto Arg : Args.filtered(options::OPT_Xclang)) {
- Arg->claim();
- if (StringRef(Arg->getValue()) != "-finclude-default-header")
- CmdArgs.push_back(Arg->getValue());
+ for (auto Arg : Args.filtered(options::OPT_Xclang)) {
+ Arg->claim();
+ // -finclude-default-header flag is for preprocessor,
+ // do not pass it to other cc1 commands when save-temps is enabled
+ if (C.getDriver().isSaveTempsEnabled() &&
+ !isa<PreprocessJobAction>(JA)) {
+ if (StringRef(Arg->getValue()) == "-finclude-default-header")
+ continue;
}
- }
- else {
- Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
+ CmdArgs.push_back(Arg->getValue());
}
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
A->claim();
@@ -6816,7 +7394,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
auto FRecordSwitches =
Args.hasFlag(options::OPT_frecord_command_line,
options::OPT_fno_record_command_line, false);
- if (FRecordSwitches && !Triple.isOSBinFormatELF())
+ if (FRecordSwitches && !Triple.isOSBinFormatELF() &&
+ !Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args)
<< TripleStr;
@@ -6844,13 +7423,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Host-side cuda compilation receives all device-side outputs in a single
- // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
+ // Host-side offloading compilation receives all device-side outputs. Include
+ // them in the host compilation depending on the target. If the host inputs
+ // are not empty we use the new-driver scheme, otherwise use the old scheme.
if ((IsCuda || IsHIP) && CudaDeviceInput) {
+ CmdArgs.push_back("-fcuda-include-gpubinary");
+ CmdArgs.push_back(CudaDeviceInput->getFilename());
+ } else if (!HostOffloadingInputs.empty()) {
+ if ((IsCuda || IsHIP) && !IsRDCMode) {
+ assert(HostOffloadingInputs.size() == 1 && "Only one input expected");
CmdArgs.push_back("-fcuda-include-gpubinary");
- CmdArgs.push_back(CudaDeviceInput->getFilename());
- if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
- CmdArgs.push_back("-fgpu-rdc");
+ CmdArgs.push_back(HostOffloadingInputs.front().getFilename());
+ } else {
+ for (const InputInfo Input : HostOffloadingInputs)
+ CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" +
+ TC.getInputFilename(Input)));
+ }
}
if (IsCuda) {
@@ -6869,10 +7457,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
auto CUID = cast<InputAction>(SourceAction)->getId();
if (!CUID.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-cuid=") + Twine(CUID)));
+
+ // -ffast-math turns on -fgpu-approx-transcendentals implicitly, but will
+ // be overriden by -fno-gpu-approx-transcendentals.
+ bool UseApproxTranscendentals = Args.hasFlag(
+ options::OPT_ffast_math, options::OPT_fno_fast_math, false);
+ if (Args.hasFlag(options::OPT_fgpu_approx_transcendentals,
+ options::OPT_fno_gpu_approx_transcendentals,
+ UseApproxTranscendentals))
+ CmdArgs.push_back("-fgpu-approx-transcendentals");
+ } else {
+ Args.claimAllArgs(options::OPT_fgpu_approx_transcendentals,
+ options::OPT_fno_gpu_approx_transcendentals);
}
- if (IsHIP)
+ if (IsHIP) {
CmdArgs.push_back("-fcuda-allow-variadic-functions");
+ Args.AddLastArg(CmdArgs, options::OPT_fgpu_default_stream_EQ);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_foffload_uniform_block,
+ options::OPT_fno_offload_uniform_block);
+
+ Args.AddLastArg(CmdArgs, options::OPT_foffload_implicit_host_device_templates,
+ options::OPT_fno_offload_implicit_host_device_templates);
if (IsCudaDevice || IsHIPDevice) {
StringRef InlineThresh =
@@ -6884,63 +7492,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ if (IsHIPDevice)
+ Args.addOptOutFlag(CmdArgs,
+ options::OPT_fhip_fp32_correctly_rounded_divide_sqrt,
+ options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt);
+
// OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
// to specify the result of the compile phase on the host, so the meaningful
- // device declarations can be identified. Also, -fopenmp-is-device is passed
- // along to tell the frontend that it is generating code for a device, so that
- // only the relevant declarations are emitted.
+ // device declarations can be identified. Also, -fopenmp-is-target-device is
+ // passed along to tell the frontend that it is generating code for a device,
+ // so that only the relevant declarations are emitted.
if (IsOpenMPDevice) {
- CmdArgs.push_back("-fopenmp-is-device");
+ CmdArgs.push_back("-fopenmp-is-target-device");
if (OpenMPDeviceInput) {
CmdArgs.push_back("-fopenmp-host-ir-file-path");
CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename()));
}
}
- // Host-side OpenMP offloading recieves the device object files and embeds it
- // in a named section including the associated target triple and architecture.
- if (IsOpenMPHost && !OpenMPHostInputs.empty()) {
- auto InputFile = OpenMPHostInputs.begin();
- auto OpenMPTCs = C.getOffloadToolChains<Action::OFK_OpenMP>();
- for (auto TI = OpenMPTCs.first, TE = OpenMPTCs.second; TI != TE;
- ++TI, ++InputFile) {
- const ToolChain *TC = TI->second;
- const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP);
- StringRef File =
- C.getArgs().MakeArgString(TC->getInputFilename(*InputFile));
- StringRef InputName = Clang::getBaseInputStem(Args, Inputs);
-
- CmdArgs.push_back(Args.MakeArgString(
- "-fembed-offload-object=" + File + "," + TC->getTripleString() + "." +
- TCArgs.getLastArgValue(options::OPT_march_EQ) + "." + InputName));
- }
- }
-
if (Triple.isAMDGPU()) {
handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs);
- if (Args.hasFlag(options::OPT_munsafe_fp_atomics,
- options::OPT_mno_unsafe_fp_atomics, /*Default=*/false))
- CmdArgs.push_back("-munsafe-fp-atomics");
+ Args.addOptInFlag(CmdArgs, options::OPT_munsafe_fp_atomics,
+ options::OPT_mno_unsafe_fp_atomics);
+ Args.addOptOutFlag(CmdArgs, options::OPT_mamdgpu_ieee,
+ options::OPT_mno_amdgpu_ieee);
}
// For all the host OpenMP offloading compile jobs we need to pass the targets
// information using -fopenmp-targets= option.
if (JA.isHostOffloading(Action::OFK_OpenMP)) {
- SmallString<128> TargetInfo("-fopenmp-targets=");
+ SmallString<128> Targets("-fopenmp-targets=");
- Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ);
- assert(Tgts && Tgts->getNumValues() &&
- "OpenMP offloading has to have targets specified.");
- for (unsigned i = 0; i < Tgts->getNumValues(); ++i) {
- if (i)
- TargetInfo += ',';
- // We need to get the string from the triple because it may be not exactly
- // the same as the one we get directly from the arguments.
- llvm::Triple T(Tgts->getValue(i));
- TargetInfo += T.getTriple();
- }
- CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
+ SmallVector<std::string, 4> Triples;
+ auto TCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
+ std::transform(TCRange.first, TCRange.second, std::back_inserter(Triples),
+ [](auto TC) { return TC.second->getTripleString(); });
+ CmdArgs.push_back(Args.MakeArgString(Targets + llvm::join(Triples, ",")));
}
bool VirtualFunctionElimination =
@@ -6968,22 +7556,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (WholeProgramVTables) {
- // Propagate -fwhole-program-vtables if this is an LTO compile.
- if (IsUsingLTO)
- CmdArgs.push_back("-fwhole-program-vtables");
+ // PS4 uses the legacy LTO API, which does not support this feature in
+ // ThinLTO mode.
+ bool IsPS4 = getToolChain().getTriple().isPS4();
+
// Check if we passed LTO options but they were suppressed because this is a
// device offloading action, or we passed device offload LTO options which
// were suppressed because this is not the device offload action.
+ // Check if we are using PS4 in regular LTO mode.
// Otherwise, issue an error.
- else if (!D.isUsingLTO(!IsDeviceOffloadAction))
+ if ((!IsUsingLTO && !D.isUsingLTO(!IsDeviceOffloadAction)) ||
+ (IsPS4 && !UnifiedLTO && (D.getLTOMode() != LTOK_Full)))
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-fwhole-program-vtables"
- << "-flto";
+ << ((IsPS4 && !UnifiedLTO) ? "-flto=full" : "-flto");
+
+ // Propagate -fwhole-program-vtables if this is an LTO compile.
+ if (IsUsingLTO)
+ CmdArgs.push_back("-fwhole-program-vtables");
}
bool DefaultsSplitLTOUnit =
- (WholeProgramVTables || SanitizeArgs.needsLTO()) &&
- (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit());
+ ((WholeProgramVTables || SanitizeArgs.needsLTO()) &&
+ (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit())) ||
+ (!Triple.isPS4() && UnifiedLTO);
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit);
@@ -6993,6 +7589,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (SplitLTOUnit)
CmdArgs.push_back("-fsplit-lto-unit");
+ if (Arg *A = Args.getLastArg(options::OPT_ffat_lto_objects,
+ options::OPT_fno_fat_lto_objects)) {
+ if (IsUsingLTO && A->getOption().matches(options::OPT_ffat_lto_objects)) {
+ assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin);
+ if (!Triple.isOSBinFormatELF()) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TC.getTripleString();
+ }
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full")));
+ CmdArgs.push_back("-flto-unit");
+ CmdArgs.push_back("-ffat-lto-objects");
+ A->render(Args, CmdArgs);
+ }
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel,
options::OPT_fno_global_isel)) {
CmdArgs.push_back("-mllvm");
@@ -7041,17 +7653,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fforce-enable-int128");
}
- if (Args.hasFlag(options::OPT_fkeep_static_consts,
- options::OPT_fno_keep_static_consts, false))
- CmdArgs.push_back("-fkeep-static-consts");
-
- if (Args.hasFlag(options::OPT_fcomplete_member_pointers,
- options::OPT_fno_complete_member_pointers, false))
- CmdArgs.push_back("-fcomplete-member-pointers");
-
- if (!Args.hasFlag(options::OPT_fcxx_static_destructors,
- options::OPT_fno_cxx_static_destructors, true))
- CmdArgs.push_back("-fno-c++-static-destructors");
+ Args.addOptInFlag(CmdArgs, options::OPT_fkeep_static_consts,
+ options::OPT_fno_keep_static_consts);
+ Args.addOptInFlag(CmdArgs, options::OPT_fkeep_persistent_storage_variables,
+ options::OPT_fno_keep_persistent_storage_variables);
+ Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers,
+ options::OPT_fno_complete_member_pointers);
+ Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors,
+ options::OPT_fno_cxx_static_destructors);
addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);
@@ -7076,6 +7685,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("+outline-atomics");
}
+ if (Triple.isAArch64() &&
+ (Args.hasArg(options::OPT_mno_fmv) ||
+ (Triple.isAndroid() && Triple.isAndroidVersionLT(23)) ||
+ getToolChain().GetRuntimeLibType(Args) != ToolChain::RLT_CompilerRT)) {
+ // Disable Function Multiversioning on AArch64 target.
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-fmv");
+ }
+
if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig,
(TC.getTriple().isOSBinFormatELF() ||
TC.getTriple().isOSBinFormatCOFF()) &&
@@ -7086,8 +7704,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-faddrsig");
if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) &&
- (EH || AsyncUnwindTables || UnwindTables ||
- DebugInfoKind != codegenoptions::NoDebugInfo))
+ (EH || UnwindTables || AsyncUnwindTables ||
+ DebugInfoKind != llvm::codegenoptions::NoDebugInfo))
CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1");
if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) {
@@ -7098,11 +7716,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Str));
}
- // Add the output path to the object file for CodeView debug infos.
- if (EmitCodeView && Output.isFilename())
- addDebugObjectName(Args, CmdArgs, DebugCompilationDir,
- Output.getFilename());
-
// Add the "-o out -x type src.c" flags last. This is done primarily to make
// the -cc1 command easier to edit when reproducing compiler crashes.
if (Output.getType() == types::TY_Dependencies) {
@@ -7125,8 +7738,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
addDashXForInput(Args, Input, CmdArgs);
ArrayRef<InputInfo> FrontendInputs = Input;
- if (IsHeaderModulePrecompile)
- FrontendInputs = ModuleHeaderInputs;
+ if (IsExtractAPI)
+ FrontendInputs = ExtractAPIInputs;
else if (Input.isNothing())
FrontendInputs = {};
@@ -7139,13 +7752,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (D.CC1Main && !D.CCGenDiagnostics) {
// Invoke the CC1 directly in this process
- C.addCommand(std::make_unique<CC1Command>(JA, *this,
- ResponseFileSupport::AtFileUTF8(),
- Exec, CmdArgs, Inputs, Output));
+ C.addCommand(std::make_unique<CC1Command>(
+ JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+ Output, D.getPrependArg()));
} else {
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileUTF8(),
- Exec, CmdArgs, Inputs, Output));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+ Output, D.getPrependArg()));
}
// Make the compile command echo its inputs for /showFilenames.
@@ -7378,66 +7991,20 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
EH.NoUnwindC = true;
}
+ if (Args.hasArg(options::OPT__SLASH_kernel)) {
+ EH.Synch = false;
+ EH.NoUnwindC = false;
+ EH.Asynch = false;
+ }
+
return EH;
}
void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
- ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind *DebugInfoKind,
- bool *EmitCodeView) const {
- unsigned RTOptionID = options::OPT__SLASH_MT;
+ ArgStringList &CmdArgs) const {
bool isNVPTX = getToolChain().getTriple().isNVPTX();
- if (Args.hasArg(options::OPT__SLASH_LDd))
- // The /LDd option implies /MTd. The dependent lib part can be overridden,
- // but defining _DEBUG is sticky.
- RTOptionID = options::OPT__SLASH_MTd;
-
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
- RTOptionID = A->getOption().getID();
-
- StringRef FlagForCRT;
- switch (RTOptionID) {
- case options::OPT__SLASH_MD:
- if (Args.hasArg(options::OPT__SLASH_LDd))
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-D_DLL");
- FlagForCRT = "--dependent-lib=msvcrt";
- break;
- case options::OPT__SLASH_MDd:
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-D_DLL");
- FlagForCRT = "--dependent-lib=msvcrtd";
- break;
- case options::OPT__SLASH_MT:
- if (Args.hasArg(options::OPT__SLASH_LDd))
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-flto-visibility-public-std");
- FlagForCRT = "--dependent-lib=libcmt";
- break;
- case options::OPT__SLASH_MTd:
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-flto-visibility-public-std");
- FlagForCRT = "--dependent-lib=libcmtd";
- break;
- default:
- llvm_unreachable("Unexpected option ID.");
- }
-
- if (Args.hasArg(options::OPT__SLASH_Zl)) {
- CmdArgs.push_back("-D_VC_NODEFAULTLIB");
- } else {
- CmdArgs.push_back(FlagForCRT.data());
-
- // This provides POSIX compatibility (maps 'open' to '_open'), which most
- // users want. The /Za flag to cl.exe turns this off, but it's not
- // implemented in clang.
- CmdArgs.push_back("--dependent-lib=oldnames");
- }
+ ProcessVSRuntimeLibrary(Args, CmdArgs);
if (Arg *ShowIncludes =
Args.getLastArg(options::OPT__SLASH_showIncludes,
@@ -7460,24 +8027,15 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong)));
}
- // Emit CodeView if -Z7 or -gline-tables-only are present.
- if (Arg *DebugInfoArg = Args.getLastArg(options::OPT__SLASH_Z7,
- options::OPT_gline_tables_only)) {
- *EmitCodeView = true;
- if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7))
- *DebugInfoKind = codegenoptions::DebugInfoConstructor;
- else
- *DebugInfoKind = codegenoptions::DebugLineTablesOnly;
- } else {
- *EmitCodeView = false;
- }
-
const Driver &D = getToolChain().getDriver();
+
EHFlags EH = parseClangCLEHFlags(D, Args);
if (!isNVPTX && (EH.Synch || EH.Asynch)) {
if (types::isCXX(InputType))
CmdArgs.push_back("-fcxx-exceptions");
CmdArgs.push_back("-fexceptions");
+ if (EH.Asynch)
+ CmdArgs.push_back("-fasync-exceptions");
}
if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC)
CmdArgs.push_back("-fexternc-nounwind");
@@ -7488,24 +8046,38 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back("-P");
}
- unsigned VolatileOptionID;
- if (getToolChain().getTriple().isX86())
- VolatileOptionID = options::OPT__SLASH_volatile_ms;
- else
- VolatileOptionID = options::OPT__SLASH_volatile_iso;
-
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group))
- VolatileOptionID = A->getOption().getID();
-
- if (VolatileOptionID == options::OPT__SLASH_volatile_ms)
- CmdArgs.push_back("-fms-volatile");
-
if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_,
options::OPT__SLASH_Zc_dllexportInlines,
false)) {
CmdArgs.push_back("-fno-dllexport-inlines");
}
+ if (Args.hasFlag(options::OPT__SLASH_Zc_wchar_t_,
+ options::OPT__SLASH_Zc_wchar_t, false)) {
+ CmdArgs.push_back("-fno-wchar");
+ }
+
+ if (Args.hasArg(options::OPT__SLASH_kernel)) {
+ llvm::Triple::ArchType Arch = getToolChain().getArch();
+ std::vector<std::string> Values =
+ Args.getAllArgValues(options::OPT__SLASH_arch);
+ if (!Values.empty()) {
+ llvm::SmallSet<std::string, 4> SupportedArches;
+ if (Arch == llvm::Triple::x86)
+ SupportedArches.insert("IA32");
+
+ for (auto &V : Values)
+ if (!SupportedArches.contains(V))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << std::string("/arch:").append(V) << "/kernel";
+ }
+
+ CmdArgs.push_back("-fno-rtti");
+ if (Args.hasFlag(options::OPT__SLASH_GR, options::OPT__SLASH_GR_, false))
+ D.Diag(diag::err_drv_argument_not_allowed_with) << "/GR"
+ << "/kernel";
+ }
+
Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
if (MostGeneralArg && BestCaseArg)
@@ -7532,6 +8104,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back("-fms-memptr-rep=virtual");
}
+ if (Args.hasArg(options::OPT_regcall4))
+ CmdArgs.push_back("-regcall4");
+
// Parse the default calling convention options.
if (Arg *CCArg =
Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr,
@@ -7568,6 +8143,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back(DCCFlag);
}
+ if (Args.hasArg(options::OPT__SLASH_Gregcall4))
+ CmdArgs.push_back("-regcall4");
+
Args.AddLastArg(CmdArgs, options::OPT_vtordisp_mode_EQ);
if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) {
@@ -7575,7 +8153,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
CmdArgs.push_back("msvc");
}
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
+ if (Args.hasArg(options::OPT__SLASH_kernel))
+ CmdArgs.push_back("-fms-kernel");
+
+ for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
StringRef GuardArgs = A->getValue();
// The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and
// "ehcont-".
@@ -7594,6 +8175,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
} else {
D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs;
}
+ A->claim();
}
}
@@ -7650,11 +8232,19 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
} else {
getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
+void ClangAs::AddLoongArchTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(loongarch::getLoongArchABI(getToolChain().getDriver(), Args,
+ getToolChain().getTriple())
+ .data());
+}
+
void ClangAs::AddRISCVTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const llvm::Triple &Triple = getToolChain().getTriple();
@@ -7662,6 +8252,12 @@ void ClangAs::AddRISCVTargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
+
+ if (Args.hasFlag(options::OPT_mdefault_build_attributes,
+ options::OPT_mno_default_build_attributes, true)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-riscv-add-build-attributes");
+ }
}
void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
@@ -7693,6 +8289,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-triple");
CmdArgs.push_back(Args.MakeArgString(TripleStr));
+ getToolChain().addClangCC1ASTargetOptions(Args, CmdArgs);
+
// Set the output mode, we currently only expect to be used as a real
// assembler.
CmdArgs.push_back("-filetype");
@@ -7737,14 +8335,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
WantDebug = !A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_ggdb0);
- unsigned DwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args);
- if (const Arg *GDwarfN = getDwarfNArg(Args))
- DwarfVersion = DwarfVersionNum(GDwarfN->getSpelling());
-
- if (DwarfVersion == 0)
- DwarfVersion = getToolChain().GetDefaultDwarfVersion();
-
- codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
+ llvm::codegenoptions::DebugInfoKind DebugInfoKind =
+ llvm::codegenoptions::NoDebugInfo;
// Add the -fdebug-compilation-dir flag if needed.
const char *DebugCompilationDir =
@@ -7756,10 +8348,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// the guard for source type, however there is a test which asserts
// that some assembler invocation receives no -debug-info-kind,
// and it's not clear whether that test is just overly restrictive.
- DebugInfoKind = (WantDebug ? codegenoptions::DebugInfoConstructor
- : codegenoptions::NoDebugInfo);
+ DebugInfoKind = (WantDebug ? llvm::codegenoptions::DebugInfoConstructor
+ : llvm::codegenoptions::NoDebugInfo);
- addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs);
+ addDebugPrefixMapArg(getToolChain().getDriver(), getToolChain(), Args,
+ CmdArgs);
// Set the AT_producer to the clang version when using the integrated
// assembler on assembly source files.
@@ -7769,12 +8362,12 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// And pass along -I options
Args.AddAllArgs(CmdArgs, options::OPT_I);
}
+ const unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args);
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
llvm::DebuggerKind::Default);
renderDwarfFormat(D, Triple, Args, CmdArgs, DwarfVersion);
RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain());
-
// Handle -fPIC et al -- the relocation-model affects the assembler
// for some targets.
llvm::Reloc::Model RelocationModel;
@@ -7850,6 +8443,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
}
break;
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ AddLoongArchTargetArgs(Args, CmdArgs);
+ break;
+
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
AddRISCVTargetArgs(Args, CmdArgs);
@@ -7868,7 +8466,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_mllvm);
- if (DebugInfoKind > codegenoptions::NoDebugInfo && Output.isFilename())
+ if (DebugInfoKind > llvm::codegenoptions::NoDebugInfo && Output.isFilename())
addDebugObjectName(Args, CmdArgs, DebugCompilationDir,
Output.getFilename());
@@ -7879,14 +8477,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
continue;
auto &JArgs = J.getArguments();
for (unsigned I = 0; I < JArgs.size(); ++I) {
- if (StringRef(JArgs[I]).startswith("-object-file-name=") &&
+ if (StringRef(JArgs[I]).starts_with("-object-file-name=") &&
Output.isFilename()) {
- ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I);
- addDebugObjectName(Args, NewArgs, DebugCompilationDir,
- Output.getFilename());
- NewArgs.append(JArgs.begin() + I + 1, JArgs.end());
- J.replaceArguments(NewArgs);
- break;
+ ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I);
+ addDebugObjectName(Args, NewArgs, DebugCompilationDir,
+ Output.getFilename());
+ NewArgs.append(JArgs.begin() + I + 1, JArgs.end());
+ J.replaceArguments(NewArgs);
+ break;
}
}
}
@@ -7904,7 +8502,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
}
if (Triple.isAMDGPU())
- handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs);
+ handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs, /*IsCC1As=*/true);
assert(Input.isFilename() && "Invalid input.");
CmdArgs.push_back(Input.getFilename());
@@ -7912,13 +8510,13 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec = getToolChain().getDriver().getClangProgramPath();
if (D.CC1Main && !D.CCGenDiagnostics) {
// Invoke cc1as directly in this process.
- C.addCommand(std::make_unique<CC1Command>(JA, *this,
- ResponseFileSupport::AtFileUTF8(),
- Exec, CmdArgs, Inputs, Output));
+ C.addCommand(std::make_unique<CC1Command>(
+ JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+ Output, D.getPrependArg()));
} else {
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileUTF8(),
- Exec, CmdArgs, Inputs, Output));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+ Output, D.getPrependArg()));
}
}
@@ -7935,8 +8533,10 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
// The bundling command looks like this:
// clang-offload-bundler -type=bc
// -targets=host-triple,openmp-triple1,openmp-triple2
- // -outputs=input_file
- // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
+ // -output=output_file
+ // -input=unbundle_file_host
+ // -input=unbundle_file_tgt1
+ // -input=unbundle_file_tgt2
ArgStringList CmdArgs;
@@ -7983,7 +8583,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
// Extract GPUArch from -march argument in TC argument list.
for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) {
auto ArchStr = StringRef(TCArgs.getArgString(ArgIndex));
- auto Arch = ArchStr.startswith_insensitive("-march=");
+ auto Arch = ArchStr.starts_with_insensitive("-march=");
if (Arch) {
GPUArchName = ArchStr.substr(7);
Triples += "-";
@@ -7997,14 +8597,12 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
// Get bundled file command.
CmdArgs.push_back(
- TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename()));
+ TCArgs.MakeArgString(Twine("-output=") + Output.getFilename()));
// Get unbundled files command.
- SmallString<128> UB;
- UB += "-inputs=";
for (unsigned I = 0; I < Inputs.size(); ++I) {
- if (I)
- UB += ',';
+ SmallString<128> UB;
+ UB += "-input=";
// Find ToolChain for this input.
const ToolChain *CurTC = &getToolChain();
@@ -8019,14 +8617,18 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
} else {
UB += CurTC->getInputFilename(Inputs[I]);
}
+ CmdArgs.push_back(TCArgs.MakeArgString(UB));
}
- CmdArgs.push_back(TCArgs.MakeArgString(UB));
-
+ if (TCArgs.hasFlag(options::OPT_offload_compress,
+ options::OPT_no_offload_compress, false))
+ CmdArgs.push_back("-compress");
+ if (TCArgs.hasArg(options::OPT_v))
+ CmdArgs.push_back("-verbose");
// All the inputs are encoded as commands.
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::None(),
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, None, Output));
+ CmdArgs, std::nullopt, Output));
}
void OffloadBundler::ConstructJobMultipleOutputs(
@@ -8039,8 +8641,10 @@ void OffloadBundler::ConstructJobMultipleOutputs(
// The unbundling command looks like this:
// clang-offload-bundler -type=bc
// -targets=host-triple,openmp-triple1,openmp-triple2
- // -inputs=input_file
- // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
+ // -input=input_file
+ // -output=unbundle_file_host
+ // -output=unbundle_file_tgt1
+ // -output=unbundle_file_tgt2
// -unbundle
ArgStringList CmdArgs;
@@ -8077,7 +8681,7 @@ void OffloadBundler::ConstructJobMultipleOutputs(
// Extract GPUArch from -march argument in TC argument list.
for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) {
StringRef ArchStr = StringRef(TCArgs.getArgString(ArgIndex));
- auto Arch = ArchStr.startswith_insensitive("-march=");
+ auto Arch = ArchStr.starts_with_insensitive("-march=");
if (Arch) {
GPUArchName = ArchStr.substr(7);
Triples += "-";
@@ -8092,49 +8696,82 @@ void OffloadBundler::ConstructJobMultipleOutputs(
// Get bundled file command.
CmdArgs.push_back(
- TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename()));
+ TCArgs.MakeArgString(Twine("-input=") + Input.getFilename()));
// Get unbundled files command.
- SmallString<128> UB;
- UB += "-outputs=";
for (unsigned I = 0; I < Outputs.size(); ++I) {
- if (I)
- UB += ',';
+ SmallString<128> UB;
+ UB += "-output=";
UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]);
+ CmdArgs.push_back(TCArgs.MakeArgString(UB));
}
- CmdArgs.push_back(TCArgs.MakeArgString(UB));
CmdArgs.push_back("-unbundle");
CmdArgs.push_back("-allow-missing-bundles");
+ if (TCArgs.hasArg(options::OPT_v))
+ CmdArgs.push_back("-verbose");
// All the inputs are encoded as commands.
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::None(),
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, None, Outputs));
+ CmdArgs, std::nullopt, Outputs));
}
-void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &Args,
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
- const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
-
- // Add the "effective" target triple.
- CmdArgs.push_back("-target");
- CmdArgs.push_back(Args.MakeArgString(Triple.getTriple()));
-
// Add the output file name.
assert(Output.isFilename() && "Invalid output.");
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- // Add inputs.
- for (const InputInfo &I : Inputs) {
- assert(I.isFilename() && "Invalid input.");
- CmdArgs.push_back(I.getFilename());
+ // Create the inputs to bundle the needed metadata.
+ for (const InputInfo &Input : Inputs) {
+ const Action *OffloadAction = Input.getAction();
+ const ToolChain *TC = OffloadAction->getOffloadingToolChain();
+ const ArgList &TCArgs =
+ C.getArgsForToolChain(TC, OffloadAction->getOffloadingArch(),
+ OffloadAction->getOffloadingDeviceKind());
+ StringRef File = C.getArgs().MakeArgString(TC->getInputFilename(Input));
+ StringRef Arch = OffloadAction->getOffloadingArch()
+ ? OffloadAction->getOffloadingArch()
+ : TCArgs.getLastArgValue(options::OPT_march_EQ);
+ StringRef Kind =
+ Action::GetOffloadKindName(OffloadAction->getOffloadingDeviceKind());
+
+ ArgStringList Features;
+ SmallVector<StringRef> FeatureArgs;
+ getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features,
+ false);
+ llvm::copy_if(Features, std::back_inserter(FeatureArgs),
+ [](StringRef Arg) { return !Arg.starts_with("-target"); });
+
+ if (TC->getTriple().isAMDGPU()) {
+ for (StringRef Feature : llvm::split(Arch.split(':').second, ':')) {
+ FeatureArgs.emplace_back(
+ Args.MakeArgString(Feature.take_back() + Feature.drop_back()));
+ }
+ }
+
+ // TODO: We need to pass in the full target-id and handle it properly in the
+ // linker wrapper.
+ SmallVector<std::string> Parts{
+ "file=" + File.str(),
+ "triple=" + TC->getTripleString(),
+ "arch=" + Arch.str(),
+ "kind=" + Kind.str(),
+ };
+
+ if (TC->getDriver().isUsingLTO(/* IsOffload */ true) ||
+ TC->getTriple().isAMDGPU())
+ for (StringRef Feature : FeatureArgs)
+ Parts.emplace_back("feature=" + Feature.str());
+
+ CmdArgs.push_back(Args.MakeArgString("--image=" + llvm::join(Parts, ",")));
}
C.addCommand(std::make_unique<Command>(
@@ -8150,120 +8787,108 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const Driver &D = getToolChain().getDriver();
const llvm::Triple TheTriple = getToolChain().getTriple();
- auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
ArgStringList CmdArgs;
// Pass the CUDA path to the linker wrapper tool.
- for (auto &I : llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) {
- const ToolChain *TC = I.second;
- if (TC->getTriple().isNVPTX()) {
- CudaInstallationDetector CudaInstallation(D, TheTriple, Args);
- if (CudaInstallation.isValid())
- CmdArgs.push_back(Args.MakeArgString(
- "--cuda-path=" + CudaInstallation.getInstallPath()));
- break;
- }
- }
-
- if (D.isUsingLTO(/* IsOffload */ true)) {
- // Pass in target features for each toolchain.
- for (auto &I :
- llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) {
+ for (Action::OffloadKind Kind : {Action::OFK_Cuda, Action::OFK_OpenMP}) {
+ auto TCRange = C.getOffloadToolChains(Kind);
+ for (auto &I : llvm::make_range(TCRange.first, TCRange.second)) {
const ToolChain *TC = I.second;
- const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP);
- ArgStringList FeatureArgs;
- TC->addClangTargetOptions(TCArgs, FeatureArgs, Action::OFK_OpenMP);
- auto FeatureIt = llvm::find(FeatureArgs, "-target-feature");
- CmdArgs.push_back(Args.MakeArgString(
- "-target-feature=" + TC->getTripleString() + "=" + *(FeatureIt + 1)));
+ if (TC->getTriple().isNVPTX()) {
+ CudaInstallationDetector CudaInstallation(D, TheTriple, Args);
+ if (CudaInstallation.isValid())
+ CmdArgs.push_back(Args.MakeArgString(
+ "--cuda-path=" + CudaInstallation.getInstallPath()));
+ break;
+ }
}
+ }
- // Pass in the bitcode library to be linked during LTO.
- for (auto &I :
- llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) {
- const ToolChain *TC = I.second;
- const Driver &TCDriver = TC->getDriver();
- const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP);
- StringRef Arch = TCArgs.getLastArgValue(options::OPT_march_EQ);
-
- std::string BitcodeSuffix;
- if (TCArgs.hasFlag(options::OPT_fopenmp_target_new_runtime,
- options::OPT_fno_openmp_target_new_runtime, true))
- BitcodeSuffix += "new-";
- if (TC->getTriple().isNVPTX())
- BitcodeSuffix += "nvptx-";
- else if (TC->getTriple().isAMDGPU())
- BitcodeSuffix += "amdgpu-";
- BitcodeSuffix += Arch;
-
- ArgStringList BitcodeLibrary;
- addOpenMPDeviceRTL(TCDriver, TCArgs, BitcodeLibrary, BitcodeSuffix,
- TC->getTriple());
-
- if (!BitcodeLibrary.empty())
- CmdArgs.push_back(
- Args.MakeArgString("-target-library=" + TC->getTripleString() +
- "-" + Arch + "=" + BitcodeLibrary.back()));
- }
+ // Pass in the optimization level to use for LTO.
+ if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ StringRef OOpt;
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ OOpt = "3";
+ else if (A->getOption().matches(options::OPT_O)) {
+ OOpt = A->getValue();
+ if (OOpt == "g")
+ OOpt = "1";
+ else if (OOpt == "s" || OOpt == "z")
+ OOpt = "2";
+ } else if (A->getOption().matches(options::OPT_O0))
+ OOpt = "0";
+ if (!OOpt.empty())
+ CmdArgs.push_back(Args.MakeArgString(Twine("--opt-level=O") + OOpt));
+ }
- // Pass in the optimization level to use for LTO.
- if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- StringRef OOpt;
- if (A->getOption().matches(options::OPT_O4) ||
- A->getOption().matches(options::OPT_Ofast))
- OOpt = "3";
- else if (A->getOption().matches(options::OPT_O)) {
- OOpt = A->getValue();
- if (OOpt == "g")
- OOpt = "1";
- else if (OOpt == "s" || OOpt == "z")
- OOpt = "2";
- } else if (A->getOption().matches(options::OPT_O0))
- OOpt = "0";
- if (!OOpt.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-opt-level=O") + OOpt));
- }
- }
-
- CmdArgs.push_back("-host-triple");
- CmdArgs.push_back(Args.MakeArgString(TheTriple.getTriple()));
+ CmdArgs.push_back(
+ Args.MakeArgString("--host-triple=" + TheTriple.getTriple()));
if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("-v");
+ CmdArgs.push_back("--wrapper-verbose");
- // Add debug information if present.
if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- const Option &Opt = A->getOption();
- if (Opt.matches(options::OPT_gN_Group)) {
- if (Opt.matches(options::OPT_gline_directives_only) ||
- Opt.matches(options::OPT_gline_tables_only))
- CmdArgs.push_back("-gline-directives-only");
- } else
- CmdArgs.push_back("-g");
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("--device-debug");
+ }
+
+ // code-object-version=X needs to be passed to clang-linker-wrapper to ensure
+ // that it is used by lld.
+ if (const Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) {
+ CmdArgs.push_back(Args.MakeArgString("-mllvm"));
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("--amdhsa-code-object-version=") + A->getValue()));
}
for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
- CmdArgs.push_back(Args.MakeArgString("-ptxas-args=" + A));
+ CmdArgs.push_back(Args.MakeArgString("--ptxas-arg=" + A));
// Forward remarks passes to the LLVM backend in the wrapper.
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-pass-remarks=") + A->getValue()));
+ CmdArgs.push_back(Args.MakeArgString(Twine("--offload-opt=-pass-remarks=") +
+ A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-pass-remarks-missed=") + A->getValue()));
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("--offload-opt=-pass-remarks-missed=") + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-pass-remarks-analysis=") + A->getValue()));
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("--offload-opt=-pass-remarks-analysis=") + A->getValue()));
if (Args.getLastArg(options::OPT_save_temps_EQ))
- CmdArgs.push_back("-save-temps");
+ CmdArgs.push_back("--save-temps");
// Construct the link job so we can wrap around it.
Linker->ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput);
const auto &LinkCommand = C.getJobs().getJobs().back();
+ // Forward -Xoffload-linker<-triple> arguments to the device link job.
+ for (Arg *A : Args.filtered(options::OPT_Xoffload_linker)) {
+ StringRef Val = A->getValue(0);
+ if (Val.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("--device-linker=") + A->getValue(1)));
+ else
+ CmdArgs.push_back(Args.MakeArgString(
+ "--device-linker=" +
+ ToolChain::getOpenMPTriple(Val.drop_front()).getTriple() + "=" +
+ A->getValue(1)));
+ }
+ Args.ClaimAllArgs(options::OPT_Xoffload_linker);
+
+ // Embed bitcode instead of an object in JIT mode.
+ if (Args.hasFlag(options::OPT_fopenmp_target_jit,
+ options::OPT_fno_openmp_target_jit, false))
+ CmdArgs.push_back("--embed-bitcode");
+
+ // Forward `-mllvm` arguments to the LLVM invocations if present.
+ for (Arg *A : Args.filtered(options::OPT_mllvm)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(A->getValue());
+ A->claim();
+ }
+
// Add the linker arguments to be forwarded by the wrapper.
- CmdArgs.push_back("-linker-path");
- CmdArgs.push_back(LinkCommand->getExecutable());
+ CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") +
+ LinkCommand->getExecutable()));
CmdArgs.push_back("--");
for (const char *LinkArg : LinkCommand->getArguments())
CmdArgs.push_back(LinkArg);
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h
index 79407c9884d5..0f503c4bd1c4 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h
@@ -10,13 +10,13 @@
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H
#include "MSVC.h"
-#include "clang/Basic/DebugInfoOptions.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/Types.h"
-#include "llvm/ADT/Triple.h"
+#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
namespace clang {
class ObjCRuntime;
@@ -57,6 +57,8 @@ private:
bool KernelOrKext) const;
void AddARM64TargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
@@ -88,9 +90,7 @@ private:
RewriteKind rewrite) const;
void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType,
- llvm::opt::ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind *DebugInfoKind,
- bool *EmitCodeView) const;
+ llvm::opt::ArgStringList &CmdArgs) const;
mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr;
void DumpCompilationDatabase(Compilation &C, StringRef Filename,
@@ -123,6 +123,8 @@ class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
public:
ClangAs(const ToolChain &TC)
: Tool("clang::as", "clang integrated assembler", TC) {}
+ void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddX86TargetArgs(const llvm::opt::ArgList &Args,
@@ -157,11 +159,11 @@ public:
const char *LinkingOutput) const override;
};
-/// Offload wrapper tool.
-class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool {
+/// Offload binary tool.
+class LLVM_LIBRARY_VISIBILITY OffloadPackager final : public Tool {
public:
- OffloadWrapper(const ToolChain &TC)
- : Tool("offload wrapper", "clang-offload-wrapper", TC) {}
+ OffloadPackager(const ToolChain &TC)
+ : Tool("Offload::Packager", "clang-offload-packager", TC) {}
bool hasIntegratedCPP() const override { return false; }
void ConstructJob(Compilation &C, const JobAction &JA,
@@ -185,6 +187,12 @@ public:
const char *LinkingOutput) const override;
};
+enum class DwarfFissionKind { None, Split, Single };
+
+DwarfFissionKind getDebugFissionKind(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::Arg *&Arg);
+
} // end namespace tools
} // end namespace driver
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp
deleted file mode 100644
index 501e3a382ec1..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//===--- CloudABI.cpp - CloudABI ToolChain Implementations ------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "CloudABI.h"
-#include "CommonArgs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/InputInfo.h"
-#include "clang/Driver/Options.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Path.h"
-
-using namespace clang::driver;
-using namespace clang::driver::tools;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const ToolChain &ToolChain = getToolChain();
- const Driver &D = ToolChain.getDriver();
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- // CloudABI only supports static linkage.
- CmdArgs.push_back("-Bstatic");
- CmdArgs.push_back("--no-dynamic-linker");
-
- // Provide PIE linker flags in case PIE is default for the architecture.
- if (ToolChain.isPIEDefault(Args)) {
- CmdArgs.push_back("-pie");
- CmdArgs.push_back("-zrelro");
- }
-
- CmdArgs.push_back("--eh-frame-hdr");
- CmdArgs.push_back("--gc-sections");
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
-
- if (D.isUsingLTO()) {
- assert(!Inputs.empty() && "Must have at least one input.");
- addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
- D.getLTOMode() == LTOK_Thin);
- }
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (ToolChain.ShouldLinkCXXStdlib(Args))
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lcompiler_rt");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
-
- const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileCurCP(),
- Exec, CmdArgs, Inputs, Output));
-}
-
-// CloudABI - CloudABI tool chain which can call ld(1) directly.
-
-CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- SmallString<128> P(getDriver().Dir);
- llvm::sys::path::append(P, "..", getTriple().str(), "lib");
- getFilePaths().push_back(std::string(P.str()));
-}
-
-void CloudABI::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- SmallString<128> P(getDriver().Dir);
- llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1");
- addSystemInclude(DriverArgs, CC1Args, P.str());
-}
-
-void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- CmdArgs.push_back("-lunwind");
-}
-
-Tool *CloudABI::buildLinker() const {
- return new tools::cloudabi::Linker(*this);
-}
-
-bool CloudABI::isPIEDefault(const llvm::opt::ArgList &Args) const {
- // Only enable PIE on architectures that support PC-relative
- // addressing. PC-relative addressing is required, as the process
- // startup code must be able to relocate itself.
- switch (getTriple().getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::x86_64:
- return true;
- default:
- return false;
- }
-}
-
-SanitizerMask CloudABI::getSupportedSanitizers() const {
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::SafeStack;
- return Res;
-}
-
-SanitizerMask CloudABI::getDefaultSanitizers() const {
- return SanitizerKind::SafeStack;
-}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h
deleted file mode 100644
index 8856fe3dde6d..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//===--- CloudABI.h - CloudABI ToolChain Implementations --------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H
-
-#include "Gnu.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Driver/ToolChain.h"
-
-namespace clang {
-namespace driver {
-namespace tools {
-
-/// cloudabi -- Directly call GNU Binutils linker
-namespace cloudabi {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("cloudabi::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace cloudabi
-} // end namespace tools
-
-namespace toolchains {
-
-class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF {
-public:
- CloudABI(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- bool HasNativeLLVMSupport() const override { return true; }
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
-
- CXXStdlibType
- GetCXXStdlibType(const llvm::opt::ArgList &Args) const override {
- return ToolChain::CST_Libcxx;
- }
- void addLibCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
- SanitizerMask getSupportedSanitizers() const override;
- SanitizerMask getDefaultSanitizers() const override;
-
-protected:
- Tool *buildLinker() const override;
-};
-
-} // end namespace toolchains
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp
index dfcef2304040..2b916f000336 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -9,15 +9,22 @@
#include "CommonArgs.h"
#include "Arch/AArch64.h"
#include "Arch/ARM.h"
+#include "Arch/CSKY.h"
+#include "Arch/LoongArch.h"
#include "Arch/M68k.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
+#include "Arch/RISCV.h"
+#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "Arch/VE.h"
#include "Arch/X86.h"
#include "HIPAMD.h"
#include "Hexagon.h"
+#include "MSP430.h"
+#include "Solaris.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
@@ -39,6 +46,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -48,39 +56,180 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLParser.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/TargetParser.h"
+#include <optional>
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs) {
+static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Args.hasArg(clang::driver::options::OPT_pg) &&
+ !Args.hasArg(clang::driver::options::OPT_mfentry))
+ return true;
+
+ if (Triple.isAndroid()) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::riscv64:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ switch (Triple.getArch()) {
+ case llvm::Triple::xcore:
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ case llvm::Triple::msp430:
+ // XCore never wants frame pointers, regardless of OS.
+ // WebAssembly never wants frame pointers.
+ return false;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppcle:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::amdgcn:
+ case llvm::Triple::r600:
+ case llvm::Triple::csky:
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ return !clang::driver::tools::areOptimizationsEnabled(Args);
+ default:
+ break;
+ }
+
+ if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
+ return !clang::driver::tools::areOptimizationsEnabled(Args);
+ }
+
+ if (Triple.isOSLinux() || Triple.isOSHurd()) {
+ switch (Triple.getArch()) {
+ // Don't use a frame pointer on linux if optimizing for certain targets.
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::systemz:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return !clang::driver::tools::areOptimizationsEnabled(Args);
+ default:
+ return true;
+ }
+ }
+
+ if (Triple.isOSWindows()) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ return !clang::driver::tools::areOptimizationsEnabled(Args);
+ case llvm::Triple::x86_64:
+ return Triple.isOSBinFormatMachO();
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // Windows on ARM builds with FPO disabled to aid fast stack walking
+ return true;
+ default:
+ // All other supported Windows ISAs use xdata unwind information, so frame
+ // pointers are not generally useful.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return false;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // ARM Darwin targets require a frame pointer to be always present to aid
+ // offline debugging via backtraces.
+ return Triple.isOSDarwin();
+ }
+}
+
+clang::CodeGenOptions::FramePointerKind
+getFramePointerKind(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ // We have 4 states:
+ //
+ // 00) leaf retained, non-leaf retained
+ // 01) leaf retained, non-leaf omitted (this is invalid)
+ // 10) leaf omitted, non-leaf retained
+ // (what -momit-leaf-frame-pointer was designed for)
+ // 11) leaf omitted, non-leaf omitted
+ //
+ // "omit" options taking precedence over "no-omit" options is the only way
+ // to make 3 valid states representable
+ llvm::opt::Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer,
+ clang::driver::options::OPT_fno_omit_frame_pointer);
+
+ bool OmitFP = A && A->getOption().matches(
+ clang::driver::options::OPT_fomit_frame_pointer);
+ bool NoOmitFP = A && A->getOption().matches(
+ clang::driver::options::OPT_fno_omit_frame_pointer);
+ bool OmitLeafFP =
+ Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer,
+ clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
+ Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
+ (Triple.isAndroid() && Triple.isRISCV64()));
+ if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
+ (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
+ if (OmitLeafFP)
+ return clang::CodeGenOptions::FramePointerKind::NonLeaf;
+ return clang::CodeGenOptions::FramePointerKind::All;
+ }
+ return clang::CodeGenOptions::FramePointerKind::None;
+}
+
+static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs,
+ const StringRef PluginOptPrefix) {
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
- CmdArgs.push_back(Args.MakeArgString(Twine("--plugin-opt=-pass-remarks=") +
- A->getValue()));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-pass-remarks=" + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=-pass-remarks-missed=") + A->getValue()));
+ Twine(PluginOptPrefix) + "-pass-remarks-missed=" + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=-pass-remarks-analysis=") + A->getValue()));
+ Twine(PluginOptPrefix) + "-pass-remarks-analysis=" + A->getValue()));
}
static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
const llvm::Triple &Triple,
const InputInfo &Input,
- const InputInfo &Output) {
+ const InputInfo &Output,
+ const StringRef PluginOptPrefix) {
StringRef Format = "yaml";
if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
Format = A->getValue();
@@ -94,29 +243,47 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
assert(!F.empty() && "Cannot determine remarks output name.");
// Append "opt.ld.<format>" to the end of the file name.
- CmdArgs.push_back(
- Args.MakeArgString(Twine("--plugin-opt=opt-remarks-filename=") + F +
- Twine(".opt.ld.") + Format));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-filename=" + F +
+ ".opt.ld." + Format));
if (const Arg *A =
Args.getLastArg(options::OPT_foptimization_record_passes_EQ))
CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=opt-remarks-passes=") + A->getValue()));
+ Twine(PluginOptPrefix) + "opt-remarks-passes=" + A->getValue()));
- CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=opt-remarks-format=") + Format.data()));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-format=" + Format.data()));
}
static void renderRemarksHotnessOptions(const ArgList &Args,
- ArgStringList &CmdArgs) {
+ ArgStringList &CmdArgs,
+ const StringRef PluginOptPrefix) {
if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
options::OPT_fno_diagnostics_show_hotness, false))
- CmdArgs.push_back("--plugin-opt=opt-remarks-with-hotness");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-with-hotness"));
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ))
- CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=opt-remarks-hotness-threshold=") + A->getValue()));
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-hotness-threshold=" + A->getValue()));
+}
+
+static bool shouldIgnoreUnsupportedTargetFeature(const Arg &TargetFeatureArg,
+ llvm::Triple T,
+ StringRef Processor) {
+ // Warn no-cumode for AMDGCN processors not supporing WGP mode.
+ if (!T.isAMDGPU())
+ return false;
+ auto GPUKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Processor)
+ : llvm::AMDGPU::parseArchR600(Processor);
+ auto GPUFeatures = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(GPUKind)
+ : llvm::AMDGPU::getArchAttrR600(GPUKind);
+ if (GPUFeatures & llvm::AMDGPU::FEATURE_WGP)
+ return false;
+ return TargetFeatureArg.getOption().matches(options::OPT_mno_cumode);
}
void tools::addPathIfExists(const Driver &D, const Twine &Path,
@@ -125,46 +292,49 @@ void tools::addPathIfExists(const Driver &D, const Twine &Path,
Paths.push_back(Path.str());
}
-void tools::handleTargetFeaturesGroup(const ArgList &Args,
+void tools::handleTargetFeaturesGroup(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
std::vector<StringRef> &Features,
OptSpecifier Group) {
+ std::set<StringRef> Warned;
for (const Arg *A : Args.filtered(Group)) {
StringRef Name = A->getOption().getName();
A->claim();
// Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
+ assert(Name.starts_with("m") && "Invalid feature name.");
Name = Name.substr(1);
- bool IsNegative = Name.startswith("no-");
+ auto Proc = getCPUName(D, Args, Triple);
+ if (shouldIgnoreUnsupportedTargetFeature(*A, Triple, Proc)) {
+ if (Warned.count(Name) == 0) {
+ D.getDiags().Report(
+ clang::diag::warn_drv_unsupported_option_for_processor)
+ << A->getAsString(Args) << Proc;
+ Warned.insert(Name);
+ }
+ continue;
+ }
+
+ bool IsNegative = Name.starts_with("no-");
if (IsNegative)
Name = Name.substr(3);
+
Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
}
-std::vector<StringRef>
-tools::unifyTargetFeatures(const std::vector<StringRef> &Features) {
- std::vector<StringRef> UnifiedFeatures;
- // 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;
+SmallVector<StringRef>
+tools::unifyTargetFeatures(ArrayRef<StringRef> Features) {
+ // Only add a feature if it hasn't been seen before starting from the end.
+ SmallVector<StringRef> UnifiedFeatures;
+ llvm::DenseSet<StringRef> UsedFeatures;
+ for (StringRef Feature : llvm::reverse(Features)) {
+ if (UsedFeatures.insert(Feature.drop_front()).second)
+ UnifiedFeatures.insert(UnifiedFeatures.begin(), Feature);
}
- 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;
-
- UnifiedFeatures.push_back(Name);
- }
return UnifiedFeatures;
}
@@ -255,6 +425,10 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
continue;
}
+ // In some error cases, the input could be Nothing; skip those.
+ if (II.isNothing())
+ continue;
+
// Otherwise, this is a linker input argument.
const Arg &A = II.getInputArg();
@@ -263,22 +437,8 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext))
TC.AddCCKextLibArgs(Args, CmdArgs);
- else if (A.getOption().matches(options::OPT_z)) {
- // Pass -z prefix for gcc linker compatibility.
- A.claim();
- A.render(Args, CmdArgs);
- } else if (A.getOption().matches(options::OPT_b)) {
- const llvm::Triple &T = TC.getTriple();
- if (!T.isOSAIX()) {
- TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
- << A.getSpelling() << T.str();
- }
- // Pass -b prefix for AIX linker.
- A.claim();
- A.render(Args, CmdArgs);
- } else {
+ else
A.renderAsInput(Args, CmdArgs);
- }
}
}
@@ -292,11 +452,11 @@ void tools::addLinkerCompressDebugSectionsOption(
// argument.
if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) {
StringRef V = A->getValue();
- if (V == "none" || V == "zlib")
+ if (V == "none" || V == "zlib" || V == "zstd")
CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V));
else
TC.getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << V;
+ << A->getSpelling() << V;
}
}
@@ -315,6 +475,7 @@ void tools::AddTargetFeature(const ArgList &Args,
/// Get the (LLVM) name of the AMDGPU gpu we are targeting.
static std::string getAMDGPUTargetGPU(const llvm::Triple &T,
const ArgList &Args) {
+ Arg *MArch = Args.getLastArg(options::OPT_march_EQ);
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
auto GPUName = getProcessorFromTargetID(T, A->getValue());
return llvm::StringSwitch<std::string>(GPUName)
@@ -327,6 +488,8 @@ static std::string getAMDGPUTargetGPU(const llvm::Triple &T,
.Case("aruba", "cayman")
.Default(GPUName.str());
}
+ if (MArch)
+ return getProcessorFromTargetID(T, MArch->getValue()).str();
return "";
}
@@ -405,41 +568,30 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args,
case llvm::Triple::ppc:
case llvm::Triple::ppcle:
case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le: {
- std::string TargetCPUName = ppc::getPPCTargetCPU(Args);
- // LLVM may default to generating code for the native CPU,
- // but, like gcc, we default to a more generic option for
- // each architecture. (except on AIX)
- if (!TargetCPUName.empty())
- return TargetCPUName;
-
- if (T.isOSAIX())
- TargetCPUName = "pwr7";
- else if (T.getArch() == llvm::Triple::ppc64le)
- TargetCPUName = "ppc64le";
- else if (T.getArch() == llvm::Triple::ppc64)
- TargetCPUName = "ppc64";
- else
- TargetCPUName = "ppc";
+ case llvm::Triple::ppc64le:
+ return ppc::getPPCTargetCPU(D, Args, T);
- return TargetCPUName;
- }
+ case llvm::Triple::csky:
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ return A->getValue();
+ else if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ return A->getValue();
+ else
+ return "ck810";
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
+ return riscv::getRISCVTargetCPU(Args, T);
+
+ case llvm::Triple::bpfel:
+ case llvm::Triple::bpfeb:
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue();
return "";
- case llvm::Triple::bpfel:
- case llvm::Triple::bpfeb:
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue();
- if (T.getArch() == llvm::Triple::sparc && T.isOSSolaris())
- return "v9";
- return "";
+ return sparc::getSparcTargetCPU(D, Args, T);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
@@ -462,6 +614,103 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args,
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return std::string(getWebAssemblyTargetCPU(Args));
+
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ return loongarch::getLoongArchTargetCPU(Args, T);
+ }
+}
+
+static void getWebAssemblyTargetFeatures(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ handleTargetFeaturesGroup(D, Triple, Args, Features,
+ options::OPT_m_wasm_Features_Group);
+}
+
+void tools::getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ bool ForAS, bool IsAux) {
+ 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(D, Triple, Args, Features, ForAS);
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppcle:
+ 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(D, Args, Features);
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64_be:
+ aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ x86::getX86TargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::hexagon:
+ hexagon::getHexagonTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ getWebAssemblyTargetFeatures(D, Triple, 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, Triple, Args, Features);
+ break;
+ case llvm::Triple::nvptx:
+ case llvm::Triple::nvptx64:
+ NVPTX::getNVPTXTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::m68k:
+ m68k::getM68kTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::msp430:
+ msp430::getMSP430TargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::ve:
+ ve::getVETargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::csky:
+ csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features);
+ break;
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ loongarch::getLoongArchTargetFeatures(D, Triple, Args, Features);
+ break;
+ }
+
+ for (auto Feature : unifyTargetFeatures(Features)) {
+ CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature");
+ CmdArgs.push_back(Feature.data());
}
}
@@ -475,22 +724,58 @@ llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) {
return LtoJobsArg->getValue();
}
-// CloudABI uses -ffunction-sections and -fdata-sections by default.
+// PS4/PS5 uses -ffunction-sections and -fdata-sections by default.
bool tools::isUseSeparateSections(const llvm::Triple &Triple) {
- return Triple.getOS() == llvm::Triple::CloudABI;
+ return Triple.isPS();
+}
+
+bool tools::isTLSDESCEnabled(const ToolChain &TC,
+ const llvm::opt::ArgList &Args) {
+ const llvm::Triple &Triple = TC.getEffectiveTriple();
+ Arg *A = Args.getLastArg(options::OPT_mtls_dialect_EQ);
+ if (!A)
+ return Triple.hasDefaultTLSDESC();
+ StringRef V = A->getValue();
+ bool SupportedArgument = false, EnableTLSDESC = false;
+ bool Unsupported = !Triple.isOSBinFormatELF();
+ if (Triple.isRISCV()) {
+ SupportedArgument = V == "desc" || V == "trad";
+ EnableTLSDESC = V == "desc";
+ } else if (Triple.isX86()) {
+ SupportedArgument = V == "gnu";
+ } else {
+ Unsupported = true;
+ }
+ if (Unsupported) {
+ TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << Triple.getTriple();
+ } else if (!SupportedArgument) {
+ TC.getDriver().Diag(diag::err_drv_unsupported_option_argument_for_target)
+ << A->getSpelling() << V << Triple.getTriple();
+ }
+ return EnableTLSDESC;
}
void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs, const InputInfo &Output,
const InputInfo &Input, bool IsThinLTO) {
+ const bool IsOSAIX = ToolChain.getTriple().isOSAIX();
+ const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN();
const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
const Driver &D = ToolChain.getDriver();
+ const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects);
+ const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto);
if (llvm::sys::path::filename(Linker) != "ld.lld" &&
- llvm::sys::path::stem(Linker) != "ld.lld") {
+ llvm::sys::path::stem(Linker) != "ld.lld" &&
+ !ToolChain.getTriple().isOSOpenBSD()) {
// Tell the linker to load the plugin. This has to come before
- // AddLinkerInputs as gold requires -plugin to come before any -plugin-opt
- // that -Wl might forward.
- CmdArgs.push_back("-plugin");
+ // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to
+ // come before any -plugin-opt/-bplugin_opt that -Wl might forward.
+ const char *PluginPrefix = IsOSAIX ? "-bplugin:" : "";
+ const char *PluginName = IsOSAIX ? "/libLTO" : "/LLVMgold";
+
+ if (!IsOSAIX)
+ CmdArgs.push_back("-plugin");
#if defined(_WIN32)
const char *Suffix = ".dll";
@@ -501,10 +786,50 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
#endif
SmallString<1024> Plugin;
- llvm::sys::path::native(
- Twine(D.Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix,
- Plugin);
- CmdArgs.push_back(Args.MakeArgString(Plugin));
+ llvm::sys::path::native(Twine(D.Dir) +
+ "/../" CLANG_INSTALL_LIBDIR_BASENAME +
+ PluginName + Suffix,
+ Plugin);
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginPrefix) + Plugin));
+ } else {
+ // Tell LLD to find and use .llvm.lto section in regular relocatable object
+ // files
+ if (IsFatLTO)
+ CmdArgs.push_back("--fat-lto-objects");
+ }
+
+ const char *PluginOptPrefix = IsOSAIX ? "-bplugin_opt:" : "-plugin-opt=";
+ const char *ExtraDash = IsOSAIX ? "-" : "";
+ const char *ParallelismOpt = IsOSAIX ? "-threads=" : "jobs=";
+
+ // Note, this solution is far from perfect, better to encode it into IR
+ // metadata, but this may not be worth it, since it looks like aranges is on
+ // the way out.
+ if (Args.hasArg(options::OPT_gdwarf_aranges)) {
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-generate-arange-section"));
+ }
+
+ // Pass vector library arguments to LTO.
+ Arg *ArgVecLib = Args.getLastArg(options::OPT_fveclib);
+ if (ArgVecLib && ArgVecLib->getNumValues() == 1) {
+ // Map the vector library names from clang front-end to opt front-end. The
+ // values are taken from the TargetLibraryInfo class command line options.
+ std::optional<StringRef> OptVal =
+ llvm::StringSwitch<std::optional<StringRef>>(ArgVecLib->getValue())
+ .Case("Accelerate", "Accelerate")
+ .Case("LIBMVEC", "LIBMVEC-X86")
+ .Case("MASSV", "MASSV")
+ .Case("SVML", "SVML")
+ .Case("SLEEF", "sleefgnuabi")
+ .Case("Darwin_libsystem_m", "Darwin_libsystem_m")
+ .Case("ArmPL", "ArmPL")
+ .Case("none", "none")
+ .Default(std::nullopt);
+
+ if (OptVal)
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "-vector-library=" + OptVal.value()));
}
// Try to pass driver level flags relevant to LTO code generation down to
@@ -513,7 +838,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
// Handle flags for selecting CPU variants.
std::string CPU = getCPUName(D, Args, ToolChain.getTriple());
if (!CPU.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "mcpu=" + CPU));
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
// The optimization level matches
@@ -530,48 +856,140 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
OOpt = "2";
} else if (A->getOption().matches(options::OPT_O0))
OOpt = "0";
- if (!OOpt.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt));
+ if (!OOpt.empty()) {
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "O" + OOpt));
+ if (IsAMDGCN)
+ CmdArgs.push_back(Args.MakeArgString(Twine("--lto-CGO") + OOpt));
+ }
}
- if (Args.hasArg(options::OPT_gsplit_dwarf)) {
+ if (Args.hasArg(options::OPT_gsplit_dwarf))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "dwo_dir=" + Output.getFilename() + "_dwo"));
+
+ if (IsThinLTO && !IsOSAIX)
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "thinlto"));
+ else if (IsThinLTO && IsOSAIX)
+ CmdArgs.push_back(Args.MakeArgString(Twine("-bdbg:thinlto")));
+
+ // Matrix intrinsic lowering happens at link time with ThinLTO. Enable
+ // LowerMatrixIntrinsicsPass, which is transitively called by
+ // buildThinLTODefaultPipeline under EnableMatrix.
+ if ((IsThinLTO || IsFatLTO || IsUnifiedLTO) &&
+ Args.hasArg(options::OPT_fenable_matrix))
CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") +
- Output.getFilename() + "_dwo"));
- }
-
- if (IsThinLTO)
- CmdArgs.push_back("-plugin-opt=thinlto");
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-matrix"));
StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty())
- CmdArgs.push_back(
- Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism)));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ ParallelismOpt + Parallelism));
+
+ // Pass down GlobalISel options.
+ if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel,
+ options::OPT_fno_global_isel)) {
+ // Parsing -fno-global-isel explicitly gives architectures that enable GISel
+ // by default a chance to disable it.
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "-global-isel=" +
+ (A->getOption().matches(options::OPT_fglobal_isel) ? "1" : "0")));
+ }
// If an explicit debugger tuning argument appeared, pass it along.
- if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
- options::OPT_ggdbN_Group)) {
+ if (Arg *A =
+ Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
if (A->getOption().matches(options::OPT_glldb))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=lldb"));
else if (A->getOption().matches(options::OPT_gsce))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=sce");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=sce"));
else if (A->getOption().matches(options::OPT_gdbx))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=dbx");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=dbx"));
else
- CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=gdb"));
+ }
+
+ if (IsOSAIX) {
+ if (!ToolChain.useIntegratedAs())
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-no-integrated-as=1"));
+
+ // On AIX, clang assumes strict-dwarf is true if any debug option is
+ // specified, unless it is told explicitly not to assume so.
+ Arg *A = Args.getLastArg(options::OPT_g_Group);
+ bool EnableDebugInfo = A && !A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_ggdb0);
+ if (EnableDebugInfo && Args.hasFlag(options::OPT_gstrict_dwarf,
+ options::OPT_gno_strict_dwarf, true))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-strict-dwarf=true"));
+
+ for (const Arg *A : Args.filtered_reverse(options::OPT_mabi_EQ)) {
+ StringRef V = A->getValue();
+ if (V == "vec-default")
+ break;
+ if (V == "vec-extabi") {
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-vec-extabi"));
+ break;
+ }
+ }
}
bool UseSeparateSections =
isUseSeparateSections(ToolChain.getEffectiveTriple());
if (Args.hasFlag(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections, UseSeparateSections)) {
- CmdArgs.push_back("-plugin-opt=-function-sections");
- }
+ options::OPT_fno_function_sections, UseSeparateSections))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=1"));
+ else if (Args.hasArg(options::OPT_fno_function_sections))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=0"));
+ bool DataSectionsTurnedOff = false;
if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
UseSeparateSections)) {
- CmdArgs.push_back("-plugin-opt=-data-sections");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=1"));
+ } else if (Args.hasArg(options::OPT_fno_data_sections)) {
+ DataSectionsTurnedOff = true;
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=0"));
+ }
+
+ if (Args.hasArg(options::OPT_mxcoff_roptr) ||
+ Args.hasArg(options::OPT_mno_xcoff_roptr)) {
+ bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr,
+ options::OPT_mno_xcoff_roptr, false);
+ StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr";
+
+ if (!IsOSAIX)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << OptStr << ToolChain.getTriple().str();
+
+ if (HasRoptr) {
+ // The data sections option is on by default on AIX. We only need to error
+ // out when -fno-data-sections is specified explicitly to turn off data
+ // sections.
+ if (DataSectionsTurnedOff)
+ D.Diag(diag::err_roptr_requires_data_sections);
+
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-mxcoff-roptr"));
+ }
+ }
+
+ // Pass an option to enable split machine functions.
+ if (auto *A = Args.getLastArg(options::OPT_fsplit_machine_functions,
+ options::OPT_fno_split_machine_functions)) {
+ if (A->getOption().matches(options::OPT_fsplit_machine_functions))
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-split-machine-functions"));
}
if (Arg *A = getLastProfileSampleUseArg(Args)) {
@@ -579,101 +997,126 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
if (!llvm::sys::fs::exists(FName))
D.Diag(diag::err_drv_no_such_file) << FName;
else
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "sample-profile=" + FName));
}
- auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
- options::OPT_fcs_profile_generate_EQ,
- options::OPT_fno_profile_generate);
- if (CSPGOGenerateArg &&
- CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
- CSPGOGenerateArg = nullptr;
-
- auto *ProfileUseArg = getLastProfileUseArg(Args);
-
- if (CSPGOGenerateArg) {
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate"));
+ if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) {
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-generate"));
if (CSPGOGenerateArg->getOption().matches(
options::OPT_fcs_profile_generate_EQ)) {
SmallString<128> Path(CSPGOGenerateArg->getValue());
llvm::sys::path::append(Path, "default_%m.profraw");
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-path=" + Path));
} else
CmdArgs.push_back(
- Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw"));
- } else if (ProfileUseArg) {
+ Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-path=default_%m.profraw"));
+ } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) {
SmallString<128> Path(
ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
if (Path.empty() || llvm::sys::fs::is_directory(Path))
llvm::sys::path::append(Path, "default.profdata");
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") +
- Path));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-path=" + Path));
}
- // Pass an option to enable/disable the new pass manager.
- if (auto *A = Args.getLastArg(options::OPT_flegacy_pass_manager,
- options::OPT_fno_legacy_pass_manager)) {
- if (A->getOption().matches(options::OPT_flegacy_pass_manager))
- CmdArgs.push_back("-plugin-opt=legacy-pass-manager");
+ // This controls whether or not we perform JustMyCode instrumentation.
+ if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) {
+ if (ToolChain.getEffectiveTriple().isOSBinFormatELF())
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-enable-jmc-instrument"));
else
- CmdArgs.push_back("-plugin-opt=new-pass-manager");
+ D.Diag(clang::diag::warn_drv_fjmc_for_elf_only);
}
+ if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
+ ToolChain.getTriple().hasDefaultEmulatedTLS())) {
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-emulated-tls"));
+ }
+ if (isTLSDESCEnabled(ToolChain, Args))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-tlsdesc"));
+
+ if (Args.hasFlag(options::OPT_fstack_size_section,
+ options::OPT_fno_stack_size_section, false))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section"));
+
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty())
CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile));
+ Args.MakeArgString(Twine(PluginOptPrefix) + "stats-file=" + StatsFile));
+
+ // Setup crash diagnostics dir.
+ if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "-crash-diagnostics-dir=" + A->getValue()));
- addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true);
+ addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true, PluginOptPrefix);
// Handle remark diagnostics on screen options: '-Rpass-*'.
- renderRpassOptions(Args, CmdArgs);
+ renderRpassOptions(Args, CmdArgs, PluginOptPrefix);
// Handle serialized remarks options: '-fsave-optimization-record'
// and '-foptimization-record-*'.
if (willEmitRemarks(Args))
renderRemarksOptions(Args, CmdArgs, ToolChain.getEffectiveTriple(), Input,
- Output);
+ Output, PluginOptPrefix);
// Handle remarks hotness/threshold related options.
- renderRemarksHotnessOptions(Args, CmdArgs);
+ renderRemarksHotnessOptions(Args, CmdArgs, PluginOptPrefix);
addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(),
- /*IsLTO=*/true);
+ /*IsLTO=*/true, PluginOptPrefix);
}
-void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
- const ArgList &Args,
- ArgStringList &CmdArgs) {
+/// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the
+/// LLVM C library for GPUs.
+static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (Args.hasArg(options::OPT_nogpulib) || Args.hasArg(options::OPT_nolibc))
+ return;
- if (Args.hasFlag(options::OPT_fopenmp_implicit_rpath,
- options::OPT_fno_openmp_implicit_rpath, true)) {
- // Default to clang lib / lib64 folder, i.e. the same location as device
- // runtime
- SmallString<256> DefaultLibPath =
- llvm::sys::path::parent_path(TC.getDriver().Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back(Args.MakeArgString(DefaultLibPath));
+ // Check the resource directory for the LLVM libc GPU declarations. If it's
+ // found we can assume that LLVM was built with support for the GPU libc.
+ SmallString<256> LibCDecls(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(LibCDecls, "include", "llvm_libc_wrappers",
+ "llvm-libc-decls");
+ bool HasLibC = llvm::sys::fs::exists(LibCDecls) &&
+ llvm::sys::fs::is_directory(LibCDecls);
+ if (Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC)) {
+ CmdArgs.push_back("-lcgpu");
+ CmdArgs.push_back("-lmgpu");
}
}
+void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
+ const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ // Default to clang lib / lib64 folder, i.e. the same location as device
+ // runtime.
+ SmallString<256> DefaultLibPath =
+ llvm::sys::path::parent_path(TC.getDriver().Dir);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
+ CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
+}
+
void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- // Enable -frtlib-add-rpath by default for the case of VE.
- const bool IsVE = TC.getTriple().isVE();
- bool DefaultValue = IsVE;
if (!Args.hasFlag(options::OPT_frtlib_add_rpath,
- options::OPT_fno_rtlib_add_rpath, DefaultValue))
+ options::OPT_fno_rtlib_add_rpath, false))
return;
- std::string CandidateRPath = TC.getArchSpecificLibPath();
- if (TC.getVFS().exists(CandidateRPath)) {
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back(Args.MakeArgString(CandidateRPath));
+ for (const auto &CandidateRPath : TC.getArchSpecificLibPaths()) {
+ if (TC.getVFS().exists(CandidateRPath)) {
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back(Args.MakeArgString(CandidateRPath));
+ }
}
}
@@ -716,14 +1159,155 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
if (IsOffloadingHost)
CmdArgs.push_back("-lomptarget");
- addArchSpecificRPath(TC, Args, CmdArgs);
+ if (IsOffloadingHost && !Args.hasArg(options::OPT_nogpulib))
+ CmdArgs.push_back("-lomptarget.devicertl");
+
+ if (IsOffloadingHost)
+ addOpenMPDeviceLibC(TC, Args, CmdArgs);
- if (RTKind == Driver::OMPRT_OMP)
- addOpenMPRuntimeSpecificRPath(TC, Args, CmdArgs);
+ addArchSpecificRPath(TC, Args, CmdArgs);
+ addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs);
return true;
}
+/// Determines if --whole-archive is active in the list of arguments.
+static bool isWholeArchivePresent(const ArgList &Args) {
+ bool WholeArchiveActive = false;
+ for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA)) {
+ if (Arg) {
+ for (StringRef ArgValue : Arg->getValues()) {
+ if (ArgValue == "--whole-archive")
+ WholeArchiveActive = true;
+ if (ArgValue == "--no-whole-archive")
+ WholeArchiveActive = false;
+ }
+ }
+ }
+
+ return WholeArchiveActive;
+}
+
+/// Determine if driver is invoked to create a shared object library (-static)
+static bool isSharedLinkage(const ArgList &Args) {
+ return Args.hasArg(options::OPT_shared);
+}
+
+/// Determine if driver is invoked to create a static object library (-shared)
+static bool isStaticLinkage(const ArgList &Args) {
+ return Args.hasArg(options::OPT_static);
+}
+
+/// Add Fortran runtime libs for MSVC
+static void addFortranRuntimeLibsMSVC(const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+ if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
+ RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
+ .Case("static", options::OPT__SLASH_MT)
+ .Case("static_dbg", options::OPT__SLASH_MTd)
+ .Case("dll", options::OPT__SLASH_MD)
+ .Case("dll_dbg", options::OPT__SLASH_MDd)
+ .Default(options::OPT__SLASH_MT);
+ }
+ switch (RTOptionID) {
+ case options::OPT__SLASH_MT:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib");
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib");
+ break;
+ case options::OPT__SLASH_MD:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib");
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib");
+ break;
+ }
+}
+
+// Add FortranMain runtime lib
+static void addFortranMain(const ToolChain &TC, const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ // 0. Shared-library linkage
+ // If we are attempting to link a library, we should not add
+ // -lFortran_main.a to the link line, as the `main` symbol is not
+ // required for a library and should also be provided by one of
+ // the translation units of the code that this shared library
+ // will be linked against eventually.
+ if (isSharedLinkage(Args) || isStaticLinkage(Args)) {
+ return;
+ }
+
+ // 1. MSVC
+ if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
+ addFortranRuntimeLibsMSVC(Args, CmdArgs);
+ return;
+ }
+
+ // 2. GNU and similar
+ const Driver &D = TC.getDriver();
+ const char *FortranMainLinkFlag = "-lFortran_main";
+
+ // Warn if the user added `-lFortran_main` - this library is an implementation
+ // detail of Flang and should be handled automaticaly by the driver.
+ for (const char *arg : CmdArgs) {
+ if (strncmp(arg, FortranMainLinkFlag, strlen(FortranMainLinkFlag)) == 0)
+ D.Diag(diag::warn_drv_deprecated_custom)
+ << FortranMainLinkFlag
+ << "see the Flang driver documentation for correct usage";
+ }
+
+ // The --whole-archive option needs to be part of the link line to make
+ // sure that the main() function from Fortran_main.a is pulled in by the
+ // linker. However, it shouldn't be used if it's already active.
+ // TODO: Find an equivalent of `--whole-archive` for Darwin and AIX.
+ if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX() &&
+ !TC.getTriple().isOSAIX()) {
+ CmdArgs.push_back("--whole-archive");
+ CmdArgs.push_back(FortranMainLinkFlag);
+ CmdArgs.push_back("--no-whole-archive");
+ return;
+ }
+
+ CmdArgs.push_back(FortranMainLinkFlag);
+}
+
+/// Add Fortran runtime libs
+void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ // 1. Link FortranMain
+ // FortranMain depends on FortranRuntime, so needs to be listed first. If
+ // -fno-fortran-main has been passed, skip linking Fortran_main.a
+ if (!Args.hasArg(options::OPT_no_fortran_main))
+ addFortranMain(TC, Args, CmdArgs);
+
+ // 2. Link FortranRuntime and FortranDecimal
+ // These are handled earlier on Windows by telling the frontend driver to
+ // add the correct libraries to link against as dependents in the object
+ // file.
+ if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) {
+ CmdArgs.push_back("-lFortranRuntime");
+ CmdArgs.push_back("-lFortranDecimal");
+ }
+}
+
+void tools::addFortranRuntimeLibraryPath(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ ArgStringList &CmdArgs) {
+ // Default to the <driver-path>/../lib directory. This works fine on the
+ // platforms that we have tested so far. We will probably have to re-fine
+ // this in the future. In particular, on some platforms, we may need to use
+ // lib64 instead of lib.
+ SmallString<256> DefaultLibPath =
+ llvm::sys::path::parent_path(TC.getDriver().Dir);
+ llvm::sys::path::append(DefaultLibPath, "lib");
+ if (TC.getTriple().isKnownWindowsMSVCEnvironment())
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath));
+ else
+ CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
+}
+
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, StringRef Sanitizer,
bool IsShared, bool IsWhole) {
@@ -744,9 +1328,11 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs,
StringRef Sanitizer) {
+ bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args);
+
// Solaris ld defaults to --export-dynamic behaviour but doesn't support
// the option, so don't try to pass it.
- if (TC.getTriple().getOS() == llvm::Triple::Solaris)
+ if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd)
return true;
SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer));
if (llvm::sys::fs::exists(SanRT + ".syms")) {
@@ -756,32 +1342,36 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
return false;
}
-const char *tools::getAsNeededOption(const ToolChain &TC, bool as_needed) {
+void tools::addAsNeededOption(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ bool as_needed) {
assert(!TC.getTriple().isOSAIX() &&
"AIX linker does not support any form of --as-needed option yet.");
+ bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args);
// While the Solaris 11.2 ld added --as-needed/--no-as-needed as aliases
// for the native forms -z ignore/-z record, they are missing in Illumos,
// so always use the native form.
- if (TC.getTriple().isOSSolaris())
- return as_needed ? "-zignore" : "-zrecord";
- else
- return as_needed ? "--as-needed" : "--no-as-needed";
+ // GNU ld doesn't support -z ignore/-z record, so don't use them even on
+ // Solaris.
+ if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back(as_needed ? "ignore" : "record");
+ } else {
+ CmdArgs.push_back(as_needed ? "--as-needed" : "--no-as-needed");
+ }
}
void tools::linkSanitizerRuntimeDeps(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
ArgStringList &CmdArgs) {
- // Fuchsia never needs these. Any sanitizer runtimes with system
- // dependencies use the `.deplibs` feature instead.
- if (TC.getTriple().isOSFuchsia())
- return;
-
// Force linking against the system libraries sanitizers depends on
// (see PR15823 why this is necessary).
- CmdArgs.push_back(getAsNeededOption(TC, false));
+ addAsNeededOption(TC, Args, CmdArgs, false);
// There's no libpthread or librt on RTEMS & Android.
if (TC.getTriple().getOS() != llvm::Triple::RTEMS &&
- !TC.getTriple().isAndroid()) {
+ !TC.getTriple().isAndroid() && !TC.getTriple().isOHOSFamily()) {
CmdArgs.push_back("-lpthread");
if (!TC.getTriple().isOSOpenBSD())
CmdArgs.push_back("-lrt");
@@ -797,6 +1387,12 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC,
TC.getTriple().isOSNetBSD() ||
TC.getTriple().isOSOpenBSD())
CmdArgs.push_back("-lexecinfo");
+ // There is no libresolv on Android, FreeBSD, OpenBSD, etc. On musl
+ // libresolv.a, even if exists, is an empty archive to satisfy POSIX -lresolv
+ // requirement.
+ if (TC.getTriple().isOSLinux() && !TC.getTriple().isAndroid() &&
+ !TC.getTriple().isMusl())
+ CmdArgs.push_back("-lresolv");
}
static void
@@ -809,40 +1405,39 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
// Collect shared runtimes.
if (SanArgs.needsSharedRt()) {
- if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsAsanRt()) {
SharedRuntimes.push_back("asan");
if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
HelperStaticRuntimes.push_back("asan-preinit");
}
- if (SanArgs.needsMemProfRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsMemProfRt()) {
SharedRuntimes.push_back("memprof");
if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
HelperStaticRuntimes.push_back("memprof-preinit");
}
- if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsUbsanRt()) {
if (SanArgs.requiresMinimalRuntime())
SharedRuntimes.push_back("ubsan_minimal");
else
SharedRuntimes.push_back("ubsan_standalone");
}
- if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
- if (SanArgs.requiresMinimalRuntime())
- SharedRuntimes.push_back("scudo_minimal");
- else
- SharedRuntimes.push_back("scudo");
+ if (SanArgs.needsScudoRt()) {
+ SharedRuntimes.push_back("scudo_standalone");
}
- if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
+ if (SanArgs.needsTsanRt())
SharedRuntimes.push_back("tsan");
- if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt())
SharedRuntimes.push_back("hwasan_aliases");
else
SharedRuntimes.push_back("hwasan");
+ if (!Args.hasArg(options::OPT_shared))
+ HelperStaticRuntimes.push_back("hwasan-preinit");
}
}
// The stats_client library is also statically linked into DSOs.
- if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes())
+ if (SanArgs.needsStatsRt())
StaticRuntimes.push_back("stats_client");
// Always link the static runtime regardless of DSO or executable.
@@ -858,20 +1453,19 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
// Each static runtime that has a DSO counterpart above is excluded below,
// but runtimes that exist only as static are not affected by needsSharedRt.
- if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
+ if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt()) {
StaticRuntimes.push_back("asan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("asan_cxx");
}
- if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt() &&
- SanArgs.linkRuntimes()) {
+ if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) {
StaticRuntimes.push_back("memprof");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("memprof_cxx");
}
- if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
+ if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt()) {
StaticRuntimes.push_back("hwasan_aliases");
if (SanArgs.linkCXXRuntimes())
@@ -882,22 +1476,21 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("hwasan_cxx");
}
}
- if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes())
+ if (SanArgs.needsDfsanRt())
StaticRuntimes.push_back("dfsan");
- if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes())
+ if (SanArgs.needsLsanRt())
StaticRuntimes.push_back("lsan");
- if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsMsanRt()) {
StaticRuntimes.push_back("msan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("msan_cxx");
}
- if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt() &&
- SanArgs.linkRuntimes()) {
+ if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt()) {
StaticRuntimes.push_back("tsan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("tsan_cxx");
}
- if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) {
+ if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
if (SanArgs.requiresMinimalRuntime()) {
StaticRuntimes.push_back("ubsan_minimal");
} else {
@@ -906,33 +1499,27 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("ubsan_standalone_cxx");
}
}
- if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsSafeStackRt()) {
NonWholeStaticRuntimes.push_back("safestack");
RequiredSymbols.push_back("__safestack_init");
}
- if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes())) {
- if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes())
+ if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt())) {
+ if (SanArgs.needsCfiRt())
StaticRuntimes.push_back("cfi");
- if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsCfiDiagRt()) {
StaticRuntimes.push_back("cfi_diag");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("ubsan_standalone_cxx");
}
}
- if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) {
+ if (SanArgs.needsStatsRt()) {
NonWholeStaticRuntimes.push_back("stats");
RequiredSymbols.push_back("__sanitizer_stats_register");
}
- if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
- if (SanArgs.requiresMinimalRuntime()) {
- StaticRuntimes.push_back("scudo_minimal");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("scudo_cxx_minimal");
- } else {
- StaticRuntimes.push_back("scudo");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("scudo_cxx");
- }
+ if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt()) {
+ StaticRuntimes.push_back("scudo_standalone");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("scudo_standalone_cxx");
}
}
@@ -940,13 +1527,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
// C runtime, etc). Returns true if sanitizer system deps need to be linked in.
bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
+ const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
- collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
- NonWholeStaticRuntimes, HelperStaticRuntimes,
- RequiredSymbols);
+ if (SanArgs.linkRuntimes()) {
+ collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
+ NonWholeStaticRuntimes, HelperStaticRuntimes,
+ RequiredSymbols);
+ }
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
// Inject libfuzzer dependencies.
if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() &&
!Args.hasArg(options::OPT_shared)) {
@@ -991,6 +1580,19 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
CmdArgs.push_back("--export-dynamic-symbol=__cfi_check");
+ if (SanArgs.hasMemTag()) {
+ if (!TC.getTriple().isAndroid()) {
+ TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << "-fsanitize=memtag*" << TC.getTriple().str();
+ }
+ CmdArgs.push_back(
+ Args.MakeArgString("--android-memtag-mode=" + SanArgs.getMemtagMode()));
+ if (SanArgs.hasMemtagHeap())
+ CmdArgs.push_back("--android-memtag-heap");
+ if (SanArgs.hasMemtagStack())
+ CmdArgs.push_back("--android-memtag-stack");
+ }
+
return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty();
}
@@ -999,19 +1601,21 @@ bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringLis
return false;
if (TC.getXRayArgs().needsXRayRt()) {
- CmdArgs.push_back("-whole-archive");
+ CmdArgs.push_back("--whole-archive");
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray"));
for (const auto &Mode : TC.getXRayArgs().modeList())
CmdArgs.push_back(TC.getCompilerRTArgString(Args, Mode));
- CmdArgs.push_back("-no-whole-archive");
+ CmdArgs.push_back("--no-whole-archive");
return true;
}
return false;
}
-void tools::linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) {
- CmdArgs.push_back(getAsNeededOption(TC, false));
+void tools::linkXRayRuntimeDeps(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ ArgStringList &CmdArgs) {
+ addAsNeededOption(TC, Args, CmdArgs, false);
CmdArgs.push_back("-lpthread");
if (!TC.getTriple().isOSOpenBSD())
CmdArgs.push_back("-lrt");
@@ -1040,26 +1644,27 @@ const char *tools::SplitDebugName(const JobAction &JA, const ArgList &Args,
F += ".dwo";
};
if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ))
- if (StringRef(A->getValue()) == "single")
+ if (StringRef(A->getValue()) == "single" && Output.isFilename())
return Args.MakeArgString(Output.getFilename());
- Arg *FinalOutput = Args.getLastArg(options::OPT_o);
- if (FinalOutput && Args.hasArg(options::OPT_c)) {
- SmallString<128> T(FinalOutput->getValue());
- llvm::sys::path::remove_filename(T);
- llvm::sys::path::append(T, llvm::sys::path::stem(FinalOutput->getValue()));
- AddPostfix(T);
- return Args.MakeArgString(T);
+ SmallString<128> T;
+ if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) {
+ T = A->getValue();
} else {
- // Use the compilation dir.
- Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
- options::OPT_fdebug_compilation_dir_EQ);
- SmallString<128> T(A ? A->getValue() : "");
- SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput()));
- AddPostfix(F);
- T += F;
- return Args.MakeArgString(T);
+ Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o);
+ if (FinalOutput && Args.hasArg(options::OPT_c)) {
+ T = FinalOutput->getValue();
+ llvm::sys::path::remove_filename(T);
+ llvm::sys::path::append(T,
+ llvm::sys::path::stem(FinalOutput->getValue()));
+ AddPostfix(T);
+ return Args.MakeArgString(T);
+ }
}
+
+ T += llvm::sys::path::stem(Input.getBaseInput());
+ AddPostfix(T);
+ return Args.MakeArgString(T);
}
void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
@@ -1101,6 +1706,17 @@ void tools::claimNoWarnArgs(const ArgList &Args) {
Args.ClaimAllArgs(options::OPT_fno_lto);
}
+Arg *tools::getLastCSProfileGenerateArg(const ArgList &Args) {
+ auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
+ options::OPT_fcs_profile_generate_EQ,
+ options::OPT_fno_profile_generate);
+ if (CSPGOGenerateArg &&
+ CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
+ CSPGOGenerateArg = nullptr;
+
+ return CSPGOGenerateArg;
+}
+
Arg *tools::getLastProfileUseArg(const ArgList &Args) {
auto *ProfileUseArg = Args.getLastArg(
options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ,
@@ -1130,6 +1746,24 @@ Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) {
options::OPT_fauto_profile_EQ);
}
+const char *tools::RelocationModelName(llvm::Reloc::Model Model) {
+ switch (Model) {
+ case llvm::Reloc::Static:
+ return "static";
+ case llvm::Reloc::PIC_:
+ return "pic";
+ case llvm::Reloc::DynamicNoPIC:
+ return "dynamic-no-pic";
+ case llvm::Reloc::ROPI:
+ return "ropi";
+ case llvm::Reloc::RWPI:
+ return "rwpi";
+ case llvm::Reloc::ROPI_RWPI:
+ return "ropi-rwpi";
+ }
+ llvm_unreachable("Unknown Reloc::Model kind");
+}
+
/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then,
/// smooshes them together with platform defaults, to decide whether
/// this compile should be using PIC mode or not. Returns a tuple of
@@ -1175,6 +1809,10 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
}
}
+ // OHOS-specific defaults for PIC/PIE
+ if (Triple.isOHOSFamily() && Triple.getArch() == llvm::Triple::aarch64)
+ PIC = true;
+
// OpenBSD-specific defaults for PIE
if (Triple.isOSOpenBSD()) {
switch (ToolChain.getArch()) {
@@ -1197,10 +1835,6 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
}
}
- // AMDGPU-specific defaults for PIC.
- if (Triple.getArch() == llvm::Triple::amdgcn)
- PIC = true;
-
// The last argument relating to either PIC or PIE wins, and no
// other argument is used. If the last argument is any flavor of the
// '-fno-...' arguments, both PIC and PIE are disabled. Any PIE
@@ -1233,30 +1867,31 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC);
} else {
PIE = PIC = false;
- if (EffectiveTriple.isPS4CPU()) {
+ if (EffectiveTriple.isPS()) {
Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ);
StringRef Model = ModelArg ? ModelArg->getValue() : "";
if (Model != "kernel") {
PIC = true;
- ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic)
- << LastPICArg->getSpelling();
+ ToolChain.getDriver().Diag(diag::warn_drv_ps_force_pic)
+ << LastPICArg->getSpelling()
+ << (EffectiveTriple.isPS4() ? "PS4" : "PS5");
}
}
}
}
}
- // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the
- // PIC level would've been set to level 1, force it back to level 2 PIC
+ // Introduce a Darwin and PS4/PS5-specific hack. If the default is PIC, but
+ // the PIC level would've been set to level 1, force it back to level 2 PIC
// instead.
- if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU()))
+ if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS()))
IsPICLevelTwo |= ToolChain.isPICDefault();
// This kernel flags are a trump-card: they will disable PIC/PIE
// generation, independent of the argument order.
if (KernelOrKext &&
((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) &&
- !EffectiveTriple.isWatchOS()))
+ !EffectiveTriple.isWatchOS() && !EffectiveTriple.isDriverKit()))
PIC = PIE = false;
if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
@@ -1374,7 +2009,49 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC,
return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value;
}
-unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC,
+void tools::addDebugInfoKind(
+ ArgStringList &CmdArgs, llvm::codegenoptions::DebugInfoKind DebugInfoKind) {
+ switch (DebugInfoKind) {
+ case llvm::codegenoptions::DebugDirectivesOnly:
+ CmdArgs.push_back("-debug-info-kind=line-directives-only");
+ break;
+ case llvm::codegenoptions::DebugLineTablesOnly:
+ CmdArgs.push_back("-debug-info-kind=line-tables-only");
+ break;
+ case llvm::codegenoptions::DebugInfoConstructor:
+ CmdArgs.push_back("-debug-info-kind=constructor");
+ break;
+ case llvm::codegenoptions::LimitedDebugInfo:
+ CmdArgs.push_back("-debug-info-kind=limited");
+ break;
+ case llvm::codegenoptions::FullDebugInfo:
+ CmdArgs.push_back("-debug-info-kind=standalone");
+ break;
+ case llvm::codegenoptions::UnusedTypeInfo:
+ CmdArgs.push_back("-debug-info-kind=unused-types");
+ break;
+ default:
+ break;
+ }
+}
+
+// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
+// to the corresponding DebugInfoKind.
+llvm::codegenoptions::DebugInfoKind tools::debugLevelToInfoKind(const Arg &A) {
+ assert(A.getOption().matches(options::OPT_gN_Group) &&
+ "Not a -g option that specifies a debug-info level");
+ if (A.getOption().matches(options::OPT_g0) ||
+ A.getOption().matches(options::OPT_ggdb0))
+ return llvm::codegenoptions::NoDebugInfo;
+ if (A.getOption().matches(options::OPT_gline_tables_only) ||
+ A.getOption().matches(options::OPT_ggdb1))
+ return llvm::codegenoptions::DebugLineTablesOnly;
+ if (A.getOption().matches(options::OPT_gline_directives_only))
+ return llvm::codegenoptions::DebugDirectivesOnly;
+ return llvm::codegenoptions::DebugInfoConstructor;
+}
+
+static unsigned ParseDebugDefaultVersion(const ToolChain &TC,
const ArgList &Args) {
const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version);
@@ -1389,6 +2066,34 @@ unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC,
return Value;
}
+unsigned tools::DwarfVersionNum(StringRef ArgValue) {
+ return llvm::StringSwitch<unsigned>(ArgValue)
+ .Case("-gdwarf-2", 2)
+ .Case("-gdwarf-3", 3)
+ .Case("-gdwarf-4", 4)
+ .Case("-gdwarf-5", 5)
+ .Default(0);
+}
+
+const Arg *tools::getDwarfNArg(const ArgList &Args) {
+ return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
+ options::OPT_gdwarf_4, options::OPT_gdwarf_5,
+ options::OPT_gdwarf);
+}
+
+unsigned tools::getDwarfVersion(const ToolChain &TC,
+ const llvm::opt::ArgList &Args) {
+ unsigned DwarfVersion = ParseDebugDefaultVersion(TC, Args);
+ if (const Arg *GDwarfN = getDwarfNArg(Args))
+ if (int N = DwarfVersionNum(GDwarfN->getSpelling()))
+ DwarfVersion = N;
+ if (DwarfVersion == 0) {
+ DwarfVersion = TC.GetDefaultDwarfVersion();
+ assert(DwarfVersion && "toolchain default DWARF version must be nonzero");
+ }
+ return DwarfVersion;
+}
+
void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs) {
llvm::Reloc::Model RelocationModel;
@@ -1411,17 +2116,12 @@ enum class LibGccType { UnspecifiedLibGcc, StaticLibGcc, SharedLibGcc };
static LibGccType getLibGccType(const ToolChain &TC, const Driver &D,
const ArgList &Args) {
if (Args.hasArg(options::OPT_static_libgcc) ||
- Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie))
+ Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie) ||
+ // The Android NDK only provides libunwind.a, not libunwind.so.
+ TC.getTriple().isAndroid())
return LibGccType::StaticLibGcc;
if (Args.hasArg(options::OPT_shared_libgcc))
return LibGccType::SharedLibGcc;
- // The Android NDK only provides libunwind.a, not libunwind.so.
- if (TC.getTriple().isAndroid())
- return LibGccType::StaticLibGcc;
- // For MinGW, don't imply a shared libgcc here, we only want to return
- // SharedLibGcc if that was explicitly requested.
- if (D.CCCIsCXX() && !TC.getTriple().isOSCygMing())
- return LibGccType::SharedLibGcc;
return LibGccType::UnspecifiedLibGcc;
}
@@ -1441,18 +2141,25 @@ static LibGccType getLibGccType(const ToolChain &TC, const Driver &D,
static void AddUnwindLibrary(const ToolChain &TC, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
ToolChain::UnwindLibType UNW = TC.GetUnwindLibType(Args);
+ // By default OHOS binaries are linked statically to libunwind.
+ if (TC.getTriple().isOHOSFamily() && UNW == ToolChain::UNW_CompilerRT) {
+ CmdArgs.push_back("-l:libunwind.a");
+ return;
+ }
+
// Targets that don't use unwind libraries.
if ((TC.getTriple().isAndroid() && UNW == ToolChain::UNW_Libgcc) ||
TC.getTriple().isOSIAMCU() || TC.getTriple().isOSBinFormatWasm() ||
- UNW == ToolChain::UNW_None)
+ TC.getTriple().isWindowsMSVCEnvironment() || UNW == ToolChain::UNW_None)
return;
LibGccType LGT = getLibGccType(TC, D, Args);
bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc &&
+ (UNW == ToolChain::UNW_CompilerRT || !D.CCCIsCXX()) &&
!TC.getTriple().isAndroid() &&
!TC.getTriple().isOSCygMing() && !TC.getTriple().isOSAIX();
if (AsNeeded)
- CmdArgs.push_back(getAsNeededOption(TC, true));
+ addAsNeededOption(TC, Args, CmdArgs, true);
switch (UNW) {
case ToolChain::UNW_None:
@@ -1472,30 +2179,32 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D,
CmdArgs.push_back("-lunwind");
} else if (LGT == LibGccType::StaticLibGcc) {
CmdArgs.push_back("-l:libunwind.a");
- } else if (TC.getTriple().isOSCygMing()) {
- if (LGT == LibGccType::SharedLibGcc)
+ } else if (LGT == LibGccType::SharedLibGcc) {
+ if (TC.getTriple().isOSCygMing())
CmdArgs.push_back("-l:libunwind.dll.a");
else
- // Let the linker choose between libunwind.dll.a and libunwind.a
- // depending on what's available, and depending on the -static flag
- CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("-l:libunwind.so");
} else {
- CmdArgs.push_back("-l:libunwind.so");
+ // Let the linker choose between libunwind.so and libunwind.a
+ // depending on what's available, and depending on the -static flag
+ CmdArgs.push_back("-lunwind");
}
break;
}
if (AsNeeded)
- CmdArgs.push_back(getAsNeededOption(TC, false));
+ addAsNeededOption(TC, Args, CmdArgs, false);
}
static void AddLibgcc(const ToolChain &TC, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
LibGccType LGT = getLibGccType(TC, D, Args);
- if (LGT != LibGccType::SharedLibGcc)
+ if (LGT == LibGccType::StaticLibGcc ||
+ (LGT == LibGccType::UnspecifiedLibGcc && !D.CCCIsCXX()))
CmdArgs.push_back("-lgcc");
AddUnwindLibrary(TC, D, CmdArgs, Args);
- if (LGT == LibGccType::SharedLibGcc)
+ if (LGT == LibGccType::SharedLibGcc ||
+ (LGT == LibGccType::UnspecifiedLibGcc && D.CCCIsCXX()))
CmdArgs.push_back("-lgcc");
}
@@ -1514,9 +2223,10 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
// Issue error diagnostic if libgcc is explicitly specified
// through command line as --rtlib option argument.
- if (Args.hasArg(options::OPT_rtlib_EQ)) {
+ Arg *A = Args.getLastArg(options::OPT_rtlib_EQ);
+ if (A && A->getValue() != StringRef("platform")) {
TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
- << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC";
+ << A->getValue() << "MSVC";
}
} else
AddLibgcc(TC, D, CmdArgs, Args);
@@ -1536,35 +2246,49 @@ SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args,
const InputInfo &Input,
const Driver &D) {
const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ);
- if (!A)
+ if (!A && !D.CCPrintInternalStats)
return {};
- StringRef SaveStats = A->getValue();
SmallString<128> StatsFile;
- if (SaveStats == "obj" && Output.isFilename()) {
- StatsFile.assign(Output.getFilename());
- llvm::sys::path::remove_filename(StatsFile);
- } else if (SaveStats != "cwd") {
- D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats;
- return {};
- }
+ if (A) {
+ StringRef SaveStats = A->getValue();
+ if (SaveStats == "obj" && Output.isFilename()) {
+ StatsFile.assign(Output.getFilename());
+ llvm::sys::path::remove_filename(StatsFile);
+ } else if (SaveStats != "cwd") {
+ D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats;
+ return {};
+ }
- StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput());
- llvm::sys::path::append(StatsFile, BaseName);
- llvm::sys::path::replace_extension(StatsFile, "stats");
+ StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput());
+ llvm::sys::path::append(StatsFile, BaseName);
+ llvm::sys::path::replace_extension(StatsFile, "stats");
+ } else {
+ assert(D.CCPrintInternalStats);
+ StatsFile.assign(D.CCPrintInternalStatReportFilename.empty()
+ ? "-"
+ : D.CCPrintInternalStatReportFilename);
+ }
return StatsFile;
}
-void tools::addMultilibFlag(bool Enabled, const char *const Flag,
+void tools::addMultilibFlag(bool Enabled, const StringRef Flag,
Multilib::flags_list &Flags) {
- Flags.push_back(std::string(Enabled ? "+" : "-") + Flag);
+ assert(Flag.front() == '-');
+ if (Enabled) {
+ Flags.push_back(Flag.str());
+ } else {
+ Flags.push_back(("!" + Flag.substr(1)).str());
+ }
}
void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args,
- ArgStringList &CmdArgs, bool IsLTO) {
+ ArgStringList &CmdArgs, bool IsLTO,
+ const StringRef PluginOptPrefix) {
auto addArg = [&, IsLTO](const Twine &Arg) {
if (IsLTO) {
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg));
+ assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg));
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(Arg));
@@ -1630,11 +2354,11 @@ void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args,
/// convention has been to use the prefix “lib”. To avoid confusion with host
/// archive libraries, we use prefix "libbc-" for the bitcode SDL archives.
///
-bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs,
+static bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
- SmallVector<std::string, 8> LibraryPaths, std::string Lib,
- StringRef Arch, StringRef Target, bool isBitCodeSDL,
- bool postClangLink) {
+ const SmallVectorImpl<std::string> &LibraryPaths,
+ StringRef Lib, StringRef Arch, StringRef Target,
+ bool isBitCodeSDL) {
SmallVector<std::string, 12> SDLs;
std::string LibDeviceLoc = "/libdevice";
@@ -1693,8 +2417,6 @@ bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs,
for (auto SDL : SDLs) {
auto FullName = Twine(LPath + SDL).str();
if (llvm::sys::fs::exists(FullName)) {
- if (postClangLink)
- CC1Args.push_back("-mlink-builtin-bitcode");
CC1Args.push_back(DriverArgs.MakeArgString(FullName));
FoundSDL = true;
break;
@@ -1709,111 +2431,124 @@ bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs,
/// Search if a user provided archive file lib<libname>.a exists in any of
/// the library paths. If so, add a new command to clang-offload-bundler to
/// unbundle this archive and create a temporary device specific archive. Name
-/// of this SDL is passed to the llvm-link (for amdgcn) or to the
-/// clang-nvlink-wrapper (for nvptx) commands by the driver.
-bool tools::GetSDLFromOffloadArchive(
+/// of this SDL is passed to the llvm-link tool.
+static void GetSDLFromOffloadArchive(
Compilation &C, const Driver &D, const Tool &T, const JobAction &JA,
const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args, SmallVector<std::string, 8> LibraryPaths,
- StringRef Lib, StringRef Arch, StringRef Target, bool isBitCodeSDL,
- bool postClangLink) {
+ llvm::opt::ArgStringList &CC1Args,
+ const SmallVectorImpl<std::string> &LibraryPaths, StringRef Lib,
+ StringRef Arch, StringRef Target, bool isBitCodeSDL) {
// We don't support bitcode archive bundles for nvptx
if (isBitCodeSDL && Arch.contains("nvptx"))
- return false;
+ return;
bool FoundAOB = false;
- SmallVector<std::string, 2> AOBFileNames;
std::string ArchiveOfBundles;
- for (auto LPath : LibraryPaths) {
- ArchiveOfBundles.clear();
-
- AOBFileNames.push_back(Twine(LPath + "/libdevice/lib" + Lib + ".a").str());
- AOBFileNames.push_back(Twine(LPath + "/lib" + Lib + ".a").str());
- for (auto AOB : AOBFileNames) {
- if (llvm::sys::fs::exists(AOB)) {
- ArchiveOfBundles = AOB;
- FoundAOB = true;
- break;
+ llvm::Triple Triple(D.getTargetTriple());
+ bool IsMSVC = Triple.isWindowsMSVCEnvironment();
+ auto Ext = IsMSVC ? ".lib" : ".a";
+ if (!Lib.starts_with(":") && !Lib.starts_with("-l")) {
+ if (llvm::sys::fs::exists(Lib)) {
+ ArchiveOfBundles = Lib;
+ FoundAOB = true;
+ }
+ } else {
+ Lib.consume_front("-l");
+ for (auto LPath : LibraryPaths) {
+ ArchiveOfBundles.clear();
+ auto LibFile = (Lib.starts_with(":") ? Lib.drop_front()
+ : IsMSVC ? Lib + Ext
+ : "lib" + Lib + Ext)
+ .str();
+ for (auto Prefix : {"/libdevice/", "/"}) {
+ auto AOB = Twine(LPath + Prefix + LibFile).str();
+ if (llvm::sys::fs::exists(AOB)) {
+ ArchiveOfBundles = AOB;
+ FoundAOB = true;
+ break;
+ }
}
+ if (FoundAOB)
+ break;
}
+ }
- if (!FoundAOB)
- continue;
-
- StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib";
- std::string OutputLib = D.GetTemporaryPath(
- Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a");
+ if (!FoundAOB)
+ return;
- C.addTempFile(C.getArgs().MakeArgString(OutputLib));
+ llvm::file_magic Magic;
+ auto EC = llvm::identify_magic(ArchiveOfBundles, Magic);
+ if (EC || Magic != llvm::file_magic::archive)
+ return;
- ArgStringList CmdArgs;
- SmallString<128> DeviceTriple;
- DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind());
+ StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib";
+ std::string OutputLib =
+ D.GetTemporaryPath(Twine(Prefix + llvm::sys::path::filename(Lib) + "-" +
+ Arch + "-" + Target)
+ .str(),
+ "a");
+
+ C.addTempFile(C.getArgs().MakeArgString(OutputLib));
+
+ ArgStringList CmdArgs;
+ SmallString<128> DeviceTriple;
+ DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind());
+ DeviceTriple += '-';
+ std::string NormalizedTriple = T.getToolChain().getTriple().normalize();
+ DeviceTriple += NormalizedTriple;
+ if (!Target.empty()) {
DeviceTriple += '-';
- std::string NormalizedTriple = T.getToolChain().getTriple().normalize();
- DeviceTriple += NormalizedTriple;
- if (!Target.empty()) {
- DeviceTriple += '-';
- DeviceTriple += Target;
- }
+ DeviceTriple += Target;
+ }
- std::string UnbundleArg("-unbundle");
- std::string TypeArg("-type=a");
- std::string InputArg("-inputs=" + ArchiveOfBundles);
- std::string OffloadArg("-targets=" + std::string(DeviceTriple));
- std::string OutputArg("-outputs=" + OutputLib);
-
- const char *UBProgram = DriverArgs.MakeArgString(
- T.getToolChain().GetProgramPath("clang-offload-bundler"));
-
- ArgStringList UBArgs;
- UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg));
- UBArgs.push_back(C.getArgs().MakeArgString(TypeArg));
- UBArgs.push_back(C.getArgs().MakeArgString(InputArg));
- UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg));
- UBArgs.push_back(C.getArgs().MakeArgString(OutputArg));
-
- // Add this flag to not exit from clang-offload-bundler if no compatible
- // code object is found in heterogenous archive library.
- std::string AdditionalArgs("-allow-missing-bundles");
- UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs));
-
- C.addCommand(std::make_unique<Command>(
- JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs,
- InputInfo(&JA, C.getArgs().MakeArgString(OutputLib))));
- if (postClangLink)
- CC1Args.push_back("-mlink-builtin-bitcode");
+ std::string UnbundleArg("-unbundle");
+ std::string TypeArg("-type=a");
+ std::string InputArg("-input=" + ArchiveOfBundles);
+ std::string OffloadArg("-targets=" + std::string(DeviceTriple));
+ std::string OutputArg("-output=" + OutputLib);
- CC1Args.push_back(DriverArgs.MakeArgString(OutputLib));
- break;
- }
+ const char *UBProgram = DriverArgs.MakeArgString(
+ T.getToolChain().GetProgramPath("clang-offload-bundler"));
+
+ ArgStringList UBArgs;
+ UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(TypeArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(InputArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(OutputArg));
+
+ // Add this flag to not exit from clang-offload-bundler if no compatible
+ // code object is found in heterogenous archive library.
+ std::string AdditionalArgs("-allow-missing-bundles");
+ UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs));
+
+ // Add this flag to treat hip and hipv4 offload kinds as compatible with
+ // openmp offload kind while extracting code objects from a heterogenous
+ // archive library. Vice versa is also considered compatible.
+ std::string HipCompatibleArgs("-hip-openmp-compatible");
+ UBArgs.push_back(C.getArgs().MakeArgString(HipCompatibleArgs));
- return FoundAOB;
+ C.addCommand(std::make_unique<Command>(
+ JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs,
+ InputInfo(&JA, C.getArgs().MakeArgString(OutputLib))));
+
+ CC1Args.push_back(DriverArgs.MakeArgString(OutputLib));
+
+ return;
}
// Wrapper function used by driver for adding SDLs during link phase.
void tools::AddStaticDeviceLibsLinking(Compilation &C, const Tool &T,
- const JobAction &JA,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink) {
+ const JobAction &JA,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ StringRef Arch, StringRef Target,
+ bool isBitCodeSDL) {
AddStaticDeviceLibs(&C, &T, &JA, &Inputs, C.getDriver(), DriverArgs, CC1Args,
- Arch, Target, isBitCodeSDL, postClangLink);
-}
-
-// Wrapper function used for post clang linking of bitcode SDLS for nvptx by
-// the CUDA toolchain.
-void tools::AddStaticDeviceLibsPostLinking(const Driver &D,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink) {
- AddStaticDeviceLibs(nullptr, nullptr, nullptr, nullptr, D, DriverArgs,
- CC1Args, Arch, Target, isBitCodeSDL, postClangLink);
+ Arch, Target, isBitCodeSDL);
}
// User defined Static Device Libraries(SDLs) can be passed to clang for
@@ -1828,11 +2563,9 @@ void tools::AddStaticDeviceLibsPostLinking(const Driver &D,
// compilation. For AMDGPU, these libraries are linked one time
// during the application link phase.
//
-// * Machine-code SDLs: They are archive files. For NVPTX, the archive members
-// contain cubin for Nvidia GPUs and are linked one time during the
-// link phase by the CUDA SDK linker called nvlink. For AMDGPU, the
-// process for machine code SDLs is still in development. But they
-// will be linked by the LLVM tool lld.
+// * Machine-code SDLs: They are archive files. For AMDGPU, the process for
+// machine code SDLs is still in development. But they will be linked
+// by the LLVM tool lld.
//
// * Bundled objects that contain both host and device codes: Bundled objects
// may also contain library code compiled from source. For NVPTX, the
@@ -1847,11 +2580,11 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T,
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink) {
+ bool isBitCodeSDL) {
SmallVector<std::string, 8> LibraryPaths;
// Add search directories from LIBRARY_PATH env variable
- llvm::Optional<std::string> LibPath =
+ std::optional<std::string> LibPath =
llvm::sys::Process::GetEnv("LIBRARY_PATH");
if (LibPath) {
SmallVector<StringRef, 8> Frags;
@@ -1867,7 +2600,7 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T,
// Add path to lib-debug folders
SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
LibraryPaths.emplace_back(DefaultLibPath.c_str());
// Build list of Static Device Libraries SDLs specified by -l option
@@ -1875,49 +2608,51 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T,
static const StringRef HostOnlyArchives[] = {
"omp", "cudart", "m", "gcc", "gcc_s", "pthread", "hip_hcc"};
for (auto SDLName : DriverArgs.getAllArgValues(options::OPT_l)) {
- if (!HostOnlyArchives->contains(SDLName)) {
- SDLNames.insert(SDLName);
+ if (!llvm::is_contained(HostOnlyArchives, SDLName)) {
+ SDLNames.insert(std::string("-l") + SDLName);
}
}
+ for (auto Input : DriverArgs.getAllArgValues(options::OPT_INPUT)) {
+ auto FileName = StringRef(Input);
+ // Clang treats any unknown file types as archives and passes them to the
+ // linker. Files with extension 'lib' are classified as TY_Object by clang
+ // but they are usually archives. It is OK if the file is not really an
+ // archive since GetSDLFromOffloadArchive will check the magic of the file
+ // and only unbundle it if it is really an archive.
+ const StringRef LibFileExt = ".lib";
+ if (!llvm::sys::path::has_extension(FileName) ||
+ types::lookupTypeForExtension(
+ llvm::sys::path::extension(FileName).drop_front()) ==
+ types::TY_INVALID ||
+ llvm::sys::path::extension(FileName) == LibFileExt)
+ SDLNames.insert(Input);
+ }
+
// The search stops as soon as an SDL file is found. The driver then provides
- // the full filename of the SDL to the llvm-link or clang-nvlink-wrapper
- // command. If no SDL is found after searching each LINKPATH with
- // SEARCH-ORDER, it is possible that an archive file lib<libname>.a exists
- // and may contain bundled object files.
+ // the full filename of the SDL to the llvm-link command. If no SDL is found
+ // after searching each LINKPATH with SEARCH-ORDER, it is possible that an
+ // archive file lib<libname>.a exists and may contain bundled object files.
for (auto SDLName : SDLNames) {
// This is the only call to SDLSearch
if (!SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target,
- isBitCodeSDL, postClangLink)) {
+ isBitCodeSDL)) {
GetSDLFromOffloadArchive(*C, D, *T, *JA, *Inputs, DriverArgs, CC1Args,
LibraryPaths, SDLName, Arch, Target,
- isBitCodeSDL, postClangLink);
+ isBitCodeSDL);
}
}
}
static llvm::opt::Arg *
getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) {
- // The last of -mcode-object-v3, -mno-code-object-v3 and
- // -mcode-object-version=<version> wins.
- return Args.getLastArg(options::OPT_mcode_object_v3_legacy,
- options::OPT_mno_code_object_v3_legacy,
- options::OPT_mcode_object_version_EQ);
+ return Args.getLastArg(options::OPT_mcode_object_version_EQ);
}
void tools::checkAMDGPUCodeObjectVersion(const Driver &D,
const llvm::opt::ArgList &Args) {
- const unsigned MinCodeObjVer = 2;
- const unsigned MaxCodeObjVer = 4;
-
- // Emit warnings for legacy options even if they are overridden.
- if (Args.hasArg(options::OPT_mno_code_object_v3_legacy))
- D.Diag(diag::warn_drv_deprecated_arg) << "-mno-code-object-v3"
- << "-mcode-object-version=2";
-
- if (Args.hasArg(options::OPT_mcode_object_v3_legacy))
- D.Diag(diag::warn_drv_deprecated_arg) << "-mcode-object-v3"
- << "-mcode-object-version=3";
+ const unsigned MinCodeObjVer = 4;
+ const unsigned MaxCodeObjVer = 5;
if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) {
if (CodeObjArg->getOption().getID() ==
@@ -1935,17 +2670,8 @@ void tools::checkAMDGPUCodeObjectVersion(const Driver &D,
unsigned tools::getAMDGPUCodeObjectVersion(const Driver &D,
const llvm::opt::ArgList &Args) {
unsigned CodeObjVer = 4; // default
- if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) {
- if (CodeObjArg->getOption().getID() ==
- options::OPT_mno_code_object_v3_legacy) {
- CodeObjVer = 2;
- } else if (CodeObjArg->getOption().getID() ==
- options::OPT_mcode_object_v3_legacy) {
- CodeObjVer = 3;
- } else {
- StringRef(CodeObjArg->getValue()).getAsInteger(0, CodeObjVer);
- }
- }
+ if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args))
+ StringRef(CodeObjArg->getValue()).getAsInteger(0, CodeObjVer);
return CodeObjVer;
}
@@ -1957,10 +2683,12 @@ bool tools::haveAMDGPUCodeObjectVersionArgument(
void tools::addMachineOutlinerArgs(const Driver &D,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- const llvm::Triple &Triple, bool IsLTO) {
+ const llvm::Triple &Triple, bool IsLTO,
+ const StringRef PluginOptPrefix) {
auto addArg = [&, IsLTO](const Twine &Arg) {
if (IsLTO) {
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg));
+ assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg));
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(Arg));
@@ -1973,9 +2701,7 @@ void tools::addMachineOutlinerArgs(const Driver &D,
// We only support -moutline in AArch64 and ARM targets right now. If
// we're not compiling for these, emit a warning and ignore the flag.
// Otherwise, add the proper mllvm flags.
- if (!(Triple.isARM() || Triple.isThumb() ||
- Triple.getArch() == llvm::Triple::aarch64 ||
- Triple.getArch() == llvm::Triple::aarch64_32)) {
+ if (!(Triple.isARM() || Triple.isThumb() || Triple.isAArch64())) {
D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName();
} else {
addArg(Twine("-enable-machine-outliner"));
@@ -1996,11 +2722,11 @@ void tools::addOpenMPDeviceRTL(const Driver &D,
// Add path to clang lib / lib64 folder.
SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
LibraryPaths.emplace_back(DefaultLibPath.c_str());
// Add user defined library paths from LIBRARY_PATH.
- llvm::Optional<std::string> LibPath =
+ std::optional<std::string> LibPath =
llvm::sys::Process::GetEnv("LIBRARY_PATH");
if (LibPath) {
SmallVector<StringRef, 8> Frags;
@@ -2011,11 +2737,12 @@ void tools::addOpenMPDeviceRTL(const Driver &D,
}
OptSpecifier LibomptargetBCPathOpt =
- Triple.isAMDGCN() ? options::OPT_libomptarget_amdgcn_bc_path_EQ
+ Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
: options::OPT_libomptarget_nvptx_bc_path_EQ;
- StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgcn" : "nvptx";
- std::string LibOmpTargetName = "libomptarget-" + BitcodeSuffix.str() + ".bc";
+ StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" : "nvptx";
+ std::string LibOmpTargetName =
+ ("libomptarget-" + ArchPrefix + "-" + BitcodeSuffix + ".bc").str();
// First check whether user specifies bc library
if (const Arg *A = DriverArgs.getLastArg(LibomptargetBCPathOpt)) {
@@ -2051,3 +2778,17 @@ void tools::addOpenMPDeviceRTL(const Driver &D,
<< LibOmpTargetName << ArchPrefix;
}
}
+void tools::addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) {
+ if ((C.getActiveOffloadKinds() & Action::OFK_HIP) &&
+ !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_no_hip_rt)) {
+ TC.AddHIPRuntimeLibArgs(Args, CmdArgs);
+ } else {
+ // Claim "no HIP libraries" arguments if any
+ for (auto *Arg : Args.filtered(options::OPT_no_hip_rt)) {
+ Arg->claim();
+ }
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h
index 23012dc247e4..807867f13a5c 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h
@@ -9,11 +9,15 @@
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
+#include "clang/Basic/CodeGenOptions.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Multilib.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
namespace clang {
@@ -37,12 +41,13 @@ bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
void linkSanitizerRuntimeDeps(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
bool addXRayRuntime(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
-void linkXRayRuntimeDeps(const ToolChain &TC,
+void linkXRayRuntimeDeps(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
@@ -55,32 +60,12 @@ void AddStaticDeviceLibsLinking(Compilation &C, const Tool &T,
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CmdArgs,
StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink);
-void AddStaticDeviceLibsPostLinking(const Driver &D,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CmdArgs,
- StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink);
+ bool isBitCodeSDL);
void AddStaticDeviceLibs(Compilation *C, const Tool *T, const JobAction *JA,
const InputInfoList *Inputs, const Driver &D,
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CmdArgs, StringRef Arch,
- StringRef Target, bool isBitCodeSDL,
- bool postClangLink);
-
-bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CmdArgs,
- SmallVector<std::string, 8> LibraryPaths, std::string Lib,
- StringRef Arch, StringRef Target, bool isBitCodeSDL,
- bool postClangLink);
-
-bool GetSDLFromOffloadArchive(Compilation &C, const Driver &D, const Tool &T,
- const JobAction &JA, const InputInfoList &Inputs,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- SmallVector<std::string, 8> LibraryPaths,
- StringRef Lib, StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink);
+ StringRef Target, bool isBitCodeSDL);
const char *SplitDebugName(const JobAction &JA, const llvm::opt::ArgList &Args,
const InputInfo &Input, const InputInfo &Output);
@@ -93,32 +78,61 @@ void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output,
const InputInfo &Input, bool IsThinLTO);
+const char *RelocationModelName(llvm::Reloc::Model Model);
+
std::tuple<llvm::Reloc::Model, unsigned, bool>
ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args);
unsigned ParseFunctionAlignment(const ToolChain &TC,
const llvm::opt::ArgList &Args);
-unsigned ParseDebugDefaultVersion(const ToolChain &TC,
- const llvm::opt::ArgList &Args);
+void addDebugInfoKind(llvm::opt::ArgStringList &CmdArgs,
+ llvm::codegenoptions::DebugInfoKind DebugInfoKind);
+
+llvm::codegenoptions::DebugInfoKind
+debugLevelToInfoKind(const llvm::opt::Arg &A);
+
+// Extract the integer N from a string spelled "-dwarf-N", returning 0
+// on mismatch. The StringRef input (rather than an Arg) allows
+// for use by the "-Xassembler" option parser.
+unsigned DwarfVersionNum(StringRef ArgValue);
+// Find a DWARF format version option.
+// This function is a complementary for DwarfVersionNum().
+const llvm::opt::Arg *getDwarfNArg(const llvm::opt::ArgList &Args);
+unsigned getDwarfVersion(const ToolChain &TC, const llvm::opt::ArgList &Args);
void AddAssemblerKPIC(const ToolChain &ToolChain,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
-void addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
- const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs);
void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
+void addOpenMPRuntimeLibraryPath(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
/// Returns true, if an OpenMP runtime has been added.
bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
const llvm::opt::ArgList &Args,
bool ForceStaticHostRuntime = false,
bool IsOffloadingHost = false, bool GompNeedsRT = false);
-const char *getAsNeededOption(const ToolChain &TC, bool as_needed);
+/// Adds Fortran runtime libraries to \p CmdArgs.
+void addFortranRuntimeLibs(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+
+/// Adds the path for the Fortran runtime libraries to \p CmdArgs.
+void addFortranRuntimeLibraryPath(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+void addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+
+void addAsNeededOption(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, bool as_needed);
+
+llvm::opt::Arg *getLastCSProfileGenerateArg(const llvm::opt::ArgList &Args);
llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args);
llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args);
@@ -130,6 +144,9 @@ llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args,
bool areOptimizationsEnabled(const llvm::opt::ArgList &Args);
bool isUseSeparateSections(const llvm::Triple &Triple);
+// Parse -mtls-dialect=. Return true if the target supports both general-dynamic
+// and TLSDESC, and TLSDESC is requested.
+bool isTLSDESCEnabled(const ToolChain &TC, const llvm::opt::ArgList &Args);
/// \p EnvVar is split by system delimiter for environment variables.
/// If \p ArgName is "-I", "-L", or an empty string, each entry from \p EnvVar
@@ -148,19 +165,24 @@ void AddTargetFeature(const llvm::opt::ArgList &Args,
std::string getCPUName(const Driver &D, const llvm::opt::ArgList &Args,
const llvm::Triple &T, bool FromAs = false);
+void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, bool ForAS,
+ bool IsAux = false);
+
/// Iterate \p Args and convert -mxxx to +xxx and -mno-xxx to -xxx and
/// append it to \p Features.
///
/// Note: Since \p Features may contain default values before calling
/// this function, or may be appended with entries to override arguments,
/// entries in \p Features are not unique.
-void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args,
+void handleTargetFeaturesGroup(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
std::vector<StringRef> &Features,
llvm::opt::OptSpecifier Group);
/// If there are multiple +xxx or -xxx features, keep the last one.
-std::vector<StringRef>
-unifyTargetFeatures(const std::vector<StringRef> &Features);
+SmallVector<StringRef> unifyTargetFeatures(ArrayRef<StringRef> Features);
/// Handles the -save-stats option and returns the filename to save statistics
/// to.
@@ -168,13 +190,13 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args,
const InputInfo &Output,
const InputInfo &Input, const Driver &D);
-/// \p Flag must be a flag accepted by the driver with its leading '-' removed,
-// otherwise '-print-multi-lib' will not emit them correctly.
-void addMultilibFlag(bool Enabled, const char *const Flag,
+/// \p Flag must be a flag accepted by the driver.
+void addMultilibFlag(bool Enabled, const StringRef Flag,
Multilib::flags_list &Flags);
void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs, bool IsLTO);
+ llvm::opt::ArgStringList &CmdArgs, bool IsLTO,
+ const StringRef PluginOptPrefix = "");
void checkAMDGPUCodeObjectVersion(const Driver &D,
const llvm::opt::ArgList &Args);
@@ -187,7 +209,8 @@ bool haveAMDGPUCodeObjectVersionArgument(const Driver &D,
void addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- const llvm::Triple &Triple, bool IsLTO);
+ const llvm::Triple &Triple, bool IsLTO,
+ const StringRef PluginOptPrefix = "");
void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
@@ -196,4 +219,7 @@ void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
} // end namespace driver
} // end namespace clang
+clang::CodeGenOptions::FramePointerKind
+getFramePointerKind(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
+
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp
deleted file mode 100644
index 5dda1b1b09fb..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//===--- Contiki.cpp - Contiki ToolChain Implementations --------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Contiki.h"
-#include "CommonArgs.h"
-
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-Contiki::Contiki(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {}
-
-SanitizerMask Contiki::getSupportedSanitizers() const {
- const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- if (IsX86)
- Res |= SanitizerKind::SafeStack;
- return Res;
-}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h
deleted file mode 100644
index 627d80bdda09..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===--- Contiki.h - Contiki ToolChain Implementations ----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H
-
-#include "Gnu.h"
-#include "clang/Driver/ToolChain.h"
-
-namespace clang {
-namespace driver {
-namespace toolchains {
-
-class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF {
-public:
- Contiki(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- // No support for finding a C++ standard library yet.
- void addLibCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
-
- SanitizerMask getSupportedSanitizers() const override;
-};
-
-} // end namespace toolchains
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp
index 2b043fbeecda..3c5dfba329cf 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp
@@ -94,7 +94,8 @@ void tools::CrossWindows::Linker::ConstructJob(
CmdArgs.push_back("-m");
switch (TC.getArch()) {
default:
- llvm_unreachable("unsupported architecture");
+ D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str();
+ break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
// FIXME: this is incorrect for WinCE
@@ -213,10 +214,11 @@ CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
const llvm::opt::ArgList &Args)
: Generic_GCC(D, T, Args) {}
-bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+CrossWindowsToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
// FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
// not know how to emit them.
- return getArch() == llvm::Triple::x86_64;
+ return getArch() == llvm::Triple::x86_64 ? UnwindTableLevel::Asynchronous : UnwindTableLevel::None;
}
bool CrossWindowsToolChain::isPICDefault() const {
@@ -273,8 +275,11 @@ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
void CrossWindowsToolChain::
AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
- if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
+ if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) {
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
+ }
}
clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const {
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h
index bab690ea34d0..c5df55a24296 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h
@@ -20,7 +20,7 @@ namespace driver {
namespace tools {
namespace CrossWindows {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {}
@@ -32,7 +32,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("CrossWindows::Linker", "ld", TC) {}
@@ -54,8 +54,8 @@ public:
CrossWindowsToolChain(const Driver &D, const llvm::Triple &T,
const llvm::opt::ArgList &Args);
- bool IsIntegratedAssemblerDefault() const override { return true; }
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp
index 4a9f6d4c4e3e..1462576ca870 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -16,16 +16,17 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/TargetParser.h"
#include <system_error>
using namespace clang::driver;
@@ -67,15 +68,29 @@ CudaVersion getCudaVersion(uint32_t raw_version) {
return CudaVersion::CUDA_114;
if (raw_version < 11060)
return CudaVersion::CUDA_115;
+ if (raw_version < 11070)
+ return CudaVersion::CUDA_116;
+ if (raw_version < 11080)
+ return CudaVersion::CUDA_117;
+ if (raw_version < 11090)
+ return CudaVersion::CUDA_118;
+ if (raw_version < 12010)
+ return CudaVersion::CUDA_120;
+ if (raw_version < 12020)
+ return CudaVersion::CUDA_121;
+ if (raw_version < 12030)
+ return CudaVersion::CUDA_122;
+ if (raw_version < 12040)
+ return CudaVersion::CUDA_123;
return CudaVersion::NEW;
}
CudaVersion parseCudaHFile(llvm::StringRef Input) {
// Helper lambda which skips the words if the line starts with them or returns
- // None otherwise.
+ // std::nullopt otherwise.
auto StartsWithWords =
[](llvm::StringRef Line,
- const SmallVector<StringRef, 3> words) -> llvm::Optional<StringRef> {
+ const SmallVector<StringRef, 3> words) -> std::optional<StringRef> {
for (StringRef word : words) {
if (!Line.consume_front(word))
return {};
@@ -189,19 +204,6 @@ CudaInstallationDetector::CudaInstallationDetector(
if (CheckLibDevice && !FS.exists(LibDevicePath))
continue;
- // On Linux, we have both lib and lib64 directories, and we need to choose
- // based on our triple. On MacOS, we have only a lib directory.
- //
- // It's sufficient for our purposes to be flexible: If both lib and lib64
- // exist, we choose whichever one matches our triple. Otherwise, if only
- // lib exists, we use it.
- if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64"))
- LibPath = InstallPath + "/lib64";
- else if (FS.exists(InstallPath + "/lib"))
- LibPath = InstallPath + "/lib";
- else
- continue;
-
Version = CudaVersion::UNKNOWN;
if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h"))
Version = parseCudaHFile((*CudaHFile)->getBuffer());
@@ -236,7 +238,7 @@ CudaInstallationDetector::CudaInstallationDetector(
// Process all bitcode filenames that look like
// libdevice.compute_XX.YY.bc
const StringRef LibDeviceName = "libdevice.";
- if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc")))
+ if (!(FileName.starts_with(LibDeviceName) && FileName.ends_with(".bc")))
continue;
StringRef GpuArch = FileName.slice(
LibDeviceName.size(), FileName.find('.', LibDeviceName.size()));
@@ -375,18 +377,20 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
const auto &TC =
- static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ static_cast<const toolchains::NVPTXToolChain &>(getToolChain());
assert(TC.getTriple().isNVPTX() && "Wrong platform");
StringRef GPUArchName;
- // If this is an OpenMP action we need to extract the device architecture
- // from the -march=arch option. This option may come from -Xopenmp-target
- // flag or the default value.
- if (JA.isDeviceOffloading(Action::OFK_OpenMP)) {
+ // If this is a CUDA action we need to extract the device architecture
+ // from the Job's associated architecture, otherwise use the -march=arch
+ // option. This option may come from -Xopenmp-target flag or the default
+ // value.
+ if (JA.isDeviceOffloading(Action::OFK_Cuda)) {
+ GPUArchName = JA.getOffloadingArch();
+ } else {
GPUArchName = Args.getLastArgValue(options::OPT_march_EQ);
assert(!GPUArchName.empty() && "Must have an architecture passed in.");
- } else
- GPUArchName = JA.getOffloadingArch();
+ }
// Obtain architecture from the action.
CudaArch gpu_arch = StringToCudaArch(GPUArchName);
@@ -447,22 +451,38 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--gpu-name");
CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch)));
CmdArgs.push_back("--output-file");
- CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output)));
- for (const auto& II : Inputs)
+ std::string OutputFileName = TC.getInputFilename(Output);
+
+ // If we are invoking `nvlink` internally we need to output a `.cubin` file.
+ // FIXME: This should hopefully be removed if NVIDIA updates their tooling.
+ if (!C.getInputArgs().getLastArg(options::OPT_c)) {
+ SmallString<256> Filename(Output.getFilename());
+ llvm::sys::path::replace_extension(Filename, "cubin");
+ OutputFileName = Filename.str();
+ }
+ if (Output.isFilename() && OutputFileName != Output.getFilename())
+ C.addTempFile(Args.MakeArgString(OutputFileName));
+
+ CmdArgs.push_back(Args.MakeArgString(OutputFileName));
+ for (const auto &II : Inputs)
CmdArgs.push_back(Args.MakeArgString(II.getFilename()));
- for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
+ for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
CmdArgs.push_back(Args.MakeArgString(A));
- bool Relocatable = false;
+ bool Relocatable;
if (JA.isOffloading(Action::OFK_OpenMP))
// In OpenMP we need to generate relocatable code.
Relocatable = Args.hasFlag(options::OPT_fopenmp_relocatable_target,
options::OPT_fnoopenmp_relocatable_target,
/*Default=*/true);
else if (JA.isOffloading(Action::OFK_Cuda))
- Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
- options::OPT_fno_gpu_rdc, /*Default=*/false);
+ // In CUDA we generate relocatable code by default.
+ Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ /*Default=*/false);
+ else
+ // Otherwise, we are compiling directly and should create linkable output.
+ Relocatable = true;
if (Relocatable)
CmdArgs.push_back("-c");
@@ -498,11 +518,11 @@ static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) {
// All inputs to this linker must be from CudaDeviceActions, as we need to look
// at the Inputs' Actions in order to figure out which GPU architecture they
// correspond to.
-void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
const auto &TC =
static_cast<const toolchains::CudaToolChain &>(getToolChain());
assert(TC.getTriple().isNVPTX() && "Wrong platform");
@@ -516,7 +536,7 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost)
CmdArgs.push_back("-g");
- for (const auto& II : Inputs) {
+ for (const auto &II : Inputs) {
auto *A = II.getAction();
assert(A->getInputs().size() == 1 &&
"Device offload action is expected to have a single input");
@@ -533,11 +553,12 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *Arch = (II.getType() == types::TY_PP_Asm)
? CudaArchToVirtualArchString(gpu_arch)
: gpu_arch_str;
- CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") +
- Arch + ",file=" + II.getFilename()));
+ CmdArgs.push_back(
+ Args.MakeArgString(llvm::Twine("--image=profile=") + Arch +
+ ",file=" + getToolChain().getInputFilename(II)));
}
- for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
+ for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
CmdArgs.push_back(Args.MakeArgString(A));
const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary"));
@@ -548,36 +569,31 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
-void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
const auto &TC =
- static_cast<const toolchains::CudaToolChain &>(getToolChain());
- assert(TC.getTriple().isNVPTX() && "Wrong platform");
-
+ static_cast<const toolchains::NVPTXToolChain &>(getToolChain());
ArgStringList CmdArgs;
- // OpenMP uses nvlink to link cubin files. The result will be embedded in the
- // host binary by the host linker.
- assert(!JA.isHostOffloading(Action::OFK_OpenMP) &&
- "CUDA toolchain not expected for an OpenMP host device.");
+ assert(TC.getTriple().isNVPTX() && "Wrong platform");
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else
- assert(Output.isNothing() && "Invalid output.");
+ }
+
if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost)
CmdArgs.push_back("-g");
if (Args.hasArg(options::OPT_v))
CmdArgs.push_back("-v");
- StringRef GPUArch =
- Args.getLastArgValue(options::OPT_march_EQ);
- assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas.");
+ StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ);
+ assert(!GPUArch.empty() && "At least one GPU Arch required for nvlink.");
CmdArgs.push_back("-arch");
CmdArgs.push_back(Args.MakeArgString(GPUArch));
@@ -588,14 +604,12 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
- llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));
for (const auto &II : Inputs) {
- if (II.getType() == types::TY_LLVM_IR ||
- II.getType() == types::TY_LTO_IR ||
- II.getType() == types::TY_LTO_BC ||
- II.getType() == types::TY_LLVM_BC) {
+ if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
+ II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) {
C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
continue;
@@ -606,65 +620,179 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
if (!II.isFilename())
continue;
- const char *CubinF = C.addTempFile(
- C.getArgs().MakeArgString(getToolChain().getInputFilename(II)));
+ // The 'nvlink' application performs RDC-mode linking when given a '.o'
+ // file and device linking when given a '.cubin' file. We always want to
+ // perform device linking, so just rename any '.o' files.
+ // FIXME: This should hopefully be removed if NVIDIA updates their tooling.
+ auto InputFile = getToolChain().getInputFilename(II);
+ if (llvm::sys::path::extension(InputFile) != ".cubin") {
+ // If there are no actions above this one then this is direct input and we
+ // can copy it. Otherwise the input is internal so a `.cubin` file should
+ // exist.
+ if (II.getAction() && II.getAction()->getInputs().size() == 0) {
+ const char *CubinF =
+ Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
+ llvm::sys::path::stem(InputFile), "cubin"));
+ if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
+ continue;
- CmdArgs.push_back(CubinF);
+ CmdArgs.push_back(CubinF);
+ } else {
+ SmallString<256> Filename(InputFile);
+ llvm::sys::path::replace_extension(Filename, "cubin");
+ CmdArgs.push_back(Args.MakeArgString(Filename));
+ }
+ } else {
+ CmdArgs.push_back(Args.MakeArgString(InputFile));
+ }
}
- AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx",
- GPUArch, /*isBitCodeSDL=*/false,
- /*postClangLink=*/false);
-
- // Find nvlink and pass it as "--nvlink-path=" argument of
- // clang-nvlink-wrapper.
- CmdArgs.push_back(Args.MakeArgString(
- Twine("--nvlink-path=" + getToolChain().GetProgramPath("nvlink"))));
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper"));
C.addCommand(std::make_unique<Command>(
JA, *this,
ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8,
"--options-file"},
- Exec, CmdArgs, Inputs, Output));
+ Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs,
+ Inputs, Output));
}
-/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
-/// which isn't properly a linker but nonetheless performs the step of stitching
-/// together object files from the assembler into a single blob.
+void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<StringRef> &Features) {
+ if (Args.hasArg(options::OPT_cuda_feature_EQ)) {
+ StringRef PtxFeature =
+ Args.getLastArgValue(options::OPT_cuda_feature_EQ, "+ptx42");
+ Features.push_back(Args.MakeArgString(PtxFeature));
+ return;
+ }
+ CudaInstallationDetector CudaInstallation(D, Triple, Args);
-CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
- const ToolChain &HostTC, const ArgList &Args,
- const Action::OffloadKind OK)
- : ToolChain(D, Triple, Args), HostTC(HostTC),
- CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) {
- if (CudaInstallation.isValid()) {
- CudaInstallation.WarnIfUnsupportedVersion();
- getProgramPaths().push_back(std::string(CudaInstallation.getBinPath()));
+ // New CUDA versions often introduce new instructions that are only supported
+ // by new PTX version, so we need to raise PTX level to enable them in NVPTX
+ // back-end.
+ const char *PtxFeature = nullptr;
+ switch (CudaInstallation.version()) {
+#define CASE_CUDA_VERSION(CUDA_VER, PTX_VER) \
+ case CudaVersion::CUDA_##CUDA_VER: \
+ PtxFeature = "+ptx" #PTX_VER; \
+ break;
+ CASE_CUDA_VERSION(123, 83);
+ CASE_CUDA_VERSION(122, 82);
+ CASE_CUDA_VERSION(121, 81);
+ CASE_CUDA_VERSION(120, 80);
+ CASE_CUDA_VERSION(118, 78);
+ CASE_CUDA_VERSION(117, 77);
+ CASE_CUDA_VERSION(116, 76);
+ CASE_CUDA_VERSION(115, 75);
+ CASE_CUDA_VERSION(114, 74);
+ CASE_CUDA_VERSION(113, 73);
+ CASE_CUDA_VERSION(112, 72);
+ CASE_CUDA_VERSION(111, 71);
+ CASE_CUDA_VERSION(110, 70);
+ CASE_CUDA_VERSION(102, 65);
+ CASE_CUDA_VERSION(101, 64);
+ CASE_CUDA_VERSION(100, 63);
+ CASE_CUDA_VERSION(92, 61);
+ CASE_CUDA_VERSION(91, 61);
+ CASE_CUDA_VERSION(90, 60);
+#undef CASE_CUDA_VERSION
+ default:
+ PtxFeature = "+ptx42";
}
+ Features.push_back(PtxFeature);
+}
+
+/// NVPTX toolchain. Our assembler is ptxas, and our linker is nvlink. This
+/// operates as a stand-alone version of the NVPTX tools without the host
+/// toolchain.
+NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::Triple &HostTriple,
+ const ArgList &Args, bool Freestanding = false)
+ : ToolChain(D, Triple, Args), CudaInstallation(D, HostTriple, Args),
+ Freestanding(Freestanding) {
+ if (CudaInstallation.isValid())
+ getProgramPaths().push_back(std::string(CudaInstallation.getBinPath()));
// Lookup binaries into the driver directory, this is used to
- // discover the clang-offload-bundler executable.
+ // discover the 'nvptx-arch' executable.
getProgramPaths().push_back(getDriver().Dir);
}
-std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
- // Only object files are changed, for example assembly files keep their .s
- // extensions. CUDA also continues to use .o as they don't use nvlink but
- // fatbinary.
- if (!(OK == Action::OFK_OpenMP && Input.getType() == types::TY_Object))
- return ToolChain::getInputFilename(Input);
+/// We only need the host triple to locate the CUDA binary utilities, use the
+/// system's default triple if not provided.
+NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : NVPTXToolChain(D, Triple, llvm::Triple(LLVM_HOST_TRIPLE), Args,
+ /*Freestanding=*/true) {}
- // Replace extension for object files with cubin because nvlink relies on
- // these particular file names.
- SmallString<256> Filename(ToolChain::getInputFilename(Input));
- llvm::sys::path::replace_extension(Filename, "cubin");
- return std::string(Filename.str());
+llvm::opt::DerivedArgList *
+NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+ DerivedArgList *DAL =
+ ToolChain::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
+ if (!DAL)
+ DAL = new DerivedArgList(Args.getBaseArgs());
+
+ const OptTable &Opts = getDriver().getOpts();
+
+ for (Arg *A : Args)
+ if (!llvm::is_contained(*DAL, A))
+ DAL->append(A);
+
+ if (!DAL->hasArg(options::OPT_march_EQ))
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
+ CudaArchToString(CudaArch::CudaDefault));
+
+ return DAL;
+}
+
+void NVPTXToolChain::addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const {
+ // If we are compiling with a standalone NVPTX toolchain we want to try to
+ // mimic a standard environment as much as possible. So we enable lowering
+ // ctor / dtor functions to global symbols that can be registered.
+ if (Freestanding)
+ CC1Args.append({"-mllvm", "--nvptx-lower-global-ctor-dtor"});
+}
+
+bool NVPTXToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const {
+ const Option &O = A->getOption();
+ return (O.matches(options::OPT_gN_Group) &&
+ !O.matches(options::OPT_gmodules)) ||
+ O.matches(options::OPT_g_Flag) ||
+ O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) ||
+ O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) ||
+ O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) ||
+ O.matches(options::OPT_gdwarf_5) ||
+ O.matches(options::OPT_gcolumn_info);
}
+void NVPTXToolChain::adjustDebugInfoKind(
+ llvm::codegenoptions::DebugInfoKind &DebugInfoKind,
+ const ArgList &Args) const {
+ switch (mustEmitDebugInfo(Args)) {
+ case DisableDebugInfo:
+ DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
+ break;
+ case DebugDirectivesOnly:
+ DebugInfoKind = llvm::codegenoptions::DebugDirectivesOnly;
+ break;
+ case EmitSameDebugInfoAsHost:
+ // Use same debug info level as the host.
+ break;
+ }
+}
+
+/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
+/// which isn't properly a linker but nonetheless performs the step of stitching
+/// together object files from the assembler into a single blob.
+
+CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const ArgList &Args)
+ : NVPTXToolChain(D, Triple, HostTC.getTriple(), Args), HostTC(HostTC) {}
+
void CudaToolChain::addClangTargetOptions(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
@@ -678,9 +806,12 @@ void CudaToolChain::addClangTargetOptions(
CC1Args.append(
{"-fcuda-is-device", "-mllvm", "-enable-memcpyopt-without-libcalls"});
- if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
- options::OPT_fno_cuda_approx_transcendentals, false))
- CC1Args.push_back("-fcuda-approx-transcendentals");
+ // Unsized function arguments used for variadics were introduced in CUDA-9.0
+ // We still do not support generating code that actually uses variadic
+ // arguments yet, but we do need to allow parsing them as recent CUDA
+ // headers rely on that. https://github.com/llvm/llvm-project/issues/58410
+ if (CudaInstallation.version() >= CudaVersion::CUDA_90)
+ CC1Args.push_back("-fcuda-allow-variadic-functions");
}
if (DriverArgs.hasArg(options::OPT_nogpulib))
@@ -701,32 +832,6 @@ void CudaToolChain::addClangTargetOptions(
clang::CudaVersion CudaInstallationVersion = CudaInstallation.version();
- // New CUDA versions often introduce new instructions that are only supported
- // by new PTX version, so we need to raise PTX level to enable them in NVPTX
- // back-end.
- const char *PtxFeature = nullptr;
- switch (CudaInstallationVersion) {
-#define CASE_CUDA_VERSION(CUDA_VER, PTX_VER) \
- case CudaVersion::CUDA_##CUDA_VER: \
- PtxFeature = "+ptx" #PTX_VER; \
- break;
- CASE_CUDA_VERSION(115, 75);
- CASE_CUDA_VERSION(114, 74);
- CASE_CUDA_VERSION(113, 73);
- CASE_CUDA_VERSION(112, 72);
- CASE_CUDA_VERSION(111, 71);
- CASE_CUDA_VERSION(110, 70);
- CASE_CUDA_VERSION(102, 65);
- CASE_CUDA_VERSION(101, 64);
- CASE_CUDA_VERSION(100, 63);
- CASE_CUDA_VERSION(92, 61);
- CASE_CUDA_VERSION(91, 61);
- CASE_CUDA_VERSION(90, 60);
-#undef CASE_CUDA_VERSION
- default:
- PtxFeature = "+ptx42";
- }
- CC1Args.append({"-target-feature", PtxFeature});
if (DriverArgs.hasFlag(options::OPT_fcuda_short_ptr,
options::OPT_fno_cuda_short_ptr, false))
CC1Args.append({"-mllvm", "--nvptx-short-ptr"});
@@ -748,18 +853,8 @@ void CudaToolChain::addClangTargetOptions(
if (getDriver().isUsingLTO(/* IsOffload */ true))
return;
- std::string BitcodeSuffix;
- if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime,
- options::OPT_fno_openmp_target_new_runtime, true))
- BitcodeSuffix = "new-nvptx-" + GpuArch.str();
- else
- BitcodeSuffix = "nvptx-" + GpuArch.str();
-
- addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix,
+ addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GpuArch.str(),
getTriple());
- AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx",
- GpuArch, /*isBitCodeSDL=*/true,
- /*postClangLink=*/true);
}
}
@@ -777,33 +872,6 @@ llvm::DenormalMode CudaToolChain::getDefaultDenormalModeForType(
return llvm::DenormalMode::getIEEE();
}
-bool CudaToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const {
- const Option &O = A->getOption();
- return (O.matches(options::OPT_gN_Group) &&
- !O.matches(options::OPT_gmodules)) ||
- O.matches(options::OPT_g_Flag) ||
- O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) ||
- O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) ||
- O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) ||
- O.matches(options::OPT_gdwarf_5) ||
- O.matches(options::OPT_gcolumn_info);
-}
-
-void CudaToolChain::adjustDebugInfoKind(
- codegenoptions::DebugInfoKind &DebugInfoKind, const ArgList &Args) const {
- switch (mustEmitDebugInfo(Args)) {
- case DisableDebugInfo:
- DebugInfoKind = codegenoptions::NoDebugInfo;
- break;
- case DebugDirectivesOnly:
- DebugInfoKind = codegenoptions::DebugDirectivesOnly;
- break;
- case EmitSameDebugInfoAsHost:
- // Use same debug info level as the host.
- break;
- }
-}
-
void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
// Check our CUDA version if we're going to include the CUDA headers.
@@ -816,6 +884,19 @@ void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
}
+std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
+ // Only object files are changed, for example assembly files keep their .s
+ // extensions. If the user requested device-only compilation don't change it.
+ if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly())
+ return ToolChain::getInputFilename(Input);
+
+ // Replace extension for object files with cubin because nvlink relies on
+ // these particular file names.
+ SmallString<256> Filename(ToolChain::getInputFilename(Input));
+ llvm::sys::path::replace_extension(Filename, "cubin");
+ return std::string(Filename);
+}
+
llvm::opt::DerivedArgList *
CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
StringRef BoundArch,
@@ -835,10 +916,22 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
if (!llvm::is_contained(*DAL, A))
DAL->append(A);
- StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ);
- if (Arch.empty())
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
- CLANG_OPENMP_NVPTX_DEFAULT_ARCH);
+ if (!DAL->hasArg(options::OPT_march_EQ)) {
+ StringRef Arch = BoundArch;
+ if (Arch.empty()) {
+ auto ArchsOrErr = getSystemGPUArchs(Args);
+ if (!ArchsOrErr) {
+ std::string ErrMsg =
+ llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError()));
+ getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march";
+ Arch = CudaArchToString(CudaArch::CudaDefault);
+ } else {
+ Arch = Args.MakeArgString(ArchsOrErr->front());
+ }
+ }
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
+ }
return DAL;
}
@@ -849,19 +942,51 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
if (!BoundArch.empty()) {
DAL->eraseArg(options::OPT_march_EQ);
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
+ BoundArch);
}
return DAL;
}
+Expected<SmallVector<std::string>>
+CudaToolChain::getSystemGPUArchs(const ArgList &Args) const {
+ // Detect NVIDIA GPUs availible on the system.
+ std::string Program;
+ if (Arg *A = Args.getLastArg(options::OPT_nvptx_arch_tool_EQ))
+ Program = A->getValue();
+ else
+ Program = GetProgramPath("nvptx-arch");
+
+ auto StdoutOrErr = executeToolChainProgram(Program);
+ if (!StdoutOrErr)
+ return StdoutOrErr.takeError();
+
+ SmallVector<std::string, 1> GPUArchs;
+ for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n"))
+ if (!Arch.empty())
+ GPUArchs.push_back(Arch.str());
+
+ if (GPUArchs.empty())
+ return llvm::createStringError(std::error_code(),
+ "No NVIDIA GPU detected in the system");
+
+ return std::move(GPUArchs);
+}
+
+Tool *NVPTXToolChain::buildAssembler() const {
+ return new tools::NVPTX::Assembler(*this);
+}
+
+Tool *NVPTXToolChain::buildLinker() const {
+ return new tools::NVPTX::Linker(*this);
+}
+
Tool *CudaToolChain::buildAssembler() const {
return new tools::NVPTX::Assembler(*this);
}
Tool *CudaToolChain::buildLinker() const {
- if (OK == Action::OFK_OpenMP)
- return new tools::NVPTX::OpenMPLinker(*this);
- return new tools::NVPTX::Linker(*this);
+ return new tools::NVPTX::FatBinary(*this);
}
void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h
index a7e6e84f4902..8a053f3393e1 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h
@@ -14,7 +14,6 @@
#include "clang/Driver/Multilib.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/VersionTuple.h"
#include <bitset>
@@ -32,7 +31,6 @@ private:
CudaVersion Version = CudaVersion::UNKNOWN;
std::string InstallPath;
std::string BinPath;
- std::string LibPath;
std::string LibDevicePath;
std::string IncludePath;
llvm::StringMap<std::string> LibDeviceMap;
@@ -70,8 +68,6 @@ public:
StringRef getBinPath() const { return BinPath; }
/// Get the detected Cuda Include path.
StringRef getIncludePath() const { return IncludePath; }
- /// Get the detected Cuda library path.
- StringRef getLibPath() const { return LibPath; }
/// Get the detected Cuda device library path.
StringRef getLibDevicePath() const { return LibDevicePath; }
/// Get libdevice file for given architecture
@@ -85,72 +81,71 @@ namespace tools {
namespace NVPTX {
// Run ptxas, the NVPTX assembler.
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
- public:
- Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {}
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {}
- bool hasIntegratedCPP() const override { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX
// assembly into a single output file.
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
- public:
- Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {}
+class LLVM_LIBRARY_VISIBILITY FatBinary : public Tool {
+public:
+ FatBinary(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {}
- bool hasIntegratedCPP() const override { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool {
- public:
- OpenMPLinker(const ToolChain &TC)
- : Tool("NVPTX::OpenMPLinker", "nvlink", TC) {}
+// Runs nvlink, which links GPU object files ("cubin" files) into a single file.
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "nvlink", TC) {}
- bool hasIntegratedCPP() const override { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
+void getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<StringRef> &Features);
+
} // end namespace NVPTX
} // end namespace tools
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain {
public:
- CudaToolChain(const Driver &D, const llvm::Triple &Triple,
- const ToolChain &HostTC, const llvm::opt::ArgList &Args,
- const Action::OffloadKind OK);
-
- const llvm::Triple *getAuxTriple() const override {
- return &HostTC.getTriple();
- }
+ NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args,
+ bool Freestanding);
- std::string getInputFilename(const InputInfo &Input) const override;
+ NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadKind) const override;
- llvm::DenormalMode getDefaultDenormalModeForType(
- const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
- const llvm::fltSemantics *FPType = nullptr) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
// Never try to use the integrated assembler with CUDA; always fork out to
// ptxas.
@@ -162,10 +157,49 @@ public:
}
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }
+
+ bool IsMathErrnoDefault() const override { return false; }
+
bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override;
- void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind,
+ void adjustDebugInfoKind(llvm::codegenoptions::DebugInfoKind &DebugInfoKind,
const llvm::opt::ArgList &Args) const override;
- bool IsMathErrnoDefault() const override { return false; }
+
+ // NVPTX supports only DWARF2.
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+ unsigned getMaxDwarfVersion() const override { return 2; }
+
+ CudaInstallationDetector CudaInstallation;
+
+protected:
+ Tool *buildAssembler() const override; // ptxas.
+ Tool *buildLinker() const override; // nvlink.
+
+private:
+ bool Freestanding = false;
+};
+
+class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain {
+public:
+ CudaToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const llvm::opt::ArgList &Args);
+
+ const llvm::Triple *getAuxTriple() const override {
+ return &HostTC.getTriple();
+ }
+
+ std::string getInputFilename(const InputInfo &Input) const override;
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ llvm::DenormalMode getDefaultDenormalModeForType(
+ const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
+ const llvm::fltSemantics *FPType = nullptr) const override;
void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -187,19 +221,16 @@ public:
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- // NVPTX supports only DWARF2.
- unsigned getMaxDwarfVersion() const override { return 2; }
-
const ToolChain &HostTC;
- CudaInstallationDetector CudaInstallation;
-protected:
- Tool *buildAssembler() const override; // ptxas
- Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
+ /// Uses nvptx-arch tool to get arch of the system GPU. Will return error
+ /// if unable to find one.
+ virtual Expected<SmallVector<std::string>>
+ getSystemGPUArchs(const llvm::opt::ArgList &Args) const override;
-private:
- const Action::OffloadKind OK;
+protected:
+ Tool *buildAssembler() const override; // ptxas
+ Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp
index f7da3f187814..fae8ad1a958a 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -23,9 +23,10 @@
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/TargetParser.h"
+#include "llvm/TargetParser/Triple.h"
#include <cstdlib> // ::getenv
using namespace clang::driver;
@@ -44,7 +45,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
// The matching this routine does is fairly pointless, since it is neither the
// complete architecture list, nor a reasonable subset. The problem is that
- // historically the driver driver accepts this and also ties its -march=
+ // historically the driver accepts this and also ties its -march=
// handling to the architecture name, so we need to be careful before removing
// support for it.
@@ -52,14 +53,11 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
// translation.
return llvm::StringSwitch<llvm::Triple::ArchType>(Str)
- .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc)
- .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc)
- .Case("ppc64", llvm::Triple::ppc64)
.Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86)
.Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
llvm::Triple::x86)
.Cases("x86_64", "x86_64h", llvm::Triple::x86_64)
- // This is derived from the driver driver.
+ // This is derived from the driver.
.Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
.Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
.Cases("armv7s", "xscale", llvm::Triple::arm)
@@ -74,7 +72,8 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
.Default(llvm::Triple::UnknownArch);
}
-void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) {
+void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str,
+ const ArgList &Args) {
const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str);
llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Str);
T.setArch(Arch);
@@ -84,6 +83,17 @@ void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) {
if (ArchKind == llvm::ARM::ArchKind::ARMV6M ||
ArchKind == llvm::ARM::ArchKind::ARMV7M ||
ArchKind == llvm::ARM::ArchKind::ARMV7EM) {
+ // Don't reject these -version-min= if we have the appropriate triple.
+ if (T.getOS() == llvm::Triple::IOS)
+ for (Arg *A : Args.filtered(options::OPT_mios_version_min_EQ))
+ A->ignoreTargetSpecific();
+ if (T.getOS() == llvm::Triple::WatchOS)
+ for (Arg *A : Args.filtered(options::OPT_mwatchos_version_min_EQ))
+ A->ignoreTargetSpecific();
+ if (T.getOS() == llvm::Triple::TvOS)
+ for (Arg *A : Args.filtered(options::OPT_mtvos_version_min_EQ))
+ A->ignoreTargetSpecific();
+
T.setOS(llvm::Triple::UnknownOS);
T.setObjectFormat(llvm::Triple::MachO);
}
@@ -209,19 +219,19 @@ static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) {
void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfoList &Inputs,
- unsigned Version[5], bool LinkerIsLLD) const {
+ VersionTuple Version, bool LinkerIsLLD,
+ bool UsePlatformVersion) const {
const Driver &D = getToolChain().getDriver();
const toolchains::MachO &MachOTC = getMachOToolChain();
// Newer linkers support -demangle. Pass it if supported and not disabled by
// the user.
- if ((Version[0] >= 100 || LinkerIsLLD) &&
+ if ((Version >= VersionTuple(100) || LinkerIsLLD) &&
!Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("-demangle");
- // FIXME: Pass most of the flags below that check Version if LinkerIsLLD too.
-
- if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137)
+ if (Args.hasArg(options::OPT_rdynamic) &&
+ (Version >= VersionTuple(137) || LinkerIsLLD))
CmdArgs.push_back("-export_dynamic");
// If we are using App Extension restrictions, pass a flag to the linker
@@ -230,7 +240,8 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
options::OPT_fno_application_extension, false))
CmdArgs.push_back("-application_extension");
- if (D.isUsingLTO() && Version[0] >= 116 && NeedsTempPath(Inputs)) {
+ if (D.isUsingLTO() && (Version >= VersionTuple(116) || LinkerIsLLD) &&
+ NeedsTempPath(Inputs)) {
std::string TmpPathName;
if (D.getLTOMode() == LTOK_Full) {
// If we are using full LTO, then automatically create a temporary file
@@ -259,7 +270,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
// clang version won't work anyways.
// lld is built at the same revision as clang and statically links in
// LLVM libraries, so it doesn't need libLTO.dylib.
- if (Version[0] >= 133 && !LinkerIsLLD) {
+ if (Version >= VersionTuple(133) && !LinkerIsLLD) {
// Search for libLTO in <InstalledDir>/../lib/libLTO.dylib
StringRef P = llvm::sys::path::parent_path(D.Dir);
SmallString<128> LibLTOPath(P);
@@ -269,8 +280,11 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath));
}
- // ld64 version 262 and above run the deduplicate pass by default.
- if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args))
+ // ld64 version 262 and above runs the deduplicate pass by default.
+ // FIXME: lld doesn't dedup by default. Should we pass `--icf=safe`
+ // if `!shouldLinkerNotDedup()` if LinkerIsLLD here?
+ if (Version >= VersionTuple(262) &&
+ shouldLinkerNotDedup(C.getJobs().empty(), Args))
CmdArgs.push_back("-no_deduplicate");
// Derived from the "link" spec.
@@ -342,7 +356,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_init);
// Add the deployment target.
- if (Version[0] >= 520 || LinkerIsLLD)
+ if (Version >= VersionTuple(520) || LinkerIsLLD || UsePlatformVersion)
MachOTC.addPlatformVersionArgs(Args, CmdArgs);
else
MachOTC.addMinVersionArgs(Args, CmdArgs);
@@ -368,7 +382,9 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
// Check if the toolchain supports bitcode build flow.
if (MachOTC.SupportsEmbeddedBitcode()) {
CmdArgs.push_back("-bitcode_bundle");
- if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) {
+ // FIXME: Pass this if LinkerIsLLD too, once it implements this flag.
+ if (C.getDriver().embedBitcodeMarkerOnly() &&
+ Version >= VersionTuple(278)) {
CmdArgs.push_back("-bitcode_process_mode");
CmdArgs.push_back("marker");
}
@@ -388,6 +404,13 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
}
}
+ if (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext) ||
+ Args.hasArg(options::OPT_ffreestanding)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-disable-atexit-based-global-dtor-lowering");
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_prebind);
Args.AddLastArg(CmdArgs, options::OPT_noprebind);
Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding);
@@ -437,6 +460,23 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name);
Args.AddLastArg(CmdArgs, options::OPT_dylinker);
Args.AddLastArg(CmdArgs, options::OPT_Mach);
+
+ if (LinkerIsLLD) {
+ if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) {
+ SmallString<128> Path(CSPGOGenerateArg->getNumValues() == 0
+ ? ""
+ : CSPGOGenerateArg->getValue());
+ llvm::sys::path::append(Path, "default_%m.profraw");
+ CmdArgs.push_back("--cs-profile-generate");
+ CmdArgs.push_back(Args.MakeArgString(Twine("--cs-profile-path=") + Path));
+ } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) {
+ SmallString<128> Path(
+ ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
+ if (Path.empty() || llvm::sys::fs::is_directory(Path))
+ llvm::sys::path::append(Path, "default.profdata");
+ CmdArgs.push_back(Args.MakeArgString(Twine("--cs-profile-path=") + Path));
+ }
+ }
}
/// Determine whether we are linking the ObjC runtime.
@@ -517,6 +557,8 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
}
}
+static void AppendPlatformPrefix(SmallString<128> &Path, const llvm::Triple &T);
+
void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -543,25 +585,25 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("touch"));
CmdArgs.push_back(Output.getFilename());
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, None, Output));
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::None(), Exec,
+ CmdArgs, std::nullopt, Output));
return;
}
- unsigned Version[5] = {0, 0, 0, 0, 0};
- if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
- if (!Driver::GetReleaseVersion(A->getValue(), Version))
- getToolChain().getDriver().Diag(diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
- }
+ VersionTuple Version = getMachOToolChain().getLinkerVersion(Args);
bool LinkerIsLLD;
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath(&LinkerIsLLD));
+ // xrOS always uses -platform-version.
+ bool UsePlatformVersion = getToolChain().getTriple().isXROS();
+
// I'm not sure why this particular decomposition exists in gcc, but
// we follow suite for ease of comparison.
- AddLinkArgs(C, Args, CmdArgs, Inputs, Version, LinkerIsLLD);
+ AddLinkArgs(C, Args, CmdArgs, Inputs, Version, LinkerIsLLD,
+ UsePlatformVersion);
if (willEmitRemarks(Args) &&
checkRemarksOptions(getToolChain().getDriver(), Args,
@@ -575,10 +617,6 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (getMachOToolChain().getMachOArchName(Args) == "arm64") {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-enable-machine-outliner");
-
- // Outline from linkonceodr functions by default in LTO.
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-enable-linkonceodr-outlining");
}
} else {
// Disable all outlining behaviour if we have mno-outline. We need to do
@@ -589,6 +627,12 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // Outline from linkonceodr functions by default in LTO, whenever the outliner
+ // is enabled. Note that the target may enable the machine outliner
+ // independently of -moutline.
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-enable-linkonceodr-outlining");
+
// Setup statistics file output.
SmallString<128> StatsFile =
getStatsFileName(Args, Output, Inputs[0], getToolChain().getDriver());
@@ -599,9 +643,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// It seems that the 'e' option is completely ignored for dynamic executables
// (the default), and with static executables, the last one wins, as expected.
- Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_u_Group,
- options::OPT_e, options::OPT_r});
+ Args.addAllArgs(CmdArgs,
+ {options::OPT_d_Flag, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_u_Group, options::OPT_r});
// Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading
// members of static archive libraries which implement Objective-C classes or
@@ -635,6 +679,13 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
InputFileList.push_back(II.getFilename());
}
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables.
+ if (getToolChain().getDriver().IsFlangMode()) {
+ addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs);
+ addFortranRuntimeLibs(getToolChain(), Args, CmdArgs);
+ }
+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
addOpenMPRuntime(CmdArgs, getToolChain(), Args);
@@ -712,8 +763,37 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // Add non-standard, platform-specific search paths, e.g., for DriverKit:
+ // -L<sysroot>/System/DriverKit/usr/lib
+ // -F<sysroot>/System/DriverKit/System/Library/Framework
+ {
+ bool NonStandardSearchPath = false;
+ const auto &Triple = getToolChain().getTriple();
+ if (Triple.isDriverKit()) {
+ // ld64 fixed the implicit -F and -L paths in ld64-605.1+.
+ NonStandardSearchPath =
+ Version.getMajor() < 605 ||
+ (Version.getMajor() == 605 && Version.getMinor().value_or(0) < 1);
+ }
+
+ if (NonStandardSearchPath) {
+ if (auto *Sysroot = Args.getLastArg(options::OPT_isysroot)) {
+ auto AddSearchPath = [&](StringRef Flag, StringRef SearchPath) {
+ SmallString<128> P(Sysroot->getValue());
+ AppendPlatformPrefix(P, Triple);
+ llvm::sys::path::append(P, SearchPath);
+ if (getToolChain().getVFS().exists(P)) {
+ CmdArgs.push_back(Args.MakeArgString(Flag + P));
+ }
+ };
+ AddSearchPath("-L", "/usr/lib");
+ AddSearchPath("-F", "/System/Library/Frameworks");
+ }
+ }
+ }
+
ResponseFileSupport ResponseSupport;
- if (Version[0] >= 705 || LinkerIsLLD) {
+ if (Version >= VersionTuple(705) || LinkerIsLLD) {
ResponseSupport = ResponseFileSupport::AtFileUTF8();
} else {
// For older versions of the linker, use the legacy filelist method instead.
@@ -869,13 +949,8 @@ types::ID MachO::LookupTypeForExtension(StringRef Ext) const {
bool MachO::HasNativeLLVMSupport() const { return true; }
ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const {
- // Default to use libc++ on OS X 10.9+ and iOS 7+.
- if ((isTargetMacOSBased() && !isMacosxVersionLT(10, 9)) ||
- (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) ||
- isTargetWatchOSBased())
- return ToolChain::CST_Libcxx;
-
- return ToolChain::CST_Libstdcxx;
+ // Always use libc++ by default
+ return ToolChain::CST_Libcxx;
}
/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
@@ -884,6 +959,13 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion);
if (isTargetIOSBased())
return ObjCRuntime(ObjCRuntime::iOS, TargetVersion);
+ if (isTargetXROS()) {
+ // XROS uses the iOS runtime.
+ auto T = llvm::Triple(Twine("arm64-apple-") +
+ llvm::Triple::getOSTypeName(llvm::Triple::XROS) +
+ TargetVersion.getAsString());
+ return ObjCRuntime(ObjCRuntime::iOS, T.getiOSVersion());
+ }
if (isNonFragile)
return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
@@ -891,7 +973,7 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
bool Darwin::hasBlocksRuntime() const {
- if (isTargetWatchOSBased())
+ if (isTargetWatchOSBased() || isTargetDriverKit() || isTargetXROS())
return true;
else if (isTargetIOSBased())
return !isIPhoneOSVersionLT(3, 2);
@@ -903,12 +985,12 @@ bool Darwin::hasBlocksRuntime() const {
void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+ CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
}
void Darwin::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+ RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
// This is just a MachO name translation routine and there's no
@@ -940,13 +1022,13 @@ static const char *ArmMachOArchNameCPU(StringRef CPU) {
// FIXME: Make sure this MachO triple mangling is really necessary.
// ARMv5* normalises to ARMv5.
- if (Arch.startswith("armv5"))
+ if (Arch.starts_with("armv5"))
Arch = Arch.substr(0, 5);
// ARMv6*, except ARMv6M, normalises to ARMv6.
- else if (Arch.startswith("armv6") && !Arch.endswith("6m"))
+ else if (Arch.starts_with("armv6") && !Arch.ends_with("6m"))
Arch = Arch.substr(0, 5);
// ARMv7A normalises to ARMv7.
- else if (Arch.endswith("v7a"))
+ else if (Arch.ends_with("v7a"))
Arch = Arch.substr(0, 5);
return Arch.data();
}
@@ -979,6 +1061,27 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const {
}
}
+VersionTuple MachO::getLinkerVersion(const llvm::opt::ArgList &Args) const {
+ if (LinkerVersion) {
+#ifndef NDEBUG
+ VersionTuple NewLinkerVersion;
+ if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ))
+ (void)NewLinkerVersion.tryParse(A->getValue());
+ assert(NewLinkerVersion == LinkerVersion);
+#endif
+ return *LinkerVersion;
+ }
+
+ VersionTuple NewLinkerVersion;
+ if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ))
+ if (NewLinkerVersion.tryParse(A->getValue()))
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << A->getAsString(Args);
+
+ LinkerVersion = NewLinkerVersion;
+ return *LinkerVersion;
+}
+
Darwin::~Darwin() {}
MachO::~MachO() {}
@@ -997,8 +1100,12 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
Str += "watchos";
else if (isTargetTvOSBased())
Str += "tvos";
+ else if (isTargetDriverKit())
+ Str += "driverkit";
else if (isTargetIOSBased() || isTargetMacCatalyst())
Str += "ios";
+ else if (isTargetXROS())
+ Str += llvm::Triple::getOSTypeName(llvm::Triple::XROS);
else
Str += "macosx";
Str += getTripleTargetVersion().getAsString();
@@ -1081,6 +1188,8 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
// ARC runtime is supported everywhere on arm64e.
if (getTriple().isArm64e())
return;
+ if (isTargetXROS())
+ return;
ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true);
@@ -1091,25 +1200,38 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
SmallString<128> P(getDriver().ClangExecutable);
llvm::sys::path::remove_filename(P); // 'clang'
llvm::sys::path::remove_filename(P); // 'bin'
+ llvm::sys::path::append(P, "lib", "arc");
// 'libarclite' usually lives in the same toolchain as 'clang'. However, the
// Swift open source toolchains for macOS distribute Clang without libarclite.
// In that case, to allow the linker to find 'libarclite', we point to the
// 'libarclite' in the XcodeDefault toolchain instead.
- if (getXcodeDeveloperPath(P).empty()) {
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ if (!getVFS().exists(P)) {
+ auto updatePath = [&](const Arg *A) {
// Try to infer the path to 'libarclite' in the toolchain from the
// specified SDK path.
StringRef XcodePathForSDK = getXcodeDeveloperPath(A->getValue());
- if (!XcodePathForSDK.empty()) {
- P = XcodePathForSDK;
- llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr");
- }
+ if (XcodePathForSDK.empty())
+ return false;
+
+ P = XcodePathForSDK;
+ llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr",
+ "lib", "arc");
+ return getVFS().exists(P);
+ };
+
+ bool updated = false;
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot))
+ updated = updatePath(A);
+
+ if (!updated) {
+ if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ))
+ updatePath(A);
}
}
CmdArgs.push_back("-force_load");
- llvm::sys::path::append(P, "lib", "arc", "libarclite_");
+ llvm::sys::path::append(P, "libarclite_");
// Mash in the platform.
if (isTargetWatchOSSimulator())
P += "watchsimulator";
@@ -1127,6 +1249,9 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
P += "macosx";
P += ".a";
+ if (!getVFS().exists(P))
+ getDriver().Diag(clang::diag::err_drv_darwin_sdk_missing_arclite) << P;
+
CmdArgs.push_back(Args.MakeArgString(P));
}
@@ -1152,8 +1277,9 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
DarwinLibName += getOSLibraryNameSuffix();
DarwinLibName += IsShared ? "_dynamic.dylib" : ".a";
SmallString<128> Dir(getDriver().ResourceDir);
- llvm::sys::path::append(
- Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin");
+ llvm::sys::path::append(Dir, "lib", "darwin");
+ if (Opts & RLO_IsEmbedded)
+ llvm::sys::path::append(Dir, "macho_embedded");
SmallString<128> P(Dir);
llvm::sys::path::append(P, DarwinLibName);
@@ -1171,7 +1297,7 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
// rpaths. This is currently true from this place, but we need to be
// careful if this function is ever called before user's rpaths are emitted.
if (Opts & RLO_AddRPath) {
- assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library");
+ assert(DarwinLibName.ends_with(".dylib") && "must be a dynamic library");
// Add @executable_path to rpath to support having the dylib copied with
// the executable.
@@ -1197,6 +1323,10 @@ StringRef Darwin::getPlatformFamily() const {
return "AppleTV";
case DarwinPlatformKind::WatchOS:
return "Watch";
+ case DarwinPlatformKind::DriverKit:
+ return "DriverKit";
+ case DarwinPlatformKind::XROS:
+ return "XR";
}
llvm_unreachable("Unsupported platform");
}
@@ -1207,8 +1337,8 @@ StringRef Darwin::getSDKName(StringRef isysroot) {
auto EndSDK = llvm::sys::path::rend(isysroot);
for (auto IT = BeginSDK; IT != EndSDK; ++IT) {
StringRef SDK = *IT;
- if (SDK.endswith(".sdk"))
- return SDK.slice(0, SDK.size() - 4);
+ if (SDK.ends_with(".sdk"))
+ return SDK.slice(0, SDK.size() - 4);
}
return "";
}
@@ -1228,6 +1358,11 @@ StringRef Darwin::getOSLibraryNameSuffix(bool IgnoreSim) const {
case DarwinPlatformKind::WatchOS:
return TargetEnvironment == NativeEnvironment || IgnoreSim ? "watchos"
: "watchossim";
+ case DarwinPlatformKind::XROS:
+ return TargetEnvironment == NativeEnvironment || IgnoreSim ? "xros"
+ : "xrossim";
+ case DarwinPlatformKind::DriverKit:
+ return "driverkit";
}
llvm_unreachable("Unsupported platform");
}
@@ -1279,20 +1414,14 @@ void Darwin::addProfileRTLibs(const ArgList &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 (ForGCOV) {
- addExportedSymbol(CmdArgs, "___gcov_dump");
- addExportedSymbol(CmdArgs, "___gcov_reset");
- addExportedSymbol(CmdArgs, "_writeout_fn_list");
- addExportedSymbol(CmdArgs, "_reset_fn_list");
- } else {
- addExportedSymbol(CmdArgs, "___llvm_profile_filename");
- addExportedSymbol(CmdArgs, "___llvm_profile_raw_version");
- }
- addExportedSymbol(CmdArgs, "_lprofDirMode");
+ if (hasExportSymbolDirective(Args) && ForGCOV) {
+ addExportedSymbol(CmdArgs, "___gcov_dump");
+ addExportedSymbol(CmdArgs, "___gcov_reset");
+ addExportedSymbol(CmdArgs, "_writeout_fn_list");
+ addExportedSymbol(CmdArgs, "_reset_fn_list");
}
- // Align __llvm_prf_{cnts,data} sections to the maximum expected page
+ // Align __llvm_prf_{cnts,bits,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().
@@ -1302,7 +1431,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
// 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}) {
+ for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_bitmap, llvm::IPSK_data}) {
addSectalignToPage(
Args, CmdArgs, "__DATA",
llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO,
@@ -1323,7 +1452,7 @@ ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType(
const ArgList &Args) const {
if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) {
StringRef Value = A->getValue();
- if (Value != "compiler-rt")
+ if (Value != "compiler-rt" && Value != "platform")
getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform)
<< Value << "darwin";
}
@@ -1356,26 +1485,57 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
const SanitizerArgs &Sanitize = getSanitizerArgs(Args);
- if (Sanitize.needsAsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
- if (Sanitize.needsLsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
- if (Sanitize.needsUbsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs,
- Sanitize.requiresMinimalRuntime() ? "ubsan_minimal"
- : "ubsan",
- Sanitize.needsSharedRt());
- if (Sanitize.needsTsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
- if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
- AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
-
- // Libfuzzer is written in C++ and requires libcxx.
- AddCXXStdlibLibArgs(Args, CmdArgs);
- }
- if (Sanitize.needsStatsRt()) {
- AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink);
- AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
+
+ if (!Sanitize.needsSharedRt()) {
+ const char *sanitizer = nullptr;
+ if (Sanitize.needsUbsanRt()) {
+ sanitizer = "UndefinedBehaviorSanitizer";
+ } else if (Sanitize.needsAsanRt()) {
+ sanitizer = "AddressSanitizer";
+ } else if (Sanitize.needsTsanRt()) {
+ sanitizer = "ThreadSanitizer";
+ }
+ if (sanitizer) {
+ getDriver().Diag(diag::err_drv_unsupported_static_sanitizer_darwin)
+ << sanitizer;
+ return;
+ }
+ }
+
+ if (Sanitize.linkRuntimes()) {
+ if (Sanitize.needsAsanRt()) {
+ if (Sanitize.needsStableAbi()) {
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "asan_abi", /*shared=*/false);
+ } else {
+ assert(Sanitize.needsSharedRt() &&
+ "Static sanitizer runtimes not supported");
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
+ }
+ }
+ if (Sanitize.needsLsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
+ if (Sanitize.needsUbsanRt()) {
+ assert(Sanitize.needsSharedRt() &&
+ "Static sanitizer runtimes not supported");
+ AddLinkSanitizerLibArgs(
+ Args, CmdArgs,
+ Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" : "ubsan");
+ }
+ if (Sanitize.needsTsanRt()) {
+ assert(Sanitize.needsSharedRt() &&
+ "Static sanitizer runtimes not supported");
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
+ }
+ if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
+
+ // Libfuzzer is written in C++ and requires libcxx.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
+ if (Sanitize.needsStatsRt()) {
+ AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink);
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
+ }
}
const XRayArgs &XRay = getXRayArgs();
@@ -1385,9 +1545,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
AddLinkRuntimeLib(Args, CmdArgs, "xray-fdr");
}
+ if (isTargetDriverKit() && !Args.hasArg(options::OPT_nodriverkitlib)) {
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("DriverKit");
+ }
+
// Otherwise link libSystem, then the dynamic runtime library, and finally any
// target specific static runtime library.
- CmdArgs.push_back("-lSystem");
+ if (!isTargetDriverKit())
+ CmdArgs.push_back("-lSystem");
// Select the dynamic runtime library and the target specific static library.
if (isTargetIOSBased()) {
@@ -1406,17 +1572,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
/// If the macOS SDK version is the same or earlier than the system version,
/// then the SDK version is returned. Otherwise the system version is returned.
static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) {
- unsigned Major, Minor, Micro;
llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
if (!SystemTriple.isMacOSX())
return std::string(MacOSSDKVersion);
VersionTuple SystemVersion;
SystemTriple.getMacOSXVersion(SystemVersion);
+
+ unsigned Major, Minor, Micro;
bool HadExtra;
if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro,
HadExtra))
return std::string(MacOSSDKVersion);
VersionTuple SDKVersion(Major, Minor, Micro);
+
if (SDKVersion > SystemVersion)
return SystemVersion.getAsString();
return std::string(MacOSSDKVersion);
@@ -1478,6 +1646,10 @@ struct DarwinPlatform {
/// Returns true if the simulator environment can be inferred from the arch.
bool canInferSimulatorFromArch() const { return InferSimulatorFromArch; }
+ const std::optional<llvm::Triple> &getTargetVariantTriple() const {
+ return TargetVariantTriple;
+ }
+
/// Adds the -m<os>-version-min argument to the compiler invocation.
void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) {
if (Argument)
@@ -1487,10 +1659,10 @@ struct DarwinPlatform {
options::ID Opt;
switch (Platform) {
case DarwinPlatformKind::MacOS:
- Opt = options::OPT_mmacosx_version_min_EQ;
+ Opt = options::OPT_mmacos_version_min_EQ;
break;
case DarwinPlatformKind::IPhoneOS:
- Opt = options::OPT_miphoneos_version_min_EQ;
+ Opt = options::OPT_mios_version_min_EQ;
break;
case DarwinPlatformKind::TvOS:
Opt = options::OPT_mtvos_version_min_EQ;
@@ -1498,6 +1670,12 @@ struct DarwinPlatform {
case DarwinPlatformKind::WatchOS:
Opt = options::OPT_mwatchos_version_min_EQ;
break;
+ case DarwinPlatformKind::XROS:
+ // xrOS always explicitly provides a version in the triple.
+ return;
+ case DarwinPlatformKind::DriverKit:
+ // DriverKit always explicitly provides a version in the triple.
+ return;
}
Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion);
Args.append(Argument);
@@ -1522,7 +1700,7 @@ struct DarwinPlatform {
void setEnvironment(llvm::Triple::EnvironmentType EnvType,
const VersionTuple &OSVersion,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
switch (EnvType) {
case llvm::Triple::Simulator:
Environment = DarwinEnvironmentKind::Simulator;
@@ -1535,11 +1713,21 @@ struct DarwinPlatform {
if (const auto *MacCatalystToMacOSMapping = SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macCatalystToMacOSPair())) {
if (auto MacOSVersion = MacCatalystToMacOSMapping->map(
- OSVersion, NativeTargetVersion, None)) {
+ OSVersion, NativeTargetVersion, std::nullopt)) {
NativeTargetVersion = *MacOSVersion;
}
}
}
+ // In a zippered build, we could be building for a macOS target that's
+ // lower than the version that's implied by the OS version. In that case
+ // we need to use the minimum version as the native target version.
+ if (TargetVariantTriple) {
+ auto TargetVariantVersion = TargetVariantTriple->getOSVersion();
+ if (TargetVariantVersion.getMajor()) {
+ if (TargetVariantVersion < NativeTargetVersion)
+ NativeTargetVersion = TargetVariantVersion;
+ }
+ }
break;
}
default:
@@ -1549,28 +1737,33 @@ struct DarwinPlatform {
static DarwinPlatform
createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ std::optional<llvm::Triple> TargetVariantTriple,
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
DarwinPlatform Result(TargetArg, getPlatformFromOS(TT.getOS()), OSVersion,
A);
VersionTuple OsVersion = TT.getOSVersion();
if (OsVersion.getMajor() == 0)
Result.HasOSVersion = false;
+ Result.TargetVariantTriple = TargetVariantTriple;
Result.setEnvironment(TT.getEnvironment(), OsVersion, SDKInfo);
return Result;
}
static DarwinPlatform
createFromMTargetOS(llvm::Triple::OSType OS, VersionTuple OSVersion,
llvm::Triple::EnvironmentType Environment, Arg *A,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
DarwinPlatform Result(MTargetOSArg, getPlatformFromOS(OS),
OSVersion.getAsString(), A);
Result.InferSimulatorFromArch = false;
Result.setEnvironment(Environment, OSVersion, SDKInfo);
return Result;
}
- static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform,
- Arg *A) {
- return DarwinPlatform(OSVersionArg, Platform, A);
+ static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, Arg *A,
+ bool IsSimulator) {
+ DarwinPlatform Result{OSVersionArg, Platform, A};
+ if (IsSimulator)
+ Result.Environment = DarwinEnvironmentKind::Simulator;
+ return Result;
}
static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform,
StringRef EnvVarName,
@@ -1625,6 +1818,10 @@ private:
return DarwinPlatformKind::TvOS;
case llvm::Triple::WatchOS:
return DarwinPlatformKind::WatchOS;
+ case llvm::Triple::XROS:
+ return DarwinPlatformKind::XROS;
+ case llvm::Triple::DriverKit:
+ return DarwinPlatformKind::DriverKit;
default:
llvm_unreachable("Unable to infer Darwin variant");
}
@@ -1638,15 +1835,16 @@ private:
bool HasOSVersion = true, InferSimulatorFromArch = true;
Arg *Argument;
StringRef EnvVarName;
+ std::optional<llvm::Triple> TargetVariantTriple;
};
/// Returns the deployment target that's specified using the -m<os>-version-min
/// argument.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
const Driver &TheDriver) {
- Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
- Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ,
+ Arg *macOSVersion = Args.getLastArg(options::OPT_mmacos_version_min_EQ);
+ Arg *iOSVersion = Args.getLastArg(options::OPT_mios_version_min_EQ,
options::OPT_mios_simulator_version_min_EQ);
Arg *TvOSVersion =
Args.getLastArg(options::OPT_mtvos_version_min_EQ,
@@ -1654,37 +1852,47 @@ getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
Arg *WatchOSVersion =
Args.getLastArg(options::OPT_mwatchos_version_min_EQ,
options::OPT_mwatchos_simulator_version_min_EQ);
- if (OSXVersion) {
+ if (macOSVersion) {
if (iOSVersion || TvOSVersion || WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
- << OSXVersion->getAsString(Args)
+ << macOSVersion->getAsString(Args)
<< (iOSVersion ? iOSVersion
: TvOSVersion ? TvOSVersion : WatchOSVersion)
->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion);
+ return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion,
+ /*IsSimulator=*/false);
} else if (iOSVersion) {
if (TvOSVersion || WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
<< iOSVersion->getAsString(Args)
<< (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion);
+ return DarwinPlatform::createOSVersionArg(
+ Darwin::IPhoneOS, iOSVersion,
+ iOSVersion->getOption().getID() ==
+ options::OPT_mios_simulator_version_min_EQ);
} else if (TvOSVersion) {
if (WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
<< TvOSVersion->getAsString(Args)
<< WatchOSVersion->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion);
+ return DarwinPlatform::createOSVersionArg(
+ Darwin::TvOS, TvOSVersion,
+ TvOSVersion->getOption().getID() ==
+ options::OPT_mtvos_simulator_version_min_EQ);
} else if (WatchOSVersion)
- return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion);
- return None;
+ return DarwinPlatform::createOSVersionArg(
+ Darwin::WatchOS, WatchOSVersion,
+ WatchOSVersion->getOption().getID() ==
+ options::OPT_mwatchos_simulator_version_min_EQ);
+ return std::nullopt;
}
/// Returns the deployment target that's specified using the
/// OS_DEPLOYMENT_TARGET environment variable.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
const llvm::Triple &Triple) {
std::string Targets[Darwin::LastDarwinPlatform + 1];
@@ -1693,10 +1901,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
"IPHONEOS_DEPLOYMENT_TARGET",
"TVOS_DEPLOYMENT_TARGET",
"WATCHOS_DEPLOYMENT_TARGET",
+ "DRIVERKIT_DEPLOYMENT_TARGET",
};
- static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1,
+ static_assert(std::size(EnvVars) == Darwin::LastDarwinPlatform + 1,
"Missing platform");
- for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) {
+ for (const auto &I : llvm::enumerate(llvm::ArrayRef(EnvVars))) {
if (char *Env = ::getenv(I.value()))
Targets[I.index()] = Env;
}
@@ -1715,11 +1924,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
Targets[Darwin::TvOS] = "";
} else {
// Don't allow conflicts in any other platform.
- unsigned FirstTarget = llvm::array_lengthof(Targets);
- for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) {
+ unsigned FirstTarget = std::size(Targets);
+ for (unsigned I = 0; I != std::size(Targets); ++I) {
if (Targets[I].empty())
continue;
- if (FirstTarget == llvm::array_lengthof(Targets))
+ if (FirstTarget == std::size(Targets))
FirstTarget = I;
else
TheDriver.Diag(diag::err_drv_conflicting_deployment_targets)
@@ -1727,13 +1936,13 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
}
}
- for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) {
+ for (const auto &Target : llvm::enumerate(llvm::ArrayRef(Targets))) {
if (!Target.value().empty())
return DarwinPlatform::createDeploymentTargetEnv(
(Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()],
Target.value());
}
- return None;
+ return std::nullopt;
}
/// Returns the SDK name without the optional prefix that ends with a '.' or an
@@ -1748,16 +1957,16 @@ static StringRef dropSDKNamePrefix(StringRef SDKName) {
/// Tries to infer the deployment target from the SDK specified by -isysroot
/// (or SDKROOT). Uses the version specified in the SDKSettings.json file if
/// it's available.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
inferDeploymentTargetFromSDK(DerivedArgList &Args,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
const Arg *A = Args.getLastArg(options::OPT_isysroot);
if (!A)
- return None;
+ return std::nullopt;
StringRef isysroot = A->getValue();
StringRef SDK = Darwin::getSDKName(isysroot);
if (!SDK.size())
- return None;
+ return std::nullopt;
std::string Version;
if (SDKInfo) {
@@ -1772,26 +1981,33 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args,
Version = std::string(SDK.slice(StartVer, EndVer + 1));
}
if (Version.empty())
- return None;
+ return std::nullopt;
auto CreatePlatformFromSDKName =
- [&](StringRef SDK) -> Optional<DarwinPlatform> {
- if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator"))
+ [&](StringRef SDK) -> std::optional<DarwinPlatform> {
+ if (SDK.starts_with("iPhoneOS") || SDK.starts_with("iPhoneSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::IPhoneOS, Version,
- /*IsSimulator=*/SDK.startswith("iPhoneSimulator"));
- else if (SDK.startswith("MacOSX"))
+ /*IsSimulator=*/SDK.starts_with("iPhoneSimulator"));
+ else if (SDK.starts_with("MacOSX"))
return DarwinPlatform::createFromSDK(Darwin::MacOS,
getSystemOrSDKMacOSVersion(Version));
- else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator"))
+ else if (SDK.starts_with("WatchOS") || SDK.starts_with("WatchSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::WatchOS, Version,
- /*IsSimulator=*/SDK.startswith("WatchSimulator"));
- else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator"))
+ /*IsSimulator=*/SDK.starts_with("WatchSimulator"));
+ else if (SDK.starts_with("AppleTVOS") ||
+ SDK.starts_with("AppleTVSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::TvOS, Version,
- /*IsSimulator=*/SDK.startswith("AppleTVSimulator"));
- return None;
+ /*IsSimulator=*/SDK.starts_with("AppleTVSimulator"));
+ else if (SDK.starts_with("XR"))
+ return DarwinPlatform::createFromSDK(
+ Darwin::XROS, Version,
+ /*IsSimulator=*/SDK.contains("Simulator"));
+ else if (SDK.starts_with("DriverKit"))
+ return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version);
+ return std::nullopt;
};
if (auto Result = CreatePlatformFromSDKName(SDK))
return Result;
@@ -1827,6 +2043,14 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple,
case llvm::Triple::WatchOS:
OsVersion = Triple.getWatchOSVersion();
break;
+ case llvm::Triple::XROS:
+ OsVersion = Triple.getOSVersion();
+ if (!OsVersion.getMajor())
+ OsVersion = OsVersion.withMajorReplaced(1);
+ break;
+ case llvm::Triple::DriverKit:
+ OsVersion = Triple.getDriverKitVersion();
+ break;
default:
llvm_unreachable("Unexpected OS type");
break;
@@ -1834,99 +2058,117 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple,
std::string OSVersion;
llvm::raw_string_ostream(OSVersion)
- << OsVersion.getMajor() << '.' << OsVersion.getMinor().getValueOr(0)
- << '.' << OsVersion.getSubminor().getValueOr(0);
+ << OsVersion.getMajor() << '.' << OsVersion.getMinor().value_or(0) << '.'
+ << OsVersion.getSubminor().value_or(0);
return OSVersion;
}
/// Tries to infer the target OS from the -arch.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain,
const llvm::Triple &Triple,
const Driver &TheDriver) {
llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS;
StringRef MachOArchName = Toolchain.getMachOArchName(Args);
- if (MachOArchName == "arm64" || MachOArchName == "arm64e") {
-#if __arm64__
- // A clang running on an Apple Silicon mac defaults
- // to building for mac when building for arm64 rather than
- // defaulting to iOS.
+ if (MachOArchName == "arm64" || MachOArchName == "arm64e")
OSTy = llvm::Triple::MacOSX;
-#else
- OSTy = llvm::Triple::IOS;
-#endif
- } else if (MachOArchName == "armv7" || MachOArchName == "armv7s")
+ else if (MachOArchName == "armv7" || MachOArchName == "armv7s")
OSTy = llvm::Triple::IOS;
else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32")
OSTy = llvm::Triple::WatchOS;
else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
MachOArchName != "armv7em")
OSTy = llvm::Triple::MacOSX;
-
if (OSTy == llvm::Triple::UnknownOS)
- return None;
+ return std::nullopt;
return DarwinPlatform::createFromArch(OSTy,
getOSVersion(OSTy, Triple, TheDriver));
}
/// Returns the deployment target that's specified using the -target option.
-Optional<DarwinPlatform> getDeploymentTargetFromTargetArg(
+std::optional<DarwinPlatform> getDeploymentTargetFromTargetArg(
DerivedArgList &Args, const llvm::Triple &Triple, const Driver &TheDriver,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
if (!Args.hasArg(options::OPT_target))
- return None;
+ return std::nullopt;
if (Triple.getOS() == llvm::Triple::Darwin ||
Triple.getOS() == llvm::Triple::UnknownOS)
- return None;
+ return std::nullopt;
std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver);
- return DarwinPlatform::createFromTarget(
- Triple, OSVersion, Args.getLastArg(options::OPT_target), SDKInfo);
+ std::optional<llvm::Triple> TargetVariantTriple;
+ for (const Arg *A : Args.filtered(options::OPT_darwin_target_variant)) {
+ llvm::Triple TVT(A->getValue());
+ // Find a matching <arch>-<vendor> target variant triple that can be used.
+ if ((Triple.getArch() == llvm::Triple::aarch64 ||
+ TVT.getArchName() == Triple.getArchName()) &&
+ TVT.getArch() == Triple.getArch() &&
+ TVT.getSubArch() == Triple.getSubArch() &&
+ TVT.getVendor() == Triple.getVendor()) {
+ if (TargetVariantTriple)
+ continue;
+ A->claim();
+ // Accept a -target-variant triple when compiling code that may run on
+ // macOS or Mac Catalyst.
+ if ((Triple.isMacOSX() && TVT.getOS() == llvm::Triple::IOS &&
+ TVT.isMacCatalystEnvironment()) ||
+ (TVT.isMacOSX() && Triple.getOS() == llvm::Triple::IOS &&
+ Triple.isMacCatalystEnvironment())) {
+ TargetVariantTriple = TVT;
+ continue;
+ }
+ TheDriver.Diag(diag::err_drv_target_variant_invalid)
+ << A->getSpelling() << A->getValue();
+ }
+ }
+ return DarwinPlatform::createFromTarget(Triple, OSVersion,
+ Args.getLastArg(options::OPT_target),
+ TargetVariantTriple, SDKInfo);
}
/// Returns the deployment target that's specified using the -mtargetos option.
-Optional<DarwinPlatform>
-getDeploymentTargetFromMTargetOSArg(DerivedArgList &Args,
- const Driver &TheDriver,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+std::optional<DarwinPlatform> getDeploymentTargetFromMTargetOSArg(
+ DerivedArgList &Args, const Driver &TheDriver,
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
auto *A = Args.getLastArg(options::OPT_mtargetos_EQ);
if (!A)
- return None;
+ return std::nullopt;
llvm::Triple TT(llvm::Twine("unknown-apple-") + A->getValue());
switch (TT.getOS()) {
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
case llvm::Triple::WatchOS:
+ case llvm::Triple::XROS:
break;
default:
TheDriver.Diag(diag::err_drv_invalid_os_in_arg)
<< TT.getOSName() << A->getAsString(Args);
- return None;
+ return std::nullopt;
}
VersionTuple Version = TT.getOSVersion();
if (!Version.getMajor()) {
TheDriver.Diag(diag::err_drv_invalid_version_number)
<< A->getAsString(Args);
- return None;
+ return std::nullopt;
}
return DarwinPlatform::createFromMTargetOS(TT.getOS(), Version,
TT.getEnvironment(), A, SDKInfo);
}
-Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS,
- const ArgList &Args,
- const Driver &TheDriver) {
+std::optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS,
+ const ArgList &Args,
+ const Driver &TheDriver) {
const Arg *A = Args.getLastArg(options::OPT_isysroot);
if (!A)
- return None;
+ return std::nullopt;
StringRef isysroot = A->getValue();
auto SDKInfoOrErr = parseDarwinSDKInfo(VFS, isysroot);
if (!SDKInfoOrErr) {
llvm::consumeError(SDKInfoOrErr.takeError());
TheDriver.Diag(diag::warn_drv_darwin_sdk_invalid_settings);
- return None;
+ return std::nullopt;
}
return *SDKInfoOrErr;
}
@@ -1960,7 +2202,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
SDKInfo = parseSDKSettings(getVFS(), Args, getDriver());
// The OS and the version can be specified using the -target argument.
- Optional<DarwinPlatform> OSTarget =
+ std::optional<DarwinPlatform> OSTarget =
getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver(), SDKInfo);
if (OSTarget) {
// Disallow mixing -target and -mtargetos=.
@@ -1970,7 +2212,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
getDriver().Diag(diag::err_drv_cannot_mix_options)
<< TargetArgStr << MTargetOSArgStr;
}
- Optional<DarwinPlatform> OSVersionArgTarget =
+ std::optional<DarwinPlatform> OSVersionArgTarget =
getDeploymentTargetFromOSVersionArg(Args, getDriver());
if (OSVersionArgTarget) {
unsigned TargetMajor, TargetMinor, TargetMicro;
@@ -1996,7 +2238,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
std::string OSVersionArg =
OSVersionArgTarget->getAsString(Args, Opts);
std::string TargetArg = OSTarget->getAsString(Args, Opts);
- getDriver().Diag(clang::diag::warn_drv_overriding_flag_option)
+ getDriver().Diag(clang::diag::warn_drv_overriding_option)
<< OSVersionArg << TargetArg;
}
}
@@ -2005,7 +2247,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
SDKInfo))) {
// The OS target can be specified using the -mtargetos= argument.
// Disallow mixing -mtargetos= and -m<os>version-min=.
- Optional<DarwinPlatform> OSVersionArgTarget =
+ std::optional<DarwinPlatform> OSVersionArgTarget =
getDeploymentTargetFromOSVersionArg(Args, getDriver());
if (OSVersionArgTarget) {
std::string MTargetOSArgStr = OSTarget->getAsString(Args, Opts);
@@ -2023,7 +2265,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple());
if (OSTarget) {
// Don't infer simulator from the arch when the SDK is also specified.
- Optional<DarwinPlatform> SDKTarget =
+ std::optional<DarwinPlatform> SDKTarget =
inferDeploymentTargetFromSDK(Args, SDKInfo);
if (SDKTarget)
OSTarget->setEnvironment(SDKTarget->getEnvironment());
@@ -2052,17 +2294,20 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
unsigned Major, Minor, Micro;
bool HadExtra;
+ // The major version should not be over this number.
+ const unsigned MajorVersionLimit = 1000;
// Set the tool chain target information.
if (Platform == MacOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major < 10 || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major < 10 || Major >= MajorVersionLimit || Minor >= 100 ||
+ Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else if (Platform == IPhoneOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
;
@@ -2094,13 +2339,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
} else if (Platform == TvOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else if (Platform == WatchOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << OSTarget->getAsString(Args, Opts);
+ } else if (Platform == DriverKit) {
+ if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
+ Micro, HadExtra) ||
+ HadExtra || Major < 19 || Major >= MajorVersionLimit || Minor >= 100 ||
+ Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << OSTarget->getAsString(Args, Opts);
+ } else if (Platform == XROS) {
+ if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
+ Micro, HadExtra) ||
+ HadExtra || Major < 1 || Major >= MajorVersionLimit || Minor >= 100 ||
+ Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else
@@ -2109,42 +2368,60 @@ 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().isX86())
+ Platform != DriverKit && OSTarget->canInferSimulatorFromArch() &&
+ getTriple().isX86())
Environment = Simulator;
VersionTuple NativeTargetVersion;
if (Environment == MacCatalyst)
NativeTargetVersion = OSTarget->getNativeTargetVersion();
setTarget(Platform, Environment, Major, Minor, Micro, NativeTargetVersion);
+ TargetVariantTriple = OSTarget->getTargetVariantTriple();
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
StringRef SDK = getSDKName(A->getValue());
if (SDK.size() > 0) {
size_t StartVer = SDK.find_first_of("0123456789");
StringRef SDKName = SDK.slice(0, StartVer);
- if (!SDKName.startswith(getPlatformFamily()) &&
- !dropSDKNamePrefix(SDKName).startswith(getPlatformFamily()))
+ if (!SDKName.starts_with(getPlatformFamily()) &&
+ !dropSDKNamePrefix(SDKName).starts_with(getPlatformFamily()))
getDriver().Diag(diag::warn_incompatible_sysroot)
<< SDKName << getPlatformFamily();
}
}
}
-// Returns the effective header sysroot path to use. This comes either from
-// -isysroot or --sysroot.
-llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const {
- if(DriverArgs.hasArg(options::OPT_isysroot))
- return DriverArgs.getLastArgValue(options::OPT_isysroot);
- if (!getDriver().SysRoot.empty())
- return getDriver().SysRoot;
- return "/";
+// For certain platforms/environments almost all resources (e.g., headers) are
+// located in sub-directories, e.g., for DriverKit they live in
+// <SYSROOT>/System/DriverKit/usr/include (instead of <SYSROOT>/usr/include).
+static void AppendPlatformPrefix(SmallString<128> &Path,
+ const llvm::Triple &T) {
+ if (T.isDriverKit()) {
+ llvm::sys::path::append(Path, "System", "DriverKit");
+ }
+}
+
+// Returns the effective sysroot from either -isysroot or --sysroot, plus the
+// platform prefix (if any).
+llvm::SmallString<128>
+DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const {
+ llvm::SmallString<128> Path("/");
+ if (DriverArgs.hasArg(options::OPT_isysroot))
+ Path = DriverArgs.getLastArgValue(options::OPT_isysroot);
+ else if (!getDriver().SysRoot.empty())
+ Path = getDriver().SysRoot;
+
+ if (hasEffectiveTriple()) {
+ AppendPlatformPrefix(Path, getEffectiveTriple());
+ }
+ return Path;
}
void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const Driver &D = getDriver();
- llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
+ llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs);
bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc);
bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc);
@@ -2229,22 +2506,27 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
// Also check whether this is used for setting library search paths.
ToolChain::AddClangCXXStdlibIncludeArgs(DriverArgs, CC1Args);
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
- llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
+ llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs);
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
- // On Darwin, libc++ can be installed in one of the following two places:
- // 1. Alongside the compiler in <install>/include/c++/v1
- // 2. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
+ // On Darwin, libc++ can be installed in one of the following places:
+ // 1. Alongside the compiler in <install>/include/c++/v1
+ // 2. Alongside the compiler in <clang-executable-folder>/../include/c++/v1
+ // 3. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
//
- // The precendence of paths is as listed above, i.e. we take the first path
- // that exists. Also note that we never include libc++ twice -- we take the
- // first path that exists and don't send the other paths to CC1 (otherwise
+ // The precedence of paths is as listed above, i.e. we take the first path
+ // that exists. Note that we never include libc++ twice -- we take the first
+ // path that exists and don't send the other paths to CC1 (otherwise
// include_next could break).
+ //
+ // Also note that in most cases, (1) and (2) are exactly the same path.
+ // Those two paths will differ only when the `clang` program being run
+ // is actually a symlink to the real executable.
// Check for (1)
// Get from '<install>/bin' to '<install>/include/c++/v1'.
@@ -2261,7 +2543,20 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
<< "\"\n";
}
- // Otherwise, check for (2)
+ // (2) Check for the folder where the executable is located, if different.
+ if (getDriver().getInstalledDir() != getDriver().Dir) {
+ InstallBin = llvm::StringRef(getDriver().Dir);
+ llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
+ if (getVFS().exists(InstallBin)) {
+ addSystemInclude(DriverArgs, CC1Args, InstallBin);
+ return;
+ } else if (DriverArgs.hasArg(options::OPT_v)) {
+ llvm::errs() << "ignoring nonexistent directory \"" << InstallBin
+ << "\"\n";
+ }
+ }
+
+ // Otherwise, check for (3)
llvm::SmallString<128> SysrootUsr = Sysroot;
llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1");
if (getVFS().exists(SysrootUsr)) {
@@ -2285,17 +2580,6 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
switch (arch) {
default: break;
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.2.1",
- "powerpc-apple-darwin10",
- arch == llvm::Triple::ppc64 ? "ppc64" : "");
- IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.0.0", "powerpc-apple-darwin10",
- arch == llvm::Triple::ppc64 ? "ppc64" : "");
- break;
-
case llvm::Triple::x86:
case llvm::Triple::x86_64:
IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
@@ -2334,6 +2618,7 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
break;
}
}
+
void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
@@ -2341,6 +2626,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
break;
case ToolChain::CST_Libstdcxx:
@@ -2395,6 +2682,12 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a");
} else if (isTargetIPhoneOS()) {
llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a");
+ } else if (isTargetDriverKit()) {
+ // DriverKit doesn't want extra runtime support.
+ } else if (isTargetXROSDevice()) {
+ llvm::sys::path::append(
+ P, llvm::Twine("libclang_rt.cc_kext_") +
+ llvm::Triple::getOSTypeName(llvm::Triple::XROS) + ".a");
} else {
llvm::sys::path::append(P, "libclang_rt.cc_kext.a");
}
@@ -2422,12 +2715,9 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
if (A->getOption().matches(options::OPT_Xarch__)) {
// Skip this argument unless the architecture matches either the toolchain
// triple arch, or the arch being bound.
- llvm::Triple::ArchType XarchArch =
- tools::darwin::getArchTypeForMachOArchName(A->getValue(0));
- if (!(XarchArch == getArch() ||
- (!BoundArch.empty() &&
- XarchArch ==
- tools::darwin::getArchTypeForMachOArchName(BoundArch))))
+ StringRef XarchArch = A->getValue(0);
+ if (!(XarchArch == getArchName() ||
+ (!BoundArch.empty() && XarchArch == BoundArch)))
continue;
Arg *OriginalArg = A;
@@ -2497,19 +2787,11 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
DAL->AddFlagArg(
A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings));
break;
-
- case options::OPT_fpascal_strings:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings));
- break;
-
- case options::OPT_fno_pascal_strings:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings));
- break;
}
}
// Add the arch options based on the particular spelling of -arch, to match
- // how the driver driver works.
+ // how the driver works.
if (!BoundArch.empty()) {
StringRef Name = BoundArch;
const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ);
@@ -2620,11 +2902,36 @@ bool Darwin::isAlignedAllocationUnavailable() const {
case WatchOS: // Earlier than 4.0.
OS = llvm::Triple::WatchOS;
break;
+ case XROS: // Always available.
+ return false;
+ case DriverKit: // Always available.
+ return false;
}
return TargetVersion < alignedAllocMinVersion(OS);
}
+static bool sdkSupportsBuiltinModules(const Darwin::DarwinPlatformKind &TargetPlatform, const std::optional<DarwinSDKInfo> &SDKInfo) {
+ if (!SDKInfo)
+ return false;
+
+ VersionTuple SDKVersion = SDKInfo->getVersion();
+ switch (TargetPlatform) {
+ case Darwin::MacOS:
+ return SDKVersion >= VersionTuple(99U);
+ case Darwin::IPhoneOS:
+ return SDKVersion >= VersionTuple(99U);
+ case Darwin::TvOS:
+ return SDKVersion >= VersionTuple(99U);
+ case Darwin::WatchOS:
+ return SDKVersion >= VersionTuple(99U);
+ case Darwin::XROS:
+ return SDKVersion >= VersionTuple(99U);
+ default:
+ return true;
+ }
+}
+
void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const {
@@ -2635,6 +2942,45 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
isAlignedAllocationUnavailable())
CC1Args.push_back("-faligned-alloc-unavailable");
+ addClangCC1ASTargetOptions(DriverArgs, CC1Args);
+
+ // Enable compatibility mode for NSItemProviderCompletionHandler in
+ // Foundation/NSItemProvider.h.
+ CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking");
+
+ // Give static local variables in inline functions hidden visibility when
+ // -fvisibility-inlines-hidden is enabled.
+ if (!DriverArgs.getLastArgNoClaim(
+ options::OPT_fvisibility_inlines_hidden_static_local_var,
+ options::OPT_fno_visibility_inlines_hidden_static_local_var))
+ CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var");
+
+ // Earlier versions of the darwin SDK have the C standard library headers
+ // all together in the Darwin module. That leads to module cycles with
+ // the _Builtin_ modules. e.g. <inttypes.h> on darwin includes <stdint.h>.
+ // The builtin <stdint.h> include-nexts <stdint.h>. When both of those
+ // darwin headers are in the Darwin module, there's a module cycle Darwin ->
+ // _Builtin_stdint -> Darwin (i.e. inttypes.h (darwin) -> stdint.h (builtin) ->
+ // stdint.h (darwin)). This is fixed in later versions of the darwin SDK,
+ // but until then, the builtin headers need to join the system modules.
+ // i.e. when the builtin stdint.h is in the Darwin module too, the cycle
+ // goes away. Note that -fbuiltin-headers-in-system-modules does nothing
+ // to fix the same problem with C++ headers, and is generally fragile.
+ if (!sdkSupportsBuiltinModules(TargetPlatform, SDKInfo))
+ CC1Args.push_back("-fbuiltin-headers-in-system-modules");
+
+ if (!DriverArgs.hasArgNoClaim(options::OPT_fdefine_target_os_macros,
+ options::OPT_fno_define_target_os_macros))
+ CC1Args.push_back("-fdefine-target-os-macros");
+}
+
+void Darwin::addClangCC1ASTargetOptions(
+ const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1ASArgs) const {
+ if (TargetVariantTriple) {
+ CC1ASArgs.push_back("-darwin-target-variant-triple");
+ CC1ASArgs.push_back(Args.MakeArgString(TargetVariantTriple->getTriple()));
+ }
+
if (SDKInfo) {
/// Pass the SDK version to the compiler when the SDK information is
/// available.
@@ -2642,32 +2988,45 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-target-sdk-version=" << V;
- CC1Args.push_back(DriverArgs.MakeArgString(OS.str()));
+ CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
};
if (isTargetMacCatalyst()) {
if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
- Optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map(
- SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), None);
+ std::optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map(
+ SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(),
+ std::nullopt);
EmitTargetSDKVersionArg(
SDKVersion ? *SDKVersion : minimumMacCatalystDeploymentTarget());
}
} else {
EmitTargetSDKVersionArg(SDKInfo->getVersion());
}
- }
-
- // Enable compatibility mode for NSItemProviderCompletionHandler in
- // Foundation/NSItemProvider.h.
- CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking");
- // Give static local variables in inline functions hidden visibility when
- // -fvisibility-inlines-hidden is enabled.
- if (!DriverArgs.getLastArgNoClaim(
- options::OPT_fvisibility_inlines_hidden_static_local_var,
- options::OPT_fno_visibility_inlines_hidden_static_local_var))
- CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var");
+ /// Pass the target variant SDK version to the compiler when the SDK
+ /// information is available and is required for target variant.
+ if (TargetVariantTriple) {
+ if (isTargetMacCatalyst()) {
+ std::string Arg;
+ llvm::raw_string_ostream OS(Arg);
+ OS << "-darwin-target-variant-sdk-version=" << SDKInfo->getVersion();
+ CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
+ } else if (const auto *MacOStoMacCatalystMapping =
+ SDKInfo->getVersionMapping(
+ DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
+ if (std::optional<VersionTuple> SDKVersion =
+ MacOStoMacCatalystMapping->map(
+ SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(),
+ std::nullopt)) {
+ std::string Arg;
+ llvm::raw_string_ostream OS(Arg);
+ OS << "-darwin-target-variant-sdk-version=" << *SDKVersion;
+ CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
+ }
+ }
+ }
+ }
}
DerivedArgList *
@@ -2676,7 +3035,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
// First get the generic Apple args, before moving onto Darwin-specific ones.
DerivedArgList *DAL =
MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
- const OptTable &Opts = getDriver().getOpts();
// If no architecture is bound, none of the translations here are relevant.
if (BoundArch.empty())
@@ -2691,7 +3049,7 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
// FIXME: It would be far better to avoid inserting those -static arguments,
// but we can't check the deployment target in the translation code until
// it is set here.
- if (isTargetWatchOSBased() ||
+ if (isTargetWatchOSBased() || isTargetDriverKit() || isTargetXROS() ||
(isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) {
for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
Arg *A = *it;
@@ -2708,26 +3066,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
}
}
- if (!Args.getLastArg(options::OPT_stdlib_EQ) &&
- GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ),
- "libc++");
-
- // Validate the C++ standard library choice.
- CXXStdlibType Type = GetCXXStdlibType(*DAL);
- if (Type == ToolChain::CST_Libcxx) {
- // Check whether the target provides libc++.
- StringRef where;
-
- // Complain about targeting iOS < 5.0 in any way.
- if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0))
- where = "iOS 5.0";
-
- if (where != StringRef()) {
- getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where;
- }
- }
-
auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch);
if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) {
if (Args.hasFlag(options::OPT_fomit_frame_pointer,
@@ -2739,13 +3077,19 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
return DAL;
}
-bool MachO::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel MachO::getDefaultUnwindTableLevel(const ArgList &Args) const {
// Unwind tables are not emitted if -fno-exceptions is supplied (except when
// targeting x86_64).
- return getArch() == llvm::Triple::x86_64 ||
- (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj &&
- Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
- true));
+ if (getArch() == llvm::Triple::x86_64 ||
+ (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj &&
+ Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
+ true)))
+ return (getArch() == llvm::Triple::aarch64 ||
+ getArch() == llvm::Triple::aarch64_32)
+ ? UnwindTableLevel::Synchronous
+ : UnwindTableLevel::Asynchronous;
+
+ return UnwindTableLevel::None;
}
bool MachO::UseDwarfDebugFlags() const {
@@ -2754,6 +3098,12 @@ bool MachO::UseDwarfDebugFlags() const {
return false;
}
+std::string MachO::GetGlobalDebugPathRemapping() const {
+ if (const char *S = ::getenv("RC_DEBUG_PREFIX_MAP"))
+ return S;
+ return {};
+}
+
llvm::ExceptionHandling Darwin::GetExceptionModel(const ArgList &Args) const {
// Darwin uses SjLj exceptions on ARM.
if (getTriple().getArch() != llvm::Triple::arm &&
@@ -2793,6 +3143,8 @@ void Darwin::addMinVersionArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
VersionTuple TargetVersion = getTripleTargetVersion();
+ assert(!isTargetXROS() && "xrOS always uses -platform-version");
+
if (isTargetWatchOS())
CmdArgs.push_back("-watchos_version_min");
else if (isTargetWatchOSSimulator())
@@ -2801,6 +3153,8 @@ void Darwin::addMinVersionArgs(const ArgList &Args,
CmdArgs.push_back("-tvos_version_min");
else if (isTargetTvOSSimulator())
CmdArgs.push_back("-tvos_simulator_version_min");
+ else if (isTargetDriverKit())
+ CmdArgs.push_back("-driverkit_version_min");
else if (isTargetIOSSimulator())
CmdArgs.push_back("-ios_simulator_version_min");
else if (isTargetIOSBased())
@@ -2816,6 +3170,25 @@ void Darwin::addMinVersionArgs(const ArgList &Args,
if (!MinTgtVers.empty() && MinTgtVers > TargetVersion)
TargetVersion = MinTgtVers;
CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+ if (TargetVariantTriple) {
+ assert(isTargetMacOSBased() && "unexpected target");
+ VersionTuple VariantTargetVersion;
+ if (TargetVariantTriple->isMacOSX()) {
+ CmdArgs.push_back("-macosx_version_min");
+ TargetVariantTriple->getMacOSXVersion(VariantTargetVersion);
+ } else {
+ assert(TargetVariantTriple->isiOS() &&
+ TargetVariantTriple->isMacCatalystEnvironment() &&
+ "unexpected target variant triple");
+ CmdArgs.push_back("-maccatalyst_version_min");
+ VariantTargetVersion = TargetVariantTriple->getiOSVersion();
+ }
+ VersionTuple MinTgtVers =
+ TargetVariantTriple->getMinimumSupportedOSVersion();
+ if (MinTgtVers.getMajor() && MinTgtVers > VariantTargetVersion)
+ VariantTargetVersion = MinTgtVers;
+ CmdArgs.push_back(Args.MakeArgString(VariantTargetVersion.getAsString()));
+ }
}
static const char *getPlatformName(Darwin::DarwinPlatformKind Platform,
@@ -2831,58 +3204,100 @@ static const char *getPlatformName(Darwin::DarwinPlatformKind Platform,
return "tvos";
case Darwin::WatchOS:
return "watchos";
+ case Darwin::XROS:
+ return "xros";
+ case Darwin::DriverKit:
+ return "driverkit";
}
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 = getTripleTargetVersion().withoutBuild();
- VersionTuple MinTgtVers = getEffectiveTriple().getMinimumSupportedOSVersion();
- if (!MinTgtVers.empty() && MinTgtVers > TargetVersion)
- TargetVersion = MinTgtVers;
- CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+ auto EmitPlatformVersionArg =
+ [&](const VersionTuple &TV, Darwin::DarwinPlatformKind TargetPlatform,
+ Darwin::DarwinEnvironmentKind TargetEnvironment,
+ const llvm::Triple &TT) {
+ // -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 = TV.withoutBuild();
+ if ((TargetPlatform == Darwin::IPhoneOS ||
+ TargetPlatform == Darwin::TvOS) &&
+ getTriple().getArchName() == "arm64e" &&
+ TargetVersion.getMajor() < 14) {
+ // arm64e slice is supported on iOS/tvOS 14+ only.
+ TargetVersion = VersionTuple(14, 0);
+ }
+ VersionTuple MinTgtVers = TT.getMinimumSupportedOSVersion();
+ if (!MinTgtVers.empty() && MinTgtVers > TargetVersion)
+ TargetVersion = MinTgtVers;
+ CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+
+ if (TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst) {
+ // Mac Catalyst programs must use the appropriate iOS SDK version
+ // that corresponds to the macOS SDK version used for the compilation.
+ std::optional<VersionTuple> iOSSDKVersion;
+ if (SDKInfo) {
+ if (const auto *MacOStoMacCatalystMapping =
+ SDKInfo->getVersionMapping(
+ DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
+ iOSSDKVersion = MacOStoMacCatalystMapping->map(
+ SDKInfo->getVersion().withoutBuild(),
+ minimumMacCatalystDeploymentTarget(), std::nullopt);
+ }
+ }
+ CmdArgs.push_back(Args.MakeArgString(
+ (iOSSDKVersion ? *iOSSDKVersion
+ : minimumMacCatalystDeploymentTarget())
+ .getAsString()));
+ return;
+ }
- if (isTargetMacCatalyst()) {
- // Mac Catalyst programs must use the appropriate iOS SDK version
- // that corresponds to the macOS SDK version used for the compilation.
- Optional<VersionTuple> iOSSDKVersion;
- if (SDKInfo) {
- if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping(
- DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
- iOSSDKVersion = MacOStoMacCatalystMapping->map(
- SDKInfo->getVersion().withoutBuild(),
- minimumMacCatalystDeploymentTarget(), None);
- }
- }
- CmdArgs.push_back(Args.MakeArgString(
- (iOSSDKVersion ? *iOSSDKVersion : minimumMacCatalystDeploymentTarget())
- .getAsString()));
+ if (SDKInfo) {
+ VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild();
+ if (!SDKVersion.getMinor())
+ SDKVersion = VersionTuple(SDKVersion.getMajor(), 0);
+ CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString()));
+ } else {
+ // Use an SDK version that's matching the deployment target if the SDK
+ // version is missing. This is preferred over an empty SDK version
+ // (0.0.0) as the system's runtime might expect the linked binary to
+ // contain a valid SDK version in order for the binary to work
+ // correctly. It's reasonable to use the deployment target version as
+ // a proxy for the SDK version because older SDKs don't guarantee
+ // support for deployment targets newer than the SDK versions, so that
+ // rules out using some predetermined older SDK version, which leaves
+ // the deployment target version as the only reasonable choice.
+ CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+ }
+ };
+ EmitPlatformVersionArg(getTripleTargetVersion(), TargetPlatform,
+ TargetEnvironment, getEffectiveTriple());
+ if (!TargetVariantTriple)
return;
- }
-
- if (SDKInfo) {
- VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild();
- CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString()));
+ Darwin::DarwinPlatformKind Platform;
+ Darwin::DarwinEnvironmentKind Environment;
+ VersionTuple TargetVariantVersion;
+ if (TargetVariantTriple->isMacOSX()) {
+ TargetVariantTriple->getMacOSXVersion(TargetVariantVersion);
+ Platform = Darwin::MacOS;
+ Environment = Darwin::NativeEnvironment;
} else {
- // Use an SDK version that's matching the deployment target if the SDK
- // version is missing. This is preferred over an empty SDK version (0.0.0)
- // as the system's runtime might expect the linked binary to contain a
- // valid SDK version in order for the binary to work correctly. It's
- // reasonable to use the deployment target version as a proxy for the
- // SDK version because older SDKs don't guarantee support for deployment
- // targets newer than the SDK versions, so that rules out using some
- // predetermined older SDK version, which leaves the deployment target
- // version as the only reasonable choice.
- CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+ assert(TargetVariantTriple->isiOS() &&
+ TargetVariantTriple->isMacCatalystEnvironment() &&
+ "unexpected target variant triple");
+ TargetVariantVersion = TargetVariantTriple->getiOSVersion();
+ Platform = Darwin::IPhoneOS;
+ Environment = Darwin::MacCatalyst;
}
+ EmitPlatformVersionArg(TargetVariantVersion, Platform, Environment,
+ *TargetVariantTriple);
}
// Add additional link args for the -dynamiclib option.
@@ -2987,7 +3402,7 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args,
}
void Darwin::CheckObjCARC() const {
- if (isTargetIOSBased() || isTargetWatchOSBased() ||
+ if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetXROS() ||
(isTargetMacOSBased() && !isMacosxVersionLT(10, 6)))
return;
getDriver().Diag(diag::err_arc_unsupported_on_toolchain);
@@ -3003,7 +3418,6 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
- Res |= SanitizerKind::Function;
Res |= SanitizerKind::ObjCCast;
// Prior to 10.9, macOS shipped a version of the C++ standard library without
@@ -3013,16 +3427,15 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
!(isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0)))
Res |= SanitizerKind::Vptr;
- if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
+ if ((IsX86_64 || IsAArch64) &&
+ (isTargetMacOSBased() || isTargetIOSSimulator() ||
+ isTargetTvOSSimulator() || isTargetWatchOSSimulator())) {
Res |= SanitizerKind::Thread;
- } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) {
- if (IsX86_64)
- Res |= SanitizerKind::Thread;
}
return Res;
}
void Darwin::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
- RocmInstallation.print(OS);
+ CudaInstallation->print(OS);
+ RocmInstallation->print(OS);
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h
index 5e23047a5512..5e60b0841d6d 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
#include "Cuda.h"
+#include "LazyDetector.h"
#include "ROCm.h"
#include "clang/Basic/DarwinSDKInfo.h"
#include "clang/Basic/LangOptions.h"
@@ -28,7 +29,8 @@ namespace tools {
namespace darwin {
llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
-void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
+void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str,
+ const llvm::opt::ArgList &Args);
class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool {
virtual void anchor();
@@ -63,8 +65,8 @@ class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool {
bool NeedsTempPath(const InputInfoList &Inputs) const;
void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- const InputInfoList &Inputs, unsigned Version[5],
- bool LinkerIsLLD) const;
+ const InputInfoList &Inputs, VersionTuple Version,
+ bool LinkerIsLLD, bool UsePlatformVersion) const;
public:
Linker(const ToolChain &TC) : MachOTool("darwin::Linker", "linker", TC) {}
@@ -147,6 +149,9 @@ private:
mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil;
mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug;
+ /// The version of the linker known to be available in the tool chain.
+ mutable std::optional<VersionTuple> LinkerVersion;
+
public:
MachO(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
@@ -159,6 +164,10 @@ public:
/// example, Apple treats different ARM variations as distinct architectures.
StringRef getMachOArchName(const llvm::opt::ArgList &Args) const;
+ /// Get the version of the linker known to be available for a particular
+ /// compiler invocation (via the `-mlinker-version=` arg).
+ VersionTuple getLinkerVersion(const llvm::opt::ArgList &Args) const;
+
/// Add the linker arguments to link the ARC runtime library.
virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {}
@@ -231,10 +240,6 @@ public:
// expected to use /usr/include/Block.h.
return true;
}
- bool IsIntegratedAssemblerDefault() const override {
- // Default integrated assembler to on for Apple's MachO targets.
- return true;
- }
bool IsMathErrnoDefault() const override { return false; }
@@ -247,7 +252,8 @@ public:
bool UseObjCMixedDispatch() const override { return true; }
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;
@@ -260,6 +266,7 @@ public:
bool SupportsProfiling() const override;
bool UseDwarfDebugFlags() const override;
+ std::string GetGlobalDebugPathRemapping() const override;
llvm::ExceptionHandling
GetExceptionModel(const llvm::opt::ArgList &Args) const override {
@@ -291,7 +298,9 @@ public:
IPhoneOS,
TvOS,
WatchOS,
- LastDarwinPlatform = WatchOS
+ DriverKit,
+ XROS,
+ LastDarwinPlatform = DriverKit
};
enum DarwinEnvironmentKind {
NativeEnvironment,
@@ -308,10 +317,13 @@ public:
mutable VersionTuple OSTargetVersion;
/// The information about the darwin SDK that was used.
- mutable Optional<DarwinSDKInfo> SDKInfo;
+ mutable std::optional<DarwinSDKInfo> SDKInfo;
- CudaInstallationDetector CudaInstallation;
- RocmInstallationDetector RocmInstallation;
+ /// The target variant triple that was specified (if any).
+ mutable std::optional<llvm::Triple> TargetVariantTriple;
+
+ LazyDetector<CudaInstallationDetector> CudaInstallation;
+ LazyDetector<RocmInstallationDetector> RocmInstallation;
private:
void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const;
@@ -338,7 +350,7 @@ public:
bool isKernelStatic() const override {
return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) &&
- !isTargetWatchOS());
+ !isTargetWatchOS() && !isTargetDriverKit());
}
void addProfileRTLibs(const llvm::opt::ArgList &Args,
@@ -394,6 +406,16 @@ public:
return isTargetIPhoneOS() || isTargetIOSSimulator();
}
+ bool isTargetXROSDevice() const {
+ return TargetPlatform == XROS && TargetEnvironment == NativeEnvironment;
+ }
+
+ bool isTargetXROSSimulator() const {
+ return TargetPlatform == XROS && TargetEnvironment == Simulator;
+ }
+
+ bool isTargetXROS() const { return TargetPlatform == XROS; }
+
bool isTargetTvOS() const {
assert(TargetInitialized && "Target not initialized!");
return TargetPlatform == TvOS && TargetEnvironment == NativeEnvironment;
@@ -424,6 +446,11 @@ public:
return TargetPlatform == WatchOS;
}
+ bool isTargetDriverKit() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == DriverKit;
+ }
+
bool isTargetMacCatalyst() const {
return TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst;
}
@@ -488,6 +515,10 @@ protected:
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const override;
+ void addClangCC1ASTargetOptions(
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CC1ASArgs) const override;
+
StringRef getPlatformFamily() const;
StringRef getOSLibraryNameSuffix(bool IgnoreSim = false) const override;
@@ -527,7 +558,8 @@ public:
GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
// Stack protectors default to on for user code on 10.5,
// and for everything in 10.6 and beyond
- if (isTargetIOSBased() || isTargetWatchOSBased())
+ if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetDriverKit() ||
+ isTargetXROS())
return LangOptions::SSPOn;
else if (isTargetMacOSBased() && !isMacosxVersionLT(10, 6))
return LangOptions::SSPOn;
@@ -605,7 +637,8 @@ private:
llvm::StringRef ArchDir,
llvm::StringRef BitDir) const;
- llvm::StringRef GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const;
+ llvm::SmallString<128>
+ GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp
index 8cfec6a6c4e0..9942fc632e0a 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -19,21 +20,19 @@ using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
-/// DragonFly Tools
-
-// For now, DragonFly Assemble does just about the same as for
-// FreeBSD, but this may change soon.
void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
+ const auto &ToolChain = static_cast<const DragonFly &>(getToolChain());
ArgStringList CmdArgs;
+ claimNoWarnArgs(Args);
+
// When building 32-bit code on DragonFly/pc64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86)
+ if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
@@ -44,7 +43,7 @@ void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as"));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
@@ -55,21 +54,27 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
+ const auto &ToolChain = static_cast<const DragonFly &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool Static = Args.hasArg(options::OPT_static);
+ const bool Shared = Args.hasArg(options::OPT_shared);
+ const bool Profiling = Args.hasArg(options::OPT_pg);
+ const bool Pie = Args.hasArg(options::OPT_pie);
ArgStringList CmdArgs;
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_static)) {
+ if (Static) {
CmdArgs.push_back("-Bstatic");
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-Bshareable");
- else {
+ if (Shared)
+ CmdArgs.push_back("-shared");
+ else if (!Args.hasArg(options::OPT_r)) {
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/usr/libexec/ld-elf.so.2");
}
@@ -79,77 +84,92 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on DragonFly/pc64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86) {
+ if (Arch == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
}
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("gcrt1.o")));
+ const char *crt1 = nullptr;
+ const char *crtbegin = nullptr;
+ if (!Shared) {
+ if (Profiling)
+ crt1 = "gcrt1.o";
else {
- if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o")));
+ if (Pie)
+ crt1 = "Scrt1.o";
else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+ crt1 = "crt1.o";
}
}
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
+
+ if (Shared || Pie)
+ crtbegin = "crtbeginS.o";
else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ crtbegin = "crtbegin.o";
+
+ if (crt1)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
- Args.AddAllArgs(CmdArgs,
- {options::OPT_L, options::OPT_T_Group, options::OPT_e});
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_s, options::OPT_t, options::OPT_r});
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
options::OPT_r)) {
- CmdArgs.push_back("-L/usr/lib/gcc80");
-
- if (!Args.hasArg(options::OPT_static)) {
+ if (!Static) {
CmdArgs.push_back("-rpath");
CmdArgs.push_back("/usr/lib/gcc80");
}
+ // Use the static OpenMP runtime with -static-openmp
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
+ addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
+
if (D.CCCIsCXX()) {
- if (getToolChain().ShouldLinkCXXStdlib(Args))
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below (i.e.
+ // AddRunTimeLibs).
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
CmdArgs.push_back("-lm");
}
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
- if (!Args.hasArg(options::OPT_nolibc)) {
+ if (!Args.hasArg(options::OPT_nolibc))
CmdArgs.push_back("-lc");
- }
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_static_libgcc)) {
+ if (Static || Args.hasArg(options::OPT_static_libgcc)) {
CmdArgs.push_back("-lgcc");
CmdArgs.push_back("-lgcc_eh");
} else {
if (Args.hasArg(options::OPT_shared_libgcc)) {
CmdArgs.push_back("-lgcc_pic");
- if (!Args.hasArg(options::OPT_shared))
+ if (!Shared)
CmdArgs.push_back("-lgcc");
} else {
CmdArgs.push_back("-lgcc");
@@ -162,18 +182,19 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
+ const char *crtend = nullptr;
+ if (Shared || Pie)
+ crtend ="crtendS.o";
else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
+ crtend = "crtend.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- getToolChain().addProfileRTLibs(Args, CmdArgs);
+ ToolChain.addProfileRTLibs(Args, CmdArgs);
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
@@ -191,8 +212,35 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple,
getProgramPaths().push_back(getDriver().Dir);
getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
- getFilePaths().push_back("/usr/lib/gcc80");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/gcc80"));
+}
+
+void DragonFly::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ concat(D.SysRoot, "/usr/include"));
+}
+
+void DragonFly::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/c++/8.0"), "", "",
+ DriverArgs, CC1Args);
}
Tool *DragonFly::buildAssembler() const {
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h
index 3ed5acefaefb..715f6b45519b 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h
@@ -16,9 +16,10 @@
namespace clang {
namespace driver {
namespace tools {
-/// dragonfly -- Directly call GNU Binutils assembler and linker
+
+/// Directly call GNU Binutils assembler and linker
namespace dragonfly {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC)
: Tool("dragonfly::Assembler", "assembler", TC) {}
@@ -31,7 +32,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("dragonfly::Linker", "linker", TC) {}
@@ -55,6 +56,13 @@ public:
bool IsMathErrnoDefault() const override { return false; }
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp
index c169e3d45793..03d68c3df7fb 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp
@@ -6,11 +6,17 @@
//
//===----------------------------------------------------------------------===//
-
#include "Flang.h"
+#include "Arch/RISCV.h"
#include "CommonArgs.h"
+#include "clang/Basic/CodeGenOptions.h"
#include "clang/Driver/Options.h"
+#include "llvm/Frontend/Debug/Options.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/RISCVISAInfo.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
#include <cassert>
@@ -19,56 +25,653 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-void Flang::AddFortranDialectOptions(const ArgList &Args,
+/// Add -x lang to \p CmdArgs for \p Input.
+static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
+ ArgStringList &CmdArgs) {
+ CmdArgs.push_back("-x");
+ // Map the driver type to the frontend type.
+ CmdArgs.push_back(types::getTypeName(Input.getType()));
+}
+
+void Flang::addFortranDialectOptions(const ArgList &Args,
ArgStringList &CmdArgs) const {
- Args.AddAllArgs(
- CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form,
- options::OPT_ffixed_line_length_EQ, options::OPT_fopenmp,
- options::OPT_fopenacc, options::OPT_finput_charset_EQ,
- options::OPT_fimplicit_none, options::OPT_fno_implicit_none,
- options::OPT_fbackslash, options::OPT_fno_backslash,
- options::OPT_flogical_abbreviations,
- options::OPT_fno_logical_abbreviations,
- options::OPT_fxor_operator, options::OPT_fno_xor_operator,
- options::OPT_falternative_parameter_statement,
- options::OPT_fdefault_real_8, options::OPT_fdefault_integer_8,
- options::OPT_fdefault_double_8, options::OPT_flarge_sizes,
- options::OPT_fno_automatic});
-}
-
-void Flang::AddPreprocessingOptions(const ArgList &Args,
+ Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form,
+ options::OPT_ffree_form,
+ options::OPT_ffixed_line_length_EQ,
+ options::OPT_fopenmp,
+ options::OPT_fopenmp_version_EQ,
+ options::OPT_fopenacc,
+ options::OPT_finput_charset_EQ,
+ options::OPT_fimplicit_none,
+ options::OPT_fno_implicit_none,
+ options::OPT_fbackslash,
+ options::OPT_fno_backslash,
+ options::OPT_flogical_abbreviations,
+ options::OPT_fno_logical_abbreviations,
+ options::OPT_fxor_operator,
+ options::OPT_fno_xor_operator,
+ options::OPT_falternative_parameter_statement,
+ options::OPT_fdefault_real_8,
+ options::OPT_fdefault_integer_8,
+ options::OPT_fdefault_double_8,
+ options::OPT_flarge_sizes,
+ options::OPT_fno_automatic});
+}
+
+void Flang::addPreprocessingOptions(const ArgList &Args,
ArgStringList &CmdArgs) const {
- Args.AddAllArgs(CmdArgs,
+ Args.addAllArgs(CmdArgs,
{options::OPT_P, options::OPT_D, options::OPT_U,
options::OPT_I, options::OPT_cpp, options::OPT_nocpp});
}
-void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
- Args.AddAllArgs(CmdArgs,
+/// @C shouldLoopVersion
+///
+/// Check if Loop Versioning should be enabled.
+/// We look for the last of one of the following:
+/// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.
+/// Loop versioning is disabled if the last option is
+/// -fno-version-loops-for-stride.
+/// Loop versioning is enabled if the last option is one of:
+/// -floop-versioning
+/// -Ofast
+/// -O4
+/// -O3
+/// For all other cases, loop versioning is is disabled.
+///
+/// The gfortran compiler automatically enables the option for -O3 or -Ofast.
+///
+/// @return true if loop-versioning should be enabled, otherwise false.
+static bool shouldLoopVersion(const ArgList &Args) {
+ const Arg *LoopVersioningArg = Args.getLastArg(
+ options::OPT_Ofast, options::OPT_O, options::OPT_O4,
+ options::OPT_floop_versioning, options::OPT_fno_loop_versioning);
+ if (!LoopVersioningArg)
+ return false;
+
+ if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning))
+ return false;
+
+ if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning))
+ return true;
+
+ if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) ||
+ LoopVersioningArg->getOption().matches(options::OPT_O4))
+ return true;
+
+ if (LoopVersioningArg->getOption().matches(options::OPT_O)) {
+ StringRef S(LoopVersioningArg->getValue());
+ unsigned OptLevel = 0;
+ // Note -Os or Oz woould "fail" here, so return false. Which is the
+ // desiered behavior.
+ if (S.getAsInteger(10, OptLevel))
+ return false;
+
+ return OptLevel > 2;
+ }
+
+ llvm_unreachable("We should not end up here");
+ return false;
+}
+
+void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
+ Args.addAllArgs(CmdArgs,
{options::OPT_module_dir, options::OPT_fdebug_module_writer,
options::OPT_fintrinsic_modules_path, options::OPT_pedantic,
- options::OPT_std_EQ, options::OPT_W_Joined});
+ options::OPT_std_EQ, options::OPT_W_Joined,
+ options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ,
+ options::OPT_funderscoring, options::OPT_fno_underscoring});
+
+ llvm::codegenoptions::DebugInfoKind DebugInfoKind;
+ if (Args.hasArg(options::OPT_gN_Group)) {
+ Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);
+ DebugInfoKind = debugLevelToInfoKind(*gNArg);
+ } else if (Args.hasArg(options::OPT_g_Flag)) {
+ DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly;
+ } else {
+ DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
+ }
+ addDebugInfoKind(CmdArgs, DebugInfoKind);
+}
+
+void Flang::addCodegenOptions(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ Arg *stackArrays =
+ Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays,
+ options::OPT_fno_stack_arrays);
+ if (stackArrays &&
+ !stackArrays->getOption().matches(options::OPT_fno_stack_arrays))
+ CmdArgs.push_back("-fstack-arrays");
+
+ if (shouldLoopVersion(Args))
+ CmdArgs.push_back("-fversion-loops-for-stride");
+
+ Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,
+ options::OPT_flang_deprecated_no_hlfir,
+ options::OPT_flang_experimental_polymorphism,
+ options::OPT_fno_ppc_native_vec_elem_order,
+ options::OPT_fppc_native_vec_elem_order});
+}
+
+void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
+ // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
+ // (RelocationModel, PICLevel, IsPIE).
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) =
+ ParsePICArgs(getToolChain(), Args);
+
+ if (auto *RMName = RelocationModelName(RelocationModel)) {
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(RMName);
+ }
+ if (PICLevel > 0) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
+ if (IsPIE)
+ CmdArgs.push_back("-pic-is-pie");
+ }
+}
+
+void Flang::AddAArch64TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Handle -msve_vector_bits=<bits>
+ if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
+ StringRef Val = A->getValue();
+ const Driver &D = getToolChain().getDriver();
+ if (Val.equals("128") || Val.equals("256") || Val.equals("512") ||
+ Val.equals("1024") || Val.equals("2048") || Val.equals("128+") ||
+ Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") ||
+ Val.equals("2048+")) {
+ unsigned Bits = 0;
+ if (Val.ends_with("+"))
+ Val = Val.substr(0, Val.size() - 1);
+ else {
+ [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);
+ assert(!Invalid && "Failed to parse value");
+ CmdArgs.push_back(
+ Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128)));
+ }
+
+ [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);
+ assert(!Invalid && "Failed to parse value");
+ CmdArgs.push_back(
+ Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128)));
+ // Silently drop requests for vector-length agnostic code as it's implied.
+ } else if (!Val.equals("scalable"))
+ // Handle the unsupported values passed to msve-vector-bits.
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
+}
+
+void Flang::AddRISCVTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ // Handle -mrvv-vector-bits=<bits>
+ if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) {
+ StringRef Val = A->getValue();
+ const Driver &D = getToolChain().getDriver();
+
+ // Get minimum VLen from march.
+ unsigned MinVLen = 0;
+ StringRef Arch = riscv::getRISCVArch(Args, Triple);
+ auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
+ Arch, /*EnableExperimentalExtensions*/ true);
+ // Ignore parsing error.
+ if (!errorToBool(ISAInfo.takeError()))
+ MinVLen = (*ISAInfo)->getMinVLen();
+
+ // If the value is "zvl", use MinVLen from march. Otherwise, try to parse
+ // as integer as long as we have a MinVLen.
+ unsigned Bits = 0;
+ if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
+ Bits = MinVLen;
+ } else if (!Val.getAsInteger(10, Bits)) {
+ // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
+ // at least MinVLen.
+ if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock ||
+ Bits > 65536 || !llvm::isPowerOf2_32(Bits))
+ Bits = 0;
+ }
+
+ // If we got a valid value try to use it.
+ if (Bits != 0) {
+ unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock;
+ CmdArgs.push_back(
+ Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin)));
+ CmdArgs.push_back(
+ Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin)));
+ } else if (!Val.equals("scalable")) {
+ // Handle the unsupported values passed to mrvv-vector-bits.
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
+ }
+}
+
+static void addVSDefines(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+
+ unsigned ver = 0;
+ const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args);
+ ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 +
+ vt.getSubminor().value_or(0);
+ CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000)));
+ CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver)));
+ CmdArgs.push_back(Args.MakeArgString("-D_WIN32"));
+
+ llvm::Triple triple = TC.getTriple();
+ if (triple.isAArch64()) {
+ CmdArgs.push_back("-D_M_ARM64=1");
+ } else if (triple.isX86() && triple.isArch32Bit()) {
+ CmdArgs.push_back("-D_M_IX86=600");
+ } else if (triple.isX86() && triple.isArch64Bit()) {
+ CmdArgs.push_back("-D_M_X64=100");
+ } else {
+ llvm_unreachable(
+ "Flang on Windows only supports X86_32, X86_64 and AArch64");
+ }
+}
+
+static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ assert(TC.getTriple().isKnownWindowsMSVCEnvironment() &&
+ "can only add VS runtime library on Windows!");
+ // if -fno-fortran-main has been passed, skip linking Fortran_main.a
+ bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main);
+ if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
+ CmdArgs.push_back(Args.MakeArgString(
+ "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins")));
+ }
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+ if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
+ RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
+ .Case("static", options::OPT__SLASH_MT)
+ .Case("static_dbg", options::OPT__SLASH_MTd)
+ .Case("dll", options::OPT__SLASH_MD)
+ .Case("dll_dbg", options::OPT__SLASH_MDd)
+ .Default(options::OPT__SLASH_MT);
+ }
+ switch (RTOptionID) {
+ case options::OPT__SLASH_MT:
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("--dependent-lib=libcmt");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib");
+ CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib");
+ CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib");
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("--dependent-lib=libcmtd");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib");
+ CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");
+ CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");
+ break;
+ case options::OPT__SLASH_MD:
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ CmdArgs.push_back("--dependent-lib=msvcrt");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib");
+ CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib");
+ CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib");
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_DLL");
+ CmdArgs.push_back("--dependent-lib=msvcrtd");
+ if (LinkFortranMain)
+ CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib");
+ CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");
+ CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");
+ break;
+ }
+}
+
+void Flang::AddAMDGPUTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) {
+ StringRef Val = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val));
+ }
+}
+
+void Flang::addTargetOptions(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const ToolChain &TC = getToolChain();
+ const llvm::Triple &Triple = TC.getEffectiveTriple();
+ const Driver &D = TC.getDriver();
+
+ std::string CPU = getCPUName(D, Args, Triple);
+ if (!CPU.empty()) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPU));
+ }
+
+ // Add the target features.
+ switch (TC.getArch()) {
+ default:
+ break;
+ case llvm::Triple::aarch64:
+ getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
+ AddAArch64TargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
+ getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
+ AddAMDGPUTargetArgs(Args, CmdArgs);
+ break;
+ case llvm::Triple::riscv64:
+ getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
+ AddRISCVTargetArgs(Args, CmdArgs);
+ break;
+ case llvm::Triple::x86_64:
+ getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
+ break;
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
+ StringRef Name = A->getValue();
+ if (Name == "SVML") {
+ if (Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ } else if (Name == "LIBMVEC-X86") {
+ if (Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ } else if (Name == "SLEEF" || Name == "ArmPL") {
+ if (Triple.getArch() != llvm::Triple::aarch64 &&
+ Triple.getArch() != llvm::Triple::aarch64_be)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ }
+
+ if (Triple.isOSDarwin()) {
+ // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these
+ // here incase they are added someday
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (A->getValue() == StringRef{"Accelerate"}) {
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("Accelerate");
+ }
+ }
+ }
+ A->render(Args, CmdArgs);
+ }
+
+ if (Triple.isKnownWindowsMSVCEnvironment()) {
+ processVSRuntimeLibrary(TC, Args, CmdArgs);
+ addVSDefines(TC, Args, CmdArgs);
+ }
+
+ // TODO: Add target specific flags, ABI, mtune option etc.
+}
+
+void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
+ const JobAction &JA, const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
+ bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) ||
+ JA.isHostOffloading(C.getActiveOffloadKinds());
+
+ // Skips the primary input file, which is the input file that the compilation
+ // proccess will be executed upon (e.g. the host bitcode file) and
+ // adds other secondary input (e.g. device bitcode files for embedding to the
+ // -fembed-offload-object argument or the host IR file for proccessing
+ // during device compilation to the fopenmp-host-ir-file-path argument via
+ // OpenMPDeviceInput). This is condensed logic from the ConstructJob
+ // function inside of the Clang driver for pushing on further input arguments
+ // needed for offloading during various phases of compilation.
+ for (size_t i = 1; i < Inputs.size(); ++i) {
+ if (Inputs[i].getType() == types::TY_Nothing) {
+ // contains nothing, so it's skippable
+ } else if (IsHostOffloadingAction) {
+ CmdArgs.push_back(
+ Args.MakeArgString("-fembed-offload-object=" +
+ getToolChain().getInputFilename(Inputs[i])));
+ } else if (IsOpenMPDevice) {
+ if (Inputs[i].getFilename()) {
+ CmdArgs.push_back("-fopenmp-host-ir-file-path");
+ CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename()));
+ } else {
+ llvm_unreachable("missing openmp host-ir file for device offloading");
+ }
+ } else {
+ llvm_unreachable(
+ "unexpectedly given multiple inputs or given unknown input");
+ }
+ }
+
+ if (IsOpenMPDevice) {
+ // -fopenmp-is-target-device is passed along to tell the frontend that it is
+ // generating code for a device, so that only the relevant code is emitted.
+ CmdArgs.push_back("-fopenmp-is-target-device");
+
+ // When in OpenMP offloading mode, enable debugging on the device.
+ Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);
+ if (Args.hasFlag(options::OPT_fopenmp_target_debug,
+ options::OPT_fno_openmp_target_debug, /*Default=*/false))
+ CmdArgs.push_back("-fopenmp-target-debug");
+
+ // When in OpenMP offloading mode, forward assumptions information about
+ // thread and team counts in the device.
+ if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
+ options::OPT_fno_openmp_assume_teams_oversubscription,
+ /*Default=*/false))
+ CmdArgs.push_back("-fopenmp-assume-teams-oversubscription");
+ if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription,
+ options::OPT_fno_openmp_assume_threads_oversubscription,
+ /*Default=*/false))
+ CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
+ if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state))
+ CmdArgs.push_back("-fopenmp-assume-no-thread-state");
+ if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))
+ CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");
+ if (Args.hasArg(options::OPT_nogpulib))
+ CmdArgs.push_back("-nogpulib");
+ }
+}
+
+static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ StringRef FPContract;
+ bool HonorINFs = true;
+ bool HonorNaNs = true;
+ bool ApproxFunc = false;
+ bool SignedZeros = true;
+ bool AssociativeMath = false;
+ bool ReciprocalMath = false;
+
+ if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {
+ const StringRef Val = A->getValue();
+ if (Val == "fast" || Val == "off") {
+ FPContract = Val;
+ } else if (Val == "on") {
+ // Warn instead of error because users might have makefiles written for
+ // gfortran (which accepts -ffp-contract=on)
+ D.Diag(diag::warn_drv_unsupported_option_for_flang)
+ << Val << A->getOption().getName() << "off";
+ FPContract = "off";
+ } else
+ // Clang's "fast-honor-pragmas" option is not supported because it is
+ // non-standard
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
+
+ for (const Arg *A : Args) {
+ auto optId = A->getOption().getID();
+ switch (optId) {
+ // if this isn't an FP option, skip the claim below
+ default:
+ continue;
+
+ case options::OPT_fhonor_infinities:
+ HonorINFs = true;
+ break;
+ case options::OPT_fno_honor_infinities:
+ HonorINFs = false;
+ break;
+ case options::OPT_fhonor_nans:
+ HonorNaNs = true;
+ break;
+ case options::OPT_fno_honor_nans:
+ HonorNaNs = false;
+ break;
+ case options::OPT_fapprox_func:
+ ApproxFunc = true;
+ break;
+ case options::OPT_fno_approx_func:
+ ApproxFunc = false;
+ break;
+ case options::OPT_fsigned_zeros:
+ SignedZeros = true;
+ break;
+ case options::OPT_fno_signed_zeros:
+ SignedZeros = false;
+ break;
+ case options::OPT_fassociative_math:
+ AssociativeMath = true;
+ break;
+ case options::OPT_fno_associative_math:
+ AssociativeMath = false;
+ break;
+ case options::OPT_freciprocal_math:
+ ReciprocalMath = true;
+ break;
+ case options::OPT_fno_reciprocal_math:
+ ReciprocalMath = false;
+ break;
+ case options::OPT_Ofast:
+ [[fallthrough]];
+ case options::OPT_ffast_math:
+ HonorINFs = false;
+ HonorNaNs = false;
+ AssociativeMath = true;
+ ReciprocalMath = true;
+ ApproxFunc = true;
+ SignedZeros = false;
+ FPContract = "fast";
+ break;
+ case options::OPT_fno_fast_math:
+ HonorINFs = true;
+ HonorNaNs = true;
+ AssociativeMath = false;
+ ReciprocalMath = false;
+ ApproxFunc = false;
+ SignedZeros = true;
+ // -fno-fast-math should undo -ffast-math so I return FPContract to the
+ // default. It is important to check it is "fast" (the default) so that
+ // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
+ if (FPContract == "fast")
+ FPContract = "";
+ break;
+ }
+
+ // If we handled this option claim it
+ A->claim();
+ }
+
+ if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
+ ApproxFunc && !SignedZeros &&
+ (FPContract == "fast" || FPContract == "")) {
+ CmdArgs.push_back("-ffast-math");
+ return;
+ }
+
+ if (!FPContract.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));
+
+ if (!HonorINFs)
+ CmdArgs.push_back("-menable-no-infs");
+
+ if (!HonorNaNs)
+ CmdArgs.push_back("-menable-no-nans");
+
+ if (ApproxFunc)
+ CmdArgs.push_back("-fapprox-func");
+
+ if (!SignedZeros)
+ CmdArgs.push_back("-fno-signed-zeros");
+
+ if (AssociativeMath && !SignedZeros)
+ CmdArgs.push_back("-mreassociate");
+
+ if (ReciprocalMath)
+ CmdArgs.push_back("-freciprocal-math");
+}
+
+static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
+ const InputInfo &Input) {
+ 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 {
+ 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());
+ }
+
+ 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());
+ }
}
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();
- // TODO: Once code-generation is available, this will need to be commented
- // out.
- // const llvm::Triple &Triple = TC.getEffectiveTriple();
- // const std::string &TripleStr = Triple.getTriple();
+ const llvm::Triple &Triple = TC.getEffectiveTriple();
+ const std::string &TripleStr = Triple.getTriple();
+ const Driver &D = TC.getDriver();
ArgStringList CmdArgs;
+ DiagnosticsEngine &Diags = D.getDiags();
// Invoke ourselves in -fc1 mode.
CmdArgs.push_back("-fc1");
- // TODO: Once code-generation is available, this will need to be commented
- // out.
// Add the "effective" target triple.
- // CmdArgs.push_back("-triple");
- // CmdArgs.push_back(Args.MakeArgString(TripleStr));
+ CmdArgs.push_back("-triple");
+ CmdArgs.push_back(Args.MakeArgString(TripleStr));
if (isa<PreprocessJobAction>(JA)) {
CmdArgs.push_back("-E");
@@ -100,27 +703,122 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor (i.e. skip when dealing with e.g. binary files).
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(Args, CmdArgs);
+ addPreprocessingOptions(Args, CmdArgs);
- AddFortranDialectOptions(Args, CmdArgs);
+ addFortranDialectOptions(Args, CmdArgs);
+
+ // Color diagnostics are parsed by the driver directly from argv and later
+ // re-parsed to construct this job; claim any possible color diagnostic here
+ // to avoid warn_drv_unused_argument.
+ Args.getLastArg(options::OPT_fcolor_diagnostics,
+ options::OPT_fno_color_diagnostics);
+ if (Diags.getDiagnosticOptions().ShowColors)
+ CmdArgs.push_back("-fcolor-diagnostics");
+
+ // LTO mode is parsed by the Clang driver library.
+ LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false);
+ assert(LTOMode != LTOK_Unknown && "Unknown LTO mode.");
+ if (LTOMode == LTOK_Full)
+ CmdArgs.push_back("-flto=full");
+ else if (LTOMode == LTOK_Thin) {
+ Diags.Report(
+ Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+ "the option '-flto=thin' is a work in progress"));
+ CmdArgs.push_back("-flto=thin");
+ }
+
+ // -fPIC and related options.
+ addPicOptions(Args, CmdArgs);
+
+ // Floating point related options
+ addFloatingPointOptions(D, Args, CmdArgs);
+
+ // Add target args, features, etc.
+ addTargetOptions(Args, CmdArgs);
+
+ // Add Codegen options
+ addCodegenOptions(Args, CmdArgs);
+
+ // Add R Group options
+ Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
+
+ // Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
+ if (willEmitRemarks(Args))
+ renderRemarksOptions(Args, CmdArgs, Input);
// Add other compile options
- AddOtherOptions(Args, CmdArgs);
+ addOtherOptions(Args, CmdArgs);
+
+ // Offloading related options
+ addOffloadOptions(C, Inputs, JA, Args, CmdArgs);
// Forward -Xflang arguments to -fc1
Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);
+ CodeGenOptions::FramePointerKind FPKeepKind =
+ getFramePointerKind(Args, Triple);
+
+ const char *FPKeepKindStr = nullptr;
+ switch (FPKeepKind) {
+ case CodeGenOptions::FramePointerKind::None:
+ FPKeepKindStr = "-mframe-pointer=none";
+ break;
+ case CodeGenOptions::FramePointerKind::NonLeaf:
+ FPKeepKindStr = "-mframe-pointer=non-leaf";
+ break;
+ case CodeGenOptions::FramePointerKind::All:
+ FPKeepKindStr = "-mframe-pointer=all";
+ break;
+ }
+ assert(FPKeepKindStr && "unknown FramePointerKind");
+ CmdArgs.push_back(FPKeepKindStr);
+
+ // Forward -mllvm options to the LLVM option parser. In practice, this means
+ // forwarding to `-fc1` as that's where the LLVM parser is run.
+ for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+
+ for (const Arg *A : Args.filtered(options::OPT_mmlir)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+
+ // Remove any unsupported gfortran diagnostic options
+ for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) {
+ A->claim();
+ D.Diag(diag::warn_drv_unsupported_diag_option_for_flang)
+ << A->getOption().getName();
+ }
+
+ // Optimization level for CodeGen.
+ if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (A->getOption().matches(options::OPT_O4)) {
+ CmdArgs.push_back("-O3");
+ D.Diag(diag::warn_O4_is_O3);
+ } else if (A->getOption().matches(options::OPT_Ofast)) {
+ CmdArgs.push_back("-O3");
+ } else {
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
assert(Input.isFilename() && "Invalid input.");
+
+ if (Args.getLastArg(options::OPT_save_temps_EQ))
+ Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
+
+ addDashXForInput(Args, Input, CmdArgs);
+
CmdArgs.push_back(Input.getFilename());
- const auto& D = C.getDriver();
// TODO: Replace flang-new with flang once the new driver replaces the
// throwaway driver
const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC));
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h
index efbdbe854e24..ec2e545a1d0b 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h
@@ -29,7 +29,7 @@ private:
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
- void AddFortranDialectOptions(const llvm::opt::ArgList &Args,
+ void addFortranDialectOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
/// Extract preprocessing options from the driver arguments and add them to
@@ -37,14 +37,71 @@ private:
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
- void AddPreprocessingOptions(const llvm::opt::ArgList &Args,
+ void addPreprocessingOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Extract PIC options from the driver arguments and add them to
+ /// the command arguments.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void addPicOptions(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Extract target options from the driver arguments and add them to
+ /// the command arguments.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void addTargetOptions(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Add specific options for AArch64 target.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void AddAArch64TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Add specific options for AMDGPU target.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void AddAMDGPUTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Add specific options for RISC-V target.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void AddRISCVTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Extract offload options from the driver arguments and add them to
+ /// the command arguments.
+ /// \param [in] C The current compilation for the driver invocation
+ /// \param [in] Inputs The input infomration on the current file inputs
+ /// \param [in] JA The job action
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
+ const JobAction &JA, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Extract options for code generation from the driver arguments and add them
+ /// to the command arguments.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void addCodegenOptions(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
/// Extract other compilation options from the driver arguments and add them
/// to the command arguments.
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
- void AddOtherOptions(const llvm::opt::ArgList &Args,
+ void addOtherOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
public:
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp
index 05c58a8f43a8..b7c9e0e51cdb 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -11,6 +11,7 @@
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
@@ -29,13 +30,16 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
+ const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());
const auto &D = getToolChain().getDriver();
+ const llvm::Triple &Triple = ToolChain.getTriple();
+ ArgStringList CmdArgs;
+
+ claimNoWarnArgs(Args);
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- switch (getToolChain().getArch()) {
+ switch (ToolChain.getArch()) {
default:
break;
case llvm::Triple::x86:
@@ -51,7 +55,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
- mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
@@ -59,7 +63,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mabi");
CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
- if (getToolChain().getTriple().isLittleEndian())
+ if (Triple.isLittleEndian())
CmdArgs.push_back("-EL");
else
CmdArgs.push_back("-EB");
@@ -70,39 +74,27 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
}
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ AddAssemblerKPIC(ToolChain, Args, CmdArgs);
break;
}
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb: {
- arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
+ arm::FloatABI ABI = arm::getARMFloatABI(ToolChain, Args);
if (ABI == arm::FloatABI::Hard)
CmdArgs.push_back("-mfpu=vfp");
else
CmdArgs.push_back("-mfpu=softvfp");
- switch (getToolChain().getTriple().getEnvironment()) {
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::GNUEABI:
- case llvm::Triple::EABI:
- CmdArgs.push_back("-meabi=5");
- break;
-
- default:
- CmdArgs.push_back("-matpcs");
- }
+ CmdArgs.push_back("-meabi=5");
break;
}
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
case llvm::Triple::sparcv9: {
- std::string CPU = getCPUName(D, Args, getToolChain().getTriple());
- CmdArgs.push_back(
- sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ std::string CPU = getCPUName(D, Args, Triple);
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));
+ AddAssemblerKPIC(ToolChain, Args, CmdArgs);
break;
}
}
@@ -128,7 +120,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as"));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
@@ -139,8 +131,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::FreeBSD &ToolChain =
- static_cast<const toolchains::FreeBSD &>(getToolChain());
+ const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool IsPIE =
@@ -169,16 +160,14 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
- } else {
+ CmdArgs.push_back("-shared");
+ } else if (!Args.hasArg(options::OPT_r)) {
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
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");
- }
+ if (Arch == llvm::Triple::arm || T.isX86())
+ CmdArgs.push_back("--hash-style=both");
CmdArgs.push_back("--enable-new-dtags");
}
@@ -220,13 +209,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("elf64ltsmip_fbsd");
break;
- case llvm::Triple::riscv32:
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf32lriscv");
- break;
case llvm::Triple::riscv64:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf64lriscv");
+ CmdArgs.push_back("-X");
break;
default:
break;
@@ -240,11 +226,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
@@ -276,16 +261,20 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
+ Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_r});
if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
- addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
D.getLTOMode() == LTOK_Thin);
}
@@ -311,10 +300,27 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-lm");
}
+
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below (i.e.
+ // AddRunTimeLibs).
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
+ if (Profiling)
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
+ }
+
if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+ linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
if (NeedsXRayDeps)
- linkXRayRuntimeDeps(ToolChain, CmdArgs);
+ linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
// the default system libraries. Just mimic this for now.
if (Profiling)
@@ -362,10 +368,12 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
+ const char *crtend = nullptr;
if (Args.hasArg(options::OPT_shared) || IsPIE)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+ crtend = "crtendS.o";
else
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ crtend = "crtend.o";
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
@@ -385,65 +393,71 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,
// When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall
// back to '/usr/lib' if it doesn't exist.
- if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() ||
- Triple.isPPC32()) &&
- D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o"))
- getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32");
+ if (Triple.isArch32Bit() &&
+ D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o")))
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32"));
else
- getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
}
-ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const {
- unsigned Major = getTriple().getOSMajorVersion();
- if (Major >= 10 || Major == 0)
- return ToolChain::CST_Libcxx;
- return ToolChain::CST_Libstdcxx;
-}
+void FreeBSD::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
-unsigned FreeBSD::GetDefaultDwarfVersion() const {
- if (getTriple().getOSMajorVersion() < 12)
- return 2;
- return 4;
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ concat(D.SysRoot, "/usr/include"));
}
void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/include/c++/v1");
-}
-
-void FreeBSD::addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/c++/4.2", "", "",
- DriverArgs, CC1Args);
+ concat(getDriver().SysRoot, "/usr/include/c++/v1"));
}
void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- CXXStdlibType Type = GetCXXStdlibType(Args);
unsigned Major = getTriple().getOSMajorVersion();
bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14;
- switch (Type) {
- case ToolChain::CST_Libcxx:
- CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
- break;
-
- case ToolChain::CST_Libstdcxx:
- CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++");
- break;
- }
+ CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
}
void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+ CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
}
void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+ RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
Tool *FreeBSD::buildAssembler() const {
@@ -452,24 +466,12 @@ Tool *FreeBSD::buildAssembler() const {
Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }
-llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const {
- // FreeBSD uses SjLj exceptions on ARM oabi.
- switch (getTriple().getEnvironment()) {
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::GNUEABI:
- case llvm::Triple::EABI:
- return llvm::ExceptionHandling::None;
- default:
- if (getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::thumb)
- return llvm::ExceptionHandling::SjLj;
- return llvm::ExceptionHandling::None;
- }
-}
-
bool FreeBSD::HasNativeLLVMSupport() const { return true; }
-bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; }
+ToolChain::UnwindTableLevel
+FreeBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {
+ return UnwindTableLevel::Asynchronous;
+}
bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const {
return getSanitizerArgs(Args).requiresPIE();
@@ -485,12 +487,11 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Vptr;
- if (IsX86_64 || IsMIPS64) {
+ if (IsAArch64 || IsX86_64 || IsMIPS64) {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Thread;
}
- if (IsX86 || IsX86_64) {
- Res |= SanitizerKind::Function;
+ if (IsAArch64 || IsX86 || IsX86_64) {
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
@@ -498,18 +499,7 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
if (IsAArch64 || IsX86_64) {
Res |= SanitizerKind::KernelAddress;
Res |= SanitizerKind::KernelMemory;
- }
- if (IsX86_64) {
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/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h
index 2a721c750a64..7ab63905ed4f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h
@@ -17,9 +17,9 @@ namespace clang {
namespace driver {
namespace tools {
-/// freebsd -- Directly call GNU Binutils assembler and linker
+/// Directly call GNU Binutils assembler and linker
namespace freebsd {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC)
: Tool("freebsd::Assembler", "assembler", TC) {}
@@ -32,7 +32,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("freebsd::Linker", "linker", TC) {}
@@ -58,12 +58,19 @@ public:
bool IsMathErrnoDefault() const override { return false; }
bool IsObjCNonFragileABIDefault() const override { return true; }
- CXXStdlibType GetDefaultCXXStdlibType() const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
+
void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- void
- addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -71,19 +78,14 @@ public:
void AddHIPIncludeArgs(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;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
- unsigned GetDefaultDwarfVersion() const override;
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
// 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/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp
index bd1600d060c8..14b838500bec 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/MultilibBuilder.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
@@ -33,10 +34,11 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::Fuchsia &ToolChain =
- static_cast<const toolchains::Fuchsia &>(getToolChain());
+ const auto &ToolChain = static_cast<const Fuchsia &>(getToolChain());
const Driver &D = ToolChain.getDriver();
+ const llvm::Triple &Triple = ToolChain.getEffectiveTriple();
+
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@@ -53,6 +55,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-z");
CmdArgs.push_back("now");
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("start-stop-visibility=hidden");
+
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||
llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")) {
@@ -84,6 +89,14 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--hash-style=gnu");
}
+ if (ToolChain.getArch() == llvm::Triple::aarch64) {
+ CmdArgs.push_back("--execute-only");
+
+ std::string CPU = getCPUName(D, Args, Triple);
+ if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
+ CmdArgs.push_back("--fix-cortex-a53-843419");
+ }
+
CmdArgs.push_back("--eh-frame-hdr");
if (Args.hasArg(options::OPT_static))
@@ -93,7 +106,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);
- if (!Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) {
std::string Dyld = D.DyldPrefix;
if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt())
Dyld += "asan/";
@@ -106,6 +119,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Dyld));
}
+ if (ToolChain.getArch() == llvm::Triple::riscv64)
+ CmdArgs.push_back("-X");
+
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -116,21 +132,26 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
- addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
D.getLTOMode() == LTOK_Thin);
}
- bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
- bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
+ addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
- ToolChain.addProfileRTLibs(Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
options::OPT_r)) {
@@ -153,11 +174,14 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+ // Note that Fuchsia never needs to link in sanitizer runtime deps. Any
+ // sanitizer runtimes with system dependencies use the `.deplibs` feature
+ // instead.
+ addSanitizerRuntimes(ToolChain, Args, CmdArgs);
- if (NeedsXRayDeps)
- linkXRayRuntimeDeps(ToolChain, CmdArgs);
+ addXRayRuntime(ToolChain, Args, CmdArgs);
+
+ ToolChain.addProfileRTLibs(Args, CmdArgs);
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
@@ -172,7 +196,53 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lc");
}
- C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::AtFileCurCP(),
+ Exec, CmdArgs, Inputs, Output));
+}
+
+void fuchsia::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // ar tool command "llvm-ar <options> <output_file> <input_files>".
+ ArgStringList CmdArgs;
+ // Create and insert file members with a deterministic index.
+ CmdArgs.push_back("rcsD");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs) {
+ if (II.isFilename()) {
+ CmdArgs.push_back(II.getFilename());
+ }
+ }
+
+ // Delete old output archive file if it already exists before generating a new
+ // archive file.
+ const char *OutputFileName = Output.getFilename();
+ if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
+ if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
+ D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
+ return;
+ }
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
}
@@ -188,68 +258,50 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
if (!D.SysRoot.empty()) {
SmallString<128> P(D.SysRoot);
llvm::sys::path::append(P, "lib");
- getFilePaths().push_back(std::string(P.str()));
+ getFilePaths().push_back(std::string(P));
}
auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> {
std::vector<std::string> FP;
- for (const std::string &Path : getStdlibPaths()) {
- SmallString<128> P(Path);
+ if (std::optional<std::string> Path = getStdlibPath()) {
+ SmallString<128> P(*Path);
llvm::sys::path::append(P, M.gccSuffix());
- FP.push_back(std::string(P.str()));
+ FP.push_back(std::string(P));
}
return FP;
};
Multilibs.push_back(Multilib());
// Use the noexcept variant with -fno-exceptions to avoid the extra overhead.
- Multilibs.push_back(Multilib("noexcept", {}, {}, 1)
- .flag("-fexceptions")
- .flag("+fno-exceptions"));
+ Multilibs.push_back(MultilibBuilder("noexcept", {}, {})
+ .flag("-fexceptions", /*Disallow=*/true)
+ .flag("-fno-exceptions")
+ .makeMultilib());
// ASan has higher priority because we always want the instrumentated version.
- Multilibs.push_back(Multilib("asan", {}, {}, 2)
- .flag("+fsanitize=address"));
+ Multilibs.push_back(MultilibBuilder("asan", {}, {})
+ .flag("-fsanitize=address")
+ .makeMultilib());
// Use the asan+noexcept variant with ASan and -fno-exceptions.
- Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3)
- .flag("+fsanitize=address")
- .flag("-fexceptions")
- .flag("+fno-exceptions"));
+ Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {})
+ .flag("-fsanitize=address")
+ .flag("-fexceptions", /*Disallow=*/true)
+ .flag("-fno-exceptions")
+ .makeMultilib());
// HWASan has higher priority because we always want the instrumentated
// version.
- Multilibs.push_back(
- Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress"));
+ Multilibs.push_back(MultilibBuilder("hwasan", {}, {})
+ .flag("-fsanitize=hwaddress")
+ .makeMultilib());
// Use the hwasan+noexcept variant with HWASan and -fno-exceptions.
- Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5)
- .flag("+fsanitize=hwaddress")
- .flag("-fexceptions")
- .flag("+fno-exceptions"));
- // Use the relative vtables ABI.
- // TODO: Remove these multilibs once relative vtables are enabled by default
- // for Fuchsia.
- Multilibs.push_back(Multilib("relative-vtables", {}, {}, 6)
- .flag("+fexperimental-relative-c++-abi-vtables"));
- Multilibs.push_back(Multilib("relative-vtables+noexcept", {}, {}, 7)
- .flag("+fexperimental-relative-c++-abi-vtables")
- .flag("-fexceptions")
- .flag("+fno-exceptions"));
- Multilibs.push_back(Multilib("relative-vtables+asan", {}, {}, 8)
- .flag("+fexperimental-relative-c++-abi-vtables")
- .flag("+fsanitize=address"));
- Multilibs.push_back(Multilib("relative-vtables+asan+noexcept", {}, {}, 9)
- .flag("+fexperimental-relative-c++-abi-vtables")
- .flag("+fsanitize=address")
- .flag("-fexceptions")
- .flag("+fno-exceptions"));
- Multilibs.push_back(Multilib("relative-vtables+hwasan", {}, {}, 10)
- .flag("+fexperimental-relative-c++-abi-vtables")
- .flag("+fsanitize=hwaddress"));
- Multilibs.push_back(Multilib("relative-vtables+hwasan+noexcept", {}, {}, 11)
- .flag("+fexperimental-relative-c++-abi-vtables")
- .flag("+fsanitize=hwaddress")
- .flag("-fexceptions")
- .flag("+fno-exceptions"));
+ Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {})
+ .flag("-fsanitize=hwaddress")
+ .flag("-fexceptions", /*Disallow=*/true)
+ .flag("-fno-exceptions")
+ .makeMultilib());
// Use Itanium C++ ABI for the compat multilib.
- Multilibs.push_back(Multilib("compat", {}, {}, 12).flag("+fc++-abi=itanium"));
+ Multilibs.push_back(MultilibBuilder("compat", {}, {})
+ .flag("-fc++-abi=itanium")
+ .makeMultilib());
Multilibs.FilterOut([&](const Multilib &M) {
std::vector<std::string> RD = FilePaths(M);
@@ -257,30 +309,31 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
});
Multilib::flags_list Flags;
- addMultilibFlag(
- Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true),
- "fexceptions", Flags);
- addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address",
- Flags);
- addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress",
+ bool Exceptions =
+ Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true);
+ addMultilibFlag(Exceptions, "-fexceptions", Flags);
+ addMultilibFlag(!Exceptions, "-fno-exceptions", Flags);
+ addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "-fsanitize=address",
Flags);
+ addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(),
+ "-fsanitize=hwaddress", Flags);
- addMultilibFlag(
- Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables,
- options::OPT_fno_experimental_relative_cxx_abi_vtables,
- /*default=*/false),
- "fexperimental-relative-c++-abi-vtables", Flags);
addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium",
- "fc++-abi=itanium", Flags);
+ "-fc++-abi=itanium", Flags);
Multilibs.setFilePathsCallback(FilePaths);
- if (Multilibs.select(Flags, SelectedMultilib))
- if (!SelectedMultilib.isDefault())
+ if (Multilibs.select(Flags, SelectedMultilibs)) {
+ // Ensure that -print-multi-directory only outputs one multilib directory.
+ Multilib LastSelected = SelectedMultilibs.back();
+ SelectedMultilibs = {LastSelected};
+
+ if (!SelectedMultilibs.back().isDefault())
if (const auto &PathsCallback = Multilibs.filePathsCallback())
- for (const auto &Path : PathsCallback(SelectedMultilib))
+ for (const auto &Path : PathsCallback(SelectedMultilibs.back()))
// Prepend the multilib path to ensure it takes the precedence.
getFilePaths().insert(getFilePaths().begin(), Path);
+ }
}
std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,
@@ -293,6 +346,10 @@ Tool *Fuchsia::buildLinker() const {
return new tools::fuchsia::Linker(*this);
}
+Tool *Fuchsia::buildStaticLibTool() const {
+ return new tools::fuchsia::StaticLibTool(*this);
+}
+
ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType(
const ArgList &Args) const {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
@@ -363,8 +420,8 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
const Driver &D = getDriver();
@@ -405,6 +462,8 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
break;
case ToolChain::CST_Libstdcxx:
@@ -431,13 +490,13 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const {
SanitizerMask Res;
switch (getTriple().getArch()) {
case llvm::Triple::aarch64:
+ case llvm::Triple::riscv64:
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/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h
index c0e69df22821..619968f58502 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h
@@ -18,7 +18,21 @@ namespace clang {
namespace driver {
namespace tools {
namespace fuchsia {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool {
+public:
+ StaticLibTool(const ToolChain &TC)
+ : Tool("fuchsia::StaticLibTool", "llvm-ar", 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;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("fuchsia::Linker", "ld.lld", TC) {}
@@ -41,17 +55,16 @@ public:
const llvm::opt::ArgList &Args);
bool HasNativeLLVMSupport() const override { return true; }
- bool IsIntegratedAssemblerDefault() const override { return true; }
bool IsMathErrnoDefault() const override { return false; }
- bool useRelaxRelocations() const override { return true; };
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;
}
CXXStdlibType GetDefaultCXXStdlibType() const override {
return ToolChain::CST_Libcxx;
}
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
- return true;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
+ return UnwindTableLevel::Asynchronous;
}
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
@@ -75,27 +88,31 @@ public:
RuntimeLibType
GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
- CXXStdlibType
- GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadKind) const override;
+ bool IsAArch64OutlineAtomicsDefault(
+ const llvm::opt::ArgList &Args) const override {
+ return true;
+ }
+
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- void
- AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
- const char *getDefaultLinker() const override {
- return "ld.lld";
- }
+ const char *getDefaultLinker() const override { return "ld.lld"; }
protected:
Tool *buildLinker() const override;
+ Tool *buildStaticLibTool() const override;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp
index 7a9570a686f4..e5e1b1d77269 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -8,6 +8,8 @@
#include "Gnu.h"
#include "Arch/ARM.h"
+#include "Arch/CSKY.h"
+#include "Arch/LoongArch.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
#include "Arch/RISCV.h"
@@ -19,14 +21,18 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/MultilibBuilder.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/TargetParser.h"
#include <system_error>
using namespace clang::driver;
@@ -82,7 +88,7 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
RenderExtraToolArgs(JA, CmdArgs);
- // If using a driver driver, force the arch.
+ // If using a driver, force the arch.
if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
CmdArgs.push_back(
@@ -112,11 +118,11 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
- assert(Output.isNothing() && "Unexpected output");
CmdArgs.push_back("-fsyntax-only");
}
@@ -215,30 +221,6 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA,
// The types are (hopefully) good enough.
}
-// On Arm the endianness of the output file is determined by the target and
-// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and
-// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a
-// normalized triple so we must handle the flag here.
-static bool isArmBigEndian(const llvm::Triple &Triple,
- const ArgList &Args) {
- bool IsBigEndian = false;
- switch (Triple.getArch()) {
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- IsBigEndian = true;
- LLVM_FALLTHROUGH;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
- options::OPT_mbig_endian))
- IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
- break;
- default:
- break;
- }
- return IsBigEndian;
-}
-
static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
switch (T.getArch()) {
case llvm::Triple::x86:
@@ -253,7 +235,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
case llvm::Triple::thumb:
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
- return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi";
+ return tools::arm::isARMBigEndian(T, Args) ? "armelfb_linux_eabi"
+ : "armelf_linux_eabi";
case llvm::Triple::m68k:
return "m68kelf";
case llvm::Triple::ppc:
@@ -277,6 +260,10 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
return "elf32_sparc";
case llvm::Triple::sparcv9:
return "elf64_sparc";
+ case llvm::Triple::loongarch32:
+ return "elf32loongarch";
+ case llvm::Triple::loongarch64:
+ return "elf64loongarch";
case llvm::Triple::mips:
return "elf32btsmip";
case llvm::Triple::mipsel:
@@ -299,32 +286,20 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
return "elf_x86_64";
case llvm::Triple::ve:
return "elf64ve";
+ case llvm::Triple::csky:
+ return "cskyelf_linux";
default:
return nullptr;
}
}
-static bool getPIE(const ArgList &Args, const ToolChain &TC) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie))
- return false;
-
- Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
- options::OPT_nopie);
- if (!A)
- return TC.isPIEDefault(Args);
- return A->getOption().matches(options::OPT_pie);
-}
-
static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) {
bool HasStaticPIE = Args.hasArg(options::OPT_static_pie);
- // -no-pie is an alias for -nopie. So, handling -nopie takes care of
- // -no-pie as well.
- if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) {
+ if (HasStaticPIE && Args.hasArg(options::OPT_no_pie)) {
const Driver &D = TC.getDriver();
const llvm::opt::OptTable &Opts = D.getOpts();
- const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie);
- const char *NoPIEName = Opts.getOptionName(options::OPT_nopie);
+ StringRef StaticPIEName = Opts.getOptionName(options::OPT_static_pie);
+ StringRef NoPIEName = Opts.getOptionName(options::OPT_nopie);
D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName;
}
return HasStaticPIE;
@@ -388,17 +363,16 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Generic_ELF, so the static_cast might return a reference to a invalid
// instance (see PR45061). Ideally, the Linker constructor needs to take a
// Generic_ELF instead.
- const toolchains::Generic_ELF &ToolChain =
- static_cast<const toolchains::Generic_ELF &>(getToolChain());
+ const auto &ToolChain = static_cast<const Generic_ELF &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool isOHOSFamily = ToolChain.getTriple().isOHOSFamily();
const bool isAndroid = ToolChain.getTriple().isAndroid();
const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU();
const bool IsVE = ToolChain.getTriple().isVE();
- const bool IsPIE = getPIE(Args, ToolChain);
const bool IsStaticPIE = getStaticPIE(Args, ToolChain);
const bool IsStatic = getStatic(Args);
const bool HasCRTBeginEndFiles =
@@ -418,44 +392,26 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
- if (IsPIE)
- CmdArgs.push_back("-pie");
-
- if (IsStaticPIE) {
- CmdArgs.push_back("-static");
- CmdArgs.push_back("-pie");
- CmdArgs.push_back("--no-dynamic-linker");
- CmdArgs.push_back("-z");
- CmdArgs.push_back("text");
- }
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
-
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("-s");
- if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) {
- bool IsBigEndian = isArmBigEndian(Triple, Args);
+ if (Triple.isARM() || Triple.isThumb()) {
+ bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
if (IsBigEndian)
arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
- IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be;
CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
+ } else if (Triple.isAArch64()) {
+ CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
}
// Most Android ARM64 targets should enable the linker fix for erratum
// 843419. Only non-Cortex-A53 devices are allowed to skip this flag.
- if (Arch == llvm::Triple::aarch64 && isAndroid) {
+ if (Arch == llvm::Triple::aarch64 && (isAndroid || isOHOSFamily)) {
std::string CPU = getCPUName(D, Args, Triple);
if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
CmdArgs.push_back("--fix-cortex-a53-843419");
}
- // Android does not allow shared text relocations. Emit a warning if the
- // user's code contains any.
- if (isAndroid)
- CmdArgs.push_back("--warn-shared-textrel");
-
ToolChain.addExtraOpts(CmdArgs);
CmdArgs.push_back("--eh-frame-hdr");
@@ -467,17 +423,29 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::err_target_unknown_triple) << Triple.str();
return;
}
+ if (Triple.isRISCV())
+ CmdArgs.push_back("-X");
- if (Args.hasArg(options::OPT_shared))
+ const bool IsShared = Args.hasArg(options::OPT_shared);
+ if (IsShared)
CmdArgs.push_back("-shared");
-
- if (IsStatic) {
+ bool IsPIE = false;
+ if (IsStaticPIE) {
CmdArgs.push_back("-static");
- } else {
+ CmdArgs.push_back("-pie");
+ CmdArgs.push_back("--no-dynamic-linker");
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("text");
+ } else if (IsStatic) {
+ CmdArgs.push_back("-static");
+ } else if (!Args.hasArg(options::OPT_r)) {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
-
- if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) {
+ if (!IsShared) {
+ IsPIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
+ ToolChain.isPIEDefault(Args));
+ if (IsPIE)
+ CmdArgs.push_back("-pie");
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) +
ToolChain.getDynamicLinker(Args)));
@@ -540,16 +508,28 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Add crtfastmath.o if available and fast math is enabled.
ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
+
+ if (isAndroid && Args.hasFlag(options::OPT_fandroid_pad_segment,
+ options::OPT_fno_android_pad_segment, false))
+ CmdArgs.push_back(
+ Args.MakeArgString(ToolChain.GetFilePath("crt_pad_segment.o")));
}
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
- addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
D.getLTOMode() == LTOK_Thin);
}
@@ -560,6 +540,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs);
+
// The profile runtime also needs access to system libraries.
getToolChain().addProfileRTLibs(Args, CmdArgs);
@@ -577,19 +560,30 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back("-lm");
}
+
// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below (i.e.
+ // AddRunTimeLibs).
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
if (IsStatic || IsStaticPIE)
CmdArgs.push_back("--start-group");
if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+ linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
if (NeedsXRayDeps)
- linkXRayRuntimeDeps(ToolChain, CmdArgs);
+ linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
Args.hasArg(options::OPT_pthreads);
@@ -609,7 +603,19 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
- if (WantPthread && !isAndroid)
+ // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so
+ // forcibly link with libatomic as a workaround.
+ // TODO: Issue #41880 and D118021.
+ if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) {
+ CmdArgs.push_back("--push-state");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-latomic");
+ CmdArgs.push_back("--pop-state");
+ }
+
+ // We don't need libpthread neither for bionic (Android) nor for musl,
+ // (used by OHOS as runtime library).
+ if (WantPthread && !isAndroid && !isOHOSFamily)
CmdArgs.push_back("-lpthread");
if (Args.hasArg(options::OPT_fsplit_stack))
@@ -686,6 +692,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
unsigned PICLevel;
bool IsPIE;
const char *DefaultAssembler = "as";
+ // Enforce GNU as on Solaris; the native assembler's input syntax isn't fully
+ // compatible.
+ if (getToolChain().getTriple().isOSSolaris())
+ DefaultAssembler = "gas";
std::tie(RelocationModel, PICLevel, IsPIE) =
ParsePICArgs(getToolChain(), Args);
@@ -694,12 +704,12 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
CmdArgs.push_back("--compress-debug-sections");
} else {
StringRef Value = A->getValue();
- if (Value == "none" || Value == "zlib") {
+ if (Value == "none" || Value == "zlib" || Value == "zstd") {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
@@ -758,6 +768,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple());
CmdArgs.push_back("-march");
CmdArgs.push_back(MArchName.data());
+ if (!Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
+ Args.addOptOutFlag(CmdArgs, options::OPT_mrelax, options::OPT_mno_relax);
break;
}
case llvm::Triple::sparc:
@@ -782,7 +794,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
case llvm::Triple::thumb:
case llvm::Triple::thumbeb: {
const llvm::Triple &Triple2 = getToolChain().getTriple();
- CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL");
+ CmdArgs.push_back(arm::isARMBigEndian(Triple2, Args) ? "-EB" : "-EL");
switch (Triple2.getSubArch()) {
case llvm::Triple::ARMSubArch_v7:
CmdArgs.push_back("-mfpu=neon");
@@ -811,6 +823,11 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
normalizeCPUNamesForAssembler(Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
+ // The integrated assembler doesn't implement e_flags setting behavior for
+ // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For
+ // compatibility we accept but warn.
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
+ A->ignoreTargetSpecific();
break;
}
case llvm::Triple::aarch64:
@@ -822,6 +839,13 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
break;
}
+ // TODO: handle loongarch32.
+ case llvm::Triple::loongarch64: {
+ StringRef ABIName =
+ loongarch::getLoongArchABI(D, Args, getToolChain().getTriple());
+ CmdArgs.push_back(Args.MakeArgString("-mabi=" + ABIName));
+ break;
+ }
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -938,6 +962,17 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
+ if (Arg *A = Args.getLastArg(options::OPT_g_Flag, options::OPT_gN_Group,
+ options::OPT_gdwarf_2, options::OPT_gdwarf_3,
+ options::OPT_gdwarf_4, options::OPT_gdwarf_5,
+ options::OPT_gdwarf))
+ if (!A->getOption().matches(options::OPT_g0)) {
+ Args.AddLastArg(CmdArgs, options::OPT_g_Flag);
+
+ unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args);
+ CmdArgs.push_back(Args.MakeArgString("-gdwarf-" + Twine(DwarfVersion)));
+ }
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler));
C.addCommand(std::make_unique<Command>(JA, *this,
@@ -1001,46 +1036,47 @@ static bool isMSP430(llvm::Triple::ArchType Arch) {
return Arch == llvm::Triple::msp430;
}
-static Multilib makeMultilib(StringRef commonSuffix) {
- return Multilib(commonSuffix, commonSuffix, commonSuffix);
-}
-
static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
FilterNonExistent &NonExistent,
DetectedMultilibs &Result) {
// Check for Code Sourcery toolchain multilibs
MultilibSet CSMipsMultilibs;
{
- auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16");
+ auto MArchMips16 = MultilibBuilder("/mips16").flag("-m32").flag("-mips16");
auto MArchMicroMips =
- makeMultilib("/micromips").flag("+m32").flag("+mmicromips");
+ MultilibBuilder("/micromips").flag("-m32").flag("-mmicromips");
- auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips");
+ auto MArchDefault = MultilibBuilder("")
+ .flag("-mips16", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true);
- auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
+ auto UCLibc = MultilibBuilder("/uclibc").flag("-muclibc");
- auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float");
+ auto SoftFloat = MultilibBuilder("/soft-float").flag("-msoft-float");
- auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
+ auto Nan2008 = MultilibBuilder("/nan2008").flag("-mnan=2008");
- auto DefaultFloat =
- makeMultilib("").flag("-msoft-float").flag("-mnan=2008");
+ auto DefaultFloat = MultilibBuilder("")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008", /*Disallow=*/true);
- auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
+ auto BigEndian =
+ MultilibBuilder("").flag("-EB").flag("-EL", /*Disallow=*/true);
- auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+ auto LittleEndian =
+ MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true);
// Note that this one's osSuffix is ""
- auto MAbi64 = makeMultilib("")
+ auto MAbi64 = MultilibBuilder("")
.gccSuffix("/64")
.includeSuffix("/64")
- .flag("+mabi=n64")
- .flag("-mabi=n32")
- .flag("-m32");
+ .flag("-mabi=n64")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-m32", /*Disallow=*/true);
CSMipsMultilibs =
- MultilibSet()
+ MultilibSetBuilder()
.Either(MArchMips16, MArchMicroMips, MArchDefault)
.Maybe(UCLibc)
.Either(SoftFloat, Nan2008, DefaultFloat)
@@ -1050,10 +1086,11 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
.Maybe(MAbi64)
.FilterOut("/mips16.*/64")
.FilterOut("/micromips.*/64")
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
- if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ if (StringRef(M.includeSuffix()).starts_with("/uclibc"))
Dirs.push_back(
"/../../../../mips-linux-gnu/libc/uclibc/usr/include");
else
@@ -1064,21 +1101,27 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
MultilibSet DebianMipsMultilibs;
{
- Multilib MAbiN32 =
- Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32");
+ MultilibBuilder MAbiN32 =
+ MultilibBuilder().gccSuffix("/n32").includeSuffix("/n32").flag(
+ "-mabi=n32");
- Multilib M64 = Multilib()
- .gccSuffix("/64")
- .includeSuffix("/64")
- .flag("+m64")
- .flag("-m32")
- .flag("-mabi=n32");
+ MultilibBuilder M64 = MultilibBuilder()
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("-m64")
+ .flag("-m32", /*Disallow=*/true)
+ .flag("-mabi=n32", /*Disallow=*/true);
- Multilib M32 =
- Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32");
+ MultilibBuilder M32 = MultilibBuilder()
+ .gccSuffix("/32")
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-m32")
+ .flag("-mabi=n32", /*Disallow=*/true);
- DebianMipsMultilibs =
- MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent);
+ DebianMipsMultilibs = MultilibSetBuilder()
+ .Either(M32, M64, MAbiN32)
+ .makeMultilibSet()
+ .FilterOut(NonExistent);
}
// Sort candidates. Toolchain that best meets the directories tree goes first.
@@ -1087,7 +1130,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
if (CSMipsMultilibs.size() < DebianMipsMultilibs.size())
std::iter_swap(Candidates, Candidates + 1);
for (const MultilibSet *Candidate : Candidates) {
- if (Candidate->select(Flags, Result.SelectedMultilib)) {
+ if (Candidate->select(Flags, Result.SelectedMultilibs)) {
if (Candidate == &DebianMipsMultilibs)
Result.BiarchSibling = Multilib();
Result.Multilibs = *Candidate;
@@ -1103,25 +1146,32 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path,
DetectedMultilibs &Result) {
MultilibSet AndroidMipsMultilibs =
- MultilibSet()
- .Maybe(Multilib("/mips-r2").flag("+march=mips32r2"))
- .Maybe(Multilib("/mips-r6").flag("+march=mips32r6"))
+ MultilibSetBuilder()
+ .Maybe(MultilibBuilder("/mips-r2", {}, {}).flag("-march=mips32r2"))
+ .Maybe(MultilibBuilder("/mips-r6", {}, {}).flag("-march=mips32r6"))
+ .makeMultilibSet()
.FilterOut(NonExistent);
MultilibSet AndroidMipselMultilibs =
- MultilibSet()
- .Either(Multilib().flag("+march=mips32"),
- Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
- Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
+ MultilibSetBuilder()
+ .Either(MultilibBuilder().flag("-march=mips32"),
+ MultilibBuilder("/mips-r2", "", "/mips-r2")
+ .flag("-march=mips32r2"),
+ MultilibBuilder("/mips-r6", "", "/mips-r6")
+ .flag("-march=mips32r6"))
+ .makeMultilibSet()
.FilterOut(NonExistent);
MultilibSet AndroidMips64elMultilibs =
- MultilibSet()
- .Either(
- Multilib().flag("+march=mips64r6"),
- Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"),
- Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
- Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
+ MultilibSetBuilder()
+ .Either(MultilibBuilder().flag("-march=mips64r6"),
+ MultilibBuilder("/32/mips-r1", "", "/mips-r1")
+ .flag("-march=mips32"),
+ MultilibBuilder("/32/mips-r2", "", "/mips-r2")
+ .flag("-march=mips32r2"),
+ MultilibBuilder("/32/mips-r6", "", "/mips-r6")
+ .flag("-march=mips32r6"))
+ .makeMultilibSet()
.FilterOut(NonExistent);
MultilibSet *MS = &AndroidMipsMultilibs;
@@ -1129,7 +1179,7 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path,
MS = &AndroidMipselMultilibs;
else if (VFS.exists(Path + "/32"))
MS = &AndroidMips64elMultilibs;
- if (MS->select(Flags, Result.SelectedMultilib)) {
+ if (MS->select(Flags, Result.SelectedMultilibs)) {
Result.Multilibs = *MS;
return true;
}
@@ -1142,18 +1192,20 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
// Musl toolchain multilibs
MultilibSet MuslMipsMultilibs;
{
- auto MArchMipsR2 = makeMultilib("")
+ auto MArchMipsR2 = MultilibBuilder("")
.osSuffix("/mips-r2-hard-musl")
- .flag("+EB")
- .flag("-EL")
- .flag("+march=mips32r2");
+ .flag("-EB")
+ .flag("-EL", /*Disallow=*/true)
+ .flag("-march=mips32r2");
- auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl")
- .flag("-EB")
- .flag("+EL")
- .flag("+march=mips32r2");
+ auto MArchMipselR2 = MultilibBuilder("/mipsel-r2-hard-musl")
+ .flag("-EB", /*Disallow=*/true)
+ .flag("-EL")
+ .flag("-march=mips32r2");
- MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2);
+ MuslMipsMultilibs = MultilibSetBuilder()
+ .Either(MArchMipsR2, MArchMipselR2)
+ .makeMultilibSet();
// Specify the callback that computes the include directories.
MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) {
@@ -1161,7 +1213,7 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
{"/../sysroot" + M.osSuffix() + "/usr/include"});
});
}
- if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
+ if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilibs)) {
Result.Multilibs = MuslMipsMultilibs;
return true;
}
@@ -1174,48 +1226,54 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
// CodeScape MTI toolchain v1.2 and early.
MultilibSet MtiMipsMultilibsV1;
{
- auto MArchMips32 = makeMultilib("/mips32")
- .flag("+m32")
+ auto MArchMips32 = MultilibBuilder("/mips32")
+ .flag("-m32")
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true)
+ .flag("-march=mips32");
+
+ auto MArchMicroMips = MultilibBuilder("/micromips")
+ .flag("-m32")
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mmicromips");
+
+ auto MArchMips64r2 = MultilibBuilder("/mips64r2")
+ .flag("-m32", /*Disallow=*/true)
+ .flag("-m64")
+ .flag("-march=mips64r2");
+
+ auto MArchMips64 = MultilibBuilder("/mips64")
+ .flag("-m32", /*Disallow=*/true)
.flag("-m64")
- .flag("-mmicromips")
- .flag("+march=mips32");
-
- auto MArchMicroMips = makeMultilib("/micromips")
- .flag("+m32")
- .flag("-m64")
- .flag("+mmicromips");
-
- auto MArchMips64r2 = makeMultilib("/mips64r2")
- .flag("-m32")
- .flag("+m64")
- .flag("+march=mips64r2");
+ .flag("-march=mips64r2", /*Disallow=*/true);
- auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag(
- "-march=mips64r2");
+ auto MArchDefault = MultilibBuilder("")
+ .flag("-m32")
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true)
+ .flag("-march=mips32r2");
- auto MArchDefault = makeMultilib("")
- .flag("+m32")
- .flag("-m64")
- .flag("-mmicromips")
- .flag("+march=mips32r2");
+ auto Mips16 = MultilibBuilder("/mips16").flag("-mips16");
- auto Mips16 = makeMultilib("/mips16").flag("+mips16");
+ auto UCLibc = MultilibBuilder("/uclibc").flag("-muclibc");
- auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
+ auto MAbi64 = MultilibBuilder("/64")
+ .flag("-mabi=n64")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-m32", /*Disallow=*/true);
- auto MAbi64 =
- makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+ auto BigEndian =
+ MultilibBuilder("").flag("-EB").flag("-EL", /*Disallow=*/true);
- auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
+ auto LittleEndian =
+ MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true);
- auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+ auto SoftFloat = MultilibBuilder("/sof").flag("-msoft-float");
- auto SoftFloat = makeMultilib("/sof").flag("+msoft-float");
-
- auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
+ auto Nan2008 = MultilibBuilder("/nan2008").flag("-mnan=2008");
MtiMipsMultilibsV1 =
- MultilibSet()
+ MultilibSetBuilder()
.Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64,
MArchDefault)
.Maybe(UCLibc)
@@ -1232,10 +1290,11 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
.Maybe(SoftFloat)
.Maybe(Nan2008)
.FilterOut(".*sof/nan2008")
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
- if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ if (StringRef(M.includeSuffix()).starts_with("/uclibc"))
Dirs.push_back("/../../../../sysroot/uclibc/usr/include");
else
Dirs.push_back("/../../../../sysroot/usr/include");
@@ -1246,80 +1305,87 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
// CodeScape IMG toolchain starting from v1.3.
MultilibSet MtiMipsMultilibsV2;
{
- auto BeHard = makeMultilib("/mips-r2-hard")
- .flag("+EB")
+ auto BeHard = MultilibBuilder("/mips-r2-hard")
+ .flag("-EB")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008", /*Disallow=*/true)
+ .flag("-muclibc", /*Disallow=*/true);
+ auto BeSoft = MultilibBuilder("/mips-r2-soft")
+ .flag("-EB")
.flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("-muclibc");
- auto BeSoft = makeMultilib("/mips-r2-soft")
- .flag("+EB")
- .flag("+msoft-float")
- .flag("-mnan=2008");
- auto ElHard = makeMultilib("/mipsel-r2-hard")
- .flag("+EL")
+ .flag("-mnan=2008", /*Disallow=*/true);
+ auto ElHard = MultilibBuilder("/mipsel-r2-hard")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008", /*Disallow=*/true)
+ .flag("-muclibc", /*Disallow=*/true);
+ auto ElSoft = MultilibBuilder("/mipsel-r2-soft")
+ .flag("-EL")
.flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("-muclibc");
- auto ElSoft = makeMultilib("/mipsel-r2-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("-mnan=2008")
- .flag("-mmicromips");
- auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("-muclibc");
- auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("-muclibc")
- .flag("-mmicromips");
- auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("+muclibc");
- auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("+muclibc");
- auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("+muclibc");
- auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("+muclibc");
- auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("+mmicromips");
- auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("-mnan=2008")
- .flag("+mmicromips");
-
- auto O32 =
- makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
- auto N32 =
- makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
- auto N64 =
- makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
+ .flag("-mnan=2008", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true);
+ auto BeHardNan = MultilibBuilder("/mips-r2-hard-nan2008")
+ .flag("-EB")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008")
+ .flag("-muclibc", /*Disallow=*/true);
+ auto ElHardNan = MultilibBuilder("/mipsel-r2-hard-nan2008")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008")
+ .flag("-muclibc", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true);
+ auto BeHardNanUclibc = MultilibBuilder("/mips-r2-hard-nan2008-uclibc")
+ .flag("-EB")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008")
+ .flag("-muclibc");
+ auto ElHardNanUclibc = MultilibBuilder("/mipsel-r2-hard-nan2008-uclibc")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008")
+ .flag("-muclibc");
+ auto BeHardUclibc = MultilibBuilder("/mips-r2-hard-uclibc")
+ .flag("-EB")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008", /*Disallow=*/true)
+ .flag("-muclibc");
+ auto ElHardUclibc = MultilibBuilder("/mipsel-r2-hard-uclibc")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008", /*Disallow=*/true)
+ .flag("-muclibc");
+ auto ElMicroHardNan = MultilibBuilder("/micromipsel-r2-hard-nan2008")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mnan=2008")
+ .flag("-mmicromips");
+ auto ElMicroSoft = MultilibBuilder("/micromipsel-r2-soft")
+ .flag("-EL")
+ .flag("-msoft-float")
+ .flag("-mnan=2008", /*Disallow=*/true)
+ .flag("-mmicromips");
+
+ auto O32 = MultilibBuilder("/lib")
+ .osSuffix("")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-mabi=n64", /*Disallow=*/true);
+ auto N32 = MultilibBuilder("/lib32")
+ .osSuffix("")
+ .flag("-mabi=n32")
+ .flag("-mabi=n64", /*Disallow=*/true);
+ auto N64 = MultilibBuilder("/lib64")
+ .osSuffix("")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-mabi=n64");
MtiMipsMultilibsV2 =
- MultilibSet()
+ MultilibSetBuilder()
.Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan,
BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc,
ElHardUclibc, ElMicroHardNan, ElMicroSoft})
.Either(O32, N32, N64)
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>({"/../../../../sysroot" +
@@ -1331,8 +1397,8 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
{"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()});
});
}
- for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
- if (Candidate->select(Flags, Result.SelectedMultilib)) {
+ for (auto *Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
+ if (Candidate->select(Flags, Result.SelectedMultilibs)) {
Result.Multilibs = *Candidate;
return true;
}
@@ -1346,18 +1412,24 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
// CodeScape IMG toolchain v1.2 and early.
MultilibSet ImgMultilibsV1;
{
- auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32");
+ auto Mips64r6 = MultilibBuilder("/mips64r6")
+ .flag("-m64")
+ .flag("-m32", /*Disallow=*/true);
- auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+ auto LittleEndian =
+ MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true);
- auto MAbi64 =
- makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+ auto MAbi64 = MultilibBuilder("/64")
+ .flag("-mabi=n64")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-m32", /*Disallow=*/true);
ImgMultilibsV1 =
- MultilibSet()
+ MultilibSetBuilder()
.Maybe(Mips64r6)
.Maybe(MAbi64)
.Maybe(LittleEndian)
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>(
@@ -1368,51 +1440,58 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
// CodeScape IMG toolchain starting from v1.3.
MultilibSet ImgMultilibsV2;
{
- auto BeHard = makeMultilib("/mips-r6-hard")
- .flag("+EB")
+ auto BeHard = MultilibBuilder("/mips-r6-hard")
+ .flag("-EB")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true);
+ auto BeSoft = MultilibBuilder("/mips-r6-soft")
+ .flag("-EB")
.flag("-msoft-float")
- .flag("-mmicromips");
- auto BeSoft = makeMultilib("/mips-r6-soft")
- .flag("+EB")
- .flag("+msoft-float")
- .flag("-mmicromips");
- auto ElHard = makeMultilib("/mipsel-r6-hard")
- .flag("+EL")
+ .flag("-mmicromips", /*Disallow=*/true);
+ auto ElHard = MultilibBuilder("/mipsel-r6-hard")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mmicromips", /*Disallow=*/true);
+ auto ElSoft = MultilibBuilder("/mipsel-r6-soft")
+ .flag("-EL")
.flag("-msoft-float")
- .flag("-mmicromips");
- auto ElSoft = makeMultilib("/mipsel-r6-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("-mmicromips");
- auto BeMicroHard = makeMultilib("/micromips-r6-hard")
- .flag("+EB")
+ .flag("-mmicromips", /*Disallow=*/true);
+ auto BeMicroHard = MultilibBuilder("/micromips-r6-hard")
+ .flag("-EB")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mmicromips");
+ auto BeMicroSoft = MultilibBuilder("/micromips-r6-soft")
+ .flag("-EB")
.flag("-msoft-float")
- .flag("+mmicromips");
- auto BeMicroSoft = makeMultilib("/micromips-r6-soft")
- .flag("+EB")
- .flag("+msoft-float")
- .flag("+mmicromips");
- auto ElMicroHard = makeMultilib("/micromipsel-r6-hard")
- .flag("+EL")
+ .flag("-mmicromips");
+ auto ElMicroHard = MultilibBuilder("/micromipsel-r6-hard")
+ .flag("-EL")
+ .flag("-msoft-float", /*Disallow=*/true)
+ .flag("-mmicromips");
+ auto ElMicroSoft = MultilibBuilder("/micromipsel-r6-soft")
+ .flag("-EL")
.flag("-msoft-float")
- .flag("+mmicromips");
- auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("+mmicromips");
-
- auto O32 =
- makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
- auto N32 =
- makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
- auto N64 =
- makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
+ .flag("-mmicromips");
+
+ auto O32 = MultilibBuilder("/lib")
+ .osSuffix("")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-mabi=n64", /*Disallow=*/true);
+ auto N32 = MultilibBuilder("/lib32")
+ .osSuffix("")
+ .flag("-mabi=n32")
+ .flag("-mabi=n64", /*Disallow=*/true);
+ auto N64 = MultilibBuilder("/lib64")
+ .osSuffix("")
+ .flag("-mabi=n32", /*Disallow=*/true)
+ .flag("-mabi=n64");
ImgMultilibsV2 =
- MultilibSet()
+ MultilibSetBuilder()
.Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft,
ElMicroHard, ElMicroSoft})
.Either(O32, N32, N64)
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>({"/../../../../sysroot" +
@@ -1424,8 +1503,8 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
{"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()});
});
}
- for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
- if (Candidate->select(Flags, Result.SelectedMultilib)) {
+ for (auto *Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
+ if (Candidate->select(Flags, Result.SelectedMultilibs)) {
Result.Multilibs = *Candidate;
return true;
}
@@ -1446,30 +1525,30 @@ bool clang::driver::findMIPSMultilibs(const Driver &D,
llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
Multilib::flags_list Flags;
- addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags);
- addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags);
- addMultilibFlag(isMips16(Args), "mips16", Flags);
- addMultilibFlag(CPUName == "mips32", "march=mips32", Flags);
+ addMultilibFlag(TargetTriple.isMIPS32(), "-m32", Flags);
+ addMultilibFlag(TargetTriple.isMIPS64(), "-m64", Flags);
+ addMultilibFlag(isMips16(Args), "-mips16", Flags);
+ addMultilibFlag(CPUName == "mips32", "-march=mips32", Flags);
addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" ||
CPUName == "mips32r5" || CPUName == "p5600",
- "march=mips32r2", Flags);
- addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags);
- addMultilibFlag(CPUName == "mips64", "march=mips64", Flags);
+ "-march=mips32r2", Flags);
+ addMultilibFlag(CPUName == "mips32r6", "-march=mips32r6", Flags);
+ addMultilibFlag(CPUName == "mips64", "-march=mips64", Flags);
addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" ||
CPUName == "mips64r5" || CPUName == "octeon" ||
CPUName == "octeon+",
- "march=mips64r2", Flags);
- addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags);
- addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
- addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags);
- addMultilibFlag(tools::mips::isNaN2008(D, Args, TargetTriple), "mnan=2008",
+ "-march=mips64r2", Flags);
+ addMultilibFlag(CPUName == "mips64r6", "-march=mips64r6", Flags);
+ addMultilibFlag(isMicroMips(Args), "-mmicromips", Flags);
+ addMultilibFlag(tools::mips::isUCLibc(Args), "-muclibc", Flags);
+ addMultilibFlag(tools::mips::isNaN2008(D, Args, TargetTriple), "-mnan=2008",
Flags);
- addMultilibFlag(ABIName == "n32", "mabi=n32", Flags);
- addMultilibFlag(ABIName == "n64", "mabi=n64", Flags);
- addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags);
- addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags);
- addMultilibFlag(isMipsEL(TargetArch), "EL", Flags);
- addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags);
+ addMultilibFlag(ABIName == "n32", "-mabi=n32", Flags);
+ addMultilibFlag(ABIName == "n64", "-mabi=n64", Flags);
+ addMultilibFlag(isSoftFloatABI(Args), "-msoft-float", Flags);
+ addMultilibFlag(!isSoftFloatABI(Args), "-mhard-float", Flags);
+ addMultilibFlag(isMipsEL(TargetArch), "-EL", Flags);
+ addMultilibFlag(!isMipsEL(TargetArch), "-EB", Flags);
if (TargetTriple.isAndroid())
return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent,
@@ -1498,7 +1577,7 @@ bool clang::driver::findMIPSMultilibs(const Driver &D,
Result.Multilibs.push_back(Default);
Result.Multilibs.FilterOut(NonExistent);
- if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) {
+ if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) {
Result.BiarchSibling = Multilib();
return true;
}
@@ -1512,22 +1591,23 @@ static void findAndroidArmMultilibs(const Driver &D,
DetectedMultilibs &Result) {
// Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb.
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
- Multilib ArmV7Multilib = makeMultilib("/armv7-a")
- .flag("+march=armv7-a")
- .flag("-mthumb");
- Multilib ThumbMultilib = makeMultilib("/thumb")
- .flag("-march=armv7-a")
- .flag("+mthumb");
- Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
- .flag("+march=armv7-a")
- .flag("+mthumb");
- Multilib DefaultMultilib = makeMultilib("")
- .flag("-march=armv7-a")
- .flag("-mthumb");
+ MultilibBuilder ArmV7Multilib = MultilibBuilder("/armv7-a")
+ .flag("-march=armv7-a")
+ .flag("-mthumb", /*Disallow=*/true);
+ MultilibBuilder ThumbMultilib = MultilibBuilder("/thumb")
+ .flag("-march=armv7-a", /*Disallow=*/true)
+ .flag("-mthumb");
+ MultilibBuilder ArmV7ThumbMultilib =
+ MultilibBuilder("/armv7-a/thumb").flag("-march=armv7-a").flag("-mthumb");
+ MultilibBuilder DefaultMultilib =
+ MultilibBuilder("")
+ .flag("-march=armv7-a", /*Disallow=*/true)
+ .flag("-mthumb", /*Disallow=*/true);
MultilibSet AndroidArmMultilibs =
- MultilibSet()
- .Either(ThumbMultilib, ArmV7Multilib,
- ArmV7ThumbMultilib, DefaultMultilib)
+ MultilibSetBuilder()
+ .Either(ThumbMultilib, ArmV7Multilib, ArmV7ThumbMultilib,
+ DefaultMultilib)
+ .makeMultilibSet()
.FilterOut(NonExistent);
Multilib::flags_list Flags;
@@ -1541,10 +1621,10 @@ static void findAndroidArmMultilibs(const Driver &D,
bool IsArmV7Mode = (IsArmArch || IsThumbArch) &&
(llvm::ARM::parseArchVersion(Arch) == 7 ||
(IsArmArch && Arch == "" && IsV7SubArch));
- addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags);
- addMultilibFlag(IsThumbMode, "mthumb", Flags);
+ addMultilibFlag(IsArmV7Mode, "-march=armv7-a", Flags);
+ addMultilibFlag(IsThumbMode, "-mthumb", Flags);
- if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
+ if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilibs))
Result.Multilibs = AndroidArmMultilibs;
}
@@ -1553,27 +1633,213 @@ static bool findMSP430Multilibs(const Driver &D,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
- Multilib WithoutExceptions = makeMultilib("/430").flag("-exceptions");
- Multilib WithExceptions = makeMultilib("/430/exceptions").flag("+exceptions");
+ MultilibBuilder WithoutExceptions =
+ MultilibBuilder("/430").flag("-exceptions", /*Disallow=*/true);
+ MultilibBuilder WithExceptions =
+ MultilibBuilder("/430/exceptions").flag("-exceptions");
// FIXME: when clang starts to support msp430x ISA additional logic
// to select between multilib must be implemented
- // Multilib MSP430xMultilib = makeMultilib("/large");
+ // MultilibBuilder MSP430xMultilib = MultilibBuilder("/large");
- Result.Multilibs.push_back(WithoutExceptions);
- Result.Multilibs.push_back(WithExceptions);
+ Result.Multilibs.push_back(WithoutExceptions.makeMultilib());
+ Result.Multilibs.push_back(WithExceptions.makeMultilib());
Result.Multilibs.FilterOut(NonExistent);
Multilib::flags_list Flags;
addMultilibFlag(Args.hasFlag(options::OPT_fexceptions,
options::OPT_fno_exceptions, false),
- "exceptions", Flags);
- if (Result.Multilibs.select(Flags, Result.SelectedMultilib))
+ "-exceptions", Flags);
+ if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
return true;
return false;
}
+static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ DetectedMultilibs &Result) {
+ FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
+
+ tools::csky::FloatABI TheFloatABI = tools::csky::getCSKYFloatABI(D, Args);
+ std::optional<llvm::StringRef> Res =
+ tools::csky::getCSKYArchName(D, Args, TargetTriple);
+
+ if (!Res)
+ return;
+ auto ARCHName = *Res;
+
+ Multilib::flags_list Flags;
+ addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Hard, "-hard-fp",
+ Flags);
+ addMultilibFlag(TheFloatABI == tools::csky::FloatABI::SoftFP, "-soft-fp",
+ Flags);
+ addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Soft, "-soft", Flags);
+ addMultilibFlag(ARCHName == "ck801", "-march=ck801", Flags);
+ addMultilibFlag(ARCHName == "ck802", "-march=ck802", Flags);
+ addMultilibFlag(ARCHName == "ck803", "-march=ck803", Flags);
+ addMultilibFlag(ARCHName == "ck804", "-march=ck804", Flags);
+ addMultilibFlag(ARCHName == "ck805", "-march=ck805", Flags);
+ addMultilibFlag(ARCHName == "ck807", "-march=ck807", Flags);
+ addMultilibFlag(ARCHName == "ck810", "-march=ck810", Flags);
+ addMultilibFlag(ARCHName == "ck810v", "-march=ck810v", Flags);
+ addMultilibFlag(ARCHName == "ck860", "-march=ck860", Flags);
+ addMultilibFlag(ARCHName == "ck860v", "-march=ck860v", Flags);
+
+ bool isBigEndian = false;
+ if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian))
+ isBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
+ addMultilibFlag(isBigEndian, "-EB", Flags);
+
+ auto HardFloat = MultilibBuilder("/hard-fp").flag("-hard-fp");
+ auto SoftFpFloat = MultilibBuilder("/soft-fp").flag("-soft-fp");
+ auto SoftFloat = MultilibBuilder("").flag("-soft");
+ auto Arch801 = MultilibBuilder("/ck801").flag("-march=ck801");
+ auto Arch802 = MultilibBuilder("/ck802").flag("-march=ck802");
+ auto Arch803 = MultilibBuilder("/ck803").flag("-march=ck803");
+ // CK804 use the same library as CK803
+ auto Arch804 = MultilibBuilder("/ck803").flag("-march=ck804");
+ auto Arch805 = MultilibBuilder("/ck805").flag("-march=ck805");
+ auto Arch807 = MultilibBuilder("/ck807").flag("-march=ck807");
+ auto Arch810 = MultilibBuilder("").flag("-march=ck810");
+ auto Arch810v = MultilibBuilder("/ck810v").flag("-march=ck810v");
+ auto Arch860 = MultilibBuilder("/ck860").flag("-march=ck860");
+ auto Arch860v = MultilibBuilder("/ck860v").flag("-march=ck860v");
+ auto BigEndian = MultilibBuilder("/big").flag("-EB");
+
+ MultilibSet CSKYMultilibs =
+ MultilibSetBuilder()
+ .Maybe(BigEndian)
+ .Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807,
+ Arch810, Arch810v, Arch860, Arch860v})
+ .Either(HardFloat, SoftFpFloat, SoftFloat)
+ .makeMultilibSet()
+ .FilterOut(NonExistent);
+
+ if (CSKYMultilibs.select(Flags, Result.SelectedMultilibs))
+ Result.Multilibs = CSKYMultilibs;
+}
+
+/// Extend the multi-lib re-use selection mechanism for RISC-V.
+/// This function will try to re-use multi-lib if they are compatible.
+/// Definition of compatible:
+/// - ABI must be the same.
+/// - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im
+/// is a subset of march=rv32imc.
+/// - march that contains atomic extension can't reuse multi-lib that
+/// doesn't have atomic, vice versa. e.g. multi-lib=march=rv32im and
+/// march=rv32ima are not compatible, because software and hardware
+/// atomic operation can't work together correctly.
+static bool
+selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
+ const Multilib::flags_list &Flags,
+ llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) {
+ // Try to find the perfect matching multi-lib first.
+ if (RISCVMultilibSet.select(Flags, SelectedMultilibs))
+ return true;
+
+ Multilib::flags_list NewFlags;
+ std::vector<MultilibBuilder> NewMultilibs;
+
+ llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult =
+ llvm::RISCVISAInfo::parseArchString(
+ Arch, /*EnableExperimentalExtension=*/true,
+ /*ExperimentalExtensionVersionCheck=*/false);
+ // Ignore any error here, we assume it will be handled in another place.
+ if (llvm::errorToBool(ParseResult.takeError()))
+ return false;
+
+ auto &ISAInfo = *ParseResult;
+
+ addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags);
+ addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags);
+
+ // Collect all flags except march=*
+ for (StringRef Flag : Flags) {
+ if (Flag.starts_with("!march=") || Flag.starts_with("-march="))
+ continue;
+
+ NewFlags.push_back(Flag.str());
+ }
+
+ llvm::StringSet<> AllArchExts;
+ // Reconstruct multi-lib list, and break march option into separated
+ // extension. e.g. march=rv32im -> +i +m
+ for (const auto &M : RISCVMultilibSet) {
+ bool Skip = false;
+
+ MultilibBuilder NewMultilib =
+ MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix());
+ for (StringRef Flag : M.flags()) {
+ // Add back all flags except -march.
+ if (!Flag.consume_front("-march=")) {
+ NewMultilib.flag(Flag);
+ continue;
+ }
+
+ // Break down -march into individual extension.
+ llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult =
+ llvm::RISCVISAInfo::parseArchString(
+ Flag, /*EnableExperimentalExtension=*/true,
+ /*ExperimentalExtensionVersionCheck=*/false);
+ // Ignore any error here, we assume it will handled in another place.
+ if (llvm::errorToBool(MLConfigParseResult.takeError())) {
+ // We might get a parsing error if rv32e in the list, we could just skip
+ // that and process the rest of multi-lib configs.
+ Skip = true;
+ continue;
+ }
+ auto &MLConfigISAInfo = *MLConfigParseResult;
+
+ const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts =
+ MLConfigISAInfo->getExtensions();
+ for (auto MLConfigArchExt : MLConfigArchExts) {
+ auto ExtName = MLConfigArchExt.first;
+ NewMultilib.flag(Twine("-", ExtName).str());
+
+ if (AllArchExts.insert(ExtName).second) {
+ addMultilibFlag(ISAInfo->hasExtension(ExtName),
+ Twine("-", ExtName).str(), NewFlags);
+ }
+ }
+
+ // Check the XLEN explicitly.
+ if (MLConfigISAInfo->getXLen() == 32) {
+ NewMultilib.flag("-m32");
+ NewMultilib.flag("-m64", /*Disallow*/ true);
+ } else {
+ NewMultilib.flag("-m32", /*Disallow*/ true);
+ NewMultilib.flag("-m64");
+ }
+
+ // Atomic extension must be explicitly checked, soft and hard atomic
+ // operation never co-work correctly.
+ if (!MLConfigISAInfo->hasExtension("a"))
+ NewMultilib.flag("-a", /*Disallow*/ true);
+ }
+
+ if (Skip)
+ continue;
+
+ NewMultilibs.emplace_back(NewMultilib);
+ }
+
+ // Build an internal used only multi-lib list, used for checking any
+ // compatible multi-lib.
+ MultilibSet NewRISCVMultilibs =
+ MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet();
+
+ if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs))
+ for (const Multilib &NewSelectedM : SelectedMultilibs)
+ for (const auto &M : RISCVMultilibSet)
+ // Look up the corresponding multi-lib entry in original multi-lib set.
+ if (M.gccSuffix() == NewSelectedM.gccSuffix())
+ return true;
+
+ return false;
+}
+
static void findRISCVBareMetalMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
@@ -1590,17 +1856,19 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
{"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"},
{"rv64imafdc", "lp64d"}};
- std::vector<Multilib> Ms;
+ std::vector<MultilibBuilder> 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()));
+ MultilibBuilder(
+ (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))
+ MultilibSetBuilder()
+ .Either(Ms)
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setFilePathsCallback([](const Multilib &M) {
return std::vector<std::string>(
@@ -1609,22 +1877,22 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
"/../../../../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);
+ 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);
+ Twine("-mabi=", Element.mabi).str().c_str(), Flags);
}
}
- if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
+ if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags,
+ Result.SelectedMultilibs))
Result.Multilibs = RISCVMultilibs;
}
@@ -1635,33 +1903,38 @@ static void findRISCVMultilibs(const Driver &D,
return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result);
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
- Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32");
- Multilib Ilp32f =
- makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f");
- Multilib Ilp32d =
- makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d");
- Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64");
- Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f");
- Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d");
+ MultilibBuilder Ilp32 =
+ MultilibBuilder("lib32/ilp32").flag("-m32").flag("-mabi=ilp32");
+ MultilibBuilder Ilp32f =
+ MultilibBuilder("lib32/ilp32f").flag("-m32").flag("-mabi=ilp32f");
+ MultilibBuilder Ilp32d =
+ MultilibBuilder("lib32/ilp32d").flag("-m32").flag("-mabi=ilp32d");
+ MultilibBuilder Lp64 =
+ MultilibBuilder("lib64/lp64").flag("-m64").flag("-mabi=lp64");
+ MultilibBuilder Lp64f =
+ MultilibBuilder("lib64/lp64f").flag("-m64").flag("-mabi=lp64f");
+ MultilibBuilder Lp64d =
+ MultilibBuilder("lib64/lp64d").flag("-m64").flag("-mabi=lp64d");
MultilibSet RISCVMultilibs =
- MultilibSet()
+ MultilibSetBuilder()
.Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d})
+ .makeMultilibSet()
.FilterOut(NonExistent);
Multilib::flags_list Flags;
bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64;
StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple);
- addMultilibFlag(!IsRV64, "m32", Flags);
- addMultilibFlag(IsRV64, "m64", Flags);
- addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags);
- addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags);
- addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags);
- addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags);
- addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags);
- addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags);
+ addMultilibFlag(!IsRV64, "-m32", Flags);
+ addMultilibFlag(IsRV64, "-m64", Flags);
+ addMultilibFlag(ABIName == "ilp32", "-mabi=ilp32", Flags);
+ addMultilibFlag(ABIName == "ilp32f", "-mabi=ilp32f", Flags);
+ addMultilibFlag(ABIName == "ilp32d", "-mabi=ilp32d", Flags);
+ addMultilibFlag(ABIName == "lp64", "-mabi=lp64", Flags);
+ addMultilibFlag(ABIName == "lp64f", "-mabi=lp64f", Flags);
+ addMultilibFlag(ABIName == "lp64d", "-mabi=lp64d", Flags);
- if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
+ if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs))
Result.Multilibs = RISCVMultilibs;
}
@@ -1670,7 +1943,7 @@ static bool findBiarchMultilibs(const Driver &D,
StringRef Path, const ArgList &Args,
bool NeedsBiarchSuffix,
DetectedMultilibs &Result) {
- Multilib Default;
+ MultilibBuilder DefaultBuilder;
// Some versions of SUSE and Fedora on ppc64 put 32-bit libs
// in what would normally be GCCInstallPath and put the 64-bit
@@ -1681,7 +1954,7 @@ static bool findBiarchMultilibs(const Driver &D,
StringRef Suff64 = "/64";
// Solaris uses platform-specific suffixes instead of /64.
- if (TargetTriple.getOS() == llvm::Triple::Solaris) {
+ if (TargetTriple.isOSSolaris()) {
switch (TargetTriple.getArch()) {
case llvm::Triple::x86:
case llvm::Triple::x86_64:
@@ -1696,24 +1969,33 @@ static bool findBiarchMultilibs(const Driver &D,
}
}
- Multilib Alt64 = Multilib()
+ Multilib Alt64 = MultilibBuilder()
.gccSuffix(Suff64)
.includeSuffix(Suff64)
- .flag("-m32")
- .flag("+m64")
- .flag("-mx32");
- Multilib Alt32 = Multilib()
+ .flag("-m32", /*Disallow=*/true)
+ .flag("-m64")
+ .flag("-mx32", /*Disallow=*/true)
+ .makeMultilib();
+ Multilib Alt32 = MultilibBuilder()
.gccSuffix("/32")
.includeSuffix("/32")
- .flag("+m32")
- .flag("-m64")
- .flag("-mx32");
- Multilib Altx32 = Multilib()
+ .flag("-m32")
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mx32", /*Disallow=*/true)
+ .makeMultilib();
+ Multilib Altx32 = MultilibBuilder()
.gccSuffix("/x32")
.includeSuffix("/x32")
- .flag("-m32")
- .flag("-m64")
- .flag("+mx32");
+ .flag("-m32", /*Disallow=*/true)
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mx32")
+ .makeMultilib();
+ Multilib Alt32sparc = MultilibBuilder()
+ .gccSuffix("/sparcv8plus")
+ .includeSuffix("/sparcv8plus")
+ .flag("-m32")
+ .flag("-m64", /*Disallow=*/true)
+ .makeMultilib();
// GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a.
FilterNonExistent NonExistent(
@@ -1725,10 +2007,14 @@ static bool findBiarchMultilibs(const Driver &D,
const bool IsX32 = TargetTriple.isX32();
if (TargetTriple.isArch32Bit() && !NonExistent(Alt32))
Want = WANT64;
+ if (TargetTriple.isArch32Bit() && !NonExistent(Alt32sparc))
+ Want = WANT64;
else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32))
Want = WANT64;
else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64))
Want = WANT32;
+ else if (TargetTriple.isArch64Bit() && !NonExistent(Alt32sparc))
+ Want = WANT64;
else {
if (TargetTriple.isArch32Bit())
Want = NeedsBiarchSuffix ? WANT64 : WANT32;
@@ -1739,31 +2025,42 @@ static bool findBiarchMultilibs(const Driver &D,
}
if (Want == WANT32)
- Default.flag("+m32").flag("-m64").flag("-mx32");
+ DefaultBuilder.flag("-m32")
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mx32", /*Disallow=*/true);
else if (Want == WANT64)
- Default.flag("-m32").flag("+m64").flag("-mx32");
+ DefaultBuilder.flag("-m32", /*Disallow=*/true)
+ .flag("-m64")
+ .flag("-mx32", /*Disallow=*/true);
else if (Want == WANTX32)
- Default.flag("-m32").flag("-m64").flag("+mx32");
+ DefaultBuilder.flag("-m32", /*Disallow=*/true)
+ .flag("-m64", /*Disallow=*/true)
+ .flag("-mx32");
else
return false;
+ Multilib Default = DefaultBuilder.makeMultilib();
+
Result.Multilibs.push_back(Default);
Result.Multilibs.push_back(Alt64);
Result.Multilibs.push_back(Alt32);
Result.Multilibs.push_back(Altx32);
+ Result.Multilibs.push_back(Alt32sparc);
Result.Multilibs.FilterOut(NonExistent);
Multilib::flags_list Flags;
- addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags);
- addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags);
- addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags);
+ addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "-m64", Flags);
+ addMultilibFlag(TargetTriple.isArch32Bit(), "-m32", Flags);
+ addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "-mx32", Flags);
- if (!Result.Multilibs.select(Flags, Result.SelectedMultilib))
+ if (!Result.Multilibs.select(Flags, Result.SelectedMultilibs))
return false;
- if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 ||
- Result.SelectedMultilib == Altx32)
+ if (Result.SelectedMultilibs.back() == Alt64 ||
+ Result.SelectedMultilibs.back() == Alt32 ||
+ Result.SelectedMultilibs.back() == Altx32 ||
+ Result.SelectedMultilibs.back() == Alt32sparc)
Result.BiarchSibling = Default;
return true;
@@ -1779,8 +2076,15 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
StringRef RHSPatchSuffix) const {
if (Major != RHSMajor)
return Major < RHSMajor;
- if (Minor != RHSMinor)
+ if (Minor != RHSMinor) {
+ // Note that versions without a specified minor sort higher than those with
+ // a minor.
+ if (RHSMinor == -1)
+ return true;
+ if (Minor == -1)
+ return false;
return Minor < RHSMinor;
+ }
if (Patch != RHSPatch) {
// Note that versions without a specified patch sort higher than those with
// a patch.
@@ -1816,45 +2120,72 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
std::pair<StringRef, StringRef> First = VersionText.split('.');
std::pair<StringRef, StringRef> Second = First.second.split('.');
- GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
- if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
- return BadVersion;
- GoodVersion.MajorStr = First.first.str();
- if (First.second.empty())
- return GoodVersion;
+ StringRef MajorStr = First.first;
StringRef MinorStr = Second.first;
- if (Second.second.empty()) {
- if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) {
- GoodVersion.PatchSuffix = std::string(MinorStr.substr(EndNumber));
- MinorStr = MinorStr.slice(0, EndNumber);
- }
- }
- if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
- return BadVersion;
- GoodVersion.MinorStr = MinorStr.str();
+ StringRef PatchStr = Second.second;
+
+ GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
- // First look for a number prefix and parse that if present. Otherwise just
- // stash the entire patch string in the suffix, and leave the number
- // unspecified. This covers versions strings such as:
- // 5 (handled above)
+ // Parse version number strings such as:
+ // 5
// 4.4
// 4.4-patched
// 4.4.0
// 4.4.x
// 4.4.2-rc4
// 4.4.x-patched
- // And retains any patch number it finds.
- StringRef PatchText = Second.second;
- if (!PatchText.empty()) {
- if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
- // Try to parse the number and any suffix.
- if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
- GoodVersion.Patch < 0)
- return BadVersion;
- GoodVersion.PatchSuffix = std::string(PatchText.substr(EndNumber));
+ // 10-win32
+ // Split on '.', handle 1, 2 or 3 such segments. Each segment must contain
+ // purely a number, except for the last one, where a non-number suffix
+ // is stored in PatchSuffix. The third segment is allowed to not contain
+ // a number at all.
+
+ auto TryParseLastNumber = [&](StringRef Segment, int &Number,
+ std::string &OutStr) -> bool {
+ // Look for a number prefix and parse that, and split out any trailing
+ // string into GoodVersion.PatchSuffix.
+
+ if (size_t EndNumber = Segment.find_first_not_of("0123456789")) {
+ StringRef NumberStr = Segment.slice(0, EndNumber);
+ if (NumberStr.getAsInteger(10, Number) || Number < 0)
+ return false;
+ OutStr = NumberStr;
+ GoodVersion.PatchSuffix = Segment.substr(EndNumber);
+ return true;
}
+ return false;
+ };
+ auto TryParseNumber = [](StringRef Segment, int &Number) -> bool {
+ if (Segment.getAsInteger(10, Number) || Number < 0)
+ return false;
+ return true;
+ };
+
+ if (MinorStr.empty()) {
+ // If no minor string, major is the last segment
+ if (!TryParseLastNumber(MajorStr, GoodVersion.Major, GoodVersion.MajorStr))
+ return BadVersion;
+ return GoodVersion;
}
+ if (!TryParseNumber(MajorStr, GoodVersion.Major))
+ return BadVersion;
+ GoodVersion.MajorStr = MajorStr;
+
+ if (PatchStr.empty()) {
+ // If no patch string, minor is the last segment
+ if (!TryParseLastNumber(MinorStr, GoodVersion.Minor, GoodVersion.MinorStr))
+ return BadVersion;
+ return GoodVersion;
+ }
+
+ if (!TryParseNumber(MinorStr, GoodVersion.Minor))
+ return BadVersion;
+ GoodVersion.MinorStr = MinorStr;
+
+ // For the last segment, tolerate a missing number.
+ std::string DummyStr;
+ TryParseLastNumber(PatchStr, GoodVersion.Patch, DummyStr);
return GoodVersion;
}
@@ -1883,8 +2214,7 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args,
/// necessary because the driver doesn't store the final version of the target
/// triple.
void Generic_GCC::GCCInstallationDetector::init(
- const llvm::Triple &TargetTriple, const ArgList &Args,
- ArrayRef<std::string> ExtraTripleAliases) {
+ const llvm::Triple &TargetTriple, const ArgList &Args) {
llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit()
? TargetTriple.get64BitArchVariant()
: TargetTriple.get32BitArchVariant();
@@ -1893,10 +2223,48 @@ void Generic_GCC::GCCInstallationDetector::init(
// The compatible GCC triples for this particular architecture.
SmallVector<StringRef, 16> CandidateTripleAliases;
SmallVector<StringRef, 16> CandidateBiarchTripleAliases;
+ // Add some triples that we want to check first.
+ CandidateTripleAliases.push_back(TargetTriple.str());
+ std::string TripleNoVendor = TargetTriple.getArchName().str() + "-" +
+ TargetTriple.getOSAndEnvironmentName().str();
+ if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor)
+ CandidateTripleAliases.push_back(TripleNoVendor);
+
CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs,
CandidateTripleAliases, CandidateBiarchLibDirs,
CandidateBiarchTripleAliases);
+ // If --gcc-install-dir= is specified, skip filesystem detection.
+ if (const Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_gcc_install_dir_EQ);
+ A && A->getValue()[0]) {
+ StringRef InstallDir = A->getValue();
+ if (!ScanGCCForMultilibs(TargetTriple, Args, InstallDir, false)) {
+ D.Diag(diag::err_drv_invalid_gcc_install_dir) << InstallDir;
+ } else {
+ (void)InstallDir.consume_back("/");
+ StringRef VersionText = llvm::sys::path::filename(InstallDir);
+ StringRef TripleText =
+ llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir));
+
+ Version = GCCVersion::Parse(VersionText);
+ GCCTriple.setTriple(TripleText);
+ GCCInstallPath = std::string(InstallDir);
+ GCCParentLibPath = GCCInstallPath + "/../../..";
+ IsValid = true;
+ }
+ return;
+ }
+
+ // If --gcc-triple is specified use this instead of trying to
+ // auto-detect a triple.
+ if (const Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_gcc_triple_EQ)) {
+ StringRef GCCTriple = A->getValue();
+ CandidateTripleAliases.clear();
+ CandidateTripleAliases.push_back(GCCTriple);
+ }
+
// Compute the set of prefixes for our search.
SmallVector<std::string, 8> Prefixes;
StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot);
@@ -1932,9 +2300,6 @@ void Generic_GCC::GCCInstallationDetector::init(
// may pick the libraries for x86_64-pc-linux-gnu even when exact matching
// triple x86_64-gentoo-linux-gnu is present.
GentooTestTriples.push_back(TargetTriple.str());
- // Check rest of triples.
- GentooTestTriples.append(ExtraTripleAliases.begin(),
- ExtraTripleAliases.end());
GentooTestTriples.append(CandidateTripleAliases.begin(),
CandidateTripleAliases.end());
if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples,
@@ -1951,19 +2316,12 @@ void Generic_GCC::GCCInstallationDetector::init(
if (!VFS.exists(Prefix))
continue;
for (StringRef Suffix : CandidateLibDirs) {
- const std::string LibDir = Prefix + Suffix.str();
+ const std::string LibDir = concat(Prefix, Suffix);
if (!VFS.exists(LibDir))
continue;
// Maybe filter out <libdir>/gcc and <libdir>/gcc-cross.
bool GCCDirExists = VFS.exists(LibDir + "/gcc");
bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross");
- // Try to match the exact target triple first.
- ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str(),
- false, GCCDirExists, GCCCrossDirExists);
- // Try rest of possible triples.
- for (StringRef Candidate : ExtraTripleAliases) // Try these first.
- ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false,
- GCCDirExists, GCCCrossDirExists);
for (StringRef Candidate : CandidateTripleAliases)
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false,
GCCDirExists, GCCCrossDirExists);
@@ -2000,8 +2358,8 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
}
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
- if (BiarchSibling.hasValue()) {
- M = BiarchSibling.getValue();
+ if (BiarchSibling) {
+ M = *BiarchSibling;
return true;
}
return false;
@@ -2010,14 +2368,21 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes,
StringRef SysRoot) {
- if (TargetTriple.getOS() == llvm::Triple::Solaris) {
+
+ if (TargetTriple.isOSHaiku()) {
+ Prefixes.push_back(concat(SysRoot, "/boot/system/develop/tools"));
+ return;
+ }
+
+ if (TargetTriple.isOSSolaris()) {
// Solaris is a special case.
// The GCC installation is under
// /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/
// so we need to find those /usr/gcc/*/lib/gcc libdirs and go with
// /usr/gcc/<version> as a prefix.
- std::string PrefixDir = SysRoot.str() + "/usr/gcc";
+ SmallVector<std::pair<GCCVersion, std::string>, 8> SolarisPrefixes;
+ std::string PrefixDir = concat(SysRoot, "/usr/gcc");
std::error_code EC;
for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC),
LE;
@@ -2034,15 +2399,27 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
if (!D.getVFS().exists(CandidateLibPath))
continue;
- Prefixes.push_back(CandidatePrefix);
+ SolarisPrefixes.emplace_back(
+ std::make_pair(CandidateVersion, CandidatePrefix));
}
+ // Sort in reverse order so GCCInstallationDetector::init picks the latest.
+ std::sort(SolarisPrefixes.rbegin(), SolarisPrefixes.rend());
+ for (auto p : SolarisPrefixes)
+ Prefixes.emplace_back(p.second);
return;
}
- // Non-Solaris is much simpler - most systems just go with "/usr".
- if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) {
- // Yet, still look for RHEL/CentOS devtoolsets and gcc-toolsets.
+ // For Linux, if --sysroot is not specified, look for RHEL/CentOS devtoolsets
+ // and gcc-toolsets.
+ if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux &&
+ D.getVFS().exists("/opt/rh")) {
+ // TODO: We may want to remove this, since the functionality
+ // can be achieved using config files.
+ Prefixes.push_back("/opt/rh/gcc-toolset-12/root/usr");
+ Prefixes.push_back("/opt/rh/gcc-toolset-11/root/usr");
Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-12/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-11/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-10/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-9/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-8/root/usr");
@@ -2052,7 +2429,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
}
- Prefixes.push_back(SysRoot.str() + "/usr");
+
+ // Fall back to /usr which is used by most non-Solaris systems.
+ Prefixes.push_back(concat(SysRoot, "/usr"));
}
/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
@@ -2092,6 +2471,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
static const char *const AVRLibDirs[] = {"/lib"};
static const char *const AVRTriples[] = {"avr"};
+ static const char *const CSKYLibDirs[] = {"/lib"};
+ static const char *const CSKYTriples[] = {
+ "csky-linux-gnuabiv2", "csky-linux-uclibcabiv2", "csky-elf-noneabiv2"};
+
static const char *const X86_64LibDirs[] = {"/lib64", "/lib"};
static const char *const X86_64Triples[] = {
"x86_64-linux-gnu", "x86_64-unknown-linux-gnu",
@@ -2107,9 +2490,13 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
static const char *const X86Triples[] = {
"i586-linux-gnu", "i686-linux-gnu", "i686-pc-linux-gnu",
"i386-redhat-linux6E", "i686-redhat-linux", "i386-redhat-linux",
- "i586-suse-linux", "i686-montavista-linux", "i686-gnu",
+ "i586-suse-linux", "i686-montavista-linux",
};
+ static const char *const LoongArch64LibDirs[] = {"/lib64", "/lib"};
+ static const char *const LoongArch64Triples[] = {
+ "loongarch64-linux-gnu", "loongarch64-unknown-linux-gnu"};
+
static const char *const M68kLibDirs[] = {"/lib"};
static const char *const M68kTriples[] = {
"m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"};
@@ -2189,16 +2576,14 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
using std::begin;
using std::end;
- if (TargetTriple.getOS() == llvm::Triple::Solaris) {
+ if (TargetTriple.isOSSolaris()) {
static const char *const SolarisLibDirs[] = {"/lib"};
static const char *const SolarisSparcV8Triples[] = {
- "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"};
+ "sparc-sun-solaris2.11"};
static const char *const SolarisSparcV9Triples[] = {
- "sparcv9-sun-solaris2.11", "sparcv9-sun-solaris2.12"};
- static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11",
- "i386-pc-solaris2.12"};
- static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11",
- "x86_64-pc-solaris2.12"};
+ "sparcv9-sun-solaris2.11"};
+ static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11"};
+ static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11"};
LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs));
BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs));
switch (TargetTriple.getArch()) {
@@ -2236,9 +2621,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
static const char *const AArch64AndroidTriples[] = {
"aarch64-linux-android"};
static const char *const ARMAndroidTriples[] = {"arm-linux-androideabi"};
- static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"};
- static const char *const MIPS64ELAndroidTriples[] = {
- "mips64el-linux-android"};
static const char *const X86AndroidTriples[] = {"i686-linux-android"};
static const char *const X86_64AndroidTriples[] = {"x86_64-linux-android"};
@@ -2253,22 +2635,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
TripleAliases.append(begin(ARMAndroidTriples), end(ARMAndroidTriples));
break;
- case llvm::Triple::mipsel:
- LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
- TripleAliases.append(begin(MIPSELAndroidTriples),
- end(MIPSELAndroidTriples));
- BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
- BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples),
- end(MIPS64ELAndroidTriples));
- break;
- case llvm::Triple::mips64el:
- LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
- TripleAliases.append(begin(MIPS64ELAndroidTriples),
- end(MIPS64ELAndroidTriples));
- BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
- BiarchTripleAliases.append(begin(MIPSELAndroidTriples),
- end(MIPSELAndroidTriples));
- break;
case llvm::Triple::x86_64:
LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
TripleAliases.append(begin(X86_64AndroidTriples),
@@ -2291,6 +2657,23 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
return;
}
+ if (TargetTriple.isOSHurd()) {
+ switch (TargetTriple.getArch()) {
+ case llvm::Triple::x86_64:
+ LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
+ TripleAliases.push_back("x86_64-gnu");
+ break;
+ case llvm::Triple::x86:
+ LibDirs.append(begin(X86LibDirs), end(X86LibDirs));
+ TripleAliases.push_back("i686-gnu");
+ break;
+ default:
+ break;
+ }
+
+ return;
+ }
+
switch (TargetTriple.getArch()) {
case llvm::Triple::aarch64:
LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
@@ -2307,7 +2690,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
case llvm::Triple::arm:
case llvm::Triple::thumb:
LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
- if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF ||
+ TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF ||
+ TargetTriple.getEnvironment() == llvm::Triple::EABIHF) {
TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
} else {
TripleAliases.append(begin(ARMTriples), end(ARMTriples));
@@ -2316,7 +2701,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
- if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF ||
+ TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF ||
+ TargetTriple.getEnvironment() == llvm::Triple::EABIHF) {
TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
} else {
TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
@@ -2326,6 +2713,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs));
TripleAliases.append(begin(AVRTriples), end(AVRTriples));
break;
+ case llvm::Triple::csky:
+ LibDirs.append(begin(CSKYLibDirs), end(CSKYLibDirs));
+ TripleAliases.append(begin(CSKYTriples), end(CSKYTriples));
+ break;
case llvm::Triple::x86_64:
if (TargetTriple.isX32()) {
LibDirs.append(begin(X32LibDirs), end(X32LibDirs));
@@ -2353,6 +2744,11 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
BiarchTripleAliases.append(begin(X32Triples), end(X32Triples));
}
break;
+ // TODO: Handle loongarch32.
+ case llvm::Triple::loongarch64:
+ LibDirs.append(begin(LoongArch64LibDirs), end(LoongArch64LibDirs));
+ TripleAliases.append(begin(LoongArch64Triples), end(LoongArch64Triples));
+ break;
case llvm::Triple::m68k:
LibDirs.append(begin(M68kLibDirs), end(M68kLibDirs));
TripleAliases.append(begin(M68kTriples), end(M68kTriples));
@@ -2454,10 +2850,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
break;
}
- // Always append the drivers target triple to the end, in case it doesn't
- // match any of our aliases.
- TripleAliases.push_back(TargetTriple.str());
-
// Also include the multiarch variant if it's different.
if (TargetTriple.str() != BiarchTriple.str())
BiarchTripleAliases.push_back(BiarchTriple.str());
@@ -2475,6 +2867,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) {
// It should also work without multilibs in a simplified toolchain.
findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected);
+ } else if (TargetTriple.isCSKY()) {
+ findCSKYMultilibs(D, TargetTriple, Path, Args, Detected);
} else if (TargetTriple.isMIPS()) {
if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected))
return false;
@@ -2490,7 +2884,9 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
}
Multilibs = Detected.Multilibs;
- SelectedMultilib = Detected.SelectedMultilib;
+ SelectedMultilib = Detected.SelectedMultilibs.empty()
+ ? Multilib()
+ : Detected.SelectedMultilibs.back();
BiarchSibling = Detected.BiarchSibling;
return true;
@@ -2565,7 +2961,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
const llvm::Triple &TargetTriple, const ArgList &Args,
const SmallVectorImpl<StringRef> &CandidateTriples,
const SmallVectorImpl<StringRef> &CandidateBiarchTriples) {
- if (!D.getVFS().exists(D.SysRoot + GentooConfigDir))
+ if (!D.getVFS().exists(concat(D.SysRoot, GentooConfigDir)))
return false;
for (StringRef CandidateTriple : CandidateTriples) {
@@ -2584,8 +2980,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
const llvm::Triple &TargetTriple, const ArgList &Args,
StringRef CandidateTriple, bool NeedsBiarchSuffix) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
- D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/config-" +
- CandidateTriple.str());
+ D.getVFS().getBufferForFile(concat(D.SysRoot, GentooConfigDir,
+ "/config-" + CandidateTriple.str()));
if (File) {
SmallVector<StringRef, 2> Lines;
File.get()->getBuffer().split(Lines, "\n");
@@ -2596,8 +2992,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
continue;
// Process the config file pointed to by CURRENT.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile =
- D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/" +
- Line.str());
+ D.getVFS().getBufferForFile(
+ concat(D.SysRoot, GentooConfigDir, "/" + Line));
std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-');
// List of paths to scan for libraries.
SmallVector<StringRef, 4> GentooScanPaths;
@@ -2630,7 +3026,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
// Scan all paths for GCC libraries.
for (const auto &GentooScanPath : GentooScanPaths) {
- std::string GentooPath = D.SysRoot + std::string(GentooScanPath);
+ std::string GentooPath = concat(D.SysRoot, GentooScanPath);
if (D.getVFS().exists(GentooPath + "/crtbegin.o")) {
if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath,
NeedsBiarchSuffix))
@@ -2685,22 +3081,26 @@ Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); }
void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
// Print the information about how we detected the GCC installation.
GCCInstallation.print(OS);
- CudaInstallation.print(OS);
- RocmInstallation.print(OS);
+ CudaInstallation->print(OS);
+ RocmInstallation->print(OS);
}
-bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+Generic_GCC::getDefaultUnwindTableLevel(const ArgList &Args) const {
switch (getArch()) {
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
case llvm::Triple::ppc:
case llvm::Triple::ppcle:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
- return true;
+ return UnwindTableLevel::Asynchronous;
default:
- return false;
+ return UnwindTableLevel::None;
}
}
@@ -2726,40 +3126,12 @@ bool Generic_GCC::isPICDefaultForced() const {
bool Generic_GCC::IsIntegratedAssemblerDefault() const {
switch (getTriple().getArch()) {
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::avr:
- case llvm::Triple::bpfel:
- case llvm::Triple::bpfeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::ppc:
- case llvm::Triple::ppcle:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
- case llvm::Triple::systemz:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::msp430:
- case llvm::Triple::m68k:
- return true;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- if (getTriple().isOSFreeBSD() || getTriple().isOSOpenBSD() ||
- getTriple().isOSSolaris())
- return true;
+ case llvm::Triple::nvptx:
+ case llvm::Triple::nvptx64:
+ case llvm::Triple::xcore:
return false;
default:
- return false;
+ return true;
}
}
@@ -2785,6 +3157,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
path_list &Paths) {
// Add the multilib suffixed paths where they are available.
if (GCCInstallation.isValid()) {
+ assert(!SelectedMultilibs.empty());
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath =
std::string(GCCInstallation.getParentLibPath());
@@ -2792,13 +3165,19 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
// Sourcery CodeBench MIPS toolchain holds some libraries under
// a biarch-like suffix of the GCC installation.
if (const auto &PathsCallback = Multilibs.filePathsCallback())
- for (const auto &Path : PathsCallback(SelectedMultilib))
+ for (const auto &Path : PathsCallback(SelectedMultilibs.back()))
addPathIfExists(D, GCCInstallation.getInstallPath() + Path, Paths);
// Add lib/gcc/$triple/$version, with an optional /multilib suffix.
- addPathIfExists(
- D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(),
- Paths);
+ addPathIfExists(D,
+ GCCInstallation.getInstallPath() +
+ SelectedMultilibs.back().gccSuffix(),
+ Paths);
+
+ // Add lib/gcc/$triple/$libdir
+ // For GCC built with --enable-version-specific-runtime-libs.
+ addPathIfExists(D, GCCInstallation.getInstallPath() + "/../" + OSLibDir,
+ Paths);
// GCC cross compiling toolchains will install target libraries which ship
// as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
@@ -2820,7 +3199,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
// Clang diverges from GCC's behavior.
addPathIfExists(D,
LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir +
- SelectedMultilib.osSuffix(),
+ SelectedMultilibs.back().osSuffix(),
Paths);
// If the GCC installation we found is inside of the sysroot, we want to
@@ -2832,7 +3211,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
// the cross. Note that GCC does include some of these directories in some
// configurations but this seems somewhere between questionable and simply
// a bug.
- if (StringRef(LibPath).startswith(SysRoot))
+ if (StringRef(LibPath).starts_with(SysRoot))
addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths);
}
}
@@ -2893,34 +3272,53 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const Driver &D = getDriver();
std::string SysRoot = computeSysRoot();
- std::string Target = getTripleString();
+ if (SysRoot.empty())
+ SysRoot = llvm::sys::path::get_separator();
- auto AddIncludePath = [&](std::string Path) {
+ auto AddIncludePath = [&](StringRef Path, bool TargetDirRequired = false) {
std::string Version = detectLibcxxVersion(Path);
if (Version.empty())
return false;
// First add the per-target include path if it exists.
- std::string TargetDir = Path + "/" + Target + "/c++/" + Version;
- if (D.getVFS().exists(TargetDir))
- addSystemInclude(DriverArgs, CC1Args, TargetDir);
+ bool TargetDirExists = false;
+ std::optional<std::string> TargetIncludeDir = getTargetSubDirPath(Path);
+ if (TargetIncludeDir) {
+ SmallString<128> TargetDir(*TargetIncludeDir);
+ llvm::sys::path::append(TargetDir, "c++", Version);
+ if (D.getVFS().exists(TargetDir)) {
+ addSystemInclude(DriverArgs, CC1Args, TargetDir);
+ TargetDirExists = true;
+ }
+ }
+ if (TargetDirRequired && !TargetDirExists)
+ return false;
// Second add the generic one.
- addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version);
+ SmallString<128> GenericDir(Path);
+ llvm::sys::path::append(GenericDir, "c++", Version);
+ addSystemInclude(DriverArgs, CC1Args, GenericDir);
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"))
- return;
+ // Android only uses the libc++ headers installed alongside the toolchain if
+ // they contain an Android-specific target include path, otherwise they're
+ // incompatible with the NDK libraries.
+ SmallString<128> DriverIncludeDir(getDriver().Dir);
+ llvm::sys::path::append(DriverIncludeDir, "..", "include");
+ if (AddIncludePath(DriverIncludeDir,
+ /*TargetDirRequired=*/getTriple().isAndroid()))
+ 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"))
+ SmallString<128> UsrLocalIncludeDir(SysRoot);
+ llvm::sys::path::append(UsrLocalIncludeDir, "usr", "local", "include");
+ if (AddIncludePath(UsrLocalIncludeDir))
return;
- if (AddIncludePath(SysRoot + "/usr/include"))
+ SmallString<128> UsrIncludeDir(SysRoot);
+ llvm::sys::path::append(UsrIncludeDir, "usr", "include");
+ if (AddIncludePath(UsrIncludeDir))
return;
}
@@ -2978,6 +3376,15 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths(
TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args))
return true;
+ // Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not
+ // empty). Like above but for GCC built with
+ // --enable-version-specific-runtime-libs.
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" +
+ Version.Text + "/include/c++/",
+ TripleStr, Multilib.includeSuffix(), DriverArgs,
+ CC1Args))
+ return true;
+
// Detect Debian g++-multiarch-incdir.diff.
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
DebianMultiarch, Multilib.includeSuffix(),
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h
index 4eb7ab0215ab..0b664a182d75 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H
#include "Cuda.h"
+#include "LazyDetector.h"
#include "ROCm.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
@@ -22,12 +23,12 @@ struct DetectedMultilibs {
/// The set of multilibs that the detected installation supports.
MultilibSet Multilibs;
- /// The primary multilib appropriate for the given flags.
- Multilib SelectedMultilib;
+ /// The multilibs appropriate for the given flags.
+ llvm::SmallVector<Multilib> SelectedMultilibs;
/// On Biarch systems, this corresponds to the default multilib when
/// targeting the non-default multilib. Otherwise, it is empty.
- llvm::Optional<Multilib> BiarchSibling;
+ std::optional<Multilib> BiarchSibling;
};
bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
@@ -201,7 +202,7 @@ public:
Multilib SelectedMultilib;
/// On Biarch systems, this corresponds to the default multilib when
/// targeting the non-default multilib. Otherwise, it is empty.
- llvm::Optional<Multilib> BiarchSibling;
+ std::optional<Multilib> BiarchSibling;
GCCVersion Version;
@@ -217,8 +218,7 @@ public:
public:
explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
- void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args,
- ArrayRef<std::string> ExtraTripleAliases = None);
+ void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
/// Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }
@@ -286,8 +286,8 @@ public:
protected:
GCCInstallationDetector GCCInstallation;
- CudaInstallationDetector CudaInstallation;
- RocmInstallationDetector RocmInstallation;
+ LazyDetector<CudaInstallationDetector> CudaInstallation;
+ LazyDetector<RocmInstallationDetector> RocmInstallation;
public:
Generic_GCC(const Driver &D, const llvm::Triple &Triple,
@@ -296,7 +296,8 @@ public:
void printVerboseInfo(raw_ostream &OS) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp
index 6d553791b394..ccb36a6c846c 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp
@@ -21,7 +21,7 @@
#include "llvm/Support/Alignment.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/TargetParser.h"
+#include "llvm/TargetParser/TargetParser.h"
using namespace clang::driver;
using namespace clang::driver::toolchains;
@@ -47,7 +47,7 @@ static bool shouldSkipSanitizeOption(const ToolChain &TC,
return false;
if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
- -options::OPT_fno_gpu_sanitize))
+ options::OPT_fno_gpu_sanitize, true))
return true;
auto &Diags = TC.getDriver().getDiags();
@@ -72,14 +72,49 @@ static bool shouldSkipSanitizeOption(const ToolChain &TC,
return false;
}
+void AMDGCN::Linker::constructLlvmLinkCommand(Compilation &C,
+ const JobAction &JA,
+ const InputInfoList &Inputs,
+ const InputInfo &Output,
+ const llvm::opt::ArgList &Args) const {
+ // Construct llvm-link command.
+ // The output from llvm-link is a bitcode file.
+ ArgStringList LlvmLinkArgs;
+
+ assert(!Inputs.empty() && "Must have at least one input.");
+
+ LlvmLinkArgs.append({"-o", Output.getFilename()});
+ for (auto Input : Inputs)
+ LlvmLinkArgs.push_back(Input.getFilename());
+
+ // Look for archive of bundled bitcode in arguments, and add temporary files
+ // for the extracted archive of bitcode to inputs.
+ auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ);
+ AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LlvmLinkArgs, "amdgcn",
+ TargetID, /*IsBitCodeSDL=*/true);
+
+ const char *LlvmLink =
+ Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
+ C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+ LlvmLink, LlvmLinkArgs, Inputs,
+ Output));
+}
+
void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const InputInfo &Output,
const llvm::opt::ArgList &Args) const {
// Construct lld command.
// The output from ld.lld is an HSA code object file.
- ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared",
+ ArgStringList LldArgs{"-flavor",
+ "gnu",
+ "-m",
+ "elf64_amdgpu",
+ "--no-undefined",
+ "-shared",
"-plugin-opt=-amdgpu-internalize-symbols"};
+ if (Args.hasArg(options::OPT_hipstdpar))
+ LldArgs.push_back("-plugin-opt=-amdgpu-enable-hipstdpar");
auto &TC = getToolChain();
auto &D = TC.getDriver();
@@ -107,27 +142,55 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
if (IsThinLTO)
LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all"));
- for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
- LldArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0)));
- }
-
if (C.getDriver().isSaveTempsEnabled())
LldArgs.push_back("-save-temps");
addLinkerCompressDebugSectionsOption(TC, Args, LldArgs);
+ // Given that host and device linking happen in separate processes, the device
+ // linker doesn't always have the visibility as to which device symbols are
+ // needed by a program, especially for the device symbol dependencies that are
+ // introduced through the host symbol resolution.
+ // For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B()
+ // (B.obj) In this case, the device linker doesn't know that A.obj actually
+ // depends on the kernel functions in B.obj. When linking to static device
+ // library, the device linker may drop some of the device global symbols if
+ // they aren't referenced. As a workaround, we are adding to the
+ // --whole-archive flag such that all global symbols would be linked in.
+ LldArgs.push_back("--whole-archive");
+
+ for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) {
+ StringRef ArgVal = Arg->getValue(1);
+ auto SplitArg = ArgVal.split("-mllvm=");
+ if (!SplitArg.second.empty()) {
+ LldArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=") + SplitArg.second));
+ } else {
+ LldArgs.push_back(Args.MakeArgString(ArgVal));
+ }
+ Arg->claim();
+ }
+
LldArgs.append({"-o", Output.getFilename()});
for (auto Input : Inputs)
LldArgs.push_back(Input.getFilename());
+ // Look for archive of bundled bitcode in arguments, and add temporary files
+ // for the extracted archive of bitcode to inputs.
+ auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ);
+ AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LldArgs, "amdgcn",
+ TargetID, /*IsBitCodeSDL=*/true);
+
+ LldArgs.push_back("--no-whole-archive");
+
const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Lld, LldArgs, Inputs, Output));
}
// For amdgcn the inputs of the linker job are device bitcode and output is
-// object file. It calls llvm-link, opt, llc, then lld steps.
+// either an object file or bitcode (-emit-llvm). It calls llvm-link, opt,
+// llc, then lld steps.
void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -143,6 +206,9 @@ void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs,
Args, *this);
+ if (JA.getType() == types::TY_LLVM_BC)
+ return constructLlvmLinkCommand(C, JA, Inputs, Output, Args);
+
return constructLldCommand(C, JA, Inputs, Output, Args);
}
@@ -154,7 +220,10 @@ HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple,
getProgramPaths().push_back(getDriver().Dir);
// Diagnose unsupported sanitizer options only once.
- for (auto A : Args.filtered(options::OPT_fsanitize_EQ)) {
+ if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
+ true))
+ return;
+ for (auto *A : Args.filtered(options::OPT_fsanitize_EQ)) {
SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false);
if (K != SanitizerKind::Address)
D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target)
@@ -172,19 +241,17 @@ void HIPAMDToolChain::addClangTargetOptions(
CC1Args.push_back("-fcuda-is-device");
- if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
- options::OPT_fno_cuda_approx_transcendentals, false))
- CC1Args.push_back("-fcuda-approx-transcendentals");
-
if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
false))
CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"});
+ if (DriverArgs.hasArgNoClaim(options::OPT_hipstdpar))
+ CC1Args.append({"-mllvm", "-amdgpu-enable-hipstdpar"});
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();
+ (Twine("--gpu-max-threads-per-block=") + MaxThreadsPerBlock).str();
CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr));
}
@@ -194,15 +261,15 @@ void HIPAMDToolChain::addClangTargetOptions(
// supported for the foreseeable future.
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
- CC1Args.append({"-fvisibility", "hidden"});
+ CC1Args.append({"-fvisibility=hidden"});
CC1Args.push_back("-fapply-global-visibility-to-externs");
}
- llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) {
+ for (auto BCFile : getDeviceLibs(DriverArgs)) {
CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
: "-mlink-bitcode-file");
CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
- });
+ }
}
llvm::opt::DerivedArgList *
@@ -217,8 +284,7 @@ HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
const OptTable &Opts = getDriver().getOpts();
for (Arg *A : Args) {
- if (!shouldSkipArgument(A) &&
- !shouldSkipSanitizeOption(*this, Args, BoundArch, A))
+ if (!shouldSkipSanitizeOption(*this, Args, BoundArch, A))
DAL->append(A);
}
@@ -262,7 +328,7 @@ void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+ RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const {
@@ -284,14 +350,14 @@ VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D,
}
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
-HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
+HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;
if (DriverArgs.hasArg(options::OPT_nogpulib))
return {};
ArgStringList LibraryPaths;
// Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
- for (auto Path : RocmInstallation.getRocmDeviceLibPathArg())
+ for (StringRef Path : RocmInstallation->getRocmDeviceLibPathArg())
LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
@@ -301,7 +367,7 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
if (!BCLibArgs.empty()) {
llvm::for_each(BCLibArgs, [&](StringRef BCName) {
StringRef FullName;
- for (std::string LibraryPath : LibraryPaths) {
+ for (StringRef LibraryPath : LibraryPaths) {
SmallString<128> Path(LibraryPath);
llvm::sys::path::append(Path, BCName);
FullName = Path;
@@ -313,7 +379,7 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
getDriver().Diag(diag::err_drv_no_such_file) << BCName;
});
} else {
- if (!RocmInstallation.hasDeviceLibrary()) {
+ if (!RocmInstallation->hasDeviceLibrary()) {
getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
return {};
}
@@ -322,9 +388,9 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
// If --hip-device-lib is not set, add the default bitcode libraries.
if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
- options::OPT_fno_gpu_sanitize) &&
+ options::OPT_fno_gpu_sanitize, true) &&
getSanitizerArgs(DriverArgs).needsAsanRt()) {
- auto AsanRTL = RocmInstallation.getAsanRTLPath();
+ auto AsanRTL = RocmInstallation->getAsanRTLPath();
if (AsanRTL.empty()) {
unsigned DiagID = getDriver().getDiags().getCustomDiagID(
DiagnosticsEngine::Error,
@@ -334,15 +400,15 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
getDriver().Diag(DiagID);
return {};
} else
- BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false});
+ BCLibs.emplace_back(AsanRTL, /*ShouldInternalize=*/false);
}
// Add the HIP specific bitcode library.
- BCLibs.push_back(RocmInstallation.getHIPPath());
+ BCLibs.push_back(RocmInstallation->getHIPPath());
// Add common device libraries like ocml etc.
- for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str()))
- BCLibs.push_back(StringRef(N));
+ for (StringRef N : getCommonDeviceLibNames(DriverArgs, GpuArch.str()))
+ BCLibs.emplace_back(N);
// Add instrument lib.
auto InstLib =
@@ -363,6 +429,6 @@ void HIPAMDToolChain::checkTargetID(
auto PTID = getParsedTargetID(DriverArgs);
if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {
getDriver().Diag(clang::diag::err_drv_bad_target_id)
- << PTID.OptionalTargetID.getValue();
+ << *PTID.OptionalTargetID;
}
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h
index cc472a595db9..d81a9733014c 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h
@@ -21,7 +21,7 @@ namespace tools {
namespace AMDGCN {
// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with
// device library, then compiles it to ISA in a shared object.
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("AMDGCN::Linker", "amdgcn-link", TC) {}
@@ -36,6 +36,10 @@ private:
void constructLldCommand(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs, const InputInfo &Output,
const llvm::opt::ArgList &Args) const;
+ void constructLlvmLinkCommand(Compilation &C, const JobAction &JA,
+ const InputInfoList &Inputs,
+ const InputInfo &Output,
+ const llvm::opt::ArgList &Args) const;
};
} // end namespace AMDGCN
@@ -72,7 +76,7 @@ public:
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
llvm::SmallVector<BitCodeLibraryInfo, 12>
- getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override;
+ getDeviceLibs(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp
index d68c87e9b3e7..a144b28057f4 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp
@@ -143,18 +143,14 @@ void HIPSPVToolChain::addClangTargetOptions(
// TODO: Allow autovectorization when SPIR-V backend arrives.
"-mllvm", "-vectorize-loops=false", "-mllvm", "-vectorize-slp=false"});
- if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
- options::OPT_fno_cuda_approx_transcendentals, false))
- CC1Args.push_back("-fcuda-approx-transcendentals");
-
// Default to "hidden" visibility, as object level linking will not be
// supported for the foreseeable future.
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat))
CC1Args.append(
- {"-fvisibility", "hidden", "-fapply-global-visibility-to-externs"});
+ {"-fvisibility=hidden", "-fapply-global-visibility-to-externs"});
- llvm::for_each(getHIPDeviceLibs(DriverArgs),
+ llvm::for_each(getDeviceLibs(DriverArgs),
[&](const BitCodeLibraryInfo &BCFile) {
CC1Args.append({"-mlink-builtin-bitcode",
DriverArgs.MakeArgString(BCFile.Path)});
@@ -206,7 +202,7 @@ void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
}
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
-HIPSPVToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
+HIPSPVToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs;
if (DriverArgs.hasArg(options::OPT_nogpulib))
return {};
@@ -283,10 +279,10 @@ VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D,
}
void HIPSPVToolChain::adjustDebugInfoKind(
- codegenoptions::DebugInfoKind &DebugInfoKind,
+ llvm::codegenoptions::DebugInfoKind &DebugInfoKind,
const llvm::opt::ArgList &Args) const {
// Debug info generation is disabled for SPIRV-LLVM-Translator
// which currently aborts on the presence of DW_OP_LLVM_convert.
// TODO: Enable debug info when the SPIR-V backend arrives.
- DebugInfoKind = codegenoptions::NoDebugInfo;
+ DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h
index 79520f77c742..ecd82e7052e4 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h
@@ -20,7 +20,7 @@ namespace HIPSPV {
// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with
// device library, then compiles it to SPIR-V in a shared object.
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("HIPSPV::Linker", "hipspv-link", TC) {}
@@ -69,7 +69,7 @@ public:
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
llvm::SmallVector<BitCodeLibraryInfo, 12>
- getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override;
+ getDeviceLibs(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
@@ -77,9 +77,8 @@ public:
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
- void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind,
+ void adjustDebugInfoKind(llvm::codegenoptions::DebugInfoKind &DebugInfoKind,
const llvm::opt::ArgList &Args) const override;
- bool IsIntegratedAssemblerDefault() const override { return true; }
bool IsMathErrnoDefault() const override { return false; }
bool useIntegratedAs() const override { return true; }
bool isCrossCompiling() const override { return true; }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp
index 1b04a20bacbf..f692458b775d 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp
@@ -10,8 +10,8 @@
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Support/Path.h"
+#include "llvm/TargetParser/Triple.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -53,8 +53,6 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
// ToDo: Remove the dummy host binary entry which is required by
// clang-offload-bundler.
std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux";
- std::string BundlerInputArg = "-inputs=" NULL_FILE;
-
// AMDGCN:
// For code object version 2 and 3, the offload kind in bundle ID is 'hip'
// for backward compatibility. For code object version 4 and greater, the
@@ -70,16 +68,28 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
"," + OffloadKind + "-" + normalizeForBundler(TT, !ArchStr.empty());
if (!ArchStr.empty())
BundlerTargetArg += "-" + ArchStr.str();
- BundlerInputArg = BundlerInputArg + "," + II.getFilename();
}
BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg));
+
+ // Use a NULL file as input for the dummy host binary entry
+ std::string BundlerInputArg = "-input=" NULL_FILE;
BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
+ for (const auto &II : Inputs) {
+ BundlerInputArg = std::string("-input=") + II.getFilename();
+ BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
+ }
std::string Output = std::string(OutputFileName);
auto *BundlerOutputArg =
- Args.MakeArgString(std::string("-outputs=").append(Output));
+ Args.MakeArgString(std::string("-output=").append(Output));
BundlerArgs.push_back(BundlerOutputArg);
+ if (Args.hasFlag(options::OPT_offload_compress,
+ options::OPT_no_offload_compress, false))
+ BundlerArgs.push_back("-compress");
+ if (Args.hasArg(options::OPT_v))
+ BundlerArgs.push_back("-verbose");
+
const char *Bundler = Args.MakeArgString(
T.getToolChain().GetProgramPath("clang-offload-bundler"));
C.addCommand(std::make_unique<Command>(
@@ -140,6 +150,8 @@ void HIP::constructGenerateObjFileFromHIPFatBinary(
ObjStream << " .incbin ";
llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true);
ObjStream << "\n";
+ if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF())
+ ObjStream << " .section .note.GNU-stack, \"\", @progbits\n";
ObjStream.flush();
// Dump the contents of the temp object file gen if the user requested that.
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp
new file mode 100644
index 000000000000..c6ad862b2294
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp
@@ -0,0 +1,259 @@
+//===--- HLSL.cpp - HLSL 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 "HLSL.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Job.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/TargetParser/Triple.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+using namespace llvm;
+
+namespace {
+
+const unsigned OfflineLibMinor = 0xF;
+
+bool isLegalShaderModel(Triple &T) {
+ if (T.getOS() != Triple::OSType::ShaderModel)
+ return false;
+
+ auto Version = T.getOSVersion();
+ if (Version.getBuild())
+ return false;
+ if (Version.getSubminor())
+ return false;
+
+ auto Kind = T.getEnvironment();
+
+ switch (Kind) {
+ default:
+ return false;
+ case Triple::EnvironmentType::Vertex:
+ case Triple::EnvironmentType::Hull:
+ case Triple::EnvironmentType::Domain:
+ case Triple::EnvironmentType::Geometry:
+ case Triple::EnvironmentType::Pixel:
+ case Triple::EnvironmentType::Compute: {
+ VersionTuple MinVer(4, 0);
+ return MinVer <= Version;
+ } break;
+ case Triple::EnvironmentType::Library: {
+ VersionTuple SM6x(6, OfflineLibMinor);
+ if (Version == SM6x)
+ return true;
+
+ VersionTuple MinVer(6, 3);
+ return MinVer <= Version;
+ } break;
+ case Triple::EnvironmentType::Amplification:
+ case Triple::EnvironmentType::Mesh: {
+ VersionTuple MinVer(6, 5);
+ return MinVer <= Version;
+ } break;
+ }
+ return false;
+}
+
+std::optional<std::string> tryParseProfile(StringRef Profile) {
+ // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
+ SmallVector<StringRef, 3> Parts;
+ Profile.split(Parts, "_");
+ if (Parts.size() != 3)
+ return std::nullopt;
+
+ Triple::EnvironmentType Kind =
+ StringSwitch<Triple::EnvironmentType>(Parts[0])
+ .Case("ps", Triple::EnvironmentType::Pixel)
+ .Case("vs", Triple::EnvironmentType::Vertex)
+ .Case("gs", Triple::EnvironmentType::Geometry)
+ .Case("hs", Triple::EnvironmentType::Hull)
+ .Case("ds", Triple::EnvironmentType::Domain)
+ .Case("cs", Triple::EnvironmentType::Compute)
+ .Case("lib", Triple::EnvironmentType::Library)
+ .Case("ms", Triple::EnvironmentType::Mesh)
+ .Case("as", Triple::EnvironmentType::Amplification)
+ .Default(Triple::EnvironmentType::UnknownEnvironment);
+ if (Kind == Triple::EnvironmentType::UnknownEnvironment)
+ return std::nullopt;
+
+ unsigned long long Major = 0;
+ if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
+ return std::nullopt;
+
+ unsigned long long Minor = 0;
+ if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library)
+ Minor = OfflineLibMinor;
+ else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
+ return std::nullopt;
+
+ // dxil-unknown-shadermodel-hull
+ llvm::Triple T;
+ T.setArch(Triple::ArchType::dxil);
+ T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() +
+ VersionTuple(Major, Minor).getAsString());
+ T.setEnvironment(Kind);
+ if (isLegalShaderModel(T))
+ return T.getTriple();
+ else
+ return std::nullopt;
+}
+
+bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
+ VersionTuple Version;
+ if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
+ Version.getSubminor() || !Version.getMinor()) {
+ D.Diag(diag::err_drv_invalid_format_dxil_validator_version)
+ << ValVersionStr;
+ return false;
+ }
+
+ uint64_t Major = Version.getMajor();
+ uint64_t Minor = *Version.getMinor();
+ if (Major == 0 && Minor != 0) {
+ D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr;
+ return false;
+ }
+ VersionTuple MinVer(1, 0);
+ if (Version < MinVer) {
+ D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr;
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ std::string DxvPath = getToolChain().GetProgramPath("dxv");
+ assert(DxvPath != "dxv" && "cannot find dxv");
+
+ ArgStringList CmdArgs;
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Unexpected verify input");
+ // Grabbing the output of the earlier cc1 run.
+ CmdArgs.push_back(Input.getFilename());
+ // Use the same name as output.
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec = Args.MakeArgString(DxvPath);
+ C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+ Exec, CmdArgs, Inputs, Input));
+}
+
+/// DirectX Toolchain
+HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ if (Args.hasArg(options::OPT_dxc_validator_path_EQ))
+ getProgramPaths().push_back(
+ Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str());
+}
+
+Tool *clang::driver::toolchains::HLSLToolChain::getTool(
+ Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::BinaryAnalyzeJobClass:
+ if (!Validator)
+ Validator.reset(new tools::hlsl::Validator(*this));
+ return Validator.get();
+ default:
+ return ToolChain::getTool(AC);
+ }
+}
+
+std::optional<std::string>
+clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
+ StringRef TargetProfile) {
+ return tryParseProfile(TargetProfile);
+}
+
+DerivedArgList *
+HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+ DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
+
+ const OptTable &Opts = getDriver().getOpts();
+
+ for (Arg *A : Args) {
+ if (A->getOption().getID() == options::OPT_dxil_validator_version) {
+ StringRef ValVerStr = A->getValue();
+ std::string ErrorMsg;
+ if (!isLegalValidatorVersion(ValVerStr, getDriver()))
+ continue;
+ }
+ if (A->getOption().getID() == options::OPT_dxc_entrypoint) {
+ DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint),
+ A->getValue());
+ A->claim();
+ continue;
+ }
+ if (A->getOption().getID() == options::OPT__SLASH_O) {
+ StringRef OStr = A->getValue();
+ if (OStr == "d") {
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0));
+ A->claim();
+ continue;
+ } else {
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr);
+ A->claim();
+ continue;
+ }
+ }
+ if (A->getOption().getID() == options::OPT_emit_pristine_llvm) {
+ // Translate fcgl into -S -emit-llvm and -disable-llvm-passes.
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm));
+ DAL->AddFlagArg(nullptr,
+ Opts.getOption(options::OPT_disable_llvm_passes));
+ A->claim();
+ continue;
+ }
+ DAL->append(A);
+ }
+
+ // Add default validator version if not set.
+ // TODO: remove this once read validator version from validator.
+ if (!DAL->hasArg(options::OPT_dxil_validator_version)) {
+ const StringRef DefaultValidatorVer = "1.7";
+ DAL->AddSeparateArg(nullptr,
+ Opts.getOption(options::OPT_dxil_validator_version),
+ DefaultValidatorVer);
+ }
+ if (!DAL->hasArg(options::OPT_O_Group)) {
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3");
+ }
+ // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and
+ // shader model 6.2.
+ // See: https://github.com/llvm/llvm-project/issues/57876
+ return DAL;
+}
+
+bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const {
+ if (Args.getLastArg(options::OPT_dxc_disable_validation))
+ return false;
+
+ std::string DxvPath = GetProgramPath("dxv");
+ if (DxvPath != "dxv")
+ return true;
+
+ getDriver().Diag(diag::warn_drv_dxc_missing_dxv);
+ return false;
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h
new file mode 100644
index 000000000000..7b775b897431
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h
@@ -0,0 +1,63 @@
+//===--- HLSL.h - HLSL 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_HLSL_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+
+namespace tools {
+
+namespace hlsl {
+class LLVM_LIBRARY_VISIBILITY Validator : public Tool {
+public:
+ Validator(const ToolChain &TC) : Tool("hlsl::Validator", "dxv", 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;
+};
+} // namespace hlsl
+} // namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain {
+public:
+ HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ Tool *getTool(Action::ActionClass AC) const override;
+
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
+ return false;
+ }
+ bool isPICDefaultForced() const override { return false; }
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ static std::optional<std::string> parseTargetProfile(StringRef TargetProfile);
+ bool requiresValidation(llvm::opt::DerivedArgList &Args) const;
+
+private:
+ mutable std::unique_ptr<tools::hlsl::Validator> Validator;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp
index a79f0f7622ad..e0d94035823f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp
@@ -8,27 +8,272 @@
#include "Haiku.h"
#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "llvm/Support/Path.h"
using namespace clang::driver;
+using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
+void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &ToolChain = static_cast<const Haiku &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool Static = Args.hasArg(options::OPT_static);
+ const bool Shared = Args.hasArg(options::OPT_shared);
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ // Silence warning for "clang -pie foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_pie);
+
+ // -rdynamic is a no-op with Haiku. Claim argument to avoid warning.
+ Args.ClaimAllArgs(options::OPT_rdynamic);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Static) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Shared)
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("--enable-new-dtags");
+ }
+
+ CmdArgs.push_back("-shared");
+
+ if (!Shared)
+ CmdArgs.push_back("--no-undefined");
+
+ if (Arch == llvm::Triple::riscv64)
+ CmdArgs.push_back("-X");
+
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
+ if (!Shared)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("start_dyn.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("init_term_dyn.o")));
+ }
+
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_s, options::OPT_t, options::OPT_r});
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
+ D.getLTOMode() == LTOK_Thin);
+ }
+
+ addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+ options::OPT_r)) {
+ // Use the static OpenMP runtime with -static-openmp
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
+ addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
+
+ if (D.CCCIsCXX() && ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below (i.e.
+ // AddRunTimeLibs).
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
+ }
+
+ CmdArgs.push_back("-lgcc");
+
+ CmdArgs.push_back("--push-state");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ CmdArgs.push_back("--pop-state");
+
+ CmdArgs.push_back("-lroot");
+
+ CmdArgs.push_back("-lgcc");
+
+ CmdArgs.push_back("--push-state");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ CmdArgs.push_back("--pop-state");
+ }
+
+ // No need to do anything for pthreads. Claim argument to avoid warning.
+ Args.claimAllArgs(options::OPT_pthread, options::OPT_pthreads);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+
+ ToolChain.addProfileRTLibs(Args, CmdArgs);
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::AtFileCurCP(),
+ Exec, CmdArgs, Inputs, Output));
+}
+
/// Haiku - Haiku tool chain which can call as(1) and ld(1) directly.
Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(Triple, Args);
+
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib"));
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib"));
+
+ if (GCCInstallation.isValid())
+ getFilePaths().push_back(GCCInstallation.getInstallPath().str());
+}
+
+void Haiku::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Add dirs specified via 'configure --with-c-include-dirs'.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (!CIncludeDirs.empty()) {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/non-packaged/develop/headers"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/app"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/device"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/drivers"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/game"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/interface"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/kernel"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/locale"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/mail"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/media"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/midi"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/midi2"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/net"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/opengl"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/storage"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/support"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/translation"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/add-ons/graphics"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/add-ons/input_server"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/add-ons/mail_daemon"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/add-ons/registrar"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/add-ons/screen_saver"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/add-ons/tracker"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/be_apps/Deskbar"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/be_apps/NetPositive"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/os/be_apps/Tracker"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/3rdparty"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/bsd"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/glibc"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/gnu"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers/posix"));
+ addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot,
+ "/boot/system/develop/headers"));
}
void Haiku::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/system/develop/headers/c++/v1");
+ concat(getDriver().SysRoot, "/boot/system/develop/headers/c++/v1"));
}
-void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- addLibStdCXXIncludePaths(getDriver().SysRoot + "/system/develop/headers/c++",
- getTriple().str(), "", DriverArgs, CC1Args);
-}
+Tool *Haiku::buildLinker() const { return new tools::haiku::Linker(*this); }
+
+bool Haiku::HasNativeLLVMSupport() const { return true; }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h
index 669379a21605..a34f76e22284 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h
@@ -15,6 +15,25 @@
namespace clang {
namespace driver {
+namespace tools {
+
+/// Directly call GNU Binutils assembler and linker
+namespace haiku {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("haiku::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 haiku
+} // end namespace tools
+
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
@@ -22,16 +41,27 @@ public:
Haiku(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
- return getTriple().getArch() == llvm::Triple::x86_64;
- }
+ bool HasNativeLLVMSupport() const override;
- void addLibCxxIncludePaths(
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+ bool isPICDefault() const override { return true; }
+
+ const char *getDefaultLinker() const override { return "ld.lld"; }
+
+ void AddClangSystemIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- void addLibStdCxxIncludePaths(
+ void addLibCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
+
+ bool GetDefaultStandaloneDebug() const override { return true; }
+
+protected:
+ Tool *buildLinker() const override;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp
index e772122f5ff5..d1eed931be5f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -40,7 +40,7 @@ static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
StringRef Val = A->getValue();
if (!Val.equals_insensitive("64b") && !Val.equals_insensitive("128b"))
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
}
@@ -54,11 +54,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef {
const std::string &S = T.str();
StringRef Opt(S);
- if (Opt.endswith("="))
+ if (Opt.ends_with("="))
Opt = Opt.drop_back(1);
- if (Opt.startswith("mno-"))
+ if (Opt.starts_with("mno-"))
Opt = Opt.drop_front(4);
- else if (Opt.startswith("m"))
+ else if (Opt.starts_with("m"))
Opt = Opt.drop_front(1);
return Args.MakeArgString(Twine(Enable ? "+" : "-") + Twine(Opt));
};
@@ -120,16 +120,17 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
HvxVerNum = 0;
// Handle HVX floating point flags.
- auto checkFlagHvxVersion = [&](auto FlagOn, auto FlagOff,
- unsigned MinVerNum) -> Optional<StringRef> {
- // Return an Optional<StringRef>:
- // - None indicates a verification failure, or that the flag was not
+ auto checkFlagHvxVersion =
+ [&](auto FlagOn, auto FlagOff,
+ unsigned MinVerNum) -> std::optional<StringRef> {
+ // Return an std::optional<StringRef>:
+ // - std::nullopt indicates a verification failure, or that the flag was not
// present in Args.
// - Otherwise the returned value is that name of the feature to add
// to Features.
Arg *A = Args.getLastArg(FlagOn, FlagOff);
if (!A)
- return None;
+ return std::nullopt;
StringRef OptName = A->getOption().getName();
if (A->getOption().matches(FlagOff))
@@ -137,12 +138,12 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
if (!HasHVX) {
D.Diag(diag::err_drv_needs_hvx) << withMinus(OptName);
- return None;
+ return std::nullopt;
}
if (HvxVerNum < MinVerNum) {
D.Diag(diag::err_drv_needs_hvx_version)
<< withMinus(OptName) << ("v" + std::to_string(HvxVerNum));
- return None;
+ return std::nullopt;
}
return makeFeature(OptName, true);
};
@@ -158,9 +159,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
}
// Hexagon target features.
-void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args,
+void hexagon::getHexagonTargetFeatures(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
std::vector<StringRef> &Features) {
- handleTargetFeaturesGroup(Args, Features,
+ handleTargetFeaturesGroup(D, Triple, Args, Features,
options::OPT_m_hexagon_Features_Group);
bool UseLongCalls = false;
@@ -215,11 +218,11 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
addSanitizerRuntimes(HTC, Args, CmdArgs);
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
- assert(Output.isNothing() && "Unexpected output");
CmdArgs.push_back("-fsyntax-only");
}
@@ -230,7 +233,7 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
}
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue())));
+ CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(*G)));
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
@@ -340,8 +343,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-pie");
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
- UseG0 = G.getValue() == 0;
+ CmdArgs.push_back(Args.MakeArgString("-G" + Twine(*G)));
+ UseG0 = *G == 0;
}
CmdArgs.push_back("-o");
@@ -360,27 +363,31 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
CmdArgs.push_back(
Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib"));
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_u_Group});
+ Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_u_Group});
AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (NeedsSanitizerDeps) {
- linkSanitizerRuntimeDeps(HTC, CmdArgs);
+ linkSanitizerRuntimeDeps(HTC, Args, CmdArgs);
CmdArgs.push_back("-lunwind");
}
if (NeedsXRayDeps)
- linkXRayRuntimeDeps(HTC, CmdArgs);
+ linkXRayRuntimeDeps(HTC, Args, CmdArgs);
CmdArgs.push_back("-lclang_rt.builtins-hexagon");
- CmdArgs.push_back("-lc");
+ if (!Args.hasArg(options::OPT_nolibc))
+ CmdArgs.push_back("-lc");
}
if (D.CCCIsCXX()) {
if (HTC.ShouldLinkCXXStdlib(Args))
HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
}
+ const ToolChain::path_list &LibPaths = HTC.getFilePaths();
+ for (const auto &LibPath : LibPaths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+ Args.ClaimAllArgs(options::OPT_L);
return;
}
@@ -439,13 +446,13 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
const ToolChain::path_list &LibPaths = HTC.getFilePaths();
for (const auto &LibPath : LibPaths)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+ Args.ClaimAllArgs(options::OPT_L);
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_u_Group});
+ Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_u_Group});
AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
@@ -464,7 +471,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
if (!IsShared) {
for (StringRef Lib : OsLibs)
CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
- CmdArgs.push_back("-lc");
+ if (!Args.hasArg(options::OPT_nolibc))
+ CmdArgs.push_back("-lc");
}
CmdArgs.push_back("-lgcc");
@@ -519,8 +527,8 @@ std::string HexagonToolChain::getHexagonTargetDir(
return InstalledDir;
}
-Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
- const ArgList &Args) {
+std::optional<unsigned>
+HexagonToolChain::getSmallDataThreshold(const ArgList &Args) {
StringRef Gn = "";
if (Arg *A = Args.getLastArg(options::OPT_G)) {
Gn = A->getValue();
@@ -533,14 +541,16 @@ Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
if (!Gn.getAsInteger(10, G))
return G;
- return None;
+ return std::nullopt;
}
std::string HexagonToolChain::getCompilerRTPath() const {
SmallString<128> Dir(getDriver().SysRoot);
llvm::sys::path::append(Dir, "usr", "lib");
- Dir += SelectedMultilib.gccSuffix();
- return std::string(Dir.str());
+ if (!SelectedMultilibs.empty()) {
+ Dir += SelectedMultilibs.back().gccSuffix();
+ }
+ return std::string(Dir);
}
void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
@@ -551,8 +561,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
// -L Args
//----------------------------------------------------------------------------
for (Arg *A : Args.filtered(options::OPT_L))
- for (const char *Value : A->getValues())
- LibPaths.push_back(Value);
+ llvm::append_range(LibPaths, A->getValues());
//----------------------------------------------------------------------------
// Other standard paths
@@ -570,7 +579,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
// Assume G0 with -shared.
bool HasG0 = Args.hasArg(options::OPT_shared);
if (auto G = getSmallDataThreshold(Args))
- HasG0 = G.getValue() == 0;
+ HasG0 = *G == 0;
const std::string CpuVer = GetTargetCPUVersion(Args).str();
for (auto &Dir : RootDirs) {
@@ -615,6 +624,8 @@ void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
CmdArgs.push_back("-lunwind");
break;
@@ -790,7 +801,7 @@ StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
CpuArg = A;
StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
- if (CPU.startswith("hexagon"))
+ if (CPU.starts_with("hexagon"))
return CPU.substr(sizeof("hexagon") - 1);
return CPU;
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h
index 899630555352..e35a224dced4 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h
@@ -20,7 +20,7 @@ namespace hexagon {
// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile
// and Compile.
// We simply use "clang -cc1" for those actions.
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC)
: Tool("hexagon::Assembler", "hexagon-as", TC) {}
@@ -35,7 +35,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("hexagon::Linker", "hexagon-ld", TC) {}
@@ -50,7 +50,8 @@ public:
const char *LinkingOutput) const override;
};
-void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
+void getHexagonTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
std::vector<StringRef> &Features);
} // end namespace hexagon.
@@ -94,9 +95,6 @@ public:
llvm::opt::ArgStringList &CmdArgs) const override;
StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
- bool IsIntegratedAssemblerDefault() const override {
- return true;
- }
std::string getHexagonTargetDir(
const std::string &InstalledDir,
@@ -110,8 +108,8 @@ public:
static StringRef GetDefaultCPU();
static StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args);
- static Optional<unsigned> getSmallDataThreshold(
- const llvm::opt::ArgList &Args);
+ static std::optional<unsigned>
+ getSmallDataThreshold(const llvm::opt::ArgList &Args);
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp
index 48b9ccadf36f..0bc114b90ffc 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp
@@ -30,13 +30,21 @@ using tools::addPathIfExists;
std::string Hurd::getMultiarchTriple(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef SysRoot) const {
- if (TargetTriple.getArch() == llvm::Triple::x86) {
+ switch (TargetTriple.getArch()) {
+ default:
+ break;
+
+ case llvm::Triple::x86:
// We use the existence of '/lib/<triple>' as a directory to detect some
// common hurd triples that don't quite match the Clang triple for both
// 32-bit and 64-bit targets. Multiarch fixes its install triples to these
// regardless of what the actual target triple is.
if (D.getVFS().exists(SysRoot + "/lib/i386-gnu"))
return "i386-gnu";
+ break;
+
+ case llvm::Triple::x86_64:
+ return "x86_64-gnu";
}
// For most architectures, just use whatever we have rather than trying to be
@@ -65,7 +73,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
Multilibs = GCCInstallation.getMultilibs();
- SelectedMultilib = GCCInstallation.getMultilib();
+ SelectedMultilibs.assign({GCCInstallation.getMultilib()});
std::string SysRoot = computeSysRoot();
ToolChain::path_list &PPaths = getProgramPaths();
@@ -92,7 +100,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// those searched.
// FIXME: It's not clear whether we should use the driver's installed
// directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot)) {
+ if (StringRef(D.Dir).starts_with(SysRoot)) {
addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths);
addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
}
@@ -110,7 +118,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// searched.
// FIXME: It's not clear whether we should use the driver's installed
// directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot))
+ if (StringRef(D.Dir).starts_with(SysRoot))
addPathIfExists(D, D.Dir + "/../lib", Paths);
addPathIfExists(D, SysRoot + "/lib", Paths);
@@ -126,8 +134,14 @@ Tool *Hurd::buildAssembler() const {
}
std::string Hurd::getDynamicLinker(const ArgList &Args) const {
- if (getArch() == llvm::Triple::x86)
+ switch (getArch()) {
+ case llvm::Triple::x86:
return "/lib/ld.so";
+ case llvm::Triple::x86_64:
+ return "/lib/ld-x86-64.so.1";
+ default:
+ break;
+ }
llvm_unreachable("unsupported architecture");
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h
index dc04b0cfe2ee..33701f7cc045 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h
@@ -29,8 +29,6 @@ public:
void addLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override {}
-
- bool IsIntegratedAssemblerDefault() const override { return true; }
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h
new file mode 100644
index 000000000000..813d00a87bb8
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h
@@ -0,0 +1,45 @@
+//===--- LazyDetector.h - Lazy ToolChain Detection --------------*- 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_LAZYDETECTOR_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+#include <optional>
+
+namespace clang {
+
+/// Simple wrapper for toolchain detector with costly initialization. This
+/// delays the creation of the actual detector until its first usage.
+
+template <class T> class LazyDetector {
+ const driver::Driver &D;
+ llvm::Triple Triple;
+ const llvm::opt::ArgList &Args;
+
+ std::optional<T> Detector;
+
+public:
+ LazyDetector(const driver::Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : D(D), Triple(Triple), Args(Args) {}
+ T *operator->() {
+ if (!Detector)
+ Detector.emplace(D, Triple, Args);
+ return &*Detector;
+ }
+ const T *operator->() const {
+ return const_cast<T const *>(
+ const_cast<LazyDetector &>(*this).operator->());
+ }
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp
index f85c04df4f6c..4300a2bdff17 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp
@@ -8,6 +8,7 @@
#include "Linux.h"
#include "Arch/ARM.h"
+#include "Arch/LoongArch.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
#include "Arch/RISCV.h"
@@ -60,12 +61,16 @@ std::string Linux::getMultiarchTriple(const Driver &D,
case llvm::Triple::thumb:
if (IsAndroid)
return "arm-linux-androideabi";
- if (TargetEnvironment == llvm::Triple::GNUEABIHF)
+ if (TargetEnvironment == llvm::Triple::GNUEABIHF ||
+ TargetEnvironment == llvm::Triple::MuslEABIHF ||
+ TargetEnvironment == llvm::Triple::EABIHF)
return "arm-linux-gnueabihf";
return "arm-linux-gnueabi";
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
- if (TargetEnvironment == llvm::Triple::GNUEABIHF)
+ if (TargetEnvironment == llvm::Triple::GNUEABIHF ||
+ TargetEnvironment == llvm::Triple::MuslEABIHF ||
+ TargetEnvironment == llvm::Triple::EABIHF)
return "armeb-linux-gnueabihf";
return "armeb-linux-gnueabi";
case llvm::Triple::x86:
@@ -85,37 +90,66 @@ std::string Linux::getMultiarchTriple(const Driver &D,
case llvm::Triple::aarch64_be:
return "aarch64_be-linux-gnu";
+ case llvm::Triple::loongarch64: {
+ const char *Libc;
+ const char *FPFlavor;
+
+ if (TargetTriple.isGNUEnvironment()) {
+ Libc = "gnu";
+ } else if (TargetTriple.isMusl()) {
+ Libc = "musl";
+ } else {
+ return TargetTriple.str();
+ }
+
+ switch (TargetEnvironment) {
+ default:
+ return TargetTriple.str();
+ case llvm::Triple::GNUSF:
+ FPFlavor = "sf";
+ break;
+ case llvm::Triple::GNUF32:
+ FPFlavor = "f32";
+ break;
+ case llvm::Triple::GNU:
+ case llvm::Triple::GNUF64:
+ // This was going to be "f64" in an earlier Toolchain Conventions
+ // revision, but starting from Feb 2023 the F64 ABI variants are
+ // unmarked in their canonical forms.
+ FPFlavor = "";
+ break;
+ }
+
+ return (Twine("loongarch64-linux-") + Libc + FPFlavor).str();
+ }
+
case llvm::Triple::m68k:
return "m68k-linux-gnu";
case llvm::Triple::mips:
return IsMipsR6 ? "mipsisa32r6-linux-gnu" : "mips-linux-gnu";
case llvm::Triple::mipsel:
- if (IsAndroid)
- return "mipsel-linux-android";
return IsMipsR6 ? "mipsisa32r6el-linux-gnu" : "mipsel-linux-gnu";
case llvm::Triple::mips64: {
std::string MT = std::string(IsMipsR6 ? "mipsisa64r6" : "mips64") +
"-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64");
- if (D.getVFS().exists(SysRoot + "/lib/" + MT))
+ if (D.getVFS().exists(concat(SysRoot, "/lib", MT)))
return MT;
- if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu"))
+ if (D.getVFS().exists(concat(SysRoot, "/lib/mips64-linux-gnu")))
return "mips64-linux-gnu";
break;
}
case llvm::Triple::mips64el: {
- if (IsAndroid)
- return "mips64el-linux-android";
std::string MT = std::string(IsMipsR6 ? "mipsisa64r6el" : "mips64el") +
"-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64");
- if (D.getVFS().exists(SysRoot + "/lib/" + MT))
+ if (D.getVFS().exists(concat(SysRoot, "/lib", MT)))
return MT;
- if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu"))
+ if (D.getVFS().exists(concat(SysRoot, "/lib/mips64el-linux-gnu")))
return "mips64el-linux-gnu";
break;
}
case llvm::Triple::ppc:
- if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
+ if (D.getVFS().exists(concat(SysRoot, "/lib/powerpc-linux-gnuspe")))
return "powerpc-linux-gnuspe";
return "powerpc-linux-gnu";
case llvm::Triple::ppcle:
@@ -124,6 +158,10 @@ std::string Linux::getMultiarchTriple(const Driver &D,
return "powerpc64-linux-gnu";
case llvm::Triple::ppc64le:
return "powerpc64le-linux-gnu";
+ case llvm::Triple::riscv64:
+ if (IsAndroid)
+ return "riscv64-linux-android";
+ return "riscv64-linux-gnu";
case llvm::Triple::sparc:
return "sparc-linux-gnu";
case llvm::Triple::sparcv9:
@@ -179,7 +217,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
Multilibs = GCCInstallation.getMultilibs();
- SelectedMultilib = GCCInstallation.getMultilib();
+ SelectedMultilibs.assign({GCCInstallation.getMultilib()});
llvm::Triple::ArchType Arch = Triple.getArch();
std::string SysRoot = computeSysRoot();
ToolChain::path_list &PPaths = getProgramPaths();
@@ -221,8 +259,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
const bool IsMips = Triple.isMIPS();
const bool IsHexagon = Arch == llvm::Triple::hexagon;
const bool IsRISCV = Triple.isRISCV();
+ const bool IsCSKY = Triple.isCSKY();
+
+ if (IsCSKY && !SelectedMultilibs.empty())
+ SysRoot = SysRoot + SelectedMultilibs.back().osSuffix();
- if (IsMips && !SysRoot.empty())
+ if ((IsMips || IsCSKY) && !SysRoot.empty())
ExtraOpts.push_back("--sysroot=" + SysRoot);
// Do not use 'gnu' hash style for Mips targets because .gnu.hash
@@ -232,25 +274,18 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// Android loader does not support .gnu.hash until API 23.
// Hexagon linker/loader does not support .gnu.hash
if (!IsMips && !IsHexagon) {
- if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() ||
- (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick) ||
- (IsAndroid && !Triple.isAndroidVersionLT(23)))
- ExtraOpts.push_back("--hash-style=gnu");
-
- if (Distro.IsDebian() || Distro.IsOpenSUSE() ||
- Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty ||
- Distro == Distro::UbuntuKarmic ||
+ if (Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid ||
+ Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic ||
(IsAndroid && Triple.isAndroidVersionLT(23)))
ExtraOpts.push_back("--hash-style=both");
+ else
+ ExtraOpts.push_back("--hash-style=gnu");
}
#ifdef ENABLE_LINKER_BUILD_ID
ExtraOpts.push_back("--build-id");
#endif
- if (IsAndroid || Distro.IsOpenSUSE())
- ExtraOpts.push_back("--enable-new-dtags");
-
// The selection of paths to try here is designed to match the patterns which
// the GCC driver itself uses, as this is part of the GCC-compatible driver.
// This was determined by running GCC in a fake filesystem, creating all
@@ -265,13 +300,13 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// used. We need add both libo32 and /lib.
if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel) {
Generic_GCC::AddMultilibPaths(D, SysRoot, "libo32", MultiarchTriple, Paths);
- addPathIfExists(D, SysRoot + "/libo32", Paths);
- addPathIfExists(D, SysRoot + "/usr/libo32", Paths);
+ addPathIfExists(D, concat(SysRoot, "/libo32"), Paths);
+ addPathIfExists(D, concat(SysRoot, "/usr/libo32"), Paths);
}
Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths);
- addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths);
- addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths);
+ addPathIfExists(D, concat(SysRoot, "/lib", MultiarchTriple), Paths);
+ addPathIfExists(D, concat(SysRoot, "/lib/..", OSLibDir), Paths);
if (IsAndroid) {
// Android sysroots contain a library directory for each supported OS
@@ -279,43 +314,30 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// directory.
addPathIfExists(
D,
- SysRoot + "/usr/lib/" + MultiarchTriple + "/" +
- llvm::to_string(Triple.getEnvironmentVersion().getMajor()),
+ concat(SysRoot, "/usr/lib", MultiarchTriple,
+ llvm::to_string(Triple.getEnvironmentVersion().getMajor())),
Paths);
}
- addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
+ addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths);
// 64-bit OpenEmbedded sysroots may not have a /usr/lib dir. So they cannot
// find /usr/lib64 as it is referenced as /usr/lib/../lib64. So we handle
// this here.
if (Triple.getVendor() == llvm::Triple::OpenEmbedded &&
Triple.isArch64Bit())
- addPathIfExists(D, SysRoot + "/usr/" + OSLibDir, Paths);
+ addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths);
else
- addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths);
+ addPathIfExists(D, concat(SysRoot, "/usr/lib/..", OSLibDir), Paths);
if (IsRISCV) {
StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
- addPathIfExists(D, SysRoot + "/" + OSLibDir + "/" + ABIName, Paths);
- addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths);
+ addPathIfExists(D, concat(SysRoot, "/", OSLibDir, ABIName), Paths);
+ addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir, ABIName), Paths);
}
Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths);
- // Similar to the logic for GCC above, if we are currently running Clang
- // inside of the requested system root, add its parent library path to those
- // searched.
- // FIXME: It's not clear whether we should use the driver's installed
- // directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot)) {
- // Even if OSLibDir != "lib", this is needed for Clang in the build
- // directory (not installed) to find libc++.
- addPathIfExists(D, D.Dir + "/../lib", Paths);
- if (OSLibDir != "lib")
- addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
- }
-
- addPathIfExists(D, SysRoot + "/lib", Paths);
- addPathIfExists(D, SysRoot + "/usr/lib", Paths);
+ addPathIfExists(D, concat(SysRoot, "/lib"), Paths);
+ addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths);
}
ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const {
@@ -361,6 +383,21 @@ std::string Linux::computeSysRoot() const {
return AndroidSysRootPath;
}
+ if (getTriple().isCSKY()) {
+ // CSKY toolchains use different names for sysroot folder.
+ if (!GCCInstallation.isValid())
+ return std::string();
+ // GCCInstallation.getInstallPath() =
+ // $GCCToolchainPath/lib/gcc/csky-linux-gnuabiv2/6.3.0
+ // Path = $GCCToolchainPath/csky-linux-gnuabiv2/libc
+ std::string Path = (GCCInstallation.getInstallPath() + "/../../../../" +
+ GCCInstallation.getTriple().str() + "/libc")
+ .str();
+ if (getVFS().exists(Path))
+ return Path;
+ return std::string();
+ }
+
if (!GCCInstallation.isValid() || !getTriple().isMIPS())
return std::string();
@@ -393,9 +430,17 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
const Distro Distro(getDriver().getVFS(), Triple);
- if (Triple.isAndroid())
+ if (Triple.isAndroid()) {
+ if (getSanitizerArgs(Args).needsHwasanRt() &&
+ !Triple.isAndroidVersionLT(34) && Triple.isArch64Bit()) {
+ // On Android 14 and newer, there is a special linker_hwasan64 that
+ // allows to run HWASan binaries on non-HWASan system images. This
+ // is also available on HWASan system images, so we can just always
+ // use that instead.
+ return "/system/bin/linker_hwasan64";
+ }
return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
-
+ }
if (Triple.isMusl()) {
std::string ArchName;
bool IsArm = false;
@@ -458,6 +503,22 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3";
break;
}
+ case llvm::Triple::loongarch32: {
+ LibDir = "lib32";
+ Loader =
+ ("ld-linux-loongarch-" +
+ tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1")
+ .str();
+ break;
+ }
+ case llvm::Triple::loongarch64: {
+ LibDir = "lib64";
+ Loader =
+ ("ld-linux-loongarch-" +
+ tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1")
+ .str();
+ break;
+ }
case llvm::Triple::m68k:
LibDir = "lib";
Loader = "ld.so.1";
@@ -537,6 +598,11 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
}
case llvm::Triple::ve:
return "/opt/nec/ve/lib/ld-linux-ve.so.1";
+ case llvm::Triple::csky: {
+ LibDir = "lib";
+ Loader = "ld.so.1";
+ break;
+ }
}
if (Distro == Distro::Exherbo &&
@@ -568,7 +634,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return;
// LOCAL_INCLUDE_DIR
- addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
+ addSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/local/include"));
// TOOL_INCLUDE_DIR
AddMultilibIncludeArgs(DriverArgs, CC1Args);
@@ -589,9 +655,10 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// /usr/include.
std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot);
if (!MultiarchIncludeDir.empty() &&
- D.getVFS().exists(SysRoot + "/usr/include/" + MultiarchIncludeDir))
- addExternCSystemInclude(DriverArgs, CC1Args,
- SysRoot + "/usr/include/" + MultiarchIncludeDir);
+ D.getVFS().exists(concat(SysRoot, "/usr/include", MultiarchIncludeDir)))
+ addExternCSystemInclude(
+ DriverArgs, CC1Args,
+ concat(SysRoot, "/usr/include", MultiarchIncludeDir));
if (getTriple().getOS() == llvm::Triple::RTEMS)
return;
@@ -599,9 +666,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Add an include of '/include' directly. This isn't provided by default by
// system GCCs, but is often used with cross-compiling GCCs, and harmless to
// add even when Clang is acting as-if it were a system compiler.
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
+ addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include"));
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+ addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include"));
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
@@ -650,12 +717,25 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+ CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
}
void Linux::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+ RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
+}
+
+void Linux::AddHIPRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back(
+ Args.MakeArgString(StringRef("-L") + RocmInstallation->getLibPath()));
+
+ if (Args.hasFlag(options::OPT_frtlib_add_rpath,
+ options::OPT_fno_rtlib_add_rpath, false))
+ CmdArgs.append(
+ {"-rpath", Args.MakeArgString(RocmInstallation->getLibPath())});
+
+ CmdArgs.push_back("-lamdhip64");
}
void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
@@ -705,6 +785,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
getTriple().getArch() == llvm::Triple::thumb ||
getTriple().getArch() == llvm::Triple::armeb ||
getTriple().getArch() == llvm::Triple::thumbeb;
+ const bool IsLoongArch64 = getTriple().getArch() == llvm::Triple::loongarch64;
const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
const bool IsSystemZ = getTriple().getArch() == llvm::Triple::systemz;
const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon;
@@ -718,24 +799,28 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::Memory;
Res |= SanitizerKind::Vptr;
Res |= SanitizerKind::SafeStack;
- if (IsX86_64 || IsMIPS64 || IsAArch64)
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64)
Res |= SanitizerKind::DataFlow;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 ||
- IsRISCV64 || IsSystemZ || IsHexagon)
+ IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64)
Res |= SanitizerKind::Leak;
- if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ)
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
+ IsLoongArch64 || IsRISCV64)
Res |= SanitizerKind::Thread;
- if (IsX86_64)
+ if (IsX86_64 || IsSystemZ)
Res |= SanitizerKind::KernelMemory;
- if (IsX86 || IsX86_64)
- Res |= SanitizerKind::Function;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
- IsPowerPC64 || IsHexagon)
+ IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64)
Res |= SanitizerKind::Scudo;
- if (IsX86_64 || IsAArch64) {
+ if (IsX86_64 || IsAArch64 || IsRISCV64) {
Res |= SanitizerKind::HWAddress;
+ }
+ if (IsX86_64 || IsAArch64) {
Res |= SanitizerKind::KernelHWAddress;
}
+ // Work around "Cannot represent a difference across sections".
+ if (getTriple().getArch() == llvm::Triple::ppc64)
+ Res &= ~SanitizerKind::Function;
return Res;
}
@@ -772,3 +857,9 @@ void Linux::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
for (const auto &Opt : ExtraOpts)
CmdArgs.push_back(Opt.c_str());
}
+
+const char *Linux::getDefaultLinker() const {
+ if (getTriple().isAndroid())
+ return "ld.lld";
+ return Generic_ELF::getDefaultLinker();
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h
index a5648d79d655..524391743090 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h
@@ -37,6 +37,8 @@ public:
llvm::opt::ArgStringList &CC1Args) const override;
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
@@ -61,6 +63,8 @@ public:
const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
const llvm::fltSemantics *FPType = nullptr) const override;
+ const char *getDefaultLinker() const override;
+
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp
index 96994ba77fac..07e875c64960 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp
@@ -101,7 +101,7 @@ void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args,
Features.push_back("+hwmultf5");
} else {
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << HWMultArg->getAsString(Args) << HWMult;
+ << HWMultArg->getSpelling() << HWMult;
}
}
@@ -142,7 +142,7 @@ std::string MSP430ToolChain::computeSysRoot() const {
else
llvm::sys::path::append(Dir, getDriver().Dir, "..");
- return std::string(Dir.str());
+ return std::string(Dir);
}
void MSP430ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -166,7 +166,7 @@ void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
return;
const StringRef MCU = MCUArg->getValue();
- if (MCU.startswith("msp430i")) {
+ if (MCU.starts_with("msp430i")) {
// 'i' should be in lower case as it's defined in TI MSP430-GCC headers
CC1Args.push_back(DriverArgs.MakeArgString(
"-D__MSP430i" + MCU.drop_front(7).upper() + "__"));
@@ -279,8 +279,7 @@ void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_r, options::OPT_g_Group))
CmdArgs.push_back("--gc-sections");
- Args.AddAllArgs(CmdArgs, {
- options::OPT_e,
+ Args.addAllArgs(CmdArgs, {
options::OPT_n,
options::OPT_s,
options::OPT_t,
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h
index 2e838c027e0f..a224c6375411 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h
@@ -59,7 +59,7 @@ private:
namespace tools {
namespace msp430 {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("MSP430::Linker", "msp430-elf-ld", TC) {}
bool hasIntegratedCPP() const override { return false; }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp
index 9f4751167ac1..396522225158 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -18,17 +18,16 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/TargetParser/Host.h"
#include <cstdio>
#ifdef _WIN32
@@ -40,91 +39,12 @@
#include <windows.h>
#endif
-#ifdef _MSC_VER
-// Don't support SetupApi on MinGW.
-#define USE_MSVC_SETUP_API
-
-// Make sure this comes before MSVCSetupApi.h
-#include <comdef.h>
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
-#endif
-#include "MSVCSetupApi.h"
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-#include "llvm/Support/COM.h"
-_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
-_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
-_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
-_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
-_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
-_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
-#endif
-
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-// Windows SDKs and VC Toolchains group their contents into subdirectories based
-// on the target architecture. This function converts an llvm::Triple::ArchType
-// to the corresponding subdirectory name.
-static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
- using ArchType = llvm::Triple::ArchType;
- switch (Arch) {
- case ArchType::x86:
- return "x86";
- case ArchType::x86_64:
- return "x64";
- case ArchType::arm:
- return "arm";
- case ArchType::aarch64:
- return "arm64";
- default:
- return "";
- }
-}
-
-// Similar to the above function, but for Visual Studios before VS2017.
-static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
- using ArchType = llvm::Triple::ArchType;
- switch (Arch) {
- case ArchType::x86:
- // x86 is default in legacy VC toolchains.
- // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
- return "";
- case ArchType::x86_64:
- return "amd64";
- case ArchType::arm:
- return "arm";
- case ArchType::aarch64:
- return "arm64";
- default:
- return "";
- }
-}
-
-// Similar to the above function, but for DevDiv internal builds.
-static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
- using ArchType = llvm::Triple::ArchType;
- switch (Arch) {
- case ArchType::x86:
- return "i386";
- case ArchType::x86_64:
- return "amd64";
- case ArchType::arm:
- return "arm";
- case ArchType::aarch64:
- return "arm64";
- default:
- return "";
- }
-}
-
static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
auto Status = VFS.status(Path);
if (!Status)
@@ -132,294 +52,6 @@ static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
}
-// Defined below.
-// Forward declare this so there aren't too many things above the constructor.
-static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- std::string &value, std::string *phValue);
-
-static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS,
- StringRef Directory) {
- std::string Highest;
- llvm::VersionTuple HighestTuple;
-
- std::error_code EC;
- for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
- DirEnd;
- !EC && DirIt != DirEnd; DirIt.increment(EC)) {
- auto Status = VFS.status(DirIt->path());
- if (!Status || !Status->isDirectory())
- continue;
- StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
- llvm::VersionTuple Tuple;
- if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
- continue;
- if (Tuple > HighestTuple) {
- HighestTuple = Tuple;
- Highest = CandidateName.str();
- }
- }
-
- return Highest;
-}
-
-// Check command line arguments to try and find a toolchain.
-static bool
-findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args,
- std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- // Don't validate the input; trust the value supplied by the user.
- // The primary motivation is to prevent unnecessary file and registry access.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir,
- options::OPT__SLASH_winsysroot)) {
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
- llvm::SmallString<128> ToolsPath(A->getValue());
- llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
- std::string VCToolsVersion;
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
- VCToolsVersion = A->getValue();
- else
- VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
- llvm::sys::path::append(ToolsPath, VCToolsVersion);
- Path = std::string(ToolsPath.str());
- } else {
- Path = A->getValue();
- }
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- }
- return false;
-}
-
-// Check various environment variables to try and find a toolchain.
-static bool
-findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- // These variables are typically set by vcvarsall.bat
- // when launching a developer command prompt.
- if (llvm::Optional<std::string> VCToolsInstallDir =
- llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
- // This is only set by newer Visual Studios, and it leads straight to
- // the toolchain directory.
- Path = std::move(*VCToolsInstallDir);
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- }
- if (llvm::Optional<std::string> VCInstallDir =
- llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
- // If the previous variable isn't set but this one is, then we've found
- // an older Visual Studio. This variable is set by newer Visual Studios too,
- // so this check has to appear second.
- // In older Visual Studios, the VC directory is the toolchain.
- Path = std::move(*VCInstallDir);
- VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
- return true;
- }
-
- // We couldn't find any VC environment variables. Let's walk through PATH and
- // see if it leads us to a VC toolchain bin directory. If it does, pick the
- // first one that we find.
- if (llvm::Optional<std::string> PathEnv =
- llvm::sys::Process::GetEnv("PATH")) {
- llvm::SmallVector<llvm::StringRef, 8> PathEntries;
- llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
- for (llvm::StringRef PathEntry : PathEntries) {
- if (PathEntry.empty())
- continue;
-
- llvm::SmallString<256> ExeTestPath;
-
- // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
- ExeTestPath = PathEntry;
- llvm::sys::path::append(ExeTestPath, "cl.exe");
- if (!VFS.exists(ExeTestPath))
- continue;
-
- // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
- // has a cl.exe. So let's check for link.exe too.
- ExeTestPath = PathEntry;
- llvm::sys::path::append(ExeTestPath, "link.exe");
- if (!VFS.exists(ExeTestPath))
- continue;
-
- // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
- llvm::StringRef TestPath = PathEntry;
- bool IsBin =
- llvm::sys::path::filename(TestPath).equals_insensitive("bin");
- if (!IsBin) {
- // Strip any architecture subdir like "amd64".
- TestPath = llvm::sys::path::parent_path(TestPath);
- IsBin = llvm::sys::path::filename(TestPath).equals_insensitive("bin");
- }
- if (IsBin) {
- llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
- llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
- if (ParentFilename.equals_insensitive("VC")) {
- Path = std::string(ParentPath);
- VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
- return true;
- }
- if (ParentFilename.equals_insensitive("x86ret") ||
- ParentFilename.equals_insensitive("x86chk") ||
- ParentFilename.equals_insensitive("amd64ret") ||
- ParentFilename.equals_insensitive("amd64chk")) {
- Path = std::string(ParentPath);
- VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
- return true;
- }
-
- } else {
- // This could be a new (>=VS2017) toolchain. If it is, we should find
- // path components with these prefixes when walking backwards through
- // the path.
- // Note: empty strings match anything.
- llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
- "MSVC", "Tools", "VC"};
-
- auto It = llvm::sys::path::rbegin(PathEntry);
- auto End = llvm::sys::path::rend(PathEntry);
- for (llvm::StringRef Prefix : ExpectedPrefixes) {
- if (It == End)
- goto NotAToolChain;
- if (!It->startswith_insensitive(Prefix))
- goto NotAToolChain;
- ++It;
- }
-
- // We've found a new toolchain!
- // Back up 3 times (/bin/Host/arch) to get the root path.
- llvm::StringRef ToolChainPath(PathEntry);
- for (int i = 0; i < 3; ++i)
- ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
-
- Path = std::string(ToolChainPath);
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- }
-
- NotAToolChain:
- continue;
- }
- }
- return false;
-}
-
-// Query the Setup Config server for installs, then pick the newest version
-// and find its default VC toolchain.
-// This is the preferred way to discover new Visual Studios, as they're no
-// longer listed in the registry.
-static bool
-findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
-#if !defined(USE_MSVC_SETUP_API)
- return false;
-#else
- // FIXME: This really should be done once in the top-level program's main
- // function, as it may have already been initialized with a different
- // threading model otherwise.
- llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
- HRESULT HR;
-
- // _com_ptr_t will throw a _com_error if a COM calls fail.
- // The LLVM coding standards forbid exception handling, so we'll have to
- // stop them from being thrown in the first place.
- // The destructor will put the regular error handler back when we leave
- // this scope.
- struct SuppressCOMErrorsRAII {
- static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
-
- SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
-
- ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
-
- } COMErrorSuppressor;
-
- ISetupConfigurationPtr Query;
- HR = Query.CreateInstance(__uuidof(SetupConfiguration));
- if (FAILED(HR))
- return false;
-
- IEnumSetupInstancesPtr EnumInstances;
- HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
- if (FAILED(HR))
- return false;
-
- ISetupInstancePtr Instance;
- HR = EnumInstances->Next(1, &Instance, nullptr);
- if (HR != S_OK)
- return false;
-
- ISetupInstancePtr NewestInstance;
- Optional<uint64_t> NewestVersionNum;
- do {
- bstr_t VersionString;
- uint64_t VersionNum;
- HR = Instance->GetInstallationVersion(VersionString.GetAddress());
- if (FAILED(HR))
- continue;
- HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
- if (FAILED(HR))
- continue;
- if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
- NewestInstance = Instance;
- NewestVersionNum = VersionNum;
- }
- } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
-
- if (!NewestInstance)
- return false;
-
- bstr_t VCPathWide;
- HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
- if (FAILED(HR))
- return false;
-
- std::string VCRootPath;
- llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
-
- llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
- llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
- "Microsoft.VCToolsVersion.default.txt");
-
- auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
- if (!ToolsVersionFile)
- return false;
-
- llvm::SmallString<256> ToolchainPath(VCRootPath);
- llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
- ToolsVersionFile->get()->getBuffer().rtrim());
- auto Status = VFS.status(ToolchainPath);
- if (!Status || !Status->isDirectory())
- return false;
-
- Path = std::string(ToolchainPath.str());
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
-#endif
-}
-
-// Look in the registry for Visual Studio installs, and use that to get
-// a toolchain path. VS2017 and newer don't get added to the registry.
-// So if we find something here, we know that it's an older version.
-static bool findVCToolChainViaRegistry(std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- std::string VSInstallPath;
- if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
- "InstallDir", VSInstallPath, nullptr) ||
- getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
- "InstallDir", VSInstallPath, nullptr)) {
- if (!VSInstallPath.empty()) {
- llvm::SmallString<256> VCPath(llvm::StringRef(
- VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
- llvm::sys::path::append(VCPath, "VC");
-
- Path = std::string(VCPath.str());
- VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
- return true;
- }
- }
- return false;
-}
-
// Try to find Exe from a Visual Studio distribution. This first tries to find
// an installed copy of Visual Studio and, failing that, looks in the PATH,
// making sure that whatever executable that's found is not a same-named exe
@@ -427,8 +59,8 @@ static bool findVCToolChainViaRegistry(std::string &Path,
static std::string FindVisualStudioExecutable(const ToolChain &TC,
const char *Exe) {
const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
- SmallString<128> FilePath(MSVC.getSubDirectoryPath(
- toolchains::MSVCToolChain::SubDirectoryType::Bin));
+ SmallString<128> FilePath(
+ MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin));
llvm::sys::path::append(FilePath, Exe);
return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
}
@@ -448,7 +80,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(std::string("-out:") + Output.getFilename()));
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
- !C.getDriver().IsCLMode()) {
+ !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {
CmdArgs.push_back("-defaultlib:libcmt");
CmdArgs.push_back("-defaultlib:oldnames");
}
@@ -469,7 +101,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
llvm::sys::path::append(DIAPath, "lib",
- llvmArchToLegacyVCArch(TC.getArch()));
+ llvm::archToLegacyVCArch(TC.getArch()));
CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
}
if (!llvm::sys::Process::GetEnv("LIB") ||
@@ -477,12 +109,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT__SLASH_winsysroot)) {
CmdArgs.push_back(Args.MakeArgString(
Twine("-libpath:") +
- TC.getSubDirectoryPath(
- toolchains::MSVCToolChain::SubDirectoryType::Lib)));
+ TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
CmdArgs.push_back(Args.MakeArgString(
Twine("-libpath:") +
- TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib,
- "atlmfc")));
+ TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
}
if (!llvm::sys::Process::GetEnv("LIB") ||
Args.getLastArg(options::OPT__SLASH_winsdkdir,
@@ -499,6 +129,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}
+ if (C.getDriver().IsFlangMode()) {
+ addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
+ addFortranRuntimeLibs(TC, Args, CmdArgs);
+
+ // Inform the MSVC linker that we're generating a console application, i.e.
+ // one with `main` as the "user-defined" entry point. The `main` function is
+ // defined in flang's runtime libraries.
+ CmdArgs.push_back("/subsystem:console");
+ }
+
// Add the compiler-rt library directories to libpath if they exist to help
// the linker find the various sanitizer, builtin, and profiling runtimes.
for (const auto &LibPath : TC.getLibraryPaths()) {
@@ -587,7 +227,7 @@ 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)) {
+ for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
StringRef GuardArgs = A->getValue();
if (GuardArgs.equals_insensitive("cf") ||
GuardArgs.equals_insensitive("cf,nochecks")) {
@@ -629,6 +269,26 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
}
+ StringRef Linker =
+ Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
+ if (Linker.empty())
+ Linker = "link";
+ // We need to translate 'lld' into 'lld-link'.
+ else if (Linker.equals_insensitive("lld"))
+ Linker = "lld-link";
+
+ if (Linker == "lld-link") {
+ for (Arg *A : Args.filtered(options::OPT_vfsoverlay))
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue()));
+
+ if (C.getDriver().isUsingLTO() &&
+ Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf,
+ false))
+ CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") +
+ Output.getFilename() + "_dwo"));
+ }
+
// Add filenames, libraries, and other linker inputs.
for (const auto &Input : Inputs) {
if (Input.isFilename()) {
@@ -642,7 +302,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (A.getOption().matches(options::OPT_l)) {
StringRef Lib = A.getValue();
const char *LinkLibArg;
- if (Lib.endswith(".lib"))
+ if (Lib.ends_with(".lib"))
LinkLibArg = Args.MakeArgString(Lib);
else
LinkLibArg = Args.MakeArgString(Lib + ".lib");
@@ -655,21 +315,15 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
A.renderAsInput(Args, CmdArgs);
}
+ addHIPRuntimeLibArgs(TC, C, Args, CmdArgs);
+
TC.addProfileRTLibs(Args, CmdArgs);
std::vector<const char *> Environment;
- // We need to special case some linker paths. In the case of lld, we need to
- // translate 'lld' into 'lld-link', and in the case of the regular msvc
+ // We need to special case some linker paths. In the case of the regular msvc
// linker, we need to use a special search algorithm.
llvm::SmallString<128> linkPath;
- StringRef Linker
- = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
- if (Linker.empty())
- Linker = "link";
- if (Linker.equals_insensitive("lld"))
- Linker = "lld-link";
-
if (Linker.equals_insensitive("link")) {
// If we're using the MSVC linker, it's not sufficient to just use link
// from the program PATH, because other environments like GnuWin32 install
@@ -689,13 +343,18 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // Clang handles passing the proper asan libs to the linker, which goes
+ // against link.exe's /INFERASANLIBS which automatically finds asan libs.
+ if (TC.getSanitizerArgs(Args).needsAsanRt())
+ CmdArgs.push_back("/INFERASANLIBS:NO");
+
#ifdef _WIN32
// When cross-compiling with VS2017 or newer, link.exe expects to have
// its containing bin directory at the top of PATH, followed by the
// native target bin directory.
// e.g. when compiling for x86 on an x64 host, PATH should start with:
// /bin/Hostx64/x86;/bin/Hostx64/x64
- // This doesn't attempt to handle ToolsetLayout::DevDivInternal.
+ // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.
if (TC.getIsVS2017OrNewer() &&
llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
@@ -729,14 +388,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// find it.
for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
llvm::StringRef EnvVar(Cursor);
- if (EnvVar.startswith_insensitive("path=")) {
- using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
+ if (EnvVar.starts_with_insensitive("path=")) {
constexpr size_t PrefixLen = 5; // strlen("path=")
Environment.push_back(Args.MakeArgString(
EnvVar.substr(0, PrefixLen) +
- TC.getSubDirectoryPath(SubDirectoryType::Bin) +
+ TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +
llvm::Twine(llvm::sys::EnvPathSeparator) +
- TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) +
+ TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) +
(EnvVar.size() > PrefixLen
? llvm::Twine(llvm::sys::EnvPathSeparator) +
EnvVar.substr(PrefixLen)
@@ -769,14 +427,29 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
+ std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
+ VCToolsDir = A->getValue();
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
+ VCToolsVersion = A->getValue();
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))
+ WinSdkDir = A->getValue();
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
+ WinSdkVersion = A->getValue();
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))
+ WinSysRoot = A->getValue();
+
// Check the command line first, that's the user explicitly telling us what to
// use. Check the environment next, in case we're being invoked from a VS
// command prompt. Failing that, just try to find the newest Visual Studio
// version we can and use its default VC toolchain.
- findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) ||
- findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) ||
- findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) ||
- findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
+ llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,
+ WinSysRoot, VCToolChainPath, VSLayout) ||
+ llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,
+ VSLayout) ||
+ llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion,
+ VCToolChainPath, VSLayout) ||
+ llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
}
Tool *MSVCToolChain::buildLinker() const {
@@ -790,20 +463,20 @@ Tool *MSVCToolChain::buildAssembler() const {
return nullptr;
}
-bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
- return true;
-}
-
-bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
// Don't emit unwind tables by default for MachO targets.
if (getTriple().isOSBinFormatMachO())
- return false;
+ return UnwindTableLevel::None;
// All non-x86_32 Windows targets require unwind tables. However, LLVM
// doesn't know how to generate them for all targets, so only enable
// the ones that are actually implemented.
- return getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64;
+ if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
+ getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
+ return UnwindTableLevel::Asynchronous;
+
+ return UnwindTableLevel::None;
}
bool MSVCToolChain::isPICDefault() const {
@@ -822,368 +495,72 @@ bool MSVCToolChain::isPICDefaultForced() const {
void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+ CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
}
void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+ RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
-void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
- RocmInstallation.print(OS);
+void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +
+ RocmInstallation->getLibPath()),
+ "amdhip64.lib"});
}
-// Get the path to a specific subdirectory in the current toolchain for
-// a given target architecture.
-// VS2017 changed the VC toolchain layout, so this should be used instead
-// of hardcoding paths.
-std::string
-MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
- llvm::StringRef SubdirParent,
- llvm::Triple::ArchType TargetArch) const {
- const char *SubdirName;
- const char *IncludeName;
- switch (VSLayout) {
- case ToolsetLayout::OlderVS:
- SubdirName = llvmArchToLegacyVCArch(TargetArch);
- IncludeName = "include";
- break;
- case ToolsetLayout::VS2017OrNewer:
- SubdirName = llvmArchToWindowsSDKArch(TargetArch);
- IncludeName = "include";
- break;
- case ToolsetLayout::DevDivInternal:
- SubdirName = llvmArchToDevDivInternalArch(TargetArch);
- IncludeName = "inc";
- break;
- }
-
- llvm::SmallString<256> Path(VCToolChainPath);
- if (!SubdirParent.empty())
- llvm::sys::path::append(Path, SubdirParent);
-
- switch (Type) {
- case SubDirectoryType::Bin:
- if (VSLayout == ToolsetLayout::VS2017OrNewer) {
- const bool HostIsX64 =
- llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
- const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
- llvm::sys::path::append(Path, "bin", HostName, SubdirName);
- } else { // OlderVS or DevDivInternal
- llvm::sys::path::append(Path, "bin", SubdirName);
- }
- break;
- case SubDirectoryType::Include:
- llvm::sys::path::append(Path, IncludeName);
- break;
- case SubDirectoryType::Lib:
- llvm::sys::path::append(Path, "lib", SubdirName);
- break;
- }
- return std::string(Path.str());
+void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
+ CudaInstallation->print(OS);
+ RocmInstallation->print(OS);
}
-#ifdef _WIN32
-static bool readFullStringValue(HKEY hkey, const char *valueName,
- std::string &value) {
- std::wstring WideValueName;
- if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
- return false;
-
- DWORD result = 0;
- DWORD valueSize = 0;
- DWORD type = 0;
- // First just query for the required size.
- result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
- &valueSize);
- if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
- return false;
- std::vector<BYTE> buffer(valueSize);
- result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
- &valueSize);
- if (result == ERROR_SUCCESS) {
- std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
- valueSize / sizeof(wchar_t));
- if (valueSize && WideValue.back() == L'\0') {
- WideValue.pop_back();
- }
- // The destination buffer must be empty as an invariant of the conversion
- // function; but this function is sometimes called in a loop that passes in
- // the same buffer, however. Simply clear it out so we can overwrite it.
- value.clear();
- return llvm::convertWideToUTF8(WideValue, value);
- }
- return false;
+std::string
+MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
+ llvm::StringRef SubdirParent) const {
+ return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
+ SubdirParent);
}
-#endif
-/// Read registry string.
-/// This also supports a means to look for high-versioned keys by use
-/// of a $VERSION placeholder in the key path.
-/// $VERSION in the key path is a placeholder for the version number,
-/// causing the highest value path to be searched for and used.
-/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
-/// There can be additional characters in the component. Only the numeric
-/// characters are compared. This function only searches HKLM.
-static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- std::string &value, std::string *phValue) {
-#ifndef _WIN32
- return false;
-#else
- HKEY hRootKey = HKEY_LOCAL_MACHINE;
- HKEY hKey = NULL;
- long lResult;
- bool returnValue = false;
-
- const char *placeHolder = strstr(keyPath, "$VERSION");
- std::string bestName;
- // If we have a $VERSION placeholder, do the highest-version search.
- if (placeHolder) {
- const char *keyEnd = placeHolder - 1;
- const char *nextKey = placeHolder;
- // Find end of previous key.
- while ((keyEnd > keyPath) && (*keyEnd != '\\'))
- keyEnd--;
- // Find end of key containing $VERSION.
- while (*nextKey && (*nextKey != '\\'))
- nextKey++;
- size_t partialKeyLength = keyEnd - keyPath;
- char partialKey[256];
- if (partialKeyLength >= sizeof(partialKey))
- partialKeyLength = sizeof(partialKey) - 1;
- strncpy(partialKey, keyPath, partialKeyLength);
- partialKey[partialKeyLength] = '\0';
- HKEY hTopKey = NULL;
- lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
- &hTopKey);
- if (lResult == ERROR_SUCCESS) {
- char keyName[256];
- double bestValue = 0.0;
- DWORD index, size = sizeof(keyName) - 1;
- for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
- NULL, NULL) == ERROR_SUCCESS;
- index++) {
- const char *sp = keyName;
- while (*sp && !isDigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isDigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double dvalue = strtod(numBuf, NULL);
- if (dvalue > bestValue) {
- // Test that InstallDir is indeed there before keeping this index.
- // Open the chosen key path remainder.
- bestName = keyName;
- // Append rest of key.
- bestName.append(nextKey);
- lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
- KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- if (readFullStringValue(hKey, valueName, value)) {
- bestValue = dvalue;
- if (phValue)
- *phValue = bestName;
- returnValue = true;
- }
- RegCloseKey(hKey);
- }
- }
- size = sizeof(keyName) - 1;
- }
- RegCloseKey(hTopKey);
- }
- } else {
- lResult =
- RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- if (readFullStringValue(hKey, valueName, value))
- returnValue = true;
- if (phValue)
- phValue->clear();
- RegCloseKey(hKey);
- }
- }
- return returnValue;
-#endif // _WIN32
+std::string
+MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
+ llvm::Triple::ArchType TargetArch) const {
+ return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
+ "");
}
// Find the most recent version of Universal CRT or Windows 10 SDK.
// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
// directory by name and uses the last one of the list.
// So we compare entry names lexicographically to find the greatest one.
-static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS,
- const std::string &SDKPath,
- std::string &SDKVersion) {
- llvm::SmallString<128> IncludePath(SDKPath);
- llvm::sys::path::append(IncludePath, "Include");
- SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
- return !SDKVersion.empty();
-}
-
-static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS,
- const ArgList &Args,
- std::string &Path, int &Major,
- std::string &Version) {
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir,
- options::OPT__SLASH_winsysroot)) {
- // Don't validate the input; trust the value supplied by the user.
- // The motivation is to prevent unnecessary file and registry access.
- llvm::VersionTuple SDKVersion;
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
- SDKVersion.tryParse(A->getValue());
-
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
- llvm::SmallString<128> SDKPath(A->getValue());
- llvm::sys::path::append(SDKPath, "Windows Kits");
- if (!SDKVersion.empty())
- llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor()));
- else
- llvm::sys::path::append(
- SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
- Path = std::string(SDKPath.str());
- } else {
- Path = A->getValue();
- }
-
- if (!SDKVersion.empty()) {
- Major = SDKVersion.getMajor();
- Version = SDKVersion.getAsString();
- } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
- Major = 10;
- }
- return true;
- }
- return false;
-}
-
-/// Get Windows SDK installation directory.
-static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args,
- std::string &Path, int &Major,
- std::string &WindowsSDKIncludeVersion,
- std::string &WindowsSDKLibVersion) {
- // Trust /winsdkdir and /winsdkversion if present.
- if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major,
- WindowsSDKIncludeVersion)) {
- WindowsSDKLibVersion = WindowsSDKIncludeVersion;
- return true;
- }
-
- // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry.
-
- // Try the Windows registry.
- std::string RegistrySDKVersion;
- if (!getSystemRegistryString(
- "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
- "InstallationFolder", Path, &RegistrySDKVersion))
- return false;
- if (Path.empty() || RegistrySDKVersion.empty())
- return false;
-
- WindowsSDKIncludeVersion.clear();
- WindowsSDKLibVersion.clear();
- Major = 0;
- std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
- if (Major <= 7)
- return true;
- if (Major == 8) {
- // Windows SDK 8.x installs libraries in a folder whose names depend on the
- // version of the OS you're targeting. By default choose the newest, which
- // usually corresponds to the version of the OS you've installed the SDK on.
- const char *Tests[] = {"winv6.3", "win8", "win7"};
- for (const char *Test : Tests) {
- llvm::SmallString<128> TestPath(Path);
- llvm::sys::path::append(TestPath, "Lib", Test);
- if (VFS.exists(TestPath)) {
- WindowsSDKLibVersion = Test;
- break;
- }
- }
- return !WindowsSDKLibVersion.empty();
- }
- if (Major == 10) {
- if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
- return false;
- WindowsSDKLibVersion = WindowsSDKIncludeVersion;
- return true;
- }
- // Unsupported SDK version
- return false;
-}
-
// Gets the library path required to link against the Windows SDK.
-bool MSVCToolChain::getWindowsSDKLibraryPath(
- const ArgList &Args, std::string &path) const {
+bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args,
+ std::string &path) const {
std::string sdkPath;
int sdkMajor = 0;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
path.clear();
- if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor,
- windowsSDKIncludeVersion, windowsSDKLibVersion))
+ if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
+ sdkPath, sdkMajor, windowsSDKIncludeVersion,
+ windowsSDKLibVersion))
return false;
llvm::SmallString<128> libPath(sdkPath);
llvm::sys::path::append(libPath, "Lib");
- if (sdkMajor >= 8) {
- llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
- llvmArchToWindowsSDKArch(getArch()));
- } else {
- switch (getArch()) {
- // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
- case llvm::Triple::x86:
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(libPath, "x64");
- break;
- case llvm::Triple::arm:
- // It is not necessary to link against Windows SDK 7.x when targeting ARM.
- return false;
- default:
- return false;
- }
- }
-
- path = std::string(libPath.str());
- return true;
+ if (sdkMajor >= 10)
+ if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
+ WinSdkVersion.has_value())
+ windowsSDKLibVersion = *WinSdkVersion;
+ if (sdkMajor >= 8)
+ llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
+ return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
+ path);
}
-// Check if the Include path of a specified version of Visual Studio contains
-// specific header files. If not, they are probably shipped with Universal CRT.
bool MSVCToolChain::useUniversalCRT() const {
- llvm::SmallString<128> TestPath(
- getSubDirectoryPath(SubDirectoryType::Include));
- llvm::sys::path::append(TestPath, "stdlib.h");
- return !getVFS().exists(TestPath);
-}
-
-static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS,
- const ArgList &Args, std::string &Path,
- std::string &UCRTVersion) {
- // If /winsdkdir is passed, use it as location for the UCRT too.
- // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
- int Major;
- if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion))
- return true;
-
- // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
- // registry.
-
- // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
- // for the specific key "KitsRoot10". So do we.
- if (!getSystemRegistryString(
- "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
- Path, nullptr))
- return false;
-
- return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
+ return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());
}
bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
@@ -1192,17 +569,23 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
std::string UCRTVersion;
Path.clear();
- if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion))
+ if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
+ WinSysRoot, UniversalCRTSdkPath,
+ UCRTVersion))
return false;
- StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
+ if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
+ WinSdkVersion.has_value())
+ UCRTVersion = *WinSdkVersion;
+
+ StringRef ArchName = llvm::archToWindowsSDKArch(getArch());
if (ArchName.empty())
return false;
llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
- Path = std::string(LibPath.str());
+ Path = std::string(LibPath);
return true;
}
@@ -1313,15 +696,20 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// the correct include paths first.
if (!VCToolChainPath.empty()) {
addSystemInclude(DriverArgs, CC1Args,
- getSubDirectoryPath(SubDirectoryType::Include));
- addSystemInclude(DriverArgs, CC1Args,
- getSubDirectoryPath(SubDirectoryType::Include, "atlmfc"));
+ getSubDirectoryPath(llvm::SubDirectoryType::Include));
+ addSystemInclude(
+ DriverArgs, CC1Args,
+ getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));
if (useUniversalCRT()) {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
- if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath,
- UCRTVersion)) {
+ if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
+ WinSysRoot, UniversalCRTSdkPath,
+ UCRTVersion)) {
+ if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
+ WinSdkVersion.has_value())
+ UCRTVersion = *WinSdkVersion;
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
"Include", UCRTVersion, "ucrt");
}
@@ -1331,8 +719,13 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
int major = 0;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
- if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major,
- windowsSDKIncludeVersion, windowsSDKLibVersion)) {
+ if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
+ WindowsSDKDir, major, windowsSDKIncludeVersion,
+ windowsSDKLibVersion)) {
+ if (major >= 10)
+ if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
+ WinSdkVersion.has_value())
+ windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion;
if (major >= 8) {
// Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
// Anyway, llvm::sys::path::append is able to manage it.
@@ -1348,7 +741,7 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (major >= 10) {
llvm::VersionTuple Tuple;
if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
- Tuple.getSubminor().getValueOr(0) >= 17134) {
+ Tuple.getSubminor().value_or(0) >= 17134) {
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"Include", windowsSDKIncludeVersion,
"cppwinrt");
@@ -1389,12 +782,16 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
if (MSVT.empty())
MSVT = getTriple().getEnvironmentVersion();
if (MSVT.empty() && IsWindowsMSVC)
- MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
+ MSVT =
+ getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));
if (MSVT.empty() &&
Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC)) {
- // -fms-compatibility-version=19.20 is default, aka 2019, 16.x
- MSVT = VersionTuple(19, 20);
+ // -fms-compatibility-version=19.33 is default, aka 2022, 17.3
+ // NOTE: when changing this value, also update
+ // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst
+ // accordingly.
+ MSVT = VersionTuple(19, 33);
}
return MSVT;
}
@@ -1405,8 +802,8 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
// The MSVC version doesn't care about the architecture, even though it
// may look at the triple internally.
VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
- MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
- MSVT.getSubminor().getValueOr(0));
+ MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0),
+ MSVT.getSubminor().value_or(0));
// For the rest of the triple, however, a computed architecture name may
// be needed.
@@ -1619,7 +1016,7 @@ void MSVCToolChain::addClangTargetOptions(
Action::OffloadKind DeviceOffloadKind) const {
// MSVC STL kindly allows removing all usages of typeid by defining
// _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
- if (DriverArgs.hasArg(options::OPT_fno_rtti, options::OPT_frtti,
- /*Default=*/false))
+ if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti,
+ /*Default=*/false))
CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h
index c842773996ed..48369e030aad 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h
@@ -11,10 +11,12 @@
#include "AMDGPU.h"
#include "Cuda.h"
-#include "clang/Basic/DebugInfoOptions.h"
+#include "LazyDetector.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/Frontend/Debug/Options.h"
+#include "llvm/WindowsDriver/MSVCPaths.h"
namespace clang {
namespace driver {
@@ -22,7 +24,7 @@ namespace tools {
/// Visual studio tools.
namespace visualstudio {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("visualstudio::Linker", "linker", TC) {}
@@ -49,8 +51,8 @@ public:
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
- bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
@@ -58,9 +60,10 @@ public:
/// Set CodeView as the default debug info format for non-MachO binary
/// formats, and to DWARF otherwise. Users can use -gcodeview and -gdwarf to
/// override the default.
- codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override {
- return getTriple().isOSBinFormatMachO() ? codegenoptions::DIF_DWARF
- : codegenoptions::DIF_CodeView;
+ llvm::codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override {
+ return getTriple().isOSBinFormatMachO()
+ ? llvm::codegenoptions::DIF_DWARF
+ : llvm::codegenoptions::DIF_CodeView;
}
/// Set the debugger tuning to "default", since we're definitely not tuning
@@ -73,29 +76,15 @@ public:
return 4;
}
- enum class SubDirectoryType {
- Bin,
- Include,
- Lib,
- };
- std::string getSubDirectoryPath(SubDirectoryType Type,
- llvm::StringRef SubdirParent,
+ std::string getSubDirectoryPath(llvm::SubDirectoryType Type,
+ llvm::StringRef SubdirParent = "") const;
+ std::string getSubDirectoryPath(llvm::SubDirectoryType Type,
llvm::Triple::ArchType TargetArch) const;
- // Convenience overload.
- // Uses the current target arch.
- std::string getSubDirectoryPath(SubDirectoryType Type,
- llvm::StringRef SubdirParent = "") const {
- return getSubDirectoryPath(Type, SubdirParent, getArch());
+ bool getIsVS2017OrNewer() const {
+ return VSLayout == llvm::ToolsetLayout::VS2017OrNewer;
}
- enum class ToolsetLayout {
- OlderVS,
- VS2017OrNewer,
- DevDivInternal,
- };
- bool getIsVS2017OrNewer() const { return VSLayout == ToolsetLayout::VS2017OrNewer; }
-
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -109,6 +98,9 @@ public:
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
bool getWindowsSDKLibraryPath(
const llvm::opt::ArgList &Args, std::string &path) const;
bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args,
@@ -142,10 +134,11 @@ protected:
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
private:
+ std::optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot;
std::string VCToolChainPath;
- ToolsetLayout VSLayout = ToolsetLayout::OlderVS;
- CudaInstallationDetector CudaInstallation;
- RocmInstallationDetector RocmInstallation;
+ llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS;
+ LazyDetector<CudaInstallationDetector> CudaInstallation;
+ LazyDetector<RocmInstallationDetector> RocmInstallation;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h
deleted file mode 100644
index 28e6e3e08e37..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h
+++ /dev/null
@@ -1,523 +0,0 @@
-// <copyright file="Program.cpp" company="Microsoft Corporation">
-// Copyright (C) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-// </copyright>
-// <license>
-// The MIT License (MIT)
-//
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-// </license>
-
-#pragma once
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
-#endif
-
-// Constants
-//
-#ifndef E_NOTFOUND
-#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
-#endif
-
-#ifndef E_FILENOTFOUND
-#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
-#endif
-
-// Enumerations
-//
-/// <summary>
-/// The state of an instance.
-/// </summary>
-enum InstanceState : unsigned {
- /// <summary>
- /// The instance state has not been determined.
- /// </summary>
- eNone = 0,
-
- /// <summary>
- /// The instance installation path exists.
- /// </summary>
- eLocal = 1,
-
- /// <summary>
- /// A product is registered to the instance.
- /// </summary>
- eRegistered = 2,
-
- /// <summary>
- /// No reboot is required for the instance.
- /// </summary>
- eNoRebootRequired = 4,
-
- /// <summary>
- /// The instance represents a complete install.
- /// </summary>
- eComplete = MAXUINT,
-};
-
-// Forward interface declarations
-//
-#ifndef __ISetupInstance_FWD_DEFINED__
-#define __ISetupInstance_FWD_DEFINED__
-typedef struct ISetupInstance ISetupInstance;
-#endif
-
-#ifndef __ISetupInstance2_FWD_DEFINED__
-#define __ISetupInstance2_FWD_DEFINED__
-typedef struct ISetupInstance2 ISetupInstance2;
-#endif
-
-#ifndef __IEnumSetupInstances_FWD_DEFINED__
-#define __IEnumSetupInstances_FWD_DEFINED__
-typedef struct IEnumSetupInstances IEnumSetupInstances;
-#endif
-
-#ifndef __ISetupConfiguration_FWD_DEFINED__
-#define __ISetupConfiguration_FWD_DEFINED__
-typedef struct ISetupConfiguration ISetupConfiguration;
-#endif
-
-#ifndef __ISetupConfiguration2_FWD_DEFINED__
-#define __ISetupConfiguration2_FWD_DEFINED__
-typedef struct ISetupConfiguration2 ISetupConfiguration2;
-#endif
-
-#ifndef __ISetupPackageReference_FWD_DEFINED__
-#define __ISetupPackageReference_FWD_DEFINED__
-typedef struct ISetupPackageReference ISetupPackageReference;
-#endif
-
-#ifndef __ISetupHelper_FWD_DEFINED__
-#define __ISetupHelper_FWD_DEFINED__
-typedef struct ISetupHelper ISetupHelper;
-#endif
-
-// Forward class declarations
-//
-#ifndef __SetupConfiguration_FWD_DEFINED__
-#define __SetupConfiguration_FWD_DEFINED__
-
-#ifdef __cplusplus
-typedef class SetupConfiguration SetupConfiguration;
-#endif
-
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Interface definitions
-//
-EXTERN_C const IID IID_ISetupInstance;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Information about an instance of a product.
-/// </summary>
-struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E")
- DECLSPEC_NOVTABLE ISetupInstance : public IUnknown {
- /// <summary>
- /// Gets the instance identifier (should match the name of the parent instance
- /// directory).
- /// </summary>
- /// <param name="pbstrInstanceId">The instance identifier.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetInstanceId)(_Out_ BSTR *pbstrInstanceId) = 0;
-
- /// <summary>
- /// Gets the local date and time when the installation was originally
- /// installed.
- /// </summary>
- /// <param name="pInstallDate">The local date and time when the installation
- /// was originally installed.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0;
-
- /// <summary>
- /// Gets the unique name of the installation, often indicating the branch and
- /// other information used for telemetry.
- /// </summary>
- /// <param name="pbstrInstallationName">The unique name of the installation,
- /// often indicating the branch and other information used for
- /// telemetry.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(GetInstallationName)(_Out_ BSTR *pbstrInstallationName) = 0;
-
- /// <summary>
- /// Gets the path to the installation root of the product.
- /// </summary>
- /// <param name="pbstrInstallationPath">The path to the installation root of
- /// the product.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(GetInstallationPath)(_Out_ BSTR *pbstrInstallationPath) = 0;
-
- /// <summary>
- /// Gets the version of the product installed in this instance.
- /// </summary>
- /// <param name="pbstrInstallationVersion">The version of the product
- /// installed in this instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(GetInstallationVersion)(_Out_ BSTR *pbstrInstallationVersion) = 0;
-
- /// <summary>
- /// Gets the display name (title) of the product installed in this instance.
- /// </summary>
- /// <param name="lcid">The LCID for the display name.</param>
- /// <param name="pbstrDisplayName">The display name (title) of the product
- /// installed in this instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0;
-
- /// <summary>
- /// Gets the description of the product installed in this instance.
- /// </summary>
- /// <param name="lcid">The LCID for the description.</param>
- /// <param name="pbstrDescription">The description of the product installed in
- /// this instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0;
-
- /// <summary>
- /// Resolves the optional relative path to the root path of the instance.
- /// </summary>
- /// <param name="pwszRelativePath">A relative path within the instance to
- /// resolve, or NULL to get the root path.</param>
- /// <param name="pbstrAbsolutePath">The full path to the optional relative
- /// path within the instance. If the relative path is NULL, the root path will
- /// always terminate in a backslash.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// property is not defined.</returns>
- STDMETHOD(ResolvePath)
- (_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupInstance2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Information about an instance of a product.
-/// </summary>
-struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C")
- DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance {
- /// <summary>
- /// Gets the state of the instance.
- /// </summary>
- /// <param name="pState">The state of the instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetState)(_Out_ InstanceState *pState) = 0;
-
- /// <summary>
- /// Gets an array of package references registered to the instance.
- /// </summary>
- /// <param name="ppsaPackages">Pointer to an array of <see
- /// cref="ISetupPackageReference"/>.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// packages property is not defined.</returns>
- STDMETHOD(GetPackages)(_Out_ LPSAFEARRAY *ppsaPackages) = 0;
-
- /// <summary>
- /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents
- /// the registered product.
- /// </summary>
- /// <param name="ppPackage">Pointer to an instance of <see
- /// cref="ISetupPackageReference"/>. This may be NULL if <see
- /// cref="GetState"/> does not return <see cref="eComplete"/>.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
- /// packages property is not defined.</returns>
- STDMETHOD(GetProduct)
- (_Outptr_result_maybenull_ ISetupPackageReference **ppPackage) = 0;
-
- /// <summary>
- /// Gets the relative path to the product application, if available.
- /// </summary>
- /// <param name="pbstrProductPath">The relative path to the product
- /// application, if available.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetProductPath)
- (_Outptr_result_maybenull_ BSTR *pbstrProductPath) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_IEnumSetupInstances;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// A enumerator of installed <see cref="ISetupInstance"/> objects.
-/// </summary>
-struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")
- DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown {
- /// <summary>
- /// Retrieves the next set of product instances in the enumeration sequence.
- /// </summary>
- /// <param name="celt">The number of product instances to retrieve.</param>
- /// <param name="rgelt">A pointer to an array of <see
- /// cref="ISetupInstance"/>.</param>
- /// <param name="pceltFetched">A pointer to the number of product instances
- /// retrieved. If celt is 1 this parameter may be NULL.</param>
- /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing
- /// was fetched (at end of enumeration), E_INVALIDARG if celt is greater than
- /// 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see
- /// cref="ISetupInstance"/> could not be allocated.</returns>
- STDMETHOD(Next)
- (_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt,
- _Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0;
-
- /// <summary>
- /// Skips the next set of product instances in the enumeration sequence.
- /// </summary>
- /// <param name="celt">The number of product instances to skip.</param>
- /// <returns>S_OK if the number of elements could be skipped; otherwise,
- /// S_FALSE;</returns>
- STDMETHOD(Skip)(_In_ ULONG celt) = 0;
-
- /// <summary>
- /// Resets the enumeration sequence to the beginning.
- /// </summary>
- /// <returns>Always returns S_OK;</returns>
- STDMETHOD(Reset)(void) = 0;
-
- /// <summary>
- /// Creates a new enumeration object in the same state as the current
- /// enumeration object: the new object points to the same place in the
- /// enumeration sequence.
- /// </summary>
- /// <param name="ppenum">A pointer to a pointer to a new <see
- /// cref="IEnumSetupInstances"/> interface. If the method fails, this
- /// parameter is undefined.</param>
- /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns>
- STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupConfiguration;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Gets information about product instances set up on the machine.
-/// </summary>
-struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B")
- DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown {
- /// <summary>
- /// Enumerates all completed product instances installed.
- /// </summary>
- /// <param name="ppEnumInstances">An enumeration of completed, installed
- /// product instances.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0;
-
- /// <summary>
- /// Gets the instance for the current process path.
- /// </summary>
- /// <param name="ppInstance">The instance for the current process
- /// path.</param>
- /// <returns>The instance for the current process path, or E_NOTFOUND if not
- /// found.</returns>
- STDMETHOD(GetInstanceForCurrentProcess)
- (_Out_ ISetupInstance **ppInstance) = 0;
-
- /// <summary>
- /// Gets the instance for the given path.
- /// </summary>
- /// <param name="ppInstance">The instance for the given path.</param>
- /// <returns>The instance for the given path, or E_NOTFOUND if not
- /// found.</returns>
- STDMETHOD(GetInstanceForPath)
- (_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupConfiguration2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Gets information about product instances.
-/// </summary>
-struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")
- DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration {
- /// <summary>
- /// Enumerates all product instances.
- /// </summary>
- /// <param name="ppEnumInstances">An enumeration of all product
- /// instances.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(EnumAllInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupPackageReference;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// A reference to a package.
-/// </summary>
-struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5")
- DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown {
- /// <summary>
- /// Gets the general package identifier.
- /// </summary>
- /// <param name="pbstrId">The general package identifier.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetId)(_Out_ BSTR *pbstrId) = 0;
-
- /// <summary>
- /// Gets the version of the package.
- /// </summary>
- /// <param name="pbstrVersion">The version of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetVersion)(_Out_ BSTR *pbstrVersion) = 0;
-
- /// <summary>
- /// Gets the target process architecture of the package.
- /// </summary>
- /// <param name="pbstrChip">The target process architecture of the
- /// package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetChip)(_Out_ BSTR *pbstrChip) = 0;
-
- /// <summary>
- /// Gets the language and optional region identifier.
- /// </summary>
- /// <param name="pbstrLanguage">The language and optional region
- /// identifier.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetLanguage)(_Out_ BSTR *pbstrLanguage) = 0;
-
- /// <summary>
- /// Gets the build branch of the package.
- /// </summary>
- /// <param name="pbstrBranch">The build branch of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetBranch)(_Out_ BSTR *pbstrBranch) = 0;
-
- /// <summary>
- /// Gets the type of the package.
- /// </summary>
- /// <param name="pbstrType">The type of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetType)(_Out_ BSTR *pbstrType) = 0;
-
- /// <summary>
- /// Gets the unique identifier consisting of all defined tokens.
- /// </summary>
- /// <param name="pbstrUniqueId">The unique identifier consisting of all
- /// defined tokens.</param>
- /// <returns>Standard HRESULT indicating success or failure, including
- /// E_UNEXPECTED if no Id was defined (required).</returns>
- STDMETHOD(GetUniqueId)(_Out_ BSTR *pbstrUniqueId) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupHelper;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Helper functions.
-/// </summary>
-/// <remarks>
-/// You can query for this interface from the <see cref="SetupConfiguration"/>
-/// class.
-/// </remarks>
-struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c")
- DECLSPEC_NOVTABLE ISetupHelper : public IUnknown {
- /// <summary>
- /// Parses a dotted quad version string into a 64-bit unsigned integer.
- /// </summary>
- /// <param name="pwszVersion">The dotted quad version string to parse, e.g.
- /// 1.2.3.4.</param>
- /// <param name="pullVersion">A 64-bit unsigned integer representing the
- /// version. You can compare this to other versions.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(ParseVersion)
- (_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0;
-
- /// <summary>
- /// Parses a dotted quad version string into a 64-bit unsigned integer.
- /// </summary>
- /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad
- /// version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param>
- /// <param name="pullMinVersion">A 64-bit unsigned integer representing the
- /// minimum version, which may be 0. You can compare this to other
- /// versions.</param>
- /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the
- /// maximum version, which may be MAXULONGLONG. You can compare this to other
- /// versions.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(ParseVersionRange)
- (_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion,
- _Out_ PULONGLONG pullMaxVersion) = 0;
-};
-#endif
-
-// Class declarations
-//
-EXTERN_C const CLSID CLSID_SetupConfiguration;
-
-#ifdef __cplusplus
-/// <summary>
-/// This class implements <see cref="ISetupConfiguration"/>, <see
-/// cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>.
-/// </summary>
-class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration;
-#endif
-
-// Function declarations
-//
-/// <summary>
-/// Gets an <see cref="ISetupConfiguration"/> that provides information about
-/// product instances installed on the machine.
-/// </summary>
-/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that
-/// provides information about product instances installed on the
-/// machine.</param>
-/// <param name="pReserved">Reserved for future use.</param>
-/// <returns>Standard HRESULT indicating success or failure.</returns>
-STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration,
- _Reserved_ LPVOID pReserved);
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp
index ceeaa79bc202..067758c05e97 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -86,9 +86,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
CmdArgs.push_back("-lmoldname");
CmdArgs.push_back("-lmingwex");
for (auto Lib : Args.getAllArgValues(options::OPT_l))
- if (StringRef(Lib).startswith("msvcr") ||
- StringRef(Lib).startswith("ucrt") ||
- StringRef(Lib).startswith("crtdll"))
+ if (StringRef(Lib).starts_with("msvcr") ||
+ StringRef(Lib).starts_with("ucrt") ||
+ StringRef(Lib).starts_with("crtdll"))
return;
CmdArgs.push_back("-lmsvcrt");
}
@@ -135,7 +135,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("arm64pe");
break;
default:
- llvm_unreachable("Unsupported target architecture.");
+ D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str();
}
Arg *SubsysArg =
@@ -169,6 +169,21 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
+ if (!Args.hasFlag(options::OPT_fauto_import, options::OPT_fno_auto_import,
+ true))
+ CmdArgs.push_back("--disable-auto-import");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) {
+ StringRef GuardArgs = A->getValue();
+ if (GuardArgs == "none")
+ CmdArgs.push_back("--no-guard-cf");
+ else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks")
+ CmdArgs.push_back("--guard-cf");
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << GuardArgs;
+ }
+
CmdArgs.push_back("-o");
const char *OutputFile = Output.getFilename();
// GCC implicitly adds an .exe extension if it is given an output file name
@@ -181,13 +196,21 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
} else
CmdArgs.push_back(OutputFile);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
// FIXME: add -N, -n flags
Args.AddLastArg(CmdArgs, options::OPT_r);
Args.AddLastArg(CmdArgs, options::OPT_s);
Args.AddLastArg(CmdArgs, options::OPT_t);
Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
- Args.AddLastArg(CmdArgs, options::OPT_Z_Flag);
+
+ // Add asan_dynamic as the first import lib before other libs. This allows
+ // asan to be initialized as early as possible to increase its instrumentation
+ // coverage to include other user DLLs which has not been built with asan.
+ if (Sanitize.needsAsanRt() && !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ // MinGW always links against a shared MSVCRT.
+ CmdArgs.push_back(
+ TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared));
+ }
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
@@ -218,6 +241,17 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ addLTOOptions(TC, Args, CmdArgs, Output, Inputs[0],
+ D.getLTOMode() == LTOK_Thin);
+ }
+
+ if (C.getDriver().IsFlangMode()) {
+ addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
+ addFortranRuntimeLibs(TC, Args, CmdArgs);
+ }
+
// TODO: Add profile stuff here
if (TC.ShouldLinkCXXStdlib(Args)) {
@@ -332,10 +366,20 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
+static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) {
+ llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE));
+ if (HostTriple.getOS() != llvm::Triple::Win32)
+ return true;
+ if (RequireArchMatch && HostTriple.getArch() != T.getArch())
+ return true;
+ return false;
+}
+
// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
- std::string &Ver) {
- auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
+ std::string &Ver,
+ toolchains::Generic_GCC::GCCVersion &Version) {
+ Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
std::error_code EC;
for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
LI = LI.increment(EC)) {
@@ -353,20 +397,33 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
return Ver.size();
}
-void toolchains::MinGW::findGccLibDir() {
- llvm::SmallVector<llvm::SmallString<32>, 2> SubdirNames;
+static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) {
+ llvm::Triple LiteralTriple(D.getTargetTriple());
+ // The arch portion of the triple may be overridden by -m32/-m64.
+ LiteralTriple.setArchName(T.getArchName());
+ return LiteralTriple;
+}
+
+void toolchains::MinGW::findGccLibDir(const llvm::Triple &LiteralTriple) {
+ llvm::SmallVector<llvm::SmallString<32>, 5> SubdirNames;
+ SubdirNames.emplace_back(LiteralTriple.str());
+ SubdirNames.emplace_back(getTriple().str());
SubdirNames.emplace_back(getTriple().getArchName());
- SubdirNames[0] += "-w64-mingw32";
+ SubdirNames.back() += "-w64-mingw32";
+ SubdirNames.emplace_back(getTriple().getArchName());
+ SubdirNames.back() += "-w64-mingw32ucrt";
SubdirNames.emplace_back("mingw32");
- if (SubdirName.empty())
- SubdirName = std::string(SubdirNames[0].str());
+ if (SubdirName.empty()) {
+ SubdirName = getTriple().getArchName();
+ SubdirName += "-w64-mingw32";
+ }
// lib: Arch Linux, Ubuntu, Windows
// lib64: openSUSE Linux
for (StringRef CandidateLib : {"lib", "lib64"}) {
for (StringRef CandidateSysroot : SubdirNames) {
llvm::SmallString<1024> LibDir(Base);
llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot);
- if (findGccVersion(LibDir, GccLibDir, Ver)) {
+ if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) {
SubdirName = std::string(CandidateSysroot);
return;
}
@@ -374,10 +431,17 @@ void toolchains::MinGW::findGccLibDir() {
}
}
-static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) {
- llvm::SmallVector<llvm::SmallString<32>, 2> Gccs;
+static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &LiteralTriple,
+ const llvm::Triple &T) {
+ llvm::SmallVector<llvm::SmallString<32>, 5> Gccs;
+ Gccs.emplace_back(LiteralTriple.str());
+ Gccs.back() += "-gcc";
+ Gccs.emplace_back(T.str());
+ Gccs.back() += "-gcc";
+ Gccs.emplace_back(T.getArchName());
+ Gccs.back() += "-w64-mingw32-gcc";
Gccs.emplace_back(T.getArchName());
- Gccs[0] += "-w64-mingw32-gcc";
+ Gccs.back() += "-w64-mingw32ucrt-gcc";
Gccs.emplace_back("mingw32-gcc");
// Please do not add "gcc" here
for (StringRef CandidateGcc : Gccs)
@@ -387,12 +451,15 @@ static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) {
}
static llvm::ErrorOr<std::string>
-findClangRelativeSysroot(const Driver &D, const llvm::Triple &T,
- std::string &SubdirName) {
- llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs;
+findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple,
+ const llvm::Triple &T, std::string &SubdirName) {
+ llvm::SmallVector<llvm::SmallString<32>, 4> Subdirs;
+ Subdirs.emplace_back(LiteralTriple.str());
Subdirs.emplace_back(T.str());
Subdirs.emplace_back(T.getArchName());
- Subdirs[1] += "-w64-mingw32";
+ Subdirs.back() += "-w64-mingw32";
+ Subdirs.emplace_back(T.getArchName());
+ Subdirs.back() += "-w64-mingw32ucrt";
StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir());
StringRef Sep = llvm::sys::path::get_separator();
for (StringRef CandidateSubdir : Subdirs) {
@@ -404,46 +471,77 @@ findClangRelativeSysroot(const Driver &D, const llvm::Triple &T,
return make_error_code(std::errc::no_such_file_or_directory);
}
+static bool looksLikeMinGWSysroot(const std::string &Directory) {
+ StringRef Sep = llvm::sys::path::get_separator();
+ if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h"))
+ return false;
+ if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a"))
+ return false;
+ return true;
+}
+
toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
RocmInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
+ std::string InstallBase =
+ std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir()));
// The sequence for detecting a sysroot here should be kept in sync with
// the testTriple function below.
+ llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple());
if (getDriver().SysRoot.size())
Base = getDriver().SysRoot;
// Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the
// base as it could still be a base for a gcc setup with libgcc.
- else if (llvm::ErrorOr<std::string> TargetSubdir =
- findClangRelativeSysroot(getDriver(), getTriple(), SubdirName))
+ else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(
+ getDriver(), LiteralTriple, getTriple(), SubdirName))
Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get()));
- else if (llvm::ErrorOr<std::string> GPPName = findGcc(getTriple()))
+ // If the install base of Clang seems to have mingw sysroot files directly
+ // in the toplevel include and lib directories, use this as base instead of
+ // looking for a triple prefixed GCC in the path.
+ else if (looksLikeMinGWSysroot(InstallBase))
+ Base = InstallBase;
+ else if (llvm::ErrorOr<std::string> GPPName =
+ findGcc(LiteralTriple, getTriple()))
Base = std::string(llvm::sys::path::parent_path(
llvm::sys::path::parent_path(GPPName.get())));
else
- Base = std::string(
- llvm::sys::path::parent_path(getDriver().getInstalledDir()));
+ Base = InstallBase;
Base += llvm::sys::path::get_separator();
- findGccLibDir();
+ findGccLibDir(LiteralTriple);
+ TripleDirName = SubdirName;
// GccLibDir must precede Base/lib so that the
// correct crtbegin.o ,cetend.o would be found.
getFilePaths().push_back(GccLibDir);
+
+ // openSUSE/Fedora
+ std::string CandidateSubdir = SubdirName + "/sys-root/mingw";
+ if (getDriver().getVFS().exists(Base + CandidateSubdir))
+ SubdirName = CandidateSubdir;
+
getFilePaths().push_back(
(Base + SubdirName + llvm::sys::path::get_separator() + "lib").str());
- getFilePaths().push_back(Base + "lib");
- // openSUSE
- getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib");
+
+ // Gentoo
+ getFilePaths().push_back(
+ (Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str());
+
+ // Only include <base>/lib if we're not cross compiling (not even for
+ // windows->windows to a different arch), or if the sysroot has been set
+ // (where we presume the user has pointed it at an arch specific
+ // subdirectory).
+ if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) ||
+ getDriver().SysRoot.size())
+ getFilePaths().push_back(Base + "lib");
NativeLLVMSupport =
Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER)
.equals_insensitive("lld");
}
-bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; }
-
Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const {
switch (AC) {
case Action::PreprocessJobClass:
@@ -471,15 +569,19 @@ bool toolchains::MinGW::HasNativeLLVMSupport() const {
return NativeLLVMSupport;
}
-bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+toolchains::MinGW::getDefaultUnwindTableLevel(const ArgList &Args) const {
Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions,
options::OPT_fseh_exceptions,
options::OPT_fdwarf_exceptions);
if (ExceptionArg &&
ExceptionArg->getOption().matches(options::OPT_fseh_exceptions))
- return true;
- return getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64;
+ return UnwindTableLevel::Asynchronous;
+
+ if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
+ getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
+ return UnwindTableLevel::Asynchronous;
+ return UnwindTableLevel::None;
}
bool toolchains::MinGW::isPICDefault() const {
@@ -495,7 +597,8 @@ bool toolchains::MinGW::isPICDefaultForced() const { return true; }
llvm::ExceptionHandling
toolchains::MinGW::GetExceptionModel(const ArgList &Args) const {
- if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64)
+ if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64 ||
+ getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb)
return llvm::ExceptionHandling::WinEH;
return llvm::ExceptionHandling::DwarfCFI;
}
@@ -511,17 +614,17 @@ SanitizerMask toolchains::MinGW::getSupportedSanitizers() const {
void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+ CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
}
void toolchains::MinGW::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+ RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
- RocmInstallation.print(OS);
+ CudaInstallation->print(OS);
+ RocmInstallation->print(OS);
}
// Include directories for various hosts:
@@ -564,6 +667,12 @@ void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const {
// /usr/include/c++/4.8/backward
// /usr/x86_64-w64-mingw32/include
+// Fedora
+// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/x86_64-w64-mingw32ucrt
+// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/backward
+// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include
+// /usr/lib/gcc/x86_64-w64-mingw32ucrt/12.2.1/include-fixed
+
void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc))
@@ -578,22 +687,55 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
- if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
- // openSUSE
- addSystemInclude(DriverArgs, CC1Args,
- Base + SubdirName + "/sys-root/mingw/include");
- }
-
addSystemInclude(DriverArgs, CC1Args,
Base + SubdirName + llvm::sys::path::get_separator() +
"include");
- addSystemInclude(DriverArgs, CC1Args, Base + "include");
+
+ // Gentoo
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + SubdirName + llvm::sys::path::get_separator() + "usr/include");
+
+ // Only include <base>/include if we're not cross compiling (but do allow it
+ // if we're on Windows and building for Windows on another architecture),
+ // or if the sysroot has been set (where we presume the user has pointed it
+ // at an arch specific subdirectory).
+ if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/false) ||
+ getDriver().SysRoot.size())
+ addSystemInclude(DriverArgs, CC1Args, Base + "include");
+}
+
+void toolchains::MinGW::addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const {
+ if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) {
+ StringRef GuardArgs = A->getValue();
+ if (GuardArgs == "none") {
+ // Do nothing.
+ } else if (GuardArgs == "cf") {
+ // Emit CFG instrumentation and the table of address-taken functions.
+ CC1Args.push_back("-cfguard");
+ } else if (GuardArgs == "cf-nochecks") {
+ // Emit only the table of address-taken functions.
+ CC1Args.push_back("-cfguard-no-checks");
+ } else {
+ getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << GuardArgs;
+ }
+ }
+
+ CC1Args.push_back("-fno-use-init-array");
+
+ for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows,
+ options::OPT_mconsole, options::OPT_mdll}) {
+ if (Arg *A = DriverArgs.getLastArgNoClaim(Opt))
+ A->ignoreTargetSpecific();
+ }
}
void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
StringRef Slash = llvm::sys::path::get_separator();
@@ -614,7 +756,7 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
}
case ToolChain::CST_Libstdcxx:
- llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
+ llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases;
CppIncludeBases.emplace_back(Base);
llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++");
CppIncludeBases.emplace_back(Base);
@@ -624,10 +766,19 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
CppIncludeBases.emplace_back(GccLibDir);
llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[4], "include",
+ "g++-v" + GccVer.Text);
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[5], "include",
+ "g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr);
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[6], "include",
+ "g++-v" + GccVer.MajorStr);
for (auto &CppIncludeBase : CppIncludeBases) {
addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
CppIncludeBase += Slash;
- addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + SubdirName);
+ addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName);
addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
}
break;
@@ -641,10 +792,17 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple,
std::string SubdirName;
if (D.SysRoot.size())
return true;
+ llvm::Triple LiteralTriple = getLiteralTriple(D, Triple);
+ std::string InstallBase =
+ std::string(llvm::sys::path::parent_path(D.getInstalledDir()));
if (llvm::ErrorOr<std::string> TargetSubdir =
- findClangRelativeSysroot(D, Triple, SubdirName))
+ findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName))
return true;
- if (llvm::ErrorOr<std::string> GPPName = findGcc(Triple))
+ // If the install base itself looks like a mingw sysroot, we'll use that
+ // - don't use any potentially unrelated gcc to influence what triple to use.
+ if (looksLikeMinGWSysroot(InstallBase))
+ return false;
+ if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple))
return true;
// If we neither found a colocated sysroot or a matching gcc executable,
// conclude that we can't know if this is the correct spelling of the triple.
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h
index c9553b4f4652..a9963d8d06c2 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h
@@ -11,6 +11,7 @@
#include "Cuda.h"
#include "Gnu.h"
+#include "LazyDetector.h"
#include "ROCm.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
@@ -20,7 +21,7 @@ namespace clang {
namespace driver {
namespace tools {
-/// MinGW -- Directly call GNU Binutils assembler and linker
+/// Directly call GNU Binutils assembler and linker
namespace MinGW {
class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
public:
@@ -34,7 +35,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {}
@@ -65,8 +66,8 @@ public:
bool HasNativeLLVMSupport() const override;
- bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
@@ -79,6 +80,10 @@ public:
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -98,16 +103,18 @@ protected:
Tool *buildAssembler() const override;
private:
- CudaInstallationDetector CudaInstallation;
- RocmInstallationDetector RocmInstallation;
+ LazyDetector<CudaInstallationDetector> CudaInstallation;
+ LazyDetector<RocmInstallationDetector> RocmInstallation;
std::string Base;
std::string GccLibDir;
+ clang::driver::toolchains::Generic_GCC::GCCVersion GccVer;
std::string Ver;
std::string SubdirName;
+ std::string TripleDirName;
mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
- void findGccLibDir();
+ void findGccLibDir(const llvm::Triple &LiteralTriple);
bool NativeLLVMSupport;
};
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp
deleted file mode 100644
index 5bceb9aba3e9..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-//===--- Minix.cpp - Minix ToolChain Implementations ------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Minix.h"
-#include "CommonArgs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/InputInfo.h"
-#include "clang/Driver/Options.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/VirtualFileSystem.h"
-
-using namespace clang::driver;
-using namespace clang;
-using namespace llvm::opt;
-
-void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileCurCP(),
- Exec, CmdArgs, Inputs, Output));
-}
-
-void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
- }
-
- Args.AddAllArgs(CmdArgs,
- {options::OPT_L, options::OPT_T_Group, options::OPT_e});
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- getToolChain().addProfileRTLibs(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX()) {
- if (getToolChain().ShouldLinkCXXStdlib(Args))
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lm");
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lCompilerRT-Generic");
- CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib");
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- }
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(std::make_unique<Command>(JA, *this,
- ResponseFileSupport::AtFileCurCP(),
- Exec, CmdArgs, Inputs, Output));
-}
-
-/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
-
-toolchains::Minix::Minix(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
-}
-
-Tool *toolchains::Minix::buildAssembler() const {
- return new tools::minix::Assembler(*this);
-}
-
-Tool *toolchains::Minix::buildLinker() const {
- return new tools::minix::Linker(*this);
-}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h
deleted file mode 100644
index af8d59c5085a..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h
+++ /dev/null
@@ -1,64 +0,0 @@
-//===--- Minix.h - Minix ToolChain Implementations --------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H
-
-#include "Gnu.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Driver/ToolChain.h"
-
-namespace clang {
-namespace driver {
-namespace tools {
-/// minix -- Directly call GNU Binutils assembler and linker
-namespace minix {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("minix::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("minix::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace minix
-} // end namespace tools
-
-namespace toolchains {
-
-class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
-public:
- Minix(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-} // end namespace toolchains
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp
index 41b7b839f3b3..4183eccceedb 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp
@@ -30,7 +30,7 @@ MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D,
DetectedMultilibs Result;
findMIPSMultilibs(D, Triple, "", Args, Result);
Multilibs = Result.Multilibs;
- SelectedMultilib = Result.SelectedMultilib;
+ SelectedMultilibs = Result.SelectedMultilibs;
// Find out the library suffix based on the ABI.
LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple);
@@ -56,7 +56,7 @@ void MipsLLVMToolChain::AddClangSystemIncludeArgs(
const auto &Callback = Multilibs.includeDirsCallback();
if (Callback) {
- for (const auto &Path : Callback(SelectedMultilib))
+ for (const auto &Path : Callback(SelectedMultilibs.back()))
addExternCSystemIncludeIfExists(DriverArgs, CC1Args,
D.getInstalledDir() + Path);
}
@@ -68,11 +68,11 @@ Tool *MipsLLVMToolChain::buildLinker() const {
std::string MipsLLVMToolChain::computeSysRoot() const {
if (!getDriver().SysRoot.empty())
- return getDriver().SysRoot + SelectedMultilib.osSuffix();
+ return getDriver().SysRoot + SelectedMultilibs.back().osSuffix();
const std::string InstalledDir(getDriver().getInstalledDir());
std::string SysRootPath =
- InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix();
+ InstalledDir + "/../sysroot" + SelectedMultilibs.back().osSuffix();
if (llvm::sys::fs::exists(SysRootPath))
return SysRootPath;
@@ -96,7 +96,7 @@ void MipsLLVMToolChain::addLibCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
if (const auto &Callback = Multilibs.includeDirsCallback()) {
- for (std::string Path : Callback(SelectedMultilib)) {
+ for (std::string Path : Callback(SelectedMultilibs.back())) {
Path = getDriver().getInstalledDir() + Path + "/c++/v1";
if (llvm::sys::fs::exists(Path)) {
addSystemInclude(DriverArgs, CC1Args, Path);
@@ -112,6 +112,8 @@ void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
"Only -lc++ (aka libxx) is supported in this toolchain.");
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
CmdArgs.push_back("-lunwind");
}
@@ -120,7 +122,7 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args,
StringRef Component,
FileType Type) const {
SmallString<128> Path(getDriver().ResourceDir);
- llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix,
+ llvm::sys::path::append(Path, SelectedMultilibs.back().osSuffix(), "lib" + LibSuffix,
getOS());
const char *Suffix;
switch (Type) {
@@ -136,5 +138,5 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args,
}
llvm::sys::path::append(
Path, Twine("libclang_rt." + Component + "-" + "mips" + Suffix));
- return std::string(Path.str());
+ return std::string(Path);
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h
index 31b547c0063c..a968804f2a6e 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h
@@ -53,7 +53,6 @@ public:
}
private:
- Multilib SelectedMultilib;
std::string LibSuffix;
};
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp
deleted file mode 100644
index f31466633104..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-//===--- Myriad.cpp - Myriad ToolChain Implementations ----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Myriad.h"
-#include "CommonArgs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Options.h"
-#include "llvm/Option/ArgList.h"
-
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-using tools::addPathIfExists;
-
-void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
- assert(Inputs.size() == 1);
- const InputInfo &II = Inputs[0];
- assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX ||
- II.getType() == types::TY_PP_CXX);
-
- if (JA.getKind() == Action::PreprocessJobClass) {
- Args.ClaimAllArgs();
- CmdArgs.push_back("-E");
- } else {
- assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm.
- CmdArgs.push_back("-S");
- CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified.
- }
- CmdArgs.push_back("-DMYRIAD2");
-
- // Append all -I, -iquote, -isystem paths, defines/undefines, 'f'
- // flags, 'g' flags, 'M' flags, optimize flags, warning options,
- // mcpu flags, mllvm flags, and Xclang flags.
- // These are spelled the same way in clang and moviCompile.
- Args.AddAllArgsExcept(
- CmdArgs,
- {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ,
- options::OPT_D, options::OPT_U, options::OPT_f_Group,
- options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group,
- options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ,
- options::OPT_mllvm, options::OPT_Xclang},
- {options::OPT_fno_split_dwarf_inlining});
- Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present.
-
- // If we're producing a dependency file, and assembly is the final action,
- // then the name of the target in the dependency file should be the '.o'
- // file, not the '.s' file produced by this step. For example, instead of
- // /tmp/mumble.s: mumble.c .../someheader.h
- // the filename on the lefthand side should be "mumble.o"
- if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) &&
- C.getActions().size() == 1 &&
- C.getActions()[0]->getKind() == Action::AssembleJobClass) {
- Arg *A = Args.getLastArg(options::OPT_o);
- if (A) {
- CmdArgs.push_back("-MT");
- CmdArgs.push_back(Args.MakeArgString(A->getValue()));
- }
- }
-
- CmdArgs.push_back(II.getFilename());
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- std::string Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("moviCompile"));
- C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
- Args.MakeArgString(Exec), CmdArgs,
- Inputs, Output));
-}
-
-void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1);
- const InputInfo &II = Inputs[0];
- assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input.
- assert(Output.getType() == types::TY_Object);
-
- CmdArgs.push_back("-no6thSlotCompression");
- const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
- if (CPUArg)
- CmdArgs.push_back(
- Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue())));
- CmdArgs.push_back("-noSPrefixing");
- CmdArgs.push_back("-a"); // Mystery option.
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
- for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) {
- A->claim();
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-i:") + A->getValue(0)));
- }
- CmdArgs.push_back(II.getFilename());
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-o:") + Output.getFilename()));
-
- std::string Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("moviAsm"));
- C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
- Args.MakeArgString(Exec), CmdArgs,
- Inputs, Output));
-}
-
-void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const auto &TC =
- static_cast<const toolchains::MyriadToolChain &>(getToolChain());
- const llvm::Triple &T = TC.getTriple();
- ArgStringList CmdArgs;
- bool UseStartfiles =
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
- bool UseDefaultLibs =
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs);
- // Silence warning if the args contain both -nostdlib and -stdlib=.
- Args.getLastArg(options::OPT_stdlib_EQ);
-
- if (T.getArch() == llvm::Triple::sparc)
- CmdArgs.push_back("-EB");
- else // SHAVE assumes little-endian, and sparcel is expressly so.
- CmdArgs.push_back("-EL");
-
- // The remaining logic is mostly like gnutools::Linker::ConstructJob,
- // but we never pass through a --sysroot option and various other bits.
- // For example, there are no sanitizers (yet) nor gold linker.
-
- // Eat some arguments that may be present but have no effect.
- Args.ClaimAllArgs(options::OPT_g_Group);
- Args.ClaimAllArgs(options::OPT_w);
- Args.ClaimAllArgs(options::OPT_static_libgcc);
-
- if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option.
- CmdArgs.push_back("-s");
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- if (UseStartfiles) {
- // If you want startfiles, it means you want the builtin crti and crtbegin,
- // but not crt0. Myriad link commands provide their own crt0.o as needed.
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
- }
-
- Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
- options::OPT_e, options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_r});
-
- TC.AddFilePathLibArgs(Args, CmdArgs);
-
- bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs);
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- if (UseDefaultLibs) {
- if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(TC, CmdArgs);
- if (C.getDriver().CCCIsCXX()) {
- if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) {
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- } else
- CmdArgs.push_back("-lstdc++");
- }
- if (T.getOS() == llvm::Triple::RTEMS) {
- CmdArgs.push_back("--start-group");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc"); // circularly dependent on rtems
- // You must provide your own "-L" option to enable finding these.
- CmdArgs.push_back("-lrtemscpu");
- CmdArgs.push_back("-lrtemsbsp");
- CmdArgs.push_back("--end-group");
- } else {
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- }
- }
- if (UseStartfiles) {
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o")));
- }
-
- std::string Exec =
- Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Exec),
- CmdArgs, Inputs, Output));
-}
-
-MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use
- // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple.
- // This won't work to find gcc. Instead we give the installation detector an
- // extra triple, which is preferable to further hacks of the logic that at
- // present is based solely on getArch(). In particular, it would be wrong to
- // choose the myriad installation when targeting a non-myriad sparc install.
- switch (Triple.getArch()) {
- default:
- D.Diag(clang::diag::err_target_unsupported_arch)
- << Triple.getArchName() << "myriad";
- LLVM_FALLTHROUGH;
- case llvm::Triple::shave:
- return;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- GCCInstallation.init(Triple, Args, {"sparc-myriad-rtems"});
- }
-
- if (GCCInstallation.isValid()) {
- // This directory contains crt{i,n,begin,end}.o as well as libgcc.
- // These files are tied to a particular version of gcc.
- SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath());
- addPathIfExists(D, CompilerSupportDir, getFilePaths());
- }
- // libstd++ and libc++ must both be found in this one place.
- addPathIfExists(D, D.Dir + "/../sparc-myriad-rtems/lib", getFilePaths());
-}
-
-MyriadToolChain::~MyriadToolChain() {}
-
-void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
- addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
-}
-
-void MyriadToolChain::addLibCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- std::string Path(getDriver().getInstalledDir());
- addSystemInclude(DriverArgs, CC1Args, Path + "/../include/c++/v1");
-}
-
-void MyriadToolChain::addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- StringRef LibDir = GCCInstallation.getParentLibPath();
- const GCCVersion &Version = GCCInstallation.getVersion();
- StringRef TripleStr = GCCInstallation.getTriple().str();
- const Multilib &Multilib = GCCInstallation.getMultilib();
- addLibStdCXXIncludePaths(
- LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
- TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args);
-}
-
-// MyriadToolChain handles several triples:
-// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf
-Tool *MyriadToolChain::SelectTool(const JobAction &JA) const {
- // The inherited method works fine if not targeting the SHAVE.
- if (!isShaveCompilation(getTriple()))
- return ToolChain::SelectTool(JA);
- switch (JA.getKind()) {
- case Action::PreprocessJobClass:
- case Action::CompileJobClass:
- if (!Compiler)
- Compiler.reset(new tools::SHAVE::Compiler(*this));
- return Compiler.get();
- case Action::AssembleJobClass:
- if (!Assembler)
- Assembler.reset(new tools::SHAVE::Assembler(*this));
- return Assembler.get();
- default:
- return ToolChain::getTool(JA.getKind());
- }
-}
-
-Tool *MyriadToolChain::buildLinker() const {
- return new tools::Myriad::Linker(*this);
-}
-
-SanitizerMask MyriadToolChain::getSupportedSanitizers() const {
- return SanitizerKind::Address;
-}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h
deleted file mode 100644
index cae574bdcfea..000000000000
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h
+++ /dev/null
@@ -1,103 +0,0 @@
-//===--- Myriad.h - Myriad ToolChain Implementations ------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H
-
-#include "Gnu.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Driver/ToolChain.h"
-
-namespace clang {
-namespace driver {
-namespace tools {
-
-/// SHAVE tools -- Directly call moviCompile and moviAsm
-namespace SHAVE {
-class LLVM_LIBRARY_VISIBILITY Compiler : public Tool {
-public:
- Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {}
-
- bool hasIntegratedCPP() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {}
-
- bool hasIntegratedCPP() const override { return false; } // not sure.
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace SHAVE
-
-/// The Myriad toolchain uses tools that are in two different namespaces.
-/// The Compiler and Assembler as defined above are in the SHAVE namespace,
-/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE,
-/// is in the Myriad namespace.
-namespace Myriad {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("shave::Linker", "ld", TC) {}
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace Myriad
-} // end namespace tools
-
-namespace toolchains {
-
-/// MyriadToolChain - A tool chain using either clang or the external compiler
-/// installed by the Movidius SDK to perform all subcommands.
-class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF {
-public:
- MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~MyriadToolChain() override;
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void addLibCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- Tool *SelectTool(const JobAction &JA) const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- SanitizerMask getSupportedSanitizers() const override;
-
-protected:
- Tool *buildLinker() const override;
- bool isShaveCompilation(const llvm::Triple &T) const {
- return T.getArch() == llvm::Triple::shave;
- }
-
-private:
- mutable std::unique_ptr<Tool> Compiler;
- mutable std::unique_ptr<Tool> Assembler;
-};
-
-} // end namespace toolchains
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp
index 753459cb230b..22f038e5152f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp
@@ -31,8 +31,7 @@ void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::NaClToolChain &ToolChain =
- static_cast<const toolchains::NaClToolChain &>(getToolChain());
+ const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain());
InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(),
"nacl-arm-macros.s");
InputInfoList NewInputs;
@@ -52,8 +51,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::NaClToolChain &ToolChain =
- static_cast<const toolchains::NaClToolChain &>(getToolChain());
+ const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool IsStatic =
@@ -120,8 +118,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
@@ -308,6 +305,8 @@ void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
// if the value is libc++, and emits an error for other values.
GetCXXStdlibType(Args);
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
}
void NaClToolChain::addLibCxxIncludePaths(
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h
index 5e5fdb583bb6..01d4719e7b92 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h
@@ -27,7 +27,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("NaCl::Linker", "linker", TC) {}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp
index d1eda14a51f0..240bf5764b9c 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp
@@ -11,6 +11,7 @@
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
@@ -29,13 +30,12 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::NetBSD &ToolChain =
- static_cast<const toolchains::NetBSD &>(getToolChain());
+ const auto &ToolChain = static_cast<const NetBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
+ ArgStringList CmdArgs;
claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
// GNU as needs different flags for creating the correct output format
// on architectures with different ABIs or optional feature sets.
@@ -77,8 +77,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel: {
+ case llvm::Triple::sparc: {
CmdArgs.push_back("-32");
std::string CPU = getCPUName(D, Args, Triple);
CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));
@@ -117,29 +116,31 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::NetBSD &ToolChain =
- static_cast<const toolchains::NetBSD &>(getToolChain());
+ const auto &ToolChain = static_cast<const NetBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
-
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool Static = Args.hasArg(options::OPT_static);
+ const bool Shared = Args.hasArg(options::OPT_shared);
+ const bool Pie = Args.hasArg(options::OPT_pie);
ArgStringList CmdArgs;
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_static)) {
+ if (Static) {
CmdArgs.push_back("-Bstatic");
- if (Args.hasArg(options::OPT_pie)) {
+ if (Pie) {
Args.AddAllArgs(CmdArgs, options::OPT_pie);
CmdArgs.push_back("--no-dynamic-linker");
}
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
- } else {
+ if (Shared) {
+ CmdArgs.push_back("-shared");
+ } else if (!Args.hasArg(options::OPT_r)) {
Args.AddAllArgs(CmdArgs, options::OPT_pie);
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld.elf_so");
@@ -148,7 +149,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Many NetBSD architectures support more than one ABI.
// Determine the correct emulation for ld.
- switch (ToolChain.getArch()) {
+ switch (Arch) {
case llvm::Triple::x86:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
@@ -192,13 +193,13 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::mips64el:
if (mips::hasMipsAbiArg(Args, "32")) {
CmdArgs.push_back("-m");
- if (ToolChain.getArch() == llvm::Triple::mips64)
+ if (Arch == llvm::Triple::mips64)
CmdArgs.push_back("elf32btsmip");
else
CmdArgs.push_back("elf32ltsmip");
} else if (mips::hasMipsAbiArg(Args, "64")) {
CmdArgs.push_back("-m");
- if (ToolChain.getArch() == llvm::Triple::mips64)
+ if (Arch == llvm::Triple::mips64)
CmdArgs.push_back("elf64btsmip");
else
CmdArgs.push_back("elf64ltsmip");
@@ -215,6 +216,16 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf64ppc");
break;
+ case llvm::Triple::riscv32:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32lriscv");
+ break;
+
+ case llvm::Triple::riscv64:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64lriscv");
+ break;
+
case llvm::Triple::sparc:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32_sparc");
@@ -229,37 +240,36 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
+ if (Triple.isRISCV())
+ CmdArgs.push_back("-X");
+
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(
- Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
- }
- CmdArgs.push_back(
- Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) {
- CmdArgs.push_back(
- Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
- } else {
- CmdArgs.push_back(
- Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
- }
+ const char *crt0 = nullptr;
+ const char *crtbegin = nullptr;
+ if (!Shared)
+ crt0 = "crt0.o";
+
+ if (Shared || Pie)
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+
+ if (crt0)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_s, options::OPT_t, options::OPT_r});
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
@@ -271,35 +281,33 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath()));
}
- VersionTuple OsVersion = Triple.getOSVersion();
bool useLibgcc = true;
- if (OsVersion >= VersionTuple(7) || OsVersion.getMajor() == 0) {
- switch (ToolChain.getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcv9:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- useLibgcc = false;
- break;
- default:
- break;
- }
+ switch (ToolChain.getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ useLibgcc = false;
+ break;
+ default:
+ break;
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
options::OPT_r)) {
// Use the static OpenMP runtime with -static-openmp
- bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
- !Args.hasArg(options::OPT_static);
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
if (D.CCCIsCXX()) {
@@ -307,16 +315,30 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
+
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below (i.e.
+ // AddRunTimeLibs).
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+
if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+ linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
if (NeedsXRayDeps)
- linkXRayRuntimeDeps(ToolChain, CmdArgs);
+ linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
if (useLibgcc) {
- if (Args.hasArg(options::OPT_static)) {
+ if (Static) {
// libgcc_eh depends on libc, so resolve as much as possible,
// pull in any new requirements from libc and then get the rest
// of libgcc.
@@ -334,12 +356,13 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+ const char *crtend = nullptr;
+ if (Shared || Pie)
+ crtend = "crtendS.o";
else
- CmdArgs.push_back(
- Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ crtend = "crtend.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
@@ -363,7 +386,7 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// what all logic is needed to emulate the '=' prefix here.
switch (Triple.getArch()) {
case llvm::Triple::x86:
- getFilePaths().push_back("=/usr/lib/i386");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/i386"));
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
@@ -372,35 +395,35 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
switch (Triple.getEnvironment()) {
case llvm::Triple::EABI:
case llvm::Triple::GNUEABI:
- getFilePaths().push_back("=/usr/lib/eabi");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabi"));
break;
case llvm::Triple::EABIHF:
case llvm::Triple::GNUEABIHF:
- getFilePaths().push_back("=/usr/lib/eabihf");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabihf"));
break;
default:
- getFilePaths().push_back("=/usr/lib/oabi");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/oabi"));
break;
}
break;
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
if (tools::mips::hasMipsAbiArg(Args, "o32"))
- getFilePaths().push_back("=/usr/lib/o32");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/o32"));
else if (tools::mips::hasMipsAbiArg(Args, "64"))
- getFilePaths().push_back("=/usr/lib/64");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/64"));
break;
case llvm::Triple::ppc:
- getFilePaths().push_back("=/usr/lib/powerpc");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/powerpc"));
break;
case llvm::Triple::sparc:
- getFilePaths().push_back("=/usr/lib/sparc");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/sparc"));
break;
default:
break;
}
- getFilePaths().push_back("=/usr/lib");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
}
}
@@ -411,39 +434,72 @@ Tool *NetBSD::buildAssembler() const {
Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); }
ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {
- VersionTuple OsVersion = getTriple().getOSVersion();
- if (OsVersion >= VersionTuple(7) || OsVersion.getMajor() == 0) {
- switch (getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcv9:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return ToolChain::CST_Libcxx;
- default:
- break;
- }
+ switch (getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return ToolChain::CST_Libcxx;
+ default:
+ break;
}
return ToolChain::CST_Libstdcxx;
}
+void NetBSD::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ concat(D.SysRoot, "/usr/include"));
+}
+
void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const std::string Candidates[] = {
// directory relative to build tree
- getDriver().Dir + "/../include/c++/v1",
+ concat(getDriver().Dir, "/../include/c++/v1"),
// system install with full upstream path
- getDriver().SysRoot + "/usr/include/c++/v1",
+ concat(getDriver().SysRoot, "/usr/include/c++/v1"),
// system install from src
- getDriver().SysRoot + "/usr/include/c++",
+ concat(getDriver().SysRoot, "/usr/include/c++"),
};
for (const auto &IncludePath : Candidates) {
@@ -458,7 +514,7 @@ void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
- addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/g++", "", "",
+ addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/g++"), "", "",
DriverArgs, CC1Args);
}
@@ -479,7 +535,6 @@ SanitizerMask NetBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
- Res |= SanitizerKind::Function;
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Scudo;
@@ -512,7 +567,9 @@ void NetBSD::addClangTargetOptions(const ArgList &DriverArgs,
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::armeb;
+ getTriple().getArch() == llvm::Triple::armeb ||
+ 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))
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h
index 8348554fd149..96303acaa009 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h
@@ -17,9 +17,9 @@ namespace clang {
namespace driver {
namespace tools {
-/// netbsd -- Directly call GNU Binutils assembler and linker
+/// Directly call GNU Binutils assembler and linker
namespace netbsd {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC) : Tool("netbsd::Assembler", "assembler", TC) {}
@@ -31,7 +31,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("netbsd::Linker", "linker", TC) {}
@@ -58,6 +58,9 @@ public:
CXXStdlibType GetDefaultCXXStdlibType() const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
void addLibCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -65,8 +68,9 @@ public:
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
- return true;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
+ return UnwindTableLevel::Asynchronous;
}
llvm::ExceptionHandling GetExceptionModel(
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp
new file mode 100644
index 000000000000..1e50c9d71d59
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp
@@ -0,0 +1,419 @@
+//===--- OHOS.cpp - OHOS 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 "OHOS.h"
+#include "Arch/ARM.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+using namespace clang::driver::tools::arm;
+
+using tools::addMultilibFlag;
+using tools::addPathIfExists;
+
+static bool findOHOSMuslMultilibs(const Multilib::flags_list &Flags,
+ DetectedMultilibs &Result) {
+ MultilibSet Multilibs;
+ Multilibs.push_back(Multilib());
+ // -mcpu=cortex-a7
+ // -mfloat-abi=soft -mfloat-abi=softfp -mfloat-abi=hard
+ // -mfpu=neon-vfpv4
+ Multilibs.push_back(
+ Multilib("/a7_soft", {}, {}, {"-mcpu=cortex-a7", "-mfloat-abi=soft"}));
+
+ Multilibs.push_back(
+ Multilib("/a7_softfp_neon-vfpv4", {}, {},
+ {"-mcpu=cortex-a7", "-mfloat-abi=softfp", "-mfpu=neon-vfpv4"}));
+
+ Multilibs.push_back(
+ Multilib("/a7_hard_neon-vfpv4", {}, {},
+ {"-mcpu=cortex-a7", "-mfloat-abi=hard", "-mfpu=neon-vfpv4"}));
+
+ if (Multilibs.select(Flags, Result.SelectedMultilibs)) {
+ Result.Multilibs = Multilibs;
+ return true;
+ }
+ return false;
+}
+
+static bool findOHOSMultilibs(const Driver &D,
+ const ToolChain &TC,
+ const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ DetectedMultilibs &Result) {
+ Multilib::flags_list Flags;
+ bool IsA7 = false;
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ IsA7 = A->getValue() == StringRef("cortex-a7");
+ addMultilibFlag(IsA7, "-mcpu=cortex-a7", Flags);
+
+ bool IsMFPU = false;
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
+ IsMFPU = A->getValue() == StringRef("neon-vfpv4");
+ addMultilibFlag(IsMFPU, "-mfpu=neon-vfpv4", Flags);
+
+ tools::arm::FloatABI ARMFloatABI = getARMFloatABI(D, TargetTriple, Args);
+ addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Soft),
+ "-mfloat-abi=soft", Flags);
+ addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::SoftFP),
+ "-mfloat-abi=softfp", Flags);
+ addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Hard),
+ "-mfloat-abi=hard", Flags);
+
+ return findOHOSMuslMultilibs(Flags, Result);
+}
+
+std::string OHOS::getMultiarchTriple(const llvm::Triple &T) const {
+ // For most architectures, just use whatever we have rather than trying to be
+ // clever.
+ switch (T.getArch()) {
+ default:
+ break;
+
+ // We use the existence of '/lib/<triple>' as a directory to detect some
+ // common linux triples that don't quite match the Clang triple for both
+ // 32-bit and 64-bit targets. Multiarch fixes its install triples to these
+ // regardless of what the actual target triple is.
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ return T.isOSLiteOS() ? "arm-liteos-ohos" : "arm-linux-ohos";
+ case llvm::Triple::riscv32:
+ return "riscv32-linux-ohos";
+ case llvm::Triple::riscv64:
+ return "riscv64-linux-ohos";
+ case llvm::Triple::mipsel:
+ return "mipsel-linux-ohos";
+ case llvm::Triple::x86:
+ return "i686-linux-ohos";
+ case llvm::Triple::x86_64:
+ return "x86_64-linux-ohos";
+ case llvm::Triple::aarch64:
+ return "aarch64-linux-ohos";
+ }
+ return T.str();
+}
+
+std::string OHOS::getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) const {
+ return getMultiarchTriple(TargetTriple);
+}
+
+static std::string makePath(const std::initializer_list<std::string> &IL) {
+ SmallString<128> P;
+ for (const auto &S : IL)
+ llvm::sys::path::append(P, S);
+ return static_cast<std::string>(P.str());
+}
+
+/// OHOS Toolchain
+OHOS::OHOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ std::string SysRoot = computeSysRoot();
+
+ // Select the correct multilib according to the given arguments.
+ DetectedMultilibs Result;
+ findOHOSMultilibs(D, *this, Triple, "", Args, Result);
+ Multilibs = Result.Multilibs;
+ SelectedMultilibs = Result.SelectedMultilibs;
+ if (!SelectedMultilibs.empty()) {
+ SelectedMultilib = SelectedMultilibs.back();
+ }
+
+ getFilePaths().clear();
+ for (const auto &CandidateLibPath : getArchSpecificLibPaths())
+ if (getVFS().exists(CandidateLibPath))
+ getFilePaths().push_back(CandidateLibPath);
+
+ getLibraryPaths().clear();
+ for (auto &Path : getRuntimePaths())
+ if (getVFS().exists(Path))
+ getLibraryPaths().push_back(Path);
+
+ // OHOS sysroots contain a library directory for each supported OS
+ // version as well as some unversioned libraries in the usual multiarch
+ // directory. Support --target=aarch64-linux-ohosX.Y.Z or
+ // --target=aarch64-linux-ohosX.Y or --target=aarch64-linux-ohosX
+ path_list &Paths = getFilePaths();
+ std::string SysRootLibPath = makePath({SysRoot, "usr", "lib"});
+ std::string MultiarchTriple = getMultiarchTriple(getTriple());
+ addPathIfExists(D, makePath({SysRootLibPath, SelectedMultilib.gccSuffix()}),
+ Paths);
+ addPathIfExists(D,
+ makePath({D.Dir, "..", "lib", MultiarchTriple,
+ SelectedMultilib.gccSuffix()}),
+ Paths);
+
+ addPathIfExists(
+ D,
+ makePath({SysRootLibPath, MultiarchTriple, SelectedMultilib.gccSuffix()}),
+ Paths);
+}
+
+ToolChain::RuntimeLibType OHOS::GetRuntimeLibType(
+ const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value != "compiler-rt")
+ getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::CXXStdlibType
+OHOS::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value != "libc++")
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::CST_Libcxx;
+}
+
+void OHOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ const llvm::Triple &Triple = getTriple();
+ std::string SysRoot = computeSysRoot();
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ SysRoot + "/usr/include/" +
+ getMultiarchTriple(Triple));
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+}
+
+void OHOS::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx: {
+ std::string IncPath = makePath({getDriver().Dir, "..", "include"});
+ std::string IncTargetPath =
+ makePath({IncPath, getMultiarchTriple(getTriple()), "c++", "v1"});
+ if (getVFS().exists(IncTargetPath)) {
+ addSystemInclude(DriverArgs, CC1Args, makePath({IncPath, "c++", "v1"}));
+ addSystemInclude(DriverArgs, CC1Args, IncTargetPath);
+ }
+ break;
+ }
+
+ default:
+ llvm_unreachable("invalid stdlib name");
+ }
+}
+
+void OHOS::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ llvm_unreachable("invalid stdlib name");
+ }
+}
+
+std::string OHOS::computeSysRoot() const {
+ std::string SysRoot =
+ !getDriver().SysRoot.empty()
+ ? getDriver().SysRoot
+ : makePath({getDriver().getInstalledDir(), "..", "..", "sysroot"});
+ if (!llvm::sys::fs::exists(SysRoot))
+ return std::string();
+
+ std::string ArchRoot = makePath({SysRoot, getMultiarchTriple(getTriple())});
+ return llvm::sys::fs::exists(ArchRoot) ? ArchRoot : SysRoot;
+}
+
+ToolChain::path_list OHOS::getRuntimePaths() const {
+ SmallString<128> P;
+ path_list Paths;
+ const Driver &D = getDriver();
+ const llvm::Triple &Triple = getTriple();
+
+ // First try the triple passed to driver as --target=<triple>.
+ P.assign(D.ResourceDir);
+ llvm::sys::path::append(P, "lib", D.getTargetTriple(), SelectedMultilib.gccSuffix());
+ Paths.push_back(P.c_str());
+
+ // Second try the normalized triple.
+ P.assign(D.ResourceDir);
+ llvm::sys::path::append(P, "lib", Triple.str(), SelectedMultilib.gccSuffix());
+ Paths.push_back(P.c_str());
+
+ // Third try the effective triple.
+ P.assign(D.ResourceDir);
+ std::string SysRoot = computeSysRoot();
+ llvm::sys::path::append(P, "lib", getMultiarchTriple(Triple),
+ SelectedMultilib.gccSuffix());
+ Paths.push_back(P.c_str());
+
+ return Paths;
+}
+
+std::string OHOS::getDynamicLinker(const ArgList &Args) const {
+ const llvm::Triple &Triple = getTriple();
+ const llvm::Triple::ArchType Arch = getArch();
+
+ assert(Triple.isMusl());
+ std::string ArchName;
+ bool IsArm = false;
+
+ switch (Arch) {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ ArchName = "arm";
+ IsArm = true;
+ break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ ArchName = "armeb";
+ IsArm = true;
+ break;
+ default:
+ ArchName = Triple.getArchName().str();
+ }
+ if (IsArm &&
+ (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
+ ArchName += "hf";
+
+ return "/lib/ld-musl-" + ArchName + ".so.1";
+}
+
+std::string OHOS::getCompilerRT(const ArgList &Args, StringRef Component,
+ FileType Type) const {
+ SmallString<128> Path(getDriver().ResourceDir);
+ llvm::sys::path::append(Path, "lib", getMultiarchTriple(getTriple()),
+ SelectedMultilib.gccSuffix());
+ const char *Prefix =
+ Type == ToolChain::FT_Object ? "" : "lib";
+ const char *Suffix;
+ switch (Type) {
+ case ToolChain::FT_Object:
+ Suffix = ".o";
+ break;
+ case ToolChain::FT_Static:
+ Suffix = ".a";
+ break;
+ case ToolChain::FT_Shared:
+ Suffix = ".so";
+ break;
+ }
+ llvm::sys::path::append(
+ Path, Prefix + Twine("clang_rt.") + Component + Suffix);
+ return static_cast<std::string>(Path.str());
+}
+
+void OHOS::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("now");
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("relro");
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("max-page-size=4096");
+ // .gnu.hash section is not compatible with the MIPS target
+ if (getArch() != llvm::Triple::mipsel)
+ CmdArgs.push_back("--hash-style=both");
+#ifdef ENABLE_LINKER_BUILD_ID
+ CmdArgs.push_back("--build-id");
+#endif
+ CmdArgs.push_back("--enable-new-dtags");
+}
+
+SanitizerMask OHOS::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::PointerCompare;
+ Res |= SanitizerKind::PointerSubtract;
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::FuzzerNoLink;
+ Res |= SanitizerKind::Memory;
+ Res |= SanitizerKind::Vptr;
+ Res |= SanitizerKind::SafeStack;
+ Res |= SanitizerKind::Scudo;
+ // TODO: kASAN for liteos ??
+ // TODO: Support TSAN and HWASAN and update mask.
+ return Res;
+}
+
+// TODO: Make a base class for Linux and OHOS and move this there.
+void OHOS::addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ // Add linker option -u__llvm_profile_runtime to cause runtime
+ // initialization module to be linked in.
+ if (needsProfileRT(Args))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
+ ToolChain::addProfileRTLibs(Args, CmdArgs);
+}
+
+ToolChain::path_list OHOS::getArchSpecificLibPaths() const {
+ ToolChain::path_list Paths;
+ llvm::Triple Triple = getTriple();
+ Paths.push_back(
+ makePath({getDriver().ResourceDir, "lib", getMultiarchTriple(Triple)}));
+ return Paths;
+}
+
+ToolChain::UnwindLibType OHOS::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
+ if (Args.getLastArg(options::OPT_unwindlib_EQ))
+ return Generic_ELF::GetUnwindLibType(Args);
+ return GetDefaultUnwindLibType();
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h
new file mode 100644
index 000000000000..2a380420922d
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h
@@ -0,0 +1,95 @@
+//===--- OHOS.h - OHOS 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_OHOS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H
+
+#include "Linux.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY OHOS : public Generic_ELF {
+public:
+ OHOS(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool HasNativeLLVMSupport() const override { return true; }
+
+ bool IsMathErrnoDefault() const override { return false; }
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
+ // Not add -funwind-tables by default
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return true; }
+ bool isPICDefaultForced() const override { return false; }
+ UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override;
+ UnwindLibType GetDefaultUnwindLibType() const override { return UNW_CompilerRT; }
+
+ RuntimeLibType
+ GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
+ CXXStdlibType
+ GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ std::string computeSysRoot() const override;
+ std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override;
+
+ std::string
+ getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ FileType Type = ToolChain::FT_Static) const override;
+
+ const char *getDefaultLinker() const override {
+ return "ld.lld";
+ }
+
+ Tool *buildLinker() const override {
+ return new tools::gnutools::Linker(*this);
+ }
+ Tool *buildAssembler() const override {
+ return new tools::gnutools::Assembler(*this);
+ }
+
+ path_list getRuntimePaths() const;
+
+protected:
+ std::string getMultiarchTriple(const llvm::Triple &T) const;
+ std::string getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) const override;
+ void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const override;
+ SanitizerMask getSupportedSanitizers() const override;
+ void addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ path_list getArchSpecificLibPaths() const override;
+
+private:
+ Multilib SelectedMultilib;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp
index 86a10ce4b0e7..fd6aa4d7e684 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp
@@ -17,6 +17,7 @@
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -29,13 +30,12 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::OpenBSD &ToolChain =
- static_cast<const toolchains::OpenBSD &>(getToolChain());
+ const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
+ ArgStringList CmdArgs;
claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
switch (ToolChain.getArch()) {
case llvm::Triple::x86:
@@ -44,8 +44,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--32");
break;
- case llvm::Triple::arm:
- case llvm::Triple::armeb: {
+ case llvm::Triple::arm: {
StringRef MArch, MCPU;
arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true);
std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple);
@@ -110,9 +109,15 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::OpenBSD &ToolChain =
- static_cast<const toolchains::OpenBSD &>(getToolChain());
+ const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool Static = Args.hasArg(options::OPT_static);
+ const bool Shared = Args.hasArg(options::OPT_shared);
+ const bool Profiling = Args.hasArg(options::OPT_pg);
+ const bool Pie = Args.hasArg(options::OPT_pie);
+ const bool Nopie = Args.hasArg(options::OPT_no_pie, options::OPT_nopie);
+ const bool Relocatable = Args.hasArg(options::OPT_r);
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@@ -123,52 +128,55 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
- if (ToolChain.getArch() == llvm::Triple::mips64)
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Arch == llvm::Triple::mips64)
CmdArgs.push_back("-EB");
- else if (ToolChain.getArch() == llvm::Triple::mips64el)
+ else if (Arch == llvm::Triple::mips64el)
CmdArgs.push_back("-EL");
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_nostdlib) && !Shared && !Relocatable) {
CmdArgs.push_back("-e");
CmdArgs.push_back("__start");
}
CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_static)) {
+ if (Static) {
CmdArgs.push_back("-Bstatic");
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_shared)) {
+ if (Shared) {
CmdArgs.push_back("-shared");
- } else {
+ } else if (!Relocatable) {
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/usr/libexec/ld.so");
}
}
- if (Args.hasArg(options::OPT_pie))
+ if (Pie)
CmdArgs.push_back("-pie");
- if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg))
+ if (Nopie || Profiling)
CmdArgs.push_back("-nopie");
+ if (Arch == llvm::Triple::riscv64)
+ CmdArgs.push_back("-X");
+
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
const char *crt0 = nullptr;
const char *crtbegin = nullptr;
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
+ if (!Shared) {
+ if (Profiling)
crt0 = "gcrt0.o";
- else if (Args.hasArg(options::OPT_static) &&
- !Args.hasArg(options::OPT_nopie))
+ else if (Static && !Nopie)
crt0 = "rcrt0.o";
else
crt0 = "crt0.o";
@@ -184,9 +192,22 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e,
- options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_r});
+ Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_r});
+
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ // Find the first filename InputInfo object.
+ auto Input = llvm::find_if(
+ Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
+ if (Input == Inputs.end())
+ // For a very rare case, all of the inputs to the linker are
+ // InputArg. If that happens, just use the first InputInfo.
+ Input = Inputs.begin();
+
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
+ D.getLTOMode() == LTOK_Thin);
+ }
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
@@ -195,39 +216,55 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
options::OPT_r)) {
// Use the static OpenMP runtime with -static-openmp
- bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
- !Args.hasArg(options::OPT_static);
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
if (D.CCCIsCXX()) {
if (ToolChain.ShouldLinkCXXStdlib(Args))
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (Args.hasArg(options::OPT_pg))
+ if (Profiling)
CmdArgs.push_back("-lm_p");
else
CmdArgs.push_back("-lm");
}
+
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below (i.e.
+ // AddRunTimeLibs).
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
+ addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
+ if (Profiling)
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
+ }
+
if (NeedsSanitizerDeps) {
CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+ linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
}
if (NeedsXRayDeps) {
CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
- linkXRayRuntimeDeps(ToolChain, CmdArgs);
+ linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
}
// FIXME: For some reason GCC passes -lgcc before adding
// the default system libraries. Just mimic this for now.
CmdArgs.push_back("-lcompiler_rt");
if (Args.hasArg(options::OPT_pthread)) {
- if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
+ if (!Shared && Profiling)
CmdArgs.push_back("-lpthread_p");
else
CmdArgs.push_back("-lpthread");
}
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
+ if (!Shared) {
+ if (Profiling)
CmdArgs.push_back("-lc_p");
else
CmdArgs.push_back("-lc");
@@ -239,7 +276,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
const char *crtend = nullptr;
- if (!Args.hasArg(options::OPT_shared))
+ if (!Shared)
crtend = "crtend.o";
else
crtend = "crtendS.o";
@@ -258,16 +295,15 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
SanitizerMask OpenBSD::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
-
- // For future use, only UBsan at the moment
SanitizerMask Res = ToolChain::getSupportedSanitizers();
-
if (IsX86 || IsX86_64) {
Res |= SanitizerKind::Vptr;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
}
-
+ if (IsX86_64) {
+ Res |= SanitizerKind::KernelAddress;
+ }
return Res;
}
@@ -276,7 +312,7 @@ SanitizerMask OpenBSD::getSupportedSanitizers() const {
OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
- getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+ getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
}
void OpenBSD::AddClangSystemIncludeArgs(
@@ -309,13 +345,14 @@ void OpenBSD::AddClangSystemIncludeArgs(
return;
}
- addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ concat(D.SysRoot, "/usr/include"));
}
void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/include/c++/v1");
+ concat(getDriver().SysRoot, "/usr/include/c++/v1"));
}
void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
@@ -323,16 +360,27 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
bool Profiling = Args.hasArg(options::OPT_pg);
CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread");
}
-std::string OpenBSD::getCompilerRT(const ArgList &Args,
- StringRef Component,
+std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component,
FileType Type) const {
- SmallString<128> Path(getDriver().SysRoot);
- llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
- return std::string(Path.str());
+ if (Component == "builtins") {
+ SmallString<128> Path(getDriver().SysRoot);
+ llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
+ return std::string(Path);
+ }
+ SmallString<128> P(getDriver().ResourceDir);
+ std::string CRTBasename =
+ buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false);
+ llvm::sys::path::append(P, "lib", CRTBasename);
+ // Checks if this is the base system case which uses a different location.
+ if (getVFS().exists(P))
+ return std::string(P);
+ return ToolChain::getCompilerRT(Args, Component, Type);
}
Tool *OpenBSD::buildAssembler() const {
@@ -343,11 +391,12 @@ Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
bool OpenBSD::HasNativeLLVMSupport() const { return true; }
-bool OpenBSD::IsUnwindTablesDefault(const ArgList &Args) const {
- switch (getArch()) {
- case llvm::Triple::arm:
- return false;
- default:
- return true;
- }
+ToolChain::UnwindTableLevel
+OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {
+ switch (getArch()) {
+ case llvm::Triple::arm:
+ return UnwindTableLevel::None;
+ default:
+ return UnwindTableLevel::Asynchronous;
+ }
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h
index 2d4c4e34520b..b4350e72d5d2 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h
@@ -18,9 +18,9 @@ namespace clang {
namespace driver {
namespace tools {
-/// openbsd -- Directly call GNU Binutils assembler and linker
+/// Directly call GNU Binutils assembler and linker
namespace openbsd {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC)
: Tool("openbsd::Assembler", "assembler", TC) {}
@@ -33,7 +33,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("openbsd::Linker", "linker", TC) {}
@@ -82,7 +82,8 @@ public:
std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
FileType Type = ToolChain::FT_Static) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
LangOptions::StackProtectorMode
GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp
index 2fea262fd109..0ed0f91ad166 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp
@@ -31,10 +31,10 @@ static bool GlibcSupportsFloat128(const std::string &Linker) {
// Since glibc 2.34, the installed .so file is not symlink anymore. But we can
// still safely assume it's newer than 2.32.
- if (LinkerName.startswith("ld64.so"))
+ if (LinkerName.starts_with("ld64.so"))
return true;
- if (!LinkerName.startswith("ld-2."))
+ if (!LinkerName.starts_with("ld-2."))
return false;
unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0');
if (Minor < 32)
@@ -49,7 +49,10 @@ PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D,
: Linux(D, Triple, Args) {
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
StringRef ABIName = A->getValue();
- if (ABIName == "ieeelongdouble" && !SupportIEEEFloat128(D, Triple, Args))
+
+ if ((ABIName == "ieeelongdouble" &&
+ !SupportIEEEFloat128(D, Triple, Args)) ||
+ (ABIName == "ibmlongdouble" && !supportIBMLongDouble(D, Args)))
D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName;
}
}
@@ -67,6 +70,18 @@ void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args);
}
+bool PPCLinuxToolChain::supportIBMLongDouble(
+ const Driver &D, const llvm::opt::ArgList &Args) const {
+ if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx))
+ return true;
+
+ CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args);
+ if (StdLib == CST_Libstdcxx)
+ return true;
+
+ return StdLib == CST_Libcxx && !defaultToIEEELongDouble();
+}
+
bool PPCLinuxToolChain::SupportIEEEFloat128(
const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args) const {
@@ -78,10 +93,11 @@ bool PPCLinuxToolChain::SupportIEEEFloat128(
CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args);
bool HasUnsupportedCXXLib =
- StdLib == CST_Libcxx ||
+ (StdLib == CST_Libcxx && !defaultToIEEELongDouble()) ||
(StdLib == CST_Libstdcxx &&
GCCInstallation.getVersion().isOlderThan(12, 1, 0));
- return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) &&
+ std::string Linker = Linux::getDynamicLinker(Args);
+ return GlibcSupportsFloat128((Twine(D.DyldPrefix) + Linker).str()) &&
!(D.CCCIsCXX() && HasUnsupportedCXXLib);
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h
index e0318ae8a3a2..63adaff6be9c 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h
@@ -27,6 +27,8 @@ public:
private:
bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args) const;
+ bool supportIBMLongDouble(const Driver &D,
+ const llvm::opt::ArgList &Args) const;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp
index bcf9147833dd..8ba8b80cfec7 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//
#include "PS4CPU.h"
-#include "FreeBSD.h"
#include "CommonArgs.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
@@ -23,8 +23,18 @@ using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
-void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
+// Helper to paste bits of an option together and return a saved string.
+static const char *makeArgString(const ArgList &Args, const char *Prefix,
+ const char *Base, const char *Suffix) {
+ // Basically "Prefix + Base + Suffix" all converted to Twine then saved.
+ return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix);
+}
+
+void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ assert(TC.getTriple().isPS());
+ auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
+
if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
false) ||
Args.hasFlag(options::OPT_fprofile_generate,
@@ -41,14 +51,16 @@ void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
options::OPT_fno_profile_generate, false) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_coverage)))
- CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a");
+ CmdArgs.push_back(makeArgString(
+ Args, "--dependent-lib=", PSTC.getProfileRTLibName(), ""));
}
-void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
claimNoWarnArgs(Args);
ArgStringList CmdArgs;
@@ -62,41 +74,57 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
assert(Input.isFilename() && "Invalid input.");
CmdArgs.push_back(Input.getFilename());
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("orbis-as"));
+ std::string AsName = TC.qualifyPSCmdName("as");
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str()));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileUTF8(),
Exec, CmdArgs, Inputs, Output));
}
-static void AddPS4SanitizerArgs(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
- if (SanArgs.needsUbsanRt()) {
- CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak");
- }
- if (SanArgs.needsAsanRt()) {
- CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak");
- }
+void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ assert(TC.getTriple().isPS());
+ auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
+ PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a");
}
-void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
+void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const char *Prefix,
+ const char *Suffix) const {
+ auto arg = [&](const char *Name) -> const char * {
+ return makeArgString(Args, Prefix, Name, Suffix);
+ };
+ const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
if (SanArgs.needsUbsanRt())
- CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a");
+ CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak"));
if (SanArgs.needsAsanRt())
- CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a");
+ CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak"));
}
-void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const toolchains::FreeBSD &ToolChain =
- static_cast<const toolchains::FreeBSD &>(getToolChain());
- const Driver &D = ToolChain.getDriver();
+void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const char *Prefix,
+ const char *Suffix) const {
+ auto arg = [&](const char *Name) -> const char * {
+ return makeArgString(Args, Prefix, Name, Suffix);
+ };
+ const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
+ if (SanArgs.needsUbsanRt())
+ CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak"));
+ if (SanArgs.needsAsanRt())
+ CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak"));
+ if (SanArgs.needsTsanRt())
+ CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
+}
+
+void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
+ const Driver &D = TC.getDriver();
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@@ -116,119 +144,195 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("--oformat=so");
+ CmdArgs.push_back("--shared");
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
- if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
- AddPS4SanitizerArgs(ToolChain, Args, CmdArgs);
+ const bool UseLTO = D.isUsingLTO();
+ const bool UseJMC =
+ Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
+ const bool IsPS4 = TC.getTriple().isPS4();
+
+ const char *PS4LTOArgs = "";
+ auto AddCodeGenFlag = [&](Twine Flag) {
+ if (IsPS4)
+ PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag);
+ else
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
+ };
+
+ if (UseLTO) {
+ // We default to creating the arange section, but LTO does not. Enable it
+ // here.
+ AddCodeGenFlag("-generate-arange-section");
+
+ // This tells LTO to perform JustMyCode instrumentation.
+ if (UseJMC)
+ AddCodeGenFlag("-enable-jmc-instrument");
+
+ if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
+ AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
+
+ StringRef Parallelism = getLTOParallelism(Args, D);
+ if (!Parallelism.empty()) {
+ if (IsPS4)
+ AddCodeGenFlag(Twine("-threads=") + Parallelism);
+ else
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
+ }
+
+ if (IsPS4) {
+ const char *Prefix = nullptr;
+ if (D.getLTOMode() == LTOK_Thin)
+ Prefix = "-lto-thin-debug-options=";
+ else if (D.getLTOMode() == LTOK_Full)
+ Prefix = "-lto-debug-options=";
+ else
+ llvm_unreachable("new LTO mode?");
+
+ CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs));
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
+ TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
+ if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
+ if (D.getLTOMode() == LTOK_Thin)
+ CmdArgs.push_back("--lto=thin");
+ else if (D.getLTOMode() == LTOK_Full)
+ CmdArgs.push_back("--lto=full");
+ }
+
+ Args.addAllArgs(CmdArgs,
+ {options::OPT_L, options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_r});
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
if (Args.hasArg(options::OPT_pthread)) {
CmdArgs.push_back("-lpthread");
}
+ if (UseJMC) {
+ CmdArgs.push_back("--whole-archive");
+ if (IsPS4)
+ CmdArgs.push_back("-lSceDbgJmc");
+ else
+ CmdArgs.push_back("-lSceJmc_nosubmission");
+ CmdArgs.push_back("--no-whole-archive");
+ }
+
if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
- << "-fuse-ld" << getToolChain().getTriple().str();
+ << "-fuse-ld" << TC.getTriple().str();
}
- const char *Exec =
- Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
+ std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileUTF8(),
Exec, CmdArgs, Inputs, Output));
}
-toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
+toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args, StringRef Platform,
+ const char *EnvVar)
: Generic_ELF(D, Triple, Args) {
if (Args.hasArg(clang::driver::options::OPT_static))
- D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static"
- << "PS4";
-
- // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR
- // if it exists; otherwise use the driver's installation path, which
- // should be <SDK_DIR>/host_tools/bin.
-
- SmallString<512> PS4SDKDir;
- if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) {
- if (!llvm::sys::fs::exists(EnvValue))
- getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue;
- PS4SDKDir = EnvValue;
- } else {
- PS4SDKDir = getDriver().Dir;
- llvm::sys::path::append(PS4SDKDir, "/../../");
- }
+ D.Diag(clang::diag::err_drv_unsupported_opt_for_target)
+ << "-static" << Platform;
- // By default, the driver won't report a warning if it can't find
- // PS4's include or lib directories. This behavior could be changed if
- // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
+ // Determine where to find the PS4/PS5 libraries.
// If -isysroot was passed, use that as the SDK base path.
- std::string PrefixDir;
+ // If not, we use the EnvVar if it exists; otherwise use the driver's
+ // installation path, which should be <SDK_DIR>/host_tools/bin.
+ SmallString<80> Whence;
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- PrefixDir = A->getValue();
- if (!llvm::sys::fs::exists(PrefixDir))
- getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir;
- } else
- PrefixDir = std::string(PS4SDKDir.str());
-
- SmallString<512> PS4SDKIncludeDir(PrefixDir);
- llvm::sys::path::append(PS4SDKIncludeDir, "target/include");
+ SDKRootDir = A->getValue();
+ if (!llvm::sys::fs::exists(SDKRootDir))
+ D.Diag(clang::diag::warn_missing_sysroot) << SDKRootDir;
+ Whence = A->getSpelling();
+ } else if (const char *EnvValue = getenv(EnvVar)) {
+ SDKRootDir = EnvValue;
+ Whence = { "environment variable '", EnvVar, "'" };
+ } else {
+ SDKRootDir = D.Dir + "/../../";
+ Whence = "compiler's location";
+ }
+
+ SmallString<512> SDKIncludeDir(SDKRootDir);
+ llvm::sys::path::append(SDKIncludeDir, "target/include");
if (!Args.hasArg(options::OPT_nostdinc) &&
!Args.hasArg(options::OPT_nostdlibinc) &&
!Args.hasArg(options::OPT_isysroot) &&
!Args.hasArg(options::OPT__sysroot_EQ) &&
- !llvm::sys::fs::exists(PS4SDKIncludeDir)) {
- getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
- << "PS4 system headers" << PS4SDKIncludeDir;
+ !llvm::sys::fs::exists(SDKIncludeDir)) {
+ D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
+ << Twine(Platform, " system headers").str() << SDKIncludeDir << Whence;
}
- SmallString<512> PS4SDKLibDir(PS4SDKDir);
- llvm::sys::path::append(PS4SDKLibDir, "target/lib");
+ SmallString<512> SDKLibDir(SDKRootDir);
+ llvm::sys::path::append(SDKLibDir, "target/lib");
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs) &&
!Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
!Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
!Args.hasArg(options::OPT_emit_ast) &&
- !llvm::sys::fs::exists(PS4SDKLibDir)) {
- getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
- << "PS4 system libraries" << PS4SDKLibDir;
+ !llvm::sys::fs::exists(SDKLibDir)) {
+ D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
+ << Twine(Platform, " system libraries").str() << SDKLibDir << Whence;
return;
}
- getFilePaths().push_back(std::string(PS4SDKLibDir.str()));
+ getFilePaths().push_back(std::string(SDKLibDir));
}
-Tool *toolchains::PS4CPU::buildAssembler() const {
- return new tools::PS4cpu::Assemble(*this);
+void toolchains::PS4PS5Base::AddClangSystemIncludeArgs(
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ SDKRootDir + "/target/include");
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ SDKRootDir + "/target/include_common");
}
-Tool *toolchains::PS4CPU::buildLinker() const {
- return new tools::PS4cpu::Link(*this);
+Tool *toolchains::PS4CPU::buildAssembler() const {
+ return new tools::PScpu::Assembler(*this);
}
-bool toolchains::PS4CPU::isPICDefault() const { return true; }
+Tool *toolchains::PS5CPU::buildAssembler() const {
+ // PS5 does not support an external assembler.
+ getDriver().Diag(clang::diag::err_no_external_assembler);
+ return nullptr;
+}
-bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; }
+Tool *toolchains::PS4PS5Base::buildLinker() const {
+ return new tools::PScpu::Linker(*this);
+}
-SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const {
+SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
@@ -237,10 +341,16 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const {
return Res;
}
-void toolchains::PS4CPU::addClangTargetOptions(
+SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const {
+ SanitizerMask Res = PS4PS5Base::getSupportedSanitizers();
+ Res |= SanitizerKind::Thread;
+ return Res;
+}
+
+void toolchains::PS4PS5Base::addClangTargetOptions(
const ArgList &DriverArgs, ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
- // PS4 does not use init arrays.
+ // PS4/PS5 do not use init arrays.
if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
@@ -249,6 +359,12 @@ void toolchains::PS4CPU::addClangTargetOptions(
CC1Args.push_back("-fno-use-init-array");
+ // Default to -fvisibility-global-new-delete=source for PS5.
+ if (getTriple().isPS5() &&
+ !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ,
+ options::OPT_fvisibility_global_new_delete_hidden))
+ CC1Args.push_back("-fvisibility-global-new-delete=source");
+
const Arg *A =
DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
options::OPT_fno_visibility_from_dllstorageclass);
@@ -281,3 +397,13 @@ void toolchains::PS4CPU::addClangTargetOptions(
CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
}
}
+
+// PS4 toolchain.
+toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {}
+
+// PS5 toolchain.
+toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h
index 4bedabaf267c..fee80e77462f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h
@@ -18,7 +18,8 @@ namespace clang {
namespace driver {
namespace tools {
-namespace PS4cpu {
+namespace PScpu {
+// Functions/classes in this namespace support both PS4 and PS5.
void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
@@ -26,75 +27,72 @@ void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
void addSanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);
-class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("PS4cpu::Assemble", "assembler", TC) {}
+ Assembler(const ToolChain &TC) : Tool("PScpu::Assembler", "assembler", TC) {}
bool hasIntegratedCPP() const override { return false; }
void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
+ const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
- Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC) {}
+ Linker(const ToolChain &TC) : Tool("PScpu::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 InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
-} // end namespace PS4cpu
+} // namespace PScpu
} // namespace tools
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF {
+// Common Toolchain base class for PS4 and PS5.
+class LLVM_LIBRARY_VISIBILITY PS4PS5Base : public Generic_ELF {
public:
- PS4CPU(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
+ PS4PS5Base(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args, StringRef Platform,
+ const char *EnvVar);
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
// No support for finding a C++ standard library yet.
- void addLibCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
+ void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override {
+ }
+ void
+ addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override {}
bool IsMathErrnoDefault() const override { return false; }
bool IsObjCNonFragileABIDefault() const override { return true; }
- bool HasNativeLLVMSupport() const override;
- bool isPICDefault() const override;
+ bool HasNativeLLVMSupport() const override { return true; }
+ bool isPICDefault() const override { return true; }
LangOptions::StackProtectorMode
GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
return LangOptions::SSPStrong;
}
- unsigned GetDefaultDwarfVersion() const override { return 4; }
llvm::DebuggerKind getDefaultDebuggerTuning() const override {
return llvm::DebuggerKind::SCE;
}
SanitizerMask getSupportedSanitizers() const override;
- // PS4 toolchain uses legacy thin LTO API, which is not
- // capable of unit splitting.
- bool canSplitThinLTOUnit() const override { return false; }
-
void addClangTargetOptions(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadingKind) const override;
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const override;
llvm::DenormalMode getDefaultDenormalModeForType(
const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
@@ -103,11 +101,73 @@ public:
return llvm::DenormalMode::getPreserveSign();
}
- bool useRelaxRelocations() const override { return true; }
+ // Helper methods for PS4/PS5.
+ virtual const char *getLinkerBaseName() const = 0;
+ virtual std::string qualifyPSCmdName(StringRef CmdName) const = 0;
+ virtual void addSanitizerArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ const char *Prefix,
+ const char *Suffix) const = 0;
+ virtual const char *getProfileRTLibName() const = 0;
protected:
- Tool *buildAssembler() const override;
Tool *buildLinker() const override;
+
+private:
+ // We compute the SDK root dir in the ctor, and use it later.
+ std::string SDKRootDir;
+};
+
+// PS4-specific Toolchain class.
+class LLVM_LIBRARY_VISIBILITY PS4CPU : public PS4PS5Base {
+public:
+ PS4CPU(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
+
+ // PS4 toolchain uses legacy thin LTO API, which is not
+ // capable of unit splitting.
+ bool canSplitThinLTOUnit() const override { return false; }
+
+ const char *getLinkerBaseName() const override { return "ld"; }
+ std::string qualifyPSCmdName(StringRef CmdName) const override {
+ return Twine("orbis-", CmdName).str();
+ }
+ void addSanitizerArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, const char *Prefix,
+ const char *Suffix) const override;
+ const char *getProfileRTLibName() const override {
+ return "libclang_rt.profile-x86_64.a";
+ }
+
+protected:
+ Tool *buildAssembler() const override;
+};
+
+// PS5-specific Toolchain class.
+class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base {
+public:
+ PS5CPU(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ unsigned GetDefaultDwarfVersion() const override { return 5; }
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+ const char *getLinkerBaseName() const override { return "lld"; }
+ std::string qualifyPSCmdName(StringRef CmdName) const override {
+ return Twine("prospero-", CmdName).str();
+ }
+ void addSanitizerArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, const char *Prefix,
+ const char *Suffix) const override;
+ const char *getProfileRTLibName() const override {
+ return "libclang_rt.profile-x86_64_nosubmission.a";
+ }
+
+protected:
+ Tool *buildAssembler() const override;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
index 714325a2db39..5e4fa4d5331f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
@@ -1,4 +1,4 @@
-//===--- RISCVToolchain.cpp - RISCV ToolChain Implementations ---*- C++ -*-===//
+//===--- RISCVToolchain.cpp - RISC-V 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.
@@ -46,17 +46,17 @@ bool RISCVToolChain::hasGCCToolchain(const Driver &D,
return llvm::sys::fs::exists(GCCDir);
}
-/// RISCV Toolchain
+/// RISC-V Toolchain
RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
if (GCCInstallation.isValid()) {
Multilibs = GCCInstallation.getMultilibs();
- SelectedMultilib = GCCInstallation.getMultilib();
+ SelectedMultilibs.assign({GCCInstallation.getMultilib()});
path_list &Paths = getFilePaths();
// Add toolchain/multilib specific file paths.
- addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
+ addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
GCCInstallation.getInstallPath(), Paths);
getFilePaths().push_back(GCCInstallation.getInstallPath().str());
ToolChain::path_list &PPaths = getProgramPaths();
@@ -98,6 +98,12 @@ void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (DriverArgs.hasArg(options::OPT_nostdinc))
return;
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
SmallString<128> Dir(computeSysRoot());
llvm::sys::path::append(Dir, "include");
@@ -135,7 +141,7 @@ std::string RISCVToolChain::computeSysRoot() const {
if (!llvm::sys::fs::exists(SysRootDir))
return std::string();
- return std::string(SysRootDir.str());
+ return std::string(SysRootDir);
}
void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -157,6 +163,7 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
} else {
CmdArgs.push_back("elf32lriscv");
}
+ CmdArgs.push_back("-X");
std::string Linker = getToolChain().GetLinkerPath();
@@ -183,19 +190,21 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
+
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
+ Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+ options::OPT_t, options::OPT_r});
// TODO: add C++ includes and libs if compiling C++.
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (ToolChain.ShouldLinkCXXStdlib(Args))
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (D.CCCIsCXX()) {
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
CmdArgs.push_back("--start-group");
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lgloss");
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h
index 62099bee0404..cec817ef7190 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h
@@ -1,4 +1,4 @@
-//===--- RISCVToolchain.h - RISCV ToolChain Implementations -----*- C++ -*-===//
+//===--- RISCVToolchain.h - RISC-V 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.
@@ -22,7 +22,6 @@ public:
const llvm::opt::ArgList &Args);
static bool hasGCCToolchain(const Driver &D, const llvm::opt::ArgList &Args);
- bool IsIntegratedAssemblerDefault() const override { return true; }
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind) const override;
@@ -47,7 +46,7 @@ private:
namespace tools {
namespace RISCV {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("RISCV::Linker", "ld", TC) {}
bool hasIntegratedCPP() const override { return false; }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h
index bb482be68260..dceb0ab03669 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h
@@ -15,13 +15,33 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/VersionTuple.h"
+#include "llvm/TargetParser/Triple.h"
namespace clang {
namespace driver {
+/// ABI version of device library.
+struct DeviceLibABIVersion {
+ unsigned ABIVersion = 0;
+ DeviceLibABIVersion(unsigned V) : ABIVersion(V) {}
+ static DeviceLibABIVersion fromCodeObjectVersion(unsigned CodeObjectVersion) {
+ if (CodeObjectVersion < 4)
+ CodeObjectVersion = 4;
+ return DeviceLibABIVersion(CodeObjectVersion * 100);
+ }
+ /// Whether ABI version bc file is requested.
+ /// ABIVersion is code object version multiplied by 100. Code object v4
+ /// and below works with ROCm 5.0 and below which does not have
+ /// abi_version_*.bc. Code object v5 requires abi_version_500.bc.
+ bool requiresLibrary() { return ABIVersion >= 500; }
+ std::string toString() {
+ assert(ABIVersion % 100 == 0 && "Not supported");
+ return Twine(ABIVersion / 100).str();
+ }
+};
+
/// A class to find a viable ROCM installation
/// TODO: Generalize to handle libclc.
class RocmInstallationDetector {
@@ -57,6 +77,9 @@ private:
const Driver &D;
bool HasHIPRuntime = false;
bool HasDeviceLibrary = false;
+ bool HasHIPStdParLibrary = false;
+ bool HasRocThrustLibrary = false;
+ bool HasRocPrimLibrary = false;
// Default version if not detected or specified.
const unsigned DefaultVersionMajor = 3;
@@ -76,6 +99,13 @@ private:
std::vector<std::string> RocmDeviceLibPathArg;
// HIP runtime path specified by --hip-path.
StringRef HIPPathArg;
+ // HIP Standard Parallel Algorithm acceleration library specified by
+ // --hipstdpar-path
+ StringRef HIPStdParPathArg;
+ // rocThrust algorithm library specified by --hipstdpar-thrust-path
+ StringRef HIPRocThrustPathArg;
+ // rocPrim algorithm library specified by --hipstdpar-prim-path
+ StringRef HIPRocPrimPathArg;
// HIP version specified by --hip-version.
StringRef HIPVersionArg;
// Wheter -nogpulib is specified.
@@ -87,6 +117,7 @@ private:
SmallString<0> LibPath;
SmallString<0> LibDevicePath;
SmallString<0> IncludePath;
+ SmallString<0> SharePath;
llvm::StringMap<std::string> LibDeviceMap;
// Libraries that are always linked.
@@ -107,6 +138,10 @@ private:
ConditionalLibrary DenormalsAreZero;
ConditionalLibrary CorrectlyRoundedSqrt;
+ // Maps ABI version to library path. The version number is in the format of
+ // three digits as used in the ABI version library name.
+ std::map<unsigned, std::string> ABIVersionMap;
+
// Cache ROCm installation search paths.
SmallVector<Candidate, 4> ROCmSearchDirs;
bool PrintROCmSearchDirs;
@@ -142,7 +177,12 @@ public:
getCommonBitcodeLibs(const llvm::opt::ArgList &DriverArgs,
StringRef LibDeviceFile, bool Wave64, bool DAZ,
bool FiniteOnly, bool UnsafeMathOpt,
- bool FastRelaxedMath, bool CorrectSqrt) const;
+ bool FastRelaxedMath, bool CorrectSqrt,
+ DeviceLibABIVersion ABIVer, bool isOpenMP) const;
+ /// Check file paths of default bitcode libraries common to AMDGPU based
+ /// toolchains. \returns false if there are invalid or missing files.
+ bool checkCommonBitcodeLibs(StringRef GPUArch, StringRef LibDeviceFile,
+ DeviceLibABIVersion ABIVer) const;
/// Check whether we detected a valid HIP runtime.
bool hasHIPRuntime() const { return HasHIPRuntime; }
@@ -150,6 +190,9 @@ public:
/// Check whether we detected a valid ROCm device library.
bool hasDeviceLibrary() const { return HasDeviceLibrary; }
+ /// Check whether we detected a valid HIP STDPAR Acceleration library.
+ bool hasHIPStdParLibrary() const { return HasHIPStdParLibrary; }
+
/// Print information about the detected ROCm installation.
void print(raw_ostream &OS) const;
@@ -214,9 +257,19 @@ public:
return CorrectlyRoundedSqrt.get(Enabled);
}
+ StringRef getABIVersionPath(DeviceLibABIVersion ABIVer) const {
+ auto Loc = ABIVersionMap.find(ABIVer.ABIVersion);
+ if (Loc == ABIVersionMap.end())
+ return StringRef();
+ return Loc->second;
+ }
+
/// Get libdevice file for given architecture
- std::string getLibDeviceFile(StringRef Gpu) const {
- return LibDeviceMap.lookup(Gpu);
+ StringRef getLibDeviceFile(StringRef Gpu) const {
+ auto Loc = LibDeviceMap.find(Gpu);
+ if (Loc == LibDeviceMap.end())
+ return "";
+ return Loc->second;
}
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -226,7 +279,7 @@ public:
void detectHIPRuntime();
/// Get the values for --rocm-device-lib-path arguments
- std::vector<std::string> getRocmDeviceLibPathArg() const {
+ ArrayRef<std::string> getRocmDeviceLibPathArg() const {
return RocmDeviceLibPathArg;
}
@@ -236,7 +289,7 @@ public:
/// Get the value for --hip-version argument
StringRef getHIPVersionArg() const { return HIPVersionArg; }
- std::string getHIPVersion() const { return DetectedVersion; }
+ StringRef getHIPVersion() const { return DetectedVersion; }
};
} // end namespace driver
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h
index a16ae3ca51fa..d4247ee0557f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h
@@ -17,9 +17,6 @@ namespace driver {
namespace tools {
namespace SPIRV {
-void addTranslatorArgs(const llvm::opt::ArgList &InArgs,
- llvm::opt::ArgStringList &OutArgs);
-
void constructTranslateCommand(Compilation &C, const Tool &T,
const JobAction &JA, const InputInfo &Output,
const InputInfo &Input,
@@ -39,7 +36,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("SPIRV::Linker", "spirv-link", TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -64,8 +61,9 @@ public:
: ToolChain(D, Triple, Args) {}
bool useIntegratedAs() const override { return true; }
- bool useIntegratedBackend() const override { return false; }
+ bool IsIntegratedBackendDefault() const override { return false; }
+ bool IsNonIntegratedBackendSupported() const override { return true; }
bool IsMathErrnoDefault() const override { return false; }
bool isCrossCompiling() const override { return true; }
bool isPICDefault() const override { return false; }
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp
index 24f18b92dd66..200ac46aa534 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp
@@ -8,12 +8,16 @@
#include "Solaris.h"
#include "CommonArgs.h"
+#include "Gnu.h"
#include "clang/Basic/LangStandard.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -29,20 +33,50 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
+ // Just call the Gnu version, which enforces gas on Solaris.
+ gnutools::Assembler::ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput);
+}
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) {
+ // Only used if targetting Solaris.
+ const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ);
+ StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER;
+ return UseLinker == "bfd" || UseLinker == "gld";
+}
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
+static bool getPIE(const ArgList &Args, const ToolChain &TC) {
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_r))
+ return false;
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
+ return Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
+ TC.isPIEDefault(Args));
+}
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
- Exec, CmdArgs, Inputs, Output));
+// FIXME: Need to handle CLANG_DEFAULT_LINKER here?
+std::string solaris::Linker::getLinkerPath(const ArgList &Args) const {
+ const ToolChain &ToolChain = getToolChain();
+ if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
+ StringRef UseLinker = A->getValue();
+ if (!UseLinker.empty()) {
+ if (llvm::sys::path::is_absolute(UseLinker) &&
+ llvm::sys::fs::can_execute(UseLinker))
+ return std::string(UseLinker);
+
+ // Accept 'bfd' and 'gld' as aliases for the GNU linker.
+ if (UseLinker == "bfd" || UseLinker == "gld")
+ // FIXME: Could also use /usr/bin/gld here.
+ return "/usr/gnu/bin/ld";
+
+ // Accept 'ld' as alias for the default linker
+ if (UseLinker != "ld")
+ ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name)
+ << A->getAsString(Args);
+ }
+ }
+
+ // getDefaultLinker() always returns an absolute path.
+ return ToolChain.getDefaultLinker();
}
void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -50,24 +84,38 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ const auto &ToolChain = static_cast<const Solaris &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool IsPIE = getPIE(Args, ToolChain);
+ const bool LinkerIsGnuLd = isLinkerGnuLd(ToolChain, Args);
ArgStringList CmdArgs;
- // Demangle C++ names in errors
- CmdArgs.push_back("-C");
+ // Demangle C++ names in errors. GNU ld already defaults to --demangle.
+ if (!LinkerIsGnuLd)
+ CmdArgs.push_back("-C");
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared,
+ options::OPT_r)) {
CmdArgs.push_back("-e");
CmdArgs.push_back("_start");
}
+ if (IsPIE) {
+ if (LinkerIsGnuLd) {
+ CmdArgs.push_back("-pie");
+ } else {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("type=pie");
+ }
+ }
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
CmdArgs.push_back("-dn");
} else {
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_r) && Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-shared");
- }
// libpthread has been folded into libc since Solaris 10, no need to do
// anything for pthreads. Claim argument to avoid warning.
@@ -75,19 +123,50 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.ClaimAllArgs(options::OPT_pthreads);
}
+ if (LinkerIsGnuLd) {
+ // Set the correct linker emulation for 32- and 64-bit Solaris.
+ switch (Arch) {
+ case llvm::Triple::x86:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_i386_sol2");
+ break;
+ case llvm::Triple::x86_64:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_x86_64_sol2");
+ break;
+ case llvm::Triple::sparc:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32_sparc_sol2");
+ break;
+ case llvm::Triple::sparcv9:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64_sparc_sol2");
+ break;
+ default:
+ break;
+ }
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ } else {
+ // -rdynamic is a no-op with Solaris ld. Claim argument to avoid warning.
+ Args.ClaimAllArgs(options::OPT_rdynamic);
+ }
+
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
bool HaveAnsi = false;
@@ -102,29 +181,54 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409.
if (HaveAnsi || (LangStd && !LangStd->isGNUMode()))
values_X = "values-Xc.o";
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(values_X)));
const char *values_xpg = "values-xpg6.o";
// Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409.
if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99())
values_xpg = "values-xpg4.o";
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath(values_xpg)));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(values_xpg)));
+
+ const char *crtbegin = nullptr;
+ if (Args.hasArg(options::OPT_shared) || IsPIE)
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ // Add crtfastmath.o if available and fast math is enabled.
+ ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
}
- getToolChain().AddFilePathLibArgs(Args, CmdArgs);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
- options::OPT_e, options::OPT_r});
+ Args.addAllArgs(CmdArgs,
+ {options::OPT_L, options::OPT_T_Group, options::OPT_r});
- bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (getToolChain().ShouldLinkCXXStdlib(Args))
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+ options::OPT_r)) {
+ // Use the static OpenMP runtime with -static-openmp
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
+ !Args.hasArg(options::OPT_static);
+ addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
+
+ if (D.CCCIsCXX()) {
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+ // Additional linker set-up and flags for Fortran. This is required in order
+ // to generate executables. As Fortran runtime depends on the C runtime,
+ // these dependencies need to be listed before the C runtime below.
+ if (D.IsFlangMode()) {
+ addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs);
+ addFortranRuntimeLibs(getToolChain(), Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
if (Args.hasArg(options::OPT_fstack_protector) ||
Args.hasArg(options::OPT_fstack_protector_strong) ||
Args.hasArg(options::OPT_fstack_protector_all)) {
@@ -134,30 +238,55 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
// LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so
// forcibly link with libatomic as a workaround.
- if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) {
- CmdArgs.push_back(getAsNeededOption(getToolChain(), true));
+ if (Arch == llvm::Triple::sparc) {
+ addAsNeededOption(ToolChain, Args, CmdArgs, true);
CmdArgs.push_back("-latomic");
- CmdArgs.push_back(getAsNeededOption(getToolChain(), false));
+ addAsNeededOption(ToolChain, Args, CmdArgs, false);
}
+ addAsNeededOption(ToolChain, Args, CmdArgs, true);
CmdArgs.push_back("-lgcc_s");
+ addAsNeededOption(ToolChain, Args, CmdArgs, false);
CmdArgs.push_back("-lc");
if (!Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("-lm");
}
- if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(getToolChain(), CmdArgs);
+ const SanitizerArgs &SA = ToolChain.getSanitizerArgs(Args);
+ if (NeedsSanitizerDeps) {
+ linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
+
+ // Work around Solaris/amd64 ld bug when calling __tls_get_addr directly.
+ // However, ld -z relax=transtls is available since Solaris 11.2, but not
+ // in Illumos.
+ if (Arch == llvm::Triple::x86_64 &&
+ (SA.needsAsanRt() || SA.needsStatsRt() ||
+ (SA.needsUbsanRt() && !SA.requiresMinimalRuntime())) &&
+ !LinkerIsGnuLd) {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("relax=transtls");
+ }
+ }
+ // Avoid AsanInitInternal cycle, Issue #64126.
+ if (ToolChain.getTriple().isX86() && SA.needsSharedRt() &&
+ SA.needsAsanRt()) {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("now");
+ }
}
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+ options::OPT_r)) {
+ const char *crtend = nullptr;
+ if (Args.hasArg(options::OPT_shared) || IsPIE)
+ crtend = "crtendS.o";
+ else
+ crtend = "crtend.o";
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
- getToolChain().addProfileRTLibs(Args, CmdArgs);
+ ToolChain.addProfileRTLibs(Args, CmdArgs);
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ const char *Exec = Args.MakeArgString(getLinkerPath(Args));
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Exec, CmdArgs, Inputs, Output));
}
@@ -166,13 +295,12 @@ static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
case llvm::Triple::x86:
case llvm::Triple::sparc:
+ default:
break;
case llvm::Triple::x86_64:
return "/amd64";
case llvm::Triple::sparcv9:
return "/sparcv9";
- default:
- llvm_unreachable("Unsupported architecture");
}
return "";
}
@@ -199,7 +327,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
// If we are currently running Clang inside of the requested system root,
// add its parent library path to those searched.
- if (StringRef(D.Dir).startswith(D.SysRoot))
+ if (StringRef(D.Dir).starts_with(D.SysRoot))
addPathIfExists(D, D.Dir + "/../lib", Paths);
addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths);
@@ -207,7 +335,6 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
SanitizerMask Solaris::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
- const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
// FIXME: Omit X86_64 until 64-bit support is figured out.
if (IsX86) {
@@ -215,12 +342,17 @@ SanitizerMask Solaris::getSupportedSanitizers() const {
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
}
- if (IsX86 || IsX86_64)
- Res |= SanitizerKind::Function;
Res |= SanitizerKind::Vptr;
return Res;
}
+const char *Solaris::getDefaultLinker() const {
+ // FIXME: Only handle Solaris ld and GNU ld here.
+ return llvm::StringSwitch<const char *>(CLANG_DEFAULT_LINKER)
+ .Cases("bfd", "gld", "/usr/gnu/bin/ld")
+ .Default("/usr/bin/ld");
+}
+
Tool *Solaris::buildAssembler() const {
return new tools::solaris::Assembler(*this);
}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h
index fbac92c2c0f3..9ec83b773da4 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h
@@ -17,12 +17,11 @@ namespace clang {
namespace driver {
namespace tools {
-/// solaris -- Directly call Solaris assembler and linker
+/// Directly call Solaris assembler and linker
namespace solaris {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public gnutools::Assembler {
public:
- Assembler(const ToolChain &TC)
- : Tool("solaris::Assembler", "assembler", TC) {}
+ Assembler(const ToolChain &TC) : gnutools::Assembler(TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -32,12 +31,15 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+bool isLinkerGnuLd(const ToolChain &TC, const llvm::opt::ArgList &Args);
+
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ std::string getLinkerPath(const llvm::opt::ArgList &Args) const;
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -63,12 +65,8 @@ public:
llvm::opt::ArgStringList &CC1Args) const override;
SanitizerMask getSupportedSanitizers() const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- const char *getDefaultLinker() const override {
- // clang currently uses Solaris ld-only options.
- return "/usr/bin/ld";
- }
+ const char *getDefaultLinker() const override;
protected:
Tool *buildAssembler() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp
index 1e43796be1ff..39529e0b6b35 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp
@@ -33,7 +33,8 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple,
// These are OK.
// Default file paths are following:
- // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPath)
+ // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, (== getArchSpecificLibPaths)
+ // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPaths)
// /lib/../lib64,
// /usr/lib/../lib64,
// ${BINPATH}/../lib,
@@ -46,11 +47,13 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple,
// Add library directories:
// ${BINPATH}/../lib/ve-unknown-linux-gnu, (== getStdlibPath)
- // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPath)
+ // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, (== getArchSpecificLibPaths)
+ // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPaths)
// ${SYSROOT}/opt/nec/ve/lib,
- for (auto &Path : getStdlibPaths())
- getFilePaths().push_back(std::move(Path));
- getFilePaths().push_back(getArchSpecificLibPath());
+ if (std::optional<std::string> Path = getStdlibPath())
+ getFilePaths().push_back(std::move(*Path));
+ for (const auto &Path : getArchSpecificLibPaths())
+ getFilePaths().push_back(Path);
getFilePaths().push_back(computeSysRoot() + "/opt/nec/ve/lib");
}
@@ -140,7 +143,15 @@ void VEToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
tools::addArchSpecificRPath(*this, Args, CmdArgs);
+ // Add paths for libc++.so and other shared libraries.
+ if (std::optional<std::string> Path = getStdlibPath()) {
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back(Args.MakeArgString(*Path));
+ }
+
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
CmdArgs.push_back("-lunwind");
// libc++ requires -lpthread under glibc environment
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h
index 964b0d0dd8d4..8b9ccaa7fada 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h
@@ -26,7 +26,6 @@ protected:
Tool *buildLinker() const override;
public:
- bool IsIntegratedAssemblerDefault() const override { return true; }
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp
index 3614272a5f74..0b16b660364f 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -8,15 +8,17 @@
#include "WebAssembly.h"
#include "CommonArgs.h"
+#include "Gnu.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-#include "llvm/Option/ArgList.h"
+#include "llvm/Support/VirtualFileSystem.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -42,8 +44,15 @@ std::string wasm::Linker::getLinkerPath(const ArgList &Args) const {
llvm::sys::fs::can_execute(UseLinker))
return std::string(UseLinker);
- // Accept 'lld', and 'ld' as aliases for the default linker
- if (UseLinker != "lld" && UseLinker != "ld")
+ // Interpret 'lld' as explicitly requesting `wasm-ld`, so look for that
+ // linker. Note that for `wasm32-wasip2` this overrides the default linker
+ // of `wasm-component-ld`.
+ if (UseLinker == "lld") {
+ return ToolChain.GetProgramPath("wasm-ld");
+ }
+
+ // Allow 'ld' as an alias for the default linker
+ if (UseLinker != "ld")
ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name)
<< A->getAsString(Args);
}
@@ -71,34 +80,56 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("--strip-all");
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
+ // On `wasip2` the default linker is `wasm-component-ld` which wraps the
+ // execution of `wasm-ld`. Find `wasm-ld` and pass it as an argument of where
+ // to find it to avoid it needing to hunt and rediscover or search `PATH` for
+ // where it is.
+ if (llvm::sys::path::stem(Linker).ends_with_insensitive(
+ "wasm-component-ld")) {
+ CmdArgs.push_back("--wasm-ld-path");
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetProgramPath("wasm-ld")));
+ }
+
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
+
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- const char *Crt1 = "crt1.o";
+ bool IsCommand = true;
+ const char *Crt1;
const char *Entry = nullptr;
- // If crt1-command.o exists, it supports new-style commands, so use it.
- // Otherwise, use the old crt1.o. This is a temporary transition measure.
- // Once WASI libc no longer needs to support LLVM versions which lack
- // support for new-style command, it can make crt1.o the same as
- // crt1-command.o. And once LLVM no longer needs to support WASI libc
- // versions before that, it can switch to using crt1-command.o.
- if (ToolChain.GetFilePath("crt1-command.o") != "crt1-command.o")
- Crt1 = "crt1-command.o";
+ // When -shared is specified, use the reactor exec model unless
+ // specified otherwise.
+ if (Args.hasArg(options::OPT_shared))
+ IsCommand = false;
if (const Arg *A = Args.getLastArg(options::OPT_mexec_model_EQ)) {
StringRef CM = A->getValue();
if (CM == "command") {
- // Use default values.
+ IsCommand = true;
} else if (CM == "reactor") {
- Crt1 = "crt1-reactor.o";
- Entry = "_initialize";
+ IsCommand = false;
} else {
ToolChain.getDriver().Diag(diag::err_drv_invalid_argument_to_option)
<< CM << A->getOption().getName();
}
}
+
+ if (IsCommand) {
+ // If crt1-command.o exists, it supports new-style commands, so use it.
+ // Otherwise, use the old crt1.o. This is a temporary transition measure.
+ // Once WASI libc no longer needs to support LLVM versions which lack
+ // support for new-style command, it can make crt1.o the same as
+ // crt1-command.o. And once LLVM no longer needs to support WASI libc
+ // versions before that, it can switch to using crt1-command.o.
+ Crt1 = "crt1.o";
+ if (ToolChain.GetFilePath("crt1-command.o") != "crt1-command.o")
+ Crt1 = "crt1-command.o";
+ } else {
+ Crt1 = "crt1-reactor.o";
+ Entry = "_initialize";
+ }
+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(Crt1)));
if (Entry) {
@@ -106,6 +137,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Entry));
}
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString("-shared"));
+
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
@@ -124,14 +158,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
+ // When optimizing, if wasm-opt is available, run it.
+ std::string WasmOptPath;
+ if (Args.getLastArg(options::OPT_O_Group)) {
+ WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
+ if (WasmOptPath == "wasm-opt") {
+ WasmOptPath = {};
+ }
+ }
+
+ if (!WasmOptPath.empty()) {
+ CmdArgs.push_back("--keep-section=target_features");
+ }
+
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Linker, CmdArgs, Inputs, Output));
- // When optimizing, if wasm-opt is available, run it.
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- auto WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
- if (WasmOptPath != "wasm-opt") {
+ if (!WasmOptPath.empty()) {
StringRef OOpt = "s";
if (A->getOption().matches(options::OPT_O4) ||
A->getOption().matches(options::OPT_Ofast))
@@ -143,13 +188,13 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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());
+ ArgStringList OptArgs;
+ OptArgs.push_back(Output.getFilename());
+ OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
+ OptArgs.push_back("-o");
+ OptArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs,
+ JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs,
Inputs, Output));
}
}
@@ -193,6 +238,12 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
}
}
+const char *WebAssembly::getDefaultLinker() const {
+ if (getOS() == "wasip2")
+ return "wasm-component-ld";
+ return "wasm-ld";
+}
+
bool WebAssembly::IsMathErrnoDefault() const { return false; }
bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }
@@ -207,8 +258,6 @@ bool WebAssembly::isPIEDefault(const llvm::opt::ArgList &Args) const {
bool WebAssembly::isPICDefaultForced() const { return false; }
-bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; }
-
bool WebAssembly::hasBlocksRuntime() const { return false; }
// TODO: Support profiling.
@@ -302,7 +351,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
StringRef Opt = A->getValue(0);
- if (Opt.startswith("-emscripten-cxx-exceptions-allowed")) {
+ if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) {
// '-mllvm -emscripten-cxx-exceptions-allowed' should be used with
// '-mllvm -enable-emscripten-cxx-exceptions'
bool EmEHArgExists = false;
@@ -329,7 +378,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
}
}
- if (Opt.startswith("-wasm-enable-sjlj")) {
+ if (Opt.starts_with("-wasm-enable-sjlj")) {
// '-mllvm -wasm-enable-sjlj' is not compatible with
// '-mno-exception-handling'
if (DriverArgs.hasFlag(options::OPT_mno_exception_handing,
@@ -371,7 +420,11 @@ ToolChain::CXXStdlibType
WebAssembly::GetCXXStdlibType(const ArgList &Args) const {
if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
StringRef Value = A->getValue();
- if (Value != "libc++")
+ if (Value == "libc++")
+ return ToolChain::CST_Libcxx;
+ else if (Value == "libstdc++")
+ return ToolChain::CST_Libstdcxx;
+ else
getDriver().Diag(diag::err_drv_invalid_stdlib_name)
<< A->getAsString(Args);
}
@@ -417,17 +470,18 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- if (!DriverArgs.hasArg(options::OPT_nostdlibinc) &&
- !DriverArgs.hasArg(options::OPT_nostdincxx)) {
- if (getTriple().getOS() != llvm::Triple::UnknownOS) {
- const std::string MultiarchTriple =
- getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/include/" + MultiarchTriple +
- "/c++/v1");
- }
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/include/c++/v1");
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc,
+ options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addLibCxxIncludePaths(DriverArgs, CC1Args);
+ break;
+ case ToolChain::CST_Libstdcxx:
+ addLibStdCXXIncludePaths(DriverArgs, CC1Args);
+ break;
}
}
@@ -437,10 +491,13 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ if (Args.hasArg(options::OPT_fexperimental_library))
+ CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
break;
case ToolChain::CST_Libstdcxx:
- llvm_unreachable("invalid stdlib name");
+ CmdArgs.push_back("-lstdc++");
+ break;
}
}
@@ -449,9 +506,86 @@ SanitizerMask WebAssembly::getSupportedSanitizers() const {
if (getTriple().isOSEmscripten()) {
Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address;
}
+ // -fsanitize=function places two words before the function label, which are
+ // -unsupported.
+ Res &= ~SanitizerKind::Function;
return Res;
}
Tool *WebAssembly::buildLinker() const {
return new tools::wasm::Linker(*this);
}
+
+void WebAssembly::addLibCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ std::string SysRoot = computeSysRoot();
+ std::string LibPath = SysRoot + "/include";
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTriple(), SysRoot);
+ bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS);
+
+ std::string Version = detectLibcxxVersion(LibPath);
+ if (Version.empty())
+ return;
+
+ // First add the per-target include path if the OS is known.
+ if (IsKnownOs) {
+ std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version;
+ addSystemInclude(DriverArgs, CC1Args, TargetDir);
+ }
+
+ // Second add the generic one.
+ addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version);
+}
+
+void WebAssembly::addLibStdCXXIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ // We cannot use GCCInstallationDetector here as the sysroot usually does
+ // not contain a full GCC installation.
+ // Instead, we search the given sysroot for /usr/include/xx, similar
+ // to how we do it for libc++.
+ const Driver &D = getDriver();
+ std::string SysRoot = computeSysRoot();
+ std::string LibPath = SysRoot + "/include";
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTriple(), SysRoot);
+ bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS);
+
+ // This is similar to detectLibcxxVersion()
+ std::string Version;
+ {
+ std::error_code EC;
+ Generic_GCC::GCCVersion MaxVersion =
+ Generic_GCC::GCCVersion::Parse("0.0.0");
+ SmallString<128> Path(LibPath);
+ llvm::sys::path::append(Path, "c++");
+ for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Path, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ if (VersionText[0] != 'v') {
+ auto Version = Generic_GCC::GCCVersion::Parse(VersionText);
+ if (Version > MaxVersion)
+ MaxVersion = Version;
+ }
+ }
+ if (MaxVersion.Major > 0)
+ Version = MaxVersion.Text;
+ }
+
+ if (Version.empty())
+ return;
+
+ // First add the per-target include path if the OS is known.
+ if (IsKnownOs) {
+ std::string TargetDir = LibPath + "/c++/" + Version + "/" + MultiarchTriple;
+ addSystemInclude(DriverArgs, CC1Args, TargetDir);
+ }
+
+ // Second add the generic one.
+ addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version);
+ // Third the backward one.
+ addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version + "/backward");
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h
index b4c3082a089a..76e0ca39bd74 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h
@@ -18,7 +18,7 @@ namespace driver {
namespace tools {
namespace wasm {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
explicit Linker(const ToolChain &TC) : Tool("wasm::Linker", "linker", TC) {}
bool isLinkJob() const override { return true; }
@@ -47,7 +47,6 @@ private:
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
- bool IsIntegratedAssemblerDefault() const override;
bool hasBlocksRuntime() const override;
bool SupportsProfiling() const override;
bool HasNativeLLVMSupport() const override;
@@ -68,13 +67,22 @@ private:
llvm::opt::ArgStringList &CmdArgs) const override;
SanitizerMask getSupportedSanitizers() const override;
- const char *getDefaultLinker() const override { return "wasm-ld"; }
+ const char *getDefaultLinker() const override;
+
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
Tool *buildLinker() const override;
std::string getMultiarchTriple(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef SysRoot) const override;
+
+ void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ void addLibStdCXXIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp
index 29fa82aec0a9..c95ebabdd30c 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp
@@ -63,11 +63,10 @@ void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
}
if (Args.hasArg(options::OPT_v))
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h
index d9a05da3c678..95359a6e2542 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h
@@ -20,7 +20,7 @@ namespace XCore {
// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and
// Compile.
// We simply use "clang -cc1" for those actions.
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
public:
Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", TC) {}
@@ -31,7 +31,7 @@ public:
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {}
@@ -57,6 +57,7 @@ protected:
Tool *buildLinker() const override;
public:
+ bool IsIntegratedAssemblerDefault() const override { return false; }
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp
index f921227076a5..96dbf602e7c1 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp
@@ -11,11 +11,17 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/WithColor.h"
+using namespace clang;
using namespace clang::driver;
+using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
+using namespace llvm;
using namespace llvm::opt;
-using namespace clang;
+using namespace llvm::sys;
ZOS::ZOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: ToolChain(D, Triple, Args) {}
@@ -31,3 +37,303 @@ void ZOS::addClangTargetOptions(const ArgList &DriverArgs,
options::OPT_fno_aligned_allocation))
CC1Args.push_back("-faligned-alloc-unavailable");
}
+
+void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ 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 z/OS 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, ResponseFileSupport::None(),
+ Exec, CmdArgs, Inputs));
+}
+
+static std::string getLEHLQ(const ArgList &Args) {
+ if (Args.hasArg(options::OPT_mzos_hlq_le_EQ)) {
+ Arg *LEHLQArg = Args.getLastArg(options::OPT_mzos_hlq_le_EQ);
+ StringRef HLQ = LEHLQArg->getValue();
+ if (!HLQ.empty())
+ return HLQ.str();
+ }
+ return "CEE";
+}
+
+static std::string getClangHLQ(const ArgList &Args) {
+ if (Args.hasArg(options::OPT_mzos_hlq_clang_EQ)) {
+ Arg *ClangHLQArg = Args.getLastArg(options::OPT_mzos_hlq_clang_EQ);
+ StringRef HLQ = ClangHLQArg->getValue();
+ if (!HLQ.empty())
+ return HLQ.str();
+ }
+ return getLEHLQ(Args);
+}
+
+static std::string getCSSHLQ(const ArgList &Args) {
+ if (Args.hasArg(options::OPT_mzos_hlq_csslib_EQ)) {
+ Arg *CsslibHLQArg = Args.getLastArg(options::OPT_mzos_hlq_csslib_EQ);
+ StringRef HLQ = CsslibHLQArg->getValue();
+ if (!HLQ.empty())
+ return HLQ.str();
+ }
+ return "SYS1";
+}
+
+void zos::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ZOS &ToolChain = static_cast<const ZOS &>(getToolChain());
+ ArgStringList CmdArgs;
+
+ const bool IsSharedLib =
+ Args.hasFlag(options::OPT_shared, options::OPT_static, false);
+
+ assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ SmallString<128> LinkerOptions;
+ LinkerOptions = "AMODE=";
+ LinkerOptions += "64";
+ LinkerOptions += ",LIST";
+ LinkerOptions += ",DYNAM=DLL";
+ LinkerOptions += ",MSGLEVEL=4";
+ LinkerOptions += ",CASE=MIXED";
+ LinkerOptions += ",REUS=RENT";
+
+ CmdArgs.push_back("-b");
+ CmdArgs.push_back(Args.MakeArgString(LinkerOptions));
+
+ if (!IsSharedLib) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("CELQSTRT");
+
+ CmdArgs.push_back("-O");
+ CmdArgs.push_back("CELQSTRT");
+
+ CmdArgs.push_back("-u");
+ CmdArgs.push_back("CELQMAIN");
+ }
+
+ // Generate side file if -shared option is present.
+ if (IsSharedLib) {
+ StringRef OutputName = Output.getFilename();
+ // Strip away the last file suffix in presence from output name and add
+ // a new .x suffix.
+ size_t Suffix = OutputName.find_last_of('.');
+ const char *SideDeckName =
+ Args.MakeArgString(OutputName.substr(0, Suffix) + ".x");
+ CmdArgs.push_back("-x");
+ CmdArgs.push_back(SideDeckName);
+ } else {
+ // We need to direct side file to /dev/null to suppress linker warning when
+ // the object file contains exported symbols, and -shared or
+ // -Wl,-x<sidedeck>.x is not specified.
+ CmdArgs.push_back("-x");
+ CmdArgs.push_back("/dev/null");
+ }
+
+ // Add archive library search paths.
+ Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
+
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ // Specify linker input file(s)
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ // z/OS tool chain depends on LE data sets and the CSSLIB data set.
+ // These data sets can have different high level qualifiers (HLQs)
+ // as each installation can define them differently.
+
+ std::string LEHLQ = getLEHLQ(Args);
+ std::string CsslibHLQ = getCSSHLQ(Args);
+
+ StringRef ld_env_var = StringRef(getenv("_LD_SYSLIB")).trim();
+ if (ld_env_var.empty()) {
+ CmdArgs.push_back("-S");
+ CmdArgs.push_back(Args.MakeArgString("//'" + LEHLQ + ".SCEEBND2'"));
+ CmdArgs.push_back("-S");
+ CmdArgs.push_back(Args.MakeArgString("//'" + CsslibHLQ + ".CSSLIB'"));
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ ld_env_var = StringRef(getenv("_LD_SIDE_DECKS")).trim();
+ if (ld_env_var.empty()) {
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS001)'"));
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS003)'"));
+ } else {
+ SmallVector<StringRef> ld_side_deck;
+ ld_env_var.split(ld_side_deck, ":");
+ for (StringRef ld_loc : ld_side_deck) {
+ CmdArgs.push_back((ld_loc.str()).c_str());
+ }
+ }
+ }
+ // Link libc++ library
+ if (ToolChain.ShouldLinkCXXStdlib(Args)) {
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
+
+ // Specify compiler-rt library path for linker
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
+ AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+ Exec, CmdArgs, Inputs));
+}
+
+ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const {
+ return ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const {
+ return ToolChain::CST_Libcxx;
+}
+
+void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libstdcxx:
+ llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS");
+ break;
+ case ToolChain::CST_Libcxx: {
+ std::string ClangHLQ = getClangHLQ(Args);
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXE)'"));
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXS)'"));
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXP)'"));
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXA)'"));
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQXLA)'"));
+ CmdArgs.push_back(
+ Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQUNW)'"));
+ } break;
+ }
+}
+
+auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); }
+
+auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); }
+
+void ZOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ const Driver &D = getDriver();
+
+ // resolve ResourceDir
+ std::string ResourceDir(D.ResourceDir);
+
+ // zos_wrappers must take highest precedence
+
+ // - <clang>/lib/clang/<ver>/include/zos_wrappers
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(ResourceDir);
+ path::append(P, "include", "zos_wrappers");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+
+ // - <clang>/lib/clang/<ver>/include
+ SmallString<128> P2(ResourceDir);
+ path::append(P2, "include");
+ addSystemInclude(DriverArgs, CC1Args, P2.str());
+ }
+
+ // - /usr/include
+ if (Arg *SysIncludeArg =
+ DriverArgs.getLastArg(options::OPT_mzos_sys_include_EQ)) {
+ StringRef SysInclude = SysIncludeArg->getValue();
+
+ // fall back to the default include path
+ if (!SysInclude.empty()) {
+
+ // -mzos-sys-include opton can have colon separated
+ // list of paths, so we need to parse the value.
+ StringRef PathLE(SysInclude);
+ size_t Colon = PathLE.find(':');
+ if (Colon == StringRef::npos) {
+ addSystemInclude(DriverArgs, CC1Args, PathLE.str());
+ return;
+ }
+
+ while (Colon != StringRef::npos) {
+ SmallString<128> P = PathLE.substr(0, Colon);
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ PathLE = PathLE.substr(Colon + 1);
+ Colon = PathLE.find(':');
+ }
+ if (PathLE.size())
+ addSystemInclude(DriverArgs, CC1Args, PathLE.str());
+
+ return;
+ }
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, "/usr/include");
+}
+
+void ZOS::TryAddIncludeFromPath(llvm::SmallString<128> Path,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ if (!getVFS().exists(Path)) {
+ if (DriverArgs.hasArg(options::OPT_v))
+ WithColor::warning(errs(), "Clang")
+ << "ignoring nonexistent directory \"" << Path << "\"\n";
+ if (!DriverArgs.hasArg(options::OPT__HASH_HASH_HASH))
+ return;
+ }
+ addSystemInclude(DriverArgs, CC1Args, Path);
+}
+
+void ZOS::AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx: {
+ // <install>/bin/../include/c++/v1
+ llvm::SmallString<128> InstallBin =
+ llvm::StringRef(getDriver().getInstalledDir());
+ llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
+ TryAddIncludeFromPath(InstallBin, DriverArgs, CC1Args);
+ break;
+ }
+ case ToolChain::CST_Libstdcxx:
+ llvm::report_fatal_error(
+ "picking up libstdc++ headers is unimplemented on z/OS");
+ break;
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h
index 50bff0993561..45204ba0a543 100644
--- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h
+++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h
@@ -14,6 +14,39 @@
namespace clang {
namespace driver {
+namespace tools {
+
+/// Directly call system default assembler and linker.
+namespace zos {
+
+class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("zos::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 final : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("zos::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 zos
+} // end namespace tools
+
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY ZOS : public ToolChain {
@@ -28,11 +61,34 @@ public:
}
bool isPICDefaultForced() const override { return false; }
- bool IsIntegratedAssemblerDefault() const override { return true; }
+ void TryAddIncludeFromPath(llvm::SmallString<128> Path,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ unsigned GetDefaultDwarfVersion() const override { return 4; }
+ CXXStdlibType GetDefaultCXXStdlibType() const override;
+
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override;
void addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const override;
+
+ const char *getDefaultLinker() const override { return "/bin/ld"; }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
} // end namespace toolchains
diff --git a/contrib/llvm-project/clang/lib/Driver/Types.cpp b/contrib/llvm-project/clang/lib/Driver/Types.cpp
index 8f6adc6c2ad1..a7b6b9000e1d 100644
--- a/contrib/llvm-project/clang/lib/Driver/Types.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/Types.cpp
@@ -42,7 +42,7 @@ static constexpr TypeInfo TypeInfos[] = {
#include "clang/Driver/Types.def"
#undef TYPE
};
-static const unsigned numTypes = llvm::array_lengthof(TypeInfos);
+static const unsigned numTypes = std::size(TypeInfos);
static const TypeInfo &getInfo(unsigned id) {
assert(id > 0 && id - 1 < numTypes && "Invalid Type ID.");
@@ -65,16 +65,23 @@ static bool isPreprocessedModuleType(ID Id) {
return Id == TY_CXXModule || Id == TY_PP_CXXModule;
}
+static bool isPreprocessedHeaderUnitType(ID Id) {
+ return Id == TY_CXXSHeader || Id == TY_CXXUHeader || Id == TY_CXXHUHeader ||
+ Id == TY_PP_CXXHeaderUnit;
+}
+
types::ID types::getPrecompiledType(ID Id) {
if (isPreprocessedModuleType(Id))
return TY_ModuleFile;
+ if (isPreprocessedHeaderUnitType(Id))
+ return TY_HeaderUnit;
if (onlyPrecompileType(Id))
return TY_PCH;
return TY_INVALID;
}
-const char *types::getTypeTempSuffix(ID Id, bool CLMode) {
- if (CLMode) {
+const char *types::getTypeTempSuffix(ID Id, bool CLStyle) {
+ if (CLStyle) {
switch (Id) {
case TY_Object:
case TY_LTO_BC:
@@ -126,7 +133,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_Asm:
case TY_C: case TY_PP_C:
- case TY_CL: case TY_CLCXX:
+ case TY_CL: case TY_PP_CL: case TY_CLCXX: case TY_PP_CLCXX:
case TY_CUDA: case TY_PP_CUDA:
case TY_CUDA_DEVICE:
case TY_HIP:
@@ -139,6 +146,10 @@ bool types::isAcceptedByClang(ID Id) {
case TY_CLHeader:
case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader:
+ case TY_CXXSHeader:
+ case TY_CXXUHeader:
+ case TY_CXXHUHeader:
+ case TY_PP_CXXHeaderUnit:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
case TY_CXXModule: case TY_PP_CXXModule:
case TY_AST: case TY_ModuleFile: case TY_PCH:
@@ -148,6 +159,20 @@ bool types::isAcceptedByClang(ID Id) {
}
}
+bool types::isAcceptedByFlang(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_Fortran:
+ case TY_PP_Fortran:
+ return true;
+ case TY_LLVM_IR:
+ case TY_LLVM_BC:
+ return true;
+ }
+}
+
bool types::isDerivedFromC(ID Id) {
switch (Id) {
default:
@@ -156,7 +181,9 @@ bool types::isDerivedFromC(ID Id) {
case TY_PP_C:
case TY_C:
case TY_CL:
+ case TY_PP_CL:
case TY_CLCXX:
+ case TY_PP_CLCXX:
case TY_PP_CUDA:
case TY_CUDA:
case TY_CUDA_DEVICE:
@@ -210,8 +237,13 @@ bool types::isCXX(ID Id) {
case TY_CXX: case TY_PP_CXX:
case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias:
case TY_CXXHeader: case TY_PP_CXXHeader:
+ case TY_CXXSHeader:
+ case TY_CXXUHeader:
+ case TY_CXXHUHeader:
+ case TY_PP_CXXHeaderUnit:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
case TY_CXXModule: case TY_PP_CXXModule:
+ case TY_PP_CLCXX:
case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE:
case TY_HIP:
case TY_PP_HIP:
@@ -257,15 +289,7 @@ 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::isHLSL(ID Id) { return Id == TY_HLSL; }
bool types::isSrcFile(ID Id) {
return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID;
@@ -273,66 +297,75 @@ bool types::isSrcFile(ID Id) {
types::ID types::lookupTypeForExtension(llvm::StringRef Ext) {
return llvm::StringSwitch<types::ID>(Ext)
- .Case("c", TY_C)
- .Case("C", TY_CXX)
- .Case("F", TY_Fortran)
- .Case("f", TY_PP_Fortran)
- .Case("h", TY_CHeader)
- .Case("H", TY_CXXHeader)
- .Case("i", TY_PP_C)
- .Case("m", TY_ObjC)
- .Case("M", TY_ObjCXX)
- .Case("o", TY_Object)
- .Case("S", TY_Asm)
- .Case("s", TY_PP_Asm)
- .Case("bc", TY_LLVM_BC)
- .Case("cc", TY_CXX)
- .Case("CC", TY_CXX)
- .Case("cl", TY_CL)
- .Case("clcpp", TY_CLCXX)
- .Case("cp", TY_CXX)
- .Case("cu", TY_CUDA)
- .Case("hh", TY_CXXHeader)
- .Case("ii", TY_PP_CXX)
- .Case("ll", TY_LLVM_IR)
- .Case("mi", TY_PP_ObjC)
- .Case("mm", TY_ObjCXX)
- .Case("rs", TY_RenderScript)
- .Case("adb", TY_Ada)
- .Case("ads", TY_Ada)
- .Case("asm", TY_PP_Asm)
- .Case("ast", TY_AST)
- .Case("ccm", TY_CXXModule)
- .Case("cpp", TY_CXX)
- .Case("CPP", TY_CXX)
- .Case("c++", TY_CXX)
- .Case("C++", TY_CXX)
- .Case("cui", TY_PP_CUDA)
- .Case("cxx", TY_CXX)
- .Case("CXX", TY_CXX)
- .Case("F90", TY_Fortran)
- .Case("f90", TY_PP_Fortran)
- .Case("F95", TY_Fortran)
- .Case("f95", TY_PP_Fortran)
- .Case("for", TY_PP_Fortran)
- .Case("FOR", TY_PP_Fortran)
- .Case("fpp", TY_Fortran)
- .Case("FPP", TY_Fortran)
- .Case("gch", TY_PCH)
- .Case("hip", TY_HIP)
- .Case("hpp", TY_CXXHeader)
- .Case("hxx", TY_CXXHeader)
- .Case("iim", TY_PP_CXXModule)
- .Case("lib", TY_Object)
- .Case("mii", TY_PP_ObjCXX)
- .Case("obj", TY_Object)
- .Case("ifs", TY_IFS)
- .Case("pch", TY_PCH)
- .Case("pcm", TY_ModuleFile)
- .Case("c++m", TY_CXXModule)
- .Case("cppm", TY_CXXModule)
- .Case("cxxm", TY_CXXModule)
- .Default(TY_INVALID);
+ .Case("c", TY_C)
+ .Case("C", TY_CXX)
+ .Case("F", TY_Fortran)
+ .Case("f", TY_PP_Fortran)
+ .Case("h", TY_CHeader)
+ .Case("H", TY_CXXHeader)
+ .Case("i", TY_PP_C)
+ .Case("m", TY_ObjC)
+ .Case("M", TY_ObjCXX)
+ .Case("o", TY_Object)
+ .Case("S", TY_Asm)
+ .Case("s", TY_PP_Asm)
+ .Case("bc", TY_LLVM_BC)
+ .Case("cc", TY_CXX)
+ .Case("CC", TY_CXX)
+ .Case("cl", TY_CL)
+ .Case("cli", TY_PP_CL)
+ .Case("clcpp", TY_CLCXX)
+ .Case("clii", TY_PP_CLCXX)
+ .Case("cp", TY_CXX)
+ .Case("cu", TY_CUDA)
+ .Case("hh", TY_CXXHeader)
+ .Case("ii", TY_PP_CXX)
+ .Case("ll", TY_LLVM_IR)
+ .Case("mi", TY_PP_ObjC)
+ .Case("mm", TY_ObjCXX)
+ .Case("rs", TY_RenderScript)
+ .Case("adb", TY_Ada)
+ .Case("ads", TY_Ada)
+ .Case("asm", TY_PP_Asm)
+ .Case("ast", TY_AST)
+ .Case("ccm", TY_CXXModule)
+ .Case("cpp", TY_CXX)
+ .Case("CPP", TY_CXX)
+ .Case("c++", TY_CXX)
+ .Case("C++", TY_CXX)
+ .Case("cui", TY_PP_CUDA)
+ .Case("cxx", TY_CXX)
+ .Case("CXX", TY_CXX)
+ .Case("F03", TY_Fortran)
+ .Case("f03", TY_PP_Fortran)
+ .Case("F08", TY_Fortran)
+ .Case("f08", TY_PP_Fortran)
+ .Case("F90", TY_Fortran)
+ .Case("f90", TY_PP_Fortran)
+ .Case("F95", TY_Fortran)
+ .Case("f95", TY_PP_Fortran)
+ .Case("for", TY_PP_Fortran)
+ .Case("FOR", TY_PP_Fortran)
+ .Case("fpp", TY_Fortran)
+ .Case("FPP", TY_Fortran)
+ .Case("gch", TY_PCH)
+ .Case("hip", TY_HIP)
+ .Case("hipi", TY_PP_HIP)
+ .Case("hpp", TY_CXXHeader)
+ .Case("hxx", TY_CXXHeader)
+ .Case("iim", TY_PP_CXXModule)
+ .Case("iih", TY_PP_CXXHeaderUnit)
+ .Case("lib", TY_Object)
+ .Case("mii", TY_PP_ObjCXX)
+ .Case("obj", TY_Object)
+ .Case("ifs", TY_IFS)
+ .Case("pch", TY_PCH)
+ .Case("pcm", TY_ModuleFile)
+ .Case("c++m", TY_CXXModule)
+ .Case("cppm", TY_CXXModule)
+ .Case("cxxm", TY_CXXModule)
+ .Case("hlsl", TY_HLSL)
+ .Default(TY_INVALID);
}
types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
diff --git a/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp b/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp
index 63b575178bd1..8c5134e25013 100644
--- a/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp
+++ b/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp
@@ -22,12 +22,7 @@ using namespace clang;
using namespace clang::driver;
using namespace llvm::opt;
-namespace {
-constexpr char XRayInstrumentOption[] = "-fxray-instrument";
-constexpr char XRayInstructionThresholdOption[] =
- "-fxray-instruction-threshold=";
-constexpr const char *const XRaySupportedModes[] = {"xray-fdr", "xray-basic"};
-} // namespace
+constexpr const char *XRaySupportedModes[] = {"xray-fdr", "xray-basic"};
XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
const Driver &D = TC.getDriver();
@@ -35,80 +30,49 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
if (!Args.hasFlag(options::OPT_fxray_instrument,
options::OPT_fno_xray_instrument, false))
return;
- if (Triple.getOS() == llvm::Triple::Linux) {
+ XRayInstrument = Args.getLastArg(options::OPT_fxray_instrument);
+ if (Triple.isMacOSX()) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::x86_64:
+ break;
+ default:
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << XRayInstrument->getSpelling() << Triple.str();
+ break;
+ }
+ } else if (Triple.isOSBinFormatELF()) {
switch (Triple.getArch()) {
case llvm::Triple::x86_64:
case llvm::Triple::arm:
case llvm::Triple::aarch64:
case llvm::Triple::hexagon:
case llvm::Triple::ppc64le:
+ case llvm::Triple::loongarch64:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
break;
default:
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on " + Triple.str());
- }
- } else if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() ||
- Triple.isOSNetBSD() || Triple.isMacOSX()) {
- if (Triple.getArch() != llvm::Triple::x86_64) {
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on " + Triple.str());
- }
- } else if (Triple.getOS() == llvm::Triple::Fuchsia) {
- switch (Triple.getArch()) {
- case llvm::Triple::x86_64:
- case llvm::Triple::aarch64:
- break;
- default:
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on " + Triple.str());
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << XRayInstrument->getSpelling() << Triple.str();
}
} else {
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on " + Triple.str());
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << XRayInstrument->getSpelling() << 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_,
- options::OPT_fxray_instruction_threshold_EQ)) {
- StringRef S = A->getValue();
- if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0)
- D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
- }
-
- // By default, the back-end will not emit the lowering for XRay customevent
- // calls if the function is not instrumented. In the future we will change
- // this default to be the reverse, but in the meantime we're going to
- // introduce the new functionality behind a flag.
- if (Args.hasFlag(options::OPT_fxray_always_emit_customevents,
- options::OPT_fno_xray_always_emit_customevents, false))
- XRayAlwaysEmitCustomEvents = true;
-
- if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents,
- options::OPT_fno_xray_always_emit_typedevents, false))
- XRayAlwaysEmitTypedEvents = true;
+ << XRayInstrument->getSpelling() << A->getSpelling();
if (!Args.hasFlag(options::OPT_fxray_link_deps,
- options::OPT_fnoxray_link_deps, true))
+ options::OPT_fno_xray_link_deps, true))
XRayRT = false;
- if (Args.hasFlag(options::OPT_fxray_ignore_loops,
- options::OPT_fno_xray_ignore_loops, false))
- XRayIgnoreLoops = true;
-
- XRayFunctionIndex = Args.hasFlag(options::OPT_fxray_function_index,
- options::OPT_fno_xray_function_index, true);
-
auto Bundles =
Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle);
if (Bundles.empty())
@@ -187,21 +151,6 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
Modes.push_back(std::string(M));
}
- if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) {
- StringRef S = A->getValue();
- if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1)
- D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
- }
-
- if (const Arg *A =
- Args.getLastArg(options::OPT_fxray_selected_function_group)) {
- StringRef S = A->getValue();
- if (S.getAsInteger(0, XRaySelectedFunctionGroup) ||
- XRaySelectedFunctionGroup < 0 ||
- XRaySelectedFunctionGroup >= XRayFunctionGroups)
- D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
- }
-
// Then we want to sort and unique the modes we've collected.
llvm::sort(Modes);
Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end());
@@ -211,34 +160,52 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, types::ID InputType) const {
if (!XRayInstrument)
return;
+ const Driver &D = TC.getDriver();
+ XRayInstrument->render(Args, CmdArgs);
- CmdArgs.push_back(XRayInstrumentOption);
-
- if (XRayAlwaysEmitCustomEvents)
- CmdArgs.push_back("-fxray-always-emit-customevents");
-
- if (XRayAlwaysEmitTypedEvents)
- CmdArgs.push_back("-fxray-always-emit-typedevents");
-
- if (XRayIgnoreLoops)
- CmdArgs.push_back("-fxray-ignore-loops");
+ // By default, the back-end will not emit the lowering for XRay customevent
+ // calls if the function is not instrumented. In the future we will change
+ // this default to be the reverse, but in the meantime we're going to
+ // introduce the new functionality behind a flag.
+ Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_customevents,
+ options::OPT_fno_xray_always_emit_customevents);
- if (!XRayFunctionIndex)
- CmdArgs.push_back("-fno-xray-function-index");
+ Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_typedevents,
+ options::OPT_fno_xray_always_emit_typedevents);
+ Args.addOptInFlag(CmdArgs, options::OPT_fxray_ignore_loops,
+ options::OPT_fno_xray_ignore_loops);
+ Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index,
+ options::OPT_fno_xray_function_index);
- if (XRayFunctionGroups > 1) {
- CmdArgs.push_back(Args.MakeArgString(Twine("-fxray-function-groups=") +
- Twine(XRayFunctionGroups)));
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) {
+ int Value;
+ StringRef S = A->getValue();
+ if (S.getAsInteger(0, Value) || Value < 0)
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ else
+ A->render(Args, CmdArgs);
}
- if (XRaySelectedFunctionGroup != 0) {
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-fxray-selected-function-group=") +
- Twine(XRaySelectedFunctionGroup)));
+ int XRayFunctionGroups = 1;
+ int XRaySelectedFunctionGroup = 0;
+ if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) {
+ StringRef S = A->getValue();
+ if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1)
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ if (XRayFunctionGroups > 1)
+ A->render(Args, CmdArgs);
+ }
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fxray_selected_function_group)) {
+ StringRef S = A->getValue();
+ if (S.getAsInteger(0, XRaySelectedFunctionGroup) ||
+ XRaySelectedFunctionGroup < 0 ||
+ XRaySelectedFunctionGroup >= XRayFunctionGroups)
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ if (XRaySelectedFunctionGroup != 0)
+ A->render(Args, CmdArgs);
}
-
- CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) +
- Twine(InstructionThreshold)));
for (const auto &Always : AlwaysInstrumentFiles) {
SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument=");