def gen_function(
    func_attrs,
    exec_cond_template,
    dim_info_dict,
    gemm_flag,
    extra_code="",
    ndims=2,
    extra_shape_template=EXTRA_SHAPE_TEMPLATE,
    problem_args_template=PROBLEM_ARGS_TEMPLATE,
    extra_header_template=EXTRA_HEADER_TEMPLATE,
    input_addr_calculator="",
    output_addr_calculator="",
):
    """Generate function body.

    Parameters
    ----------
    func_attrs : Dict
        Operation attributes.
    exec_cond_template : jinja2.Template
        Generates if statement to execute kernel.
    dim_info_dict: Dict[str, DimInfo]
        Generated from gemm._extract_dims().
        Used to store mapping between dim_names to input / output tensor dims.
    gemm_flag : str
        Flag telling which backend should be generated. options are '','bias','bias_relu','bias_add_relu'.
    extra_code : str
        Extra code for self-defined operators.
    ndims : int
        Number of dims for each parameter, 2 for gemm, 3 for bmm.
    extra_shape_template: jinja2.Template
        Shape evaluation template.
    extra_header_template: jinja2.Template
        Extra header template as we have different headers for gemm and bmm.
    input_addr_calculator : str
        Used to adjust input address based on input tensor accessors if accessors exist
    output_addr_calculator : str
        Used to adjust output address based on output tensor accessors if accessors exist


    Returns
    -------
    str
        The rendered template of generated function body.
    """
    func_name = func_attrs["name"]
    exec_path = func_attrs["exec_path"]
    op_instance = func_attrs["op_instance"]

    inst_def_flag = set()
    instances = {}
    instance_decl = ""
    has_d0_flag = has_d0(func_attrs)
    has_d1_flag = has_d1(func_attrs)
    for key, value in exec_path.items():
        fname = "f" + sha1(key.encode()).hexdigest()
        algo = value.algo
        if algo not in inst_def_flag:
            config = emit_instance(op_instance[algo])
            inst_def_flag.add(algo)
        else:
            config = ""
        inst = INSTANCE_TEMPLATE.render(
            config=config, name=fname, config_name=extract_config_name(config)
        )
        instances[key] = inst
        instance_decl += inst

    extra_shape_func = extra_shape_template.render(indent="  ")
    shape_eval_func = gemm_common.gen_shape_eval_code(
        indent=1, dtype="ck::index_t", dim_info_dict=dim_info_dict, is_ptr=True
    )
    exec_paths = ""
    for key, _ in instances.items():
        fname = "f" + sha1(key.encode()).hexdigest()
        problem_args = problem_args_template.render(
            indent="    ",
            gemm_flag=gemm_flag,
            has_d0=has_d0_flag,
            has_d1=has_d1_flag,
        )
        program = EXEC_TEMPLATE.render(
            indent="    ",
            instance=fname,
            problem_args=problem_args,
            is_profiler=False,
        )
        has_dynamic_shape = False
        for inp in func_attrs["inputs"]:
            for dim in inp.shape():
                if isinstance(dim, IntVar):
                    has_dynamic_shape = True
        if has_dynamic_shape:
            key = "true"
        exec_inst = exec_cond_template.render(indent="  ", cond=key, program=program)
        exec_paths += exec_inst
    extra_header = extra_header_template.render(
        gemm_flag=gemm_flag, has_d0=has_d0(func_attrs)
    )
    pdims = len(func_attrs["shape"]) if func_attrs.get("shape") is not None else 0
    return SRC_TEMPLATE.render(
        instances=instance_decl,
        function_name=func_name,
        shape_func=shape_eval_func,
        extra_shape=extra_shape_func,
        input_addr_calculator=input_addr_calculator,
        output_addr_calculator=output_addr_calculator,
        exec_paths=exec_paths,
        extra_code=extra_code,
        extra_header=extra_header,
        gemm_flag=gemm_flag,
        ndims=ndims,
        pdims=pdims,
        has_d0=has_d0_flag,
        has_d1=has_d1_flag,
    )
Generate function body.

Parameters
----------
func_attrs : Dict
Operation attributes.
exec_cond_template : jinja2.Template
Generates if statement to execute kernel.
dim_info_dict: Dict[str, DimInfo]
Generated from gemm._extract_dims().
Used to store mapping between dim_names to input / output tensor dims.
gemm_flag : str
Flag telling which backend should be generated. options are '','bias','bias_relu','bias_add_relu'.
extra_code : str
Extra code for self-defined operators.
ndims : int
Number of dims for each parameter, 2 for gemm, 3 for bmm.
extra_shape_template: jinja2.Template
Shape evaluation template.
extra_header_template: jinja2.Template
Extra header template as we have different headers for gemm and bmm.
input_addr_calculator : str
Used to adjust input address based on input tensor accessors if accessors exist
output_addr_calculator : str
Used to adjust output address based on output tensor accessors if accessors exist


Returns
-------
str
The rendered template of generated function body.
python/aitemplate/backend/rocm/gemm/common.py