203struct SignatureTrait {
205 static constexpr size_t kArgsCount = 0;
207 static constexpr size_t kTyArgsCount = 0;
209 static constexpr size_t kVarArgsCount = 0;
211 static constexpr size_t kVarTyArgsCount = 0;
213 static constexpr size_t kCallAttrsCount = 0;
217struct ValidateState {
223 size_t args_index = 0;
225 size_t ty_args_index = 0;
232 size_t index, ffi::AnyView actual) {
233 const auto& fixed = type_arg ? state->op->ty_args_info : state->op->args_info;
234 const auto& tail = type_arg ? state->op->var_ty_args_info : state->op->var_args_info;
236 if (index < fixed.size()) {
237 name = fixed[index]->name;
238 }
else if (tail.has_value()) {
239 name = tail.value()->name;
241 std::string name_clause = name.empty() ?
"" :
" (`" + name +
"`)";
242 TVMFFIAny raw = actual.CopyToTVMFFIAny();
243 *out = TVM_FFI_UNEXPECTED(TypeError)
244 <<
"Op `" << state->op->name <<
"`: `" << (type_arg ?
"Call.ty_args[" :
"Call.args[")
245 << index <<
"]`" << name_clause <<
" expected `" << ffi::TypeTraits<T>::TypeStr()
246 <<
"`, got `" << ffi::TypeTraits<T>::GetMismatchTypeInfo(&raw) <<
"`.";
254template <
typename T = Expr>
255struct arg : SignatureTrait {
256 static_assert(std::is_base_of_v<Expr, T>,
"arg<T> expects an expression view");
258 static constexpr size_t kArgsCount = 1;
264 explicit arg(ffi::String name, ffi::String doc =
"")
265 : name(std::move(name)), doc(std::move(doc)) {}
267 void CollectMetadata(OpNode* op)
const {
268 auto info = ffi::make_object<ArgumentInfoObj>();
271 op->args_info.push_back(ArgumentInfo(ffi::UnsafeInit{}, std::move(info)));
274 static bool Validate(ValidateState* state, ffi::Expected<void>* out) {
275 if constexpr (!std::is_same_v<T, Expr>) {
276 ffi::AnyView value(state->call->args.GetArrayObj()->begin()[state->args_index]);
277 if (TVM_FFI_PREDICT_FALSE(value ==
nullptr ||
278 !ffi::details::AnyUnsafe::CheckAnyViewStrict<T>(value))) {
279 return details::ReportTypeMismatch<T>(out, state,
false, state->args_index, value);
289template <
typename T = Expr>
290struct var_args : SignatureTrait {
291 static_assert(std::is_base_of_v<Expr, T>,
"var_args<T> expects an expression view");
293 static constexpr size_t kVarArgsCount = 1;
299 explicit var_args(ffi::String name, ffi::String doc =
"")
300 : name(std::move(name)), doc(std::move(doc)) {}
302 void CollectMetadata(OpNode* op)
const {
303 auto info = ffi::make_object<ArgumentInfoObj>();
306 op->var_args_info = ArgumentInfo(ffi::UnsafeInit{}, std::move(info));
309 static bool Validate(ValidateState* state, ffi::Expected<void>* out) {
310 if constexpr (!std::is_same_v<T, Expr>) {
311 const ffi::Any* values = state->call->args.GetArrayObj()->begin();
312 for (; state->args_index != state->call->args.size(); ++state->args_index) {
313 ffi::AnyView value(values[state->args_index]);
314 if (TVM_FFI_PREDICT_FALSE(value ==
nullptr ||
315 !ffi::details::AnyUnsafe::CheckAnyViewStrict<T>(value))) {
316 return details::ReportTypeMismatch<T>(out, state,
false, state->args_index, value);
320 state->args_index = state->call->args.size();
328template <
typename T = Type>
329struct ty_arg : SignatureTrait {
330 static_assert(std::is_base_of_v<Type, T>,
"ty_arg<T> expects a type view");
332 static constexpr size_t kTyArgsCount = 1;
338 explicit ty_arg(ffi::String name, ffi::String doc =
"")
339 : name(std::move(name)), doc(std::move(doc)) {}
341 void CollectMetadata(OpNode* op)
const {
342 auto info = ffi::make_object<ArgumentInfoObj>();
345 op->ty_args_info.push_back(ArgumentInfo(ffi::UnsafeInit{}, std::move(info)));
348 static bool Validate(ValidateState* state, ffi::Expected<void>* out) {
349 if constexpr (!std::is_same_v<T, Type>) {
350 ffi::AnyView value(state->call->ty_args.GetArrayObj()->begin()[state->ty_args_index]);
351 if (TVM_FFI_PREDICT_FALSE(value ==
nullptr ||
352 !ffi::details::AnyUnsafe::CheckAnyViewStrict<T>(value))) {
353 return details::ReportTypeMismatch<T>(out, state,
true, state->ty_args_index, value);
356 ++state->ty_args_index;
363template <
typename T = Type>
364struct var_ty_args : SignatureTrait {
365 static_assert(std::is_base_of_v<Type, T>,
"var_ty_args<T> expects a type view");
367 static constexpr size_t kVarTyArgsCount = 1;
373 explicit var_ty_args(ffi::String name, ffi::String doc =
"")
374 : name(std::move(name)), doc(std::move(doc)) {}
376 void CollectMetadata(OpNode* op)
const {
377 auto info = ffi::make_object<ArgumentInfoObj>();
380 op->var_ty_args_info = ArgumentInfo(ffi::UnsafeInit{}, std::move(info));
383 static bool Validate(ValidateState* state, ffi::Expected<void>* out) {
384 if constexpr (!std::is_same_v<T, Type>) {
385 const ffi::Any* values = state->call->ty_args.GetArrayObj()->begin();
386 for (; state->ty_args_index != state->call->ty_args.size(); ++state->ty_args_index) {
387 ffi::AnyView value(values[state->ty_args_index]);
388 if (TVM_FFI_PREDICT_FALSE(value ==
nullptr ||
389 !ffi::details::AnyUnsafe::CheckAnyViewStrict<T>(value))) {
390 return details::ReportTypeMismatch<T>(out, state,
true, state->ty_args_index, value);
394 state->ty_args_index = state->call->ty_args.size();
409struct call_attrs : SignatureTrait {
410 static_assert(std::is_base_of_v<AttrsNode, T>,
"call_attrs<T> expects an attribute node type");
412 static constexpr size_t kCallAttrsCount = 1;
414 void CollectMetadata(OpNode* op)
const {
415 uint32_t index = T::RuntimeTypeIndex();
416 op->attrs_type_key = T::_type_key;
417 op->attrs_type_index = index;
420 static bool Validate(ValidateState* state, ffi::Expected<void>* out) {
421 ffi::AnyView attrs(state->call->attrs);
422 if (TVM_FFI_PREDICT_FALSE(!state->call->attrs.has_value() ||
423 !ffi::details::AnyUnsafe::CheckAnyViewStrict<const T*>(attrs))) {
424 TVMFFIAny raw = attrs.CopyToTVMFFIAny();
425 std::string actual = state->call->attrs.has_value()
426 ?
"`" + ffi::TypeTraits<const T*>::GetMismatchTypeInfo(&raw) +
"`"
428 *out = TVM_FFI_UNEXPECTED(TypeError)
429 <<
"Op `" << state->op->name <<
"`: Call.attrs expected `"
430 << ffi::TypeTraits<const T*>::TypeStr() <<
"`, got " << actual;
471 template <
typename AttrsType>
473 uint32_t index = AttrsType::RuntimeTypeIndex();
513 template <
typename... Specs>
515 auto updated = ffi::make_object<OpNode>();
516 (ApplySignatureTrait(updated.get(), specs), ...);
517 if (op_->validator ==
nullptr) {
518 using View = ffi::reflection::NativeFunctionView<void(
const CallNode*)>;
519 set_validator(View::FromNative<&ValidateSignature<Specs...>>());
523 target->
args_info = std::move(updated->args_info);
524 target->
ty_args_info = std::move(updated->ty_args_info);
539 template <
typename ValueType>
540 OpDef&
set_attr(
const ffi::String& attr_name,
const ValueType& value,
bool override =
false) {
541 UpdateAttr(attr_name, ffi::Any(value),
override);
564 bool override =
false) {
565 TVM_FFI_CHECK(
override || op_->validator ==
nullptr, ValueError)
566 <<
"Validator of " << op_->name <<
" is already registered";
567 get()->
validator = ffi::reflection::NativeFunction<void(
const CallNode*)>::From(validator);
579 template <
typename Spec>
580 static void ApplySignatureTrait(
OpNode*
op,
const Spec& spec) {
581 static_assert(std::is_base_of_v<sig::SignatureTrait, Spec>,
"Unknown signature descriptor");
582 spec.CollectMetadata(
op);
585 template <
typename... Specs>
586 TVM_FFI_INLINE
static ffi::Expected<void> ValidateSignature(
const CallNode* call)
noexcept {
587 static_assert((std::is_base_of_v<sig::SignatureTrait, Specs> && ...),
588 "Unknown signature descriptor");
589 constexpr size_t n_args = (
size_t{0} + ... + Specs::kArgsCount);
590 constexpr size_t n_ty_args = (
size_t{0} + ... + Specs::kTyArgsCount);
591 constexpr size_t n_var_args = (
size_t{0} + ... + Specs::kVarArgsCount);
592 constexpr size_t n_var_ty_args = (
size_t{0} + ... + Specs::kVarTyArgsCount);
593 constexpr size_t n_attrs = (
size_t{0} + ... + Specs::kCallAttrsCount);
594 static_assert(n_var_args <= 1 && n_var_ty_args <= 1 && n_attrs <= 1,
595 "Duplicate signature tail or call_attrs");
596 const OpNode*
op = call ? call->op.as<OpNode>() : nullptr;
597 if (TVM_FFI_PREDICT_FALSE(!
op)) {
598 return TVM_FFI_UNEXPECTED(TypeError) <<
"Invalid Op Call";
600 if (TVM_FFI_PREDICT_FALSE(!call->args.defined() || !call->ty_args.defined())) {
601 return TVM_FFI_UNEXPECTED(TypeError) <<
"Op `" <<
op->name <<
"`: invalid Call";
603 ffi::Expected<void> result;
605 if (TVM_FFI_PREDICT_FALSE(n_var_args ? call->args.size() < n_args
606 : call->args.size() != n_args)) {
607 *out = TVM_FFI_UNEXPECTED(TypeError)
608 <<
"Op `" <<
op->name <<
"`: Call.args expected " << (n_var_args ?
"at least " :
"")
609 << n_args << (n_args == 1 ?
" argument" :
" arguments") <<
", got "
610 << call->args.size();
613 if (TVM_FFI_PREDICT_FALSE(n_var_ty_args ? call->ty_args.size() < n_ty_args
614 : call->ty_args.size() != n_ty_args)) {
615 *out = TVM_FFI_UNEXPECTED(TypeError)
616 <<
"Op `" <<
op->name <<
"`: Call.ty_args expected "
617 << (n_var_ty_args ?
"at least " :
"") << n_ty_args
618 << (n_ty_args == 1 ?
" type argument" :
" type arguments") <<
", got "
619 << call->ty_args.size();
622 if constexpr (
sizeof...(Specs) != 0) {
623 sig::ValidateState state{call,
op};
624 if (TVM_FFI_PREDICT_FALSE(!(Specs::Validate(&state, out) && ...))) {
631 OpNode* get() {
return const_cast<OpNode*
>(op_.operator->()); }
632 TVM_TIRX_DLL void UpdateAttr(
const ffi::String& attr_name, ffi::Any value,
bool override);