def is_valid_inputs(output_shapes, c_shapes):
    """
    Used by bmm_xxx_add ops to check whether elementwise ops
    can be fused to the bmm op via epilogue fusion. So far,
    only add ops are supported.
    """
    msg = ""
    if output_shapes == c_shapes:
        return True, msg

    def _squeeze_leading_1s(shapes):
        out = []
        if len(shapes) == 0:
            return out
        i = 0
        for shape in shapes:
            if not isinstance(shape, IntImm):
                break
            if shape.value() != 1:
                break
            i = i + 1

        out = shapes[i:]
        if len(out) == 0:
            out.append(shapes[-1])
        return out

    msg = (
        f"C can't be broadcast to the bmm output."
        f"Output shapes: {output_shapes}, C shapes: {c_shapes}"
    )
    bias_shapes = _squeeze_leading_1s(c_shapes)
    if len(bias_shapes) >= len(output_shapes):
        return False, msg

    for o_shape, c_shape in zip(reversed(output_shapes), reversed(bias_shapes)):
        if o_shape != c_shape:
            return False, msg

    return True, ""

    Used by bmm_xxx_add ops to check whether elementwise ops
    can be fused to the bmm op via epilogue fusion. So far,
    only add ops are supported.
    
python/aitemplate/compiler/ops/gemm_universal/bmm.py