brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · f8ca2a3 Raw
305 lines · cpp
1//===- Compilation.cpp - Compilation Task Implementation ------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Driver/Compilation.h"10#include "clang/Basic/LLVM.h"11#include "clang/Driver/Action.h"12#include "clang/Driver/Driver.h"13#include "clang/Driver/Job.h"14#include "clang/Driver/ToolChain.h"15#include "clang/Driver/Util.h"16#include "clang/Options/Options.h"17#include "llvm/Option/ArgList.h"18#include "llvm/Option/OptSpecifier.h"19#include "llvm/Option/Option.h"20#include "llvm/Support/FileSystem.h"21#include "llvm/Support/raw_ostream.h"22#include "llvm/TargetParser/Triple.h"23#include <cassert>24#include <string>25#include <system_error>26#include <utility>27 28using namespace clang;29using namespace driver;30using namespace llvm::opt;31 32Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,33                         InputArgList *_Args, DerivedArgList *_TranslatedArgs,34                         bool ContainsError)35    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),36      TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {37  // The offloading host toolchain is the default toolchain.38  OrderedOffloadingToolchains.insert(39      std::make_pair(Action::OFK_Host, &DefaultToolChain));40}41 42Compilation::~Compilation() {43  // Remove temporary files. This must be done before arguments are freed, as44  // the file names might be derived from the input arguments.45  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)46    CleanupFileList(TempFiles);47 48  delete TranslatedArgs;49  delete Args;50 51  // Free any derived arg lists.52  for (auto Arg : TCArgs)53    if (Arg.second != TranslatedArgs)54      delete Arg.second;55}56 57const DerivedArgList &58Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,59                                 Action::OffloadKind DeviceOffloadKind) {60  if (!TC)61    TC = &DefaultToolChain;62 63  DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];64  if (!Entry) {65    SmallVector<Arg *, 4> AllocatedArgs;66    DerivedArgList *OpenMPArgs = nullptr;67    // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.68    if (DeviceOffloadKind == Action::OFK_OpenMP) {69      const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();70      bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());71      OpenMPArgs = TC->TranslateOpenMPTargetArgs(72          *TranslatedArgs, SameTripleAsHost, AllocatedArgs);73    }74 75    DerivedArgList *NewDAL = nullptr;76    if (!OpenMPArgs) {77      NewDAL = TC->TranslateXarchArgs(*TranslatedArgs, BoundArch,78                                      DeviceOffloadKind, &AllocatedArgs);79    } else {80      NewDAL = TC->TranslateXarchArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind,81                                      &AllocatedArgs);82      if (!NewDAL)83        NewDAL = OpenMPArgs;84      else85        delete OpenMPArgs;86    }87 88    if (!NewDAL) {89      Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);90      if (!Entry)91        Entry = TranslatedArgs;92    } else {93      Entry = TC->TranslateArgs(*NewDAL, BoundArch, DeviceOffloadKind);94      if (!Entry)95        Entry = NewDAL;96      else97        delete NewDAL;98    }99 100    // Add allocated arguments to the final DAL.101    for (auto *ArgPtr : AllocatedArgs)102      Entry->AddSynthesizedArg(ArgPtr);103  }104 105  return *Entry;106}107 108bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {109  // FIXME: Why are we trying to remove files that we have not created? For110  // example we should only try to remove a temporary assembly file if111  // "clang -cc1" succeed in writing it. Was this a workaround for when112  // clang was writing directly to a .s file and sometimes leaving it behind113  // during a failure?114 115  // FIXME: If this is necessary, we can still try to split116  // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the117  // duplicated stat from is_regular_file.118 119  // Don't try to remove files which we don't have write access to (but may be120  // able to remove), or non-regular files. Underlying tools may have121  // intentionally not overwritten them.122  if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))123    return true;124 125  if (std::error_code EC = llvm::sys::fs::remove(File)) {126    // Failure is only failure if the file exists and is "regular". We checked127    // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,128    // so we don't need to check again.129 130    if (IssueErrors)131      getDriver().Diag(diag::err_drv_unable_to_remove_file)132        << EC.message();133    return false;134  }135  return true;136}137 138bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,139                                  bool IssueErrors) const {140  bool Success = true;141  for (const auto &File: Files)142    Success &= CleanupFile(File, IssueErrors);143  return Success;144}145 146bool Compilation::CleanupFileMap(const ArgStringMap &Files,147                                 const JobAction *JA,148                                 bool IssueErrors) const {149  bool Success = true;150  for (const auto &File : Files) {151    // If specified, only delete the files associated with the JobAction.152    // Otherwise, delete all files in the map.153    if (JA && File.first != JA)154      continue;155    Success &= CleanupFile(File.second, IssueErrors);156  }157  return Success;158}159 160int Compilation::ExecuteCommand(const Command &C,161                                const Command *&FailingCommand,162                                bool LogOnly) const {163  if ((getDriver().CCPrintOptions ||164       getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {165    raw_ostream *OS = &llvm::errs();166    std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;167 168    // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the169    // output stream.170    if (getDriver().CCPrintOptions &&171        !getDriver().CCPrintOptionsFilename.empty()) {172      std::error_code EC;173      OwnedStream.reset(new llvm::raw_fd_ostream(174          getDriver().CCPrintOptionsFilename, EC,175          llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF));176      if (EC) {177        getDriver().Diag(diag::err_drv_cc_print_options_failure)178            << EC.message();179        FailingCommand = &C;180        return 1;181      }182      OS = OwnedStream.get();183    }184 185    if (getDriver().CCPrintOptions)186      *OS << "[Logging clang options]\n";187 188    C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);189  }190 191  if (LogOnly)192    return 0;193 194  std::string Error;195  bool ExecutionFailed;196  int Res = C.Execute(Redirects, &Error, &ExecutionFailed);197  if (PostCallback)198    PostCallback(C, Res);199  if (!Error.empty()) {200    assert(Res && "Error string set with 0 result code!");201    getDriver().Diag(diag::err_drv_command_failure) << Error;202  }203 204  if (Res)205    FailingCommand = &C;206 207  return ExecutionFailed ? 1 : Res;208}209 210using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;211 212static bool ActionFailed(const Action *A,213                         const FailingCommandList &FailingCommands) {214  if (FailingCommands.empty())215    return false;216 217  // CUDA/HIP/SYCL can have the same input source code compiled multiple times218  // so do not compile again if there are already failures. It is OK to abort219  // the CUDA/HIP/SYCL pipeline on errors.220  if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP) ||221      A->isOffloading(Action::OFK_SYCL))222    return true;223 224  for (const auto &CI : FailingCommands)225    if (A == &(CI.second->getSource()))226      return true;227 228  for (const auto *AI : A->inputs())229    if (ActionFailed(AI, FailingCommands))230      return true;231 232  return false;233}234 235void Compilation::ExecuteJobs(const JobList &Jobs,236                              FailingCommandList &FailingCommands,237                              bool LogOnly) const {238  // According to UNIX standard, driver need to continue compiling all the239  // inputs on the command line even one of them failed.240  // In all but CLMode, execute all the jobs unless the necessary inputs for the241  // job is missing due to previous failures.242  for (const auto &Job : Jobs) {243    if (ActionFailed(&Job.getSource(), FailingCommands))244      continue;245    const Command *FailingCommand = nullptr;246    if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) {247      FailingCommands.push_back(std::make_pair(Res, FailingCommand));248      // Bail as soon as one command fails in cl driver mode.249      if (TheDriver.IsCLMode())250        return;251    }252  }253}254 255void Compilation::initCompilationForDiagnostics() {256  ForDiagnostics = true;257 258  // Free actions and jobs.259  Actions.clear();260  AllActions.clear();261  Jobs.clear();262 263  // Remove temporary files.264  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)265    CleanupFileList(TempFiles);266 267  // Clear temporary/results file lists.268  TempFiles.clear();269  ResultFiles.clear();270  FailureResultFiles.clear();271 272  // Remove any user specified output.  Claim any unclaimed arguments, so as273  // to avoid emitting warnings about unused args.274  OptSpecifier OutputOpts[] = {275      options::OPT_o,  options::OPT_MD, options::OPT_MMD, options::OPT_M,276      options::OPT_MM, options::OPT_MF, options::OPT_MG,  options::OPT_MJ,277      options::OPT_MQ, options::OPT_MT, options::OPT_MV};278  for (const auto &Opt : OutputOpts) {279    if (TranslatedArgs->hasArg(Opt))280      TranslatedArgs->eraseArg(Opt);281  }282  TranslatedArgs->ClaimAllArgs();283 284  // Force re-creation of the toolchain Args, otherwise our modifications just285  // above will have no effect.286  for (auto Arg : TCArgs)287    if (Arg.second != TranslatedArgs)288      delete Arg.second;289  TCArgs.clear();290 291  // Redirect stdout/stderr to /dev/null.292  Redirects = {std::nullopt, {""}, {""}};293 294  // Temporary files added by diagnostics should be kept.295  ForceKeepTempFiles = true;296}297 298StringRef Compilation::getSysRoot() const {299  return getDriver().SysRoot;300}301 302void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {303  this->Redirects = Redirects;304}305