()
| 110 | @pytest.mark.gpu |
| 111 | @pytest.mark.skipif(not env.has_cuda(), reason="need cuda") |
| 112 | def test_cuda_bf16_vectorize_add(): |
| 113 | if not have_bf16(tvm.cuda(0).compute_version): |
| 114 | print("skip because gpu does not support bf16") |
| 115 | return |
| 116 | num_thread = 8 |
| 117 | |
| 118 | def np_float2np_bf16(arr): |
| 119 | """Convert a numpy array of float to a numpy array |
| 120 | of bf16 in uint16""" |
| 121 | orig = arr.view("<u4") |
| 122 | bias = np.bitwise_and(np.right_shift(orig, 16), 1) + 0x7FFF |
| 123 | return np.right_shift(orig + bias, 16).astype("uint16") |
| 124 | |
| 125 | def np_bf162np_float(arr): |
| 126 | """Convert a numpy array of bf16 (uint16) to a numpy array |
| 127 | of float""" |
| 128 | u32 = np.left_shift(arr.astype("uint32"), 16) |
| 129 | return u32.view("<f4") |
| 130 | |
| 131 | def check_cuda(n, lanes): |
| 132 | vec_dtype = f"bfloat16x{lanes}" |
| 133 | num_blocks = n // num_thread |
| 134 | one = tvm.tirx.Broadcast(tvm.tirx.const(1, "bfloat16"), lanes) |
| 135 | |
| 136 | @I.ir_module(s_tir=True) |
| 137 | class Module: |
| 138 | @T.prim_func(s_tir=True) |
| 139 | def main(A: T.Buffer((n,), vec_dtype), B: T.Buffer((n,), vec_dtype)): |
| 140 | T.func_attr({"tirx.noalias": True}) |
| 141 | for i_0 in T.thread_binding(num_blocks, thread="blockIdx.x"): |
| 142 | for i_1 in T.thread_binding(num_thread, thread="threadIdx.x"): |
| 143 | with T.sblock("B"): |
| 144 | v_i = T.axis.spatial(n, i_0 * num_thread + i_1) |
| 145 | T.reads(A[v_i]) |
| 146 | T.writes(B[v_i]) |
| 147 | B[v_i] = A[v_i] + one |
| 148 | |
| 149 | with tvm.transform.PassContext( |
| 150 | disabled_pass=["tirx.BF16Promote", "tirx.BF16CastElimination", "tirx.BF16TypeLowering"] |
| 151 | ): |
| 152 | fun = tvm.compile(Module, target="cuda") |
| 153 | dev = tvm.cuda(0) |
| 154 | np_a = np.random.uniform(size=(n, lanes)).astype("float32") |
| 155 | np_a = np_bf162np_float(np_float2np_bf16(np_a)) |
| 156 | a = tvm.runtime.empty((n,), vec_dtype, dev).copyfrom(np_float2np_bf16(np_a)) |
| 157 | c = tvm.runtime.empty((n,), vec_dtype, dev) |
| 158 | fun(a, c) |
| 159 | c = tvm.runtime.empty((n, lanes), "uint16", dev).copyfrom(c) |
| 160 | tvm.testing.assert_allclose(c.numpy(), np_float2np_bf16(np_a + 1)) |
| 161 | |
| 162 | check_cuda(64, 2) |
| 163 | check_cuda(64, 4) |
| 164 | check_cuda(64, 6) |
| 165 | check_cuda(64, 8) |
| 166 | |
| 167 | |
| 168 | @pytest.mark.gpu |
nothing calls this directly
no test coverage detected
searching dependent graphs…