def gen_function(
    func_attrs,
    exec_cond_template,
    shape_eval_template,
    shape_save_template,
):
    """
    Parameters
    ----------
    func_attrs : Dict
        Stores the operation attributes.
    exec_cond_template : jinja2.Template
        Generates if statement to execute kernel.
    shape_eval_template : jinja2.Template
        Generates shape calculation.
        The template is passed from compiler/ops/pool.
    shape_save_template : jinja2.Template
        Generates output dimensions.
        The template is passed from compiler/ops/pool.

    Returns
    -------
    str
        The rendered template of generated function body.

    Raises
    ------
    NotImplementedError
        An error is raised if op_type is not max or average pooling.
    """
    op_type = func_attrs["op"]
    func_name = func_attrs["name"]
    exec_path = func_attrs["exec_path"]
    reduce_op = ""
    if "max" in op_type:
        reduce_op = "ck::ReduceTensorOp::MAX"
    elif "avg" in op_type:
        reduce_op = "ck::ReduceTensorOp::AVG"
    else:
        raise NotImplementedError
    instances = {}
    instance_decl = ""
    for key, _ in exec_path.items():
        fname = "f" + sha1(key.encode()).hexdigest()
        inst = INSTANCE_TEMPLATE.render(name=fname, reduce_func=reduce_op)
        instances[key] = inst
        instance_decl += inst
    shape_eval_func = shape_eval_template.render(
        indent="  ",
        dtype="int64_t ",
        x_dim0="*batch",
        x_dim1="*in_h",
        x_dim2="*in_w",
        x_dim3="*in_ch",
        kernel_h="kernel_h",
        kernel_w="kernel_w",
        stride="stride",
        pad="pad",
        div="/",
    )
    shape_save_func = shape_save_template.render(
        indent="  ",
        y_dim0="*out_batch",
        y_dim1="*out_h",
        y_dim2="*out_w",
        y_dim3="*in_ch",
    )
    shape_func = shape_eval_func + shape_save_func
    exec_paths = ""
    for key in instances:
        fname = "f" + sha1(key.encode()).hexdigest()
        program = EXEC_TEMPLATE.render(indent="    ", instance=fname)
        exec_inst = exec_cond_template.render(indent="  ", cond=key, program=program)
        exec_paths += exec_inst
    return SRC_TEMPLATE.render(
        instances=instance_decl,
        function_name=func_name,
        shape_function=shape_func,
        exec_paths=exec_paths,
    )
Parameters
----------
func_attrs : Dict
Stores the operation attributes.
exec_cond_template : jinja2.Template
Generates if statement to execute kernel.
shape_eval_template : jinja2.Template
Generates shape calculation.
The template is passed from compiler/ops/pool.
shape_save_template : jinja2.Template
Generates output dimensions.
The template is passed from compiler/ops/pool.

Returns
-------
str
The rendered template of generated function body.

Raises
------
NotImplementedError
An error is raised if op_type is not max or average pooling.
python/aitemplate/backend/rocm/pool2d/pool2d.py