tvm
Loading...
Searching...
No Matches
config_schema.h
Go to the documentation of this file.
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
27#ifndef TVM_TARGET_CONFIG_SCHEMA_H_
28#define TVM_TARGET_CONFIG_SCHEMA_H_
29
30#include <tvm/ffi/container/map.h>
31#include <tvm/ffi/function.h>
32#include <tvm/ffi/reflection/registry.h>
33
34#include <sstream>
35#include <string>
36#include <type_traits>
37#include <unordered_map>
38#include <utility>
39#include <vector>
40
41namespace tvm {
42
53 public:
54 using ConfigMap = ffi::Map<ffi::String, ffi::Any>;
55 using Canonicalizer = ffi::TypedFunction<ConfigMap(ConfigMap)>;
56
58 struct OptionEntry {
60 ffi::String key;
62 ffi::String type_str;
64 ffi::TypedFunction<ffi::Any(ffi::Any)> validator;
66 bool has_default = false;
70 ffi::Any default_value;
71 };
72
85 template <typename T, typename... Traits>
86 ConfigSchema& def_option(const ffi::String& key, Traits&&... traits) {
87 std::string skey(key);
88 if (key_to_index_.count(skey)) {
89 TVM_FFI_THROW(ValueError) << "Duplicate config option key: '" << key << "'";
90 }
91 key_to_index_[skey] = options_.size();
92 options_.push_back(MakeEntry<T>(key, std::forward<Traits>(traits)...));
93 return *this;
94 }
95
97 void set_canonicalizer(Canonicalizer f) { canonicalizer_ = std::move(f); }
98
101 ffi::TypedFunction<ffi::Any(ffi::Any)> func;
102 explicit AttrValidator(ffi::TypedFunction<ffi::Any(ffi::Any)> f) : func(std::move(f)) {}
103 };
104
106 void set_error_on_unknown(bool value) { error_on_unknown_ = value; }
107
122 ConfigMap result;
123
124 // Step 1: validate/coerce and materialize options in declaration order
125 for (const auto& e : options_) {
126 auto it = config.find(e.key);
127 if (it != config.end()) {
128 result.Set(e.key, e.validator((*it).second));
129 } else if (e.has_default) {
130 if (e.default_from_factory) {
131 result.Set(e.key, e.default_value.cast<ffi::Function>()());
132 } else {
133 result.Set(e.key, e.default_value);
134 }
135 }
136 // else: missing non-required option, stays absent
137 }
138
139 // Step 2: unknown-key policy
140 if (error_on_unknown_) {
141 for (const auto& kv : config) {
142 if (!key_to_index_.count(std::string(kv.first))) {
143 std::ostringstream os;
144 os << "Unknown config option '" << kv.first << "'. Known options: ";
145 bool first = true;
146 for (const auto& e : options_) {
147 if (!first) os << ", ";
148 os << "'" << e.key << "'";
149 first = false;
150 }
151 TVM_FFI_THROW(ValueError) << os.str();
152 }
153 }
154 }
155
156 // Step 3: whole-object canonicalization (last)
157 if (canonicalizer_ != nullptr) {
158 result = canonicalizer_(result);
159 }
160
161 return result;
162 }
163
168 const std::vector<OptionEntry>& ListOptions() const { return options_; }
169
171 bool HasOption(const ffi::String& key) const { return key_to_index_.count(std::string(key)) > 0; }
172
173 private:
174 template <typename T>
175 static ffi::TypedFunction<ffi::Any(ffi::Any)> MakeValidator(const ffi::String& key) {
176 return ffi::TypedFunction<ffi::Any(ffi::Any)>([key](ffi::Any val) -> ffi::Any {
177 auto opt = val.try_cast<T>();
178 if (!opt.has_value()) {
179 TVM_FFI_THROW(TypeError) << "Option '" << key << "': expected type '"
180 << ffi::TypeTraits<T>::TypeStr() << "' but got '"
181 << val.GetTypeKey() << "'";
182 }
183 return ffi::Any(opt.value());
184 });
185 }
186
187 template <typename Trait>
188 static void ApplyTrait(OptionEntry* entry, ffi::reflection::FieldInfoBuilder* info,
189 Trait&& trait) {
190 using T = std::decay_t<Trait>;
191 if constexpr (std::is_same_v<T, AttrValidator>) {
192 entry->validator = std::move(trait.func);
193 } else if constexpr (std::is_base_of_v<ffi::reflection::InfoTrait, T>) {
194 trait.Apply(info);
195 } else if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, char*>) {
196 const char* doc = trait;
197 if (doc != nullptr && doc[0] != '\0') {
198 info->doc = TVMFFIByteArray{doc, std::char_traits<char>::length(doc)};
199 }
200 }
201 }
202
203 template <typename T, typename... Traits>
204 OptionEntry MakeEntry(const ffi::String& key, Traits&&... traits) {
205 OptionEntry e;
206 e.key = key;
207 e.type_str = ffi::String(ffi::TypeTraits<T>::TypeStr());
208 e.validator = MakeValidator<T>(key);
209 // Apply traits through a temporary FieldInfoBuilder so existing
210 // reflection traits (notably refl::DefaultValue) are reused unchanged.
211 ffi::reflection::FieldInfoBuilder info{};
212 info.flags = 0;
213 info.default_value_or_factory = ffi::AnyView(nullptr).CopyToTVMFFIAny();
214 info.doc = TVMFFIByteArray{nullptr, 0};
215 (ApplyTrait(&e, &info, std::forward<Traits>(traits)), ...);
216 if (info.flags & kTVMFFIFieldFlagBitMaskHasDefault) {
217 e.has_default = true;
218 e.default_from_factory = (info.flags & kTVMFFIFieldFlagBitMaskDefaultFromFactory) != 0;
219 e.default_value = ffi::AnyView::CopyFromTVMFFIAny(info.default_value_or_factory);
220 // Release the extra ref created by CopyToTVMFFIAny in Apply
221 if (info.default_value_or_factory.type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin) {
222 ffi::details::ObjectUnsafe::DecRefObjectHandle(info.default_value_or_factory.v_obj);
223 }
224 }
225 return e;
226 }
227
229 std::vector<OptionEntry> options_;
231 std::unordered_map<std::string, size_t> key_to_index_;
233 Canonicalizer canonicalizer_{nullptr};
235 bool error_on_unknown_ = true;
236};
237
238} // namespace tvm
239
240#endif // TVM_TARGET_CONFIG_SCHEMA_H_
Dynamic config schema for map-like options.
Definition config_schema.h:52
bool HasOption(const ffi::String &key) const
Check if an option with the given key exists.
Definition config_schema.h:171
const std::vector< OptionEntry > & ListOptions() const
List declared options in declaration order.
Definition config_schema.h:168
void set_error_on_unknown(bool value)
Set whether unknown keys trigger an error.
Definition config_schema.h:106
void set_canonicalizer(Canonicalizer f)
Set whole-object canonicalizer.
Definition config_schema.h:97
ConfigMap Resolve(ConfigMap config) const
Default/validate, then canonicalize a config object.
Definition config_schema.h:121
ConfigSchema & def_option(const ffi::String &key, Traits &&... traits)
Declare a typed option.
Definition config_schema.h:86
ffi::Map< ffi::String, ffi::Any > ConfigMap
Definition config_schema.h:54
ffi::TypedFunction< ConfigMap(ConfigMap)> Canonicalizer
Definition config_schema.h:55
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition attr.h:23
Trait to set a custom validator for a config option.
Definition config_schema.h:100
AttrValidator(ffi::TypedFunction< ffi::Any(ffi::Any)> f)
Definition config_schema.h:102
ffi::TypedFunction< ffi::Any(ffi::Any)> func
Definition config_schema.h:101
Schema entry for one declared option.
Definition config_schema.h:58
ffi::String type_str
Type string for this option.
Definition config_schema.h:62
bool has_default
Whether this option has a default value or factory.
Definition config_schema.h:66
ffi::Any default_value
Default value, or factory function () -> Any when default_from_factory is true.
Definition config_schema.h:70
ffi::String key
Option key.
Definition config_schema.h:60
bool default_from_factory
Whether the default is produced by a factory function.
Definition config_schema.h:68
ffi::TypedFunction< ffi::Any(ffi::Any)> validator
Per-option validator/coercer (Any -> Any).
Definition config_schema.h:64