def METHOD_NAME(x_datas, y_datas, golden_outputs, scale_and_zp, data_dtype="uint8"):
    # all x, y and golden outputs should be of the same length
    assert len(x_datas) == len(y_datas)
    assert len(y_datas) == len(golden_outputs)
    x = relay.var("x", shape=(1, 4), dtype=data_dtype)
    y = relay.var("y", shape=(1, 4), dtype=data_dtype)
    lhs_scale = relay.const(scale_and_zp["lhs_scale"], "float32")
    lhs_zp = relay.const(scale_and_zp["lhs_zp"], "int32")
    rhs_scale = relay.const(scale_and_zp["rhs_scale"], "float32")
    rhs_zp = relay.const(scale_and_zp["rhs_zp"], "int32")
    output_scale = relay.const(scale_and_zp["output_scale"], "float32")
    output_zp = relay.const(scale_and_zp["output_zp"], "int32")
    z = relay.qnn.op.subtract(
        lhs=x,
        rhs=y,
        lhs_scale=lhs_scale,
        lhs_zero_point=lhs_zp,
        rhs_scale=rhs_scale,
        rhs_zero_point=rhs_zp,
        output_scale=output_scale,
        output_zero_point=output_zp,
    )
    func = relay.Function([x, y], z)
    mod = tvm.IRModule.from_expr(func)
    mod = relay.transform.InferType()(mod)
    mod = relay.qnn.transform.CanonicalizeOps()(mod)
    func = mod["main"]
    for i in range(0, len(x_datas)):
        x_data = x_datas[i]
        y_data = y_datas[i]
        golden_output = golden_outputs[i]
        op_res = relay.create_executor("graph", device=tvm.cpu(0), target="llvm").evaluate(func)(
            x_data, y_data
        )
        np.testing.assert_equal(op_res.numpy(), golden_output)