1 //===- Compilation.h - Compilation Task Data Structure ----------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LLVM_CLANG_DRIVER_COMPILATION_H
11 #define LLVM_CLANG_DRIVER_COMPILATION_H
12 
13 #include "clang/Basic/LLVM.h"
14 #include "clang/Driver/Action.h"
15 #include "clang/Driver/Job.h"
16 #include "clang/Driver/Util.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/Optional.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Option/Option.h"
22 #include <cassert>
23 #include <iterator>
24 #include <map>
25 #include <memory>
26 #include <utility>
27 #include <vector>
28 
29 namespace llvm {
30 namespace opt {
31 
32 class DerivedArgList;
33 class InputArgList;
34 
35 } // namespace opt
36 } // namespace llvm
37 
38 namespace clang {
39 namespace driver {
40 
41 class Driver;
42 class ToolChain;
43 
44 /// Compilation - A set of tasks to perform for a single driver
45 /// invocation.
46 class Compilation {
47   /// The driver we were created by.
48   const Driver &TheDriver;
49 
50   /// The default tool chain.
51   const ToolChain &DefaultToolChain;
52 
53   /// A mask of all the programming models the host has to support in the
54   /// current compilation.
55   unsigned ActiveOffloadMask = 0;
56 
57   /// Array with the toolchains of offloading host and devices in the order they
58   /// were requested by the user. We are preserving that order in case the code
59   /// generation needs to derive a programming-model-specific semantic out of
60   /// it.
61   std::multimap<Action::OffloadKind, const ToolChain *>
62       OrderedOffloadingToolchains;
63 
64   /// The original (untranslated) input argument list.
65   llvm::opt::InputArgList *Args;
66 
67   /// The driver translated arguments. Note that toolchains may perform their
68   /// own argument translation.
69   llvm::opt::DerivedArgList *TranslatedArgs;
70 
71   /// The list of actions we've created via MakeAction.  This is not accessible
72   /// to consumers; it's here just to manage ownership.
73   std::vector<std::unique_ptr<Action>> AllActions;
74 
75   /// The list of actions.  This is maintained and modified by consumers, via
76   /// getActions().
77   ActionList Actions;
78 
79   /// The root list of jobs.
80   JobList Jobs;
81 
82   /// Cache of translated arguments for a particular tool chain, bound
83   /// architecture, and device offload kind.
84   struct TCArgsKey final {
85     const ToolChain *TC = nullptr;
86     StringRef BoundArch;
87     Action::OffloadKind DeviceOffloadKind = Action::OFK_None;
88 
TCArgsKeyfinal89     TCArgsKey(const ToolChain *TC, StringRef BoundArch,
90               Action::OffloadKind DeviceOffloadKind)
91         : TC(TC), BoundArch(BoundArch), DeviceOffloadKind(DeviceOffloadKind) {}
92 
93     bool operator<(const TCArgsKey &K) const {
94       if (TC < K.TC)
95         return true;
96       else if (TC == K.TC && BoundArch < K.BoundArch)
97         return true;
98       else if (TC == K.TC && BoundArch == K.BoundArch &&
99                DeviceOffloadKind < K.DeviceOffloadKind)
100         return true;
101       return false;
102     }
103   };
104   std::map<TCArgsKey, llvm::opt::DerivedArgList *> TCArgs;
105 
106   /// Temporary files which should be removed on exit.
107   llvm::opt::ArgStringList TempFiles;
108 
109   /// Result files which should be removed on failure.
110   ArgStringMap ResultFiles;
111 
112   /// Result files which are generated correctly on failure, and which should
113   /// only be removed if we crash.
114   ArgStringMap FailureResultFiles;
115 
116   /// Optional redirection for stdin, stdout, stderr.
117   std::vector<Optional<StringRef>> Redirects;
118 
119   /// Whether we're compiling for diagnostic purposes.
120   bool ForDiagnostics = false;
121 
122   /// Whether an error during the parsing of the input args.
123   bool ContainsError;
124 
125   /// Whether to keep temporary files regardless of -save-temps.
126   bool ForceKeepTempFiles = false;
127 
128 public:
129   Compilation(const Driver &D, const ToolChain &DefaultToolChain,
130               llvm::opt::InputArgList *Args,
131               llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError);
132   ~Compilation();
133 
getDriver()134   const Driver &getDriver() const { return TheDriver; }
135 
getDefaultToolChain()136   const ToolChain &getDefaultToolChain() const { return DefaultToolChain; }
137 
isOffloadingHostKind(Action::OffloadKind Kind)138   unsigned isOffloadingHostKind(Action::OffloadKind Kind) const {
139     return ActiveOffloadMask & Kind;
140   }
141 
142   /// Iterator that visits device toolchains of a given kind.
143   using const_offload_toolchains_iterator =
144       const std::multimap<Action::OffloadKind,
145                           const ToolChain *>::const_iterator;
146   using const_offload_toolchains_range =
147       std::pair<const_offload_toolchains_iterator,
148                 const_offload_toolchains_iterator>;
149 
150   template <Action::OffloadKind Kind>
getOffloadToolChains()151   const_offload_toolchains_range getOffloadToolChains() const {
152     return OrderedOffloadingToolchains.equal_range(Kind);
153   }
154 
155   /// Return true if an offloading tool chain of a given kind exists.
hasOffloadToolChain()156   template <Action::OffloadKind Kind> bool hasOffloadToolChain() const {
157     return OrderedOffloadingToolchains.find(Kind) !=
158            OrderedOffloadingToolchains.end();
159   }
160 
161   /// Return an offload toolchain of the provided kind. Only one is expected to
162   /// exist.
163   template <Action::OffloadKind Kind>
getSingleOffloadToolChain()164   const ToolChain *getSingleOffloadToolChain() const {
165     auto TCs = getOffloadToolChains<Kind>();
166 
167     assert(TCs.first != TCs.second &&
168            "No tool chains of the selected kind exist!");
169     assert(std::next(TCs.first) == TCs.second &&
170            "More than one tool chain of the this kind exist.");
171     return TCs.first->second;
172   }
173 
addOffloadDeviceToolChain(const ToolChain * DeviceToolChain,Action::OffloadKind OffloadKind)174   void addOffloadDeviceToolChain(const ToolChain *DeviceToolChain,
175                                  Action::OffloadKind OffloadKind) {
176     assert(OffloadKind != Action::OFK_Host && OffloadKind != Action::OFK_None &&
177            "This is not a device tool chain!");
178 
179     // Update the host offload kind to also contain this kind.
180     ActiveOffloadMask |= OffloadKind;
181     OrderedOffloadingToolchains.insert(
182         std::make_pair(OffloadKind, DeviceToolChain));
183   }
184 
getInputArgs()185   const llvm::opt::InputArgList &getInputArgs() const { return *Args; }
186 
getArgs()187   const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; }
188 
getArgs()189   llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; }
190 
getActions()191   ActionList &getActions() { return Actions; }
getActions()192   const ActionList &getActions() const { return Actions; }
193 
194   /// Creates a new Action owned by this Compilation.
195   ///
196   /// The new Action is *not* added to the list returned by getActions().
MakeAction(Args &&...Arg)197   template <typename T, typename... Args> T *MakeAction(Args &&... Arg) {
198     T *RawPtr = new T(std::forward<Args>(Arg)...);
199     AllActions.push_back(std::unique_ptr<Action>(RawPtr));
200     return RawPtr;
201   }
202 
getJobs()203   JobList &getJobs() { return Jobs; }
getJobs()204   const JobList &getJobs() const { return Jobs; }
205 
addCommand(std::unique_ptr<Command> C)206   void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(std::move(C)); }
207 
getTempFiles()208   const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
209 
getResultFiles()210   const ArgStringMap &getResultFiles() const { return ResultFiles; }
211 
getFailureResultFiles()212   const ArgStringMap &getFailureResultFiles() const {
213     return FailureResultFiles;
214   }
215 
216   /// Returns the sysroot path.
217   StringRef getSysRoot() const;
218 
219   /// getArgsForToolChain - Return the derived argument list for the
220   /// tool chain \p TC (or the default tool chain, if TC is not specified).
221   /// If a device offloading kind is specified, a translation specific for that
222   /// kind is performed, if any.
223   ///
224   /// \param BoundArch - The bound architecture name, or 0.
225   /// \param DeviceOffloadKind - The offload device kind that should be used in
226   /// the translation, if any.
227   const llvm::opt::DerivedArgList &
228   getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
229                       Action::OffloadKind DeviceOffloadKind);
230 
231   /// addTempFile - Add a file to remove on exit, and returns its
232   /// argument.
addTempFile(const char * Name)233   const char *addTempFile(const char *Name) {
234     TempFiles.push_back(Name);
235     return Name;
236   }
237 
238   /// addResultFile - Add a file to remove on failure, and returns its
239   /// argument.
addResultFile(const char * Name,const JobAction * JA)240   const char *addResultFile(const char *Name, const JobAction *JA) {
241     ResultFiles[JA] = Name;
242     return Name;
243   }
244 
245   /// addFailureResultFile - Add a file to remove if we crash, and returns its
246   /// argument.
addFailureResultFile(const char * Name,const JobAction * JA)247   const char *addFailureResultFile(const char *Name, const JobAction *JA) {
248     FailureResultFiles[JA] = Name;
249     return Name;
250   }
251 
252   /// CleanupFile - Delete a given file.
253   ///
254   /// \param IssueErrors - Report failures as errors.
255   /// \return Whether the file was removed successfully.
256   bool CleanupFile(const char *File, bool IssueErrors = false) const;
257 
258   /// CleanupFileList - Remove the files in the given list.
259   ///
260   /// \param IssueErrors - Report failures as errors.
261   /// \return Whether all files were removed successfully.
262   bool CleanupFileList(const llvm::opt::ArgStringList &Files,
263                        bool IssueErrors = false) const;
264 
265   /// CleanupFileMap - Remove the files in the given map.
266   ///
267   /// \param JA - If specified, only delete the files associated with this
268   /// JobAction.  Otherwise, delete all files in the map.
269   /// \param IssueErrors - Report failures as errors.
270   /// \return Whether all files were removed successfully.
271   bool CleanupFileMap(const ArgStringMap &Files,
272                       const JobAction *JA,
273                       bool IssueErrors = false) const;
274 
275   /// ExecuteCommand - Execute an actual command.
276   ///
277   /// \param FailingCommand - For non-zero results, this will be set to the
278   /// Command which failed, if any.
279   /// \return The result code of the subprocess.
280   int ExecuteCommand(const Command &C, const Command *&FailingCommand) const;
281 
282   /// ExecuteJob - Execute a single job.
283   ///
284   /// \param FailingCommands - For non-zero results, this will be a vector of
285   /// failing commands and their associated result code.
286   void ExecuteJobs(
287       const JobList &Jobs,
288       SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const;
289 
290   /// initCompilationForDiagnostics - Remove stale state and suppress output
291   /// so compilation can be reexecuted to generate additional diagnostic
292   /// information (e.g., preprocessed source(s)).
293   void initCompilationForDiagnostics();
294 
295   /// Return true if we're compiling for diagnostics.
isForDiagnostics()296   bool isForDiagnostics() const { return ForDiagnostics; }
297 
298   /// Return whether an error during the parsing of the input args.
containsError()299   bool containsError() const { return ContainsError; }
300 
301   /// Redirect - Redirect output of this compilation. Can only be done once.
302   ///
303   /// \param Redirects - array of optional paths. The array should have a size
304   /// of three. The inferior process's stdin(0), stdout(1), and stderr(2) will
305   /// be redirected to the corresponding paths, if provided (not llvm::None).
306   void Redirect(ArrayRef<Optional<StringRef>> Redirects);
307 };
308 
309 } // namespace driver
310 } // namespace clang
311 
312 #endif // LLVM_CLANG_DRIVER_COMPILATION_H
313