Files
apache--tvm/include/tvm/tirx/function.h
T
wehub-resource-sync 26446540fa
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:36:25 +08:00

382 lines
13 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/tirx/function.h
* \brief TIR Function.
*/
#ifndef TVM_TIR_FUNCTION_H_
#define TVM_TIR_FUNCTION_H_
#include <tvm/ffi/container/map.h>
#include <tvm/ffi/container/variant.h>
#include <tvm/ir/cow.h>
#include <tvm/ir/function.h>
#include <tvm/runtime/tensor.h>
#include <tvm/tirx/buffer.h>
#include <tvm/tirx/expr.h>
#include <tvm/tirx/stmt.h>
#include <string>
namespace tvm {
namespace tirx {
/*!
* \brief Primitive functions that contains TIR statements.
*
* The PrimFunc provides low-level code representation does not
* automatically manage
*
* \sa PrimFunc
*/
class PrimFuncNode : public BaseFuncNode {
public:
/*! \brief Function parameters */
ffi::Array<tirx::Var> params;
/*! \brief The return type of the function. */
Type ret_type = Type::Missing();
/*!
* \brief Maps some parameters to specific Buffer data structures.
*
* buffer_map provides a way to express data structure's field and shape
* constraints. The provided information is used in the program analysis
* and the code generation.
*
* - It defines the vars in the Buffer (m, n) in the cases below when
* they appears in the buffer_map for the first time.
* - When a var appears multiple times, they translate into runtime
* assertion to check the field constraint.
*
* \code
*
* # The corresponding fields of f are as follows
* #
* # - f.params = [a, b]
* # - f.buffer_map = {a: A, b: B}
* # - A = decl_buffer(shape=[m, n])
* # - B = decl_buffer(shape=[m, n])
*
* def f(a, b):
* m, n = var(), var()
* A = bind_buffer(a, shape=[m, n])
* B = bind_buffer(b, shape=[m, n])
* # body
*
* \endcode
*
* buffer_map is a sugar to express:
* - Parameter unpacking: e.g. I can load a.shape[0] to get value of m
* - Constraint checking: a.shape[0] must equal b.shape[0] because they
* both corresponds to m.
* While we could have express parameter unpacking and constraint using
* normal statements, making buffer_map as first class citizen of PrimFunc
* will make program analysis much easier.
*
* Prior to buffer flattening, which is performed FlattenBuffer for
* TIR-based schedules, these buffer objects are used directly in
* the body of the function. After buffer flattening, these buffer
* objects remain unflattened for use in argument validation, but
* all usage in the body of the function is done through a
* flattened alias of the buffer.
*/
ffi::Map<tirx::Var, Buffer> buffer_map;
/*! \brief The body of the function */
tirx::Stmt body;
static void RegisterReflection() {
namespace refl = tvm::ffi::reflection;
refl::ObjectDef<PrimFuncNode>()
.def_ro("params", &PrimFuncNode::params, refl::AttachFieldFlag::SEqHashDefRecursive())
.def_ro("ret_type", &PrimFuncNode::ret_type)
.def_ro("buffer_map", &PrimFuncNode::buffer_map)
.def_ro("body", &PrimFuncNode::body);
refl::TypeAttrDef<PrimFuncNode>()
.def("__s_equal__", &PrimFuncNode::SEqual)
.def("__s_hash__", &PrimFuncNode::SHash);
}
bool SEqual(const PrimFuncNode* other,
ffi::TypedFunction<bool(AnyView, AnyView, bool, AnyView)> equal) const {
// `ty` is derived from the fields below. PrimFunc transformations update
// those source fields without maintaining this redundant cache eagerly.
// Remove this exception once all PrimFunc mutation paths recompute `ty`.
return equal(attrs, other->attrs, false, "attrs") &&
equal(params, other->params, true, "params") &&
equal(ret_type, other->ret_type, false, "ret_type") &&
equal(buffer_map, other->buffer_map, false, "buffer_map") &&
equal(body, other->body, false, "body");
}
int64_t SHash(int64_t init_hash, ffi::TypedFunction<int64_t(AnyView, int64_t, bool)> hash) const {
int64_t hash_value = init_hash;
hash_value = hash(attrs, hash_value, false);
hash_value = hash(params, hash_value, true);
hash_value = hash(ret_type, hash_value, false);
hash_value = hash(buffer_map, hash_value, false);
hash_value = hash(body, hash_value, false);
return hash_value;
}
/*!
* \brief Return the derived function annotation of this function.
*
* \return The function type annotation.
* \note The function type annotation of PrimExpr is
* directly derived from the Vars without the need of type inference.
*/
TVM_DLL FuncType func_type_annotation() const;
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("tirx.PrimFunc", PrimFuncNode, BaseFuncNode);
};
/*!
* \brief Managed reference to PrimFuncNode.
* \sa PrimFuncNode
*/
class PrimFunc : public BaseFunc {
public:
/*!
* \brief Constructor
*
* \param params The parameters of the function.
*
* \param body The body of the function.
*
* \param ret_type The return type of the function.
*
* \param buffer_map The buffer map for parameter buffer unpacking.
* This contains buffer objects as they appear in the body of the
* PrimFunc. (e.g. a buffer of shape ``[1024]`` originally
* generated as a tensor of shape ``[32, 32]``)
*
* \param attrs Additional function attributes.
*
* \param span The location of this object in the source code.
*/
TVM_DLL PrimFunc(ffi::Array<tirx::Var> params, Stmt body, Type ret_type = VoidType(),
ffi::Map<tirx::Var, Buffer> buffer_map = ffi::Map<tirx::Var, Buffer>(),
DictAttrs attrs = DictAttrs(), Span span = Span());
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(PrimFunc, BaseFunc, PrimFuncNode);
TVM_DEFINE_OBJECT_REF_COW_METHOD(PrimFuncNode);
};
/*!
* \brief Tensor intrinsics for tensorization
*/
class TensorIntrinNode : public ffi::Object {
public:
/*! \brief The function to describe the computation. */
PrimFunc desc;
/*! \brief The function of the implementation for the execution. */
PrimFunc impl;
static void RegisterReflection() {
namespace refl = tvm::ffi::reflection;
refl::ObjectDef<TensorIntrinNode>()
.def_ro("desc", &TensorIntrinNode::desc)
.def_ro("impl", &TensorIntrinNode::impl);
}
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("tirx.TensorIntrin", TensorIntrinNode, ffi::Object);
};
/*!
* \brief Managed reference to TensorIntrinNode.
*/
class TensorIntrin : public ffi::ObjectRef {
public:
/*!
* \brief Constructor
* \param desc The function to describe the computation.
* \param impl The function of the implementation for the execution.
*/
TVM_DLL explicit TensorIntrin(PrimFunc desc, PrimFunc impl);
/*!
* \brief Create and register a TensorIntrin. After registration, the TensorIntrin can be looked
* up with its name.
* \param name The name of the TensorIntrin to register
* \param intrin The TensorIntrin to register.
* \param override Whether override existing intrinsic.
* \throws This method throws an exception if the TensorIntrin with the specified name already
* exists.
*/
TVM_DLL static void Register(ffi::String name, TensorIntrin intrin, bool override = false);
/*!
* \brief Look up TensorIntrin by name. Raises an exception if not found.
* \param name The name of the TensorIntrin.
* \param allow_missing Whether to allow missing tensor intrin. If false, an exception is raised
* if the tensor intrin is not found.
* \return The TensorIntrin with the specified name.
* \throws This method throws an exception if the TensorIntrin does not exist and allow_missing is
* false.
*/
TVM_DLL static ffi::Optional<TensorIntrin> Get(ffi::String name, bool allow_missing = false);
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TensorIntrin, ffi::ObjectRef, TensorIntrinNode);
};
/*!
* \brief Specialize parameters of PrimFunc.
* \param func The PrimFunc to be specialized.
* \param param_map The mapping from function params to the instance.
* \return The new function with parameter specialized.
* \note We can define a Meta TIR function with symbolic shape:
*
* \code{.py}
* @T.prim_func
* def mem_copy(a: T.handle, b: T.handle, m: T.int32, n: T.int32) -> None:
* A = T.match_buffer(a, (m, n), "float32")
* B = T.match_buffer(b, (m, n), "float32")
* for i, j in T.grid(m, n):
* with T.sblock():
* vi, vj = T.axis.remap("SS", [i, j])
* B[vi, vj] = A[vi, vj]
* \endcode
*
* Then we can make it specialized with given shapes or buffers.
*
* \code{.py}
* a, _, m, n = mem_copy.params
* func = mem_copy.specialize({a: tirx.decl_buffer((16, 16))})
* # or
* func = mem_copy.specialize({n: 16, m: 16})
* \endcode
*
* \code{.py}
* @T.prim_func
* def mem_copy_16_16(a: T.handle, b: T.handle) -> None:
* A = T.match_buffer(a, (16, 16), "float32")
* B = T.match_buffer(b, (16, 16), "float32")
* for i, j in T.grid(16, 16):
* with T.sblock():
* vi, vj = T.axis.remap("SS", [i, j])
* B[vi, vj] = A[vi, vj]
* \endcode
*/
PrimFunc Specialize(PrimFunc func, const ffi::Map<Var, ffi::Variant<Buffer, Expr>>& param_map);
/*!
* \brief PrimFunc specific attribute names.
*
* \sa tvm::attr
*/
namespace attr {
/*!
* \brief List of thread IterVar that a DeviceLaunch function corresponds to.
*
* Type: ffi::Array<ffi::String>
*
* We call a device kernel launch function f using the following convention:
*
* Call(f,
* [arg1, arg2, ..., arg_n,
* work_size_1, work_size_2, ... work_size_m, dyn_shmem_size])
*
* Here n = len(arg), m = len(work_size) = len(launch_params)-1.
*
* The list of kernel launch params indicates which additional
* parameters will be provided to the ffi::Function by the calling
* scope.
*
* - "threadIdx.x", "threadIdx.y", "threadIdx.z"
*
* The extent of the thread count in x/y/z, to be used when
* launching the compute kernel on the device. For example, the
* gridDimX/Y/Z parameters passed to cuLaunchKernel when launching a
* CUDA kernel, or the groupCountX/Y/Z parameters passed to
* vkCmdDispatch when dispatching a compute pipeline to Vulkan.
*
* - "blockIdx.x", "blockIdx.y", "blockIdx.z"
*
* The extent of the block iterators, to be used when launching the
* compute kernel on the device. For example, the blockDimX/Y/Z
* parameters passed to cuLaunchKernel when launching a CUDA kernel.
* For runtimes that do not require the block to be provided
* externally, this parameter is ignored. For example, the
* spv::ExecutionModeLocalSize for SPIR-V shaders on Vulkan, where
* this parameter is defined in the shader.
*
* - tvm::runtime::launch_param::kUseDynamicSharedMemoryTag
*
* The size of the shared memory that may be allocated internally by
* the kernel. For example, exposed as the
* CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES attribute in
* CUDA.
*
* Defined as "tirx.use_dyn_shared_memory".
*
* \sa tvm::CallingConv::kDeviceKernelLaunch
*/
constexpr const char* kKernelLaunchParams = "tirx.kernel_launch_params";
/*!
* \brief CUDA launch bound minimum CTAs per SM.
*
* Type: IntImm
*/
constexpr const char* kLaunchBoundsMinBlocksPerSM = "tirx.launch_bounds_min_blocks_per_sm";
/*!
* \brief Whether to set noalias rule on the function arguments.
*
* Type: IntImm
*/
constexpr const char* kNoAlias = "tirx.noalias";
/*!
* \brief Mark the function as the entry function of
* the final generated runtime module.
*
* Type: IntImm
*
* \note There can only be one entry function per module.
*/
constexpr const char* kIsEntryFunc = "tirx.is_entry_func";
/*!
* \brief Mark the function as the global function called from the host.
*
* Type: IntImm
*/
constexpr const char* kIsGlobalFunc = "tirx.is_global_func";
/*!
* \brief Mark the function as run on the host, mutually exclusive with kTarget.
*
* Type: IntImm
*/
constexpr const char* kIsHostFunc = "tirx.is_host_func";
/*!
* \brief Mark the function as scheduled, so the default schedule will pass will skip it.
*
* Type: IntImm
*/
constexpr const char* kIsScheduled = "tirx.is_scheduled";
} // namespace attr
} // namespace tirx
} // namespace tvm
#endif // TVM_TIR_FUNCTION_H_