1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20/*! \file llvm_instance.h
21 */
22#ifndef TVM_TARGET_LLVM_LLVM_INSTANCE_H_
23#define TVM_TARGET_LLVM_LLVM_INSTANCE_H_
24
25#ifdef TVM_LLVM_VERSION
26
27#include <llvm/ADT/ArrayRef.h>
28#if TVM_LLVM_VERSION >= 150
29#include <llvm/IR/FMF.h>
30#else
31#include <llvm/IR/Operator.h>
32#endif
33#include <llvm/Support/CodeGen.h>
34#include <llvm/Target/TargetOptions.h>
35#include <tvm/ir/expr.h>
36#include <tvm/runtime/container/array.h>
37#include <tvm/runtime/container/optional.h>
38#include <tvm/runtime/container/string.h>
39#include <tvm/target/target.h>
40
41#include <algorithm>
42#include <memory>
43#include <string>
44#include <utility>
45#include <vector>
46
47namespace llvm {
48class LLVMContext;
49class MemoryBuffer;
50class Module;
51class TargetMachine;
52} // namespace llvm
53
54namespace tvm {
55namespace codegen {
56
57class LLVMTarget;
58
59/*!
60 * \class LLVMInstance
61 * \brief LLVMInstance is a class that (conceptually) starts and stops LLVM.
62 * All uses of LLVM should take place within a lifetime of an object
63 * of this class.
64 *
65 * E.g.
66 * ```{.cpp}
67 * {
68 * LLVMInstance llvm_instance;
69 * ...
70 * someFunctionFromLLVM(...);
71 * ...
72 * }
73 * // no more calls to LLVM here
74 * ```
75 * In addition to that, LLVMInstance provides an LLVM context (llvm::LLVMContext).
76 * The context is a structure in LLVM where common IR constructs are maintained,
77 * (such as types, constants, etc.) so that they can be identified by their
78 * address (i.e. pointer comparison). Because of that, it's important to use
79 * the same context throughout compilation.
80 *
81 * At the moment the "starting" of LLVM performs initialization of LLVM, but
82 * "stopping" doesn't do anything. In the future, if such a need arises, this
83 * functionality may be extended to perform dlopen/dlclose of the LLVM-based
84 * code in TVM.
85 *
86 * This class provides means to deserialize an LLVM module, either from text
87 * (in a string), or from a file. In either case, the serialized module can
88 * be LLVM IR assembly, or binary bitcode enconding.
89 */
90class LLVMInstance {
91 public:
92 /*!
93 * \brief Constructs LLVMInstance
94 */
95 LLVMInstance();
96 /*!
97 * \brief Destroys LLVMInstance object
98 */
99 ~LLVMInstance(); // Must not be "= default" here in the header file.
100
101 /*!
102 * \brief Get the LLVM context for this scope.
103 */
104 std::shared_ptr<llvm::LLVMContext> GetContext() const { return ctx_; }
105
106 /*!
107 * \brief Create `llvm::Module` from a string.
108 *
109 * Parse the string in \param llvm_ir, and return the `llvm::Module`.
110 * At the moment this function will abort if the parsing fails.
111 * \param llvm_ir string with the LLVM IR assembly or bitcode
112 * \return created `llvm::Module`
113 */
114 std::unique_ptr<llvm::Module> ParseIR(const std::string& llvm_ir) const;
115 /*!
116 * \brief Load `llvm::Module` from a given file
117 *
118 * Read the file \param file_name, and return the `llvm::Module`.
119 * At the moment this function will abort if reading of the file or creation
120 * of the module fails.
121 * \param file_name file with the LLVM IR assembly or bitcode
122 * \return created `llvm::Module`
123 */
124 std::unique_ptr<llvm::Module> LoadIR(const std::string& file_name) const;
125
126 private:
127 std::unique_ptr<llvm::Module> ParseBuffer(const llvm::MemoryBuffer& buffer) const;
128
129 std::shared_ptr<llvm::LLVMContext> ctx_;
130};
131
132/*!
133 * \class LLVMTargetInfo
134 * \brief Summary of information for this TVM target relevant to LLVM code
135 * generation.
136 *
137 * This class contains all information that LLVM needs for code generation for
138 * a particular target. The purpose of this class is only to provide information
139 * in an easily-accessible form (for example for querying the target properties).
140 *
141 * Note that objects of this class must be created within the lifetime of an
142 * LLVMInstance object.
143 */
144class LLVMTargetInfo {
145 public:
146 /*!
147 * \brief Constructs LLVMTargetInfo from `Target`
148 * \param scope LLVMInstance object
149 * \param target TVM Target object for target "llvm"
150 */
151 LLVMTargetInfo(LLVMInstance& scope, const Target& target); // NOLINT(runtime/references)
152 /*!
153 * \brief Constructs LLVMTargetInfo from target string
154 * \param scope LLVMInstance object
155 * \param target TVM target string for target "llvm"
156 */
157 // NOLINTNEXTLINE(runtime/references)
158 LLVMTargetInfo(LLVMInstance& scope, const std::string& target_str);
159 /*!
160 * \brief Destroys LLVMTargetInfo object
161 */
162 ~LLVMTargetInfo();
163
164 /*!
165 * \brief Returns string representation (as TVM target) of the LLVMTargetInfo
166 * \return Target string
167 *
168 * Note: If the LLVMTargetInfo object was created from a string `s`, the string
169 * returned here may not be exactly equal to `s`. For example, if the CPU
170 * was "default", the returned string will have CPU set to the detected host
171 * CPU.
172 */
173 std::string str() const;
174
175 /*!
176 * \brief Return LLVM's `TargetMachine`, or nullptr
177 * \param allow_missing do not abort if the target machine cannot be created,
178 * return nullptr instead
179 * \return Pointer to the `TargetMachine` object (or nullptr if it cannot be
180 * created, \see allow_missing)
181 */
182 llvm::TargetMachine* GetOrCreateTargetMachine(bool allow_missing = false);
183
184 /*!
185 * \brief Get the target triple
186 * \return the target triple
187 */
188 const std::string& GetTargetTriple() const { return triple_; }
189 /*!
190 * \brief Get the CPU name
191 * \return the CPU name: the detected host CPU if the original TVM target
192 * specified it as "default"
193 */
194 const std::string& GetCPU() const { return cpu_; }
195 /*!
196 * \brief Get the list of LLVM target features
197 * \return array of individual feature strings
198 */
199 llvm::ArrayRef<std::string> GetTargetFeatures() const { return attrs_; }
200 /*!
201 * \brief Get the LLVM target feature string
202 * \return comma-separated list of LLVM target features
203 */
204 std::string GetTargetFeatureString() const;
205 /*!
206 * \brief Get the LLVM target options
207 * \return `llvm::TargetOptions` object for this target
208 */
209 const llvm::TargetOptions& GetTargetOptions() const { return target_options_; }
210 /*!
211 * \brief Get fast math flags
212 * \return `llvm::FastMathFlags` for this target
213 */
214 llvm::FastMathFlags GetFastMathFlags() const { return fast_math_flags_; }
215 /*!
216 * \brief Get the LLVM optimization level
217 * \return optimization level for this target
218 */
219 llvm::CodeGenOpt::Level GetOptLevel() const { return opt_level_; }
220
221 /*!
222 * \class Option
223 * \brief Internal representation of command-line option
224 */
225 struct Option {
226 enum class OptType {
227 Invalid = 0, //!< placeholder, indicates parsing error
228 Bool, //!< enum value corresponding to type string "bool"
229 Int, //!< enum value corresponding to type string "int"
230 UInt, //!< enum value corresponding to type string "uint"
231 String, //!< enum value corresponding to type string "string"
232 };
233 std::string name; //!< option name
234 OptType type; //!< type of the option value
235 struct {
236 union {
237 bool b; //!< bool option value
238 int i; //!< int option value
239 unsigned u = 0; //!< unsigned option value
240 };
241 std::string s; //!< string option value
242 } value; //!< option value specified in the option string
243 };
244
245 /*!
246 * \brief Get LLVM command line options
247 * \return the list of LLVM command line options specified for this target
248 */
249 const std::vector<Option>& GetCommandLineOptions() const { return llvm_options_; }
250
251 /*!
252 * \brief Parse a string from the `cl-opt` target attribute
253 * \param str the option string
254 * \return parsed `Option` object, if parsing failed the type member will be
255 * set to `Option::OptType::Invalid`
256 */
257 static Option ParseOptionString(const std::string& str);
258
259 /*!
260 * \brief Checks if the settings in this object that describe global state
261 * match the current global state
262 * \return true or false correspondingly
263 * \note The global state can be modified by command line options. This
264 * function checks if the specified options differ from their current
265 * values.
266 */
267 bool MatchesGlobalState() const;
268
269 protected:
270 /*!
271 * \brief Get the current value of given LLVM option
272 * \param opt Option with "type" and "name" set
273 * Fills in the "value" field in the provided Option argument, or sets the
274 * "type" to Invalid if the option value cannot be obtained.
275 */
276 void GetOptionValue(Option* opt) const;
277
278 private:
279 std::string triple_;
280 std::string cpu_;
281 std::vector<std::string> attrs_;
282 std::vector<Option> llvm_options_;
283 llvm::TargetOptions target_options_;
284 llvm::FastMathFlags fast_math_flags_;
285 llvm::CodeGenOpt::Level opt_level_;
286 llvm::Reloc::Model reloc_model_ = llvm::Reloc::PIC_;
287 llvm::CodeModel::Model code_model_ = llvm::CodeModel::Small;
288 std::shared_ptr<llvm::TargetMachine> target_machine_;
289};
290
291/*!
292 * \class LLVMTarget
293 * \brief Information used by LLVM for code generation for particular target
294 *
295 * In addition to all information that LLVM needs for code generation for
296 * a particular target, objects of this class handle saving and restoring
297 * global LLVM state that may be affected by these flags. This way, code
298 * generation for each LLVM-based target in TVM will start with the same LLVM
299 * global state.
300 *
301 * Note that objects of this class must be created within the lifetime of an
302 * LLVMInstance object.
303 */
304class LLVMTarget : public LLVMTargetInfo {
305 public:
306 /*!
307 * \brief Constructs LLVMTarget from `Target`
308 * \param scope LLVMInstance object
309 * \param target_info Target info object for target "llvm"
310 */
311 LLVMTarget(LLVMInstance& scope, const LLVMTargetInfo& target_info); // NOLINT(runtime/references)
312 /*!
313 * \brief Constructs LLVMTarget from `Target`
314 * \param scope LLVMInstance object
315 * \param target TVM Target object for target "llvm"
316 */
317 LLVMTarget(LLVMInstance& scope, const Target& target); // NOLINT(runtime/references)
318 /*!
319 * \brief Constructs LLVMTarget from target string
320 * \param scope LLVMInstance object
321 * \param target TVM target string for target "llvm"
322 */
323 LLVMTarget(LLVMInstance& scope, const std::string& target_str); // NOLINT(runtime/references)
324 /*!
325 * \brief Destroys LLVMTarget object
326 */
327 ~LLVMTarget();
328
329 /*!
330 * \brief Get the LLVMInstance object from which the LLVMTarget object was
331 * created
332 * \return The enclosing LLVMInstance object
333 */
334 const LLVMInstance& GetInstance() const { return instance_; }
335 /*!
336 * \brief Get the current LLVM context
337 * \return the current LLVM context
338 */
339 llvm::LLVMContext* GetContext() const;
340 /*!
341 * \brief Extract the target string from given `llvm::Module`
342 * \param module LLVM module with the TVM target string embedded as metadata
343 * \return the target string from module's metadata
344 */
345 static std::string GetTargetMetadata(const llvm::Module& module);
346 /*!
347 * \brief Embed target string as metadata in given `llvm::Module`
348 * \param module the module to insert the target string into
349 */
350 void SetTargetMetadata(llvm::Module* module) const;
351
352 // Stubs to enable use with `With`.
353 void EnterWithScope() {}
354 void ExitWithScope() {}
355
356 private:
357 std::vector<Option> saved_llvm_options_;
358
359 /*!
360 * \brief Apply or revert command-line LLVM options
361 * \param apply_otherwise_revert if true, apply the options (saving previous
362 * values, if false, then restore the saved values
363 * \param dry_run if true, do not make any changes (or save anything)
364 * \return true is changes were made (or would have been made in a dry run),
365 * false otherwise
366 */
367 bool ApplyLLVMOptions(bool apply_otherwise_revert, bool dry_run = false);
368
369 const LLVMInstance& instance_;
370 std::weak_ptr<llvm::LLVMContext> ctx_;
371
372 /*!
373 * \brief Global singleton flag indicating whether LLVM's global state has
374 * been modified or not (via command-line flags). There can only be
375 * a single such modification in effect at any given time.
376 */
377 static bool modified_llvm_state_;
378};
379
380} // namespace codegen
381} // namespace tvm
382
383#endif // TVM_LLVM_VERSION
384#endif // TVM_TARGET_LLVM_LLVM_INSTANCE_H_
385