19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/SmallPtrSet.h"
21#include "llvm/Option/ArgList.h"
22#include "llvm/Option/OptSpecifier.h"
23#include "llvm/Option/Option.h"
24#include "llvm/Support/FileSystem.h"
25#include "llvm/Support/ThreadPool.h"
26#include "llvm/Support/Threading.h"
27#include "llvm/Support/raw_ostream.h"
28#include "llvm/TargetParser/Triple.h"
33#include <system_error>
41 InputArgList *_Args, DerivedArgList *_TranslatedArgs,
43 : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
44 TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
46 OrderedOffloadingToolchains.insert(
53 if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
56 delete TranslatedArgs;
60 for (
auto Arg : TCArgs)
61 if (Arg.second != TranslatedArgs)
69 TC = &DefaultToolChain;
71 DerivedArgList *&Entry = TCArgs[{TC, BA, DeviceOffloadKind}];
74 DerivedArgList *OpenMPArgs =
nullptr;
79 *TranslatedArgs, HostTC->
getTriple(), AllocatedArgs);
82 DerivedArgList *NewDAL =
nullptr;
95 if (NewDAL && TheDriver.IsCLMode()) {
99 *NewDAL, DefaultToolChain.getTriple(), *TranslatedArgs);
105 Entry = TC->
TranslateArgs(*TranslatedArgs, BA, DeviceOffloadKind);
107 Entry = TranslatedArgs;
117 for (
auto *ArgPtr : AllocatedArgs)
118 Entry->AddSynthesizedArg(ArgPtr);
138 if (!llvm::sys::fs::can_write(
File) || !llvm::sys::fs::is_regular_file(
File))
141 if (std::error_code EC = llvm::sys::fs::remove(
File)) {
155 bool IssueErrors)
const {
157 for (
const auto &
File: Files)
164 bool IssueErrors)
const {
166 for (
const auto &
File : Files) {
169 if (JA &&
File.first != JA)
177 const Command *&FailingCommand,
178 bool LogOnly)
const {
181 raw_ostream *OS = &llvm::errs();
182 std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
187 !
getDriver().CCPrintOptionsFilename.empty()) {
189 OwnedStream.reset(
new llvm::raw_fd_ostream(
191 llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF));
198 OS = OwnedStream.get();
202 *OS <<
"[Logging clang options]\n";
204 C.Print(*OS,
"\n",
getDriver().CCPrintOptions);
211 bool ExecutionFailed;
212 int Res =
C.Execute(Redirects, &
Error, &ExecutionFailed);
214 PostCallback(
C, Res);
215 if (!
Error.empty()) {
216 assert(Res &&
"Error string set with 0 result code!");
223 return ExecutionFailed ? 1 : Res;
230 if (FailingCommands.empty())
240 for (
const auto &CI : FailingCommands)
241 if (A == &(CI.second->getSource()))
244 for (
const auto *AI : A->
inputs())
253 return ActionDependsOn(Input, Other);
271 return llvm::none_of(Jobs, [&](
const Command *Job) {
276static std::optional<llvm::ThreadPoolStrategy>
282 if (!OffloadJobs.isValid())
286 return llvm::jobserver_concurrency();
288 if (OffloadJobs.NumThreads < 2)
291 return llvm::hardware_concurrency(std::min(OffloadJobs.NumThreads, NumJobs));
303 ArrayRef<std::optional<StringRef>> Redirects,
306 llvm::SmallPtrSetImpl<const Command *> &Done,
308 const Command &Job = *JobStorage[StartIndex];
315 for (
size_t I = StartIndex + 1; I < JobStorage.size(); ++I) {
316 const Command &Candidate = *JobStorage[I];
317 if (Done.contains(&Candidate) ||
326 auto EarlierJobs = llvm::make_range(JobStorage.begin() + StartIndex,
327 JobStorage.begin() + I);
328 if (!llvm::all_of(EarlierJobs, [&](
const auto &
Other) {
329 return Done.contains(
Other.get()) ||
334 ParallelJobs.push_back(&Candidate);
337 std::optional<llvm::ThreadPoolStrategy> Strategy =
343 llvm::DefaultThreadPool Pool(*Strategy);
344 for (
auto IndexedJob : llvm::enumerate(ParallelJobs)) {
345 size_t Index = IndexedJob.index();
346 const Command *ParallelJob = IndexedJob.value();
347 Pool.async([&, Index, ParallelJob] {
348 Results[Index].Res = ParallelJob->
Execute(
349 Redirects, &Results[Index].
Error, &Results[Index].ExecutionFailed);
354 for (
auto [Index, ParallelJob] : llvm::enumerate(ParallelJobs)) {
356 if (!
Result.Error.empty()) {
357 assert(
Result.Res &&
"Error string set with 0 result code!");
358 D.
Diag(diag::err_drv_command_failure) <<
Result.Error;
362 FailingCommands.push_back(
363 std::make_pair(
Result.ExecutionFailed ? 1 :
Result.Res, ParallelJob));
367 for (
const Command *ParallelJob : ParallelJobs)
368 Done.insert(ParallelJob);
374 bool LogOnly)
const {
379 bool CanRunJobsInParallel =
383 Redirects.empty() && !PostCallback;
389 const auto &JobStorage = Jobs.getJobs();
390 for (
size_t I = 0; I < JobStorage.size(); ++I) {
391 const auto &Job = *JobStorage[I];
392 if (Done.contains(&Job))
397 if (CanRunJobsInParallel &&
399 JobStorage, I, Done, FailingCommands))
402 const Command *FailingCommand =
nullptr;
404 FailingCommands.push_back(std::make_pair(Res, FailingCommand));
406 if (TheDriver.IsCLMode())
413 ForDiagnostics =
true;
421 if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
427 FailureResultFiles.clear();
431 OptSpecifier OutputOpts[] = {
432 options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M,
433 options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ,
434 options::OPT_MQ, options::OPT_MT, options::OPT_MV};
435 for (
const auto &Opt : OutputOpts) {
436 if (TranslatedArgs->hasArg(Opt))
437 TranslatedArgs->eraseArg(Opt);
439 TranslatedArgs->ClaimAllArgs();
443 for (
auto Arg : TCArgs)
444 if (Arg.second != TranslatedArgs)
449 Redirects = {std::nullopt, {
""}, {
""}};
452 ForceKeepTempFiles =
true;
460 this->Redirects = Redirects;
static bool ActionFailed(const Action *A, const FailingCommandList &FailingCommands)
static bool tryExecuteParallelOffloadJobGroup(const Driver &D, const ArgList &Args, ArrayRef< std::optional< StringRef > > Redirects, const JobList::list_type &JobStorage, size_t StartIndex, llvm::SmallPtrSetImpl< const Command * > &Done, FailingCommandList &FailingCommands)
static bool HasDistinctBoundArch(const Command &Candidate, ArrayRef< const Command * > Jobs)
static bool ActionDependsOn(const Action *A, const Action *Other)
static bool SameParallelOffloadJobGroup(const Command &A, const Command &B)
SmallVectorImpl< std::pair< int, const Command * > > FailingCommandList
static bool CanRunInParallelOffloadJobGroup(const Command &Job)
static std::optional< llvm::ThreadPoolStrategy > getParallelOffloadJobsStrategy(const ArgList &Args, unsigned NumJobs)
Result
Implement __builtin_bit_cast and related operations.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Action - Represent an abstract compilation step to perform.
bool isOffloading(OffloadKind OKind) const
static llvm::opt::DerivedArgList * translateArgs(const llvm::opt::DerivedArgList &Args, const llvm::Triple &HostTriple, const llvm::opt::DerivedArgList &Owner)
Translate a filtered list that may contain new clang-cl options, replacing earlier /O expansions.
Command - An executable path/name and argument vector to execute.
const Action & getSource() const
getSource - Return the Action which caused the creation of this job.
StringRef getOffloadDeviceParallelJobGroup() const
bool PrintInputFilenames
Whether to print the input filenames when executing.
bool InProcess
Whether the command will be executed in this process or not.
BoundArch getBoundArch() const
Return the bound architecture for this command, if any.
virtual int Execute(ArrayRef< std::optional< StringRef > > Redirects, std::string *ErrMsg, bool *ExecutionFailed) const
int ExecuteCommand(const Command &C, const Command *&FailingCommand, bool LogOnly=false) const
ExecuteCommand - Execute an actual command.
bool CleanupFileMap(const ArgStringMap &Files, const JobAction *JA, bool IssueErrors=false) const
CleanupFileMap - Remove the files in the given map.
bool CleanupFile(const char *File, bool IssueErrors=false) const
CleanupFile - Delete a given file.
Compilation(const Driver &D, const ToolChain &DefaultToolChain, llvm::opt::InputArgList *Args, llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError)
bool CleanupFileList(const llvm::opt::ArgStringList &Files, bool IssueErrors=false) const
CleanupFileList - Remove the files in the given list.
const llvm::opt::DerivedArgList & getArgsForToolChain(const ToolChain *TC, BoundArch BA, Action::OffloadKind DeviceOffloadKind)
getArgsForToolChain - Return the derived argument list for the tool chain TC (or the default tool cha...
StringRef getSysRoot() const
Returns the sysroot path.
void Redirect(ArrayRef< std::optional< StringRef > > Redirects)
Redirect - Redirect output of this compilation.
void initCompilationForDiagnostics()
initCompilationForDiagnostics - Remove stale state and suppress output so compilation can be reexecut...
const llvm::opt::DerivedArgList & getArgs() const
void ExecuteJobs(const JobList &Jobs, SmallVectorImpl< std::pair< int, const Command * > > &FailingCommands, bool LogOnly=false) const
ExecuteJob - Execute a single job.
const ToolChain * getSingleOffloadToolChain() const
Return an offload toolchain of the provided kind.
const Driver & getDriver() const
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
std::string SysRoot
sysroot, if present
unsigned CCPrintProcessStats
Set CC_PRINT_PROC_STAT mode, which causes the driver to dump performance report to CC_PRINT_PROC_STAT...
bool IsCLMode() const
Whether the driver should follow cl.exe like behavior.
unsigned CCGenDiagnostics
Whether the driver is generating diagnostics for debugging purposes.
DiagnosticBuilder Diag(unsigned DiagID) const
unsigned CCPrintOptions
Set CC_PRINT_OPTIONS mode, which is like -v but logs the commands to CCPrintOptionsFilename or to std...
JobList - A sequence of jobs to perform.
SmallVector< std::unique_ptr< Command >, 4 > list_type
llvm::DenseMap< const JobAction *, const char * > ArgStringMap
ArgStringMap - Type used to map a JobAction to its result file.
Top level wrappers for InstallAPI frontend operations.
@ Success
Annotation was successful.
@ Other
Other implicit parameter.
Represents a bound architecture for offload / multiple architecture compilation.