blob: 560cee6c9d8943ccf6949a2b920a784e164201f1 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*!
* \file src/ir/op.cc
* \brief Primitive operators and intrinsics.
*/
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/op.h>
#include <tvm/ir/type.h>
#include <tvm/tirx/op_attr_types.h>
#include <memory>
#include "attr_registry.h"
namespace tvm {
TVM_FFI_STATIC_INIT_BLOCK() {
ArgumentInfoNode::RegisterReflection();
OpNode::RegisterReflection();
}
using ffi::Any;
using ffi::Function;
using ffi::PackedArgs;
using tirx::FLowerIntrinsic;
using OpRegistry = AttrRegistry<OpRegEntry, Op>;
// find operator by name
const Op& Op::Get(const ffi::String& name) {
const OpRegEntry* reg = OpRegistry::Global()->Get(name);
TVM_FFI_CHECK(reg != nullptr, AttributeError) << "Operator " << name << " is not registered";
return reg->op();
}
Op OpRegEntry::MakeOp(uint32_t reg_index) {
ffi::ObjectPtr<OpNode> n = ffi::make_object<OpNode>();
n->index_ = reg_index;
return Op(n);
}
OpRegEntry::OpRegEntry(uint32_t reg_index) : op_(MakeOp(reg_index)) {}
OpRegEntry& OpRegEntry::RegisterOrGet(const ffi::String& name) {
return OpRegistry::Global()->RegisterOrGet(name);
}
// Get attribute map by key
const AttrRegistryMapContainerMap<Op>& Op::GetAttrMapContainer(const ffi::String& attr_name) {
return OpRegistry::Global()->GetAttrMap(attr_name);
}
// Check if a key is present in the registry.
bool Op::HasAttrMap(const ffi::String& attr_name) {
return OpRegistry::Global()->HasAttrMap(attr_name);
}
// Resets attr of the OpAttrMap.
void OpRegEntry::reset_attr(const std::string& attr_name) {
OpRegistry::Global()->ResetAttr(attr_name, op_);
}
void OpRegEntry::UpdateAttr(const ffi::String& key, ffi::Any value, int plevel) {
OpRegistry::Global()->UpdateAttr(key, op_, value, plevel);
}
// Frontend APIs
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
refl::GlobalDef()
.def("ir.ListOpNames", []() { return OpRegistry::Global()->ListAllNames(); })
.def("ir.GetOp", [](ffi::String name) -> Op { return Op::Get(name); })
.def("ir.OpGetAttr",
[](Op op, ffi::String attr_name) -> ffi::Any {
auto op_map = Op::GetAttrMap<ffi::Any>(attr_name);
ffi::Any rv;
if (op_map.count(op)) {
rv = op_map[op];
}
return rv;
})
.def("ir.OpHasAttr",
[](Op op, ffi::String attr_name) -> bool { return Op::HasAttrMap(attr_name); })
.def("ir.OpSetAttr",
[](Op op, ffi::String attr_name, ffi::AnyView value, int plevel) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op->name).set_name();
reg.set_attr(attr_name, value, plevel);
})
.def("ir.OpResetAttr",
[](Op op, ffi::String attr_name) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op->name);
reg.reset_attr(attr_name);
})
.def("ir.RegisterOp",
[](ffi::String op_name, ffi::String descr) {
const OpRegEntry* reg = OpRegistry::Global()->Get(op_name);
TVM_FFI_CHECK(reg == nullptr, AttributeError)
<< "Operator " << op_name << " is registered before";
auto& op = OpRegistry::Global()->RegisterOrGet(op_name).set_name();
op.describe(descr);
})
.def("ir.OpAddArgument",
[](Op op, ffi::String name, ffi::String type, ffi::String description) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op->name).set_name();
reg.add_argument(name, type, description);
})
.def("ir.OpSetSupportLevel",
[](Op op, int level) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op->name).set_name();
reg.set_support_level(level);
})
.def("ir.OpSetNumInputs",
[](Op op, int n) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op->name).set_name();
reg.set_num_inputs(n);
})
.def("ir.OpSetAttrsTypeKey",
[](Op op, ffi::String key) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op->name).set_name();
reg.set_attrs_type_key(key);
})
.def("ir.RegisterOpAttr",
[](ffi::String op_name, ffi::String attr_key, ffi::AnyView value, int plevel) {
auto& reg = OpRegistry::Global()->RegisterOrGet(op_name).set_name();
// enable resgiteration and override of certain properties
if (attr_key == "num_inputs" && plevel > 128) {
reg.set_num_inputs(value.cast<int>());
} else if (attr_key == "attrs_type_key" && plevel > 128) {
TVM_FFI_THROW(InternalError) << "attrs type key no longer supported";
} else {
reg.set_attr(attr_key, value, plevel);
}
})
.def("ir.RegisterOpLowerIntrinsic",
[](ffi::String name, ffi::Function f, ffi::String target, int plevel) {
tvm::OpRegEntry::RegisterOrGet(name).set_attr<FLowerIntrinsic>(
target + ".FLowerIntrinsic", f, plevel);
});
// override OpNode to use name as the repr
refl::TypeAttrDef<OpNode>()
.def("__data_to_json__",
[](const OpNode* node) -> ffi::String {
// simply save as the string
return node->name;
})
.def("__data_from_json__", [](const ffi::String& name) -> Op { return Op::Get(name); });
}
// Pattern A (RM): auto-default repr from reflection.
} // namespace tvm