def bind_constants(graph: List[Tensor], constants: Dict[str, TorchTensor]) -> None:
    """Bind all user-provided constants to the graph. Internally, the constants are
    represented as ConstantTensors. These can be folded, and are packaged into
    the final *.so.

    Parameters
    ----------
    graph : List[Tensor]
        Input graph
    constants : Dict[str, TorchTensor]
        Constants to bind

    """
    if not constants:
        return
    for tensor in graph:
        name = tensor._attrs["name"]
        if name not in constants:
            continue

        if tensor._attrs["data"] is not None:
            raise ValueError(f"Tensor {name} is already bound!")

        if tensor.src_ops():
            raise ValueError(f"Cannot bind non-constant tensor {name}")

        if tensor._attrs["is_input"]:
            raise ValueError(f"Cannot bind input tensor {name}")

        tensor._bind_data(_TorchConstantTensorData(constants[name]))
Bind all user-provided constants to the graph. Internally, the constants are
represented as ConstantTensors. These can be folded, and are packaged into
the final *.so.

Parameters
----------
graph : List[Tensor]
Input graph
constants : Dict[str, TorchTensor]
Constants to bind
python/aitemplate/compiler/transform/bind_constants.py