/* * 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/tirx/op.h * \brief Common operators defined for Expr. * * \note Most of the operator defined here perform simple constant folding * when the type is int32 or int64 for simplifying the index expressions. */ // Acknowledgement: Most operator APIs originate from Halide. #ifndef TVM_TIRX_OP_H_ #define TVM_TIRX_OP_H_ #include #include #include #include #include #include #include #include #include #include #include namespace tvm { #define TVM_TIR_REGISTER_OP(OpName) \ TVM_REGISTER_OP("tirx." OpName) \ .set_attr("TScriptPrinterName", OpName) \ .set_attr("TIRxOpCategory", ffi::String("builtin"), /*plevel=*/1) #define TVM_TIRX_REGISTER_OP(OpName) TVM_TIR_REGISTER_OP(OpName) // Most common operators can be overloaded by argument type(PrimExpr). // So we put them under the root namespace. // // We put more developer oriented APIs -- MakeConst and is_const under tirx // as they are more specific to the tirx namespace. /*! * \brief Get the type of the expression under the unified type system. * * This function could return a more refined type than the runtime dtype * implied by PrimExpr::ty(). * * \param expr The input parameter. * \return The result type. * * \sa tvm/ir/type.h for discussion about the relation between Type and DLPack dtype. */ TVM_DLL Type GetType(const PrimExpr& expr); /*! * \brief Get the type corresponding to a runtime DLPack dtype. * \param dtype The runtime dtype. * \return The result type * * \sa tvm/ir/type.h for discussion about the relation between Type and DLPack dtype. */ TVM_DLL Type GetTypeFromRuntimeDataType(DLDataType dtype); /*! * \brief Return the value. * * \param value The returned value. * \param span The location of this operation in the source. * \return The return expression. */ TVM_DLL PrimExpr ret(PrimExpr value, Span span = Span()); TVM_DLL Expr ret(Expr value, Span span = Span()); /*! * \brief Return from a thread. * * \param span The location of this operation in the source. * \return The return expression. */ TVM_DLL PrimExpr thread_return(Span span = Span()); /*! * \brief Continue current loop. * \param span The location of this operation in the source. * \return The continue loop expression. */ TVM_DLL PrimExpr continue_loop(Span span = Span()); /*! * \brief Break current loop. * \param span The location of this operation in the source. * \return The break loop expression. */ TVM_DLL PrimExpr break_loop(Span span = Span()); /*! * Query the maximum possible value of dtype. * \param dtype The primitive type. * \param span The location of this operation in the source. * \return the maximum possible value in this format. */ TVM_DLL PrimExpr max_value(PrimType dtype, Span span = Span()); /*! * Query the minimum possible value of dtype. * \param dtype The primitive type. * \param span The location of this operation in the source. * \return the minimum possible value in this format. */ TVM_DLL PrimExpr min_value(PrimType dtype, Span span = Span()); /*! * Get the value of infinity. * \param dtype The primitive type. * \param span The location of this operation in the source. * \return the infinity value in this format. */ TVM_DLL PrimExpr infinity(PrimType dtype, Span span = Span()); /*! * \brief cast value to type. * * \param t the target type. * \param value The value * \param span The location of this operation in the source. * \return The result expression. * \note This function may return value if the type is the same. */ TVM_DLL PrimExpr cast(PrimType t, PrimExpr value, Span span = Span()); /*! * \brief perform reinterpret cast value to type. * * \param t the target type. * \param value The value * \param span The location of this operation in the source. * \return The result expression. * \note This function may return value if the type is the same. */ TVM_DLL PrimExpr reinterpret(PrimType t, PrimExpr value, Span span = Span()); /*! \brief Perform a reinterpret cast involving an exact primitive or pointer type. */ TVM_DLL Expr reinterpret(Type target_ty, Expr value, Span span = Span()); /*! * \brief add operator * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr add(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief subtraction operator * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr sub(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief negation. * * \param a input. * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr neg(PrimExpr a, Span span = Span()); /*! * \brief multiplication operator * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr mul(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief left shift operator * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr left_shift(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief right shift operator * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr right_shift(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief greater * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr greater(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief greater_equal * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr greater_equal(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief less * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr less(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief less_equal * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr less_equal(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief equal * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr equal(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief not_equal * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr not_equal(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief and * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note This operator does eager constant folding. */ TVM_DLL PrimExpr logical_and(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief or * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note This operator does eager constant folding. */ TVM_DLL PrimExpr logical_or(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief not * * \param a left operand * \param span The location of this operation in the source. * \return The result expression. * \note This operator does eager constant folding. */ TVM_DLL PrimExpr logical_not(PrimExpr a, Span span = Span()); /*! * \brief compute division in C semantics. * * a / b as in C/C++. * * When operands are integers, it directly corresponds to truncdiv. * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr div(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute trunc(a / b) * * This is the default integer division behavior in C. * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr truncdiv(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute the remainder of truncdiv * * This is the default integer division behavior in C. * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr truncmod(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute floor(a / b) where a and b are non-negative. * * Use this function for index split calculation. * * This function might take advantage of the fact * that a and b are non-negative. * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr indexdiv(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute ceil(a / b) where a and b are non-negative. * * Use this function for shape split calculation. * * This function might take advantage of the fact * that a and b are non-negative. * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * shape types(int32, int64) when possible. */ TVM_DLL PrimExpr shapediv(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute the remainder floor(a / b) where a and b are non-negative. * * Use this function for index split calculation. * This function might take advantage of the fact * that a and b are non-negative. * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr indexmod(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute floor(a / b) * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr floordiv(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief Compute log(exp(a) + exp(b)). * * \param a Left operand. * \param b Right operand. * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr logaddexp(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute ceil(a / b) * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr ceildiv(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief compute the remainder of floordiv * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr floormod(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief take maximum of two values * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr max(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief take minimum of two values * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr min(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief take bitwise and of two values * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr bitwise_and(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief take bitwise or of two values * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr bitwise_or(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief take bitwise xor of two values * * \param a left operand * \param b right operand * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr bitwise_xor(PrimExpr a, PrimExpr b, Span span = Span()); /*! * \brief take bitwise negation of two values * * \param a the input expression. * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr bitwise_neg(PrimExpr a, Span span = Span()); /*! * \brief Conditional expression. * * \param cond The condition * \param true_value The value when results are true. * \param false_value The value when results are false. * \param span The location of this operation in the source. * \return The result expression. * \note this function does eager constant folding for * index types(int32, int64) when possible. */ TVM_DLL PrimExpr if_then_else(PrimExpr cond, PrimExpr true_value, PrimExpr false_value, Span span = Span()); /*! * \brief Mark condition as likely. * \param cond The condition * \param span The location of this operation in the source. * \return The marked expression. */ TVM_DLL PrimExpr likely(PrimExpr cond, Span span = Span()); /*! * \brief Calculate power(x, y) * \param x The left operand. * \param y The right operand. * \param span The location of this operation in the source. */ TVM_DLL PrimExpr pow(PrimExpr x, PrimExpr y, Span span = Span()); /*! * \brief Calculate absolute value of x. * \param x The input data * \param span The location of this operation in the source. * * \return The absolute value of input data x */ TVM_DLL PrimExpr abs(PrimExpr x, Span span = Span()); /*! * \brief Check if x is NaN. * \param x The input data * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr isnan(PrimExpr x, Span span = Span()); /*! * \brief Check if x is finite. * \param x The input data * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr isfinite(PrimExpr x, Span span = Span()); /*! * \brief Check if x is infinite. * \param x The input data * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr isinf(PrimExpr x, Span span = Span()); /*! * \brief sum of source expression over axis * \param source The source expression. * \param axis List of iteration variables that will be used for reduction. * \param init The value with which to initialize the output. * \param span The location of this operation in the source. * \return The result. */ TVM_DLL PrimExpr sum(PrimExpr source, ffi::Array axis, ffi::Array init = {}, Span span = Span()); /*! * \brief logical And of source expression over axis * \param source The source expression. * \param axis List of iteration variables that will be used for reduction. * \param init The value with which to initialize the output. * \param span The location of this operation in the source. */ TVM_DLL PrimExpr all(PrimExpr source, ffi::Array axis, ffi::Array init = {}, Span span = Span()); /*! * \brief logical Or of source expression over axis * \param source The source expression. * \param axis List of iteration variables that will be used for reduction. * \param init The value with which to initialize the output. * \param span The location of this operation in the source. * \return The result. */ TVM_DLL PrimExpr any(PrimExpr source, ffi::Array axis, ffi::Array init = {}, Span span = Span()); /*! * \brief max of source expression over axis * \param source The source expression. * \param axis List of iteration variables that will be used for reduction. * \param init The value with which to initialize the output. * \param span The location of this operation in the source. * \return The result. */ TVM_DLL PrimExpr max(PrimExpr source, ffi::Array axis, ffi::Array init = {}, Span span = Span()); /*! * \brief max of source expression over axis * \param source The source expression. * \param axis List of iteration variables that will be used for reduction. * \param init The value with which to initialize the output. * \param span The location of this operation in the source. * \return The result. */ TVM_DLL PrimExpr min(PrimExpr source, ffi::Array axis, ffi::Array init = {}, Span span = Span()); /*! * \brief product of source expression over axis * \param source The source expression. * \param axis List of iteration variables that will be used for reduction. * \param init The value with which to initialize the output. * \param span The location of this operation in the source. * \return The result. */ TVM_DLL PrimExpr prod(PrimExpr source, ffi::Array axis, ffi::Array init = {}, Span span = Span()); /*! * \brief Calculate floor(x) * \param x The input expression. * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr floor(PrimExpr x, Span span = Span()); /*! * \brief Calculate ceil(x) * \param x The input expression. * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr ceil(PrimExpr x, Span span = Span()); /*! * \brief Round x to the nearest integer, ties to even. * * Uses IEEE 754 default rounding mode (ties-to-even / banker's rounding). * Constant-folding and all backends consistently use std::nearbyint semantics. * * \param x The input expression. * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr round(PrimExpr x, Span span = Span()); /*! * \brief Round x to the nearest integer, ties to even. * * Equivalent to round(). Both use IEEE 754 default rounding mode (ties-to-even). * * \param x The input expression. * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr nearbyint(PrimExpr x, Span span = Span()); /*! * \brief Calculate trunc(x) * \param x The input expression. * \param span The location of this operation in the source. * \return The result expression. */ TVM_DLL PrimExpr trunc(PrimExpr x, Span span = Span()); /*! * \brief Construct a large uint constant by its low 32 bits and high 32bits. * \param value_ty The final primitive type. * \param low The lower 32 bits. * \param high The higher 32 bits. * \param span The location of this operation in the source. * \return The constructed expression. */ TVM_DLL PrimExpr LargeUIntImm(PrimType value_ty, int64_t low, int64_t high, Span span = Span()); /*! * \brief Execute a multiplication between two Q-numbers x and y * followed by a right shift s. The mathematical expression is: * * out = round(x*y*2^-s) * * Please note that the two Q-numbers x and y are supposed to have * the same number of fractional bits q. * * More about Q-numbers here: https://en.wikipedia.org/wiki/Q_(number_format) * * The rounding rule is to the nearest value, rounding half up * (i.e., round(x.1) = x and round (x.5) = x+1) * \param x first Q-number * \param y second Q-number * \param q number of fractional bits in x and y. Needs to be > 0 * \param s integer right shift * \param span The location of this operation in the source. * \return The constructed expression. */ TVM_DLL PrimExpr q_multiply_shift(PrimExpr x, PrimExpr y, PrimExpr q, PrimExpr s, Span span = Span()); /*! * \brief Fast_erf_float expression from Eigen * * \param arg The input expression. * \param bits The number of bits in the type. * \return The constructed expression. */ TVM_DLL PrimExpr fast_erf_float_expr(PrimExpr arg, int bits); inline void CheckMathUnaryOpInputDType(const char* op_name, const PrimType& dtype) { TVM_FFI_CHECK(dtype.code() == DLDataTypeCode::kDLFloat || dtype.MatchesElementType(DLDataTypeCode::kDLBfloat, 16), TypeError) << "tirx." << op_name << " only supports floating-point inputs, but got " << dtype; } // Intrinsic operators #define TVM_DECLARE_INTRIN_UNARY_WITH_CHECK(OpName, CheckInputDType) \ inline PrimExpr OpName(PrimExpr x, Span span = Span()) { \ static const Op op = Op::Get("tirx." #OpName); \ PrimType x_ty = x.ty(); \ CheckInputDType(#OpName, x_ty); \ if (x_ty.MatchesElementType(DLDataTypeCode::kDLBfloat, 16)) { \ PrimType bf16_ty = x_ty; \ PrimType f32_ty = \ x_ty.IsScalableVector() \ ? PrimType::ScalableVector(DLDataTypeCode::kDLFloat, 32, x_ty.VScaleFactor()) \ : PrimType::Float(32, x_ty.lanes()); \ PrimExpr x_fp32 = tirx::Cast(f32_ty, x, span); \ PrimExpr result_fp32 = Call(f32_ty, op, {x_fp32}, {}, {}, span).as_or_throw(); \ return tirx::Cast(bf16_ty, result_fp32, span); \ } else { \ return Call(x_ty, op, {x}, {}, {}, span).as_or_throw(); \ } \ } #define TVM_DECLARE_INTRIN_UNARY(OpName) \ TVM_DECLARE_INTRIN_UNARY_WITH_CHECK(OpName, [](const char*, const PrimType&) {}) #define TVM_DECLARE_FLOAT_INTRIN_UNARY(OpName) \ TVM_DECLARE_INTRIN_UNARY_WITH_CHECK(OpName, CheckMathUnaryOpInputDType) TVM_DECLARE_INTRIN_UNARY(exp); TVM_DECLARE_INTRIN_UNARY(exp2); TVM_DECLARE_INTRIN_UNARY(exp10); TVM_DECLARE_INTRIN_UNARY(erf); TVM_DECLARE_FLOAT_INTRIN_UNARY(tanh); TVM_DECLARE_INTRIN_UNARY(sigmoid); TVM_DECLARE_INTRIN_UNARY(sqrt); TVM_DECLARE_INTRIN_UNARY(rsqrt); TVM_DECLARE_INTRIN_UNARY(log); TVM_DECLARE_INTRIN_UNARY(log2); TVM_DECLARE_INTRIN_UNARY(log10); TVM_DECLARE_INTRIN_UNARY(log1p); TVM_DECLARE_INTRIN_UNARY(popcount); TVM_DECLARE_FLOAT_INTRIN_UNARY(tan); TVM_DECLARE_FLOAT_INTRIN_UNARY(cos); TVM_DECLARE_FLOAT_INTRIN_UNARY(cosh); TVM_DECLARE_FLOAT_INTRIN_UNARY(sin); TVM_DECLARE_FLOAT_INTRIN_UNARY(sinh); TVM_DECLARE_FLOAT_INTRIN_UNARY(asin); TVM_DECLARE_FLOAT_INTRIN_UNARY(acos); TVM_DECLARE_FLOAT_INTRIN_UNARY(atan); TVM_DECLARE_FLOAT_INTRIN_UNARY(acosh); TVM_DECLARE_FLOAT_INTRIN_UNARY(asinh); TVM_DECLARE_FLOAT_INTRIN_UNARY(atanh); TVM_DECLARE_INTRIN_UNARY(clz); #define TVM_DECLARE_INTRIN_BINARY(OpName) \ inline PrimExpr OpName(PrimExpr x, PrimExpr y, Span span = Span()) { \ static const Op op = Op::Get("tirx." #OpName); \ return Call(x.ty(), op, {x, y}, {}, {}, span).as_or_throw(); \ } TVM_DECLARE_INTRIN_BINARY(atan2); TVM_DECLARE_INTRIN_BINARY(nextafter); TVM_DECLARE_INTRIN_BINARY(copysign); TVM_DECLARE_INTRIN_BINARY(hypot); TVM_DECLARE_INTRIN_BINARY(ldexp); namespace tirx { /*! * \brief Check if type is a pointer to a runtime element type. * \param type The type to be checked. * \param element_type The corresponding element type. * \return The check results */ inline bool IsPointerType(const Type& type, DLDataType element_type) { if (type.IsMissing()) return false; if (const auto* ptr_type = type.as()) { if (const auto* prim_type = ptr_type->element_type.as()) { return prim_type->dtype == element_type; } } return false; } /*! * \brief Make a const value with certain data type. * * Prefer direct IntImm or FloatImm construction when dtype is known to be * scalar integer or floating point. This makes the compiled code more compact * and efficient. Keep MakeConst for generic overload cases where dtype can be * integer, floating point, or vector-valued and the caller needs its * scalar/vector dispatch. * * \param dtype The target type. * \param value The input value * \return the result expression. * \tparam ValueType The constant value type * \param span The location of this operation in the source. */ template ::value && std::is_trivial::value>::type> inline PrimExpr MakeConst(PrimType dtype, ValueType value, Span span = Span()); /*! * \brief Make a constant opaque-pointer value. * \param value The integer payload to reinterpret as a handle. * \param span The location of this operation in the source. * \return The result expression. */ inline Expr ConstHandle(int64_t value, Span span = Span()); /*! * \brief Get x as constant int expression. * \param x The expression * \return the address to the int expression, * return nullptr, if x is not IntImm. */ inline const int64_t* as_const_int(const PrimExpr& x) { if (!x.defined()) return nullptr; if (const tirx::IntImmNode* op = x.as()) { return &(op->value); } return nullptr; } /*! * \brief Check whether x is a constant integer expression. * \param x The input argument * \param value the value to be compared against. * \return whether x is constant expression. */ inline bool is_const_int(const PrimExpr& x, int64_t value); /*! * \brief Check whether stmt is nop. * \param stmt The input statement * \return whether stmt is nop */ inline bool is_no_op(const tirx::Stmt& stmt); /*! * \brief Check whether x is a constant integer 1 * \param x The input argument. * \note This only return true for integer types. * \return whether x is constant 1 */ inline bool is_one(const PrimExpr& x) { return is_const_int(x, 1); } /*! * \brief Check whether x is a constant integer 0 * \param x The input argument * \return whether x is constant 0 * \note This only return true for integer types. */ inline bool is_zero(const PrimExpr& x) { return is_const_int(x, 0); } /*! * \brief Check whether x is an integer constant. * \note This only return true for integer types. * \return whether x is constant */ inline bool is_const_int(const PrimExpr& x); /*! * \brief Check whether x is an integer/float constant. * \note This only return true for integer types. * \return whether x is constant */ inline bool is_const_number(const PrimExpr& x); /*! * \brief Left fold. * \param freduce The reduction function. * \param init_value The initial value. * \param values The values to be folded. * \param span The location of the fold in the source. * \return The result. * \tparam FReduce The type of the reduction. */ template inline PrimExpr foldl(FReduce freduce, PrimExpr init_value, const ffi::Array& values, Span span = Span()) { for (PrimExpr val : values) { init_value = freduce(init_value, val, span); } return init_value; } /*! * \brief Check whether x is a constant power of two * If x is power of two, write the power to the shift. * * \param x The input expression. * \param shift The output shift if x is power of two. * \return whether x is constant power of two */ TVM_DLL bool is_const_power_of_two_integer(const PrimExpr& x, int* shift); // Implementation details after this inline bool is_const_int(const PrimExpr& x) { return as_const_int(x); } inline bool is_const_number(const PrimExpr& x) { if (x.as()) { return true; } else if (x.as()) { return true; } else if (const auto* op = x.as()) { return (op->value->IsInstance() || op->value->IsInstance()); } return false; } inline bool is_positive_const(const PrimExpr& a) { const int64_t* as_int = as_const_int(a); return as_int && (*as_int > 0); } inline bool is_negative_const(const PrimExpr& a) { const int64_t* as_int = as_const_int(a); return as_int && (*as_int < 0); } inline bool is_const_int(const PrimExpr& x, int64_t value) { const int64_t* as_int = as_const_int(x); return as_int && (*as_int == value); } inline bool is_no_op(const tirx::Stmt& stmt) { if (!stmt.defined()) return true; if (const auto* op = stmt.as()) { auto value = op->value.as(); return value && is_const_int(value.value()); } if (const auto* op = stmt.as()) { return op->seq.size() == 0; } return false; } template inline PrimExpr MakeConstScalar(PrimType dtype, ValueType value, Span span = Span()) { DLDataTypeCode code = dtype.code(); if (code == DLDataTypeCode::kDLInt || code == DLDataTypeCode::kDLBool) { return IntImm(dtype, static_cast(value), span); } if (code == DLDataTypeCode::kDLUInt) { // Use IntImm if it is a small integer uint64_t uval = static_cast(value); if (value < static_cast(0)) { TVM_FFI_THROW(InternalError) << "cannot make uint from negative value " << value; } else if (uval <= static_cast(std::numeric_limits::max())) { return IntImm(dtype, static_cast(value), span); } else { uint64_t mask = (static_cast(1) << 32U) - 1U; uint64_t low = uval & mask; uint64_t high = uval >> 32U; return LargeUIntImm(dtype, static_cast(low), static_cast(high), span); } } if (dtype.MatchesCode(DLDataTypeCode::kDLFloat, DLDataTypeCode::kDLFloat8_e3m4, DLDataTypeCode::kDLFloat8_e4m3, DLDataTypeCode::kDLFloat8_e4m3b11fnuz, DLDataTypeCode::kDLFloat8_e4m3fn, DLDataTypeCode::kDLFloat8_e4m3fnuz, DLDataTypeCode::kDLFloat8_e5m2, DLDataTypeCode::kDLFloat8_e5m2fnuz, DLDataTypeCode::kDLFloat8_e8m0fnu, DLDataTypeCode::kDLFloat6_e2m3fn, DLDataTypeCode::kDLFloat6_e3m2fn, DLDataTypeCode::kDLFloat4_e2m1fn) || dtype.MatchesElementType(DLDataTypeCode::kDLBfloat, 16)) { return FloatImm(dtype, static_cast(value), span); } TVM_FFI_THROW(InternalError) << "cannot make const for type " << dtype; throw; } template <> inline PrimExpr MakeConstScalar(PrimType dtype, bool value, Span span) { return MakeConstScalar(dtype, static_cast(value), span); } template inline PrimExpr MakeConst(PrimType dtype, ValueType value, Span span) { if (!dtype.IsScalableVector() && !dtype.IsFixedLengthVector()) { return MakeConstScalar(dtype, value, span); } PrimType elem_ty = dtype.WithLanes(1); if (dtype.IsFixedLengthVector()) { return tirx::Broadcast(MakeConstScalar(elem_ty, value, span), dtype.lanes(), span); } PrimExpr lanes = tirx::Mul(Call(PrimType::Int(32), tirx::builtin::vscale(), {}).as_or_throw(), dtype.VScaleFactor()); return tirx::Broadcast(MakeConstScalar(elem_ty, value, span), lanes, span); } inline Expr ConstHandle(int64_t value, Span span) { return reinterpret(PointerType::VoidPointerTy(), IntImm(PrimType::UInt(64), value, span), span); } } // namespace tirx // additional const expression overloading #define TVM_DEFINE_ASSIGN_OP_OVERLOAD(Name, OpFunc) \ inline PrimExpr Name(PrimExpr& a, PrimExpr b) { \ a = OpFunc(a, b); \ return a; \ } #define TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(Name) \ inline PrimExpr Name(const PrimExpr& a, float b) { return Name(a, PrimExpr(b)); } \ inline PrimExpr Name(float a, const PrimExpr& b) { return Name(PrimExpr(a), b); } \ inline PrimExpr Name(int a, const PrimExpr& b) { return Name(tirx::MakeConst(b.ty(), a), b); } \ inline PrimExpr Name(const PrimExpr& a, int b) { return Name(a, tirx::MakeConst(a.ty(), b)); } \ inline PrimExpr Name(const PrimExpr& a, double b) { \ return Name(a, FloatImm(PrimType::Float(64), b)); \ } #define TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(Name) \ inline PrimExpr Name(const PrimExpr& a, float b, Span span = Span()) { \ return Name(a, PrimExpr(b), span); \ } \ inline PrimExpr Name(float a, const PrimExpr& b, Span span = Span()) { \ return Name(PrimExpr(a), b, span); \ } \ inline PrimExpr Name(int a, const PrimExpr& b, Span span = Span()) { \ return Name(tirx::MakeConst(b.ty(), a), b, span); \ } \ inline PrimExpr Name(const PrimExpr& a, int b, Span span = Span()) { \ return Name(a, tirx::MakeConst(a.ty(), b), span); \ } \ inline PrimExpr Name(const PrimExpr& a, double b, Span span = Span()) { \ return Name(a, FloatImm(PrimType::Float(64), b), span); \ } #define TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD(Name) \ inline PrimExpr Name(const PrimExpr& a, bool b) { return Name(a, PrimExpr(b)); } \ inline PrimExpr Name(bool a, const PrimExpr& b) { return Name(PrimExpr(a), b); } #define TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD_SPANNED(Name) \ inline PrimExpr Name(const PrimExpr& a, bool b, Span span = Span()) { \ return Name(a, PrimExpr(b), span); \ } \ inline PrimExpr Name(bool a, const PrimExpr& b, Span span = Span()) { \ return Name(PrimExpr(a), b, span); \ } #define TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD(Name) \ inline PrimExpr Name(const PrimExpr& a, int b) { return Name(a, tirx::MakeConst(a.ty(), b)); } \ inline PrimExpr Name(int a, const PrimExpr& b) { return Name(tirx::MakeConst(b.ty(), a), b); } #define TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(Name) \ inline PrimExpr Name(const PrimExpr& a, int b, Span span = Span()) { \ return Name(a, tirx::MakeConst(a.ty(), b), span); \ } \ inline PrimExpr Name(int a, const PrimExpr& b, Span span = Span()) { \ return Name(tirx::MakeConst(b.ty(), a), b, span); \ } TVM_DEFINE_ASSIGN_OP_OVERLOAD(operator+=, operator+); TVM_DEFINE_ASSIGN_OP_OVERLOAD(operator-=, operator-); TVM_DEFINE_ASSIGN_OP_OVERLOAD(operator*=, operator*); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator+); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator-); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator*); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator>); // NOLINT(*) TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator>=); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator<); // NOLINT(*) TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD(operator<=); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(max); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(min); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(div); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(add); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(sub); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(mul); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(greater); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(greater_equal); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(less); TVM_DEFINE_BINOP_CONST_VAL_OVERLOAD_SPANNED(less_equal); // integer related ops TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(indexdiv); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(indexmod); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(truncdiv); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(truncmod); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(floordiv); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(logaddexp); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(floormod); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(right_shift); // NOLINT(*) TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(left_shift); // NOLINT(*) TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(bitwise_and); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(bitwise_or); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD_SPANNED(bitwise_xor); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD(operator>>); // NOLINT(*) TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD(operator<<); // NOLINT(*) TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD(operator&); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD(operator|); TVM_DEFINE_INT_OP_CONST_VAL_OVERLOAD(operator^); // logical ops TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD(operator&&); TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD(operator||); TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD_SPANNED(logical_and); TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD_SPANNED(logical_or); /*! * \brief Helper function to raise a compiler error about division ambiguity. * \note The call to this function will always results in a compiler error. * \tparam TA Any class type. */ template inline void DivAmbiguityError(const TA& a) { constexpr bool div_ambiguity = !std::is_class::value; static_assert(div_ambiguity, "TVM supports multiple types of integer divisions, " "please call div, indexdiv/indexmod, " "floordiv/floormod or truncdiv/truncmod directly " "to avoid ambiguity in the code. " "Checkout these functions in tirx/op.h."); } // The following code are not intended to be used in the codebase. // Instead, they generate clear compiler errors that ask developers // to use the specific division function. // The second template argument is necessary to make sure the // code compiles lazily by the compiler during invocation. template inline PrimExpr operator/(const PrimExpr& a, const TB& b) { DivAmbiguityError(a); return a; } template inline PrimExpr operator/=(const PrimExpr& a, const TB& b) { DivAmbiguityError(a); return a; } template inline PrimExpr operator%(const PrimExpr& a, const TB& b) { DivAmbiguityError(a); return a; } } // namespace tvm #endif // TVM_TIR_OP_H_