This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new 0bec7b439d Use dedicated TargetKind registry and fluent definitions
(#20469)
0bec7b439d is described below
commit 0bec7b439d4a2ed298a41b684c44d43f07c7f46f
Author: Tianqi Chen <[email protected]>
AuthorDate: Sat Sep 26 12:06:08 2026 -0400
Use dedicated TargetKind registry and fluent definitions (#20469)
TargetKind only needs canonical named instances and typed configuration
options. A small dedicated registry and temporary TargetKindDef builder
make registration direct and remove the unused attribute-map API.
- Keep TargetKind as a plain Object with its existing reflection and
target behavior.
- Define common and backend options through ConfigSchema in grouped
static initialization blocks.
- Remove the generic AttrRegistry dependency and obsolete attribute-map
forwarding API.
---
include/tvm/target/target_kind.h | 267 ++++++++++-------------------
python/tvm/target/target.py | 15 --
src/backend/cuda/codegen/target_kind.cc | 50 +++---
src/backend/hexagon/codegen/target_kind.cc | 27 ++-
src/backend/metal/codegen/target_kind.cc | 32 ++--
src/backend/opencl/codegen/target_kind.cc | 37 ++--
src/backend/rocm/codegen/target_kind.cc | 35 ++--
src/backend/trn/codegen/target_kind.cc | 22 +--
src/backend/vulkan/codegen/target_kind.cc | 85 +++++----
src/backend/webgpu/codegen/target_kind.cc | 25 ++-
src/target/target_kind.cc | 254 ++++++++++++++-------------
tests/cpp/target_test.cc | 72 ++++----
12 files changed, 398 insertions(+), 523 deletions(-)
diff --git a/include/tvm/target/target_kind.h b/include/tvm/target/target_kind.h
index 3a3d21ce53..caea01b077 100644
--- a/include/tvm/target/target_kind.h
+++ b/include/tvm/target/target_kind.h
@@ -24,14 +24,12 @@
#ifndef TVM_TARGET_TARGET_KIND_H_
#define TVM_TARGET_TARGET_KIND_H_
+#include <tvm/ffi/container/map.h>
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
-#include <tvm/ir/attr_registry_map.h>
#include <tvm/ir/config_schema.h>
#include <tvm/runtime/base.h>
-#include <memory>
-#include <unordered_map>
#include <utility>
#include <vector>
@@ -50,9 +48,6 @@ using FTargetCanonicalizer =
class TargetInternal;
-template <typename>
-class TargetKindAttrMap;
-
/*! \brief Target kind, specifies the kind of the target */
class TargetKindNode : public ffi::Object {
public:
@@ -79,20 +74,10 @@ class TargetKindNode : public ffi::Object {
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("target.TargetKind", TargetKindNode,
ffi::Object);
private:
- /*! \brief Return the index stored in attr registry */
- uint32_t AttrRegistryIndex() const { return index_; }
- /*! \brief Return the name stored in attr registry */
- ffi::String AttrRegistryName() const { return name; }
/*! \brief ConfigSchema for validating and resolving target attributes */
ir::ConfigSchema schema_;
- /*! \brief Index used for internal lookup of attribute registry */
- uint32_t index_;
-
- template <typename, typename>
- friend class AttrRegistry;
- template <typename>
- friend class AttrRegistryMapContainerMap;
- friend class TargetKindRegEntry;
+ friend class TargetKindRegistry;
+ friend class TargetKindDef;
friend class TargetInternal;
};
@@ -106,13 +91,10 @@ class TargetKind : public ffi::ObjectRef {
explicit TargetKind(ffi::ObjectPtr<TargetKindNode> data) :
ffi::ObjectRef(data) {
TVM_FFI_ICHECK(data != nullptr);
}
- /*! \brief Get the attribute map given the attribute name */
- template <typename ValueType>
- static inline TargetKindAttrMap<ValueType> GetAttrMap(const ffi::String&
attr_name);
/*!
* \brief Retrieve the TargetKind given its name
* \param target_kind_name Name of the target kind
- * \return The TargetKind requested
+ * \return The canonical kind, or nullopt when the name is unknown.
*/
TVM_DLL static ffi::Optional<TargetKind> Get(const ffi::String&
target_kind_name);
/*! \brief Mutable access to the container class */
@@ -121,26 +103,9 @@ class TargetKind : public ffi::ObjectRef {
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TargetKind, ffi::ObjectRef,
TargetKindNode);
private:
- TVM_DLL static const AttrRegistryMapContainerMap<TargetKind>&
GetAttrMapContainer(
- const ffi::String& attr_name);
- friend class TargetKindRegEntry;
friend class TargetInternal;
};
-/*!
- * \brief ffi::Map<TargetKind, ValueType> used to store meta-information about
TargetKind
- * \tparam ValueType The type of the value stored in map
- */
-template <typename ValueType>
-class TargetKindAttrMap : public AttrRegistryMap<TargetKind, ValueType> {
- public:
- using TParent = AttrRegistryMap<TargetKind, ValueType>;
- using TParent::count;
- using TParent::get;
- using TParent::operator[];
- explicit TargetKindAttrMap(const AttrRegistryMapContainerMap<TargetKind>&
map) : TParent(map) {}
-};
-
/*! \brief Value used with --runtime in target specs to indicate the C++
runtime. */
static constexpr const char* kTvmRuntimeCpp = "c++";
@@ -148,171 +113,111 @@ static constexpr const char* kTvmRuntimeCpp = "c++";
static constexpr const char* kTvmRuntimeCrt = "c";
/*!
- * \brief Helper structure to register TargetKind
- * \sa TVM_REGISTER_TARGET_KIND
+ * \brief Process-wide registry of canonical target kinds, keyed by name.
*/
-class TargetKindRegEntry {
+class TargetKindRegistry {
public:
/*!
- * \brief Register additional attributes to target_kind.
- * \param attr_name The name of the attribute.
- * \param value The value to be set.
- * \param plevel The priority level of this attribute,
- * an higher priority level attribute
- * will replace lower priority level attribute.
- * Must be bigger than 0.
- *
- * Cannot set with same plevel twice in the code.
- *
- * \tparam ValueType The type of the value to be set.
+ * \brief Access the process-wide registry.
+ * \return The singleton registry.
*/
- template <typename ValueType>
- inline TargetKindRegEntry& set_attr(const ffi::String& attr_name, const
ValueType& value,
- int plevel = 10);
+ TVM_DLL static TargetKindRegistry* Global();
/*!
- * \brief Set DLPack's device_type the target
- * \param device_type Device type
+ * \brief Register a name or return its existing canonical kind.
+ * \param name Target kind name.
+ * \return The canonical target kind for name. Standard target options are
+ * declared when the name is first registered.
*/
- inline TargetKindRegEntry& set_default_device_type(int device_type);
+ TVM_DLL TargetKind RegisterOrGet(const ffi::String& name);
/*!
- * \brief Set DLPack's device_type the target
- * \param keys The default keys
+ * \brief Look up a registered kind.
+ * \param name Target kind name.
+ * \return The canonical kind, or nullopt when name is unknown.
*/
- inline TargetKindRegEntry& set_default_keys(std::vector<ffi::String> keys);
+ TVM_DLL ffi::Optional<TargetKind> Get(const ffi::String& name);
/*!
- * \brief Set the canonicalizer function applied upon target creation.
- * \param canonicalizer The target canonicalizer function.
+ * \brief List registered kind names.
+ * \return Names of all registered target kinds.
*/
- inline TargetKindRegEntry& set_target_canonicalizer(FTargetCanonicalizer
canonicalizer);
+ TVM_DLL ffi::Array<ffi::String> ListTargetKinds();
/*!
- * \brief Register a valid configuration option and its ValueType for
validation
- * \param key The configuration key
- * \param traits Optional traits (e.g. refl::DefaultValue, doc string, or
raw default value)
- * \tparam ValueType The value type to be registered
- * \tparam Traits Optional trait types
+ * \brief List declared option names and types for a kind.
+ * \param kind Registered target kind.
+ * \return Map from option name to type string.
*/
- template <typename ValueType, typename... Traits>
- inline TargetKindRegEntry& add_attr_option(const ffi::String& key,
Traits&&... traits);
- /*! \brief Set name of the TargetKind to be the same as registry if it is
empty */
- inline TargetKindRegEntry& set_name();
+ TVM_DLL ffi::Map<ffi::String, ffi::String> ListTargetKindOptions(const
TargetKind& kind);
+
+ private:
+ ffi::Map<ffi::String, TargetKind> kinds_;
+};
+
+/*!
+ * \brief Temporary fluent builder for registering a target kind.
+ *
+ * The registry retains the canonical kind after this builder is destroyed.
+ * Group related definitions inside TVM_FFI_STATIC_INIT_BLOCK():
+ * \code
+ * TVM_FFI_STATIC_INIT_BLOCK() {
+ * TargetKindDef("llvm")
+ * .set_default_device_type(kDLCPU)
+ * .set_default_keys({"cpu"})
+ * .def_option<ffi::String>("mcpu");
+ * }
+ * \endcode
+ */
+class TargetKindDef {
+ public:
/*!
- * \brief List all the entry names in the registry.
- * \return The entry names.
+ * \brief Register or retrieve the canonical kind with this name.
+ * \param name Target kind name.
*/
- TVM_DLL static ffi::Array<ffi::String> ListTargetKinds();
+ explicit TargetKindDef(const ffi::String& name)
+ : kind_(TargetKindRegistry::Global()->RegisterOrGet(name)) {}
/*!
- * \brief Get all supported option names and types for a given Target kind.
- * \return Map of option name to type
+ * \brief Set the default DLPack device type.
+ * \param device_type DLPack device type.
+ * \return This builder for chaining.
*/
- TVM_DLL static ffi::Map<ffi::String, ffi::String>
ListTargetKindOptions(const TargetKind& kind);
-
+ TargetKindDef& set_default_device_type(int device_type) {
+ kind_->default_device_type = device_type;
+ return *this;
+ }
/*!
- * \brief Register or get a new entry.
- * \param target_kind_name The name of the TargetKind.
- * \return the corresponding entry.
+ * \brief Set default target keys.
+ * \param keys Default keys in priority order.
+ * \return This builder for chaining.
*/
- TVM_DLL static TargetKindRegEntry& RegisterOrGet(const ffi::String&
target_kind_name);
-
- private:
- TargetKind kind_;
- ffi::String name;
-
- /*! \brief private constructor */
- explicit TargetKindRegEntry(uint32_t reg_index) :
kind_(ffi::make_object<TargetKindNode>()) {
- kind_->index_ = reg_index;
+ TargetKindDef& set_default_keys(std::vector<ffi::String> keys) {
+ kind_->default_keys = keys;
+ return *this;
}
/*!
- * \brief update the attribute TargetKindAttrMap
- * \param key The name of the attribute
- * \param value The value to be set
- * \param plevel The priority level
+ * \brief Set the canonicalizer used when constructing targets of this kind.
+ * \param canonicalizer Function from a validated config map to its
canonical form.
+ * \return This builder for chaining. Also updates the kind's ConfigSchema.
*/
- TVM_DLL void UpdateAttr(const ffi::String& key, ffi::Any value, int plevel);
- template <typename, typename>
- friend class AttrRegistry;
- friend class TargetKind;
-};
-
-template <typename ValueType>
-inline TargetKindAttrMap<ValueType> TargetKind::GetAttrMap(const ffi::String&
attr_name) {
- return TargetKindAttrMap<ValueType>(GetAttrMapContainer(attr_name));
-}
-
-template <typename ValueType>
-inline TargetKindRegEntry& TargetKindRegEntry::set_attr(const ffi::String&
attr_name,
- const ValueType&
value, int plevel) {
- TVM_FFI_ICHECK_GT(plevel, 0) << "plevel in set_attr must be greater than 0";
- ffi::Any rv;
- rv = value;
- UpdateAttr(attr_name, rv, plevel);
- return *this;
-}
-
-inline TargetKindRegEntry& TargetKindRegEntry::set_default_device_type(int
device_type) {
- kind_->default_device_type = device_type;
- return *this;
-}
-
-inline TargetKindRegEntry&
TargetKindRegEntry::set_default_keys(std::vector<ffi::String> keys) {
- kind_->default_keys = keys;
- return *this;
-}
-
-inline TargetKindRegEntry& TargetKindRegEntry::set_target_canonicalizer(
- FTargetCanonicalizer canonicalizer) {
- kind_->target_canonicalizer = canonicalizer;
- kind_->schema_.set_canonicalizer(canonicalizer);
- return *this;
-}
-
-template <typename ValueType, typename... Traits>
-inline TargetKindRegEntry& TargetKindRegEntry::add_attr_option(const
ffi::String& key,
- Traits&&...
traits) {
- kind_->schema_.def_option<ValueType>(key, std::forward<Traits>(traits)...);
- return *this;
-}
-
-inline TargetKindRegEntry& TargetKindRegEntry::set_name() {
- if (kind_->name.empty()) {
- kind_->name = name;
+ TargetKindDef& set_target_canonicalizer(FTargetCanonicalizer canonicalizer) {
+ kind_->target_canonicalizer = canonicalizer;
+ kind_->schema_.set_canonicalizer(canonicalizer);
+ return *this;
+ }
+ /*!
+ * \brief Declare a typed target option in the kind's ConfigSchema.
+ * \tparam ValueType Canonical option value type.
+ * \tparam Traits Optional metadata or validator trait types.
+ * \param key Option name.
+ * \param traits Optional traits such as a default value or validator.
+ * \return This builder for chaining. Duplicate option names raise
ValueError.
+ */
+ template <typename ValueType, typename... Traits>
+ TargetKindDef& def_option(const ffi::String& key, Traits&&... traits) {
+ kind_->schema_.def_option<ValueType>(key, std::forward<Traits>(traits)...);
+ return *this;
}
- return *this;
-}
-
-#define TVM_TARGET_KIND_REGISTER_VAR_DEF \
- [[maybe_unused]] static ::tvm::TargetKindRegEntry& __make_##TargetKind
-/*!
- * \def TVM_REGISTER_TARGET_KIND
- * \brief Register a new target kind, or set attribute of the corresponding
target kind.
- *
- * \param TargetKindName The name of target kind
- * \param DeviceType The DLDeviceType of the target kind
- *
- * \code
- *
- * TVM_REGISTER_TARGET_KIND("llvm")
- * .set_attr<TPreCodegenPass>("TPreCodegenPass", a-pre-codegen-pass)
- * .add_attr_option<Bool>("system_lib")
- * .add_attr_option<ffi::String>("mtriple")
- * .add_attr_option<ffi::String>("mattr");
- *
- * \endcode
- */
-#define TVM_REGISTER_TARGET_KIND(TargetKindName, DeviceType) \
- TVM_FFI_STR_CONCAT(TVM_TARGET_KIND_REGISTER_VAR_DEF, __COUNTER__) = \
- ::tvm::TargetKindRegEntry::RegisterOrGet(TargetKindName) \
- .set_name() \
- .set_default_device_type(DeviceType) \
- .add_attr_option<ffi::String>("kind") \
- .add_attr_option<ffi::Array<ffi::String>>("keys") \
- .add_attr_option<ffi::String>("tag") \
- .add_attr_option<ffi::String>("device") \
- .add_attr_option<ffi::String>("model") \
- .add_attr_option<ffi::Array<ffi::String>>("libs") \
- .add_attr_option<Target>("host") \
- .add_attr_option<int64_t>("from_device") \
- .add_attr_option<int64_t>("target_device_type")
+ private:
+ TargetKind kind_;
+};
} // namespace tvm
diff --git a/python/tvm/target/target.py b/python/tvm/target/target.py
index a1f7a8091c..0ecfd1d34c 100644
--- a/python/tvm/target/target.py
+++ b/python/tvm/target/target.py
@@ -210,21 +210,6 @@ class Target(Object):
return str(value) if isinstance(value, String) else value
raise AttributeError(f"'Target' object has no attribute '{name}'")
- def get_kind_attr(self, attr_name):
- """Get additional attribute about the target kind.
-
- Parameters
- ----------
- attr_name : str
- The attribute name.
-
- Returns
- -------
- value : object
- The attribute value
- """
- return _ffi_api.TargetKindGetAttr(self.kind, attr_name)
-
def get_target_device_type(self):
"""Returns the device_type for this target."""
return _ffi_api.TargetGetDeviceType(self)
diff --git a/src/backend/cuda/codegen/target_kind.cc
b/src/backend/cuda/codegen/target_kind.cc
index b63f1f6e96..26b8a506fc 100644
--- a/src/backend/cuda/codegen/target_kind.cc
+++ b/src/backend/cuda/codegen/target_kind.cc
@@ -111,35 +111,39 @@ ffi::Map<ffi::String, ffi::Any>
UpdateNVPTXAttrs(ffi::Map<ffi::String, ffi::Any>
return target;
}
-void RegisterTargetKinds() {
+} // namespace cuda
+} // namespace backend
+} // namespace tvm
+
+TVM_FFI_STATIC_INIT_BLOCK() {
+ using namespace tvm;
+ using namespace tvm::backend::cuda;
namespace refl = tvm::ffi::reflection;
- TVM_REGISTER_TARGET_KIND("cuda_host", kDLCPU).set_default_keys({"cpu"});
+ TargetKindDef("cuda_host")
+ .set_default_device_type(kDLCPU) // line break
+ .set_default_keys({"cpu"});
- TVM_REGISTER_TARGET_KIND("cuda", kDLCUDA)
- .add_attr_option<ffi::String>("mcpu")
- .add_attr_option<ffi::String>("arch")
- .add_attr_option<int64_t>("max_shared_memory_per_block")
- .add_attr_option<int64_t>("max_threads_per_block")
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(32))
- .add_attr_option<int64_t>("registers_per_block")
- .add_attr_option<int64_t>("l2_cache_size_bytes")
- .add_attr_option<int64_t>("max_num_threads",
- refl::DefaultValue(1024)) // TODO(@zxybazh):
deprecate it
+ TargetKindDef("cuda")
+ .set_default_device_type(kDLCUDA)
+ .def_option<ffi::String>("mcpu")
+ .def_option<ffi::String>("arch")
+ .def_option<int64_t>("max_shared_memory_per_block")
+ .def_option<int64_t>("max_threads_per_block")
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(32))
+ .def_option<int64_t>("registers_per_block")
+ .def_option<int64_t>("l2_cache_size_bytes")
+ .def_option<int64_t>("max_num_threads",
+ refl::DefaultValue(1024)) // TODO(@zxybazh):
deprecate it
.set_default_keys({"cuda", "gpu"})
.set_target_canonicalizer(UpdateCUDAAttrs);
- TVM_REGISTER_TARGET_KIND("nvptx", kDLCUDA)
- .add_attr_option<ffi::String>("mcpu")
- .add_attr_option<ffi::String>("mtriple")
- .add_attr_option<int64_t>("max_num_threads", refl::DefaultValue(1024))
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(32))
+ TargetKindDef("nvptx")
+ .set_default_device_type(kDLCUDA)
+ .def_option<ffi::String>("mcpu")
+ .def_option<ffi::String>("mtriple")
+ .def_option<int64_t>("max_num_threads", refl::DefaultValue(1024))
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(32))
.set_default_keys({"cuda", "gpu"})
.set_target_canonicalizer(UpdateNVPTXAttrs);
}
-
-} // namespace cuda
-} // namespace backend
-} // namespace tvm
-
-TVM_FFI_STATIC_INIT_BLOCK() { tvm::backend::cuda::RegisterTargetKinds(); }
diff --git a/src/backend/hexagon/codegen/target_kind.cc
b/src/backend/hexagon/codegen/target_kind.cc
index c71d734f9f..fd00be35cd 100644
--- a/src/backend/hexagon/codegen/target_kind.cc
+++ b/src/backend/hexagon/codegen/target_kind.cc
@@ -28,22 +28,6 @@
#include <tvm/target/target_kind.h>
namespace tvm {
-namespace backend {
-namespace hexagon {
-
-void RegisterTargetKind() {
- TVM_REGISTER_TARGET_KIND("hexagon", kDLHexagon)
- .add_attr_option<ffi::Array<ffi::String>>("mattr")
- .add_attr_option<ffi::String>("mcpu")
- .add_attr_option<ffi::String>("mtriple")
- .add_attr_option<ffi::Array<ffi::String>>("llvm-options")
- .add_attr_option<int64_t>("num-cores")
- .add_attr_option<int64_t>("vtcm-capacity")
- .set_default_keys({"hexagon", "cpu"});
-}
-
-} // namespace hexagon
-} // namespace backend
#ifdef TVM_LLVM_VERSION
namespace codegen {
@@ -56,7 +40,16 @@ void RegisterHexagonIntrinRules();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::hexagon::RegisterTargetKind();
+ using namespace tvm;
+ TargetKindDef("hexagon")
+ .set_default_device_type(kDLHexagon)
+ .def_option<ffi::Array<ffi::String>>("mattr")
+ .def_option<ffi::String>("mcpu")
+ .def_option<ffi::String>("mtriple")
+ .def_option<ffi::Array<ffi::String>>("llvm-options")
+ .def_option<int64_t>("num-cores")
+ .def_option<int64_t>("vtcm-capacity")
+ .set_default_keys({"hexagon", "cpu"});
#ifdef TVM_LLVM_VERSION
tvm::codegen::llvm::RegisterHexagonIntrinRules();
tvm::codegen::RegisterHexagonCodegen();
diff --git a/src/backend/metal/codegen/target_kind.cc
b/src/backend/metal/codegen/target_kind.cc
index 3fda53fe70..f7c35e0a60 100644
--- a/src/backend/metal/codegen/target_kind.cc
+++ b/src/backend/metal/codegen/target_kind.cc
@@ -29,25 +29,6 @@
namespace tvm {
-namespace backend {
-namespace metal {
-
-void RegisterTargetKind() {
- namespace refl = tvm::ffi::reflection;
-
- // Metal limits the number of kernel arguments. `max_function_args`
captures that bound.
- TVM_REGISTER_TARGET_KIND("metal", kDLMetal)
- .add_attr_option<int64_t>("max_num_threads", refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_threads_per_block",
refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(32768))
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(16))
- .add_attr_option<int64_t>("max_function_args", refl::DefaultValue(31))
- .set_default_keys({"metal", "gpu"});
-}
-
-} // namespace metal
-} // namespace backend
-
namespace codegen {
void RegisterMetalCodegen();
namespace intrin {
@@ -57,7 +38,18 @@ void RegisterMetalIntrinRules();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::metal::RegisterTargetKind();
+ using namespace tvm;
+ namespace refl = tvm::ffi::reflection;
+
+ // Metal limits the number of kernel arguments. `max_function_args`
captures that bound.
+ TargetKindDef("metal")
+ .set_default_device_type(kDLMetal)
+ .def_option<int64_t>("max_num_threads", refl::DefaultValue(256))
+ .def_option<int64_t>("max_threads_per_block", refl::DefaultValue(256))
+ .def_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(32768))
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(16))
+ .def_option<int64_t>("max_function_args", refl::DefaultValue(31))
+ .set_default_keys({"metal", "gpu"});
tvm::codegen::intrin::RegisterMetalIntrinRules();
tvm::codegen::RegisterMetalCodegen();
}
diff --git a/src/backend/opencl/codegen/target_kind.cc
b/src/backend/opencl/codegen/target_kind.cc
index dfdc10e062..70219c7bf3 100644
--- a/src/backend/opencl/codegen/target_kind.cc
+++ b/src/backend/opencl/codegen/target_kind.cc
@@ -28,27 +28,6 @@
#include <tvm/target/target_kind.h>
namespace tvm {
-namespace backend {
-namespace opencl {
-
-void RegisterTargetKind() {
- namespace refl = tvm::ffi::reflection;
-
- TVM_REGISTER_TARGET_KIND("opencl", kDLOpenCL)
- .add_attr_option<int64_t>("max_threads_per_block",
refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(16384))
- .add_attr_option<int64_t>("max_num_threads", refl::DefaultValue(256))
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(1))
- .add_attr_option<int64_t>("texture_spatial_limit",
refl::DefaultValue(16384))
- .add_attr_option<int64_t>("texture_depth_limit",
refl::DefaultValue(2048))
- // Qualcomm OpenCL runtimes may crash when the number of kernel
arguments is too large.
- .add_attr_option<int64_t>("max_function_args", refl::DefaultValue(128))
- .add_attr_option<int64_t>("image_base_address_alignment",
refl::DefaultValue(64))
- .set_default_keys({"opencl", "gpu"});
-}
-
-} // namespace opencl
-} // namespace backend
namespace codegen {
void RegisterOpenCLCodegen();
@@ -60,7 +39,21 @@ void RegisterOpenCLIntrinRules();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::opencl::RegisterTargetKind();
+ using namespace tvm;
+ namespace refl = tvm::ffi::reflection;
+
+ TargetKindDef("opencl")
+ .set_default_device_type(kDLOpenCL)
+ .def_option<int64_t>("max_threads_per_block", refl::DefaultValue(256))
+ .def_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(16384))
+ .def_option<int64_t>("max_num_threads", refl::DefaultValue(256))
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(1))
+ .def_option<int64_t>("texture_spatial_limit", refl::DefaultValue(16384))
+ .def_option<int64_t>("texture_depth_limit", refl::DefaultValue(2048))
+ // Qualcomm OpenCL runtimes may crash when the number of kernel
arguments is too large.
+ .def_option<int64_t>("max_function_args", refl::DefaultValue(128))
+ .def_option<int64_t>("image_base_address_alignment",
refl::DefaultValue(64))
+ .set_default_keys({"opencl", "gpu"});
tvm::codegen::intrin::RegisterOpenCLIntrinRules();
tvm::codegen::RegisterOpenCLCodegen();
tvm::codegen::RegisterOpenCLDeviceScopeCompatibility();
diff --git a/src/backend/rocm/codegen/target_kind.cc
b/src/backend/rocm/codegen/target_kind.cc
index f0f5898def..cfc24bc0a1 100644
--- a/src/backend/rocm/codegen/target_kind.cc
+++ b/src/backend/rocm/codegen/target_kind.cc
@@ -109,23 +109,6 @@ ffi::Map<ffi::String, ffi::Any>
UpdateROCmAttrs(ffi::Map<ffi::String, ffi::Any>
return target;
}
-void RegisterTargetKind() {
- namespace refl = tvm::ffi::reflection;
-
- TVM_REGISTER_TARGET_KIND("rocm", kDLROCM)
- .add_attr_option<ffi::String>("mcpu")
- .add_attr_option<ffi::String>("mtriple")
- .add_attr_option<ffi::Array<ffi::String>>("mattr")
- // TODO(masahi): Support querying from a target device
- // On RDNA cards, thread_warp_size should be 32
- .add_attr_option<int64_t>("max_num_threads", refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_threads_per_block",
refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(65536))
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(64))
- .set_default_keys({"rocm", "gpu"})
- .set_target_canonicalizer(UpdateROCmAttrs);
-}
-
} // namespace rocm
} // namespace backend
@@ -140,7 +123,23 @@ void RegisterROCMIntrinRules();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::rocm::RegisterTargetKind();
+ using namespace tvm;
+ using namespace tvm::backend::rocm;
+ namespace refl = tvm::ffi::reflection;
+
+ TargetKindDef("rocm")
+ .set_default_device_type(kDLROCM)
+ .def_option<ffi::String>("mcpu")
+ .def_option<ffi::String>("mtriple")
+ .def_option<ffi::Array<ffi::String>>("mattr")
+ // TODO(masahi): Support querying from a target device
+ // On RDNA cards, thread_warp_size should be 32
+ .def_option<int64_t>("max_num_threads", refl::DefaultValue(256))
+ .def_option<int64_t>("max_threads_per_block", refl::DefaultValue(256))
+ .def_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(65536))
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(64))
+ .set_default_keys({"rocm", "gpu"})
+ .set_target_canonicalizer(UpdateROCmAttrs);
#ifdef TVM_LLVM_VERSION
tvm::codegen::llvm::RegisterROCMIntrinRules();
tvm::codegen::RegisterAMDGPUCodegen();
diff --git a/src/backend/trn/codegen/target_kind.cc
b/src/backend/trn/codegen/target_kind.cc
index 2c1e9676e6..3d29c4aec0 100644
--- a/src/backend/trn/codegen/target_kind.cc
+++ b/src/backend/trn/codegen/target_kind.cc
@@ -29,20 +29,6 @@
namespace tvm {
-namespace backend {
-namespace trn {
-
-void RegisterTargetKind() {
- TVM_REGISTER_TARGET_KIND("trn", kDLTrn)
- .add_attr_option<int64_t>("partition_size", 128)
- .add_attr_option<int64_t>("max_sbuf_size_per_partition", 196608)
- .add_attr_option<int64_t>("max_psum_size_per_partition", 16384)
- .add_attr_option<int64_t>("num-cores");
-}
-
-} // namespace trn
-} // namespace backend
-
namespace codegen {
void RegisterTRNCodegen();
} // namespace codegen
@@ -55,7 +41,13 @@ void RegisterTRNTransforms();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::trn::RegisterTargetKind();
+ using namespace tvm;
+ TargetKindDef("trn")
+ .set_default_device_type(kDLTrn)
+ .def_option<int64_t>("partition_size", 128)
+ .def_option<int64_t>("max_sbuf_size_per_partition", 196608)
+ .def_option<int64_t>("max_psum_size_per_partition", 16384)
+ .def_option<int64_t>("num-cores");
tvm::codegen::RegisterTRNCodegen();
tvm::tirx::transform::RegisterTRNTransforms();
}
diff --git a/src/backend/vulkan/codegen/target_kind.cc
b/src/backend/vulkan/codegen/target_kind.cc
index d956196ddd..52ad669bc3 100644
--- a/src/backend/vulkan/codegen/target_kind.cc
+++ b/src/backend/vulkan/codegen/target_kind.cc
@@ -28,51 +28,6 @@
#include <tvm/target/target_kind.h>
namespace tvm {
-namespace backend {
-namespace vulkan {
-
-void RegisterTargetKind() {
- namespace refl = tvm::ffi::reflection;
-
- TVM_REGISTER_TARGET_KIND("vulkan", kDLVulkan)
- .add_attr_option<ffi::Array<ffi::String>>("mattr")
- .add_attr_option<bool>("supports_float16")
- .add_attr_option<bool>("supports_float32", refl::DefaultValue(true))
- .add_attr_option<bool>("supports_float64")
- .add_attr_option<bool>("supports_int8")
- .add_attr_option<bool>("supports_int16")
- .add_attr_option<bool>("supports_int32", refl::DefaultValue(true))
- .add_attr_option<bool>("supports_int64")
- .add_attr_option<bool>("supports_8bit_buffer")
- .add_attr_option<bool>("supports_16bit_buffer")
- .add_attr_option<bool>("supports_storage_buffer_storage_class")
- .add_attr_option<bool>("supports_push_descriptor")
- .add_attr_option<bool>("supports_dedicated_allocation")
- .add_attr_option<bool>("supports_integer_dot_product")
- .add_attr_option<bool>("supports_cooperative_matrix")
- .add_attr_option<int64_t>("supported_subgroup_operations")
- .add_attr_option<int64_t>("max_num_threads", refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_threads_per_block",
refl::DefaultValue(256))
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(1))
- .add_attr_option<int64_t>("max_block_size_x")
- .add_attr_option<int64_t>("max_block_size_y")
- .add_attr_option<int64_t>("max_block_size_z")
- .add_attr_option<int64_t>("max_push_constants_size")
- .add_attr_option<int64_t>("max_uniform_buffer_range")
- .add_attr_option<int64_t>("max_storage_buffer_range")
- .add_attr_option<int64_t>("max_per_stage_descriptor_storage_buffer")
- .add_attr_option<int64_t>("max_shared_memory_per_block")
- .add_attr_option<ffi::String>("device_type")
- .add_attr_option<ffi::String>("device_name")
- .add_attr_option<ffi::String>("driver_name")
- .add_attr_option<int64_t>("driver_version")
- .add_attr_option<int64_t>("vulkan_api_version")
- .add_attr_option<int64_t>("max_spirv_version")
- .set_default_keys({"vulkan", "gpu"});
-}
-
-} // namespace vulkan
-} // namespace backend
#ifdef TVM_ENABLE_SPIRV
namespace codegen {
@@ -85,7 +40,45 @@ void RegisterVulkanIntrinRules();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::vulkan::RegisterTargetKind();
+ using namespace tvm;
+ namespace refl = tvm::ffi::reflection;
+
+ TargetKindDef("vulkan")
+ .set_default_device_type(kDLVulkan)
+ .def_option<ffi::Array<ffi::String>>("mattr")
+ .def_option<bool>("supports_float16")
+ .def_option<bool>("supports_float32", refl::DefaultValue(true))
+ .def_option<bool>("supports_float64")
+ .def_option<bool>("supports_int8")
+ .def_option<bool>("supports_int16")
+ .def_option<bool>("supports_int32", refl::DefaultValue(true))
+ .def_option<bool>("supports_int64")
+ .def_option<bool>("supports_8bit_buffer")
+ .def_option<bool>("supports_16bit_buffer")
+ .def_option<bool>("supports_storage_buffer_storage_class")
+ .def_option<bool>("supports_push_descriptor")
+ .def_option<bool>("supports_dedicated_allocation")
+ .def_option<bool>("supports_integer_dot_product")
+ .def_option<bool>("supports_cooperative_matrix")
+ .def_option<int64_t>("supported_subgroup_operations")
+ .def_option<int64_t>("max_num_threads", refl::DefaultValue(256))
+ .def_option<int64_t>("max_threads_per_block", refl::DefaultValue(256))
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(1))
+ .def_option<int64_t>("max_block_size_x")
+ .def_option<int64_t>("max_block_size_y")
+ .def_option<int64_t>("max_block_size_z")
+ .def_option<int64_t>("max_push_constants_size")
+ .def_option<int64_t>("max_uniform_buffer_range")
+ .def_option<int64_t>("max_storage_buffer_range")
+ .def_option<int64_t>("max_per_stage_descriptor_storage_buffer")
+ .def_option<int64_t>("max_shared_memory_per_block")
+ .def_option<ffi::String>("device_type")
+ .def_option<ffi::String>("device_name")
+ .def_option<ffi::String>("driver_name")
+ .def_option<int64_t>("driver_version")
+ .def_option<int64_t>("vulkan_api_version")
+ .def_option<int64_t>("max_spirv_version")
+ .set_default_keys({"vulkan", "gpu"});
#ifdef TVM_ENABLE_SPIRV
tvm::codegen::spirv::RegisterVulkanIntrinRules();
tvm::codegen::RegisterVulkanCodegen();
diff --git a/src/backend/webgpu/codegen/target_kind.cc
b/src/backend/webgpu/codegen/target_kind.cc
index abb40fdc29..658ac4dca7 100644
--- a/src/backend/webgpu/codegen/target_kind.cc
+++ b/src/backend/webgpu/codegen/target_kind.cc
@@ -51,18 +51,6 @@ ffi::Map<ffi::String, ffi::Any>
UpdateWebGPUAttrs(ffi::Map<ffi::String, ffi::Any
return target;
}
-void RegisterTargetKind() {
- namespace refl = tvm::ffi::reflection;
-
- TVM_REGISTER_TARGET_KIND("webgpu", kDLWebGPU)
- .add_attr_option<int64_t>("max_num_threads", refl::DefaultValue(256))
- .add_attr_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(32768))
- .add_attr_option<bool>("supports_subgroups", refl::DefaultValue(false))
- .add_attr_option<int64_t>("thread_warp_size", refl::DefaultValue(1))
- .set_target_canonicalizer(UpdateWebGPUAttrs)
- .set_default_keys({"webgpu", "gpu"});
-}
-
} // namespace webgpu
} // namespace backend
@@ -75,7 +63,18 @@ void RegisterWebGPUIntrinRules();
} // namespace tvm
TVM_FFI_STATIC_INIT_BLOCK() {
- tvm::backend::webgpu::RegisterTargetKind();
+ using namespace tvm;
+ using namespace tvm::backend::webgpu;
+ namespace refl = tvm::ffi::reflection;
+
+ TargetKindDef("webgpu")
+ .set_default_device_type(kDLWebGPU)
+ .def_option<int64_t>("max_num_threads", refl::DefaultValue(256))
+ .def_option<int64_t>("max_shared_memory_per_block",
refl::DefaultValue(32768))
+ .def_option<bool>("supports_subgroups", refl::DefaultValue(false))
+ .def_option<int64_t>("thread_warp_size", refl::DefaultValue(1))
+ .set_target_canonicalizer(UpdateWebGPUAttrs)
+ .set_default_keys({"webgpu", "gpu"});
tvm::codegen::intrin::RegisterWebGPUIntrinRules();
tvm::codegen::RegisterWebGPUCodegen();
}
diff --git a/src/target/target_kind.cc b/src/target/target_kind.cc
index 87da6875d1..93c66869dc 100644
--- a/src/target/target_kind.cc
+++ b/src/target/target_kind.cc
@@ -32,7 +32,6 @@
#include <algorithm>
-#include "../ir/attr_registry.h"
#include "../support/utils.h"
#include "./canonicalizer/llvm/canonicalize.h"
@@ -60,40 +59,57 @@ TVM_FFI_STATIC_INIT_BLOCK() {
}
/********** Registry-related code **********/
-using TargetKindRegistry = AttrRegistry<TargetKindRegEntry, TargetKind>;
-
-ffi::Array<ffi::String> TargetKindRegEntry::ListTargetKinds() {
- return TargetKindRegistry::Global()->ListAllNames();
+TargetKindRegistry* TargetKindRegistry::Global() {
+ static TargetKindRegistry registry;
+ return ®istry;
}
-ffi::Map<ffi::String, ffi::String> TargetKindRegEntry::ListTargetKindOptions(
- const TargetKind& target_kind) {
- ffi::Map<ffi::String, ffi::String> options;
- for (const auto& e : target_kind->schema_.ListOptions()) {
- options.Set(e.key, e.type_str);
+TargetKind TargetKindRegistry::RegisterOrGet(const ffi::String& name) {
+ if (auto it = kinds_.find(name); it != kinds_.end()) {
+ return (*it).second;
}
- return options;
+ TargetKind kind(ffi::make_object<TargetKindNode>());
+ kind->name = name;
+ kind->default_device_type = kDLCPU;
+ kind->schema_.def_option<ffi::String>("kind")
+ .def_option<ffi::Array<ffi::String>>("keys")
+ .def_option<ffi::String>("tag")
+ .def_option<ffi::String>("device")
+ .def_option<ffi::String>("model")
+ .def_option<ffi::Array<ffi::String>>("libs")
+ .def_option<Target>("host")
+ .def_option<int64_t>("from_device")
+ .def_option<int64_t>("target_device_type");
+ kinds_.Set(name, kind);
+ return kind;
}
-TargetKindRegEntry& TargetKindRegEntry::RegisterOrGet(const ffi::String&
target_kind_name) {
- return TargetKindRegistry::Global()->RegisterOrGet(target_kind_name);
+ffi::Optional<TargetKind> TargetKindRegistry::Get(const ffi::String& name) {
+ if (auto it = kinds_.find(name); it != kinds_.end()) {
+ return (*it).second;
+ }
+ return std::nullopt;
}
-void TargetKindRegEntry::UpdateAttr(const ffi::String& key, ffi::Any value,
int plevel) {
- TargetKindRegistry::Global()->UpdateAttr(key, kind_, value, plevel);
+ffi::Array<ffi::String> TargetKindRegistry::ListTargetKinds() {
+ ffi::Array<ffi::String> names;
+ for (const auto& entry : kinds_) {
+ names.push_back(entry.first);
+ }
+ return names;
}
-const AttrRegistryMapContainerMap<TargetKind>& TargetKind::GetAttrMapContainer(
- const ffi::String& attr_name) {
- return TargetKindRegistry::Global()->GetAttrMap(attr_name);
+ffi::Map<ffi::String, ffi::String> TargetKindRegistry::ListTargetKindOptions(
+ const TargetKind& target_kind) {
+ ffi::Map<ffi::String, ffi::String> options;
+ for (const auto& e : target_kind->schema_.ListOptions()) {
+ options.Set(e.key, e.type_str);
+ }
+ return options;
}
ffi::Optional<TargetKind> TargetKind::Get(const ffi::String& target_kind_name)
{
- const TargetKindRegEntry* reg =
TargetKindRegistry::Global()->Get(target_kind_name);
- if (reg == nullptr) {
- return std::nullopt;
- }
- return reg->kind_;
+ return TargetKindRegistry::Global()->Get(target_kind_name);
}
/*!
@@ -108,112 +124,112 @@ ffi::Map<ffi::String, ffi::Any>
TestTargetParser(ffi::Map<ffi::String, ffi::Any>
/********** Register Target kinds and attributes **********/
-TVM_REGISTER_TARGET_KIND("llvm", kDLCPU)
- .add_attr_option<ffi::Array<ffi::String>>("mattr")
- .add_attr_option<ffi::String>("mcpu")
- .add_attr_option<ffi::String>("mtriple")
- .add_attr_option<ffi::String>("mfloat-abi")
- .add_attr_option<ffi::String>("mabi")
- .add_attr_option<int64_t>("num-cores")
- // Fast math flags, see https://llvm.org/docs/LangRef.html#fast-math-flags
- .add_attr_option<bool>("fast-math") // implies all the below
- .add_attr_option<bool>("fast-math-nnan")
- .add_attr_option<bool>("fast-math-ninf")
- .add_attr_option<bool>("fast-math-nsz")
- .add_attr_option<bool>("fast-math-arcp")
- .add_attr_option<bool>("fast-math-contract")
- .add_attr_option<bool>("fast-math-reassoc")
- .add_attr_option<int64_t>("opt-level")
- // LLVM command line flags, see below
- .add_attr_option<ffi::Array<ffi::String>>("cl-opt")
- // LLVM JIT engine mcjit/orcjit
- .add_attr_option<ffi::String>("jit")
- // TVM & LLVM custom vector bit width
- .add_attr_option<int64_t>("vector-width")
- .set_default_keys({"cpu"})
- // Force the external codegen kind attribute to be registered, even if no
external
- // codegen targets are enabled by the TVM build.
- .set_target_canonicalizer(tvm::target::canonicalizer::llvm::Canonicalize);
-
-// Note regarding the "cl-opt" attribute:
-// Each string in the array has the format
-// -optionname[[:type]=value]
-// where
-// * optionname is the actual LLVM option (e.g. "unroll-threshold")
-// * type is one of "bool", "int", "uint", or "string"
-// * value is the corresponding option value (for "bool" type is can be 0 or
"false"
-// for false value, or 1 or "true" for true value)
-// If type is omitted, it is assumed to be "bool". If value is omitted, it is
assumed
-// to be "true".
-//
-// The type must match the option type in LLVM. To find the type, search the
LLVM
-// repository (https://github.com/llvm/llvm-project) for optionname, and look
for
-// its definition: it will be a declaration of a variable of type cl::opt<T>
with
-// optionname being an argument to the constructor. The T in the declaration is
-// the type.
-// For example, for unroll-threshold, we get the following declaration:
-// static cl::opt<unsigned>
-// UnrollThreshold("unroll-threshold", cl::Hidden,
-// cl::desc("The cost threshold for loop unrolling"));
-// Hence the type is "uint".
-
-TVM_REGISTER_TARGET_KIND("c", kDLCPU)
- .add_attr_option<ffi::String>("mcpu")
- .add_attr_option<ffi::String>("march")
- .add_attr_option<int64_t>("workspace-byte-alignment")
- .add_attr_option<int64_t>("constants-byte-alignment")
- .set_default_keys({"cpu"})
- .set_target_canonicalizer(tvm::target::canonicalizer::llvm::Canonicalize);
-
-TVM_REGISTER_TARGET_KIND("ext_dev", kDLExtDev);
-
-TVM_REGISTER_TARGET_KIND("composite", kDLCPU) // line break
- .add_attr_option<ffi::Array<Target>>(
- "devices",
-
ir::ConfigSchema::AttrValidator(ffi::TypedFunction<ffi::Any(ffi::Any)>( //
- [](ffi::Any val) -> ffi::Any {
- // Allow elements to be strings or dicts, converting them to
Target objects.
- if (val.try_cast<ffi::Array<Target>>().has_value()) return val;
- auto arr = val.cast<ffi::Array<ffi::Any>>();
- ffi::Array<Target> result;
- for (const auto& elem : arr) {
- if (auto t = elem.try_cast<Target>()) {
- result.push_back(t.value());
- } else if (auto s = elem.try_cast<ffi::String>()) {
- result.push_back(Target(s.value()));
- } else if (auto m = elem.try_cast<ffi::Map<ffi::String,
ffi::Any>>()) {
- result.push_back(Target(m.value()));
- } else {
- TVM_FFI_THROW(TypeError)
- << "Expected Target, string, or dict in 'devices' array,
got '"
- << elem.GetTypeKey() << "'";
+TVM_FFI_STATIC_INIT_BLOCK() {
+ TargetKindDef("llvm")
+ .set_default_device_type(kDLCPU)
+ .def_option<ffi::Array<ffi::String>>("mattr")
+ .def_option<ffi::String>("mcpu")
+ .def_option<ffi::String>("mtriple")
+ .def_option<ffi::String>("mfloat-abi")
+ .def_option<ffi::String>("mabi")
+ .def_option<int64_t>("num-cores")
+ // Fast math flags, see
https://llvm.org/docs/LangRef.html#fast-math-flags
+ .def_option<bool>("fast-math") // implies all the below
+ .def_option<bool>("fast-math-nnan")
+ .def_option<bool>("fast-math-ninf")
+ .def_option<bool>("fast-math-nsz")
+ .def_option<bool>("fast-math-arcp")
+ .def_option<bool>("fast-math-contract")
+ .def_option<bool>("fast-math-reassoc")
+ .def_option<int64_t>("opt-level")
+ // LLVM command line flags, see below
+ .def_option<ffi::Array<ffi::String>>("cl-opt")
+ // LLVM JIT engine mcjit/orcjit
+ .def_option<ffi::String>("jit")
+ // TVM & LLVM custom vector bit width
+ .def_option<int64_t>("vector-width")
+ .set_default_keys({"cpu"})
+ // Force the external codegen kind attribute to be registered, even if
no external
+ // codegen targets are enabled by the TVM build.
+
.set_target_canonicalizer(tvm::target::canonicalizer::llvm::Canonicalize);
+
+ // Note regarding the "cl-opt" attribute:
+ // Each string in the array has the format
+ // -optionname[[:type]=value]
+ // where
+ // * optionname is the actual LLVM option (e.g. "unroll-threshold")
+ // * type is one of "bool", "int", "uint", or "string"
+ // * value is the corresponding option value (for "bool" type is can be 0
or "false"
+ // for false value, or 1 or "true" for true value)
+ // If type is omitted, it is assumed to be "bool". If value is omitted, it
is assumed
+ // to be "true".
+ //
+ // The type must match the option type in LLVM. To find the type, search the
LLVM
+ // repository (https://github.com/llvm/llvm-project) for optionname, and
look for
+ // its definition: it will be a declaration of a variable of type cl::opt<T>
with
+ // optionname being an argument to the constructor. The T in the declaration
is
+ // the type.
+ // For example, for unroll-threshold, we get the following declaration:
+ // static cl::opt<unsigned>
+ // UnrollThreshold("unroll-threshold", cl::Hidden,
+ // cl::desc("The cost threshold for loop unrolling"));
+ // Hence the type is "uint".
+
+ TargetKindDef("c")
+ .set_default_device_type(kDLCPU)
+ .def_option<ffi::String>("mcpu")
+ .def_option<ffi::String>("march")
+ .def_option<int64_t>("workspace-byte-alignment")
+ .def_option<int64_t>("constants-byte-alignment")
+ .set_default_keys({"cpu"})
+
.set_target_canonicalizer(tvm::target::canonicalizer::llvm::Canonicalize);
+
+ TargetKindDef("ext_dev") // line break
+ .set_default_device_type(kDLExtDev);
+
+ TargetKindDef("composite")
+ .set_default_device_type(kDLCPU) // line break
+ .def_option<ffi::Array<Target>>(
+ "devices",
+
ir::ConfigSchema::AttrValidator(ffi::TypedFunction<ffi::Any(ffi::Any)>( //
+ [](ffi::Any val) -> ffi::Any {
+ // Allow elements to be strings or dicts, converting them to
Target objects.
+ if (val.try_cast<ffi::Array<Target>>().has_value()) return val;
+ auto arr = val.cast<ffi::Array<ffi::Any>>();
+ ffi::Array<Target> result;
+ for (const auto& elem : arr) {
+ if (auto t = elem.try_cast<Target>()) {
+ result.push_back(t.value());
+ } else if (auto s = elem.try_cast<ffi::String>()) {
+ result.push_back(Target(s.value()));
+ } else if (auto m = elem.try_cast<ffi::Map<ffi::String,
ffi::Any>>()) {
+ result.push_back(Target(m.value()));
+ } else {
+ TVM_FFI_THROW(TypeError)
+ << "Expected Target, string, or dict in 'devices'
array, got '"
+ << elem.GetTypeKey() << "'";
+ }
}
- }
- return ffi::Any(result);
- })));
+ return ffi::Any(result);
+ })));
-TVM_REGISTER_TARGET_KIND("test", kDLCPU) // line break
- .set_target_canonicalizer(TestTargetParser);
+ TargetKindDef("test")
+ .set_default_device_type(kDLCPU) // line break
+ .set_target_canonicalizer(TestTargetParser);
+}
/********** Registry **********/
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
refl::GlobalDef()
- .def("target.TargetKindGetAttr",
- [](TargetKind kind, ffi::String attr_name) -> ffi::Any {
- auto target_attr_map =
TargetKind::GetAttrMap<ffi::Any>(attr_name);
- ffi::Any rv;
- if (target_attr_map.count(kind)) {
- rv = target_attr_map[kind];
- }
- return rv;
- })
- .def("target.ListTargetKinds", TargetKindRegEntry::ListTargetKinds)
- .def("target.ListTargetKindOptions",
TargetKindRegEntry::ListTargetKindOptions)
+ .def("target.ListTargetKinds", [] { return
TargetKindRegistry::Global()->ListTargetKinds(); })
+ .def(
+ "target.ListTargetKindOptions",
+ [](TargetKind kind) { return
TargetKindRegistry::Global()->ListTargetKindOptions(kind); })
.def("target.ListTargetKindOptionsFromName", [](ffi::String
target_kind_name) {
TargetKind kind = TargetKind::Get(target_kind_name).value();
- return TargetKindRegEntry::ListTargetKindOptions(kind);
+ return TargetKindRegistry::Global()->ListTargetKindOptions(kind);
});
}
diff --git a/tests/cpp/target_test.cc b/tests/cpp/target_test.cc
index a536d1ca58..0bf728425f 100644
--- a/tests/cpp/target_test.cc
+++ b/tests/cpp/target_test.cc
@@ -27,11 +27,13 @@
using namespace tvm;
-TVM_REGISTER_TARGET_KIND("TestTargetKind", kDLCPU)
- .set_attr<std::string>("Attr1", "Value1")
- .add_attr_option<bool>("my_bool")
- .add_attr_option<ffi::Array<ffi::String>>("your_names")
- .add_attr_option<ffi::Map<ffi::String, int64_t>>("her_maps");
+TVM_FFI_STATIC_INIT_BLOCK() {
+ TargetKindDef("TestTargetKind")
+ .set_default_device_type(kDLCPU)
+ .def_option<bool>("my_bool")
+ .def_option<ffi::Array<ffi::String>>("your_names")
+ .def_option<ffi::Map<ffi::String, int64_t>>("her_maps");
+}
ffi::Map<ffi::String, ffi::Any> TestTargetParser(ffi::Map<ffi::String,
ffi::Any> target) {
ffi::String mcpu = target.at("mcpu").as_or_throw<ffi::String>();
@@ -46,28 +48,26 @@ ffi::Map<ffi::String, ffi::Any>
TestAttrsPreProcessor(ffi::Map<ffi::String, ffi:
return attrs;
}
-TVM_REGISTER_TARGET_KIND("TestTargetParser", kDLCPU)
- .add_attr_option<ffi::String>("mattr")
- .add_attr_option<ffi::String>("mcpu")
- .set_default_keys({"cpu"})
- .set_target_canonicalizer(TestTargetParser);
-
-TVM_REGISTER_TARGET_KIND("TestAttrsPreprocessor", kDLCPU)
- .add_attr_option<ffi::String>("mattr")
- .set_default_keys({"cpu"})
- .set_target_canonicalizer(TestAttrsPreProcessor);
-
-TVM_REGISTER_TARGET_KIND("TestClashingPreprocessor", kDLCPU)
- .add_attr_option<ffi::String>("mattr")
- .add_attr_option<ffi::String>("mcpu")
- .set_default_keys({"cpu"})
- .set_target_canonicalizer(TestTargetParser);
-
-TEST(TargetKind, GetAttrMap) {
- auto map = tvm::TargetKind::GetAttrMap<std::string>("Attr1");
- auto target_kind = tvm::TargetKind::Get("TestTargetKind").value();
- std::string result = map[target_kind];
- TVM_FFI_ICHECK_EQ(result, "Value1");
+TVM_FFI_STATIC_INIT_BLOCK() {
+ TargetKindDef("TestTargetParser")
+ .set_default_device_type(kDLCPU)
+ .def_option<ffi::String>("mattr")
+ .def_option<ffi::String>("mcpu")
+ .set_default_keys({"cpu"})
+ .set_target_canonicalizer(TestTargetParser);
+
+ TargetKindDef("TestAttrsPreprocessor")
+ .set_default_device_type(kDLCPU)
+ .def_option<ffi::String>("mattr")
+ .set_default_keys({"cpu"})
+ .set_target_canonicalizer(TestAttrsPreProcessor);
+
+ TargetKindDef("TestClashingPreprocessor")
+ .set_default_device_type(kDLCPU)
+ .def_option<ffi::String>("mattr")
+ .def_option<ffi::String>("mcpu")
+ .set_default_keys({"cpu"})
+ .set_target_canonicalizer(TestTargetParser);
}
TEST(TargetCreation, NestedConfig) {
@@ -277,11 +277,14 @@ TEST(TargetCreationFail, UnknownNonFeatureKeyStillFails) {
ASSERT_THROW({ Target{config}; }, tvm::ffi::Error);
}
-TVM_REGISTER_TARGET_KIND("TestStringKind", kDLCPU)
- .add_attr_option<ffi::String>("single")
- .add_attr_option<ffi::Array<ffi::String>>("array")
- .add_attr_option<ffi::Array<ffi::Array<ffi::String>>>("nested-array")
-
.add_attr_option<ffi::Array<ffi::Array<ffi::Array<ffi::String>>>>("nested2-array");
+TVM_FFI_STATIC_INIT_BLOCK() {
+ TargetKindDef("TestStringKind")
+ .set_default_device_type(kDLCPU)
+ .def_option<ffi::String>("single")
+ .def_option<ffi::Array<ffi::String>>("array")
+ .def_option<ffi::Array<ffi::Array<ffi::String>>>("nested-array")
+
.def_option<ffi::Array<ffi::Array<ffi::Array<ffi::String>>>>("nested2-array");
+}
TEST(TargetCreation, ProcessStrings) {
// Test single string attribute
@@ -384,13 +387,14 @@ TEST(TargetCreation, DeduplicateKeys) {
}
TEST(TargetKindRegistry, ListTargetKinds) {
- ffi::Array<ffi::String> names = TargetKindRegEntry::ListTargetKinds();
+ ffi::Array<ffi::String> names =
TargetKindRegistry::Global()->ListTargetKinds();
TVM_FFI_ICHECK_EQ(names.empty(), false);
TVM_FFI_ICHECK_EQ(std::count(std::begin(names), std::end(names), "llvm"), 1);
}
TEST(TargetKindRegistry, ListTargetOptions) {
TargetKind llvm = TargetKind::Get("llvm").value();
- ffi::Map<ffi::String, ffi::String> attrs =
TargetKindRegEntry::ListTargetKindOptions(llvm);
+ ffi::Map<ffi::String, ffi::String> attrs =
+ TargetKindRegistry::Global()->ListTargetKindOptions(llvm);
TVM_FFI_ICHECK_EQ(attrs.empty(), false);
}