You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by an...@apache.org on 2022/09/17 00:01:31 UTC
[tvm] 13/18: llvm instance optional
This is an automated email from the ASF dual-hosted git repository.
andrewzhaoluo pushed a commit to branch aluo/rebase-09162022-autotensorization
in repository https://gitbox.apache.org/repos/asf/tvm.git
commit 848d5a1c29f38c2b1464927a4e54c9f712637149
Author: Andrew Zhao Luo <an...@gmail.com>
AuthorDate: Fri Sep 2 14:59:23 2022 -0700
llvm instance optional
---
src/target/llvm/llvm_instance.cc | 430 ++-------------------------------------
src/target/llvm/llvm_instance.h | 194 ++++--------------
src/target/llvm/llvm_module.cc | 8 +-
3 files changed, 56 insertions(+), 576 deletions(-)
diff --git a/src/target/llvm/llvm_instance.cc b/src/target/llvm/llvm_instance.cc
index 19ff480452..772e71b287 100644
--- a/src/target/llvm/llvm_instance.cc
+++ b/src/target/llvm/llvm_instance.cc
@@ -39,7 +39,6 @@
#include <llvm/Support/TargetRegistry.h>
#endif
#include <llvm/Support/CodeGen.h>
-#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ErrorOr.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/MemoryBuffer.h>
@@ -57,14 +56,9 @@
#include <tvm/target/target.h>
#include <atomic>
-#include <cctype>
-#include <memory>
-#include <optional>
-#include <ostream>
#include <sstream>
#include <string>
#include <system_error>
-#include <utility>
namespace tvm {
namespace codegen {
@@ -142,27 +136,10 @@ std::unique_ptr<llvm::Module> LLVMInstance::ParseBuffer(const llvm::MemoryBuffer
return module;
}
-// LLVMTargetInfo
-
-std::ostream& operator<<(std::ostream& os, const LLVMTargetInfo::Option& opt) {
- os << '-' << opt.name;
- switch (opt.type) {
- case LLVMTargetInfo::Option::OptType::Bool:
- return os << ":bool=" << (opt.value.b ? "true" : "false");
- case LLVMTargetInfo::Option::OptType::Int:
- return os << ":int=" << opt.value.i;
- case LLVMTargetInfo::Option::OptType::UInt:
- return os << ":uint=" << opt.value.u;
- case LLVMTargetInfo::Option::OptType::String:
- return os << ":string=" << opt.value.s;
- default:
- os << ":?(" << static_cast<int>(opt.type) << ")";
- break;
- }
- return os;
-}
+// LLVMTarget
-LLVMTargetInfo::LLVMTargetInfo(LLVMInstance& instance, const Target& target) {
+LLVMTarget::LLVMTarget(LLVMInstance& instance, const Target& target)
+ : instance_(instance), ctx_(instance.GetContext()) {
triple_ = target->GetAttr<String>("mtriple").value_or("default");
if (triple_.empty() || triple_ == "default") {
@@ -176,26 +153,6 @@ LLVMTargetInfo::LLVMTargetInfo(LLVMInstance& instance, const Target& target) {
}
}
- if (const Optional<Array<String>>& v = target->GetAttr<Array<String>>("cl-opt")) {
- llvm::StringMap<llvm::cl::Option*>& options = llvm::cl::getRegisteredOptions();
- bool parse_error = false;
- for (const String& s : v.value()) {
- Option opt = ParseOptionString(s);
- if (opt.type == Option::OptType::Invalid) {
- parse_error = true;
- continue;
- }
- if (options.count(opt.name)) {
- llvm_options_.push_back(opt);
- } else {
- // Flag an error, but don't abort. LLVM flags may change, and this would
- // give the code a chance to run even if the option no longer applies.
- LOG(ERROR) << "\"" << opt.name << "\" is not an LLVM option, option ignored";
- }
- }
- ICHECK(!parse_error) << "there were errors parsing command-line options";
- }
-
llvm::FloatABI::ABIType float_abi = llvm::FloatABI::Default;
if (const Optional<String>& v = target->GetAttr<String>("mfloat-abi")) {
String value = v.value();
@@ -281,12 +238,17 @@ LLVMTargetInfo::LLVMTargetInfo(LLVMInstance& instance, const Target& target) {
}
}
-LLVMTargetInfo::LLVMTargetInfo(LLVMInstance& scope, const std::string& target_str)
- : LLVMTargetInfo(scope, Target(target_str)) {}
+LLVMTarget::LLVMTarget(LLVMInstance& scope, const std::string& target_str)
+ : LLVMTarget(scope, Target(target_str)) {}
-LLVMTargetInfo::~LLVMTargetInfo() = default;
+LLVMTarget::~LLVMTarget() = default;
+
+llvm::LLVMContext* LLVMTarget::GetContext() const {
+ ICHECK(!ctx_.expired()) << "LLVM scope has been deleted";
+ return ctx_.lock().get();
+}
-llvm::TargetMachine* LLVMTargetInfo::GetOrCreateTargetMachine(bool allow_missing) {
+llvm::TargetMachine* LLVMTarget::GetOrCreateTargetMachine(bool allow_missing) {
if (target_machine_) return target_machine_.get();
std::string error;
@@ -302,11 +264,11 @@ llvm::TargetMachine* LLVMTargetInfo::GetOrCreateTargetMachine(bool allow_missing
return target_machine_.get();
}
-std::string LLVMTargetInfo::GetTargetFeatureString() const { //
+std::string LLVMTarget::GetTargetFeatureString() const { //
return Join(",", attrs_);
}
-std::string LLVMTargetInfo::str() const {
+std::string LLVMTarget::str() const {
std::ostringstream os;
os << "llvm";
if (!triple_.empty()) {
@@ -378,324 +340,9 @@ std::string LLVMTargetInfo::str() const {
}
}
- if (size_t num = llvm_options_.size(); num > 0) {
- os << " -cl-opt=";
- std::vector<std::string> opts;
- for (const Option& opt : llvm_options_) {
- std::stringstream os;
- os << opt;
- opts.emplace_back(os.str());
- }
- auto* quote = num > 1 ? "'" : "";
- os << quote << Join(",", opts) << quote;
- }
-
return os.str();
}
-LLVMTargetInfo::Option LLVMTargetInfo::ParseOptionString(const std::string& str) {
- Option opt;
- opt.type = Option::OptType::Invalid;
-
- // Option string: "-"+ <option_name> ":" <type> "=" <value>
- //
- // Note: "-"+ means 1 or more dashes, but only "-" are "--" valid.
-
- // The first step is to do "lexing" of the option string, i.e. to break
- // it up into parts (like "tokens") according to the syntax above. These
- // parts will be non-overlapping substrings of the option string, and
- // concatenated together, they will be equal to the option string.
- // The literal elements are parts on their own.
- //
- // Note that the option string may be malformed, so any of the literal
- // elements in the syntax may be missing.
-
- std::vector<std::string> parts;
-
- auto find_first_of = [](const std::string& str, const std::string& chars, auto start = 0) {
- auto pos = str.find_first_of(chars, start);
- return pos != std::string::npos ? pos : str.size();
- };
- auto find_first_not_of = [](const std::string& str, const std::string& chars, auto start = 0) {
- auto pos = str.find_first_not_of(chars, start);
- return pos != std::string::npos ? pos : str.size();
- };
-
- // "-"+
- std::string::size_type pos_start = 0, pos_end = str.size();
- std::string::size_type pos_at = find_first_not_of(str, "-", pos_start);
- if (pos_at > 0) {
- parts.push_back(str.substr(pos_start, pos_at));
- }
- // <option_name>, always present, may be empty string
- pos_start = pos_at;
- pos_at = find_first_of(str, ":=", pos_start);
- parts.push_back(str.substr(pos_start, pos_at - pos_start));
-
- // ":" or "=", if any
- pos_start = pos_at;
- char c = pos_start < pos_end ? str[pos_start] : 0;
- if (c != 0) {
- parts.emplace_back(1, c);
- pos_start++;
- }
- // If the character found in the previous step wasn't '=', look for '='.
- if (c == ':') {
- // <type>
- pos_at = find_first_of(str, "=", pos_start);
- if (pos_at > pos_start) { // if non-empty
- parts.push_back(str.substr(pos_start, pos_at - pos_start));
- }
-
- // "="
- if (pos_at < pos_end) {
- parts.emplace_back(1, str[pos_at]);
- pos_start = pos_at + 1;
- }
- }
- if (pos_start < pos_end) {
- // <value>
- parts.push_back(str.substr(pos_start));
- }
-
- // After breaking up the option string, examine and validate the individual
- // parts.
-
- int part_this = 0, part_end = parts.size();
-
- const std::string error_header = "while parsing option \"" + str + "\": ";
-
- // Check for "-" or "--".
- if (part_this < part_end) {
- auto& p = parts[part_this++];
- if ((p.size() != 1 && p.size() != 2) || p.find_first_not_of('-') != std::string::npos) {
- LOG(ERROR) << error_header << "option must start with \"-\" or \"--\"";
- return opt;
- }
- }
-
- // Validate option name.
- if (part_this < part_end) {
- auto& p = parts[part_this++];
- if (p.empty()) {
- LOG(ERROR) << error_header << "option name must not be empty";
- return opt;
- }
- opt.name = std::move(p);
- }
-
- // Check type, if present.
- Option::OptType type = Option::OptType::Invalid;
- if (part_this < part_end) {
- auto& p0 = parts[part_this];
- if (p0 == ":") {
- part_this++; // Only advance if we saw ":".
- if (part_this < part_end) {
- auto& p1 = parts[part_this];
- ICHECK(!p1.empty()) << "tokenizing error"; // This shouldn't happen.
- if (p1 != "=") {
- part_this++;
- if (p1 == "bool") {
- type = Option::OptType::Bool;
- } else if (p1 == "int") {
- type = Option::OptType::Int;
- } else if (p1 == "uint") {
- type = Option::OptType::UInt;
- } else if (p1 == "string") {
- type = Option::OptType::String;
- }
- }
- }
- // If there was ":", there must be a type.
- if (type == Option::OptType::Invalid) {
- LOG(ERROR) << error_header << "invalid type";
- return opt;
- }
- }
- }
-
- // Check value, if present.
- std::optional<std::string> value;
- if (part_this < part_end) {
- auto& p0 = parts[part_this];
- if (p0 == "=") {
- part_this++;
- if (part_this < part_end) {
- value = std::move(parts[part_this]);
- } else {
- value = "";
- }
- } else {
- // If there are still any parts left to be processed, there must be "=".
- LOG(ERROR) << error_header << "expecting \"=\"";
- return opt;
- }
- }
-
- // NOLINTNEXTLINE(runtime/int)
- auto to_integer = [](const std::string& s) -> std::optional<long long> {
- // std::stoll takes "long long"
- long long number; // NOLINT(runtime/int)
- size_t pos;
- try {
- number = std::stoll(s, &pos);
- } catch (...) {
- return std::nullopt;
- }
- if (pos == s.size()) {
- return number;
- } else {
- return std::nullopt;
- }
- };
-
- auto to_boolean = [&to_integer](const std::string& s) -> std::optional<bool> {
- // Return 0 or 1, if string corresponds to a valid boolean value,
- // otherwise return 2.
- auto ti = to_integer(s);
- if (ti.has_value() && (ti.value() == 0 || ti.value() == 1)) {
- return static_cast<bool>(ti.value());
- }
-
- std::string lower;
- std::transform(s.begin(), s.end(), std::back_inserter(lower),
- [](unsigned char c) { return std::tolower(c); });
- if (lower == "true") {
- return true;
- } else if (lower == "false") {
- return false;
- }
- return std::nullopt;
- };
-
- if (value.has_value()) {
- if (type == Option::OptType::Int || type == Option::OptType::UInt) {
- auto v = to_integer(value.value());
- if (!v.has_value()) {
- LOG(ERROR) << error_header << "invalid integer value \"" << value.value() << "\"";
- return opt;
- }
- if (type == Option::OptType::Int) {
- opt.value.i = static_cast<int>(v.value());
- if (opt.value.i != v.value()) {
- LOG(WARNING) << error_header << "value exceeds int range, assuming " << opt.value.i;
- }
- } else {
- // NOLINTNEXTLINE(runtime/int)
- opt.value.u = static_cast<unsigned>(static_cast<unsigned long long>(v.value()));
- if (opt.value.u != static_cast<unsigned long long>(v.value())) { // NOLINT(runtime/int)
- LOG(WARNING) << error_header << "value exceeds int range, assuming " << opt.value.u;
- }
- }
- } else if (type == Option::OptType::String) {
- opt.value.s = std::move(value.value());
- } else {
- // "type" is either Bool (given explicitly) or Invalid (type not present in string)
- auto v = to_boolean(value.value());
- if (!v.has_value()) {
- LOG(ERROR) << error_header << "invalid boolean value \"" << value.value() << "\"";
- return opt;
- }
- opt.value.b = v.value();
- type = Option::OptType::Bool;
- }
- } else {
- // Value was not present in string. Assume "true" if "type" is Bool or Invalid
- if (type == Option::OptType::Bool || type == Option::OptType::Invalid) {
- opt.value.b = true;
- type = Option::OptType::Bool;
- } else {
- LOG(ERROR) << error_header << "must have a value";
- return opt;
- }
- }
-
- ICHECK(type != Option::OptType::Invalid);
- opt.type = type;
- return opt;
-}
-
-bool LLVMTargetInfo::MatchesGlobalState() const {
- for (const Option& opt : GetCommandLineOptions()) {
- Option current_opt = opt;
- GetOptionValue(¤t_opt);
- ICHECK(current_opt.type != Option::OptType::Invalid);
- switch (current_opt.type) {
- case Option::OptType::Bool:
- if (current_opt.value.b != opt.value.b) return false;
- continue;
- case Option::OptType::Int:
- if (current_opt.value.i != opt.value.i) return false;
- continue;
- case Option::OptType::UInt:
- if (current_opt.value.u != opt.value.u) return false;
- continue;
- case Option::OptType::String:
- if (current_opt.value.s != opt.value.s) return false;
- continue;
- default:; // NOLINT(whitespace/semicolon)
- }
- }
- return true;
-}
-
-void LLVMTargetInfo::GetOptionValue(LLVMTargetInfo::Option* opt) const {
- llvm::StringMap<llvm::cl::Option*>& options = llvm::cl::getRegisteredOptions();
- llvm::cl::Option* base_op = options[opt->name];
-
- if (opt->type == Option::OptType::Bool) {
- auto* bool_op = static_cast<llvm::cl::opt<bool>*>(base_op);
- opt->value.b = bool_op->getValue();
- } else if (opt->type == Option::OptType::Int) {
- auto* int_op = static_cast<llvm::cl::opt<int>*>(base_op);
- opt->value.i = int_op->getValue();
- } else if (opt->type == Option::OptType::UInt) {
- auto* uint_op = static_cast<llvm::cl::opt<unsigned>*>(base_op);
- opt->value.u = uint_op->getValue();
- } else if (opt->type == Option::OptType::String) {
- auto* str_op = static_cast<llvm::cl::opt<std::string>*>(base_op);
- opt->value.s = str_op->getValue();
- } else {
- opt->type = Option::OptType::Invalid;
- }
-}
-
-// LLVMTarget
-
-bool LLVMTarget::modified_llvm_state_ = false;
-
-LLVMTarget::LLVMTarget(LLVMInstance& instance, const LLVMTargetInfo& target_info)
- : LLVMTargetInfo(target_info), instance_(instance), ctx_(instance.GetContext()) {
- // Populate the list of saved options with the current values.
- for (const Option& opt : GetCommandLineOptions()) {
- GetOptionValue(&saved_llvm_options_.emplace_back(opt));
- }
-
- if (modified_llvm_state_) {
- ICHECK(!ApplyLLVMOptions(true));
- } else {
- modified_llvm_state_ = ApplyLLVMOptions(true);
- }
-}
-
-LLVMTarget::LLVMTarget(LLVMInstance& instance, const Target& target)
- : LLVMTarget(instance, LLVMTargetInfo(instance, target)) {}
-
-LLVMTarget::LLVMTarget(LLVMInstance& scope, const std::string& target_str)
- : LLVMTarget(scope, Target(target_str)) {}
-
-LLVMTarget::~LLVMTarget() {
- // Revert all applied LLVM options.
- if (ApplyLLVMOptions(false)) {
- modified_llvm_state_ = false;
- }
-}
-
-llvm::LLVMContext* LLVMTarget::GetContext() const {
- ICHECK(!ctx_.expired()) << "LLVM scope has been deleted";
- return ctx_.lock().get();
-}
-
std::string LLVMTarget::GetTargetMetadata(const llvm::Module& module) {
if (llvm::Metadata* tvm_target = module.getModuleFlag("tvm_target")) {
auto* mdstr = llvm::cast<llvm::MDString>(tvm_target);
@@ -712,55 +359,6 @@ void LLVMTarget::SetTargetMetadata(llvm::Module* module) const {
llvm::MDString::get(*GetContext(), str()));
}
-bool LLVMTarget::ApplyLLVMOptions(bool apply_otherwise_revert, bool dry_run) {
- llvm::StringMap<llvm::cl::Option*>& options = llvm::cl::getRegisteredOptions();
- bool changed = false;
-
-#define HANDLE_OPTION_VALUE(option, new_val, saved_val) \
- do { \
- auto current = (option)->getValue(); \
- auto replacement = apply_otherwise_revert ? (new_val) : (saved_val); \
- if (current != replacement) { \
- changed = true; \
- if (!dry_run) { \
- (option)->setValue(replacement); \
- } \
- } \
- } while (false);
-
- const auto& new_options = GetCommandLineOptions();
- for (size_t i = 0, e = saved_llvm_options_.size(); i != e; ++i) {
- const Option& new_opt = new_options[i];
- const Option& saved_opt = saved_llvm_options_[i];
-
- llvm::cl::Option* base_op = options[new_opt.name];
-
- if (new_opt.type == Option::OptType::Bool) {
- auto* bool_op = static_cast<llvm::cl::opt<bool>*>(base_op);
- HANDLE_OPTION_VALUE(bool_op, new_opt.value.b, saved_opt.value.b);
- } else if (new_opt.type == Option::OptType::Int) {
- auto* int_op = static_cast<llvm::cl::opt<int>*>(base_op);
- HANDLE_OPTION_VALUE(int_op, new_opt.value.i, saved_opt.value.i);
- } else if (new_opt.type == Option::OptType::UInt) {
- auto* uint_op = static_cast<llvm::cl::opt<unsigned>*>(base_op);
- HANDLE_OPTION_VALUE(uint_op, new_opt.value.u, saved_opt.value.u);
- } else if (new_opt.type == Option::OptType::String) {
- auto* str_op = static_cast<llvm::cl::opt<std::string>*>(base_op);
- HANDLE_OPTION_VALUE(str_op, new_opt.value.s, saved_opt.value.s);
- } else {
- LOG(FATAL) << "unexpected type in option " << new_opt;
- }
-
- if (dry_run && changed) {
- return true;
- }
- }
-
-#undef HANDLE_OPTION_VALUE
-
- return changed;
-}
-
} // namespace codegen
} // namespace tvm
diff --git a/src/target/llvm/llvm_instance.h b/src/target/llvm/llvm_instance.h
index 217db63aad..afb6e58deb 100644
--- a/src/target/llvm/llvm_instance.h
+++ b/src/target/llvm/llvm_instance.h
@@ -38,7 +38,6 @@
#include <tvm/runtime/container/string.h>
#include <tvm/target/target.h>
-#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -58,9 +57,8 @@ class LLVMTarget;
/*!
* \class LLVMInstance
- * \brief LLVMInstance is a class that (conceptually) starts and stops LLVM.
- * All uses of LLVM should take place within a lifetime of an object
- * of this class.
+ * \brief LLVMInstance is a class that (conceptually) starts and stops LLVM. All
+ * uses of LLVM should take place within a lifetime of an object of this class.
*
* E.g.
* ```{.cpp}
@@ -130,48 +128,60 @@ class LLVMInstance {
};
/*!
- * \class LLVMTargetInfo
- * \brief Summary of information for this TVM target relevant to LLVM code
- * generation.
+ * \class LLVMTarget
+ * \brief Information used by LLVM for code generation for particular target
*
* This class contains all information that LLVM needs for code generation for
- * a particular target. The purpose of this class is only to provide information
- * in an easily-accessible form (for example for querying the target properties).
+ * a particular target. Since Target in TVM will soon contain command line
+ * flags for LLVM, objects of this class will handle saving and restoring
+ * global LLVM state that may be affected by these flags. This way, code
+ * generation for each LLVM-based target in TVM will start with the same LLVM
+ * global state.
*
* Note that objects of this class must be created within the lifetime of an
* LLVMInstance object.
*/
-class LLVMTargetInfo {
+class LLVMTarget {
public:
/*!
- * \brief Constructs LLVMTargetInfo from `Target`
+ * \brief Constructs LLVMTarget from `Target`
* \param scope LLVMInstance object
* \param target TVM Target object for target "llvm"
*/
- LLVMTargetInfo(LLVMInstance& scope, const Target& target); // NOLINT(runtime/references)
+ LLVMTarget(LLVMInstance& scope, const Target& target); // NOLINT(runtime/references)
/*!
- * \brief Constructs LLVMTargetInfo from target string
+ * \brief Constructs LLVMTarget from target string
* \param scope LLVMInstance object
* \param target TVM target string for target "llvm"
*/
- // NOLINTNEXTLINE(runtime/references)
- LLVMTargetInfo(LLVMInstance& scope, const std::string& target_str);
+ LLVMTarget(LLVMInstance& scope, const std::string& target_str); // NOLINT(runtime/references)
/*!
- * \brief Destroys LLVMTargetInfo object
+ * \brief Destroys LLVMTarget object
*/
- ~LLVMTargetInfo();
+ ~LLVMTarget();
/*!
- * \brief Returns string representation (as TVM target) of the LLVMTargetInfo
+ * \brief Returns string representation (as TVM target) of the LLVMTarget
* \return Target string
*
- * Note: If the LLVMTargetInfo object was created from a string `s`, the string
+ * Note: If the LLVMTarget object was created from a string `s`, the string
* returned here may not be exactly equal to `s`. For example, if the CPU
* was "default", the returned string will have CPU set to the detected host
* CPU.
*/
std::string str() const;
+ /*!
+ * \brief Get the LLVMInstance object from which the LLVMTarget object was
+ * created
+ * \return The enclosing LLVMInstance object
+ */
+ const LLVMInstance& GetInstance() const { return instance_; }
+ /*!
+ * \brief Get the current LLVM context
+ * \return the current LLVM context
+ */
+ llvm::LLVMContext* GetContext() const;
/*!
* \brief Return LLVM's `TargetMachine`, or nullptr
* \param allow_missing do not abort if the target machine cannot be created,
@@ -218,125 +228,6 @@ class LLVMTargetInfo {
*/
llvm::CodeGenOpt::Level GetOptLevel() const { return opt_level_; }
- /*!
- * \class Option
- * \brief Internal representation of command-line option
- */
- struct Option {
- enum class OptType {
- Invalid = 0, //!< placeholder, indicates parsing error
- Bool, //!< enum value corresponding to type string "bool"
- Int, //!< enum value corresponding to type string "int"
- UInt, //!< enum value corresponding to type string "uint"
- String, //!< enum value corresponding to type string "string"
- };
- std::string name; //!< option name
- OptType type; //!< type of the option value
- struct {
- union {
- bool b; //!< bool option value
- int i; //!< int option value
- unsigned u = 0; //!< unsigned option value
- };
- std::string s; //!< string option value
- } value; //!< option value specified in the option string
- };
-
- /*!
- * \brief Get LLVM command line options
- * \return the list of LLVM command line options specified for this target
- */
- const std::vector<Option>& GetCommandLineOptions() const { return llvm_options_; }
-
- /*!
- * \brief Parse a string from the `cl-opt` target attribute
- * \param str the option string
- * \return parsed `Option` object, if parsing failed the type member will be
- * set to `Option::OptType::Invalid`
- */
- static Option ParseOptionString(const std::string& str);
-
- /*!
- * \brief Checks if the settings in this object that describe global state
- * match the current global state
- * \return true or false correspondingly
- * \note The global state can be modified by command line options. This
- * function checks if the specified options differ from their current
- * values.
- */
- bool MatchesGlobalState() const;
-
- protected:
- /*!
- * \brief Get the current value of given LLVM option
- * \param opt Option with "type" and "name" set
- * Fills in the "value" field in the provided Option argument, or sets the
- * "type" to Invalid if the option value cannot be obtained.
- */
- void GetOptionValue(Option* opt) const;
-
- private:
- std::string triple_;
- std::string cpu_;
- std::vector<std::string> attrs_;
- std::vector<Option> llvm_options_;
- llvm::TargetOptions target_options_;
- llvm::FastMathFlags fast_math_flags_;
- llvm::CodeGenOpt::Level opt_level_;
- llvm::Reloc::Model reloc_model_ = llvm::Reloc::PIC_;
- llvm::CodeModel::Model code_model_ = llvm::CodeModel::Small;
- std::shared_ptr<llvm::TargetMachine> target_machine_;
-};
-
-/*!
- * \class LLVMTarget
- * \brief Information used by LLVM for code generation for particular target
- *
- * In addition to all information that LLVM needs for code generation for
- * a particular target, objects of this class handle saving and restoring
- * global LLVM state that may be affected by these flags. This way, code
- * generation for each LLVM-based target in TVM will start with the same LLVM
- * global state.
- *
- * Note that objects of this class must be created within the lifetime of an
- * LLVMInstance object.
- */
-class LLVMTarget : public LLVMTargetInfo {
- public:
- /*!
- * \brief Constructs LLVMTarget from `Target`
- * \param scope LLVMInstance object
- * \param target_info Target info object for target "llvm"
- */
- LLVMTarget(LLVMInstance& scope, const LLVMTargetInfo& target_info); // NOLINT(runtime/references)
- /*!
- * \brief Constructs LLVMTarget from `Target`
- * \param scope LLVMInstance object
- * \param target TVM Target object for target "llvm"
- */
- LLVMTarget(LLVMInstance& scope, const Target& target); // NOLINT(runtime/references)
- /*!
- * \brief Constructs LLVMTarget from target string
- * \param scope LLVMInstance object
- * \param target TVM target string for target "llvm"
- */
- LLVMTarget(LLVMInstance& scope, const std::string& target_str); // NOLINT(runtime/references)
- /*!
- * \brief Destroys LLVMTarget object
- */
- ~LLVMTarget();
-
- /*!
- * \brief Get the LLVMInstance object from which the LLVMTarget object was
- * created
- * \return The enclosing LLVMInstance object
- */
- const LLVMInstance& GetInstance() const { return instance_; }
- /*!
- * \brief Get the current LLVM context
- * \return the current LLVM context
- */
- llvm::LLVMContext* GetContext() const;
/*!
* \brief Extract the target string from given `llvm::Module`
* \param module LLVM module with the TVM target string embedded as metadata
@@ -354,27 +245,18 @@ class LLVMTarget : public LLVMTargetInfo {
void ExitWithScope() {}
private:
- std::vector<Option> saved_llvm_options_;
-
- /*!
- * \brief Apply or revert command-line LLVM options
- * \param apply_otherwise_revert if true, apply the options (saving previous
- * values, if false, then restore the saved values
- * \param dry_run if true, do not make any changes (or save anything)
- * \return true is changes were made (or would have been made in a dry run),
- * false otherwise
- */
- bool ApplyLLVMOptions(bool apply_otherwise_revert, bool dry_run = false);
-
const LLVMInstance& instance_;
std::weak_ptr<llvm::LLVMContext> ctx_;
- /*!
- * \brief Global singleton flag indicating whether LLVM's global state has
- * been modified or not (via command-line flags). There can only be
- * a single such modification in effect at any given time.
- */
- static bool modified_llvm_state_;
+ std::string triple_;
+ std::string cpu_;
+ std::vector<std::string> attrs_;
+ llvm::TargetOptions target_options_;
+ llvm::FastMathFlags fast_math_flags_;
+ llvm::CodeGenOpt::Level opt_level_;
+ llvm::Reloc::Model reloc_model_ = llvm::Reloc::PIC_;
+ llvm::CodeModel::Model code_model_ = llvm::CodeModel::Small;
+ std::shared_ptr<llvm::TargetMachine> target_machine_;
};
} // namespace codegen
diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc
index 8749925781..9aed66fffc 100644
--- a/src/target/llvm/llvm_module.cc
+++ b/src/target/llvm/llvm_module.cc
@@ -390,8 +390,8 @@ void LLVMModuleNode::LazyInitJIT() {
}
bool LLVMModuleNode::IsCompatibleWithHost(const llvm::TargetMachine* tm) const {
- LLVMTargetInfo host_target(*llvm_instance_, "llvm");
- auto tm_host = host_target.GetOrCreateTargetMachine();
+ With<LLVMTarget> host_target(*llvm_instance_, "llvm"); // FIXME(kparzysz-quic): nesting
+ auto tm_host = host_target->GetOrCreateTargetMachine();
if (tm_host->getTargetTriple().getArch() != tm->getTargetTriple().getArch()) {
LOG(INFO) << "Architecture mismatch: module=" << tm->getTargetTriple().str()
<< " host=" << tm_host->getTargetTriple().str();
@@ -496,7 +496,7 @@ runtime::Module CreateLLVMCppMetadataModule(runtime::metadata::Metadata metadata
auto llvm_instance = std::make_unique<LLVMInstance>();
With<LLVMTarget> llvm_target(*llvm_instance, target);
bool system_lib = runtime->GetAttr<Bool>("system-lib").value_or(Bool(false));
- auto cg = std::make_unique<CodeGenCPU>();
+ std::unique_ptr<CodeGenCPU> cg{new CodeGenCPU()};
cg->Init("TVMMetadataMod", llvm_target.get(), system_lib, system_lib,
/*target_c_runtime=*/false);
@@ -544,7 +544,7 @@ runtime::Module CreateLLVMCrtMetadataModule(const Array<runtime::Module>& module
ICHECK(system_lib && target_c_runtime)
<< "For LLVM C-runtime metadata module, must include --system-lib and --runtime=c; "
<< "got target: " << target->str();
- auto cg = std::make_unique<CodeGenCPU>();
+ std::unique_ptr<CodeGenCPU> cg{new CodeGenCPU()};
cg->Init("TVMMetadataMod", llvm_target.operator->(), system_lib, system_lib, target_c_runtime);
cg->DefineFunctionRegistry(func_names);