/* * 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 tvm/ir/expr.h * \brief Base expr nodes in TVM. */ #ifndef TVM_IR_EXPR_H_ #define TVM_IR_EXPR_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace tvm { // Forward-declare VirtualDevice to avoid circular imports. class VirtualDevice; /*! * \brief add operator * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator+(PrimExpr a, PrimExpr b); /*! * \brief subtraction operator * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator-(PrimExpr a, PrimExpr b); /*! * \brief negation. * * \param a input. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator-(PrimExpr a); /*! * \brief multiplication operator * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator*(PrimExpr a, PrimExpr b); /*! * \brief division operator * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator/(PrimExpr a, PrimExpr b); /*! * \brief left shift operator * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator<<(PrimExpr a, PrimExpr b); /*! * \brief right shift operator * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator>>(PrimExpr a, PrimExpr b); /*! * \brief greater * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator>(PrimExpr a, PrimExpr b); /*! * \brief greater_equal * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator>=(PrimExpr a, PrimExpr b); /*! * \brief less * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator<(PrimExpr a, PrimExpr b); /*! * \brief less_equal * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator<=(PrimExpr a, PrimExpr b); /*! * \brief equal * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator==(PrimExpr a, PrimExpr b); /*! * \brief not_equal * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator!=(PrimExpr a, PrimExpr b); /*! * \brief and * * \param a left operand * \param b right operand * \return The result expression. * \note This operator does eager constant folding. */ TVM_DLL PrimExpr operator&&(PrimExpr a, PrimExpr b); /*! * \brief or * * \param a left operand * \param b right operand * \return The result expression. * \note This operator does eager constant folding. */ TVM_DLL PrimExpr operator||(PrimExpr a, PrimExpr b); /*! * \brief not * * \param a left operand * \return The result expression. * \note This operator does eager constant folding. */ TVM_DLL PrimExpr operator!(PrimExpr a); /*! * \brief take bitwise and of two values * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator&(PrimExpr a, PrimExpr b); /*! * \brief take bitwise or of two values * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator|(PrimExpr a, PrimExpr b); /*! * \brief take bitwise xor of two values * * \param a left operand * \param b right operand * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator^(PrimExpr a, PrimExpr b); /*! * \brief take bitwise negation of two values * * \param a the input expression. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr operator~(PrimExpr a); class GlobalVar; /*! * \brief Global variable that lives in the top-level module. * * A GlobalVar only refers to function definitions. * This is used to enable recursive calls between function. * * \sa GlobalVarNode */ class GlobalVarNode : public ExprNode { public: /*! \brief The name of the variable, this only acts as a hint. */ ffi::String name_hint; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef().def_ro("name_hint", &GlobalVarNode::name_hint); // A GlobalVar identifies a module-level symbol. Its type is derived from the // corresponding function definition and is not part of the symbol identity. refl::TypeAttrDef() .def("__s_equal__", &GlobalVarNode::SEqual) .def("__s_hash__", &GlobalVarNode::SHash); } bool SEqual(const GlobalVarNode* other, ffi::TypedFunction equal) const { return equal(name_hint, other->name_hint, false, "name_hint"); } int64_t SHash(int64_t init_hash, ffi::TypedFunction hash) const { return hash(name_hint, init_hash, false); } static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind = kTVMFFISEqHashKindFreeVar; TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.GlobalVar", GlobalVarNode, ExprNode); }; /*! * \brief Managed reference to GlobalVarNode. * \sa GlobalVarNode */ class GlobalVar : public Expr { public: TVM_DLL explicit GlobalVar(ffi::String name_hint, Span span = {}); TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(GlobalVar, Expr, GlobalVarNode); TVM_DEFINE_OBJECT_REF_COW_METHOD(GlobalVarNode); }; /*! * \brief Call corresponds to callable invocation. */ class CallNode : public ExprNode { public: /*! * \brief The operator/function being invoked. * * It can be an Op, a GlobalVar, a local function value, or another callable * expression. */ Expr op; /*! \brief The arguments of the call. */ ffi::Array args; /*! \brief The additional attributes. */ Attrs attrs; /*! \brief The type information arguments passed to the callee. */ ffi::Array ty_args; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef() .def_ro("op", &CallNode::op) .def_ro("args", &CallNode::args) .def_ro("attrs", &CallNode::attrs) .def_ro("ty_args", &CallNode::ty_args); } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Call", CallNode, ExprNode); }; /*! * \brief Managed reference to CallNode. */ class Call : public Expr { public: TVM_DLL Call(Type ret_ty, Expr op, ffi::Array args, Attrs attrs = Attrs(), ffi::Array ty_args = ffi::Array(), Span span = Span()); TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(Call, Expr, CallNode); TVM_DEFINE_OBJECT_REF_COW_METHOD(CallNode); }; /*! * \brief Constant integer literals in the program. * \sa IntImm */ class IntImmNode : public ExprNode { public: /*! \brief the Internal value. */ int64_t value; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef().def_ro("value", &IntImmNode::value); } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.IntImm", IntImmNode, ExprNode); }; /*! * \brief Managed reference class to IntImmNode. * * \sa IntImmNode */ class IntImm : public PrimExpr { public: /*! * \brief Constructor. * \param value_ty The primitive type of the value. * \param value The internal value. * \param span The location of this object in the source code. */ TVM_DLL IntImm(PrimType value_ty, int64_t value, Span span = Span()); /*! * \brief Construct a scalar boolean constant. * \param value The boolean value. * \param span The location of this object in the source code. */ static IntImm Bool(bool value, Span span = Span()) { return IntImm(PrimType::Bool(), value, span); } /*! * \brief Construct a scalar int32 constant. * \param value The integer value. * \param span The location of this object in the source code. */ static IntImm Int32(int64_t value, Span span = Span()) { return IntImm(PrimType::Int(32), value, span); } /*! * \brief Construct a scalar int64 constant. * \param value The integer value. * \param span The location of this object in the source code. */ static IntImm Int64(int64_t value, Span span = Span()) { return IntImm(PrimType::Int(64), value, span); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(IntImm, PrimExpr, IntImmNode); static constexpr bool _type_container_is_exact = true; TVM_DEFINE_OBJECT_REF_COW_METHOD(IntImmNode); }; /*! * \brief Constant floating point literals in the program. * \sa FloatImm */ class FloatImmNode : public ExprNode { public: /*! \brief The constant value content. */ double value; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef().def_ro("value", &FloatImmNode::value); } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.FloatImm", FloatImmNode, ExprNode); }; /*! * \brief Managed reference class to FloatImmNode. * * \sa FloatImmNode */ class FloatImm : public PrimExpr { public: /*! * \brief Constructor. * \param value_ty The primitive type of the value. * \param value The internal value. * \param span The location in the source code. */ TVM_DLL FloatImm(PrimType value_ty, double value, Span span = Span()); TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(FloatImm, PrimExpr, FloatImmNode); static constexpr bool _type_container_is_exact = true; TVM_DEFINE_OBJECT_REF_COW_METHOD(FloatImmNode); }; /*! \brief range over one dimension */ class RangeNode : public ffi::Object { public: /*! \brief beginning of the node */ PrimExpr min; /*! \brief the extend of range */ PrimExpr extent; /*! \brief the location of this range in the source */ mutable Span span; /*! \brief constructor */ RangeNode() {} RangeNode(PrimExpr min, PrimExpr extent, Span span = Span()) : min(min), extent(extent), span(span) {} static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef() .def_ro("min", &RangeNode::min) .def_ro("extent", &RangeNode::extent) .def_ro("span", &RangeNode::span, refl::AttachFieldFlag::SEqHashIgnore()); } static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind = kTVMFFISEqHashKindTreeNode; TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Range", RangeNode, ffi::Object); }; /*! \brief Range container */ class Range : public ffi::ObjectRef { public: /*! * \brief constructor by begin and end * \param begin The begin of the range. * \param end The end of the range. * \param span The location of the Range in the source. */ TVM_DLL Range(PrimExpr begin, PrimExpr end, Span span = Span()); /*! * \brief construct a new range with min and extent * The corresponding constructor is removed, * because that is counter convention of tradition meaning * of range(begin, end) * * \param min The minimum range. * \param extent The extent of the range. * \param span The location of the Range in the source. */ TVM_DLL static Range FromMinExtent(PrimExpr min, PrimExpr extent, Span span = Span()); // declare range. TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(Range, ffi::ObjectRef, RangeNode); }; namespace ffi { template <> inline constexpr bool object_ref_contains_v = true; template <> inline constexpr bool object_ref_contains_v = true; // Type traits to enable automatic conversion into IntImm, Integer, and Bool // when called through the FFI template <> inline constexpr bool use_default_type_traits_v = false; // specialize to enable implicit conversion from const char* template <> struct TypeTraits : public ObjectRefWithFallbackTraitsBase { TVM_FFI_INLINE static IntImm ConvertFallbackValue(int64_t value) { auto value_ty = (value > std::numeric_limits::max() || value < std::numeric_limits::min()) ? PrimType::Int(64) : PrimType::Int(32); return IntImm(value_ty, value); } }; template <> inline constexpr bool use_default_type_traits_v = false; template <> struct TypeTraits : public ObjectRefWithFallbackTraitsBase { TVM_FFI_INLINE static FloatImm ConvertFallbackValue(double value) { return FloatImm(PrimType::Float(32), value); } }; } // namespace ffi } // namespace tvm /* \brief Allow tvm.GLobalVar as key in STL tables * * For most IR expressions, it would be ambiguous whether the * expression should follow reference equality or structural equality. * This is not the case for variables, which do not contain nested * internal structure, and are frequently used as keys in lookup * tables. * * Providing `std::hash` and `std::equal_to` specializations for * `tvm::GlobalVar` allows it to be used as a key in STL tables. For * other IR expressions, the user must specify the type of equality * used (e.g. `std::unordered_set` * or `std::unordered_set`). */ template <> struct std::hash { std::size_t operator()(const tvm::GlobalVar& var) const { return tvm::ffi::ObjectPtrHash()(var); } }; template <> struct std::equal_to { bool operator()(const tvm::GlobalVar& var_a, const tvm::GlobalVar& var_b) const { return tvm::ffi::ObjectPtrEqual()(var_a, var_b); } }; #endif // TVM_IR_EXPR_H_