Files
apache--tvm/include/tvm/ir/expr.h
T
wehub-resource-sync 26446540fa
Lint / lint (push) Waiting to run
CI / MacOS (push) Waiting to run
CI / Windows (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:36:25 +08:00

569 lines
16 KiB
C++

/*
* 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 <tvm/ffi/dtype.h>
#include <tvm/ffi/extra/dataclass.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/string.h>
#include <tvm/ir/attrs.h>
#include <tvm/ir/base_expr.h>
#include <tvm/ir/cow.h>
#include <tvm/ir/source_map.h>
#include <algorithm>
#include <functional>
#include <limits>
#include <optional>
#include <string>
#include <type_traits>
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<GlobalVarNode>().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<GlobalVarNode>()
.def("__s_equal__", &GlobalVarNode::SEqual)
.def("__s_hash__", &GlobalVarNode::SHash);
}
bool SEqual(const GlobalVarNode* other,
ffi::TypedFunction<bool(AnyView, AnyView, bool, AnyView)> equal) const {
return equal(name_hint, other->name_hint, false, "name_hint");
}
int64_t SHash(int64_t init_hash, ffi::TypedFunction<int64_t(AnyView, int64_t, bool)> 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<Expr> args;
/*! \brief The additional attributes. */
Attrs attrs;
/*! \brief The type information arguments passed to the callee. */
ffi::Array<Type> ty_args;
static void RegisterReflection() {
namespace refl = tvm::ffi::reflection;
refl::ObjectDef<CallNode>()
.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<Expr> args, Attrs attrs = Attrs(),
ffi::Array<Type> ty_args = ffi::Array<Type>(), 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<IntImmNode>().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<FloatImmNode>().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<RangeNode>()
.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<PrimExpr, IntImmNode> = true;
template <>
inline constexpr bool object_ref_contains_v<PrimExpr, FloatImmNode> = 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<IntImm> = false;
// specialize to enable implicit conversion from const char*
template <>
struct TypeTraits<IntImm> : public ObjectRefWithFallbackTraitsBase<IntImm, int64_t> {
TVM_FFI_INLINE static IntImm ConvertFallbackValue(int64_t value) {
auto value_ty =
(value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min())
? PrimType::Int(64)
: PrimType::Int(32);
return IntImm(value_ty, value);
}
};
template <>
inline constexpr bool use_default_type_traits_v<FloatImm> = false;
template <>
struct TypeTraits<FloatImm> : public ObjectRefWithFallbackTraitsBase<FloatImm, double> {
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<T, StructuralHash, StructuralEqual>`
* or `std::unordered_set<T, ffi::ObjectPtrHash, ffi::ObjectPtrEqual>`).
*/
template <>
struct std::hash<tvm::GlobalVar> {
std::size_t operator()(const tvm::GlobalVar& var) const { return tvm::ffi::ObjectPtrHash()(var); }
};
template <>
struct std::equal_to<tvm::GlobalVar> {
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_