def get_elementwise_read_backend_type(
        self,
        num_elements: int,
        dtype: str,
    ) -> str:
        """
        Get a backend type for reading in elementwise ops.
        For example, if we're dealing with fp16 and num_elements is divisible by 8,
        we can use uint4.
        """
        if dtype in ("float", "float32", "int32"):
            num_elems_to_backend_type = ((4, "uint4"), (2, "uint2"), (1, "float"))

        elif dtype == "float16":
            num_elems_to_backend_type = (
                (8, "uint4"),
                (4, "uint2"),
                (2, "uint"),
                (1, "half"),
            )
        elif dtype == "bfloat16":
            num_elems_to_backend_type = (
                (8, "uint4"),
                (4, "uint2"),
                (2, "uint"),
                (1, "bfloat16"),
            )
        elif dtype == "int64":
            num_elems_to_backend_type = (
                (2, "uint4"),
                (1, "uint2"),
            )
        else:
            raise NotImplementedError("Unsupported dtype {}!".format(dtype))

        for mod, dtype in num_elems_to_backend_type:
            if num_elements % mod == 0:
                return dtype

        raise RuntimeError(
            f"Failed to infer data type due to invalid num elems to backend type mapping: {num_elems_to_backend_type}"
        )

        Get a backend type for reading in elementwise ops.
        For example, if we're dealing with fp16 and num_elements is divisible by 8,
        we can use uint4.
        
python/aitemplate/backend/backend_spec.py