chore: import upstream snapshot with attribution
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:25 +08:00
commit 26446540fa
3151 changed files with 974126 additions and 0 deletions
+321
View File
@@ -0,0 +1,321 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501, F841
import tempfile
import pytest
pytest.importorskip("cloudpickle") # tvm.s_tir.dlight.benchmark imports cloudpickle
import tvm.testing
from tvm.s_tir import meta_schedule as ms
from tvm.s_tir.dlight.benchmark import (
benchmark,
benchmark_prim_func,
benchmark_relax_func,
extract_from_relax,
extract_func_info_from_prim_func,
extract_prim_func,
)
from tvm.s_tir.meta_schedule.testing.local_rpc import LocalRPC
from tvm.script import ir as I
from tvm.script import relax as R
from tvm.script import tirx as T
# The test function uses an undefined symbolic var in Relax.
# In principle, this should be attached to an argument.
# pylint: disable=no-self-argument,invalid-name,line-too-long,no-method-argument
# fmt: off
@I.ir_module(check_well_formed=False, s_tir=True)
class Module:
@T.prim_func(s_tir=True)
def full1(var_T_full: T.handle):
T.func_attr({"op_pattern": 0, "tirx.noalias": True})
n = T.int64()
T_full = T.match_buffer(var_T_full, (T.int64(1), T.int64(32), T.int64(1), n), "float16")
# with T.sblock("root"):
for ax0, ax1, ax2, ax3 in T.grid(T.int64(1), T.int64(32), T.int64(1), n):
with T.sblock("T_full"):
v_ax0, v_ax1, v_ax2, v_ax3 = T.axis.remap("SSSS", [ax0, ax1, ax2, ax3])
T.reads()
T.writes(T_full[v_ax0, v_ax1, v_ax2, v_ax3])
T_full[v_ax0, v_ax1, v_ax2, v_ax3] = T.float16(1.0)
@T.prim_func(s_tir=True)
def full2(var_T_full: T.handle):
T.func_attr({"op_pattern": 0, "tirx.noalias": True})
n = T.int64()
T_full = T.match_buffer(var_T_full, (T.int64(1), T.int64(32), n, T.int64(128)), "float16")
# with T.sblock("root"):
for ax0, ax1, ax2, ax3 in T.grid(T.int64(1), T.int64(32), n, T.int64(128)):
with T.sblock("T_full"):
v_ax0, v_ax1, v_ax2, v_ax3 = T.axis.remap("SSSS", [ax0, ax1, ax2, ax3])
T.reads()
T.writes(T_full[v_ax0, v_ax1, v_ax2, v_ax3])
T_full[v_ax0, v_ax1, v_ax2, v_ax3] = T.float16(1.0)
@T.prim_func(s_tir=True)
def matmul1(var_A: T.handle, var_B: T.handle, matmul: T.Buffer((T.int64(1), T.int64(32), T.int64(1), T.int64(128)), "float16")):
T.func_attr({"op_pattern": 4, "tirx.noalias": True})
n = T.int64()
A = T.match_buffer(var_A, (T.int64(1), T.int64(32), T.int64(1), n), "float16")
B = T.match_buffer(var_B, (T.int64(1), T.int64(32), n, T.int64(128)), "float16")
# with T.sblock("root"):
for i0, i1, i2, i3, k in T.grid(T.int64(1), T.int64(32), T.int64(1), T.int64(128), n):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_i3, v_k = T.axis.remap("SSSSR", [i0, i1, i2, i3, k])
T.reads(A[v_i0, v_i1, v_i2, v_k], B[v_i0, v_i1, v_k, v_i3])
T.writes(matmul[v_i0, v_i1, v_i2, v_i3])
with T.init():
matmul[v_i0, v_i1, v_i2, v_i3] = T.float16(0)
matmul[v_i0, v_i1, v_i2, v_i3] = matmul[v_i0, v_i1, v_i2, v_i3] + A[v_i0, v_i1, v_i2, v_k] * B[v_i0, v_i1, v_k, v_i3]
@R.function
def test():
n = T.int64()
R.func_attr({"tir_var_upper_bound": {"n": 2048}})
cls = Module
with R.dataflow():
lv1 = R.call_tir(cls.full1,(), out_ty=R.Tensor((1, 32, 1, n), dtype="float16"))
lv1_1 = R.call_tir(cls.full1,(), out_ty=R.Tensor((1, 32, 1, n), dtype="float16"))
lv1_2 = R.call_tir(cls.full1,(), out_ty=R.Tensor((1, 32, 1, n), dtype="float16"))
lv2 = R.call_tir(cls.full2,(), out_ty=R.Tensor((1, 32, n, 128), dtype="float16"))
lv2_1 = R.call_tir(cls.full2,(), out_ty=R.Tensor((1, 32, n, 128), dtype="float16"))
lv3 = R.call_tir(cls.matmul1, (lv1, lv2), out_ty=R.Tensor((1, 32, 1, 128), dtype="float16"))
R.output(lv3)
return lv3
@T.prim_func(s_tir=True)
def cuda_workload(var_inp0: T.handle, inp1: T.Buffer((T.int64(4096), T.int64(4096)), "float32"), var_matmul: T.handle):
T.func_attr({"tirx.is_scheduled": True})
m = T.int64()
inp0 = T.match_buffer(var_inp0, (T.int64(1), m, T.int64(4096)))
matmul = T.match_buffer(var_matmul, (T.int64(1), m, T.int64(4096)))
# with T.sblock("root"):
matmul_reindex_pad_local = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(4096)), scope="local")
inp0_reindex_pad_shared = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(4096)), scope="shared")
inp1_reindex_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(4096), T.int64(4096)), scope="shared")
for ax0 in T.thread_binding(T.int64(1), thread="blockIdx.z"):
for ax1_0 in T.thread_binding((m + T.int64(31)) // T.int64(32), thread="blockIdx.x"):
for ax2_0 in T.thread_binding(T.int64(64), thread="blockIdx.y"):
for ax2_1 in T.thread_binding(T.int64(1), thread="vthread.y"):
for ax1_1 in T.thread_binding(T.int64(1), thread="vthread.x"):
for ax2_2 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax1_2 in T.thread_binding(T.int64(8), thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax2_3_init, ax1_3_init in T.grid(T.int64(4), T.int64(4)):
with T.sblock("matmul_init"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3_init)
v2 = T.axis.spatial(T.int64(4096), ax2_0 * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_init)
T.reads()
T.writes(matmul_reindex_pad_local[T.int64(0), v1, v2])
matmul_reindex_pad_local[T.int64(0), v1, v2] = T.float32(0)
for ax3_0 in range(T.int64(256)):
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(2)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("inp0_reindex_pad_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(inp0[v0, v1, v2])
T.writes(inp0_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
inp0_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < m, inp0[v0, v1, v2], T.float32(0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(4)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("inp1_reindex_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(4096), ax2_0 * T.int64(64) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(inp1[v2, v1])
T.writes(inp1_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
inp1_reindex_shared[v0, v1, v2] = inp1[v2, v1]
for ax3_1, ax2_3, ax1_3 in T.grid(T.int64(16), T.int64(4), T.int64(4)):
with T.sblock("matmul_update"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3)
v2 = T.axis.spatial(T.int64(4096), ax2_0 * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3)
v3 = T.axis.reduce(T.int64(4096), ax3_0 * T.int64(16) + ax3_1)
T.reads(matmul_reindex_pad_local[T.int64(0), v1, v2], inp0_reindex_pad_shared[T.int64(0), v1, v3], inp1_reindex_shared[T.int64(0), v2, v3])
T.writes(matmul_reindex_pad_local[T.int64(0), v1, v2])
matmul_reindex_pad_local[T.int64(0), v1, v2] = matmul_reindex_pad_local[T.int64(0), v1, v2] + inp0_reindex_pad_shared[T.int64(0), v1, v3] * inp1_reindex_shared[T.int64(0), v2, v3]
for ax0_1, ax1, ax2_0_1 in T.grid(T.int64(1), T.int64(4), T.int64(2)):
for ax2_1_1 in T.vectorized(T.int64(2)):
with T.sblock("matmul_reindex_pad_local"):
v0 = T.axis.spatial(T.int64(1), ax0_1)
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1)
v2 = T.axis.spatial(T.int64(4096), ax2_0 * T.int64(64) + ax2_2 * T.int64(4) + ax2_0_1 * T.int64(2) + ax2_1_1)
T.reads(matmul_reindex_pad_local[v0, v1, v2])
T.writes(matmul[T.int64(0), v1, v2])
if v1 < m:
matmul[T.int64(0), v1, v2] = matmul_reindex_pad_local[v0, v1, v2]
# fmt: on
# pylint: enable=no-self-argument,invalid-name,line-too-long,no-method-argument
@pytest.mark.skip("requires CUDA")
def test_benchmark_prim_func_rpc():
with LocalRPC() as rpc:
rpc_config = ms.runner.RPCConfig(
tracker_host=rpc.tracker_host,
tracker_port=rpc.tracker_port,
tracker_key=rpc.tracker_key,
session_priority=1,
session_timeout_sec=100,
)
input_infos, _, _ = benchmark(
cuda_workload,
args=[
((1, "m", 4096), "float32"),
((4096, 4096), "float32"),
((1, "m", 4096), "float32"),
],
dym_var_sample={"m": 128},
target="nvidia/geforce-rtx-3070",
rpc_config=rpc_config,
)
assert input_infos == [
((1, 128, 4096), "float32"),
((4096, 4096), "float32"),
((1, 128, 4096), "float32"),
]
@pytest.mark.skip("requires CUDA")
def test_benchmark_prim_func_local():
input_infos, _, _ = benchmark(
cuda_workload,
args=[
((1, "m", 4096), "float32"),
((4096, 4096), "float32"),
((1, "m", 4096), "float32"),
],
dym_var_sample={"m": 128},
target="nvidia/geforce-rtx-3070",
)
assert input_infos == [
((1, 128, 4096), "float32"),
((4096, 4096), "float32"),
((1, 128, 4096), "float32"),
]
@pytest.mark.skip("requires CUDA")
def test_benchmark_prim_func_full_local():
with tvm.target.Target("nvidia/geforce-rtx-3070"):
benchmark_prim_func(
cuda_workload,
)
@pytest.mark.skip("requires CUDA")
def test_benchmark_prim_func_full_rpc():
with LocalRPC() as rpc:
rpc_config = ms.runner.RPCConfig(
tracker_host=rpc.tracker_host,
tracker_port=rpc.tracker_port,
tracker_key=rpc.tracker_key,
session_priority=1,
session_timeout_sec=100,
)
benchmark_prim_func(
cuda_workload,
target="nvidia/geforce-rtx-3070",
rpc_config=rpc_config,
evaluator_config=ms.runner.EvaluatorConfig(
number=10,
repeat=10,
min_repeat_ms=0,
enable_cpu_cache_flush=False,
),
)
def test_benchmark_relax_func():
with tvm.target.Target({"kind": "llvm", "num-cores": 4}):
benchmark_relax_func(Module, "test")
def test_extract_prim_func_full1():
print(
extract_prim_func(
model_name="TEST",
relax_func_name="test",
prim_func_name="full1",
func=Module["full1"], # type: ignore
func_args=[((1, 32, 1, "n"), "float16")],
dym_var_dict={"n": "int32"},
weight=2,
sample_number=10,
target={"kind": "llvm", "num-cores": 4},
)
)
def test_extract_prim_func_matmul1():
print(
extract_prim_func(
model_name="TEST",
relax_func_name="test",
prim_func_name="matmul1",
func=Module["matmul1"], # type: ignore
weight=2,
sample_number=10,
target={"kind": "llvm", "num-cores": 4},
)
)
def test_extract_from_relax():
with tvm.target.Target({"kind": "llvm", "num-cores": 4}):
with tempfile.TemporaryDirectory() as filepath:
extract_from_relax(
Module,
"TEST",
file_path=filepath,
)
def test_extract_func_info_from_prim_func():
assert (
str(extract_func_info_from_prim_func(cuda_workload))
== "([((1, m, 4096), 'float32'), ((4096, 4096), 'float32'), ((1, m, 4096), 'float32')], {'m': 'int64'})"
)
assert (
str(extract_func_info_from_prim_func(Module["full1"]))
== "([((1, 32, 1, n), 'float16')], {'n': 'int64'})"
)
assert (
str(extract_func_info_from_prim_func(Module["matmul1"]))
== "([((1, 32, 1, n), 'float16'), ((1, 32, n, 128), 'float16'), ((1, 32, 1, 128), 'float16')], {'n': 'int64'})"
)
assert (
str(extract_func_info_from_prim_func(Module["full2"]))
== "([((1, 32, n, 128), 'float16')], {'n': 'int64'})"
)
if __name__ == "__main__":
tvm.testing.main()
+590
View File
@@ -0,0 +1,590 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501, F401, F841
import pytest
import tvm.testing
from tvm.s_tir import dlight as dl
from tvm.script import tirx as T
from tvm.target import Target
def test_gemv_basic():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv1637: T.Buffer((1, 32, 1, 128), "float16"), p_lv1638: T.handle, p_lv1614: T.handle, p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int32()
lv1638 = T.match_buffer(p_lv1638, (1, 32, n, 128), "float16")
lv1614 = T.match_buffer(p_lv1614, (1, 1, 1, n), "float16")
var_compute_intermediate = T.match_buffer(p_output0, (1, 32, 1, n))
# with T.sblock("root"):
var_NT_matmul_intermediate = T.sblock_alloc_buffer((1, 32, 1, n), "float16")
var_T_divide_intermediate = T.sblock_alloc_buffer((1, 32, 1, n), "float16")
var_T_maximum_intermediate = T.sblock_alloc_buffer((1, 32, 1, n), "float16")
var_T_minimum_intermediate = T.sblock_alloc_buffer((1, 32, 1, n), "float16")
for i0, i1, i2, i3, k in T.grid(1, 32, 1, n, 128):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_i3, v_k = T.axis.remap("SSSSR", [i0, i1, i2, i3, k])
T.reads(lv1637[v_i0, v_i1, v_i2, v_k], lv1638[v_i0, v_i1, v_i3, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1, v_i2, v_i3])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1, v_i2, v_i3] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1, v_i2, v_i3] = var_NT_matmul_intermediate[v_i0, v_i1, v_i2, v_i3] + lv1637[v_i0, v_i1, v_i2, v_k] * lv1638[v_i0, v_i1, v_i3, v_k]
for ax0, ax1, ax2, ax3 in T.grid(1, 32, 1, n):
with T.sblock("T_divide"):
v_ax0, v_ax1, v_ax2, v_ax3 = T.axis.remap("SSSS", [ax0, ax1, ax2, ax3])
T.reads(var_NT_matmul_intermediate[v_ax0, v_ax1, v_ax2, v_ax3])
T.writes(var_T_divide_intermediate[v_ax0, v_ax1, v_ax2, v_ax3])
var_T_divide_intermediate[v_ax0, v_ax1, v_ax2, v_ax3] = var_NT_matmul_intermediate[v_ax0, v_ax1, v_ax2, v_ax3] * T.float16(0.088397790055248615)
for ax0, ax1, ax2, ax3 in T.grid(1, 32, 1, n):
with T.sblock("T_maximum"):
v_ax0, v_ax1, v_ax2, v_ax3 = T.axis.remap("SSSS", [ax0, ax1, ax2, ax3])
T.reads(var_T_divide_intermediate[v_ax0, v_ax1, v_ax2, v_ax3])
T.writes(var_T_maximum_intermediate[v_ax0, v_ax1, v_ax2, v_ax3])
var_T_maximum_intermediate[v_ax0, v_ax1, v_ax2, v_ax3] = T.max(var_T_divide_intermediate[v_ax0, v_ax1, v_ax2, v_ax3], T.float16(-65504))
for ax0, ax1, ax2, ax3 in T.grid(1, 32, 1, n):
with T.sblock("T_minimum"):
v_ax0, v_ax1, v_ax2, v_ax3 = T.axis.remap("SSSS", [ax0, ax1, ax2, ax3])
T.reads(var_T_maximum_intermediate[v_ax0, v_ax1, v_ax2, v_ax3], lv1614[v_ax0, 0, v_ax2, v_ax3])
T.writes(var_T_minimum_intermediate[v_ax0, v_ax1, v_ax2, v_ax3])
var_T_minimum_intermediate[v_ax0, v_ax1, v_ax2, v_ax3] = T.min(var_T_maximum_intermediate[v_ax0, v_ax1, v_ax2, v_ax3], lv1614[v_ax0, 0, v_ax2, v_ax3])
for i0, i1, i2, i3 in T.grid(1, 32, 1, n):
with T.sblock("compute"):
v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSS", [i0, i1, i2, i3])
T.reads(var_T_minimum_intermediate[v_i0, v_i1, v_i2, v_i3])
T.writes(var_compute_intermediate[v_i0, v_i1, v_i2, v_i3])
var_compute_intermediate[v_i0, v_i1, v_i2, v_i3] = T.Cast("float32", var_T_minimum_intermediate[v_i0, v_i1, v_i2, v_i3])
@T.prim_func(private=True, s_tir=True)
def expected(lv1637: T.Buffer((1, 32, 1, 128), "float16"), p_lv1638: T.handle, p_lv1614: T.handle, p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int32()
lv1638 = T.match_buffer(p_lv1638, (1, 32, n, 128), "float16")
lv1614 = T.match_buffer(p_lv1614, (1, 1, 1, n), "float16")
var_compute_intermediate = T.match_buffer(p_output0, (1, 32, 1, n))
# with T.sblock("root"):
var_NT_matmul_intermediate = T.sblock_alloc_buffer((1, 32, 1, n), "float16")
for ax0_fused in range(32):
for ax1_fused_0 in T.parallel((n + 63) // 64):
for ax1_fused_1 in T.vectorized(64):
for ax2_fused_0 in T.serial(2, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax2_fused_1, u_0, u_1 in T.grid(64, 1, 1):
with T.sblock("NT_matmul"):
v0 = T.axis.spatial(32, ax0_fused)
v1 = T.axis.spatial(n, ax1_fused_0 * 64 + ax1_fused_1)
v2 = T.axis.reduce(128, ax2_fused_0 * 64 + ax2_fused_1)
T.where(ax1_fused_0 * 64 + ax1_fused_1 < n)
T.reads(lv1637[0, v0, 0, v2], lv1638[0, v0, v1, v2])
T.writes(var_NT_matmul_intermediate[0, v0, 0, v1])
with T.init():
var_NT_matmul_intermediate[0, v0, 0, v1] = T.float16(0.0)
var_NT_matmul_intermediate[0, v0, 0, v1] = var_NT_matmul_intermediate[0, v0, 0, v1] + lv1637[0, v0, 0, v2] * lv1638[0, v0, v1, v2]
for ax0, ax1 in T.grid(32, n):
with T.sblock("compute"):
v0, v1 = T.axis.remap("SS", [ax0, ax1])
T.reads(var_NT_matmul_intermediate[0, v0, 0, v1], lv1614[0, 0, 0, v1])
T.writes(var_compute_intermediate[0, v0, 0, v1])
var_compute_intermediate[0, v0, 0, v1] = T.Cast("float32", T.min(T.max(var_NT_matmul_intermediate[0, v0, 0, v1] * T.float16(0.088397790055248615), T.float16(-65504.0)), lv1614[0, 0, 0, v1]))
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_decode_gemv_256_threads():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv571: T.Buffer((22016, 512), "uint32"), lv572: T.Buffer((22016, 128), "float16"), lv1654: T.Buffer((1, 1, 4096), "float16"), var_NT_matmul_intermediate: T.Buffer((1, 1, 22016), "float16")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
p_output0_intermediate = T.sblock_alloc_buffer((22016, 4096), "float16")
for i, j in T.grid(22016, 4096):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv571[v_i, v_j // 8], lv572[v_i, v_j // 32])
T.writes(p_output0_intermediate[v_i, v_j])
p_output0_intermediate[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv571[v_i, v_j // 8], T.Cast("uint32", v_j % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv572[v_i, v_j // 32]
for i0, i1, i2, k in T.grid(1, 1, 22016, 4096):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv1654[v_i0, v_i1, v_k], p_output0_intermediate[v_i2, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = var_NT_matmul_intermediate[v_i0, v_i1, v_i2] + lv1654[v_i0, v_i1, v_k] * p_output0_intermediate[v_i2, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(lv571: T.Buffer((22016, 512), "uint32"), lv572: T.Buffer((22016, 128), "float16"), lv1654: T.Buffer((1, 1, 4096), "float16"), var_NT_matmul_intermediate: T.Buffer((1, 1, 22016), "float16")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
for u_fused in range(1):
for ax0_fused_0 in T.parallel(172):
for ax0_fused_1 in T.vectorized(128):
for ax1_0_fused_0 in T.serial(8, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0_fused_1, ax1_1_0, ax1_1_1 in T.grid(64, 1, 8):
with T.sblock("NT_matmul"):
v0 = T.axis.spatial(22016, ax0_fused_0 * 128 + ax0_fused_1)
v1 = T.axis.reduce(4096, ax1_0_fused_0 * 512 + ax1_0_fused_1 * 8 + ax1_1_0 * 8 + ax1_1_1)
T.reads(lv1654[0, 0, v1], lv571[v0, v1 // 8], lv572[v0, v1 // 32])
T.writes(var_NT_matmul_intermediate[0, 0, v0])
with T.init():
var_NT_matmul_intermediate[0, 0, v0] = T.float16(0.0)
var_NT_matmul_intermediate[0, 0, v0] = var_NT_matmul_intermediate[0, 0, v0] + lv1654[0, 0, v1] * ((T.Cast("float16", T.bitwise_and(T.shift_right(lv571[v0, v1 // 8], T.Cast("uint32", v1 % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7.0)) * lv572[v0, v1 // 32])
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_decode_gemv1():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv571: T.Buffer((22016, 512), "uint32"), lv572: T.Buffer((22016, 128), "float16"), lv1654: T.Buffer((1, 1, 4096), "float16"), var_NT_matmul_intermediate: T.Buffer((1, 1, 22016), "float16")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
p_output0_intermediate = T.sblock_alloc_buffer((22016, 4096), "float16")
for i, j in T.grid(22016, 4096):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv571[v_i, v_j // 8], lv572[v_i, v_j // 32])
T.writes(p_output0_intermediate[v_i, v_j])
p_output0_intermediate[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv571[v_i, v_j // 8], T.Cast("uint32", v_j % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv572[v_i, v_j // 32]
for i0, i1, i2, k in T.grid(1, 1, 22016, 4096):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv1654[v_i0, v_i1, v_k], p_output0_intermediate[v_i2, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = var_NT_matmul_intermediate[v_i0, v_i1, v_i2] + lv1654[v_i0, v_i1, v_k] * p_output0_intermediate[v_i2, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(lv571: T.Buffer((22016, 512), "uint32"), lv572: T.Buffer((22016, 128), "float16"), lv1654: T.Buffer((1, 1, 4096), "float16"), var_NT_matmul_intermediate: T.Buffer((1, 1, 22016), "float16")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
for u_fused in range(1):
for ax0_fused_0 in T.parallel(172):
for ax0_fused_1 in T.vectorized(128):
for ax1_0_fused_0 in T.serial(8, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0_fused_1, ax1_1_0, ax1_1_1 in T.grid(64, 1, 8):
with T.sblock("NT_matmul"):
v0 = T.axis.spatial(22016, ax0_fused_0 * 128 + ax0_fused_1)
v1 = T.axis.reduce(4096, ax1_0_fused_0 * 512 + ax1_0_fused_1 * 8 + ax1_1_0 * 8 + ax1_1_1)
T.reads(lv1654[0, 0, v1], lv571[v0, v1 // 8], lv572[v0, v1 // 32])
T.writes(var_NT_matmul_intermediate[0, 0, v0])
with T.init():
var_NT_matmul_intermediate[0, 0, v0] = T.float16(0.0)
var_NT_matmul_intermediate[0, 0, v0] = var_NT_matmul_intermediate[0, 0, v0] + lv1654[0, 0, v1] * ((T.Cast("float16", T.bitwise_and(T.shift_right(lv571[v0, v1 // 8], T.Cast("uint32", v1 % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7.0)) * lv572[v0, v1 // 32])
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_decode_gemv2():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv771: T.Buffer((32000, 512), "uint32"), lv772: T.Buffer((32000, 128), "float16"), lv3216: T.Buffer((1, 1, 4096), "float16"), p_output0_intermediate: T.Buffer((1, 1, 32000), "float32")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((32000, 4096), "float16")
var_NT_matmul_intermediate = T.sblock_alloc_buffer((1, 1, 32000), "float16")
for i, j in T.grid(32000, 4096):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv771[v_i, v_j // 8], lv772[v_i, v_j // 32])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv771[v_i, v_j // 8], T.Cast("uint32", v_j % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv772[v_i, v_j // 32]
for i0, i1, i2, k in T.grid(1, 1, 32000, 4096):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv3216[v_i0, v_i1, v_k], p_output0_intermediate_1[v_i2, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = var_NT_matmul_intermediate[v_i0, v_i1, v_i2] + lv3216[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_i2, v_k]
for i0, i1, i2 in T.grid(1, 1, 32000):
with T.sblock("compute"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
T.writes(p_output0_intermediate[v_i0, v_i1, v_i2])
p_output0_intermediate[v_i0, v_i1, v_i2] = T.Cast("float32", var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
@T.prim_func(private=True, s_tir=True)
def expected(lv771: T.Buffer((32000, 512), "uint32"), lv772: T.Buffer((32000, 128), "float16"), lv3216: T.Buffer((1, 1, 4096), "float16"), p_output0_intermediate: T.Buffer((1, 1, 32000), "float32")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
var_NT_matmul_intermediate = T.sblock_alloc_buffer((1, 1, 32000), "float16")
for u_fused in range(1):
for ax0_fused_0 in T.parallel(250):
for ax0_fused_1 in T.vectorized(128):
for ax1_0_fused_0 in T.serial(8, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0_fused_1, ax1_1_0, ax1_1_1 in T.grid(64, 1, 8):
with T.sblock("NT_matmul"):
v0 = T.axis.spatial(32000, ax0_fused_0 * 128 + ax0_fused_1)
v1 = T.axis.reduce(4096, ax1_0_fused_0 * 512 + ax1_0_fused_1 * 8 + ax1_1_0 * 8 + ax1_1_1)
T.reads(lv3216[0, 0, v1], lv771[v0, v1 // 8], lv772[v0, v1 // 32])
T.writes(var_NT_matmul_intermediate[0, 0, v0])
with T.init():
var_NT_matmul_intermediate[0, 0, v0] = T.float16(0.0)
var_NT_matmul_intermediate[0, 0, v0] = var_NT_matmul_intermediate[0, 0, v0] + lv3216[0, 0, v1] * ((T.Cast("float16", T.bitwise_and(T.shift_right(lv771[v0, v1 // 8], T.Cast("uint32", v1 % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7.0)) * lv772[v0, v1 // 32])
for ax0 in range(32000):
with T.sblock("compute"):
v0 = T.axis.spatial(32000, ax0)
T.reads(var_NT_matmul_intermediate[0, 0, v0])
T.writes(p_output0_intermediate[0, 0, v0])
p_output0_intermediate[0, 0, v0] = T.Cast("float32", var_NT_matmul_intermediate[0, 0, v0])
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_decode_gemv3():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv575: T.Buffer((T.int64(4096), T.int64(1376)), "uint32"), lv576: T.Buffer((T.int64(4096), T.int64(344)), "float16"), lv574: T.Buffer((T.int64(1), T.int64(1), T.int64(11008)), "float16"), lv570: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16"), p_output0_intermediate: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((T.int64(4096), T.int64(11008)), "float16")
var_NT_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16")
for i, j in T.grid(T.int64(4096), T.int64(11008)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv575[v_i, v_j // T.int64(8)], lv576[v_i, v_j // T.int64(32)])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv575[v_i, v_j // T.int64(8)], T.Cast("uint32", v_j % T.int64(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv576[v_i, v_j // T.int64(32)]
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(1), T.int64(4096), T.int64(11008)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv574[v_i0, v_i1, v_k], p_output0_intermediate_1[v_i2, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = var_NT_matmul_intermediate[v_i0, v_i1, v_i2] + lv574[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_i2, v_k]
for ax0, ax1, ax2 in T.grid(T.int64(1), T.int64(1), T.int64(4096)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(lv570[v_ax0, v_ax1, v_ax2], var_NT_matmul_intermediate[v_ax0, v_ax1, v_ax2])
T.writes(p_output0_intermediate[v_ax0, v_ax1, v_ax2])
p_output0_intermediate[v_ax0, v_ax1, v_ax2] = lv570[v_ax0, v_ax1, v_ax2] + var_NT_matmul_intermediate[v_ax0, v_ax1, v_ax2]
@T.prim_func(private=True, s_tir=True)
def expected(lv575: T.Buffer((T.int64(4096), T.int64(1376)), "uint32"), lv576: T.Buffer((T.int64(4096), T.int64(344)), "float16"), lv574: T.Buffer((T.int64(1), T.int64(1), T.int64(11008)), "float16"), lv570: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16"), p_output0_intermediate: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
var_NT_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16")
for u_fused in range(1):
for ax0_fused_0 in T.parallel(T.int64(64)):
for ax0_fused_1 in T.vectorized(T.int64(64)):
for ax1_0_fused_0 in T.serial(T.int64(11), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0_fused_1, ax1_1_0, ax1_1_1 in T.grid(T.int64(128), T.int64(1), T.int64(8)):
with T.sblock("NT_matmul"):
v0 = T.axis.spatial(T.int64(4096), ax0_fused_0 * T.int64(64) + ax0_fused_1)
v1 = T.axis.reduce(T.int64(11008), (ax1_0_fused_0 * T.int64(128) + ax1_0_fused_1) * T.int64(8) + ax1_1_0 * T.int64(8) + ax1_1_1)
T.where(ax1_0_fused_0 * T.int64(128) + ax1_0_fused_1 < T.int64(1376))
T.reads(lv574[T.int64(0), T.int64(0), v1], lv575[v0, v1 // T.int64(8)], lv576[v0, v1 // T.int64(32)])
T.writes(var_NT_matmul_intermediate[T.int64(0), T.int64(0), v0])
with T.init():
var_NT_matmul_intermediate[T.int64(0), T.int64(0), v0] = T.float16(0.0)
var_NT_matmul_intermediate[T.int64(0), T.int64(0), v0] = var_NT_matmul_intermediate[T.int64(0), T.int64(0), v0] + lv574[T.int64(0), T.int64(0), v1] * ((T.Cast("float16", T.bitwise_and(T.shift_right(lv575[v0, v1 // T.int64(8)], T.Cast("uint32", v1 % T.int64(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7.0)) * lv576[v0, v1 // T.int64(32)])
for ax0 in range(T.int64(4096)):
with T.sblock("T_add"):
v0 = T.axis.spatial(T.int64(4096), ax0)
T.reads(lv570[T.int64(0), T.int64(0), v0], var_NT_matmul_intermediate[T.int64(0), T.int64(0), v0])
T.writes(p_output0_intermediate[T.int64(0), T.int64(0), v0])
p_output0_intermediate[T.int64(0), T.int64(0), v0] = lv570[T.int64(0), T.int64(0), v0] + var_NT_matmul_intermediate[T.int64(0), T.int64(0), v0]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_autogptq_decode_gemv():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def func(lv9: T.Buffer((T.int64(512), T.int64(4096)), "uint32"), lv10: T.Buffer((T.int64(32), T.int64(512)), "uint32"), lv11: T.Buffer((T.int64(32), T.int64(4096)), "float16"), lv12: T.Buffer((T.int64(4096),), "uint32"), lv8: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16"), lv1613: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16"), p_output0_intermediate: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
decode_intermediate = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)), "float16")
var_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16")
for i, j in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv9[v_i // T.int64(8), v_j], lv10[lv12[v_i], v_j // T.int64(8)], lv12[v_i], lv11[lv12[v_i], v_j])
T.writes(decode_intermediate[v_i, v_j])
decode_intermediate[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv9[v_i // T.int64(8), v_j], T.Cast("uint32", v_i % T.int64(8) * T.int64(4))), T.uint32(15))) - (T.Cast("float16", T.bitwise_and(T.shift_right(lv10[lv12[v_i], v_j // T.int64(8)], T.Cast("uint32", v_j % T.int64(8) * T.int64(4))), T.uint32(15))) + T.float16(1))) * lv11[lv12[v_i], v_j]
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(1), T.int64(4096), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv8[v_i0, v_i1, v_k], decode_intermediate[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + lv8[v_i0, v_i1, v_k] * decode_intermediate[v_k, v_i2]
for ax0, ax1, ax2 in T.grid(T.int64(1), T.int64(1), T.int64(4096)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(lv1613[v_ax0, v_ax1, v_ax2], var_matmul_intermediate[v_ax0, v_ax1, v_ax2])
T.writes(p_output0_intermediate[v_ax0, v_ax1, v_ax2])
p_output0_intermediate[v_ax0, v_ax1, v_ax2] = lv1613[v_ax0, v_ax1, v_ax2] + var_matmul_intermediate[v_ax0, v_ax1, v_ax2]
# fmt: on
# The GeMV rule does not yet support the inner dim being grouped.
# So the rule is expected to skip transforming this function.
mod = tvm.IRModule({"main": func})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], func)
def test_outer_reduction_adreno():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(
lv575: T.Buffer((1376, 4096), "uint32"),
lv576: T.Buffer((344, 4096), "float16"),
lv574: T.Buffer((1, 1, 11008), "float16"),
lv570: T.Buffer((1, 1, 4096), "float16"),
p_output0_intermediate: T.Buffer((1, 1, 4096), "float16"),
):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((11008, 4096), "float16")
var_matmul_intermediate = T.sblock_alloc_buffer((1, 1, 4096), "float16")
for i, j in T.grid(11008, 4096):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv575[v_i // 8, v_j], T.Cast("uint32", v_i % 8) * T.uint32(4)), T.uint32(15)))- T.float16(7)) * lv576[v_i // 32, v_j]
for i0, i1, i2, k in T.grid(1, 1, 4096, 11008):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + lv574[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_k, v_i2]
for ax0, ax1, ax2 in T.grid(1, 1, 4096):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
p_output0_intermediate[v_ax0, v_ax1, v_ax2] = lv570[v_ax0, v_ax1, v_ax2] + var_matmul_intermediate[v_ax0, v_ax1, v_ax2]
@T.prim_func(private=True, s_tir=True)
def expected(lv575: T.Buffer((1376, 4096), "uint32"), lv576: T.Buffer((344, 4096), "float16"), lv574: T.Buffer((1, 1, 11008), "float16"), lv570: T.Buffer((1, 1, 4096), "float16"), p_output0_intermediate: T.Buffer((1, 1, 4096), "float16")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((11008, 4096), "float16")
var_matmul_intermediate = T.sblock_alloc_buffer((1, 1, 4096), "float16")
for i, j in T.grid(11008, 4096):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv575[v_i // 8, v_j], lv576[v_i // 32, v_j])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv575[v_i // 8, v_j], T.Cast("uint32", v_i % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7.0)) * lv576[v_i // 32, v_j]
for i0, i1, i2, k in T.grid(1, 1, 4096, 11008):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv574[v_i0, v_i1, v_k], p_output0_intermediate_1[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0.0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + lv574[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_k, v_i2]
for ax0, ax1, ax2 in T.grid(1, 1, 4096):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(lv570[v_ax0, v_ax1, v_ax2], var_matmul_intermediate[v_ax0, v_ax1, v_ax2])
T.writes(p_output0_intermediate[v_ax0, v_ax1, v_ax2])
p_output0_intermediate[v_ax0, v_ax1, v_ax2] = lv570[v_ax0, v_ax1, v_ax2] + var_matmul_intermediate[v_ax0, v_ax1, v_ax2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_outer_reduction_adreno_dynamic():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(p_lv612: T.handle, p_lv613: T.handle, lv1607: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16"), p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
v = T.int64()
lv612 = T.match_buffer(p_lv612, (T.int64(512), v), "uint32")
lv613 = T.match_buffer(p_lv613, (T.int64(128), v), "float16")
p_output0_intermediate = T.match_buffer(p_output0, (T.int64(1), T.int64(1), v))
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((T.int64(4096), v), "float16")
var_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(1), v), "float16")
for i, j in T.grid(T.int64(4096), v):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv612[v_i // T.int64(8), v_j], lv613[v_i // T.int64(32), v_j])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv612[v_i // T.int64(8), v_j], T.Cast("uint32", v_i % T.int64(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv613[v_i // T.int64(32), v_j]
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(1), v, T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv1607[v_i0, v_i1, v_k], p_output0_intermediate_1[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + lv1607[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_k, v_i2]
for i0, i1, i2 in T.grid(T.int64(1), T.int64(1), v):
with T.sblock("compute"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(var_matmul_intermediate[v_i0, v_i1, v_i2])
T.writes(p_output0_intermediate[v_i0, v_i1, v_i2])
p_output0_intermediate[v_i0, v_i1, v_i2] = T.Cast("float32", var_matmul_intermediate[v_i0, v_i1, v_i2])
@T.prim_func(private=True, s_tir=True)
def expected(p_lv612: T.handle, p_lv613: T.handle, lv1607: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float16"), p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
v = T.int64()
lv612 = T.match_buffer(p_lv612, (T.int64(512), v), "uint32")
lv613 = T.match_buffer(p_lv613, (T.int64(128), v), "float16")
p_output0_intermediate = T.match_buffer(p_output0, (T.int64(1), T.int64(1), v))
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((T.int64(4096), v), "float16")
var_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(1), v), "float16")
for i, j in T.grid(T.int64(4096), v):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv612[v_i // T.int64(8), v_j], lv613[v_i // T.int64(32), v_j])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv612[v_i // T.int64(8), v_j], T.Cast("uint32", v_i % T.int64(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7.0)) * lv613[v_i // T.int64(32), v_j]
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(1), v, T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv1607[v_i0, v_i1, v_k], p_output0_intermediate_1[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0.0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + lv1607[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_k, v_i2]
for i0, i1, i2 in T.grid(T.int64(1), T.int64(1), v):
with T.sblock("compute"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(var_matmul_intermediate[v_i0, v_i1, v_i2])
T.writes(p_output0_intermediate[v_i0, v_i1, v_i2])
p_output0_intermediate[v_i0, v_i1, v_i2] = T.Cast("float32", var_matmul_intermediate[v_i0, v_i1, v_i2])
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_blockized_gemv():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(x: T.Buffer((1, 4096), "float16"), w: T.Buffer((8, 16384, 4096), "float16"), indptr: T.Buffer((2,), "int32"), o: T.Buffer((2, 16384), "float16")):
# with T.sblock("root"):
for expert_id in T.thread_binding(2, thread="blockIdx.y"):
with T.sblock("gemv_o"):
v_expert_id_o = T.axis.spatial(2, expert_id)
vi_o = T.axis.spatial(1, 0)
vj_o = T.axis.reduce(1, 0)
T.reads(x[0, 0:4096], w[indptr[v_expert_id_o], 0:16384, 0:4096], indptr[v_expert_id_o])
T.writes(o[v_expert_id_o, 0:16384])
for i, j in T.grid(16384, 4096):
with T.sblock("gemv"):
vi_i, vj_i = T.axis.remap("SR", [i, j])
T.reads(x[0, vj_i], w[indptr[v_expert_id_o], vi_i, vj_i], indptr[v_expert_id_o])
T.writes(o[v_expert_id_o, vi_i])
with T.init():
o[v_expert_id_o, vi_i] = T.float16(0)
o[v_expert_id_o, vi_i] = o[v_expert_id_o, vi_i] + x[0, vj_i] * w[indptr[v_expert_id_o], vi_i, vj_i]
@T.prim_func(private=True, s_tir=True)
def expected(x: T.Buffer((1, 4096), "float16"), w: T.Buffer((8, 16384, 4096), "float16"), indptr: T.Buffer((2,), "int32"), o: T.Buffer((2, 16384), "float16")):
T.func_attr({"tirx.is_scheduled": True})
# with T.sblock("root"):
for expert_id in T.thread_binding(2, thread="blockIdx.y"):
with T.sblock("gemv_o"):
v_expert_id_o = T.axis.spatial(2, expert_id)
vi_o = T.axis.spatial(1, 0)
vj_o = T.axis.reduce(1, 0)
T.reads(x[0, 0:4096], w[indptr[v_expert_id_o], 0:16384, 0:4096], indptr[v_expert_id_o])
T.writes(o[v_expert_id_o, 0:16384])
for u_fused in range(1):
for ax0_fused_0 in T.parallel(128):
for ax0_fused_1 in T.vectorized(128):
for ax1_fused_0 in T.serial(64, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_fused_1, u_0, u_1 in T.grid(64, 1, 1):
with T.sblock("gemv"):
v0 = T.axis.spatial(16384, ax0_fused_0 * 128 + ax0_fused_1)
v1 = T.axis.reduce(4096, ax1_fused_0 * 64 + ax1_fused_1)
T.reads(x[0, v1], w[indptr[v_expert_id_o], v0, v1], indptr[v_expert_id_o])
T.writes(o[v_expert_id_o, v0])
with T.init():
o[v_expert_id_o, v0] = T.float16(0.0)
o[v_expert_id_o, v0] = o[v_expert_id_o, v0] + x[0, v1] * w[indptr[v_expert_id_o], v0, v1]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_func_to_skip():
@T.prim_func(s_tir=True)
def before(var_A: T.handle, var_exclusive_scan_thrust: T.handle, seq_len: T.int64):
data_buf = T.match_buffer(var_A, (seq_len * T.int64(8),), "int32", align=8)
output_buf = T.match_buffer(
var_exclusive_scan_thrust, (seq_len * T.int64(8),), "int32", align=8
)
with T.sblock("exclusive_scan_thrust"):
T.reads()
T.writes()
T.call_packed(
"tvm.contrib.thrust.sum_scan",
T.tvm_stack_make_array(
data_buf.data, T.tvm_stack_make_shape(seq_len * T.int64(8)), 0, 1, 0, T.int64(0)
),
T.tvm_stack_make_array(
output_buf.data,
T.tvm_stack_make_shape(seq_len * T.int64(8)),
0,
1,
0,
T.int64(0),
),
T.bool(False),
)
# This function should be skipped.
mod = tvm.IRModule({"main": before})
with Target("llvm"):
mod = dl.ApplyDefaultSchedule(dl.cpu.GEMV())(mod)
tvm.ir.assert_structural_equal(mod["main"], before)
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,275 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
"""Tests for CPU DLight Reduction schedule rule."""
import pytest
import tvm
import tvm.testing
from tvm import te, tirx, topi
from tvm.s_tir import dlight as dl
from tvm.s_tir.dlight.cpu import Reduction
from tvm.target import Target
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _llvm_target():
return Target({"kind": "llvm"})
def _rvv_target():
return Target(
{
"kind": "llvm",
"mtriple": "riscv64-linux-gnu",
"mcpu": "generic-rv64",
"mabi": "lp64d",
"mattr": ["+64bit", "+m", "+a", "+f", "+d", "+c", "+v"],
}
)
def _build_softmax(batch, features, fast=False):
A = te.placeholder((batch, features), dtype="float32", name="A")
B = topi.nn.fast_softmax(A, axis=1) if fast else topi.nn.softmax(A, axis=1)
func = te.create_prim_func([A, B])
return tvm.IRModule({"main": func})
def _apply_and_check(mod, target):
"""Apply Reduction rule and verify it was applied."""
rule = Reduction()
result = rule.apply(mod["main"], target, False)
assert result is not None, "Reduction rule should apply"
return result
# ---------------------------------------------------------------------------
# Test: schedule applicability
# ---------------------------------------------------------------------------
@pytest.mark.parametrize("fast", [False, True], ids=["softmax", "fast_softmax"])
@pytest.mark.parametrize(
"batch,features",
[
(1, 10),
(1, 128),
(14, 185),
(32, 256),
(64, 512),
(128, 1024),
(1, 30522),
],
)
def test_reduction_applies(batch, features, fast):
"""Reduction rule should apply to softmax/fast_softmax of various shapes."""
mod = _build_softmax(batch, features, fast=fast)
target = _llvm_target()
_apply_and_check(mod, target)
# ---------------------------------------------------------------------------
# Test: scheduled TIR structure
# ---------------------------------------------------------------------------
def test_softmax_schedule_structure():
"""Verify the scheduled TIR has expected structure:
- parallel on batch axis
- vectorized innermost loops for injective blocks
- split+unroll for reduction blocks
"""
mod = _build_softmax(14, 185, fast=False)
target = _llvm_target()
sch = _apply_and_check(mod, target)
scheduled_mod = sch.mod
# Check that tirx.is_scheduled is NOT set (only set by ApplyDefaultSchedule)
# but the schedule should be valid
assert scheduled_mod is not None
# Verify via ApplyDefaultSchedule path
with target:
scheduled = dl.ApplyDefaultSchedule(Reduction())(mod)
func = scheduled["main"]
# Check tirx.is_scheduled is set
assert func.attrs and func.attrs.get("tirx.is_scheduled", False)
def test_fast_softmax_schedule_structure():
"""fast_softmax should keep T_fast_exp as a separate vectorizable block."""
mod = _build_softmax(14, 185, fast=True)
target = _llvm_target()
sch = _apply_and_check(mod, target)
script = str(sch.mod)
# fast_exp block should exist (not inlined)
assert "T_fast_exp" in script or "T_softmax_delta" in script
# Should have T.parallel
assert "T.parallel" in script
# Should have T.vectorized
assert "T.vectorized" in script
# ---------------------------------------------------------------------------
# Test: LLVM IR quality (cross-compile to RISC-V RVV)
# ---------------------------------------------------------------------------
def _codegen_llvm_ir(mod, target):
"""Lower and codegen to LLVM IR (no linking)."""
bound = tirx.transform.BindTarget(target.with_host(target))(mod)
pipeline, finalize_host, _ = tirx.get_tir_pipeline("default")
lowered = pipeline(bound)
from tvm.tirx.build import split_host_device_mods
host_mod, _ = split_host_device_mods(lowered)
host_mod = finalize_host()(host_mod)
built = tvm.target.codegen.build_module(host_mod, target)
return built.inspect_source("ll")
def _codegen_asm(mod, target):
"""Lower and codegen to assembly (no linking)."""
bound = tirx.transform.BindTarget(target.with_host(target))(mod)
pipeline, finalize_host, _ = tirx.get_tir_pipeline("default")
lowered = pipeline(bound)
from tvm.tirx.build import split_host_device_mods
host_mod, _ = split_host_device_mods(lowered)
host_mod = finalize_host()(host_mod)
built = tvm.target.codegen.build_module(host_mod, target)
return built.inspect_source("s")
@pytest.mark.parametrize("fast", [False, True], ids=["softmax", "fast_softmax"])
def test_rvv_code_size_reduction(fast):
"""Scheduled RVV code should be smaller than unscheduled.
The original issue (apache/tvm#18569) shows RVV softmax is 1.34x slower
than scalar, partly due to LLVM generating bloated code with excessive
unrolling. The schedule should reduce code size significantly.
"""
target = _rvv_target()
mod = _build_softmax(14, 185, fast=fast)
# Unscheduled
ir_unsched = _codegen_llvm_ir(mod, target)
n_unsched = len(ir_unsched.splitlines())
# Scheduled
with target:
mod_sched = dl.ApplyDefaultSchedule(Reduction())(mod)
ir_sched = _codegen_llvm_ir(mod_sched, target)
n_sched = len(ir_sched.splitlines())
# Scheduled should be meaningfully smaller (at least 30% reduction)
ratio = n_sched / n_unsched
assert ratio < 0.75, (
f"Expected >=25% code reduction, got {(1 - ratio) * 100:.1f}% "
f"({n_unsched} -> {n_sched} lines)"
)
# The arith analyzer no longer proves vscale-bearing inequalities via
# substitution (CanProveVscaleExpressionFromKnownValues was deleted). This
# weakens simplification of scalable-vector index expressions, which can
# prevent the RVV vectorization schedule from producing scalable vector ops.
@pytest.mark.xfail(reason="arith no longer proves vscale-bearing inequalities via substitution")
def test_rvv_fast_softmax_vectorizes_exp():
"""fast_softmax + schedule should produce RVV vector instructions
for the polynomial exp approximation (no scalar exp calls)."""
target = _rvv_target()
mod = _build_softmax(14, 185, fast=True)
with target:
mod_sched = dl.ApplyDefaultSchedule(Reduction())(mod)
ir = _codegen_llvm_ir(mod_sched, target)
# Should have zero scalar exp calls (fast_exp uses polynomial)
scalar_exp = sum(1 for line in ir.splitlines() if "llvm.exp.f32" in line)
assert scalar_exp == 0, f"Expected 0 scalar exp calls, got {scalar_exp}"
# Should have scalable vector operations
n_svec = ir.count("<vscale x")
assert n_svec > 0, "Expected scalable vector operations in LLVM IR"
def test_rvv_asm_instruction_reduction():
"""Scheduled RVV assembly should have fewer total instructions
than both unscheduled RVV and scalar RV."""
rvv = _rvv_target()
rv = Target(
{
"kind": "llvm",
"mtriple": "riscv64-linux-gnu",
"mcpu": "generic-rv64",
"mabi": "lp64d",
"mattr": ["+64bit", "+m", "+a", "+f", "+d", "+c"],
}
)
mod = _build_softmax(14, 185, fast=True)
# Scalar baseline
asm_rv = _codegen_asm(mod, rv)
n_rv = len(
[
line
for line in asm_rv.splitlines()
if line.strip() and not line.strip().startswith((".", "#", "/"))
]
)
# RVV unscheduled
asm_rvv = _codegen_asm(mod, rvv)
n_rvv = len(
[
line
for line in asm_rvv.splitlines()
if line.strip() and not line.strip().startswith((".", "#", "/"))
]
)
# RVV scheduled
with rvv:
mod_sched = dl.ApplyDefaultSchedule(Reduction())(mod)
asm_sched = _codegen_asm(mod_sched, rvv)
n_sched = len(
[
line
for line in asm_sched.splitlines()
if line.strip() and not line.strip().startswith((".", "#", "/"))
]
)
# Scheduled should be smaller than both unscheduled RVV and scalar
assert n_sched < n_rvv, (
f"Scheduled ({n_sched}) should have fewer instructions than unscheduled RVV ({n_rvv})"
)
assert n_sched <= n_rv * 1.1, (
f"Scheduled ({n_sched}) should not be much larger than scalar RV ({n_rv})"
)
if __name__ == "__main__":
pytest.main([__file__, "-v"])
+112
View File
@@ -0,0 +1,112 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501
import tvm
import tvm.testing
from tvm.s_tir import dlight as dl
from tvm.script import tirx as T
from tvm.target import Target
def test_conv3d():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(
A: T.Buffer((14308, 3, 2, 14, 14), "float16"),
W: T.Buffer((1280, 3, 2, 14, 14), "float16"),
C: T.Buffer((14308, 1280, 1, 1, 1), "float16"),
):
pad_A = T.sblock_alloc_buffer((14308, 3, 2, 14, 14), "float16")
for i0, i1, i2, i3, i4 in T.grid(14308, 3, 2, 14, 14):
with T.sblock("pad_A"):
v_i0, v_i1, v_i2, v_i3, v_i4 = T.axis.remap("SSSSS", [i0, i1, i2, i3, i4])
pad_A[v_i0, v_i1, v_i2, v_i3, v_i4] = A[v_i0, v_i1, v_i2, v_i3, v_i4]
for nn, ff, yy, xx, zz, rc, ry, rx, rz in T.grid(14308, 1280, 1, 1, 1, 3, 2, 14, 14):
with T.sblock("C"):
v_nn, v_ff, v_yy, v_xx, v_zz, v_rc, v_ry, v_rx, v_rz = T.axis.remap("SSSSSRRRR", [nn, ff, yy, xx, zz, rc, ry, rx, rz])
with T.init():
C[v_nn, v_ff, v_yy, v_xx, v_zz] = T.float16(0.0)
C[v_nn, v_ff, v_yy, v_xx, v_zz] += pad_A[v_nn, v_rc, v_yy * 2 + v_ry, v_xx * 14 + v_rx, v_zz * 14 + v_rz]* W[v_ff, v_rc, v_ry, v_rx, v_rz]
@T.prim_func(private=True, s_tir=True)
def expected(A: T.Buffer((14308, 3, 2, 14, 14), "float16"), W: T.Buffer((1280, 3, 2, 14, 14), "float16"), C: T.Buffer((14308, 1280, 1, 1, 1), "float16")):
T.func_attr({"tirx.is_scheduled": True})
# with T.sblock("root"):
C_reindex_pad_local = T.sblock_alloc_buffer((1, 14336, 1280), "float16", scope="local")
pad_A_reindex_pad_shared = T.sblock_alloc_buffer((1, 14336, 1184), "float16", scope="shared")
W_reindex_pad_shared = T.sblock_alloc_buffer((1, 1280, 1184), "float16", scope="shared")
for ax0_ax2_0_fused in T.thread_binding(20, thread="blockIdx.y"):
for ax1_0 in T.thread_binding(448, thread="blockIdx.x"):
for ax2_1 in T.thread_binding(1, thread="vthread.y"):
for ax1_1 in T.thread_binding(1, thread="vthread.x"):
for ax2_2 in T.thread_binding(16, thread="threadIdx.y"):
for ax1_2 in T.thread_binding(8, thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(4, 2):
for ax2_3_1_init in T.vectorized(2):
with T.sblock("C_init"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(14336, ax1_0 * 32 + ax1_1 * 32 + ax1_2 * 4 + ax1_3_init)
v2 = T.axis.spatial(1280, ax0_ax2_0_fused * 64 + ax2_1 * 64 + ax2_2 * 4 + ax2_3_0_init * 2 + ax2_3_1_init)
C_reindex_pad_local[0, v1, v2] = T.float16(0.0)
for ax3_0 in range(74):
for ax0_ax1_ax2_fused_0 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(8, thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(2):
for ax0_ax1_ax2_fused_3 in T.vectorized(2):
with T.sblock("pad_A_reindex_pad_shared"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(14336, ax1_0 * 32 + (ax0_ax1_ax2_fused_0 * 32 + ax0_ax1_ax2_fused_1 * 4 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) // 16)
v2 = T.axis.spatial(1184, ax3_0 * 16 + (ax0_ax1_ax2_fused_0 * 32 + ax0_ax1_ax2_fused_1 * 4 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) % 16)
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
pad_A_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < 14308 and v2 < 1176, A[v1, v2 // 392, v2 // 196 % 2, v2 // 14 % 14, v2 % 14], T.float16(0.0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(8, thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(4):
for ax0_ax1_ax2_fused_3 in T.vectorized(2):
with T.sblock("W_reindex_pad_shared"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(1280, ax0_ax2_0_fused * 64 + (ax0_ax1_ax2_fused_0 * 64 + ax0_ax1_ax2_fused_1 * 8 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) // 16)
v2 = T.axis.spatial(1184, ax3_0 * 16 + (ax0_ax1_ax2_fused_0 * 64 + ax0_ax1_ax2_fused_1 * 8 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) % 16)
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
W_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v2 < 1176, W[v1, v2 // 392, v2 // 196 % 2, v2 // 14 % 14, v2 % 14], T.float16(0.0))
for ax3_1, ax1_3, ax2_3_0 in T.grid(16, 4, 2):
for ax2_3_1 in T.vectorized(2):
with T.sblock("C_update"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(14336, ax1_0 * 32 + ax1_1 * 32 + ax1_2 * 4 + ax1_3)
v2 = T.axis.spatial(1280, ax0_ax2_0_fused * 64 + ax2_1 * 64 + ax2_2 * 4 + ax2_3_0 * 2 + ax2_3_1)
v3 = T.axis.reduce(1184, ax3_0 * 16 + ax3_1)
C_reindex_pad_local[0, v1, v2] = C_reindex_pad_local[0, v1, v2] + pad_A_reindex_pad_shared[0, v1, v3] * W_reindex_pad_shared[0, v2, v3]
for ax0, ax1, ax2_0 in T.grid(1, 4, 2):
for ax2_1_1 in T.vectorized(2):
with T.sblock("C_reindex_pad_local"):
v0 = T.axis.spatial(1, ax0)
v1 = T.axis.spatial(14336, ax1_0 * 32 + ax1_2 * 4 + ax1)
v2 = T.axis.spatial(1280, ax0_ax2_0_fused * 64 + ax2_2 * 4 + ax2_0 * 2 + ax2_1_1)
T.where(ax1_0 * 32 + ax1_2 * 4 + ax1 < 14308)
C[v1, v2, 0, 0, 0] = C_reindex_pad_local[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,262 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501, E741, F841
import tvm.testing
from tvm.ir import assert_structural_equal
from tvm.s_tir import dlight as dl
from tvm.script import ir as I
from tvm.script import tirx as T
from tvm.target import Target
def test_fallback():
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(
A: T.Buffer((1, 32, 1, 128), "float16"),
C: T.Buffer((1, 1, 4096), "float16"),
):
B = T.sblock_alloc_buffer((1, 1, 32, 128), "float16")
for i, j, k, l in T.grid(1, 1, 32, 128):
with T.sblock("T_transpose"):
vi, vj, vk, vl = T.axis.remap("SSSS", [i, j, k, l])
B[vi, vj, vk, vl] = A[vi, vk, vj, vl]
for i, j, k in T.grid(1, 1, 4096):
with T.sblock("T_reshape"):
vi, vj, vk = T.axis.remap("SSS", [i, j, k])
C[vi, vj, vk] = B[0, 0, vk % 4096 // 128, vk % 128]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(
A: T.Buffer((1, 32, 1, 128), "float16"),
C: T.Buffer((1, 1, 4096), "float16"),
):
T.func_attr({"tirx.is_scheduled": True})
for ax0_fused_0 in T.thread_binding(4, thread="blockIdx.x"):
for ax0_fused_1 in T.thread_binding(1024, thread="threadIdx.x"):
with T.sblock("T_reshape"):
v0 = T.axis.spatial(4096, ax0_fused_0 * 1024 + ax0_fused_1)
T.reads(A[0, v0 // 128, 0, v0 % 128])
T.writes(C[0, 0, v0])
C[0, 0, v0] = A[0, v0 // 128, 0, v0 % 128]
target = Target("nvidia/geforce-rtx-3090-ti")
with target:
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.Fallback(),
)(Before)
assert_structural_equal(mod, After)
def test_fallback_reduction():
@I.ir_module(s_tir=True)
class Module:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((1, 6144), "float32"), B: T.Buffer((1,), "float32")):
for ax0, ax1 in T.grid(1, 6144):
with T.sblock("block"):
v0 = T.axis.spatial(1, ax0)
v1 = T.axis.reduce(6144, ax1)
T.reads(A[v0, v1])
T.writes(B[v0])
with T.init():
B[v0] = T.float32(0)
B[v0] = B[v0] + T.Cast("float32", A[v0, v1])
@I.ir_module(s_tir=True)
class Expected:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((1, 6144), "float32"), B: T.Buffer((1,), "float32")):
T.func_attr({"tirx.is_scheduled": True})
for ax0_fused_0 in T.thread_binding(T.int64(1), thread="blockIdx.x"):
for ax0_fused_1 in T.thread_binding(T.int64(1024), thread="threadIdx.x"):
with T.sblock("block_init"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
T.where(ax0_fused_0 * T.int64(1024) + ax0_fused_1 < T.int64(1))
T.reads()
T.writes(B[0])
B[0] = T.float32(0)
for ax1 in range(6144):
with T.sblock("block_update"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.reduce(6144, ax1)
T.where(ax0_fused_0 * T.int64(1024) + ax0_fused_1 < T.int64(1))
T.reads(B[0], A[0, v1])
T.writes(B[0])
B[0] = B[0] + T.Cast("float32", A[0, v1])
with Target("apple/m1-gpu"):
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.Fallback(),
)(Module)
assert_structural_equal(mod, Expected)
def test_fallback_irregular_spatial():
@T.prim_func(private=True, s_tir=True)
def func(
var_pages: T.handle,
var_page_table_indptr: T.handle,
var_page_table_values: T.handle,
var_values: T.handle,
seq_id: T.int32,
):
nhead = T.int32()
nlayer = T.int32()
seqlen = T.int32()
npage = T.int32()
page_size = T.int32()
num_total_pages = T.int32()
num_total_seqs_plus_1 = T.int32()
pages = T.match_buffer(var_pages, (num_total_pages, nlayer, nhead, page_size), "float16")
page_table_indptr = T.match_buffer(var_page_table_indptr, (num_total_seqs_plus_1,), "int32")
page_table_values = T.match_buffer(var_page_table_values, (npage,), "int32")
values = T.match_buffer(var_values, (nlayer, nhead, seqlen), "float16")
for l, h, pos in T.grid(nlayer, nhead, seqlen):
with T.sblock("block"):
vl, vh, vp = T.axis.remap("SSS", [l, h, pos])
values[vl, vh, vp] = pages[
page_table_values[page_table_indptr[seq_id] + T.floordiv(vp, page_size)],
vl,
vh,
T.floormod(vp, page_size),
]
# fmt: off
@T.prim_func(private=True, s_tir=True)
def expected(var_pages: T.handle, var_page_table_indptr: T.handle, var_page_table_values: T.handle, var_values: T.handle, seq_id: T.int32):
T.func_attr({"tirx.is_scheduled": True})
nhead = T.int32()
nlayer = T.int32()
seqlen = T.int32()
npage = T.int32()
page_size = T.int32()
num_total_pages = T.int32()
num_total_seqs_plus_1 = T.int32()
pages = T.match_buffer(var_pages, (num_total_pages, nlayer, nhead, page_size), "float16")
page_table_indptr = T.match_buffer(var_page_table_indptr, (num_total_seqs_plus_1,), "int32")
page_table_values = T.match_buffer(var_page_table_values, (npage,), "int32")
values = T.match_buffer(var_values, (nlayer, nhead, seqlen), "float16")
for ax0_ax1_ax2_fused_0 in T.thread_binding((nlayer * nhead * seqlen + 1023) // 1024, thread="blockIdx.x"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(1024, thread="threadIdx.x"):
with T.sblock("block"):
v0 = T.axis.spatial(nlayer, (ax0_ax1_ax2_fused_0 * 1024 + ax0_ax1_ax2_fused_1) // (nhead * seqlen))
v1 = T.axis.spatial(nhead, (ax0_ax1_ax2_fused_0 * 1024 + ax0_ax1_ax2_fused_1) % (nhead * seqlen) // seqlen)
v2 = T.axis.spatial(seqlen, (ax0_ax1_ax2_fused_0 * 1024 + ax0_ax1_ax2_fused_1) % seqlen)
T.where(ax0_ax1_ax2_fused_0 * 1024 + ax0_ax1_ax2_fused_1 < nlayer * nhead * seqlen)
T.reads(pages[page_table_values[page_table_indptr[seq_id] + v2 // page_size], v0, v1, v2 % page_size], page_table_values[page_table_indptr[seq_id] + v2 // page_size], page_table_indptr[seq_id])
T.writes(values[v0, v1, v2])
values[v0, v1, v2] = pages[page_table_values[page_table_indptr[seq_id] + v2 // page_size], v0, v1, v2 % page_size]
# fmt: on
target = Target("nvidia/geforce-rtx-3090-ti")
with target:
mod = tvm.IRModule({"main": func})
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.Fallback(),
)(mod)
assert_structural_equal(mod["main"], expected)
def test_gpu_fallback_ignores_non_gpu_functions():
@I.ir_module(s_tir=True)
class Before:
# This function has no "target" attribute, and is scheduled
# using the `Target.current`.
@T.prim_func(s_tir=True)
def gpu_func(
A: T.Buffer((1, 32, 1, 128), "float16"),
C: T.Buffer((1, 1, 4096), "float16"),
):
B = T.sblock_alloc_buffer((1, 1, 32, 128), "float16")
for i, j, k, l in T.grid(1, 1, 32, 128):
with T.sblock("T_transpose"):
vi, vj, vk, vl = T.axis.remap("SSSS", [i, j, k, l])
B[vi, vj, vk, vl] = A[vi, vk, vj, vl]
for i, j, k in T.grid(1, 1, 4096):
with T.sblock("T_reshape"):
vi, vj, vk = T.axis.remap("SSS", [i, j, k])
C[vi, vj, vk] = B[0, 0, vk % 4096 // 128, vk % 128]
# This function is identical, except that it is explicitly
# annotated with the "target" attribute, and is scheduled
# based on the annotation's target.
@T.prim_func(s_tir=True)
def cpu_func(
A: T.Buffer((1, 32, 1, 128), "float16"),
C: T.Buffer((1, 1, 4096), "float16"),
):
T.func_attr({"target": T.target("llvm")})
B = T.sblock_alloc_buffer((1, 1, 32, 128), "float16")
for i, j, k, l in T.grid(1, 1, 32, 128):
with T.sblock("T_transpose"):
vi, vj, vk, vl = T.axis.remap("SSSS", [i, j, k, l])
B[vi, vj, vk, vl] = A[vi, vk, vj, vl]
for i, j, k in T.grid(1, 1, 4096):
with T.sblock("T_reshape"):
vi, vj, vk = T.axis.remap("SSS", [i, j, k])
C[vi, vj, vk] = B[0, 0, vk % 4096 // 128, vk % 128]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def gpu_func(
A: T.Buffer((1, 32, 1, 128), "float16"),
C: T.Buffer((1, 1, 4096), "float16"),
):
T.func_attr({"tirx.is_scheduled": True})
for ax0_fused_0 in T.thread_binding(4, thread="blockIdx.x"):
for ax0_fused_1 in T.thread_binding(1024, thread="threadIdx.x"):
with T.sblock("T_reshape"):
v0 = T.axis.spatial(4096, ax0_fused_0 * 1024 + ax0_fused_1)
T.reads(A[0, v0 // 128, 0, v0 % 128])
T.writes(C[0, 0, v0])
C[0, 0, v0] = A[0, v0 // 128, 0, v0 % 128]
@T.prim_func(s_tir=True)
def cpu_func(
A: T.Buffer((1, 32, 1, 128), "float16"),
C: T.Buffer((1, 1, 4096), "float16"),
):
T.func_attr({"target": T.target("llvm")})
B = T.sblock_alloc_buffer((1, 1, 32, 128), "float16")
for i, j, k, l in T.grid(1, 1, 32, 128):
with T.sblock("T_transpose"):
vi, vj, vk, vl = T.axis.remap("SSSS", [i, j, k, l])
B[vi, vj, vk, vl] = A[vi, vk, vj, vl]
for i, j, k in T.grid(1, 1, 4096):
with T.sblock("T_reshape"):
vi, vj, vk = T.axis.remap("SSS", [i, j, k])
C[vi, vj, vk] = B[0, 0, vk % 4096 // 128, vk % 128]
with Target("cuda"):
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.Fallback(),
)(Before)
assert_structural_equal(mod, After)
if __name__ == "__main__":
tvm.testing.main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,695 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501, F841
import tvm
import tvm.testing
from tvm.ir import IRModule, assert_structural_equal
from tvm.s_tir import dlight as dl
from tvm.script import ir as I
from tvm.script import tirx as T
from tvm.target import Target
def _check(mod_before: IRModule, mod_after: IRModule):
target = Target("nvidia/geforce-rtx-3090-ti")
with target:
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.GeneralReduction(),
)(mod_before)
assert_structural_equal(mod, mod_after)
def test_softmax_1():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(p_lv44: T.handle, p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
n, m = T.int64(), T.int64()
lv44 = T.match_buffer(p_lv44, (T.int64(1), T.int64(32), n, m))
var_compute_intermediate = T.match_buffer(p_output0, (T.int64(1), T.int64(32), n, m), "float16")
# with T.sblock("root"):
T_softmax_maxelem = T.sblock_alloc_buffer((T.int64(1), T.int64(32), n))
T_softmax_exp = T.sblock_alloc_buffer((T.int64(1), T.int64(32), n, m))
T_softmax_expsum = T.sblock_alloc_buffer((T.int64(1), T.int64(32), n))
var_T_softmax_norm_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(32), n, m))
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(32), n, m):
with T.sblock("T_softmax_maxelem"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv44[v_i0, v_i1, v_i2, v_k])
T.writes(T_softmax_maxelem[v_i0, v_i1, v_i2])
with T.init():
T_softmax_maxelem[v_i0, v_i1, v_i2] = T.float32(-3.4028234663852886e+38)
T_softmax_maxelem[v_i0, v_i1, v_i2] = T.max(T_softmax_maxelem[v_i0, v_i1, v_i2], lv44[v_i0, v_i1, v_i2, v_k])
for i0, i1, i2, i3 in T.grid(T.int64(1), T.int64(32), n, m):
with T.sblock("T_softmax_exp"):
v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSS", [i0, i1, i2, i3])
T.reads(lv44[v_i0, v_i1, v_i2, v_i3], T_softmax_maxelem[v_i0, v_i1, v_i2])
T.writes(T_softmax_exp[v_i0, v_i1, v_i2, v_i3])
T_softmax_exp[v_i0, v_i1, v_i2, v_i3] = T.exp(lv44[v_i0, v_i1, v_i2, v_i3] - T_softmax_maxelem[v_i0, v_i1, v_i2])
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(32), n, m):
with T.sblock("T_softmax_expsum"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(T_softmax_exp[v_i0, v_i1, v_i2, v_k])
T.writes(T_softmax_expsum[v_i0, v_i1, v_i2])
with T.init():
T_softmax_expsum[v_i0, v_i1, v_i2] = T.float32(0)
T_softmax_expsum[v_i0, v_i1, v_i2] = T_softmax_expsum[v_i0, v_i1, v_i2] + T_softmax_exp[v_i0, v_i1, v_i2, v_k]
for i0, i1, i2, i3 in T.grid(T.int64(1), T.int64(32), n, m):
with T.sblock("T_softmax_norm"):
v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSS", [i0, i1, i2, i3])
T.reads(T_softmax_exp[v_i0, v_i1, v_i2, v_i3], T_softmax_expsum[v_i0, v_i1, v_i2])
T.writes(var_T_softmax_norm_intermediate[v_i0, v_i1, v_i2, v_i3])
T.sblock_attr({"axis": 3})
var_T_softmax_norm_intermediate[v_i0, v_i1, v_i2, v_i3] = T_softmax_exp[v_i0, v_i1, v_i2, v_i3] / T_softmax_expsum[v_i0, v_i1, v_i2]
for i0, i1, i2, i3 in T.grid(T.int64(1), T.int64(32), n, m):
with T.sblock("compute"):
v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSS", [i0, i1, i2, i3])
T.reads(var_T_softmax_norm_intermediate[v_i0, v_i1, v_i2, v_i3])
T.writes(var_compute_intermediate[v_i0, v_i1, v_i2, v_i3])
var_compute_intermediate[v_i0, v_i1, v_i2, v_i3] = T.Cast("float16", var_T_softmax_norm_intermediate[v_i0, v_i1, v_i2, v_i3])
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(p_lv44: T.handle, p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n, m = T.int64(), T.int64()
lv44 = T.match_buffer(p_lv44, (T.int64(1), T.int64(32), n, m))
var_compute_intermediate = T.match_buffer(p_output0, (T.int64(1), T.int64(32), n, m), "float16")
# with T.sblock("root"):
T_softmax_maxelem_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(32), n), scope="shared")
T_softmax_expsum_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(32), n), scope="shared")
for ax0_ax1_fused in T.thread_binding(n * T.int64(32), thread="blockIdx.x"):
for ax0, ax1 in T.grid(T.int64(1), T.int64(1)):
for ax2_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_fused_0 in T.serial((m + T.int64(255)) // T.int64(256), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_maxelem"):
v0 = T.axis.spatial(T.int64(32), ax0_ax1_fused // n + ax0)
v1 = T.axis.spatial(n, ax0_ax1_fused % n + ax1)
v2 = T.axis.reduce(m, ax2_fused_0 * T.int64(256) + ax2_fused_1)
T.where(ax2_fused_0 * T.int64(256) + ax2_fused_1 < m)
T.reads(lv44[T.int64(0), v0, v1, v2])
T.writes(T_softmax_maxelem_shared[T.int64(0), v0, v1])
with T.init():
T_softmax_maxelem_shared[T.int64(0), v0, v1] = T.float32(-3.4028234663852886e+38)
T_softmax_maxelem_shared[T.int64(0), v0, v1] = T.max(T_softmax_maxelem_shared[T.int64(0), v0, v1], lv44[T.int64(0), v0, v1, v2])
for ax0, ax1 in T.grid(T.int64(1), T.int64(1)):
for ax2_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_fused_0 in T.serial((m + T.int64(255)) // T.int64(256), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_expsum"):
v0 = T.axis.spatial(T.int64(32), ax0_ax1_fused // n + ax0)
v1 = T.axis.spatial(n, ax0_ax1_fused % n + ax1)
v2 = T.axis.reduce(m, ax2_fused_0 * T.int64(256) + ax2_fused_1)
T.where(ax2_fused_0 * T.int64(256) + ax2_fused_1 < m)
T.reads(lv44[T.int64(0), v0, v1, v2], T_softmax_maxelem_shared[T.int64(0), v0, v1])
T.writes(T_softmax_expsum_shared[T.int64(0), v0, v1])
with T.init():
T_softmax_expsum_shared[T.int64(0), v0, v1] = T.float32(0)
T_softmax_expsum_shared[T.int64(0), v0, v1] = T_softmax_expsum_shared[T.int64(0), v0, v1] + T.exp(lv44[T.int64(0), v0, v1, v2] - T_softmax_maxelem_shared[T.int64(0), v0, v1])
for ax2_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_0 in T.serial((m + T.int64(255)) // T.int64(256), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("compute"):
v0 = T.axis.spatial(T.int64(32), ax0_ax1_fused // n)
v1 = T.axis.spatial(n, ax0_ax1_fused % n)
v2 = T.axis.spatial(m, ax2_0 * T.int64(256) + ax2_1)
T.where(ax2_0 * T.int64(256) + ax2_1 < m)
T.reads(lv44[T.int64(0), v0, v1, v2], T_softmax_maxelem_shared[T.int64(0), v0, v1], T_softmax_expsum_shared[T.int64(0), v0, v1])
T.writes(var_compute_intermediate[T.int64(0), v0, v1, v2])
var_compute_intermediate[T.int64(0), v0, v1, v2] = T.Cast("float16", T.exp(lv44[T.int64(0), v0, v1, v2] - T_softmax_maxelem_shared[T.int64(0), v0, v1]) / T_softmax_expsum_shared[T.int64(0), v0, v1])
# fmt: on
_check(Before, After)
def test_softmax_2():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((T.int64(1), T.int64(1), T.int64(32000)), "float32"), T_softmax_norm: T.Buffer((T.int64(1), T.int64(1), T.int64(32000)), "float32")):
# with T.sblock("root"):
T_softmax_maxelem = T.sblock_alloc_buffer((T.int64(1), T.int64(1)))
T_softmax_exp = T.sblock_alloc_buffer((T.int64(1), T.int64(1), T.int64(32000)))
T_softmax_expsum = T.sblock_alloc_buffer((T.int64(1), T.int64(1)))
for i0, i1, k in T.grid(T.int64(1), T.int64(1), T.int64(32000)):
with T.sblock("T_softmax_maxelem"):
v_i0, v_i1, v_k = T.axis.remap("SSR", [i0, i1, k])
T.reads(A[v_i0, v_i1, v_k])
T.writes(T_softmax_maxelem[v_i0, v_i1])
with T.init():
T_softmax_maxelem[v_i0, v_i1] = T.float32(-3.4028234663852886e+38)
T_softmax_maxelem[v_i0, v_i1] = T.max(T_softmax_maxelem[v_i0, v_i1], A[v_i0, v_i1, v_k])
for i0, i1, i2 in T.grid(T.int64(1), T.int64(1), T.int64(32000)):
with T.sblock("T_softmax_exp"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(A[v_i0, v_i1, v_i2], T_softmax_maxelem[v_i0, v_i1])
T.writes(T_softmax_exp[v_i0, v_i1, v_i2])
T_softmax_exp[v_i0, v_i1, v_i2] = T.exp(A[v_i0, v_i1, v_i2] - T_softmax_maxelem[v_i0, v_i1])
for i0, i1, k in T.grid(T.int64(1), T.int64(1), T.int64(32000)):
with T.sblock("T_softmax_expsum"):
v_i0, v_i1, v_k = T.axis.remap("SSR", [i0, i1, k])
T.reads(T_softmax_exp[v_i0, v_i1, v_k])
T.writes(T_softmax_expsum[v_i0, v_i1])
with T.init():
T_softmax_expsum[v_i0, v_i1] = T.float32(0)
T_softmax_expsum[v_i0, v_i1] = T_softmax_expsum[v_i0, v_i1] + T_softmax_exp[v_i0, v_i1, v_k]
for i0, i1, i2 in T.grid(T.int64(1), T.int64(1), T.int64(32000)):
with T.sblock("T_softmax_norm"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(T_softmax_exp[v_i0, v_i1, v_i2], T_softmax_expsum[v_i0, v_i1])
T.writes(T_softmax_norm[v_i0, v_i1, v_i2])
T.sblock_attr({"axis": 2})
T_softmax_norm[v_i0, v_i1, v_i2] = T_softmax_exp[v_i0, v_i1, v_i2] / T_softmax_expsum[v_i0, v_i1]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((T.int64(1), T.int64(1), T.int64(32000)), "float32"), T_softmax_norm: T.Buffer((T.int64(1), T.int64(1), T.int64(32000)), "float32")):
T.func_attr({"tirx.is_scheduled": True})
# with T.sblock("root"):
T_softmax_maxelem_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(1)), scope="shared")
T_softmax_expsum_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(1)), scope="shared")
for ax0_fused in T.thread_binding(T.int64(1), thread="blockIdx.x"):
for ax0 in T.serial(T.int64(0), T.int64(1)):
for ax1_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_fused_0 in T.serial(T.int64(125), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_maxelem"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.reduce(T.int64(32000), ax1_fused_0 * T.int64(256) + ax1_fused_1)
T.reads(A[T.int64(0), T.int64(0), v1])
T.writes(T_softmax_maxelem_shared[T.int64(0), T.int64(0)])
with T.init():
T_softmax_maxelem_shared[T.int64(0), T.int64(0)] = T.float32(-3.4028234663852886e+38)
T_softmax_maxelem_shared[T.int64(0), T.int64(0)] = T.max(T_softmax_maxelem_shared[T.int64(0), T.int64(0)], A[T.int64(0), T.int64(0), v1])
for ax0 in T.serial(T.int64(0), T.int64(1)):
for ax1_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_fused_0 in T.serial(T.int64(125), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_expsum"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.reduce(T.int64(32000), ax1_fused_0 * T.int64(256) + ax1_fused_1)
T.reads(A[T.int64(0), T.int64(0), v1], T_softmax_maxelem_shared[T.int64(0), T.int64(0)])
T.writes(T_softmax_expsum_shared[T.int64(0), T.int64(0)])
with T.init():
T_softmax_expsum_shared[T.int64(0), T.int64(0)] = T.float32(0)
T_softmax_expsum_shared[T.int64(0), T.int64(0)] = T_softmax_expsum_shared[T.int64(0), T.int64(0)] + T.exp(A[T.int64(0), T.int64(0), v1] - T_softmax_maxelem_shared[T.int64(0), T.int64(0)])
for ax1_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_0 in T.serial(T.int64(125), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_norm"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(32000), ax1_0 * T.int64(256) + ax1_1)
T.reads(A[T.int64(0), T.int64(0), v1], T_softmax_maxelem_shared[T.int64(0), T.int64(0)], T_softmax_expsum_shared[T.int64(0), T.int64(0)])
T.writes(T_softmax_norm[T.int64(0), T.int64(0), v1])
T.sblock_attr({"axis": 2})
T_softmax_norm[T.int64(0), T.int64(0), v1] = T.exp(A[T.int64(0), T.int64(0), v1] - T_softmax_maxelem_shared[T.int64(0), T.int64(0)]) / T_softmax_expsum_shared[T.int64(0), T.int64(0)]
# fmt: on
_check(Before, After)
def test_softmax_3():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(input: T.Buffer((T.int64(1), T.int64(4), T.int64(32), T.int64(8192)), "float32"), T_softmax_norm: T.Buffer((T.int64(1), T.int64(4), T.int64(32), T.int64(8192)), "float32")):
# with T.sblock("root"):
T_softmax_maxelem = T.sblock_alloc_buffer((T.int64(1), T.int64(4), T.int64(8192)))
T_softmax_exp = T.sblock_alloc_buffer((T.int64(1), T.int64(4), T.int64(32), T.int64(8192)))
T_softmax_expsum = T.sblock_alloc_buffer((T.int64(1), T.int64(4), T.int64(8192)))
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(4), T.int64(8192), T.int64(32)):
with T.sblock("T_softmax_maxelem"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(input[v_i0, v_i1, v_k, v_i2])
T.writes(T_softmax_maxelem[v_i0, v_i1, v_i2])
with T.init():
T_softmax_maxelem[v_i0, v_i1, v_i2] = T.float32(-340282346638528859811704183484516925440.0)
T_softmax_maxelem[v_i0, v_i1, v_i2] = T.max(T_softmax_maxelem[v_i0, v_i1, v_i2], input[v_i0, v_i1, v_k, v_i2])
for i0, i1, i2, i3 in T.grid(T.int64(1), T.int64(4), T.int64(32), T.int64(8192)):
with T.sblock("T_softmax_exp"):
v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSS", [i0, i1, i2, i3])
T.reads(input[v_i0, v_i1, v_i2, v_i3], T_softmax_maxelem[v_i0, v_i1, v_i3])
T.writes(T_softmax_exp[v_i0, v_i1, v_i2, v_i3])
T_softmax_exp[v_i0, v_i1, v_i2, v_i3] = T.exp(input[v_i0, v_i1, v_i2, v_i3] - T_softmax_maxelem[v_i0, v_i1, v_i3])
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(4), T.int64(8192), T.int64(32)):
with T.sblock("T_softmax_expsum"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(T_softmax_exp[v_i0, v_i1, v_k, v_i2])
T.writes(T_softmax_expsum[v_i0, v_i1, v_i2])
with T.init():
T_softmax_expsum[v_i0, v_i1, v_i2] = T.float32(0.0)
T_softmax_expsum[v_i0, v_i1, v_i2] = T_softmax_expsum[v_i0, v_i1, v_i2] + T_softmax_exp[v_i0, v_i1, v_k, v_i2]
for i0, i1, i2, i3 in T.grid(T.int64(1), T.int64(4), T.int64(32), T.int64(8192)):
with T.sblock("T_softmax_norm"):
v_i0, v_i1, v_i2, v_i3 = T.axis.remap("SSSS", [i0, i1, i2, i3])
T.reads(T_softmax_exp[v_i0, v_i1, v_i2, v_i3], T_softmax_expsum[v_i0, v_i1, v_i3])
T.writes(T_softmax_norm[v_i0, v_i1, v_i2, v_i3])
T.sblock_attr({"axis": 2})
T_softmax_norm[v_i0, v_i1, v_i2, v_i3] = T_softmax_exp[v_i0, v_i1, v_i2, v_i3] / T_softmax_expsum[v_i0, v_i1, v_i3]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(input: T.Buffer((T.int64(1), T.int64(4), T.int64(32), T.int64(8192)), "float32"), T_softmax_norm: T.Buffer((T.int64(1), T.int64(4), T.int64(32), T.int64(8192)), "float32")):
T.func_attr({"tirx.is_scheduled": True})
# with T.sblock("root"):
T_softmax_maxelem_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(4), T.int64(8192)), scope="shared")
T_softmax_expsum_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(4), T.int64(8192)), scope="shared")
for ax0_ax2_fused in T.thread_binding(T.int64(32768), thread="blockIdx.x"):
for ax0, ax1 in T.grid(T.int64(1), T.int64(1)):
for ax2_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_fused_0 in T.serial(T.int64(1), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_maxelem"):
v0 = T.axis.spatial(T.int64(4), ax0_ax2_fused // T.int64(8192) + ax0)
v1 = T.axis.spatial(T.int64(8192), ax0_ax2_fused % T.int64(8192) + ax1)
v2 = T.axis.reduce(T.int64(32), ax2_fused_0 * T.int64(256) + ax2_fused_1)
T.where(ax2_fused_0 * T.int64(256) + ax2_fused_1 < T.int64(32))
T.reads(input[T.int64(0), v0, v2, v1])
T.writes(T_softmax_maxelem_shared[T.int64(0), v0, v1])
with T.init():
T_softmax_maxelem_shared[T.int64(0), v0, v1] = T.float32(-340282346638528859811704183484516925440.0)
T_softmax_maxelem_shared[T.int64(0), v0, v1] = T.max(T_softmax_maxelem_shared[T.int64(0), v0, v1], input[T.int64(0), v0, v2, v1])
for ax0, ax1 in T.grid(T.int64(1), T.int64(1)):
for ax2_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_fused_0 in T.serial(T.int64(1), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_expsum"):
v0 = T.axis.spatial(T.int64(4), ax0_ax2_fused // T.int64(8192) + ax0)
v1 = T.axis.spatial(T.int64(8192), ax0_ax2_fused % T.int64(8192) + ax1)
v2 = T.axis.reduce(T.int64(32), ax2_fused_0 * T.int64(256) + ax2_fused_1)
T.where(ax2_fused_0 * T.int64(256) + ax2_fused_1 < T.int64(32))
T.reads(input[T.int64(0), v0, v2, v1], T_softmax_maxelem_shared[T.int64(0), v0, v1])
T.writes(T_softmax_expsum_shared[T.int64(0), v0, v1])
with T.init():
T_softmax_expsum_shared[T.int64(0), v0, v1] = T.float32(0.0)
T_softmax_expsum_shared[T.int64(0), v0, v1] = T_softmax_expsum_shared[T.int64(0), v0, v1] + T.exp(input[T.int64(0), v0, v2, v1] - T_softmax_maxelem_shared[T.int64(0), v0, v1])
for ax1_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_0 in T.serial(T.int64(1), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_softmax_norm"):
v0 = T.axis.spatial(T.int64(4), ax0_ax2_fused // T.int64(8192))
v1 = T.axis.spatial(T.int64(32), ax1_0 * T.int64(256) + ax1_1)
v2 = T.axis.spatial(T.int64(8192), ax0_ax2_fused % T.int64(8192))
T.where(ax1_0 * T.int64(256) + ax1_1 < T.int64(32))
T.reads(input[T.int64(0), v0, v1, v2], T_softmax_maxelem_shared[T.int64(0), v0, v2], T_softmax_expsum_shared[T.int64(0), v0, v2])
T.writes(T_softmax_norm[T.int64(0), v0, v1, v2])
T.sblock_attr({"axis": 2})
T_softmax_norm[T.int64(0), v0, v1, v2] = T.exp(input[T.int64(0), v0, v1, v2] - T_softmax_maxelem_shared[T.int64(0), v0, v2]) / T_softmax_expsum_shared[T.int64(0), v0, v2]
# fmt: on
_check(Before, After)
def test_layer_norm():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(p_lv6: T.handle, weight1: T.Buffer((T.int64(2560),), "float32"), bias: T.Buffer((T.int64(2560),), "float32"), p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int64()
lv6 = T.match_buffer(p_lv6, (T.int64(1), n, T.int64(2560)))
var_compute_intermediate = T.match_buffer(p_output0, (T.int64(1), n, T.int64(2560)), "float16")
# with T.sblock("root"):
A_red_temp_v0 = T.sblock_alloc_buffer((T.int64(1), n))
A_red_temp_v1 = T.sblock_alloc_buffer((T.int64(1), n))
var_T_layer_norm_intermediate = T.sblock_alloc_buffer((T.int64(1), n, T.int64(2560)))
for ax0, ax1, k2 in T.grid(T.int64(1), n, T.int64(2560)):
with T.sblock("A_red_temp"):
v_ax0, v_ax1, v_k2 = T.axis.remap("SSR", [ax0, ax1, k2])
T.reads(lv6[v_ax0, v_ax1, v_k2])
T.writes(A_red_temp_v0[v_ax0, v_ax1], A_red_temp_v1[v_ax0, v_ax1])
with T.init():
A_red_temp_v0[v_ax0, v_ax1] = T.float32(0)
A_red_temp_v1[v_ax0, v_ax1] = T.float32(0)
v_A_red_temp_v0: T.let[T.float32] = A_red_temp_v0[v_ax0, v_ax1] + lv6[v_ax0, v_ax1, v_k2]
v_A_red_temp_v1: T.let[T.float32] = A_red_temp_v1[v_ax0, v_ax1] + lv6[v_ax0, v_ax1, v_k2] * lv6[v_ax0, v_ax1, v_k2]
A_red_temp_v0[v_ax0, v_ax1] = v_A_red_temp_v0
A_red_temp_v1[v_ax0, v_ax1] = v_A_red_temp_v1
for ax0, ax1, ax2 in T.grid(T.int64(1), n, T.int64(2560)):
with T.sblock("T_layer_norm"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(lv6[v_ax0, v_ax1, v_ax2], A_red_temp_v0[v_ax0, v_ax1], A_red_temp_v1[v_ax0, v_ax1], weight1[v_ax2], bias[v_ax2])
T.writes(var_T_layer_norm_intermediate[v_ax0, v_ax1, v_ax2])
var_T_layer_norm_intermediate[v_ax0, v_ax1, v_ax2] = (lv6[v_ax0, v_ax1, v_ax2] - A_red_temp_v0[v_ax0, v_ax1] * T.float32(0.00039062500000000002)) * T.rsqrt(A_red_temp_v1[v_ax0, v_ax1] * T.float32(0.00039062500000000002) - A_red_temp_v0[v_ax0, v_ax1] * T.float32(0.00039062500000000002) * (A_red_temp_v0[v_ax0, v_ax1] * T.float32(0.00039062500000000002)) + T.float32(1.0000000000000001e-05)) * weight1[v_ax2] + bias[v_ax2]
for i0, i1, i2 in T.grid(T.int64(1), n, T.int64(2560)):
with T.sblock("compute"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(var_T_layer_norm_intermediate[v_i0, v_i1, v_i2])
T.writes(var_compute_intermediate[v_i0, v_i1, v_i2])
var_compute_intermediate[v_i0, v_i1, v_i2] = T.Cast("float16", var_T_layer_norm_intermediate[v_i0, v_i1, v_i2])
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(p_lv6: T.handle, weight1: T.Buffer((T.int64(2560),), "float32"), bias: T.Buffer((T.int64(2560),), "float32"), p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int64()
lv6 = T.match_buffer(p_lv6, (T.int64(1), n, T.int64(2560)))
var_compute_intermediate = T.match_buffer(p_output0, (T.int64(1), n, T.int64(2560)), "float16")
# with T.sblock("root"):
A_red_temp_v0_shared = T.sblock_alloc_buffer((T.int64(1), n), scope="shared")
A_red_temp_v1_shared = T.sblock_alloc_buffer((T.int64(1), n), scope="shared")
for ax0_fused in T.thread_binding(n, thread="blockIdx.x"):
for ax0 in T.serial(T.int64(0), T.int64(1)):
for ax1_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_fused_0 in T.serial(T.int64(10), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("A_red_temp"):
v0 = T.axis.spatial(n, ax0_fused + ax0)
v1 = T.axis.reduce(T.int64(2560), ax1_fused_0 * T.int64(256) + ax1_fused_1)
T.reads(lv6[T.int64(0), v0, v1])
T.writes(A_red_temp_v0_shared[T.int64(0), v0], A_red_temp_v1_shared[T.int64(0), v0])
with T.init():
A_red_temp_v0_shared[T.int64(0), v0] = T.float32(0)
A_red_temp_v1_shared[T.int64(0), v0] = T.float32(0)
v_A_red_temp_v0: T.let[T.float32] = A_red_temp_v0_shared[T.int64(0), v0] + lv6[T.int64(0), v0, v1]
v_A_red_temp_v1: T.let[T.float32] = A_red_temp_v1_shared[T.int64(0), v0] + lv6[T.int64(0), v0, v1] * lv6[T.int64(0), v0, v1]
A_red_temp_v0_shared[T.int64(0), v0] = v_A_red_temp_v0
A_red_temp_v1_shared[T.int64(0), v0] = v_A_red_temp_v1
for ax1_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_0 in T.serial(T.int64(10), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("compute"):
v0 = T.axis.spatial(n, ax0_fused)
v1 = T.axis.spatial(T.int64(2560), ax1_0 * T.int64(256) + ax1_1)
T.reads(lv6[T.int64(0), v0, v1], A_red_temp_v0_shared[T.int64(0), v0], A_red_temp_v1_shared[T.int64(0), v0], weight1[v1], bias[v1])
T.writes(var_compute_intermediate[T.int64(0), v0, v1])
var_compute_intermediate[T.int64(0), v0, v1] = T.Cast("float16", (lv6[T.int64(0), v0, v1] - A_red_temp_v0_shared[T.int64(0), v0] * T.float32(0.00039062500000000002)) * T.rsqrt(A_red_temp_v1_shared[T.int64(0), v0] * T.float32(0.00039062500000000002) - A_red_temp_v0_shared[T.int64(0), v0] * T.float32(0.00039062500000000002) * (A_red_temp_v0_shared[T.int64(0), v0] * T.float32(0.00039062500000000002)) + T.float32(1.0000000000000001e-05)) * weight1[v1] + bias[v1])
# fmt: on
_check(Before, After)
def test_rms_norm():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(var_A: T.handle, B: T.Buffer((T.int64(4096),), "float16"), var_rms_norm: T.handle):
T.func_attr({"op_pattern": 4, "tirx.noalias": True})
n = T.int64()
A = T.match_buffer(var_A, (T.int64(1), n, T.int64(4096)), "float16")
rms_norm_1 = T.match_buffer(var_rms_norm, (T.int64(1), n, T.int64(4096)), "float16")
# with T.sblock("root"):
Ared_temp = T.sblock_alloc_buffer((T.int64(1), n))
for bsz, i, k in T.grid(T.int64(1), n, T.int64(4096)):
with T.sblock("Ared_temp"):
v_bsz, v_i, v_k = T.axis.remap("SSR", [bsz, i, k])
T.reads(A[v_bsz, v_i, v_k])
T.writes(Ared_temp[v_bsz, v_i])
with T.init():
Ared_temp[v_bsz, v_i] = T.float32(0)
Ared_temp[v_bsz, v_i] = Ared_temp[v_bsz, v_i] + T.Cast("float32", A[v_bsz, v_i, v_k]) * T.Cast("float32", A[v_bsz, v_i, v_k])
for bsz, i, k in T.grid(T.int64(1), n, T.int64(4096)):
with T.sblock("rms_norm"):
v_bsz, v_i, v_k = T.axis.remap("SSS", [bsz, i, k])
T.reads(B[v_k], A[v_bsz, v_i, v_k], Ared_temp[v_bsz, v_i])
T.writes(rms_norm_1[v_bsz, v_i, v_k])
rms_norm_1[v_bsz, v_i, v_k] = T.Cast("float16", T.Cast("float32", B[v_k]) * (T.Cast("float32", A[v_bsz, v_i, v_k]) / T.sqrt(Ared_temp[v_bsz, v_i] * T.float32(0.000244140625) + T.float32(9.9999999999999995e-07))))
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(var_A: T.handle, B: T.Buffer((T.int64(4096),), "float16"), var_rms_norm: T.handle):
T.func_attr({"op_pattern": 4, "tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int64()
A = T.match_buffer(var_A, (T.int64(1), n, T.int64(4096)), "float16")
rms_norm_1 = T.match_buffer(var_rms_norm, (T.int64(1), n, T.int64(4096)), "float16")
# with T.sblock("root"):
Ared_temp_shared = T.sblock_alloc_buffer((T.int64(1), n), scope="shared")
for ax0_fused in T.thread_binding(n, thread="blockIdx.x"):
for ax0 in T.serial(T.int64(0), T.int64(1)):
for ax1_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_fused_0 in T.serial(T.int64(16), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("Ared_temp"):
v0 = T.axis.spatial(n, ax0_fused + ax0)
v1 = T.axis.reduce(T.int64(4096), ax1_fused_0 * T.int64(256) + ax1_fused_1)
T.reads(A[T.int64(0), v0, v1])
T.writes(Ared_temp_shared[T.int64(0), v0])
with T.init():
Ared_temp_shared[T.int64(0), v0] = T.float32(0)
Ared_temp_shared[T.int64(0), v0] = Ared_temp_shared[T.int64(0), v0] + T.Cast("float32", A[T.int64(0), v0, v1]) * T.Cast("float32", A[T.int64(0), v0, v1])
for ax1_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax1_0 in T.serial(T.int64(16), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("rms_norm"):
v0 = T.axis.spatial(n, ax0_fused)
v1 = T.axis.spatial(T.int64(4096), ax1_0 * T.int64(256) + ax1_1)
T.reads(B[v1], A[T.int64(0), v0, v1], Ared_temp_shared[T.int64(0), v0])
T.writes(rms_norm_1[T.int64(0), v0, v1])
rms_norm_1[T.int64(0), v0, v1] = T.Cast("float16", T.Cast("float32", B[v1]) * (T.Cast("float32", A[T.int64(0), v0, v1]) / T.sqrt(Ared_temp_shared[T.int64(0), v0] * T.float32(0.000244140625) + T.float32(9.9999999999999995e-07))))
# fmt: on
_check(Before, After)
def test_group_norm():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((1, 2048), "float32"), B: T.Buffer((2048,), "float32"), C: T.Buffer((2048,), "float32"), T_reshape: T.Buffer((1, 2048), "float32")):
T.func_attr({"tirx.noalias": True})
T_reshape_1 = T.sblock_alloc_buffer((1, 32, 64))
A_red_temp_v0 = T.sblock_alloc_buffer((1, 32))
A_red_temp_v1 = T.sblock_alloc_buffer((1, 32))
T_reshape_2 = T.sblock_alloc_buffer((32, 64))
T_reshape_3 = T.sblock_alloc_buffer((32, 64))
T_group_norm = T.sblock_alloc_buffer((1, 32, 64))
for ax0, ax1, ax2 in T.grid(1, 32, 64):
with T.sblock("T_reshape"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(A[0, (v_ax1 * 64 + v_ax2) % 2048])
T.writes(T_reshape_1[v_ax0, v_ax1, v_ax2])
T_reshape_1[v_ax0, v_ax1, v_ax2] = A[0, (v_ax1 * 64 + v_ax2) % 2048]
for ax0, ax1, k2 in T.grid(1, 32, 64):
with T.sblock("A_red_temp"):
v_ax0, v_ax1, v_k2 = T.axis.remap("SSR", [ax0, ax1, k2])
T.reads(T_reshape_1[v_ax0, v_ax1, v_k2])
T.writes(A_red_temp_v0[v_ax0, v_ax1], A_red_temp_v1[v_ax0, v_ax1])
with T.init():
A_red_temp_v0[v_ax0, v_ax1] = T.float32(0)
A_red_temp_v1[v_ax0, v_ax1] = T.float32(0)
v_A_red_temp_v0: T.let[T.float32] = A_red_temp_v0[v_ax0, v_ax1] + T_reshape_1[v_ax0, v_ax1, v_k2]
v_A_red_temp_v1: T.let[T.float32] = A_red_temp_v1[v_ax0, v_ax1] + T_reshape_1[v_ax0, v_ax1, v_k2] * T_reshape_1[v_ax0, v_ax1, v_k2]
A_red_temp_v0[v_ax0, v_ax1] = v_A_red_temp_v0
A_red_temp_v1[v_ax0, v_ax1] = v_A_red_temp_v1
for ax0, ax1 in T.grid(32, 64):
with T.sblock("T_reshape_1"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(B[(v_ax0 * 64 + v_ax1) % 2048])
T.writes(T_reshape_2[v_ax0, v_ax1])
T_reshape_2[v_ax0, v_ax1] = B[(v_ax0 * 64 + v_ax1) % 2048]
for ax0, ax1 in T.grid(32, 64):
with T.sblock("T_reshape_2"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(C[(v_ax0 * 64 + v_ax1) % 2048])
T.writes(T_reshape_3[v_ax0, v_ax1])
T_reshape_3[v_ax0, v_ax1] = C[(v_ax0 * 64 + v_ax1) % 2048]
for ax0, ax1, ax2 in T.grid(1, 32, 64):
with T.sblock("T_group_norm"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(T_reshape_1[v_ax0, v_ax1, v_ax2], A_red_temp_v0[v_ax0, v_ax1], A_red_temp_v1[v_ax0, v_ax1], T_reshape_2[v_ax1, v_ax2], T_reshape_3[v_ax1, v_ax2])
T.writes(T_group_norm[v_ax0, v_ax1, v_ax2])
T_group_norm[v_ax0, v_ax1, v_ax2] = (T_reshape_1[v_ax0, v_ax1, v_ax2] - A_red_temp_v0[v_ax0, v_ax1] * T.float32(0.015625)) * T.rsqrt(A_red_temp_v1[v_ax0, v_ax1] * T.float32(0.015625) - A_red_temp_v0[v_ax0, v_ax1] * T.float32(0.015625) * (A_red_temp_v0[v_ax0, v_ax1] * T.float32(0.015625)) + T.float32(1.0000000000000001e-05)) * T_reshape_2[v_ax1, v_ax2] + T_reshape_3[v_ax1, v_ax2]
for ax0, ax1 in T.grid(1, 2048):
with T.sblock("T_reshape_3"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(T_group_norm[0, v_ax1 % 2048 // 64, v_ax1 % 64])
T.writes(T_reshape[v_ax0, v_ax1])
T_reshape[v_ax0, v_ax1] = T_group_norm[0, v_ax1 % 2048 // 64, v_ax1 % 64]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((1, 2048), "float32"), B: T.Buffer((2048,), "float32"), C: T.Buffer((2048,), "float32"), T_reshape: T.Buffer((1, 2048), "float32")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
A_red_temp_v0_shared = T.sblock_alloc_buffer((1, 32), scope="shared")
A_red_temp_v1_shared = T.sblock_alloc_buffer((1, 32), scope="shared")
for ax0_fused in T.thread_binding(T.int64(1), thread="blockIdx.x"):
for ax0 in range(32):
for ax1_fused_1 in T.thread_binding(256, thread="threadIdx.x"):
for ax1_fused_0 in T.serial(1, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("A_red_temp"):
v0 = T.axis.spatial(32, ax0)
v1 = T.axis.reduce(64, ax1_fused_0 * 256 + ax1_fused_1)
T.where(ax1_fused_0 * 256 + ax1_fused_1 < 64)
T.reads(A[0, v0 * 64 + v1])
T.writes(A_red_temp_v0_shared[0, v0], A_red_temp_v1_shared[0, v0])
with T.init():
A_red_temp_v0_shared[0, v0] = T.float32(0)
A_red_temp_v1_shared[0, v0] = T.float32(0)
v_A_red_temp_v0: T.let[T.float32] = A_red_temp_v0_shared[0, v0] + A[0, v0 * 64 + v1]
v_A_red_temp_v1: T.let[T.float32] = A_red_temp_v1_shared[0, v0] + A[0, v0 * 64 + v1] * A[0, v0 * 64 + v1]
A_red_temp_v0_shared[0, v0] = v_A_red_temp_v0
A_red_temp_v1_shared[0, v0] = v_A_red_temp_v1
for ax1_1 in T.thread_binding(256, thread="threadIdx.x"):
for ax1_0 in T.serial(8, annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
with T.sblock("T_reshape_3"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(2048, ax1_0 * 256 + ax1_1)
T.reads(A[0, v1], A_red_temp_v0_shared[0, v1 // 64], A_red_temp_v1_shared[0, v1 // 64], B[v1], C[v1])
T.writes(T_reshape[0, v1])
T_reshape[0, v1] = (A[0, v1] - A_red_temp_v0_shared[0, v1 // 64] * T.float32(0.015625)) * T.rsqrt(A_red_temp_v1_shared[0, v1 // 64] * T.float32(0.015625) - A_red_temp_v0_shared[0, v1 // 64] * T.float32(0.015625) * (A_red_temp_v0_shared[0, v1 // 64] * T.float32(0.015625)) + T.float32(1.0000000000000001e-05)) * B[v1] + C[v1]
_check(Before, After)
def test_logsumexp():
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def compute_lse(var_A: T.handle, var_blocked_lse: T.handle):
T.func_attr({"tirx.noalias": True})
batch_size = T.int64()
vocab_size = T.int64()
num_chunks = T.int64()
A = T.match_buffer(var_A, (batch_size, vocab_size), dtype="float32")
blocked_lse = T.match_buffer(var_blocked_lse, (batch_size, num_chunks), dtype="float32")
A_pad = T.sblock_alloc_buffer((batch_size, num_chunks, T.int64(4096)), dtype="float32")
temp_max = T.sblock_alloc_buffer((batch_size, num_chunks), dtype="float32")
temp_sum = T.sblock_alloc_buffer((batch_size, num_chunks), dtype="float32")
for l0, l1, l2 in T.grid(batch_size, num_chunks, T.int64(4096)):
with T.sblock("pad"):
v0, v1, v2 = T.axis.remap("SSS", [l0, l1, l2])
A_pad[v0, v1, v2] = T.if_then_else(
v1 * T.int64(4096) + v2 < vocab_size,
A[v0, v1 * T.int64(4096) + v2],
T.min_value("float32"),
)
for l0, l1, l2 in T.grid(batch_size, num_chunks, T.int64(4096)):
with T.sblock("max"):
v0, v1, v2 = T.axis.remap("SSR", [l0, l1, l2])
with T.init():
temp_max[v0, v1] = T.min_value("float32")
temp_max[v0, v1] = T.max(temp_max[v0, v1], A_pad[v0, v1, v2])
for l0, l1, l2 in T.grid(batch_size, num_chunks, T.int64(4096)):
with T.sblock("sum_exp"):
v0, v1, v2 = T.axis.remap("SSR", [l0, l1, l2])
with T.init():
temp_sum[v0, v1] = T.float32(0)
temp_sum[v0, v1] += T.if_then_else(
v1 * T.int64(4096) + v2 < vocab_size,
T.exp(A_pad[v0, v1, v2] - temp_max[v0, v1]),
T.float32(0),
)
for l0, l1, l2 in T.grid(batch_size, num_chunks, T.int64(1)):
with T.sblock("log"):
v0, v1, v2 = T.axis.remap("SSS", [l0, l1, l2])
blocked_lse[v0, v1] = T.log(temp_sum[v0, v1]) + temp_max[v0, v1]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def compute_lse(var_A: T.handle, var_blocked_lse: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
batch_size, vocab_size = T.int64(), T.int64()
A = T.match_buffer(var_A, (batch_size, vocab_size))
num_chunks = T.int64()
blocked_lse = T.match_buffer(var_blocked_lse, (batch_size, num_chunks))
temp_max_shared = T.sblock_alloc_buffer((batch_size, num_chunks), scope="shared")
temp_sum_shared = T.sblock_alloc_buffer((batch_size, num_chunks), scope="shared")
for ax0_ax1_fused in T.thread_binding(batch_size * num_chunks, thread="blockIdx.x"):
for ax0, ax1 in T.grid(T.int64(1), T.int64(1)):
for ax2_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_fused_0 in T.serial(
T.int64(16),
annotations={
"pragma_auto_unroll_max_step": 256,
"pragma_unroll_explicit": 1,
},
):
with T.sblock("max"):
v0 = T.axis.spatial(
batch_size,
ax0_ax1_fused // num_chunks + ax0,
)
v1 = T.axis.spatial(num_chunks, ax0_ax1_fused % num_chunks + ax1)
v2 = T.axis.reduce(
T.int64(4096), ax2_fused_0 * T.int64(256) + ax2_fused_1
)
T.reads(A[v0, v1 * T.int64(4096) + v2])
T.writes(temp_max_shared[v0, v1])
with T.init():
temp_max_shared[v0, v1] = T.min_value("float32")
temp_max_shared[v0, v1] = T.max(
temp_max_shared[v0, v1],
T.if_then_else(
v1 * T.int64(4096) + v2 < vocab_size,
A[v0, v1 * T.int64(4096) + v2],
T.min_value("float32"),
),
)
for ax0, ax1 in T.grid(T.int64(1), T.int64(1)):
for ax2_fused_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_fused_0 in T.serial(
T.int64(16),
annotations={
"pragma_auto_unroll_max_step": 256,
"pragma_unroll_explicit": 1,
},
):
with T.sblock("sum_exp"):
v0 = T.axis.spatial(
batch_size,
ax0_ax1_fused // num_chunks + ax0,
)
v1 = T.axis.spatial(num_chunks, ax0_ax1_fused % num_chunks + ax1)
v2 = T.axis.reduce(
T.int64(4096), ax2_fused_0 * T.int64(256) + ax2_fused_1
)
T.reads(A[v0, v1 * T.int64(4096) + v2], temp_max_shared[v0, v1])
T.writes(temp_sum_shared[v0, v1])
with T.init():
temp_sum_shared[v0, v1] = T.float32(0)
temp_sum_shared[v0, v1] = temp_sum_shared[v0, v1] + T.if_then_else(
v1 * T.int64(4096) + v2 < vocab_size,
T.exp(
T.if_then_else(
v1 * T.int64(4096) + v2 < vocab_size,
A[v0, v1 * T.int64(4096) + v2],
T.min_value("float32"),
)
- temp_max_shared[v0, v1]
),
T.float32(0),
)
for ax2_1 in T.thread_binding(T.int64(256), thread="threadIdx.x"):
for ax2_0 in T.serial(
T.int64(1),
annotations={
"pragma_auto_unroll_max_step": 256,
"pragma_unroll_explicit": 1,
},
):
with T.sblock("log"):
v0 = T.axis.spatial(batch_size, ax0_ax1_fused // num_chunks)
v1 = T.axis.spatial(num_chunks, ax0_ax1_fused % num_chunks)
v2 = T.axis.spatial(T.int64(1), ax2_0 * T.int64(256) + ax2_1)
T.where(ax2_0 * T.int64(256) + ax2_1 < T.int64(1))
T.reads(temp_sum_shared[v0, v1], temp_max_shared[v0, v1])
T.writes(blocked_lse[v0, v1])
blocked_lse[v0, v1] = (
T.log(temp_sum_shared[v0, v1]) + temp_max_shared[v0, v1]
)
_check(Before, After)
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,561 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501
import tvm.testing
from tvm.s_tir import dlight as dl
from tvm.script import tirx as T
from tvm.target import Target
def test_batch_decode_gemv():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv429: T.Buffer((T.int64(4096), T.int64(3584)), "uint32"), lv430: T.Buffer((T.int64(4096), T.int64(896)), "float16"), p_lv807: T.handle, p_output0: T.handle):
T.func_attr({"tirx.noalias": True, "tirx.HoistIfThenElseExprWithBlock": 1})
batch_size = T.int64()
lv807 = T.match_buffer(p_lv807, (batch_size, T.int64(1), T.int64(28672)), "float16")
NT_matmul_intermediate = T.match_buffer(p_output0, (batch_size, T.int64(1), T.int64(4096)), "float16")
# with T.sblock("root"):
compute = T.sblock_alloc_buffer((T.int64(4096), T.int64(28672)), "float16")
dequantize_intermediate_intermediate = T.sblock_alloc_buffer((T.int64(4096), T.int64(28672)), "float16")
for i0, i1 in T.grid(T.int64(4096), T.int64(28672)):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(lv429[v_i0, v_i1 // T.int64(8)])
T.writes(compute[v_i0, v_i1])
compute[v_i0, v_i1] = T.Cast("float16", T.bitwise_and(T.shift_right(lv429[v_i0, v_i1 // T.int64(8)], T.Cast("uint32", v_i1 % T.int64(8) * T.int64(4))), T.uint32(15)))
for i0, i1 in T.grid(T.int64(4096), T.int64(28672)):
with T.sblock("dequantize"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(compute[v_i0, v_i1], lv430[v_i0, v_i1 // T.int64(32)])
T.writes(dequantize_intermediate_intermediate[v_i0, v_i1])
dequantize_intermediate_intermediate[v_i0, v_i1] = (compute[v_i0, v_i1] - T.float16(7)) * lv430[v_i0, v_i1 // T.int64(32)]
for i0, i1, i2, k in T.grid(batch_size, T.int64(1), T.int64(4096), T.int64(28672)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv807[v_i0, v_i1, v_k], dequantize_intermediate_intermediate[v_i2, v_k])
T.writes(NT_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
NT_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
NT_matmul_intermediate[v_i0, v_i1, v_i2] = NT_matmul_intermediate[v_i0, v_i1, v_i2] + lv807[v_i0, v_i1, v_k] * dequantize_intermediate_intermediate[v_i2, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(lv429: T.Buffer((T.int64(4096), T.int64(3584)), "uint32"), lv430: T.Buffer((T.int64(4096), T.int64(896)), "float16"), p_lv807: T.handle, p_output0: T.handle):
T.func_attr({"tirx.HoistIfThenElseExprWithBlock": 1, "tirx.is_scheduled": True, "tirx.noalias": True})
batch_size = T.int64()
lv807 = T.match_buffer(p_lv807, (batch_size, T.int64(1), T.int64(28672)), "float16")
NT_matmul_intermediate = T.match_buffer(p_output0, (batch_size, T.int64(1), T.int64(4096)), "float16")
# with T.sblock("root"):
dequantize_intermediate_intermediate_local = T.sblock_alloc_buffer((T.int64(4096), T.int64(28672)), "float16", scope="local")
NT_matmul_intermediate_pad_local = T.sblock_alloc_buffer(((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(1), T.int64(4096)), "float16", scope="local")
NT_matmul_intermediate_pad_rf_local = T.sblock_alloc_buffer((T.int64(128), (batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(1), T.int64(4096)), "float16", scope="local")
NT_matmul_intermediate_pad_rf_local_1 = T.sblock_alloc_buffer((T.int64(32), (batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(1), T.int64(4096)), "float16", scope="local")
for ax0_0 in T.thread_binding((batch_size + T.int64(3)) // T.int64(4), thread="blockIdx.y"):
for u_fused_ax1_fused_fused_0 in T.thread_binding(T.int64(256), thread="blockIdx.x"):
for u_fused_ax1_fused_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 in T.thread_binding(T.int64(32), thread="threadIdx.y"):
for ax0_1_init, u_fused_ax1_fused_fused_2_init in T.grid(T.int64(4), T.int64(2)):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1_init in T.vectorized(T.int64(4)):
with T.sblock("NT_matmul_rf_init"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused = T.axis.spatial(T.int64(128), ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1_init)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax0_1_init)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1 * T.int64(2) + u_fused_ax1_fused_fused_2_init)
T.reads()
T.writes(NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1])
NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1] = T.float16(0)
for ax2_fused_u_fused_0 in T.serial(T.int64(112), annotations={"pragma_auto_unroll_max_step": 8, "pragma_unroll_explicit": 1}):
for ax0_0_1, ax1 in T.grid(T.int64(2), T.int64(8)):
for ax0_1 in T.vectorized(T.int64(1)):
with T.sblock("dequantize"):
v0 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1 * T.int64(2) + ax0_0_1 + ax0_1)
v1 = T.axis.spatial(T.int64(28672), ax2_fused_u_fused_0 * T.int64(256) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(8) + ax1)
T.reads(lv429[v0, v1 // T.int64(8)], lv430[v0, v1 // T.int64(32)])
T.writes(dequantize_intermediate_intermediate_local[v0, v1])
dequantize_intermediate_intermediate_local[v0, v1] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv429[v0, v1 // T.int64(8)], T.Cast("uint32", v1 % T.int64(8) * T.int64(4))), T.uint32(15))) - T.float16(7)) * lv430[v0, v1 // T.int64(32)]
for ax0_1, u_fused_ax1_fused_fused_2, ax2_fused_u_fused_2 in T.grid(T.int64(4), T.int64(2), T.int64(2)):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1 in T.vectorized(T.int64(4)):
with T.sblock("NT_matmul_rf_update"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused = T.axis.spatial(T.int64(128), ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax0_1)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1 * T.int64(2) + u_fused_ax1_fused_fused_2)
vax2_fused_u_fused_0, vax2_fused_u_fused_2 = T.axis.remap("RR", [ax2_fused_u_fused_0, ax2_fused_u_fused_2])
T.reads(NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1], lv807[v0, T.int64(0), vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)], dequantize_intermediate_intermediate_local[v1, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)])
T.writes(NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1])
NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1] = NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1] + T.if_then_else(v0 < batch_size, lv807[v0, T.int64(0), vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)], T.float16(0)) * dequantize_intermediate_intermediate_local[v1, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)]
for ax3_fused_0_ax3_fused_1_fused in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0 in T.thread_binding(T.int64(32), thread="threadIdx.y"):
for ax3_fused_2_0 in T.serial(T.int64(1), annotations={"pragma_auto_unroll_max_step": 8, "pragma_unroll_explicit": 1}):
for ax2 in T.serial(T.int64(0), T.int64(4)):
for ax3_fused_2_1 in T.vectorized(T.int64(2)):
with T.sblock("NT_matmul_rf_init"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 = T.axis.spatial(T.int64(32), ax0)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax2)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax3_fused_0_ax3_fused_1_fused * T.int64(2) + ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1)
T.reads()
T.writes(NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1])
NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1] = T.float16(0)
for ax1 in T.serial(T.int64(0), T.int64(4)):
with T.sblock("NT_matmul_rf_update"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1 = T.axis.remap("SR", [ax0, ax1])
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax2)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax3_fused_0_ax3_fused_1_fused * T.int64(2) + ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1)
T.reads(NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1], NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1, v0, T.int64(0), v1])
T.writes(NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1])
NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1] = NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1] + NT_matmul_intermediate_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1, v0, T.int64(0), v1]
for ax2_fused_2, ax1 in T.grid(T.int64(2), T.int64(4)):
for ax2_fused_0_ax2_fused_1_fused in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0 in T.thread_binding(T.int64(32), thread="threadIdx.y"):
with T.sblock("NT_matmul"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 = T.axis.reduce(T.int64(32), ax0)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax1)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax2_fused_0_ax2_fused_1_fused * T.int64(2) + ax2_fused_2)
T.reads(NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1])
T.writes(NT_matmul_intermediate_pad_local[v0, T.int64(0), v1])
with T.init():
NT_matmul_intermediate_pad_local[v0, T.int64(0), v1] = T.float16(0)
NT_matmul_intermediate_pad_local[v0, T.int64(0), v1] = NT_matmul_intermediate_pad_local[v0, T.int64(0), v1] + NT_matmul_intermediate_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1]
for ax0 in T.serial(T.int64(0), T.int64(4)):
for ax1_fused_0_ax1_fused_1_fused in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax1_fused_2 in T.serial(T.int64(0), T.int64(2)):
with T.sblock("NT_matmul_intermediate_pad"):
v0 = T.axis.spatial(batch_size, ax0_0 * T.int64(4) + ax0)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax1_fused_0_ax1_fused_1_fused * T.int64(2) + ax1_fused_2)
T.where((ax0_0 - (batch_size + T.int64(3)) // T.int64(4) < T.int64(0) or ax0_0 * T.int64(4) + ax0 == T.int64(0)) and ax0_0 * T.int64(4) + ax0 < batch_size)
T.reads(NT_matmul_intermediate_pad_local[v0, T.int64(0), v1])
T.writes(NT_matmul_intermediate[v0, T.int64(0), v1])
NT_matmul_intermediate[v0, T.int64(0), v1] = NT_matmul_intermediate_pad_local[v0, T.int64(0), v1]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("metal"):
mod = dl.ApplyDefaultSchedule(dl.gpu.LowBatchGEMV(4))(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_batch_gemv():
N = 4096
K = 4096
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_A: T.handle, B: T.Buffer((T.int64(N), T.int64(K)), "float16"), var_NT_matmul: T.handle):
T.func_attr({"tirx.noalias": True, "tirx.HoistIfThenElseExprWithBlock": 1})
batch_size = T.int64()
A = T.match_buffer(var_A, (batch_size, T.int64(1), T.int64(K)), "float16")
NT_matmul = T.match_buffer(var_NT_matmul, (batch_size, T.int64(1), T.int64(N)), "float16")
# with T.sblock("root"):
for i0, i1, i2, k in T.grid(batch_size, T.int64(1), T.int64(N), T.int64(K)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(A[v_i0, v_i1, v_k], B[v_i2, v_k])
T.writes(NT_matmul[v_i0, v_i1, v_i2])
with T.init():
NT_matmul[v_i0, v_i1, v_i2] = T.float16(0)
NT_matmul[v_i0, v_i1, v_i2] = NT_matmul[v_i0, v_i1, v_i2] + A[v_i0, v_i1, v_k] * B[v_i2, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(var_A: T.handle, B: T.Buffer((T.int64(4096), T.int64(4096)), "float16"), var_NT_matmul: T.handle):
T.func_attr({"tirx.HoistIfThenElseExprWithBlock": 1, "tirx.is_scheduled": True, "tirx.noalias": True})
batch_size = T.int64()
A = T.match_buffer(var_A, (batch_size, T.int64(1), T.int64(4096)), "float16")
NT_matmul = T.match_buffer(var_NT_matmul, (batch_size, T.int64(1), T.int64(4096)), "float16")
# with T.sblock("root"):
NT_matmul_pad_local = T.sblock_alloc_buffer(((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(1), T.int64(4096)), "float16", scope="local")
NT_matmul_pad_rf_local = T.sblock_alloc_buffer((T.int64(128), (batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(1), T.int64(4096)), "float16", scope="local")
NT_matmul_pad_rf_local_1 = T.sblock_alloc_buffer((T.int64(32), (batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(1), T.int64(4096)), "float16", scope="local")
for ax0_0 in T.thread_binding((batch_size + T.int64(3)) // T.int64(4), thread="blockIdx.y"):
for u_fused_ax1_fused_fused_0 in T.thread_binding(T.int64(256), thread="blockIdx.x"):
for u_fused_ax1_fused_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 in T.thread_binding(T.int64(32), thread="threadIdx.y"):
for ax0_1_init, u_fused_ax1_fused_fused_2_init in T.grid(T.int64(4), T.int64(2)):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1_init in T.vectorized(T.int64(4)):
with T.sblock("NT_matmul_rf_init"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused = T.axis.spatial(T.int64(128), ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1_init)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax0_1_init)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1 * T.int64(2) + u_fused_ax1_fused_fused_2_init)
T.reads()
T.writes(NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1])
NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1] = T.float16(0)
for ax2_fused_u_fused_0 in T.serial(T.int64(16), annotations={"pragma_auto_unroll_max_step": 8, "pragma_unroll_explicit": 1}):
for ax0_1, u_fused_ax1_fused_fused_2, ax2_fused_u_fused_2 in T.grid(T.int64(4), T.int64(2), T.int64(2)):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1 in T.vectorized(T.int64(4)):
with T.sblock("NT_matmul_rf_update"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused = T.axis.spatial(T.int64(128), ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax0_1)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1 * T.int64(2) + u_fused_ax1_fused_fused_2)
vax2_fused_u_fused_0, vax2_fused_u_fused_2 = T.axis.remap("RR", [ax2_fused_u_fused_0, ax2_fused_u_fused_2])
T.reads(NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1], A[v0, T.int64(0), vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)], B[v1, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)])
T.writes(NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1])
NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1] = NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, T.int64(0), v1] + T.if_then_else(v0 < batch_size, A[v0, T.int64(0), vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)], T.float16(0)) * B[v1, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)]
for ax3_fused_0_ax3_fused_1_fused in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0 in T.thread_binding(T.int64(32), thread="threadIdx.y"):
for ax3_fused_2_0 in T.serial(T.int64(1), annotations={"pragma_auto_unroll_max_step": 8, "pragma_unroll_explicit": 1}):
for ax2 in T.serial(T.int64(0), T.int64(4)):
for ax3_fused_2_1 in T.vectorized(T.int64(2)):
with T.sblock("NT_matmul_rf_init"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 = T.axis.spatial(T.int64(32), ax0)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax2)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax3_fused_0_ax3_fused_1_fused * T.int64(2) + ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1)
T.reads()
T.writes(NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1])
NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1] = T.float16(0)
for ax1 in T.serial(T.int64(0), T.int64(4)):
with T.sblock("NT_matmul_rf_update"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1 = T.axis.remap("SR", [ax0, ax1])
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax2)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax3_fused_0_ax3_fused_1_fused * T.int64(2) + ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1)
T.reads(NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1], NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1, v0, T.int64(0), v1])
T.writes(NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1])
NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1] = NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1] + NT_matmul_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1, v0, T.int64(0), v1]
for ax2_fused_2, ax1 in T.grid(T.int64(2), T.int64(4)):
for ax2_fused_0_ax2_fused_1_fused in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0 in T.thread_binding(T.int64(32), thread="threadIdx.y"):
with T.sblock("NT_matmul"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 = T.axis.reduce(T.int64(32), ax0)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax1)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax2_fused_0_ax2_fused_1_fused * T.int64(2) + ax2_fused_2)
T.reads(NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1])
T.writes(NT_matmul_pad_local[v0, T.int64(0), v1])
with T.init():
NT_matmul_pad_local[v0, T.int64(0), v1] = T.float16(0)
NT_matmul_pad_local[v0, T.int64(0), v1] = NT_matmul_pad_local[v0, T.int64(0), v1] + NT_matmul_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, T.int64(0), v1]
for ax0 in T.serial(T.int64(0), T.int64(4)):
for ax1_fused_0_ax1_fused_1_fused in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax1_fused_2 in T.serial(T.int64(0), T.int64(2)):
with T.sblock("NT_matmul_pad"):
v0 = T.axis.spatial(batch_size, ax0_0 * T.int64(4) + ax0)
v1 = T.axis.spatial(T.int64(4096), u_fused_ax1_fused_fused_0 * T.int64(16) + ax1_fused_0_ax1_fused_1_fused * T.int64(2) + ax1_fused_2)
T.where((ax0_0 - (batch_size + T.int64(3)) // T.int64(4) < T.int64(0) or ax0_0 * T.int64(4) + ax0 == T.int64(0)) and ax0_0 * T.int64(4) + ax0 < batch_size)
T.reads(NT_matmul_pad_local[v0, T.int64(0), v1])
T.writes(NT_matmul[v0, T.int64(0), v1])
NT_matmul[v0, T.int64(0), v1] = NT_matmul_pad_local[v0, T.int64(0), v1]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("metal"):
mod = dl.ApplyDefaultSchedule(dl.gpu.LowBatchGEMV(4))(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_reduction_symbolic_var():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_A: T.handle, var_B: T.handle, matmul: T.Buffer((T.int64(1), T.int64(32), T.int64(1), T.int64(128)), "float32")):
T.func_attr({"tirx.noalias": True})
kv_seq_len = T.int64()
A = T.match_buffer(var_A, (T.int64(1), T.int64(32), T.int64(1), kv_seq_len))
B = T.match_buffer(var_B, (T.int64(1), T.int64(32), kv_seq_len, T.int64(128)))
# with T.sblock("root"):
for i0, i1, i2, i3, k in T.grid(T.int64(1), T.int64(32), T.int64(1), T.int64(128), kv_seq_len):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_i3, v_k = T.axis.remap("SSSSR", [i0, i1, i2, i3, k])
T.reads(A[v_i0, v_i1, v_i2, v_k], B[v_i0, v_i1, v_k, v_i3])
T.writes(matmul[v_i0, v_i1, v_i2, v_i3])
with T.init():
matmul[v_i0, v_i1, v_i2, v_i3] = T.float32(0)
matmul[v_i0, v_i1, v_i2, v_i3] = matmul[v_i0, v_i1, v_i2, v_i3] + A[v_i0, v_i1, v_i2, v_k] * B[v_i0, v_i1, v_k, v_i3]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("metal"):
mod = dl.ApplyDefaultSchedule(dl.gpu.LowBatchGEMV(4))(mod)
tvm.ir.assert_structural_equal(mod["main"], before)
def test_small_spatial_axis():
@T.prim_func(private=True, s_tir=True)
def func(var_A: T.handle, B: T.Buffer((T.int64(8), T.int64(4096)), "float16"), var_C: T.handle):
T.func_attr({"tirx.noalias": True})
batch_size = T.int64()
A = T.match_buffer(var_A, (batch_size, T.int64(4096)), "float16")
C = T.match_buffer(var_C, (batch_size, T.int64(8)), "float16")
for i0, i1, k in T.grid(batch_size, T.int64(8), T.int64(4096)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_k = T.axis.remap("SSR", [i0, i1, k])
T.reads(A[v_i0, v_k], B[v_i1, v_k])
T.writes(C[v_i0, v_i1])
with T.init():
C[v_i0, v_i1] = T.float16(0)
C[v_i0, v_i1] = C[v_i0, v_i1] + A[v_i0, v_k] * B[v_i1, v_k]
# fmt: off
@T.prim_func(private=True, s_tir=True)
def expected(var_A: T.handle, B: T.Buffer((T.int64(8), T.int64(4096)), "float16"), var_C: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
batch_size = T.int64()
A = T.match_buffer(var_A, (batch_size, T.int64(4096)), "float16")
C = T.match_buffer(var_C, (batch_size, T.int64(8)), "float16")
# with T.sblock("root"):
C_pad_local = T.sblock_alloc_buffer(((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(8)), "float16", scope="local")
C_pad_rf_local = T.sblock_alloc_buffer((T.int64(128), (batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(8)), "float16", scope="local")
C_pad_rf_local_1 = T.sblock_alloc_buffer((T.int64(32), (batch_size + T.int64(3)) // T.int64(4) * T.int64(4), T.int64(8)), "float16", scope="local")
for ax0_0 in T.thread_binding((batch_size + T.int64(3)) // T.int64(4), thread="blockIdx.y"):
for u_fused_ax1_fused_fused_0 in T.thread_binding(T.int64(1), thread="blockIdx.x"):
for u_fused_ax1_fused_fused_1 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
for ax0_1_init, u_fused_ax1_fused_fused_2_init in T.grid(T.int64(4), T.int64(2)):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1_init in T.vectorized(T.int64(4)):
with T.sblock("NT_matmul_rf_init"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused = T.axis.spatial(T.int64(128), ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1_init)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax0_1_init)
v1 = T.axis.spatial(T.int64(8), u_fused_ax1_fused_fused_0 * T.int64(32) + u_fused_ax1_fused_fused_1 * T.int64(2) + u_fused_ax1_fused_fused_2_init)
T.where((u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1) * T.int64(2) + u_fused_ax1_fused_fused_2_init < T.int64(8))
T.reads()
T.writes(C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, v1])
C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, v1] = T.float16(0)
for ax2_fused_u_fused_0 in T.serial(T.int64(16), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax0_1, u_fused_ax1_fused_fused_2, ax2_fused_u_fused_2 in T.grid(T.int64(4), T.int64(2), T.int64(2)):
for ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1 in T.vectorized(T.int64(4)):
with T.sblock("NT_matmul_rf_update"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused = T.axis.spatial(T.int64(128), ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + ax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax0_1)
v1 = T.axis.spatial(T.int64(8), u_fused_ax1_fused_fused_0 * T.int64(32) + u_fused_ax1_fused_fused_1 * T.int64(2) + u_fused_ax1_fused_fused_2)
vax2_fused_u_fused_0, vax2_fused_u_fused_2 = T.axis.remap("RR", [ax2_fused_u_fused_0, ax2_fused_u_fused_2])
T.where((u_fused_ax1_fused_fused_0 * T.int64(16) + u_fused_ax1_fused_fused_1) * T.int64(2) + u_fused_ax1_fused_fused_2 < T.int64(8))
T.reads(C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, v1], A[v0, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)], B[v1, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)])
T.writes(C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, v1])
C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, v1] = C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused, v0, v1] + T.if_then_else(v0 < batch_size, A[v0, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)], T.float16(0)) * B[v1, vax2_fused_u_fused_0 * T.int64(256) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused // T.int64(4) * T.int64(8) + vax2_fused_u_fused_2 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused % T.int64(4)]
for ax3_fused_0_ax3_fused_1_fused in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
for ax3_fused_2_0 in T.serial(T.int64(1), annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax2 in T.serial(T.int64(0), T.int64(4)):
for ax3_fused_2_1 in T.vectorized(T.int64(2)):
with T.sblock("NT_matmul_rf_init"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 = T.axis.spatial(T.int64(32), ax0)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax2)
v1 = T.axis.spatial(T.int64(8), ax3_fused_0_ax3_fused_1_fused * T.int64(2) + ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1)
T.where((T.Mul(T.int64(0), T.int64(16)) + ax3_fused_0_ax3_fused_1_fused % T.int64(16)) * T.int64(2) + (ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1) < T.int64(8))
T.reads()
T.writes(C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1])
C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1] = T.float16(0)
for ax1 in T.serial(T.int64(0), T.int64(4)):
with T.sblock("NT_matmul_rf_update"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1 = T.axis.remap("SR", [ax0, ax1])
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax2)
v1 = T.axis.spatial(T.int64(8), ax3_fused_0_ax3_fused_1_fused * T.int64(2) + ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1)
T.where((T.Mul(T.int64(0), T.int64(16)) + ax3_fused_0_ax3_fused_1_fused % T.int64(16)) * T.int64(2) + (ax3_fused_2_0 * T.int64(2) + ax3_fused_2_1) < T.int64(8))
T.reads(C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1], C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1, v0, v1])
T.writes(C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1])
C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1] = C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1] + C_pad_rf_local[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 * T.int64(4) + vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_1, v0, v1]
for ax2_fused_2, ax1 in T.grid(T.int64(2), T.int64(4)):
for ax2_fused_0_ax2_fused_1_fused in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
with T.sblock("NT_matmul"):
vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0 = T.axis.reduce(T.int64(32), ax0)
v0 = T.axis.spatial((batch_size + T.int64(3)) // T.int64(4) * T.int64(4), ax0_0 * T.int64(4) + ax1)
v1 = T.axis.spatial(T.int64(8), ax2_fused_0_ax2_fused_1_fused * T.int64(2) + ax2_fused_2)
T.where((T.Mul(T.int64(0), T.int64(16)) + ax2_fused_0_ax2_fused_1_fused % T.int64(16)) * T.int64(2) + ax2_fused_2 < T.int64(8))
T.reads(C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1])
T.writes(C_pad_local[v0, v1])
with T.init():
C_pad_local[v0, v1] = T.float16(0)
C_pad_local[v0, v1] = C_pad_local[v0, v1] + C_pad_rf_local_1[vax2_fused_u_fused_1_ax2_fused_u_fused_3_fused_0, v0, v1]
for ax0 in T.serial(T.int64(0), T.int64(4)):
for ax1_fused_0_ax1_fused_1_fused in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax1_fused_2 in T.serial(T.int64(0), T.int64(2)):
with T.sblock("C_pad"):
v0 = T.axis.spatial(batch_size, ax0_0 * T.int64(4) + ax0)
v1 = T.axis.spatial(T.int64(8), ax1_fused_0_ax1_fused_1_fused * T.int64(2) + ax1_fused_2)
T.where((ax0_0 - (batch_size + T.int64(3)) // T.int64(4) < T.int64(0) or ax0_0 * T.int64(4) + ax0 == T.int64(0)) and ax0_0 * T.int64(4) + ax0 < batch_size and (T.Mul(T.int64(0), T.int64(16)) + ax1_fused_0_ax1_fused_1_fused % T.int64(16)) * T.int64(2) + ax1_fused_2 < T.int64(8))
T.reads(C_pad_local[v0, v1])
T.writes(C[v0, v1])
C[v0, v1] = C_pad_local[v0, v1]
# fmt: on
mod = tvm.IRModule({"main": func})
with Target("cuda"):
mod = dl.ApplyDefaultSchedule(dl.gpu.LowBatchGEMV(4))(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_outer_reduction():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(
B0: T.Buffer((512, 6144), "uint32"),
B1: T.Buffer((128, 6144), "float16"),
var_A: T.handle,
var_C: T.handle
):
batch_size = T.int32()
A = T.match_buffer(var_A, (batch_size, 1, 4096), "float16")
C = T.match_buffer(var_C, (batch_size, 1, 6144), "float16")
compute = T.sblock_alloc_buffer((4096, 6144), "float16")
B = T.sblock_alloc_buffer((4096, 6144), "float16")
for i0, i1 in T.grid(4096, 6144):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
compute[v_i0, v_i1] = T.Cast("float16", T.bitwise_and(T.shift_right(B0[v_i0 // 8, v_i1], T.Cast("uint32", v_i0 % 8 * 4)), T.uint32(15)))
for i0, i1 in T.grid(4096, 6144):
with T.sblock("dequantize"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
B[v_i0, v_i1] = (compute[v_i0, v_i1] - T.float16(7)) * B1[v_i0 // 32, v_i1]
for i0, i1, i2, k in T.grid(batch_size, 1, 6144, 4096):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
with T.init():
C[v_i0, v_i1, v_i2] = T.float16(0)
C[v_i0, v_i1, v_i2] = C[v_i0, v_i1, v_i2] + A[v_i0, v_i1, v_k] * B[v_k, v_i2]
@T.prim_func(private=True, s_tir=True)
def expected(B0: T.Buffer((512, 6144), "uint32"), B1: T.Buffer((128, 6144), "float16"), var_A: T.handle, var_C: T.handle):
T.func_attr({"tirx.is_scheduled": True})
batch_size = T.int32()
A = T.match_buffer(var_A, (batch_size, 1, 4096), "float16")
C = T.match_buffer(var_C, (batch_size, 1, 6144), "float16")
# with T.sblock("root"):
B_local = T.sblock_alloc_buffer((4096, 6144), "float16", scope="local")
A_pad_shared = T.sblock_alloc_buffer(((batch_size + 3) // 4 * 4, 1, 4096), "float16", scope="shared")
C_pad_local = T.sblock_alloc_buffer(((batch_size + 3) // 4 * 4, 1, 6144), "float16", scope="local")
C_pad_rf_local = T.sblock_alloc_buffer((32, (batch_size + 3) // 4 * 4, 1, 6144), "float16", scope="local")
C_pad_rf_local_1 = T.sblock_alloc_buffer((4, (batch_size + 3) // 4 * 4, 1, 6144), "float16", scope="local")
B0_local = T.sblock_alloc_buffer((512, 6144), "uint32", scope="local")
B1_local = T.sblock_alloc_buffer((128, 6144), "float16", scope="local")
for ax0_0 in T.thread_binding((batch_size + 3) // 4, thread="blockIdx.y"):
for ax1_fused_0 in T.thread_binding(96, thread="blockIdx.x"):
for ax1_fused_1 in T.thread_binding(64, thread="threadIdx.x"):
for ax2_fused_1_ax2_fused_3_fused_0 in T.thread_binding(4, thread="threadIdx.y"):
for ax0_1_init, ax2_fused_1_ax2_fused_3_fused_1_0_init in T.grid(4, 2):
for ax2_fused_1_ax2_fused_3_fused_1_1_init in T.vectorized(4):
with T.sblock("matmul_rf_init"):
vax2_fused_1_ax2_fused_3_fused = T.axis.spatial(32, ax2_fused_1_ax2_fused_3_fused_0 * 8 + ax2_fused_1_ax2_fused_3_fused_1_0_init * 4 + ax2_fused_1_ax2_fused_3_fused_1_1_init)
v0 = T.axis.spatial((batch_size + 3) // 4 * 4, ax0_0 * 4 + ax0_1_init)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax1_fused_1)
T.reads()
T.writes(C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused, v0, 0, v1])
C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused, v0, 0, v1] = T.float16(0)
for ax2_fused_0 in range(32):
for ax0_ax1_fused in T.vectorized(4):
with T.sblock("B0_local"):
v0 = T.axis.spatial(512, ax2_fused_0 * 16 + ax2_fused_1_ax2_fused_3_fused_0 * 4 + ax0_ax1_fused)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax1_fused_1)
T.reads(B0[v0, v1])
T.writes(B0_local[v0, v1])
B0_local[v0, v1] = B0[v0, v1]
for ax0_ax1_fused in T.vectorized(1):
with T.sblock("B1_local"):
v0 = T.axis.spatial(128, ax2_fused_0 * 4 + ax2_fused_1_ax2_fused_3_fused_0)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax1_fused_1)
T.reads(B1[v0, v1])
T.writes(B1_local[v0, v1])
B1_local[v0, v1] = B1[v0, v1]
for ax0_ax1_fused_0 in T.thread_binding(4, thread="threadIdx.y"):
for ax0_ax1_fused_1 in T.thread_binding(64, thread="threadIdx.x"):
for ax0_ax1_fused_2 in T.vectorized(2):
with T.sblock("A_pad"):
v0 = T.axis.spatial((batch_size + 3) // 4 * 4, ax0_0 * 4 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 2 + ax0_ax1_fused_2) // 128)
v1 = T.axis.spatial(4096, ax2_fused_0 * 128 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 2 + ax0_ax1_fused_2) % 128)
T.reads(A[v0, 0, v1])
T.writes(A_pad_shared[v0, 0, v1])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 1]]})
A_pad_shared[v0, 0, v1] = T.if_then_else(v0 < batch_size, A[v0, 0, v1], T.float16(0))
for ax2_fused_2 in range(4):
for ax0_ax1_fused_0 in range(2):
for ax0_ax1_fused_1 in T.vectorized(4):
with T.sblock("dequantize"):
v0 = T.axis.spatial(4096, ax2_fused_0 * 128 + ax2_fused_1_ax2_fused_3_fused_0 * 32 + ax2_fused_2 * 8 + ax0_ax1_fused_0 * 4 + ax0_ax1_fused_1)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax1_fused_1)
T.reads(B0_local[v0 // 8, v1], B1_local[v0 // 32, v1])
T.writes(B_local[v0, v1])
B_local[v0, v1] = (T.Cast("float16", T.bitwise_and(T.shift_right(B0_local[v0 // 8, v1], T.Cast("uint32", v0 % 8 * 4)), T.uint32(15))) - T.float16(7)) * B1_local[v0 // 32, v1]
for ax0_1, ax2_fused_1_ax2_fused_3_fused_1_0 in T.grid(4, 2):
for ax2_fused_1_ax2_fused_3_fused_1_1 in T.vectorized(4):
with T.sblock("matmul_rf_update"):
vax2_fused_1_ax2_fused_3_fused = T.axis.spatial(32, ax2_fused_1_ax2_fused_3_fused_0 * 8 + ax2_fused_1_ax2_fused_3_fused_1_0 * 4 + ax2_fused_1_ax2_fused_3_fused_1_1)
v0 = T.axis.spatial((batch_size + 3) // 4 * 4, ax0_0 * 4 + ax0_1)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax1_fused_1)
vax2_fused_0, vax2_fused_2 = T.axis.remap("RR", [ax2_fused_0, ax2_fused_2])
T.reads(C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused, v0, 0, v1], A_pad_shared[v0, 0, vax2_fused_0 * 128 + vax2_fused_1_ax2_fused_3_fused // 8 * 32 + vax2_fused_2 * 8 + vax2_fused_1_ax2_fused_3_fused % 8], B_local[vax2_fused_0 * 128 + vax2_fused_1_ax2_fused_3_fused // 8 * 32 + vax2_fused_2 * 8 + vax2_fused_1_ax2_fused_3_fused % 8, v1])
T.writes(C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused, v0, 0, v1])
C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused, v0, 0, v1] = C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused, v0, 0, v1] + A_pad_shared[v0, 0, vax2_fused_0 * 128 + vax2_fused_1_ax2_fused_3_fused // 8 * 32 + vax2_fused_2 * 8 + vax2_fused_1_ax2_fused_3_fused % 8] * B_local[vax2_fused_0 * 128 + vax2_fused_1_ax2_fused_3_fused // 8 * 32 + vax2_fused_2 * 8 + vax2_fused_1_ax2_fused_3_fused % 8, v1]
for ax3 in T.thread_binding(64, thread="threadIdx.x"):
for ax0 in T.thread_binding(4, thread="threadIdx.y"):
for ax2_init in range(4):
with T.sblock("matmul_rf_init"):
vax2_fused_1_ax2_fused_3_fused_0 = T.axis.spatial(4, ax0)
v0 = T.axis.spatial((batch_size + 3) // 4 * 4, ax0_0 * 4 + ax2_init)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax3)
T.reads()
T.writes(C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1])
C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1] = T.float16(0)
for ax2, ax1 in T.grid(4, 8):
with T.sblock("matmul_rf_update"):
vax2_fused_1_ax2_fused_3_fused_0, vax2_fused_1_ax2_fused_3_fused_1 = T.axis.remap("SR", [ax0, ax1])
v0 = T.axis.spatial((batch_size + 3) // 4 * 4, ax0_0 * 4 + ax2)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax3)
T.reads(C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1], C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused_0 * 8 + vax2_fused_1_ax2_fused_3_fused_1, v0, 0, v1])
T.writes(C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1])
C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1] = C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1] + C_pad_rf_local[vax2_fused_1_ax2_fused_3_fused_0 * 8 + vax2_fused_1_ax2_fused_3_fused_1, v0, 0, v1]
for ax1 in range(4):
for ax2 in T.thread_binding(64, thread="threadIdx.x"):
for ax0 in T.thread_binding(4, thread="threadIdx.y"):
with T.sblock("matmul"):
vax2_fused_1_ax2_fused_3_fused_0 = T.axis.reduce(4, ax0)
v0 = T.axis.spatial((batch_size + 3) // 4 * 4, ax0_0 * 4 + ax1)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax2)
T.reads(C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1])
T.writes(C_pad_local[v0, 0, v1])
with T.init():
C_pad_local[v0, 0, v1] = T.float16(0)
C_pad_local[v0, 0, v1] = C_pad_local[v0, 0, v1] + C_pad_rf_local_1[vax2_fused_1_ax2_fused_3_fused_0, v0, 0, v1]
for ax0 in range(4):
for ax1 in T.thread_binding(64, thread="threadIdx.x"):
with T.sblock("C_pad"):
v0 = T.axis.spatial(batch_size, ax0_0 * 4 + ax0)
v1 = T.axis.spatial(6144, ax1_fused_0 * 64 + ax1)
T.where((ax0_0 - (batch_size + 3) // 4 < 0 or ax0_0 * 4 + ax0 == 0) and ax0_0 * 4 + ax0 < batch_size)
T.reads(C_pad_local[v0, 0, v1])
T.writes(C[v0, 0, v1])
C[v0, 0, v1] = C_pad_local[v0, 0, v1]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("metal"):
mod = dl.ApplyDefaultSchedule(dl.gpu.LowBatchGEMV(4))(mod) # pylint: disable=not-callable
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_low_batch_gemv_cuda_target_without_max_shared_memory_per_block():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_A: T.handle, B: T.Buffer((T.int64(128), T.int64(128)), "float16"), var_C: T.handle):
T.func_attr({"tir.noalias": True})
batch_size = T.int64()
A = T.match_buffer(var_A, (batch_size, T.int64(1), T.int64(128)), "float16")
C = T.match_buffer(var_C, (batch_size, T.int64(1), T.int64(128)), "float16")
for i0, i1, i2, k in T.grid(batch_size, T.int64(1), T.int64(128), T.int64(128)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(A[v_i0, v_i1, v_k], B[v_i2, v_k])
T.writes(C[v_i0, v_i1, v_i2])
with T.init():
C[v_i0, v_i1, v_i2] = T.float16(0)
C[v_i0, v_i1, v_i2] = C[v_i0, v_i1, v_i2] + A[v_i0, v_i1, v_k] * B[v_i2, v_k]
# fmt: on
target = Target({"kind": "cuda", "max_num_threads": 1024})
assert target.attrs.get("max_shared_memory_per_block", None) is None
mod = tvm.IRModule({"main": before})
with target:
mod = dl.ApplyDefaultSchedule(dl.gpu.LowBatchGEMV(4))(mod)
assert mod["main"].attrs["tirx.is_scheduled"] == 1
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,858 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501
import tvm
import tvm.testing
from tvm.s_tir import dlight as dl
from tvm.script import tirx as T
from tvm.target import Target
def test_matmul():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_inp0: T.handle, inp1: T.Buffer((T.int64(4096), T.int64(4096)), "float32"), var_matmul: T.handle):
m = T.int64()
inp0 = T.match_buffer(var_inp0, (T.int64(1), m, T.int64(4096)))
matmul = T.match_buffer(var_matmul, (T.int64(1), m, T.int64(4096)))
for i0, i1, i2, k in T.grid(T.int64(1), m, T.int64(4096), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
with T.init():
matmul[v_i0, v_i1, v_i2] = T.float32(0)
matmul[v_i0, v_i1, v_i2] = matmul[v_i0, v_i1, v_i2] + inp0[v_i0, v_i1, v_k] * inp1[v_k, v_i2]
@T.prim_func(private=True, s_tir=True)
def expected(var_inp0: T.handle, inp1: T.Buffer((T.int64(4096), T.int64(4096)), "float32"), var_matmul: T.handle):
T.func_attr({"tirx.is_scheduled": True})
m = T.int64()
inp0 = T.match_buffer(var_inp0, (T.int64(1), m, T.int64(4096)))
matmul = T.match_buffer(var_matmul, (T.int64(1), m, T.int64(4096)))
# with T.sblock("root"):
matmul_reindex_pad_local = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(4096)), scope="local")
inp0_reindex_pad_shared = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(4096)), scope="shared")
inp1_reindex_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(4096), T.int64(4096)), scope="shared")
for ax0_ax2_0_fused in T.thread_binding(T.int64(64), thread="blockIdx.y"):
for ax1_0 in T.thread_binding((m + T.int64(31)) // T.int64(32), thread="blockIdx.x"):
for ax2_1 in T.thread_binding(T.int64(1), thread="vthread.y"):
for ax1_1 in T.thread_binding(T.int64(1), thread="vthread.x"):
for ax2_2 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax1_2 in T.thread_binding(T.int64(8), thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(T.int64(4), T.int64(2)):
for ax2_3_1_init in T.vectorized(T.int64(2)):
with T.sblock("matmul_init"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3_init)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0_init * T.int64(2) + ax2_3_1_init)
T.reads()
T.writes(matmul_reindex_pad_local[T.int64(0), v1, v2])
matmul_reindex_pad_local[T.int64(0), v1, v2] = T.float32(0)
for ax3_0 in range(T.int64(256)):
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(2)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("inp0_reindex_pad_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(inp0[v0, v1, v2])
T.writes(inp0_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
inp0_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < m, inp0[v0, v1, v2], T.float32(0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(4)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("inp1_reindex_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(inp1[v2, v1])
T.writes(inp1_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
inp1_reindex_shared[v0, v1, v2] = inp1[v2, v1]
for ax3_1, ax1_3, ax2_3_0 in T.grid(T.int64(16), T.int64(4), T.int64(2)):
for ax2_3_1 in T.vectorized(T.int64(2)):
with T.sblock("matmul_update"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0 * T.int64(2) + ax2_3_1)
v3 = T.axis.reduce(T.int64(4096), ax3_0 * T.int64(16) + ax3_1)
T.reads(matmul_reindex_pad_local[T.int64(0), v1, v2], inp0_reindex_pad_shared[T.int64(0), v1, v3], inp1_reindex_shared[T.int64(0), v2, v3])
T.writes(matmul_reindex_pad_local[T.int64(0), v1, v2])
matmul_reindex_pad_local[T.int64(0), v1, v2] = matmul_reindex_pad_local[T.int64(0), v1, v2] + inp0_reindex_pad_shared[T.int64(0), v1, v3] * inp1_reindex_shared[T.int64(0), v2, v3]
for ax0, ax1, ax2_0 in T.grid(T.int64(1), T.int64(4), T.int64(2)):
for ax2_1_1 in T.vectorized(T.int64(2)):
with T.sblock("matmul_reindex_pad_local"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((m + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_2 * T.int64(4) + ax2_0 * T.int64(2) + ax2_1_1)
T.where(ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1 < m)
T.reads(matmul_reindex_pad_local[v0, v1, v2])
T.writes(matmul[T.int64(0), v1, v2])
matmul[T.int64(0), v1, v2] = matmul_reindex_pad_local[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_int32():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def func(var_inp0: T.handle, inp1: T.Buffer((4096, 4096), "float32"), var_matmul: T.handle):
m = T.int32()
inp0 = T.match_buffer(var_inp0, (1, m, 4096))
matmul = T.match_buffer(var_matmul, (1, m, 4096))
for i0, i1, i2, k in T.grid(1, m, 4096, 4096):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
with T.init():
matmul[v_i0, v_i1, v_i2] = T.float32(0)
matmul[v_i0, v_i1, v_i2] = matmul[v_i0, v_i1, v_i2] + inp0[v_i0, v_i1, v_k] * inp1[v_k, v_i2]
@T.prim_func(private=True, s_tir=True)
def expected(var_inp0: T.handle, inp1: T.Buffer((4096, 4096), "float32"), var_matmul: T.handle):
T.func_attr({"tirx.is_scheduled": True})
m = T.int32()
inp0 = T.match_buffer(var_inp0, (1, m, 4096))
matmul = T.match_buffer(var_matmul, (1, m, 4096))
# with T.sblock("root"):
matmul_reindex_pad_local = T.sblock_alloc_buffer((1, (m + 31) // 32 * 32, 4096), scope="local")
inp0_reindex_pad_shared = T.sblock_alloc_buffer((1, (m + 31) // 32 * 32, 4096), scope="shared")
inp1_reindex_shared = T.sblock_alloc_buffer((1, 4096, 4096), scope="shared")
for ax0_ax2_0_fused in T.thread_binding(64, thread="blockIdx.y"):
for ax1_0 in T.thread_binding((m + 31) // 32, thread="blockIdx.x"):
for ax2_1 in T.thread_binding(1, thread="vthread.y"):
for ax1_1 in T.thread_binding(1, thread="vthread.x"):
for ax2_2 in T.thread_binding(16, thread="threadIdx.y"):
for ax1_2 in T.thread_binding(8, thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(4, 2):
for ax2_3_1_init in T.vectorized(2):
with T.sblock("matmul_init"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + ax1_1 * 32 + ax1_2 * 4 + ax1_3_init)
v2 = T.axis.spatial(4096, ax0_ax2_0_fused * 64 + ax2_1 * 64 + ax2_2 * 4 + ax2_3_0_init * 2 + ax2_3_1_init)
T.reads()
T.writes(matmul_reindex_pad_local[0, v1, v2])
matmul_reindex_pad_local[0, v1, v2] = T.float32(0)
for ax3_0 in range(256):
for ax0_ax1_ax2_fused_0 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(8, thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(2):
for ax0_ax1_ax2_fused_3 in T.vectorized(2):
with T.sblock("inp0_reindex_pad_shared"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + (ax0_ax1_ax2_fused_0 * 32 + ax0_ax1_ax2_fused_1 * 4 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) // 16)
v2 = T.axis.spatial(4096, ax3_0 * 16 + (ax0_ax1_ax2_fused_0 * 32 + ax0_ax1_ax2_fused_1 * 4 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) % 16)
T.reads(inp0[v0, v1, v2])
T.writes(inp0_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
inp0_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < m, inp0[v0, v1, v2], T.float32(0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(8, thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(4):
for ax0_ax1_ax2_fused_3 in T.vectorized(2):
with T.sblock("inp1_reindex_shared"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(4096, ax0_ax2_0_fused * 64 + (ax0_ax1_ax2_fused_0 * 64 + ax0_ax1_ax2_fused_1 * 8 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) // 16)
v2 = T.axis.spatial(4096, ax3_0 * 16 + (ax0_ax1_ax2_fused_0 * 64 + ax0_ax1_ax2_fused_1 * 8 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) % 16)
T.reads(inp1[v2, v1])
T.writes(inp1_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
inp1_reindex_shared[v0, v1, v2] = inp1[v2, v1]
for ax3_1, ax1_3, ax2_3_0 in T.grid(16, 4, 2):
for ax2_3_1 in T.vectorized(2):
with T.sblock("matmul_update"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + ax1_1 * 32 + ax1_2 * 4 + ax1_3)
v2 = T.axis.spatial(4096, ax0_ax2_0_fused * 64 + ax2_1 * 64 + ax2_2 * 4 + ax2_3_0 * 2 + ax2_3_1)
v3 = T.axis.reduce(4096, ax3_0 * 16 + ax3_1)
T.reads(matmul_reindex_pad_local[0, v1, v2], inp0_reindex_pad_shared[0, v1, v3], inp1_reindex_shared[0, v2, v3])
T.writes(matmul_reindex_pad_local[0, v1, v2])
matmul_reindex_pad_local[0, v1, v2] = matmul_reindex_pad_local[0, v1, v2] + inp0_reindex_pad_shared[0, v1, v3] * inp1_reindex_shared[0, v2, v3]
for ax0, ax1, ax2_0 in T.grid(1, 4, 2):
for ax2_1_1 in T.vectorized(2):
with T.sblock("matmul_reindex_pad_local"):
v0 = T.axis.spatial(1, ax0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + ax1_2 * 4 + ax1)
v2 = T.axis.spatial(4096, ax0_ax2_0_fused * 64 + ax2_2 * 4 + ax2_0 * 2 + ax2_1_1)
T.where(ax1_0 * 32 + ax1_2 * 4 + ax1 < m)
T.reads(matmul_reindex_pad_local[v0, v1, v2])
T.writes(matmul[0, v1, v2])
matmul[0, v1, v2] = matmul_reindex_pad_local[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": func})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_fused_matmul():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(W: T.Buffer((T.int64(512), T.int64(4096)), "uint32"), S: T.Buffer((T.int64(128), T.int64(4096)), "uint32"), A: T.Buffer((T.int64(1), T.int64(32), T.int64(4096)), "float32"), C: T.Buffer((T.int64(1), T.int64(32), T.int64(4096)), "float32"), Out: T.Buffer((T.int64(1), T.int64(32), T.int64(4096)), "float32")):
var_decode_intermediate = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)))
var_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(32), T.int64(4096)))
for i, j in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(W[v_i // T.int64(8), v_j], S[v_i // T.int64(32), v_j])
T.writes(var_decode_intermediate[v_i, v_j])
var_decode_intermediate[v_i, v_j] = T.Cast("float32", T.bitwise_and(T.shift_right(W[v_i // T.int64(8), v_j], T.Cast("uint32", v_i % T.int64(8) * T.int64(4))), T.uint32(15))) * T.reinterpret("float32", T.shift_left(T.bitwise_and(S[v_i // T.int64(32), v_j], T.uint32(65535)), T.uint32(16))) + T.reinterpret("float32", T.shift_left(T.bitwise_and(T.shift_right(S[v_i // T.int64(32), v_j], T.uint32(16)), T.uint32(65535)), T.uint32(16)))
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(32), T.int64(4096), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(A[v_i0, v_i1, v_k], var_decode_intermediate[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float32(0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + A[v_i0, v_i1, v_k] * var_decode_intermediate[v_k, v_i2]
for ax0, ax1, ax2 in T.grid(T.int64(1), T.int64(32), T.int64(4096)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(C[v_ax0, v_ax1, v_ax2], var_matmul_intermediate[v_ax0, v_ax1, v_ax2])
T.writes(Out[v_ax0, v_ax1, v_ax2])
Out[v_ax0, v_ax1, v_ax2] = C[v_ax0, v_ax1, v_ax2] + var_matmul_intermediate[v_ax0, v_ax1, v_ax2]
@T.prim_func(private=True, s_tir=True)
def expected(W: T.Buffer((T.int64(512), T.int64(4096)), "uint32"), S: T.Buffer((T.int64(128), T.int64(4096)), "uint32"), A: T.Buffer((T.int64(1), T.int64(32), T.int64(4096)), "float32"), C: T.Buffer((T.int64(1), T.int64(32), T.int64(4096)), "float32"), Out: T.Buffer((T.int64(1), T.int64(32), T.int64(4096)), "float32")):
T.func_attr({"tirx.is_scheduled": True})
# with T.sblock("root"):
var_matmul_intermediate_reindex_local = T.sblock_alloc_buffer((T.int64(1), T.int64(32), T.int64(4096)), scope="local")
A_reindex_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(32), T.int64(4096)), scope="shared")
var_decode_intermediate_reindex_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(4096), T.int64(4096)), scope="shared")
for ax0_ax2_0_fused in T.thread_binding(T.int64(64), thread="blockIdx.y"):
for ax1_0 in T.thread_binding(T.int64(1), thread="blockIdx.x"):
for ax2_1 in T.thread_binding(T.int64(1), thread="vthread.y"):
for ax1_1 in T.thread_binding(T.int64(1), thread="vthread.x"):
for ax2_2 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax1_2 in T.thread_binding(T.int64(8), thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(T.int64(4), T.int64(2)):
for ax2_3_1_init in T.vectorized(T.int64(2)):
with T.sblock("matmul_init"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3_init)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0_init * T.int64(2) + ax2_3_1_init)
T.reads()
T.writes(var_matmul_intermediate_reindex_local[T.int64(0), v1, v2])
var_matmul_intermediate_reindex_local[T.int64(0), v1, v2] = T.float32(0)
for ax3_0 in range(T.int64(256)):
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(2)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("A_reindex_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(32), (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(A[v0, v1, v2])
T.writes(A_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
A_reindex_shared[v0, v1, v2] = A[v0, v1, v2]
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(4)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("var_decode_intermediate_reindex_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(W[v2 // T.int64(8), v1], S[v2 // T.int64(32), v1])
T.writes(var_decode_intermediate_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
var_decode_intermediate_reindex_shared[v0, v1, v2] = T.Cast("float32", T.bitwise_and(T.shift_right(W[v2 // T.int64(8), v1], T.Cast("uint32", v2 % T.int64(8) * T.int64(4))), T.uint32(15))) * T.reinterpret("float32", T.shift_left(T.bitwise_and(S[v2 // T.int64(32), v1], T.uint32(65535)), T.uint32(16))) + T.reinterpret("float32", T.shift_left(T.bitwise_and(T.shift_right(S[v2 // T.int64(32), v1], T.uint32(16)), T.uint32(65535)), T.uint32(16)))
for ax3_1, ax1_3, ax2_3_0 in T.grid(T.int64(16), T.int64(4), T.int64(2)):
for ax2_3_1 in T.vectorized(T.int64(2)):
with T.sblock("matmul_update"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0 * T.int64(2) + ax2_3_1)
v3 = T.axis.reduce(T.int64(4096), ax3_0 * T.int64(16) + ax3_1)
T.reads(var_matmul_intermediate_reindex_local[T.int64(0), v1, v2], A_reindex_shared[T.int64(0), v1, v3], var_decode_intermediate_reindex_shared[T.int64(0), v2, v3])
T.writes(var_matmul_intermediate_reindex_local[T.int64(0), v1, v2])
var_matmul_intermediate_reindex_local[T.int64(0), v1, v2] = var_matmul_intermediate_reindex_local[T.int64(0), v1, v2] + A_reindex_shared[T.int64(0), v1, v3] * var_decode_intermediate_reindex_shared[T.int64(0), v2, v3]
for ax0, ax1, ax2_0 in T.grid(T.int64(1), T.int64(4), T.int64(2)):
for ax2_1_1 in T.vectorized(T.int64(2)):
with T.sblock("var_matmul_intermediate_reindex_local"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial(T.int64(32), ax1_2 * T.int64(4) + ax1)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_2 * T.int64(4) + ax2_0 * T.int64(2) + ax2_1_1)
T.reads(C[T.int64(0), v1, v2], var_matmul_intermediate_reindex_local[v0, v1, v2])
T.writes(Out[T.int64(0), v1, v2])
Out[T.int64(0), v1, v2] = C[T.int64(0), v1, v2] + var_matmul_intermediate_reindex_local[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_skip_gemv():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(W: T.Buffer((T.int64(512), T.int64(4096)), "uint32"), S: T.Buffer((T.int64(128), T.int64(4096)), "uint32"), A: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float32"), C: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float32"), Out: T.Buffer((T.int64(1), T.int64(1), T.int64(4096)), "float32")):
T.func_attr({"tirx.noalias": True})
var_decode_intermediate = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)))
var_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), T.int64(1), T.int64(4096)))
for i, j in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(W[v_i // T.int64(8), v_j], S[v_i // T.int64(32), v_j])
T.writes(var_decode_intermediate[v_i, v_j])
var_decode_intermediate[v_i, v_j] = T.Cast("float32", T.bitwise_and(T.shift_right(W[v_i // T.int64(8), v_j], T.Cast("uint32", v_i % T.int64(8) * T.int64(4))), T.uint32(15))) * T.reinterpret("float32", T.shift_left(T.bitwise_and(S[v_i // T.int64(32), v_j], T.uint32(65535)), T.uint32(16))) + T.reinterpret("float32", T.shift_left(T.bitwise_and(T.shift_right(S[v_i // T.int64(32), v_j], T.uint32(16)), T.uint32(65535)), T.uint32(16)))
for i0, i1, i2, k in T.grid(T.int64(1), T.int64(1), T.int64(4096), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(A[v_i0, v_i1, v_k], var_decode_intermediate[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float32(0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + A[v_i0, v_i1, v_k] * var_decode_intermediate[v_k, v_i2]
for ax0, ax1, ax2 in T.grid(T.int64(1), T.int64(1), T.int64(4096)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(C[v_ax0, v_ax1, v_ax2], var_matmul_intermediate[v_ax0, v_ax1, v_ax2])
T.writes(Out[v_ax0, v_ax1, v_ax2])
Out[v_ax0, v_ax1, v_ax2] = C[v_ax0, v_ax1, v_ax2] + var_matmul_intermediate[v_ax0, v_ax1, v_ax2]
# fmt: on
expected = before
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_output_fp32():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv13: T.Buffer((T.int64(4096), T.int64(512)), "uint32"), lv14: T.Buffer((T.int64(4096), T.int64(128)), "float16"), p_lv48: T.handle, lv13_1: T.Buffer((T.int64(4096),), "float16"), p_lv3: T.handle, p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int64()
lv48 = T.match_buffer(p_lv48, (T.int64(1), n, T.int64(4096)), "float16")
lv3 = T.match_buffer(p_lv3, (T.int64(1), n, T.int64(4096)), "float16")
p_output0_intermediate = T.match_buffer(p_output0, (T.int64(1), n, T.int64(4096)), "float16")
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)), "float16")
var_matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), n, T.int64(4096)))
var_compute_intermediate = T.sblock_alloc_buffer((T.int64(4096),))
var_T_add_intermediate = T.sblock_alloc_buffer((T.int64(1), n, T.int64(4096)))
var_compute_intermediate_1 = T.sblock_alloc_buffer((T.int64(1), n, T.int64(4096)), "float16")
for i, j in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv13[v_i, v_j // T.int64(8)], lv14[v_i, v_j // T.int64(32)])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv13[v_i, v_j // T.int64(8)], T.Cast("uint32", v_j % T.int64(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv14[v_i, v_j // T.int64(32)]
for i0, i1, i2, k in T.grid(T.int64(1), n, T.int64(4096), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv48[v_i0, v_i1, v_k], p_output0_intermediate_1[v_k, v_i2])
T.writes(var_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_matmul_intermediate[v_i0, v_i1, v_i2] = T.float32(0)
var_matmul_intermediate[v_i0, v_i1, v_i2] = var_matmul_intermediate[v_i0, v_i1, v_i2] + T.Cast("float32", lv48[v_i0, v_i1, v_k]) * T.Cast("float32", p_output0_intermediate_1[v_k, v_i2])
for i0 in range(T.int64(4096)):
with T.sblock("compute"):
v_i0 = T.axis.spatial(T.int64(4096), i0)
T.reads(lv13_1[v_i0])
T.writes(var_compute_intermediate[v_i0])
var_compute_intermediate[v_i0] = T.Cast("float32", lv13_1[v_i0])
for ax0, ax1, ax2 in T.grid(T.int64(1), n, T.int64(4096)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(var_matmul_intermediate[v_ax0, v_ax1, v_ax2], var_compute_intermediate[v_ax2])
T.writes(var_T_add_intermediate[v_ax0, v_ax1, v_ax2])
var_T_add_intermediate[v_ax0, v_ax1, v_ax2] = var_matmul_intermediate[v_ax0, v_ax1, v_ax2] + var_compute_intermediate[v_ax2]
for i0, i1, i2 in T.grid(T.int64(1), n, T.int64(4096)):
with T.sblock("compute_1"):
v_i0, v_i1, v_i2 = T.axis.remap("SSS", [i0, i1, i2])
T.reads(var_T_add_intermediate[v_i0, v_i1, v_i2])
T.writes(var_compute_intermediate_1[v_i0, v_i1, v_i2])
var_compute_intermediate_1[v_i0, v_i1, v_i2] = T.Cast("float16", var_T_add_intermediate[v_i0, v_i1, v_i2])
for ax0, ax1, ax2 in T.grid(T.int64(1), n, T.int64(4096)):
with T.sblock("T_add_1"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(var_compute_intermediate_1[v_ax0, v_ax1, v_ax2], lv3[v_ax0, v_ax1, v_ax2])
T.writes(p_output0_intermediate[v_ax0, v_ax1, v_ax2])
p_output0_intermediate[v_ax0, v_ax1, v_ax2] = var_compute_intermediate_1[v_ax0, v_ax1, v_ax2] + lv3[v_ax0, v_ax1, v_ax2]
@T.prim_func(private=True, s_tir=True)
def expected(lv13: T.Buffer((T.int64(4096), T.int64(512)), "uint32"), lv14: T.Buffer((T.int64(4096), T.int64(128)), "float16"), p_lv48: T.handle, lv13_1: T.Buffer((T.int64(4096),), "float16"), p_lv3: T.handle, p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int64()
lv48 = T.match_buffer(p_lv48, (T.int64(1), n, T.int64(4096)), "float16")
lv3 = T.match_buffer(p_lv3, (T.int64(1), n, T.int64(4096)), "float16")
p_output0_intermediate = T.match_buffer(p_output0, (T.int64(1), n, T.int64(4096)), "float16")
# with T.sblock("root"):
var_matmul_intermediate_reindex_pad_local = T.sblock_alloc_buffer((T.int64(1), (n + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(4096)), scope="local")
lv48_reindex_pad_shared = T.sblock_alloc_buffer((T.int64(1), (n + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(4096)), "float16", scope="shared")
p_output0_intermediate_1_reindex_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(4096), T.int64(4096)), "float16", scope="shared")
for ax0_ax2_0_fused in T.thread_binding(T.int64(64), thread="blockIdx.y"):
for ax1_0 in T.thread_binding((n + T.int64(31)) // T.int64(32), thread="blockIdx.x"):
for ax2_1 in T.thread_binding(T.int64(1), thread="vthread.y"):
for ax1_1 in T.thread_binding(T.int64(1), thread="vthread.x"):
for ax2_2 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax1_2 in T.thread_binding(T.int64(8), thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(T.int64(4), T.int64(2)):
for ax2_3_1_init in T.vectorized(T.int64(2)):
with T.sblock("matmul_init"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3_init)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0_init * T.int64(2) + ax2_3_1_init)
T.reads()
T.writes(var_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2])
var_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2] = T.float32(0)
for ax3_0 in range(T.int64(256)):
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(2)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("lv48_reindex_pad_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(lv48[v0, v1, v2])
T.writes(lv48_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
lv48_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < n, lv48[v0, v1, v2], T.float16(0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(4)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("p_output0_intermediate_1_reindex_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(4096), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(lv13[v2, v1 // T.int64(8)], lv14[v2, v1 // T.int64(32)])
T.writes(p_output0_intermediate_1_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
p_output0_intermediate_1_reindex_shared[v0, v1, v2] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv13[v2, v1 // T.int64(8)], T.Cast("uint32", v1 % T.int64(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv14[v2, v1 // T.int64(32)]
for ax3_1, ax1_3, ax2_3_0 in T.grid(T.int64(16), T.int64(4), T.int64(2)):
for ax2_3_1 in T.vectorized(T.int64(2)):
with T.sblock("matmul_update"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0 * T.int64(2) + ax2_3_1)
v3 = T.axis.reduce(T.int64(4096), ax3_0 * T.int64(16) + ax3_1)
T.reads(var_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2], lv48_reindex_pad_shared[T.int64(0), v1, v3], p_output0_intermediate_1_reindex_shared[T.int64(0), v2, v3])
T.writes(var_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2])
var_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2] = var_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2] + T.Cast("float32", lv48_reindex_pad_shared[T.int64(0), v1, v3]) * T.Cast("float32", p_output0_intermediate_1_reindex_shared[T.int64(0), v2, v3])
for ax0, ax1, ax2_0 in T.grid(T.int64(1), T.int64(4), T.int64(2)):
for ax2_1_1 in T.vectorized(T.int64(2)):
with T.sblock("var_matmul_intermediate_reindex_pad_local"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1)
v2 = T.axis.spatial(T.int64(4096), ax0_ax2_0_fused * T.int64(64) + ax2_2 * T.int64(4) + ax2_0 * T.int64(2) + ax2_1_1)
T.where(ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1 < n)
T.reads(var_matmul_intermediate_reindex_pad_local[v0, v1, v2], lv13_1[v2], lv3[T.int64(0), v1, v2])
T.writes(p_output0_intermediate[T.int64(0), v1, v2])
p_output0_intermediate[T.int64(0), v1, v2] = T.Cast("float16", var_matmul_intermediate_reindex_pad_local[v0, v1, v2] + T.Cast("float32", lv13_1[v2])) + lv3[T.int64(0), v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_inline_consumer_chain():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(p_lv26: T.handle, lv9: T.Buffer((T.int64(2048), T.int64(2048)), "float16"), p_lv52: T.handle, p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int64()
lv26 = T.match_buffer(p_lv26, (n, T.int64(2048)), "float16")
lv52 = T.match_buffer(p_lv52, (T.int64(1), n, T.int64(2048)))
var_T_multiply_intermediate = T.match_buffer(p_output0, (n, T.int64(2048)), "float16")
# with T.sblock("root"):
var_NT_matmul_intermediate = T.sblock_alloc_buffer((n, T.int64(2048)), "float16")
compute = T.sblock_alloc_buffer((n, T.int64(2048)), "float16")
var_T_multiply_intermediate_1 = T.sblock_alloc_buffer((n, T.int64(2048)), "float16")
var_T_squeeze_intermediate = T.sblock_alloc_buffer((n, T.int64(2048)))
var_compute_intermediate = T.sblock_alloc_buffer((n, T.int64(2048)), "float16")
for i0, i1, k in T.grid(n, T.int64(2048), T.int64(2048)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_k = T.axis.remap("SSR", [i0, i1, k])
T.reads(lv26[v_i0, v_k], lv9[v_i1, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1] = var_NT_matmul_intermediate[v_i0, v_i1] + lv26[v_i0, v_k] * lv9[v_i1, v_k]
for i0, i1 in T.grid(n, T.int64(2048)):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(var_NT_matmul_intermediate[v_i0, v_i1])
T.writes(compute[v_i0, v_i1])
compute[v_i0, v_i1] = T.sigmoid(var_NT_matmul_intermediate[v_i0, v_i1])
for ax0, ax1 in T.grid(n, T.int64(2048)):
with T.sblock("T_multiply"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(var_NT_matmul_intermediate[v_ax0, v_ax1], compute[v_ax0, v_ax1])
T.writes(var_T_multiply_intermediate_1[v_ax0, v_ax1])
var_T_multiply_intermediate_1[v_ax0, v_ax1] = var_NT_matmul_intermediate[v_ax0, v_ax1] * compute[v_ax0, v_ax1]
for ax0, ax1 in T.grid(n, T.int64(2048)):
with T.sblock("T_squeeze"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(lv52[T.int64(0), v_ax0, v_ax1])
T.writes(var_T_squeeze_intermediate[v_ax0, v_ax1])
var_T_squeeze_intermediate[v_ax0, v_ax1] = lv52[T.int64(0), v_ax0, v_ax1]
for i0, i1 in T.grid(n, T.int64(2048)):
with T.sblock("compute_1"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(var_T_squeeze_intermediate[v_i0, v_i1])
T.writes(var_compute_intermediate[v_i0, v_i1])
var_compute_intermediate[v_i0, v_i1] = T.Cast("float16", var_T_squeeze_intermediate[v_i0, v_i1])
for ax0, ax1 in T.grid(n, T.int64(2048)):
with T.sblock("T_multiply_1"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(var_compute_intermediate[v_ax0, v_ax1], var_T_multiply_intermediate_1[v_ax0, v_ax1])
T.writes(var_T_multiply_intermediate[v_ax0, v_ax1])
var_T_multiply_intermediate[v_ax0, v_ax1] = var_compute_intermediate[v_ax0, v_ax1] * var_T_multiply_intermediate_1[v_ax0, v_ax1]
@T.prim_func(private=True, s_tir=True)
def expected(p_lv26: T.handle, lv9: T.Buffer((T.int64(2048), T.int64(2048)), "float16"), p_lv52: T.handle, p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int64()
lv26 = T.match_buffer(p_lv26, (n, T.int64(2048)), "float16")
lv52 = T.match_buffer(p_lv52, (T.int64(1), n, T.int64(2048)))
var_T_multiply_intermediate = T.match_buffer(p_output0, (n, T.int64(2048)), "float16")
# with T.sblock("root"):
var_NT_matmul_intermediate_reindex_pad_local = T.sblock_alloc_buffer((T.int64(1), (n + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(2048)), "float16", scope="local")
lv26_reindex_pad_shared = T.sblock_alloc_buffer((T.int64(1), (n + T.int64(31)) // T.int64(32) * T.int64(32), T.int64(2048)), "float16", scope="shared")
lv9_reindex_shared = T.sblock_alloc_buffer((T.int64(1), T.int64(2048), T.int64(2048)), "float16", scope="shared")
for ax0_ax2_0_fused in T.thread_binding(T.int64(32), thread="blockIdx.y"):
for ax1_0 in T.thread_binding((n + T.int64(31)) // T.int64(32), thread="blockIdx.x"):
for ax2_1 in T.thread_binding(T.int64(1), thread="vthread.y"):
for ax1_1 in T.thread_binding(T.int64(1), thread="vthread.x"):
for ax2_2 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax1_2 in T.thread_binding(T.int64(8), thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(T.int64(4), T.int64(2)):
for ax2_3_1_init in T.vectorized(T.int64(2)):
with T.sblock("NT_matmul_init"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3_init)
v2 = T.axis.spatial(T.int64(2048), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0_init * T.int64(2) + ax2_3_1_init)
T.reads()
T.writes(var_NT_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2])
var_NT_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2] = T.float16(0)
for ax3_0 in range(T.int64(128)):
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(2)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("lv26_reindex_pad_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(2048), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(32) + ax0_ax1_ax2_fused_1 * T.int64(4) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(lv26[v1, v2])
T.writes(lv26_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
lv26_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < n, lv26[v1, v2], T.float16(0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(T.int64(16), thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(T.int64(4)):
for ax0_ax1_ax2_fused_3 in T.vectorized(T.int64(2)):
with T.sblock("lv9_reindex_shared"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(T.int64(2048), ax0_ax2_0_fused * T.int64(64) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) // T.int64(16))
v2 = T.axis.spatial(T.int64(2048), ax3_0 * T.int64(16) + (ax0_ax1_ax2_fused_0 * T.int64(64) + ax0_ax1_ax2_fused_1 * T.int64(8) + ax0_ax1_ax2_fused_2 * T.int64(2) + ax0_ax1_ax2_fused_3) % T.int64(16))
T.reads(lv9[v1, v2])
T.writes(lv9_reindex_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
lv9_reindex_shared[v0, v1, v2] = lv9[v1, v2]
for ax3_1, ax1_3, ax2_3_0 in T.grid(T.int64(16), T.int64(4), T.int64(2)):
for ax2_3_1 in T.vectorized(T.int64(2)):
with T.sblock("NT_matmul_update"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_1 * T.int64(32) + ax1_2 * T.int64(4) + ax1_3)
v2 = T.axis.spatial(T.int64(2048), ax0_ax2_0_fused * T.int64(64) + ax2_1 * T.int64(64) + ax2_2 * T.int64(4) + ax2_3_0 * T.int64(2) + ax2_3_1)
v3 = T.axis.reduce(T.int64(2048), ax3_0 * T.int64(16) + ax3_1)
T.reads(var_NT_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2], lv26_reindex_pad_shared[T.int64(0), v1, v3], lv9_reindex_shared[T.int64(0), v2, v3])
T.writes(var_NT_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2])
var_NT_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2] = var_NT_matmul_intermediate_reindex_pad_local[T.int64(0), v1, v2] + lv26_reindex_pad_shared[T.int64(0), v1, v3] * lv9_reindex_shared[T.int64(0), v2, v3]
for ax0, ax1, ax2_0 in T.grid(T.int64(1), T.int64(4), T.int64(2)):
for ax2_1_1 in T.vectorized(T.int64(2)):
with T.sblock("var_NT_matmul_intermediate_reindex_pad_local"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((n + T.int64(31)) // T.int64(32) * T.int64(32), ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1)
v2 = T.axis.spatial(T.int64(2048), ax0_ax2_0_fused * T.int64(64) + ax2_2 * T.int64(4) + ax2_0 * T.int64(2) + ax2_1_1)
T.reads(lv52[T.int64(0), v1, v2], var_NT_matmul_intermediate_reindex_pad_local[v0, v1, v2])
T.where(ax1_0 * T.int64(32) + ax1_2 * T.int64(4) + ax1 < n)
T.writes(var_T_multiply_intermediate[v1, v2])
var_T_multiply_intermediate[v1, v2] = T.Cast("float16", lv52[T.int64(0), v1, v2]) * (var_NT_matmul_intermediate_reindex_pad_local[v0, v1, v2] * T.sigmoid(var_NT_matmul_intermediate_reindex_pad_local[v0, v1, v2]))
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-gtx-1080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_android():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_inp0: T.handle, inp1: T.Buffer((T.int64(4096), T.int64(4096)), "float32"), var_matmul: T.handle):
m = T.int64()
inp0 = T.match_buffer(var_inp0, (T.int64(1), m, T.int64(4096)))
matmul = T.match_buffer(var_matmul, (T.int64(1), m, T.int64(4096)))
for i0, i1, i2, k in T.grid(T.int64(1), m, T.int64(4096), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
with T.init():
matmul[v_i0, v_i1, v_i2] = T.float32(0)
matmul[v_i0, v_i1, v_i2] = matmul[v_i0, v_i1, v_i2] + inp0[v_i0, v_i1, v_k] * inp1[v_k, v_i2]
@T.prim_func(private=True, s_tir=True)
def expected(var_inp0: T.handle, inp1: T.Buffer((T.int64(4096), T.int64(4096)), "float32"), var_matmul: T.handle):
T.func_attr({"tirx.is_scheduled": True})
m = T.int64()
inp0 = T.match_buffer(var_inp0, (T.int64(1), m, T.int64(4096)))
matmul = T.match_buffer(var_matmul, (T.int64(1), m, T.int64(4096)))
# with T.sblock("root"):
inp0_reindex_pad = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(15)) // T.int64(16), T.int64(4096), T.int64(16)))
matmul_pad_local = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(15)) // T.int64(16) * T.int64(16), T.int64(4096)), scope="local")
inp0_reindex_pad_local = T.sblock_alloc_buffer((T.int64(1), (m + T.int64(15)) // T.int64(16), T.int64(4096), T.int64(16)), scope="local")
for i0 in T.thread_binding(T.int64(1), thread="blockIdx.z"):
for i1_0 in T.thread_binding(((m + T.int64(15)) // T.int64(16) * T.int64(16) + T.int64(63)) // T.int64(64), thread="blockIdx.y"):
for i2_0 in T.thread_binding(T.int64(128), thread="blockIdx.x"):
for i1_1 in T.thread_binding(T.int64(4), thread="threadIdx.y"):
for i2_1 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
for i1_2 in T.vectorized(T.int64(16)):
with T.sblock("inp0_reindex_pad"):
v0 = T.axis.spatial(T.int64(1), i0)
v1 = T.axis.spatial((m + T.int64(15)) // T.int64(16) * T.int64(16), i1_0 * T.int64(64) + i1_1 * T.int64(16) + i1_2)
v2 = T.axis.spatial(T.int64(4096), i2_0 * T.int64(32) + i2_1)
T.where((i1_0 * T.int64(4) + i1_1) * T.int64(16) + i1_2 < (m + T.int64(15)) // T.int64(16) * T.int64(16))
T.reads(inp0[v0, v1, v2])
T.writes(inp0_reindex_pad[v0, v1 // T.int64(16), v2, v1 % T.int64(16)])
inp0_reindex_pad[v0, v1 // T.int64(16), v2, v1 % T.int64(16)] = T.if_then_else(v1 < m, inp0[v0, v1, v2], T.float32(0))
for i2_0 in T.thread_binding(T.int64(16), thread="blockIdx.x"):
for i0_i1_fused_0 in T.thread_binding(((m + T.int64(15)) // T.int64(16) * T.int64(16) + T.int64(63)) // T.int64(64), thread="blockIdx.y"):
for i2_1 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
for i0_i1_fused_1 in T.thread_binding(T.int64(4), thread="threadIdx.y"):
for i0_i1_fused_2_init in T.unroll(T.int64(16)):
for i2_2_init in T.vectorized(T.int64(8)):
with T.sblock("matmul_init"):
v_i0 = T.axis.spatial(T.int64(1), T.int64(0))
v_i1 = T.axis.spatial((m + T.int64(15)) // T.int64(16) * T.int64(16), i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + i0_i1_fused_2_init)
v_i2 = T.axis.spatial(T.int64(4096), i2_0 * T.int64(256) + i2_1 * T.int64(8) + i2_2_init)
T.where((i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1) * T.int64(16) + i0_i1_fused_2_init < (m + T.int64(15)) // T.int64(16) * T.int64(16))
T.reads()
T.writes(matmul_pad_local[v_i0, v_i1, v_i2])
matmul_pad_local[v_i0, v_i1, v_i2] = T.float32(0)
for k_0, k_1 in T.grid(T.int64(128), T.int64(4)):
for k_2 in T.unroll(T.int64(8)):
for ax0, ax1, ax2 in T.grid(T.int64(1), T.int64(1), T.int64(1)):
for ax3 in T.vectorized(T.int64(16)):
with T.sblock("inp0_reindex_pad_local"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((m + T.int64(15)) // T.int64(16), i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1 + ax1)
v2 = T.axis.spatial(T.int64(4096), k_0 * T.int64(32) + k_1 * T.int64(8) + k_2 + ax2)
v3 = T.axis.spatial(T.int64(16), ax3)
T.where(i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1 < (m + T.int64(15)) // T.int64(16))
T.reads(inp0_reindex_pad[v0, v1, v2, v3])
T.writes(inp0_reindex_pad_local[v0, v1, v2, v3])
inp0_reindex_pad_local[v0, v1, v2, v3] = inp0_reindex_pad[v0, v1, v2, v3]
for i0_i1_fused_2 in T.unroll(T.int64(16)):
for i2_2 in T.vectorized(T.int64(8)):
with T.sblock("matmul_update"):
v_i0 = T.axis.spatial(T.int64(1), T.int64(0))
v_i1 = T.axis.spatial((m + T.int64(15)) // T.int64(16) * T.int64(16), i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + i0_i1_fused_2)
v_i2 = T.axis.spatial(T.int64(4096), i2_0 * T.int64(256) + i2_1 * T.int64(8) + i2_2)
v_k = T.axis.reduce(T.int64(4096), k_0 * T.int64(32) + k_1 * T.int64(8) + k_2)
T.where((i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1) * T.int64(16) + i0_i1_fused_2 < (m + T.int64(15)) // T.int64(16) * T.int64(16))
T.reads(matmul_pad_local[v_i0, v_i1, v_i2], inp0_reindex_pad_local[v_i0, v_i1 // T.int64(16), v_k, v_i1 % T.int64(16)], inp1[v_k, v_i2])
T.writes(matmul_pad_local[v_i0, v_i1, v_i2])
matmul_pad_local[v_i0, v_i1, v_i2] = matmul_pad_local[v_i0, v_i1, v_i2] + inp0_reindex_pad_local[v_i0, v_i1 // T.int64(16), v_k, v_i1 % T.int64(16)] * inp1[v_k, v_i2]
for ax0 in T.unroll(T.int64(16)):
for ax1 in T.vectorized(T.int64(8)):
with T.sblock("matmul_pad"):
v0 = T.axis.spatial(T.int64(1), T.int64(0))
v1 = T.axis.spatial(m, i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + ax0)
v2 = T.axis.spatial(T.int64(4096), i2_0 * T.int64(256) + i2_1 * T.int64(8) + ax1)
T.where((i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1 - (m + T.int64(15)) // T.int64(16) < T.int64(0) or i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + ax0 == T.int64(0)) and i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + ax0 < m)
T.reads(matmul_pad_local[v0, v1, v2])
T.writes(matmul[v0, v1, v2])
matmul[v0, v1, v2] = matmul_pad_local[v0, v1, v2]
mod = tvm.IRModule({"main": before})
with Target("opencl", host={"kind": "llvm", "mtriple": "aarch64-linux-android"}):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_fused_dequant_matmul_android():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv452: T.Buffer((T.int64(512), T.int64(12288)), "uint32"), lv453: T.Buffer((T.int64(128), T.int64(12288)), "float16"), p_rms_norm130: T.handle, transformer_h_0_attn_c_attn_bias3: T.Buffer((T.int64(12288),), "float16"), p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
seq_len = T.int64()
rms_norm130 = T.match_buffer(p_rms_norm130, (T.int64(1), seq_len, T.int64(4096)), "float16")
T_add_intermediate_intermediate = T.match_buffer(p_output0, (T.int64(1), seq_len, T.int64(12288)), "float16")
# with T.sblock("root"):
compute = T.sblock_alloc_buffer((T.int64(4096), T.int64(12288)), "float16")
dequantize_intermediate_intermediate = T.sblock_alloc_buffer((T.int64(4096), T.int64(12288)), "float16")
matmul_intermediate = T.sblock_alloc_buffer((T.int64(1), seq_len, T.int64(12288)), "float16")
for i0, i1 in T.grid(T.int64(4096), T.int64(12288)):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(lv452[v_i0 // T.int64(8), v_i1])
T.writes(compute[v_i0, v_i1])
compute[v_i0, v_i1] = T.Cast("float16", T.bitwise_and(T.shift_right(lv452[v_i0 // T.int64(8), v_i1], T.Cast("uint32", v_i0 % T.int64(8) * T.int64(4))), T.uint32(15)))
for i0, i1 in T.grid(T.int64(4096), T.int64(12288)):
with T.sblock("dequantize"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
T.reads(compute[v_i0, v_i1], lv453[v_i0 // T.int64(32), v_i1])
T.writes(dequantize_intermediate_intermediate[v_i0, v_i1])
dequantize_intermediate_intermediate[v_i0, v_i1] = (compute[v_i0, v_i1] - T.float16(7)) * lv453[v_i0 // T.int64(32), v_i1]
for i0, i1, i2, k in T.grid(T.int64(1), seq_len, T.int64(12288), T.int64(4096)):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(rms_norm130[v_i0, v_i1, v_k], dequantize_intermediate_intermediate[v_k, v_i2])
T.writes(matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
matmul_intermediate[v_i0, v_i1, v_i2] = matmul_intermediate[v_i0, v_i1, v_i2] + rms_norm130[v_i0, v_i1, v_k] * dequantize_intermediate_intermediate[v_k, v_i2]
for ax0, ax1, ax2 in T.grid(T.int64(1), seq_len, T.int64(12288)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(matmul_intermediate[v_ax0, v_ax1, v_ax2], transformer_h_0_attn_c_attn_bias3[v_ax2])
T.writes(T_add_intermediate_intermediate[v_ax0, v_ax1, v_ax2])
T_add_intermediate_intermediate[v_ax0, v_ax1, v_ax2] = matmul_intermediate[v_ax0, v_ax1, v_ax2] + transformer_h_0_attn_c_attn_bias3[v_ax2]
@T.prim_func(private=True, s_tir=True)
def expected(lv452: T.Buffer((T.int64(512), T.int64(12288)), "uint32"), lv453: T.Buffer((T.int64(128), T.int64(12288)), "float16"), p_rms_norm130: T.handle, transformer_h_0_attn_c_attn_bias3: T.Buffer((T.int64(12288),), "float16"), p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
seq_len = T.int64()
rms_norm130 = T.match_buffer(p_rms_norm130, (T.int64(1), seq_len, T.int64(4096)), "float16")
T_add_intermediate_intermediate = T.match_buffer(p_output0, (T.int64(1), seq_len, T.int64(12288)), "float16")
# with T.sblock("root"):
dequantize_intermediate_intermediate_local = T.sblock_alloc_buffer((T.int64(4096), T.int64(12288)), "float16", scope="local")
rms_norm130_reindex_pad = T.sblock_alloc_buffer((T.int64(1), (seq_len + T.int64(15)) // T.int64(16), T.int64(4096), T.int64(16)), "float16")
matmul_intermediate_pad_local = T.sblock_alloc_buffer((T.int64(1), (seq_len + T.int64(15)) // T.int64(16) * T.int64(16), T.int64(12288)), "float16", scope="local")
rms_norm130_reindex_pad_local = T.sblock_alloc_buffer((T.int64(1), (seq_len + T.int64(15)) // T.int64(16), T.int64(4096), T.int64(16)), "float16", scope="local")
lv452_local = T.sblock_alloc_buffer((T.int64(512), T.int64(12288)), "uint32", scope="local")
lv453_local = T.sblock_alloc_buffer((T.int64(128), T.int64(12288)), "float16", scope="local")
for i0 in T.thread_binding(T.int64(1), thread="blockIdx.z"):
for i1_0 in T.thread_binding(((seq_len + T.int64(15)) // T.int64(16) * T.int64(16) + T.int64(63)) // T.int64(64), thread="blockIdx.y"):
for i2_0 in T.thread_binding(T.int64(128), thread="blockIdx.x"):
for i1_1 in T.thread_binding(T.int64(4), thread="threadIdx.y"):
for i2_1 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
for i1_2 in T.vectorized(T.int64(16)):
with T.sblock("rms_norm130_reindex_pad"):
v0 = T.axis.spatial(T.int64(1), i0)
v1 = T.axis.spatial((seq_len + T.int64(15)) // T.int64(16) * T.int64(16), i1_0 * T.int64(64) + i1_1 * T.int64(16) + i1_2)
v2 = T.axis.spatial(T.int64(4096), i2_0 * T.int64(32) + i2_1)
T.where((i1_0 * T.int64(4) + i1_1) * T.int64(16) + i1_2 < (seq_len + T.int64(15)) // T.int64(16) * T.int64(16))
T.reads(rms_norm130[v0, v1, v2])
T.writes(rms_norm130_reindex_pad[v0, v1 // T.int64(16), v2, v1 % T.int64(16)])
rms_norm130_reindex_pad[v0, v1 // T.int64(16), v2, v1 % T.int64(16)] = T.if_then_else(v1 < seq_len, rms_norm130[v0, v1, v2], T.float16(0))
for i2_0 in T.thread_binding(T.int64(48), thread="blockIdx.x"):
for i0_i1_fused_0 in T.thread_binding(((seq_len + T.int64(15)) // T.int64(16) * T.int64(16) + T.int64(63)) // T.int64(64), thread="blockIdx.y"):
for i2_1 in T.thread_binding(T.int64(32), thread="threadIdx.x"):
for i0_i1_fused_1 in T.thread_binding(T.int64(4), thread="threadIdx.y"):
for i0_i1_fused_2_init in T.unroll(T.int64(16)):
for i2_2_init in T.vectorized(T.int64(8)):
with T.sblock("matmul_init"):
v_i0 = T.axis.spatial(T.int64(1), T.int64(0))
v_i1 = T.axis.spatial((seq_len + T.int64(15)) // T.int64(16) * T.int64(16), i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + i0_i1_fused_2_init)
v_i2 = T.axis.spatial(T.int64(12288), i2_0 * T.int64(256) + i2_1 * T.int64(8) + i2_2_init)
T.where((i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1) * T.int64(16) + i0_i1_fused_2_init < (seq_len + T.int64(15)) // T.int64(16) * T.int64(16))
T.reads()
T.writes(matmul_intermediate_pad_local[v_i0, v_i1, v_i2])
matmul_intermediate_pad_local[v_i0, v_i1, v_i2] = T.float16(0)
for k_0 in range(T.int64(128)):
for ax0 in range(T.int64(1)):
for ax1 in T.vectorized(T.int64(8)):
with T.sblock("lv453_local"):
v0 = T.axis.spatial(T.int64(128), k_0 + ax0)
v1 = T.axis.spatial(T.int64(12288), i2_0 * T.int64(256) + i2_1 * T.int64(8) + ax1)
T.reads(lv453[v0, v1])
T.writes(lv453_local[v0, v1])
lv453_local[v0, v1] = lv453[v0, v1]
for k_1 in range(T.int64(4)):
for ax0 in range(T.int64(1)):
for ax1 in T.vectorized(T.int64(8)):
with T.sblock("lv452_local"):
v0 = T.axis.spatial(T.int64(512), k_0 * T.int64(4) + k_1 + ax0)
v1 = T.axis.spatial(T.int64(12288), i2_0 * T.int64(256) + i2_1 * T.int64(8) + ax1)
T.reads(lv452[v0, v1])
T.writes(lv452_local[v0, v1])
lv452_local[v0, v1] = lv452[v0, v1]
for k_2 in T.unroll(T.int64(8)):
for ax0 in T.vectorized(T.int64(8)):
with T.sblock("dequantize"):
v_i0 = T.axis.spatial(T.int64(4096), k_0 * T.int64(32) + k_1 * T.int64(8) + k_2)
v_i1 = T.axis.spatial(T.int64(12288), i2_0 * T.int64(256) + i2_1 * T.int64(8) + ax0)
T.reads(lv452_local[v_i0 // T.int64(8), v_i1], lv453_local[v_i0 // T.int64(32), v_i1])
T.writes(dequantize_intermediate_intermediate_local[v_i0, v_i1])
dequantize_intermediate_intermediate_local[v_i0, v_i1] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv452_local[v_i0 // T.int64(8), v_i1], T.Cast("uint32", v_i0 % T.int64(8) * T.int64(4))), T.uint32(15))) - T.float16(7)) * lv453_local[v_i0 // T.int64(32), v_i1]
for ax0, ax1, ax2 in T.grid(T.int64(1), T.int64(1), T.int64(1)):
for ax3 in T.vectorized(T.int64(16)):
with T.sblock("rms_norm130_reindex_pad_local"):
v0 = T.axis.spatial(T.int64(1), ax0)
v1 = T.axis.spatial((seq_len + T.int64(15)) // T.int64(16), i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1 + ax1)
v2 = T.axis.spatial(T.int64(4096), k_0 * T.int64(32) + k_1 * T.int64(8) + k_2 + ax2)
v3 = T.axis.spatial(T.int64(16), ax3)
T.where(i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1 < (seq_len + T.int64(15)) // T.int64(16))
T.reads(rms_norm130_reindex_pad[v0, v1, v2, v3])
T.writes(rms_norm130_reindex_pad_local[v0, v1, v2, v3])
rms_norm130_reindex_pad_local[v0, v1, v2, v3] = rms_norm130_reindex_pad[v0, v1, v2, v3]
for i0_i1_fused_2 in T.unroll(T.int64(16)):
for i2_2 in T.vectorized(T.int64(8)):
with T.sblock("matmul_update"):
v_i0 = T.axis.spatial(T.int64(1), T.int64(0))
v_i1 = T.axis.spatial((seq_len + T.int64(15)) // T.int64(16) * T.int64(16), i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + i0_i1_fused_2)
v_i2 = T.axis.spatial(T.int64(12288), i2_0 * T.int64(256) + i2_1 * T.int64(8) + i2_2)
v_k = T.axis.reduce(T.int64(4096), k_0 * T.int64(32) + k_1 * T.int64(8) + k_2)
T.where((i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1) * T.int64(16) + i0_i1_fused_2 < (seq_len + T.int64(15)) // T.int64(16) * T.int64(16))
T.reads(matmul_intermediate_pad_local[v_i0, v_i1, v_i2], rms_norm130_reindex_pad_local[v_i0, v_i1 // T.int64(16), v_k, v_i1 % T.int64(16)], dequantize_intermediate_intermediate_local[v_k, v_i2])
T.writes(matmul_intermediate_pad_local[v_i0, v_i1, v_i2])
matmul_intermediate_pad_local[v_i0, v_i1, v_i2] = matmul_intermediate_pad_local[v_i0, v_i1, v_i2] + rms_norm130_reindex_pad_local[v_i0, v_i1 // T.int64(16), v_k, v_i1 % T.int64(16)] * dequantize_intermediate_intermediate_local[v_k, v_i2]
for ax0 in T.unroll(T.int64(16)):
for ax1 in T.vectorized(T.int64(8)):
with T.sblock("T_add"):
v_ax0 = T.axis.spatial(T.int64(1), T.int64(0))
v_ax1 = T.axis.spatial(seq_len, i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + ax0)
v_ax2 = T.axis.spatial(T.int64(12288), i2_0 * T.int64(256) + i2_1 * T.int64(8) + ax1)
T.where((i0_i1_fused_0 * T.int64(4) + i0_i1_fused_1 - (seq_len + T.int64(15)) // T.int64(16) < T.int64(0) or i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + ax0 == T.int64(0)) and i0_i1_fused_0 * T.int64(64) + i0_i1_fused_1 * T.int64(16) + ax0 < seq_len)
T.reads(matmul_intermediate_pad_local[v_ax0, v_ax1, v_ax2], transformer_h_0_attn_c_attn_bias3[v_ax2])
T.writes(T_add_intermediate_intermediate[v_ax0, v_ax1, v_ax2])
T_add_intermediate_intermediate[v_ax0, v_ax1, v_ax2] = matmul_intermediate_pad_local[v_ax0, v_ax1, v_ax2] + transformer_h_0_attn_c_attn_bias3[v_ax2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("opencl", host={"kind": "llvm", "mtriple": "aarch64-linux-android"}):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,994 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring, unused-variable, invalid-name
# ruff: noqa: E501, F841
import tvm
import tvm.testing
from tvm.s_tir import dlight as dl
from tvm.script import tirx as T
from tvm.target import Target
def test_matmul_tensorize():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(X: T.Buffer((256, 256), "float16"), W: T.Buffer((256, 256), "float16"), compute: T.Buffer((256, 256), "float16")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
for i, j, k in T.grid(256, 256, 256):
with T.sblock("compute"):
v_i, v_j, v_k = T.axis.remap("SSR", [i, j, k])
T.reads(X[v_i, v_k], W[v_j, v_k])
T.writes(compute[v_i, v_j])
with T.init():
compute[v_i, v_j] = T.float16(0)
compute[v_i, v_j] = compute[v_i, v_j] + X[v_i, v_k] * W[v_j, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(X: T.Buffer((256, 256), "float16"), W: T.Buffer((256, 256), "float16"), compute: T.Buffer((256, 256), "float16")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
X_reindex_shared_dyn = T.sblock_alloc_buffer((1, 256, 256), "float16", scope="shared.dyn")
W_reindex_shared_dyn = T.sblock_alloc_buffer((1, 256, 256), "float16", scope="shared.dyn")
X_reindex_shared_dyn_wmma_matrix_a = T.sblock_alloc_buffer((1, 256, 256), "float16", scope="wmma.matrix_a")
W_reindex_shared_dyn_wmma_matrix_b = T.sblock_alloc_buffer((1, 256, 256), "float16", scope="wmma.matrix_b")
compute_reindex_shared_dyn = T.sblock_alloc_buffer((1, 256, 256), "float16", scope="shared.dyn")
compute_reindex_shared_dyn_wmma_accumulator = T.sblock_alloc_buffer((1, 256, 256), "float16", scope="wmma.accumulator")
for ax0 in T.thread_binding(1, thread="blockIdx.z"):
for ax1_0_0_ax2_0_0_fused in T.thread_binding(2, thread="blockIdx.x"):
for ax1_0_1_ax2_0_1_fused in T.thread_binding(2, thread="blockIdx.y"):
for ax2_0_2_ax1_0_2_fused in T.thread_binding(16, thread="threadIdx.y"):
for ax1_0_3_init, ax2_0_3_init in T.grid(2, 2):
with T.sblock("compute_o_init"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3_init)
v2_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3_init)
T.reads()
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("compute_init_o"):
v1_i_init_o = T.axis.spatial(1, 0)
v2_i_init_o = T.axis.spatial(1, 0)
T.reads()
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
C = T.match_buffer(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_fill_fragment(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.float32(0))
for ax3_0_0 in range(4, annotations={"software_pipeline_order": [0, 3, 1, 4, 5, 2, 6], "software_pipeline_stage": [0, 0, 0, 0, 0, 1, 1]}):
for ax0_ax1_fused_0 in range(4):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("X_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(256, ax1_0_0_ax2_0_0_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 64)
v2 = T.axis.spatial(256, ax3_0_0 * 64 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 64)
T.reads(X[v1, v2])
T.writes(X_reindex_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 8]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
X_reindex_shared_dyn[v0, v1, v2] = X[v1, v2]
for ax0_ax1_fused_0 in range(4):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("W_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 64)
v2 = T.axis.spatial(256, ax3_0_0 * 64 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 64)
T.reads(W[v1, v2])
T.writes(W_reindex_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 8]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
W_reindex_shared_dyn[v0, v1, v2] = W[v1, v2]
for ax3_0_1 in range(4, annotations={"software_pipeline_order": [0, 1, 2], "software_pipeline_stage": [0, 0, 1]}):
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("X_reindex_shared.dyn_wmma.matrix_a_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(16, ax3_0_0 * 4 + ax3_0_1 + ax1_0)
T.reads(X_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(X_reindex_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(X_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(X_reindex_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.matrix_a", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("float16"), A.data, A.elem_offset, A.strides[0] * 16, 1), A.strides[0], "row_major")
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("W_reindex_shared.dyn_wmma.matrix_b_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax0_0)
v2_o = T.axis.spatial(16, ax3_0_0 * 4 + ax3_0_1 + ax1_0)
T.reads(W_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(W_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(W_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(W_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.matrix_b", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("float16"), A.data, A.elem_offset, A.strides[0] * 16, 1), A.strides[0], "col_major")
for ax1_0_3, ax2_0_3 in T.grid(2, 2):
with T.sblock("compute_o_update"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3)
v2_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3)
v3_o = T.axis.reduce(16, ax3_0_0 * 4 + ax3_0_1)
T.reads(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], X_reindex_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], W_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("compute_o"):
v1_i_o = T.axis.spatial(1, 0)
v2_i_o = T.axis.spatial(1, 0)
v3_i_o = T.axis.reduce(1, 0)
T.reads(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], X_reindex_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], W_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(X_reindex_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="wmma.matrix_a", offset_factor=16)
B = T.match_buffer(W_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "float16", strides=("B_s0", "B_s1"), scope="wmma.matrix_b", offset_factor=16)
C = T.match_buffer(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_mma_sync(C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, A.data, A.elem_offset // A.strides[0] // 16 * (A.strides[0] // 16) + A.elem_offset % A.strides[0] // 16, B.data, B.elem_offset // B.strides[0] // 16 * (B.strides[0] // 16) + B.elem_offset % B.strides[0] // 16, C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16)
for ax0_0, ax1_0 in T.grid(2, 2):
with T.sblock("compute_reindex_shared.dyn_wmma.accumulator_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax1_0)
T.reads(compute_reindex_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(compute_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(compute_reindex_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="wmma.accumulator", offset_factor=16)
C = T.match_buffer(compute_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="shared.dyn", offset_factor=16)
T.tvm_store_matrix_sync(A.data, 16, 16, 16, A.elem_offset // A.strides[0] // 16 * (A.strides[0] // 16) + A.elem_offset % A.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("float16"), C.data, C.elem_offset, C.strides[0] * 16, 2), C.strides[0], "row_major")
for ax0_ax1_fused_0 in range(8):
for ax0_ax1_fused_1 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_2 in T.vectorized(4):
with T.sblock("compute_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(256, ax1_0_0_ax2_0_0_fused * 128 + ax2_0_2_ax1_0_2_fused % 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) // 32)
v2 = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 128 + ax2_0_2_ax1_0_2_fused // 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) % 32)
T.reads(compute_reindex_shared_dyn[v0, v1, v2])
T.writes(compute[v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 4]]})
compute[v1, v2] = compute_reindex_shared_dyn[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-rtx-2080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_tensorize_too_small():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_X: T.handle, W: T.Buffer((15, 256), "float16"), var_compute: T.handle):
T.func_attr({"tirx.noalias": True})
m = T.int32()
X = T.match_buffer(var_X, (m, 256), "float16")
compute = T.match_buffer(var_compute, (m, 15))
# with T.sblock("root"):
for i, j, k in T.grid(m, 15, 256):
with T.sblock("compute"):
v_i, v_j, v_k = T.axis.remap("SSR", [i, j, k])
T.reads(X[v_i, v_k], W[v_j, v_k])
T.writes(compute[v_i, v_j])
with T.init():
compute[v_i, v_j] = T.float32(0)
compute[v_i, v_j] = compute[v_i, v_j] + T.Cast("float32", X[v_i, v_k]) * T.Cast("float32", W[v_j, v_k])
@T.prim_func(private=True, s_tir=True)
def expected(var_X: T.handle, W: T.Buffer((15, 256), "float16"), var_compute: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
m = T.int32()
X = T.match_buffer(var_X, (m, 256), "float16")
compute = T.match_buffer(var_compute, (m, 15))
# with T.sblock("root"):
compute_reindex_pad_local = T.sblock_alloc_buffer((1, (m + 31) // 32 * 32, 64), scope="local")
X_reindex_pad_shared = T.sblock_alloc_buffer((1, (m + 31) // 32 * 32, 256), "float16", scope="shared")
W_reindex_pad_shared = T.sblock_alloc_buffer((1, 64, 256), "float16", scope="shared")
for ax0_ax2_0_fused in T.thread_binding(1, thread="blockIdx.y"):
for ax1_0 in T.thread_binding((m + 31) // 32, thread="blockIdx.x"):
for ax2_1 in T.thread_binding(1, thread="vthread.y"):
for ax1_1 in T.thread_binding(1, thread="vthread.x"):
for ax2_2 in T.thread_binding(16, thread="threadIdx.y"):
for ax1_2 in T.thread_binding(8, thread="threadIdx.x", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_3_init, ax2_3_0_init in T.grid(4, 2):
for ax2_3_1_init in T.vectorized(2):
with T.sblock("compute_init"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + ax1_1 * 32 + ax1_2 * 4 + ax1_3_init)
v2 = T.axis.spatial(64, ax2_1 * 64 + ax2_2 * 4 + ax2_3_0_init * 2 + ax2_3_1_init)
T.reads()
T.writes(compute_reindex_pad_local[0, v1, v2])
compute_reindex_pad_local[0, v1, v2] = T.float32(0)
for ax3_0 in range(16):
for ax0_ax1_ax2_fused_0 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(8, thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(2):
for ax0_ax1_ax2_fused_3 in T.vectorized(2):
with T.sblock("X_reindex_pad_shared"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + (ax0_ax1_ax2_fused_0 * 32 + ax0_ax1_ax2_fused_1 * 4 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) // 16)
v2 = T.axis.spatial(256, ax3_0 * 16 + (ax0_ax1_ax2_fused_0 * 32 + ax0_ax1_ax2_fused_1 * 4 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) % 16)
T.reads(X[v1, v2])
T.writes(X_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
X_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < m, X[v1, v2], T.float16(0))
for ax0_ax1_ax2_fused_0 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_ax2_fused_1 in T.thread_binding(8, thread="threadIdx.x"):
for ax0_ax1_ax2_fused_2 in range(4):
for ax0_ax1_ax2_fused_3 in T.vectorized(2):
with T.sblock("W_reindex_pad_shared"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(64, (ax0_ax1_ax2_fused_0 * 64 + ax0_ax1_ax2_fused_1 * 8 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) // 16)
v2 = T.axis.spatial(256, ax3_0 * 16 + (ax0_ax1_ax2_fused_0 * 64 + ax0_ax1_ax2_fused_1 * 8 + ax0_ax1_ax2_fused_2 * 2 + ax0_ax1_ax2_fused_3) % 16)
T.reads(W[v1, v2])
T.writes(W_reindex_pad_shared[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 8, 2]]})
W_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < 15, W[v1, v2], T.float16(0))
for ax3_1, ax1_3, ax2_3_0 in T.grid(16, 4, 2):
for ax2_3_1 in T.vectorized(2):
with T.sblock("compute_update"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + ax1_1 * 32 + ax1_2 * 4 + ax1_3)
v2 = T.axis.spatial(64, ax2_1 * 64 + ax2_2 * 4 + ax2_3_0 * 2 + ax2_3_1)
v3 = T.axis.reduce(256, ax3_0 * 16 + ax3_1)
T.reads(compute_reindex_pad_local[0, v1, v2], X_reindex_pad_shared[0, v1, v3], W_reindex_pad_shared[0, v2, v3])
T.writes(compute_reindex_pad_local[0, v1, v2])
compute_reindex_pad_local[0, v1, v2] = compute_reindex_pad_local[0, v1, v2] + T.Cast("float32", X_reindex_pad_shared[0, v1, v3]) * T.Cast("float32", W_reindex_pad_shared[0, v2, v3])
for ax0, ax1, ax2_0 in T.grid(1, 4, 2):
for ax2_1_1 in T.vectorized(2):
with T.sblock("compute_reindex_pad_local"):
v0 = T.axis.spatial(1, ax0)
v1 = T.axis.spatial((m + 31) // 32 * 32, ax1_0 * 32 + ax1_2 * 4 + ax1)
v2 = T.axis.spatial(64, ax2_2 * 4 + ax2_0 * 2 + ax2_1_1)
T.where(ax1_0 * 32 + ax1_2 * 4 + ax1 < m and ax2_2 * 4 + ax2_0 * 2 + ax2_1_1 < 15)
T.reads(compute_reindex_pad_local[v0, v1, v2])
T.writes(compute[v1, v2])
compute[v1, v2] = compute_reindex_pad_local[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-rtx-2080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_tensorize_epilogue():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(lv686: T.Buffer((T.int32(4096), T.int32(256)), "uint32"), lv687: T.Buffer((T.int32(4096), T.int32(64)), "float16"), p_lv42: T.handle, p_lv3: T.handle, p_output0: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int32()
lv42 = T.match_buffer(p_lv42, (T.int32(1), n, T.int32(2048)), "float16")
lv3 = T.match_buffer(p_lv3, (T.int32(1), n, T.int32(4096)), "float16")
p_output0_intermediate = T.match_buffer(p_output0, (T.int32(1), n, T.int32(4096)), "float16")
# with T.sblock("root"):
p_output0_intermediate_1 = T.sblock_alloc_buffer((T.int32(4096), T.int32(2048)), "float16")
var_NT_matmul_intermediate = T.sblock_alloc_buffer((T.int32(1), n, T.int32(4096)), "float16")
var_T_divide_intermediate = T.sblock_alloc_buffer((T.int32(1), n, T.int32(4096)), "float16")
for i, j in T.grid(T.int32(4096), T.int32(2048)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(lv686[v_i, v_j // T.int32(8)], lv687[v_i, v_j // T.int32(32)])
T.writes(p_output0_intermediate_1[v_i, v_j])
p_output0_intermediate_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv686[v_i, v_j // T.int32(8)], T.Cast("uint32", v_j % T.int32(8)) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv687[v_i, v_j // T.int32(32)]
for i0, i1, i2, k in T.grid(T.int32(1), n, T.int32(4096), T.int32(2048)):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(lv42[v_i0, v_i1, v_k], p_output0_intermediate_1[v_i2, v_k])
T.writes(var_NT_matmul_intermediate[v_i0, v_i1, v_i2])
with T.init():
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = T.float16(0)
var_NT_matmul_intermediate[v_i0, v_i1, v_i2] = var_NT_matmul_intermediate[v_i0, v_i1, v_i2] + lv42[v_i0, v_i1, v_k] * p_output0_intermediate_1[v_i2, v_k]
for ax0, ax1, ax2 in T.grid(T.int32(1), n, T.int32(4096)):
with T.sblock("T_divide"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(lv3[v_ax0, v_ax1, v_ax2])
T.writes(var_T_divide_intermediate[v_ax0, v_ax1, v_ax2])
var_T_divide_intermediate[v_ax0, v_ax1, v_ax2] = lv3[v_ax0, v_ax1, v_ax2] * T.float16(0.5)
for ax0, ax1, ax2 in T.grid(T.int32(1), n, T.int32(4096)):
with T.sblock("T_add"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(var_T_divide_intermediate[v_ax0, v_ax1, v_ax2], var_NT_matmul_intermediate[v_ax0, v_ax1, v_ax2])
T.writes(p_output0_intermediate[v_ax0, v_ax1, v_ax2])
p_output0_intermediate[v_ax0, v_ax1, v_ax2] = var_T_divide_intermediate[v_ax0, v_ax1, v_ax2] + var_NT_matmul_intermediate[v_ax0, v_ax1, v_ax2]
@T.prim_func(private=True, s_tir=True)
def expected(lv686: T.Buffer((4096, 256), "uint32"), lv687: T.Buffer((4096, 64), "float16"), p_lv42: T.handle, p_lv3: T.handle, p_output0: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int32()
lv42 = T.match_buffer(p_lv42, (1, n, 2048), "float16")
lv3 = T.match_buffer(p_lv3, (1, n, 4096), "float16")
p_output0_intermediate = T.match_buffer(p_output0, (1, n, 4096), "float16")
# with T.sblock("root"):
lv42_reindex_pad_shared_dyn = T.sblock_alloc_buffer((1, (n + 127) // 128 * 128, 2048), "float16", scope="shared.dyn")
p_output0_intermediate_1_reindex_shared_dyn = T.sblock_alloc_buffer((1, 4096, 2048), "float16", scope="shared.dyn")
lv42_reindex_pad_shared_dyn_wmma_matrix_a = T.sblock_alloc_buffer((1, (n + 127) // 128 * 128, 2048), "float16", scope="wmma.matrix_a")
p_output0_intermediate_1_reindex_shared_dyn_wmma_matrix_b = T.sblock_alloc_buffer((1, 4096, 2048), "float16", scope="wmma.matrix_b")
var_NT_matmul_intermediate_reindex_pad_shared_dyn = T.sblock_alloc_buffer((1, (n + 127) // 128 * 128, 4096), "float16", scope="shared.dyn")
var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator = T.sblock_alloc_buffer((1, (n + 127) // 128 * 128, 4096), "float16", scope="wmma.accumulator")
for ax0 in T.thread_binding(1, thread="blockIdx.z"):
for ax1_0_0_ax2_0_0_fused in T.thread_binding((n + 127) // 128, thread="blockIdx.x"):
for ax1_0_1_ax2_0_1_fused in T.thread_binding(32, thread="blockIdx.y"):
for ax2_0_2_ax1_0_2_fused in T.thread_binding(16, thread="threadIdx.y"):
for ax1_0_3_init, ax2_0_3_init in T.grid(2, 2):
with T.sblock("NT_matmul_o_init"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial((n + 127) // 128 * 8, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3_init)
v2_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3_init)
T.reads()
T.writes(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("NT_matmul_init_o"):
v1_i_init_o = T.axis.spatial(1, 0)
v2_i_init_o = T.axis.spatial(1, 0)
T.reads()
T.writes(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
C = T.match_buffer(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_fill_fragment(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.float32(0))
for ax3_0_0 in range(32, annotations={"software_pipeline_order": [0, 3, 1, 4, 5, 2, 6], "software_pipeline_stage": [0, 0, 0, 0, 0, 1, 1]}):
for ax0_ax1_fused_0 in range(4):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("lv42_reindex_pad_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((n + 127) // 128 * 128, ax1_0_0_ax2_0_0_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 64)
v2 = T.axis.spatial(2048, ax3_0_0 * 64 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 64)
T.reads(lv42[v0, v1, v2])
T.writes(lv42_reindex_pad_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 8]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
lv42_reindex_pad_shared_dyn[v0, v1, v2] = T.if_then_else(v1 < n, lv42[v0, v1, v2], T.float16(0))
for ax0_ax1_fused_0 in range(4):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("p_output0_intermediate_1_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(4096, ax1_0_1_ax2_0_1_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 64)
v2 = T.axis.spatial(2048, ax3_0_0 * 64 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 64)
T.reads(lv686[v1, v2 // 8], lv687[v1, v2 // 32])
T.writes(p_output0_intermediate_1_reindex_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 8]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
p_output0_intermediate_1_reindex_shared_dyn[v0, v1, v2] = (T.Cast("float16", T.bitwise_and(T.shift_right(lv686[v1, v2 // 8], T.Cast("uint32", v2 % 8) * T.uint32(4)), T.uint32(15))) - T.float16(7)) * lv687[v1, v2 // 32]
for ax3_0_1 in range(4, annotations={"software_pipeline_order": [0, 1, 2], "software_pipeline_stage": [0, 0, 1]}):
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("lv42_reindex_pad_shared.dyn_wmma.matrix_a_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(8 * ((n + 127) // 128), ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(128, ax3_0_0 * 4 + ax3_0_1 + ax1_0)
T.reads(lv42_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(lv42_reindex_pad_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(lv42_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(lv42_reindex_pad_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.matrix_a", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("float16"), A.data, A.elem_offset, A.strides[0] * 16, 1), A.strides[0], "row_major")
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("p_output0_intermediate_1_reindex_shared.dyn_wmma.matrix_b_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax0_0)
v2_o = T.axis.spatial(128, ax3_0_0 * 4 + ax3_0_1 + ax1_0)
T.reads(p_output0_intermediate_1_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(p_output0_intermediate_1_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(p_output0_intermediate_1_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(p_output0_intermediate_1_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.matrix_b", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("float16"), A.data, A.elem_offset, A.strides[0] * 16, 1), A.strides[0], "col_major")
for ax1_0_3, ax2_0_3 in T.grid(2, 2):
with T.sblock("NT_matmul_o_update"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial((n + 127) // 128 * 8, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3)
v2_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3)
v3_o = T.axis.reduce(128, ax3_0_0 * 4 + ax3_0_1)
T.reads(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], lv42_reindex_pad_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], p_output0_intermediate_1_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("NT_matmul_o"):
v1_i_o = T.axis.spatial(1, 0)
v2_i_o = T.axis.spatial(1, 0)
v3_i_o = T.axis.reduce(1, 0)
T.reads(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], lv42_reindex_pad_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], p_output0_intermediate_1_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(lv42_reindex_pad_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="wmma.matrix_a", offset_factor=16)
B = T.match_buffer(p_output0_intermediate_1_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "float16", strides=("B_s0", "B_s1"), scope="wmma.matrix_b", offset_factor=16)
C = T.match_buffer(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_mma_sync(C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, A.data, A.elem_offset // A.strides[0] // 16 * (A.strides[0] // 16) + A.elem_offset % A.strides[0] // 16, B.data, B.elem_offset // B.strides[0] // 16 * (B.strides[0] // 16) + B.elem_offset % B.strides[0] // 16, C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16)
for ax0_0, ax1_0 in T.grid(2, 2):
with T.sblock("var_NT_matmul_intermediate_reindex_pad_shared.dyn_wmma.accumulator_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(8 * ((n + 127) // 128), ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax1_0)
T.reads(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(var_NT_matmul_intermediate_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(var_NT_matmul_intermediate_reindex_pad_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("A_s0", "A_s1"), scope="wmma.accumulator", offset_factor=16)
C = T.match_buffer(var_NT_matmul_intermediate_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "float16", strides=("C_s0", "C_s1"), scope="shared.dyn", offset_factor=16)
T.tvm_store_matrix_sync(A.data, 16, 16, 16, A.elem_offset // A.strides[0] // 16 * (A.strides[0] // 16) + A.elem_offset % A.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("float16"), C.data, C.elem_offset, C.strides[0] * 16, 2), C.strides[0], "row_major")
for ax0_ax1_fused_0 in range(8):
for ax0_ax1_fused_1 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_2 in T.vectorized(4):
with T.sblock("var_NT_matmul_intermediate_reindex_pad_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((n + 127) // 128 * 128, ax1_0_0_ax2_0_0_fused * 128 + ax2_0_2_ax1_0_2_fused % 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) // 32)
v2 = T.axis.spatial(4096, ax1_0_1_ax2_0_1_fused * 128 + ax2_0_2_ax1_0_2_fused // 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) % 32)
T.where(ax1_0_0_ax2_0_0_fused * 128 + ax2_0_2_ax1_0_2_fused % 4 * 32 + ((ax0_ax1_fused_0 * 32 + ax0_ax1_fused_1) * 4 + ax0_ax1_fused_2) // 32 < n)
T.reads(lv3[0, v1, v2], var_NT_matmul_intermediate_reindex_pad_shared_dyn[v0, v1, v2])
T.writes(p_output0_intermediate[0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 4]]})
p_output0_intermediate[0, v1, v2] = lv3[0, v1, v2] * T.float16(0.5) + var_NT_matmul_intermediate_reindex_pad_shared_dyn[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-rtx-2080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_int8_tensorize():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(X: T.Buffer((256, 256), "int8"), W: T.Buffer((256, 256), "int8"), compute: T.Buffer((256, 256), "int32")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
for i, j, r in T.grid(256, 256, 256):
with T.sblock("compute"):
v_i, v_j, v_k = T.axis.remap("SSR", [i, j, r])
T.reads(X[v_i, v_k], W[v_j, v_k])
T.writes(compute[v_i, v_j])
with T.init():
compute[v_i, v_j] = 0
compute[v_i, v_j] = compute[v_i, v_j] + T.Cast("int32", X[v_i, v_k]) * T.Cast("int32", W[v_j, v_k])
@T.prim_func(private=True, s_tir=True)
def expected(X: T.Buffer((256, 256), "int8"), W: T.Buffer((256, 256), "int8"), compute: T.Buffer((256, 256), "int32")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
X_reindex_shared_dyn = T.sblock_alloc_buffer((1, 256, 256), "int8", scope="shared.dyn")
W_reindex_shared_dyn = T.sblock_alloc_buffer((1, 256, 256), "int8", scope="shared.dyn")
X_reindex_shared_dyn_wmma_matrix_a = T.sblock_alloc_buffer((1, 256, 256), "int8", scope="wmma.matrix_a")
W_reindex_shared_dyn_wmma_matrix_b = T.sblock_alloc_buffer((1, 256, 256), "int8", scope="wmma.matrix_b")
compute_reindex_shared_dyn = T.sblock_alloc_buffer((1, 256, 256), "int32", scope="shared.dyn")
compute_reindex_shared_dyn_wmma_accumulator = T.sblock_alloc_buffer((1, 256, 256), "int32", scope="wmma.accumulator")
for ax0 in T.thread_binding(1, thread="blockIdx.z"):
for ax1_0_0_ax2_0_0_fused in T.thread_binding(2, thread="blockIdx.x"):
for ax1_0_1_ax2_0_1_fused in T.thread_binding(2, thread="blockIdx.y"):
for ax2_0_2_ax1_0_2_fused in T.thread_binding(16, thread="threadIdx.y"):
for ax1_0_3_init, ax2_0_3_init in T.grid(2, 2):
with T.sblock("compute_o_init"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3_init)
v2_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3_init)
T.reads()
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("compute_init_o"):
v1_i_init_o = T.axis.spatial(1, 0)
v2_i_init_o = T.axis.spatial(1, 0)
T.reads()
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
C = T.match_buffer(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_fill_fragment(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.float32(0))
for ax3_0_0 in T.serial(16, annotations={"software_pipeline_order": [0, 3, 1, 4, 5, 2, 6], "software_pipeline_stage": [0, 0, 0, 0, 0, 1, 1]}):
for ax0_ax1_fused_0 in range(1):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("X_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(256, ax1_0_0_ax2_0_0_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 16)
v2 = T.axis.spatial(256, ax3_0_0 * 16 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 16)
T.reads(X[v1, v2])
T.writes(X_reindex_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 32, 16]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
X_reindex_shared_dyn[v0, v1, v2] = X[v1, v2]
for ax0_ax1_fused_0 in range(1):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("W_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 16)
v2 = T.axis.spatial(256, ax3_0_0 * 16 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 16)
T.reads(W[v1, v2])
T.writes(W_reindex_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 32, 16]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
W_reindex_shared_dyn[v0, v1, v2] = W[v1, v2]
for ax3_0_1 in T.serial(1, annotations={"software_pipeline_order": [0, 1, 2], "software_pipeline_stage": [0, 0, 1]}):
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("X_reindex_shared.dyn_wmma.matrix_a_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(16, ax3_0_0 + ax1_0)
T.reads(X_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(X_reindex_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(X_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(X_reindex_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("C_s0", "C_s1"), scope="wmma.matrix_a", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("int8"), A.data, A.elem_offset, A.strides[0] * 16, 1), A.strides[0], "row_major")
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("W_reindex_shared.dyn_wmma.matrix_b_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax0_0)
v2_o = T.axis.spatial(16, ax3_0_0 + ax1_0)
T.reads(W_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(W_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(W_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(W_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("C_s0", "C_s1"), scope="wmma.matrix_b", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("int8"), A.data, A.elem_offset, A.strides[0] * 16, 1), A.strides[0], "col_major")
for ax1_0_3, ax2_0_3 in T.grid(2, 2):
with T.sblock("compute_o_update"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3)
v2_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3)
v3_o = T.axis.reduce(16, ax3_0_0 + ax3_0_1)
T.reads(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], X_reindex_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], W_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("compute_o"):
v1_i_o = T.axis.spatial(1, 0)
v2_i_o = T.axis.spatial(1, 0)
v3_i_o = T.axis.reduce(1, 0)
T.reads(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], X_reindex_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], W_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(X_reindex_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "int8", strides=("A_s0", "A_s1"), scope="wmma.matrix_a", offset_factor=16)
B = T.match_buffer(W_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "int8", strides=("B_s0", "B_s1"), scope="wmma.matrix_b", offset_factor=16)
C = T.match_buffer(compute_reindex_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_mma_sync(C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, A.data, A.elem_offset // A.strides[0] // 16 * (A.strides[0] // 16) + A.elem_offset % A.strides[0] // 16, B.data, B.elem_offset // B.strides[0] // 16 * (B.strides[0] // 16) + B.elem_offset % B.strides[0] // 16, C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16)
for ax0_0, ax1_0 in T.grid(2, 2):
with T.sblock("compute_reindex_shared.dyn_wmma.accumulator_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(16, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(16, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax1_0)
T.reads(compute_reindex_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(compute_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A = T.match_buffer(compute_reindex_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("A_s0", "A_s1"), scope="wmma.accumulator", offset_factor=16)
C = T.match_buffer(compute_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("C_s0", "C_s1"), scope="shared.dyn", offset_factor=16)
T.tvm_store_matrix_sync(A.data, 16, 16, 16, A.elem_offset // A.strides[0] // 16 * (A.strides[0] // 16) + A.elem_offset % A.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("int32"), C.data, C.elem_offset, C.strides[0] * 16, 2), C.strides[0], "row_major")
for ax0_ax1_fused_0 in range(8):
for ax0_ax1_fused_1 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_2 in T.vectorized(4):
with T.sblock("compute_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(256, ax1_0_0_ax2_0_0_fused * 128 + ax2_0_2_ax1_0_2_fused % 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) // 32)
v2 = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 128 + ax2_0_2_ax1_0_2_fused // 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) % 32)
T.reads(compute_reindex_shared_dyn[v0, v1, v2])
T.writes(compute[v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 4]]})
compute[v1, v2] = compute_reindex_shared_dyn[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-rtx-2080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_int8_tensorize_3d2d_dyn():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(var_A: T.handle, B: T.Buffer((4096, 22016), "int8"), var_matmul: T.handle):
T.func_attr({"op_pattern": 4, "tirx.noalias": True})
m = T.int32()
A = T.match_buffer(var_A, (1, m, 22016), "int8")
matmul_1 = T.match_buffer(var_matmul, (1, m, 4096), "int32")
# with T.sblock("root"):
for i0, i1, i2, k in T.grid(1, m, 4096, 22016):
with T.sblock("matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.reads(A[v_i0, v_i1, v_k], B[v_i2, v_k])
T.writes(matmul_1[v_i0, v_i1, v_i2])
with T.init():
matmul_1[v_i0, v_i1, v_i2] = 0
matmul_1[v_i0, v_i1, v_i2] = matmul_1[v_i0, v_i1, v_i2] + T.Cast("int32", A[v_i0, v_i1, v_k]) * T.Cast("int32", B[v_i2, v_k])
@T.prim_func(private=True, s_tir=True)
def expected(var_A: T.handle, B: T.Buffer((4096, 22016), "int8"), var_matmul: T.handle):
T.func_attr({"op_pattern": 4, "tirx.is_scheduled": True, "tirx.noalias": True})
m = T.int32()
A = T.match_buffer(var_A, (1, m, 22016), "int8")
matmul_1 = T.match_buffer(var_matmul, (1, m, 4096), "int32")
# with T.sblock("root"):
A_reindex_pad_shared_dyn = T.sblock_alloc_buffer((1, (m + 127) // 128 * 128, 22016), "int8", scope="shared.dyn")
B_reindex_shared_dyn = T.sblock_alloc_buffer((1, 4096, 22016), "int8", scope="shared.dyn")
A_reindex_pad_shared_dyn_wmma_matrix_a = T.sblock_alloc_buffer((1, (m + 127) // 128 * 128, 22016), "int8", scope="wmma.matrix_a")
B_reindex_shared_dyn_wmma_matrix_b = T.sblock_alloc_buffer((1, 4096, 22016), "int8", scope="wmma.matrix_b")
matmul_1_reindex_pad_shared_dyn = T.sblock_alloc_buffer((1, (m + 127) // 128 * 128, 4096), "int32", scope="shared.dyn")
matmul_1_reindex_pad_shared_dyn_wmma_accumulator = T.sblock_alloc_buffer((1, (m + 127) // 128 * 128, 4096), "int32", scope="wmma.accumulator")
for ax0 in T.thread_binding(1, thread="blockIdx.z"):
for ax1_0_0_ax2_0_0_fused in T.thread_binding((m + 127) // 128, thread="blockIdx.x"):
for ax1_0_1_ax2_0_1_fused in T.thread_binding(32, thread="blockIdx.y"):
for ax2_0_2_ax1_0_2_fused in T.thread_binding(16, thread="threadIdx.y"):
for ax1_0_3_init, ax2_0_3_init in T.grid(2, 2):
with T.sblock("matmul_o_init"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial((m + 127) // 128 * 8, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3_init)
v2_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3_init)
T.reads()
T.writes(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("matmul_init_o"):
v1_i_init_o = T.axis.spatial(1, 0)
v2_i_init_o = T.axis.spatial(1, 0)
T.reads()
T.writes(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
C = T.match_buffer(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_fill_fragment(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.float32(0))
for ax3_0_0 in T.serial(1376, annotations={"software_pipeline_order": [0, 3, 1, 4, 5, 2, 6], "software_pipeline_stage": [0, 0, 0, 0, 0, 1, 1]}):
for ax0_ax1_fused_0 in range(1):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("A_reindex_pad_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 127) // 128 * 128, ax1_0_0_ax2_0_0_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 16)
v2 = T.axis.spatial(22016, ax3_0_0 * 16 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 16)
T.reads(A[v0, v1, v2])
T.writes(A_reindex_pad_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 32, 16]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
A_reindex_pad_shared_dyn[v0, v1, v2] = T.if_then_else(v1 < m, A[v0, v1, v2], T.int8(0))
for ax0_ax1_fused_0 in range(1):
for ax0_ax1_fused_1 in T.thread_binding(16, thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.vectorized(4):
with T.sblock("B_reindex_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(4096, ax1_0_1_ax2_0_1_fused * 128 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) // 16)
v2 = T.axis.spatial(22016, ax3_0_0 * 16 + (ax0_ax1_fused_0 * 2048 + ax0_ax1_fused_1 * 128 + ax0_ax1_fused_2 * 4 + ax0_ax1_fused_3) % 16)
T.reads(B[v1, v2])
T.writes(B_reindex_shared_dyn[v0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 32, 16]], "double_buffer_scope": 0, "tirx.manifest_shared_memory_local_stage": 1})
B_reindex_shared_dyn[v0, v1, v2] = B[v1, v2]
for ax3_0_1 in T.serial(1, annotations={"software_pipeline_order": [0, 1, 2], "software_pipeline_stage": [0, 0, 1]}):
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("A_reindex_pad_shared.dyn_wmma.matrix_a_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(8 * ((m + 127) // 128), ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(1376, ax3_0_0 + ax1_0)
T.reads(A_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(A_reindex_pad_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A_1 = T.match_buffer(A_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(A_reindex_pad_shared_dyn_wmma_matrix_a[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("C_s0", "C_s1"), scope="wmma.matrix_a", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("int8"), A_1.data, A_1.elem_offset, A_1.strides[0] * 16, 1), A_1.strides[0], "row_major")
for ax0_0 in T.unroll(2):
for ax1_0 in T.unroll(1):
with T.sblock("B_reindex_shared.dyn_wmma.matrix_b_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax0_0)
v2_o = T.axis.spatial(1376, ax3_0_0 + ax1_0)
T.reads(B_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(B_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A_1 = T.match_buffer(B_reindex_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("A_s0", "A_s1"), scope="shared.dyn", offset_factor=16)
C = T.match_buffer(B_reindex_shared_dyn_wmma_matrix_b[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int8", strides=("C_s0", "C_s1"), scope="wmma.matrix_b", offset_factor=16)
T.tvm_load_matrix_sync(C.data, 16, 16, 16, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("int8"), A_1.data, A_1.elem_offset, A_1.strides[0] * 16, 1), A_1.strides[0], "col_major")
for ax1_0_3, ax2_0_3 in T.grid(2, 2):
with T.sblock("matmul_o_update"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial((m + 127) // 128 * 8, ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax1_0_3)
v2_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax2_0_3)
v3_o = T.axis.reduce(1376, ax3_0_0 + ax3_0_1)
T.reads(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], A_reindex_pad_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], B_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
with T.sblock("matmul_o"):
v1_i_o = T.axis.spatial(1, 0)
v2_i_o = T.axis.spatial(1, 0)
v3_i_o = T.axis.reduce(1, 0)
T.reads(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], A_reindex_pad_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], B_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16])
T.writes(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A_1 = T.match_buffer(A_reindex_pad_shared_dyn_wmma_matrix_a[0, v1_o * 16:v1_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "int8", strides=("A_s0", "A_s1"), scope="wmma.matrix_a", offset_factor=16)
B_1 = T.match_buffer(B_reindex_shared_dyn_wmma_matrix_b[0, v2_o * 16:v2_o * 16 + 16, v3_o * 16:v3_o * 16 + 16], (16, 16), "int8", strides=("B_s0", "B_s1"), scope="wmma.matrix_b", offset_factor=16)
C = T.match_buffer(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[0, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("C_s0", "C_s1"), scope="wmma.accumulator", offset_factor=16)
T.tvm_mma_sync(C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16, A_1.data, A_1.elem_offset // A_1.strides[0] // 16 * (A_1.strides[0] // 16) + A_1.elem_offset % A_1.strides[0] // 16, B_1.data, B_1.elem_offset // B_1.strides[0] // 16 * (B_1.strides[0] // 16) + B_1.elem_offset % B_1.strides[0] // 16, C.data, C.elem_offset // C.strides[0] // 16 * (C.strides[0] // 16) + C.elem_offset % C.strides[0] // 16)
for ax0_0, ax1_0 in T.grid(2, 2):
with T.sblock("matmul_1_reindex_pad_shared.dyn_wmma.accumulator_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(8 * ((m + 127) // 128), ax1_0_0_ax2_0_0_fused * 8 + ax2_0_2_ax1_0_2_fused % 4 * 2 + ax0_0)
v2_o = T.axis.spatial(256, ax1_0_1_ax2_0_1_fused * 8 + ax2_0_2_ax1_0_2_fused // 4 * 2 + ax1_0)
T.reads(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
T.writes(matmul_1_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16])
A_1 = T.match_buffer(matmul_1_reindex_pad_shared_dyn_wmma_accumulator[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("A_s0", "A_s1"), scope="wmma.accumulator", offset_factor=16)
C = T.match_buffer(matmul_1_reindex_pad_shared_dyn[v0_o, v1_o * 16:v1_o * 16 + 16, v2_o * 16:v2_o * 16 + 16], (16, 16), "int32", strides=("C_s0", "C_s1"), scope="shared.dyn", offset_factor=16)
T.tvm_store_matrix_sync(A_1.data, 16, 16, 16, A_1.elem_offset // A_1.strides[0] // 16 * (A_1.strides[0] // 16) + A_1.elem_offset % A_1.strides[0] // 16, T.tvm_access_ptr(T.type_annotation("int32"), C.data, C.elem_offset, C.strides[0] * 16, 2), C.strides[0], "row_major")
for ax0_ax1_fused_0 in range(8):
for ax0_ax1_fused_1 in T.thread_binding(32, thread="threadIdx.x"):
for ax0_ax1_fused_2 in T.vectorized(4):
with T.sblock("matmul_1_reindex_pad_shared.dyn"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial((m + 127) // 128 * 128, ax1_0_0_ax2_0_0_fused * 128 + ax2_0_2_ax1_0_2_fused % 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) // 32)
v2 = T.axis.spatial(4096, ax1_0_1_ax2_0_1_fused * 128 + ax2_0_2_ax1_0_2_fused // 4 * 32 + (ax0_ax1_fused_0 * 128 + ax0_ax1_fused_1 * 4 + ax0_ax1_fused_2) % 32)
T.where(ax1_0_0_ax2_0_0_fused * 128 + ax2_0_2_ax1_0_2_fused % 4 * 32 + ((ax0_ax1_fused_0 * 32 + ax0_ax1_fused_1) * 4 + ax0_ax1_fused_2) // 32 < m)
T.reads(matmul_1_reindex_pad_shared_dyn[v0, v1, v2])
T.writes(matmul_1[0, v1, v2])
T.sblock_attr({"buffer_dim_align": [[0, 1, 16, 4]]})
matmul_1[0, v1, v2] = matmul_1_reindex_pad_shared_dyn[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("nvidia/geforce-rtx-2080-ti"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_metal():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(
var_A: T.handle,
B: T.Buffer((28672, 4096), "float16"),
var_C: T.handle,
):
batch_size = T.int32()
A = T.match_buffer(var_A, (batch_size, 1, 4096), "float16")
C = T.match_buffer(var_C, (batch_size, 1, 28672), "float16")
for i0, i1, i2, k in T.grid(batch_size, 1, 28672, 4096):
with T.sblock("C"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
T.writes(C[v_i0, v_i1, v_i2])
with T.init():
C[v_i0, v_i1, v_i2] = T.float16(0)
C[v_i0, v_i1, v_i2] += A[v_i0, v_i1, v_k] * B[v_i2, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(var_A: T.handle, B: T.Buffer((28672, 4096), "float16"), var_C: T.handle):
T.func_attr({"tirx.is_scheduled": True})
batch_size = T.int32()
A = T.match_buffer(var_A, (batch_size, 1, 4096), "float16")
C = T.match_buffer(var_C, (batch_size, 1, 28672), "float16")
# with T.sblock("root"):
A_reindex_pad_shared = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 4096), "float16", scope="shared")
B_reindex_shared = T.sblock_alloc_buffer((1, 28672, 4096), "float16", scope="shared")
A_reindex_pad_shared_metal_simdgroup = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 4096), "float16", scope="metal.simdgroup")
B_reindex_shared_metal_simdgroup = T.sblock_alloc_buffer((1, 4096, 28672), "float16", scope="metal.simdgroup")
C_reindex_pad_metal_simdgroup = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 28672), "float16", scope="metal.simdgroup")
C_reindex_pad_shared = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 28672), "float16", scope="shared")
for ax0 in T.thread_binding(1, thread="blockIdx.z"):
for ax1_0 in T.thread_binding((batch_size + 15) // 16, thread="blockIdx.x"):
for ax2_0 in T.thread_binding(448, thread="blockIdx.y"):
for ax1_1 in T.thread_binding(1, thread="threadIdx.y"):
for ax2_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_2_init, ax2_2_init, ax1_3_init_0, ax2_3_init_0 in T.grid(2, 2, 1, 1):
with T.sblock("C_init_o"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax1_1 * 2 + ax1_2_init + ax1_3_init_0)
v2_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax2_2_init + ax2_3_init_0)
T.reads()
T.writes(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.make_filled_simdgroup_matrix(A_1.data, A_1.elem_offset // A_1.strides[0] // 8 * (A_1.strides[0] // 8) + A_1.elem_offset % A_1.strides[0] // 8, T.float32(0), 8, 8)
for ax3_0 in range(128):
for ax0_1, ax1_ax2_fused_0 in T.grid(1, 1):
for ax1_ax2_fused_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_ax2_fused_2 in T.thread_binding(1, thread="threadIdx.y"):
for ax1_ax2_fused_3 in T.thread_binding(32, thread="threadIdx.x"):
for ax1_ax2_fused_4 in T.vectorized(4):
with T.sblock("A_reindex_pad_shared"):
v0 = T.axis.spatial(1, ax0_1)
v1 = T.axis.spatial((batch_size + 15) // 16 * 16, ax1_0 * 16 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) // 32)
v2 = T.axis.spatial(4096, ax3_0 * 32 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) % 32)
T.reads(A[v1, 0, v2])
T.writes(A_reindex_pad_shared[v0, v1, v2])
A_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < batch_size, A[v1, 0, v2], T.float16(0))
for ax0_1, ax1_ax2_fused_0 in T.grid(1, 4):
for ax1_ax2_fused_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_ax2_fused_2 in T.thread_binding(1, thread="threadIdx.y"):
for ax1_ax2_fused_3 in T.thread_binding(32, thread="threadIdx.x"):
for ax1_ax2_fused_4 in T.vectorized(4):
with T.sblock("B_reindex_shared"):
v0 = T.axis.spatial(1, ax0_1)
v1 = T.axis.spatial(28672, ax2_0 * 64 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) // 32)
v2 = T.axis.spatial(4096, ax3_0 * 32 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) % 32)
T.reads(B[v1, v2])
T.writes(B_reindex_shared[v0, v1, v2])
B_reindex_shared[v0, v1, v2] = B[v1, v2]
for ax3_1 in range(4):
for ax0_0, ax1_0_1 in T.grid(2, 1):
with T.sblock("A_reindex_pad_shared_metal.simdgroup_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax0_0)
v2_o = T.axis.spatial(512, ax3_0 * 4 + ax3_1 + ax1_0_1)
T.reads(A_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(A_reindex_pad_shared_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(A_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="shared", offset_factor=1)
C_1 = T.match_buffer(A_reindex_pad_shared_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.simdgroup_load(C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8, T.tvm_access_ptr(T.type_annotation("float16"), A_1.data, A_1.elem_offset, A_1.strides[0] * 8, 1), A_1.strides[0], 8, 8, T.bool(False))
for ax0_0, ax1_0_1 in T.grid(2, 1):
with T.sblock("B_reindex_shared_metal.simdgroup_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax0_0)
v2_o = T.axis.spatial(512, ax3_0 * 4 + ax3_1 + ax1_0_1)
T.reads(B_reindex_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(B_reindex_shared_metal_simdgroup[v0_o, v2_o * 8:v2_o * 8 + 8, v1_o * 8:v1_o * 8 + 8])
A_1 = T.match_buffer(B_reindex_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="shared", offset_factor=1)
C_1 = T.match_buffer(B_reindex_shared_metal_simdgroup[v0_o, v2_o * 8:v2_o * 8 + 8, v1_o * 8:v1_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.simdgroup_load(C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8, T.tvm_access_ptr(T.type_annotation("float16"), A_1.data, A_1.elem_offset, A_1.strides[0] * 8, 1), A_1.strides[0], 8, 8, T.bool(True))
for ax1_2, ax2_2 in T.grid(2, 2):
with T.sblock("C_update_o"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax1_1 * 2 + ax1_2)
v2_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax2_2)
v3_o = T.axis.reduce(512, ax3_0 * 4 + ax3_1)
T.reads(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], A_reindex_pad_shared_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v3_o * 8:v3_o * 8 + 8], B_reindex_shared_metal_simdgroup[0, v3_o * 8:v3_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(A_reindex_pad_shared_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v3_o * 8:v3_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="metal.simdgroup", offset_factor=1)
B_1 = T.match_buffer(B_reindex_shared_metal_simdgroup[0, v3_o * 8:v3_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("B_s0", "B_s1"), scope="metal.simdgroup", offset_factor=1)
C_1 = T.match_buffer(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.simdgroup_multiply_accumulate(C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8, A_1.data, A_1.elem_offset // A_1.strides[0] // 8 * (A_1.strides[0] // 8) + A_1.elem_offset % A_1.strides[0] // 8, B_1.data, B_1.elem_offset // B_1.strides[0] // 8 * (B_1.strides[0] // 8) + B_1.elem_offset % B_1.strides[0] // 8, C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8)
for ax0_1, ax1_0_1, ax2_0_1 in T.grid(1, 2, 2):
with T.sblock("C_reindex_pad_metal.simdgroup_o"):
v0_o = T.axis.spatial(1, ax0_1)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax1_0_1)
v2_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax2_0_1)
T.reads(C_reindex_pad_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(C_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(C_reindex_pad_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="metal.simdgroup", offset_factor=1)
C_1 = T.match_buffer(C_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="shared", offset_factor=1)
T.metal.simdgroup_store(A_1.data, A_1.elem_offset // A_1.strides[0] // 8 * (A_1.strides[0] // 8) + A_1.elem_offset % A_1.strides[0] // 8, T.tvm_access_ptr(T.type_annotation("float16"), C_1.data, C_1.elem_offset, C_1.strides[0] * 8, 2), C_1.strides[0], 8, 8, T.bool(False))
for ax0_1, ax1_ax2_fused_0 in T.grid(1, 2):
for ax1_ax2_fused_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_ax2_fused_2 in T.thread_binding(1, thread="threadIdx.y"):
for ax1_ax2_fused_3 in T.thread_binding(32, thread="threadIdx.x"):
for ax1_ax2_fused_4 in T.vectorized(4):
with T.sblock("C_reindex_pad_shared"):
v0 = T.axis.spatial(1, ax0_1)
v1 = T.axis.spatial((batch_size + 15) // 16 * 16, ax1_0 * 16 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) // 64)
v2 = T.axis.spatial(28672, ax2_0 * 64 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) % 64)
T.where(ax1_0 * 16 + (((ax1_ax2_fused_0 * 4 + ax1_ax2_fused_1 + ax1_ax2_fused_2) * 32 + ax1_ax2_fused_3) * 4 + ax1_ax2_fused_4) // 64 < batch_size)
T.reads(C_reindex_pad_shared[v0, v1, v2])
T.writes(C[v1, 0, v2])
C[v1, 0, v2] = C_reindex_pad_shared[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("metal"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
def test_matmul_metal_int4_quant():
# fmt: off
@T.prim_func(private=True, s_tir=True)
def before(
B0: T.Buffer((28672, 512), "uint32"),
B1: T.Buffer((28672, 128), "float16"),
var_A: T.handle,
var_C: T.handle
):
batch_size = T.int32()
A = T.match_buffer(var_A, (batch_size, 1, 4096), "float16")
C = T.match_buffer(var_C, (batch_size, 1, 28672), "float16")
compute = T.sblock_alloc_buffer((28672, 4096), "float16")
B = T.sblock_alloc_buffer((28672, 4096), "float16")
for i0, i1 in T.grid(28672, 4096):
with T.sblock("compute"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
compute[v_i0, v_i1] = T.Cast("float16", T.bitwise_and(T.shift_right(B0[v_i0, v_i1 // 8], T.Cast("uint32", v_i1 % 8 * 4)), T.uint32(15)))
for i0, i1 in T.grid(28672, 4096):
with T.sblock("dequantize"):
v_i0, v_i1 = T.axis.remap("SS", [i0, i1])
B[v_i0, v_i1] = (compute[v_i0, v_i1] - T.float16(7)) * B1[v_i0, v_i1 // 32]
for i0, i1, i2, k in T.grid(batch_size, 1, 28672, 4096):
with T.sblock("NT_matmul"):
v_i0, v_i1, v_i2, v_k = T.axis.remap("SSSR", [i0, i1, i2, k])
with T.init():
C[v_i0, v_i1, v_i2] = T.float16(0)
C[v_i0, v_i1, v_i2] = C[v_i0, v_i1, v_i2] + A[v_i0, v_i1, v_k] * B[v_i2, v_k]
@T.prim_func(private=True, s_tir=True)
def expected(B0: T.Buffer((28672, 512), "uint32"), B1: T.Buffer((28672, 128), "float16"), var_A: T.handle, var_C: T.handle):
T.func_attr({"tirx.is_scheduled": True})
batch_size = T.int32()
A = T.match_buffer(var_A, (batch_size, 1, 4096), "float16")
C = T.match_buffer(var_C, (batch_size, 1, 28672), "float16")
# with T.sblock("root"):
A_reindex_pad_shared = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 4096), "float16", scope="shared")
B_reindex_shared = T.sblock_alloc_buffer((1, 28672, 4096), "float16", scope="shared")
A_reindex_pad_shared_metal_simdgroup = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 4096), "float16", scope="metal.simdgroup")
B_reindex_shared_metal_simdgroup = T.sblock_alloc_buffer((1, 4096, 28672), "float16", scope="metal.simdgroup")
C_reindex_pad_metal_simdgroup = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 28672), "float16", scope="metal.simdgroup")
C_reindex_pad_shared = T.sblock_alloc_buffer((1, (batch_size + 15) // 16 * 16, 28672), "float16", scope="shared")
for ax0 in T.thread_binding(1, thread="blockIdx.z"):
for ax1_0 in T.thread_binding((batch_size + 15) // 16, thread="blockIdx.x"):
for ax2_0 in T.thread_binding(448, thread="blockIdx.y"):
for ax1_1 in T.thread_binding(1, thread="threadIdx.y"):
for ax2_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_2_init, ax2_2_init, ax1_3_init_0, ax2_3_init_0 in T.grid(2, 2, 1, 1):
with T.sblock("NT_matmul_init_o"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax1_1 * 2 + ax1_2_init + ax1_3_init_0)
v2_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax2_2_init + ax2_3_init_0)
T.reads()
T.writes(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.make_filled_simdgroup_matrix(A_1.data, A_1.elem_offset // A_1.strides[0] // 8 * (A_1.strides[0] // 8) + A_1.elem_offset % A_1.strides[0] // 8, T.float32(0), 8, 8)
for ax3_0 in range(128):
for ax0_1, ax1_ax2_fused_0 in T.grid(1, 1):
for ax1_ax2_fused_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_ax2_fused_2 in T.thread_binding(1, thread="threadIdx.y"):
for ax1_ax2_fused_3 in T.thread_binding(32, thread="threadIdx.x"):
for ax1_ax2_fused_4 in T.vectorized(4):
with T.sblock("A_reindex_pad_shared"):
v0 = T.axis.spatial(1, ax0_1)
v1 = T.axis.spatial((batch_size + 15) // 16 * 16, ax1_0 * 16 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) // 32)
v2 = T.axis.spatial(4096, ax3_0 * 32 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) % 32)
T.reads(A[v1, 0, v2])
T.writes(A_reindex_pad_shared[v0, v1, v2])
A_reindex_pad_shared[v0, v1, v2] = T.if_then_else(v1 < batch_size, A[v1, 0, v2], T.float16(0))
for ax0_1, ax1_ax2_fused_0 in T.grid(1, 4):
for ax1_ax2_fused_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_ax2_fused_2 in T.thread_binding(1, thread="threadIdx.y"):
for ax1_ax2_fused_3 in T.thread_binding(32, thread="threadIdx.x"):
for ax1_ax2_fused_4 in T.vectorized(4):
with T.sblock("B_reindex_shared"):
v0 = T.axis.spatial(1, ax0_1)
v1 = T.axis.spatial(28672, ax2_0 * 64 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) // 32)
v2 = T.axis.spatial(4096, ax3_0 * 32 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) % 32)
T.reads(B0[v1, v2 // 8], B1[v1, v2 // 32])
T.writes(B_reindex_shared[v0, v1, v2])
B_reindex_shared[v0, v1, v2] = (T.Cast("float16", T.bitwise_and(T.shift_right(B0[v1, v2 // 8], T.Cast("uint32", v2 % 8 * 4)), T.uint32(15))) - T.float16(7)) * B1[v1, v2 // 32]
for ax3_1 in range(4):
for ax0_0, ax1_0_1 in T.grid(2, 1):
with T.sblock("A_reindex_pad_shared_metal.simdgroup_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax0_0)
v2_o = T.axis.spatial(512, ax3_0 * 4 + ax3_1 + ax1_0_1)
T.reads(A_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(A_reindex_pad_shared_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(A_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="shared", offset_factor=1)
C_1 = T.match_buffer(A_reindex_pad_shared_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.simdgroup_load(C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8, T.tvm_access_ptr(T.type_annotation("float16"), A_1.data, A_1.elem_offset, A_1.strides[0] * 8, 1), A_1.strides[0], 8, 8, T.bool(False))
for ax0_0, ax1_0_1 in T.grid(2, 1):
with T.sblock("B_reindex_shared_metal.simdgroup_o"):
v0_o = T.axis.spatial(1, 0)
v1_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax0_0)
v2_o = T.axis.spatial(512, ax3_0 * 4 + ax3_1 + ax1_0_1)
T.reads(B_reindex_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(B_reindex_shared_metal_simdgroup[v0_o, v2_o * 8:v2_o * 8 + 8, v1_o * 8:v1_o * 8 + 8])
A_1 = T.match_buffer(B_reindex_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="shared", offset_factor=1)
C_1 = T.match_buffer(B_reindex_shared_metal_simdgroup[v0_o, v2_o * 8:v2_o * 8 + 8, v1_o * 8:v1_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.simdgroup_load(C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8, T.tvm_access_ptr(T.type_annotation("float16"), A_1.data, A_1.elem_offset, A_1.strides[0] * 8, 1), A_1.strides[0], 8, 8, T.bool(True))
for ax1_2, ax2_2 in T.grid(2, 2):
with T.sblock("NT_matmul_update_o"):
v0_o = T.axis.spatial(1, ax0)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax1_1 * 2 + ax1_2)
v2_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax2_2)
v3_o = T.axis.reduce(512, ax3_0 * 4 + ax3_1)
T.reads(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], A_reindex_pad_shared_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v3_o * 8:v3_o * 8 + 8], B_reindex_shared_metal_simdgroup[0, v3_o * 8:v3_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(A_reindex_pad_shared_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v3_o * 8:v3_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="metal.simdgroup", offset_factor=1)
B = T.match_buffer(B_reindex_shared_metal_simdgroup[0, v3_o * 8:v3_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("B_s0", "B_s1"), scope="metal.simdgroup", offset_factor=1)
C_1 = T.match_buffer(C_reindex_pad_metal_simdgroup[0, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="metal.simdgroup", offset_factor=1)
T.metal.simdgroup_multiply_accumulate(C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8, A_1.data, A_1.elem_offset // A_1.strides[0] // 8 * (A_1.strides[0] // 8) + A_1.elem_offset % A_1.strides[0] // 8, B.data, B.elem_offset // B.strides[0] // 8 * (B.strides[0] // 8) + B.elem_offset % B.strides[0] // 8, C_1.data, C_1.elem_offset // C_1.strides[0] // 8 * (C_1.strides[0] // 8) + C_1.elem_offset % C_1.strides[0] // 8)
for ax0_1, ax1_0_1, ax2_0_1 in T.grid(1, 2, 2):
with T.sblock("C_reindex_pad_metal.simdgroup_o"):
v0_o = T.axis.spatial(1, ax0_1)
v1_o = T.axis.spatial(2 * ((batch_size + 15) // 16), ax1_0 * 2 + ax1_0_1)
v2_o = T.axis.spatial(3584, ax2_0 * 8 + ax2_1 * 2 + ax2_0_1)
T.reads(C_reindex_pad_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
T.writes(C_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8])
A_1 = T.match_buffer(C_reindex_pad_metal_simdgroup[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("A_s0", "A_s1"), scope="metal.simdgroup", offset_factor=1)
C_1 = T.match_buffer(C_reindex_pad_shared[v0_o, v1_o * 8:v1_o * 8 + 8, v2_o * 8:v2_o * 8 + 8], (8, 8), "float16", strides=("C_s0", "C_s1"), scope="shared", offset_factor=1)
T.metal.simdgroup_store(A_1.data, A_1.elem_offset // A_1.strides[0] // 8 * (A_1.strides[0] // 8) + A_1.elem_offset % A_1.strides[0] // 8, T.tvm_access_ptr(T.type_annotation("float16"), C_1.data, C_1.elem_offset, C_1.strides[0] * 8, 2), C_1.strides[0], 8, 8, T.bool(False))
for ax0_1, ax1_ax2_fused_0 in T.grid(1, 2):
for ax1_ax2_fused_1 in T.thread_binding(4, thread="threadIdx.z"):
for ax1_ax2_fused_2 in T.thread_binding(1, thread="threadIdx.y"):
for ax1_ax2_fused_3 in T.thread_binding(32, thread="threadIdx.x"):
for ax1_ax2_fused_4 in T.vectorized(4):
with T.sblock("C_reindex_pad_shared"):
v0 = T.axis.spatial(1, ax0_1)
v1 = T.axis.spatial((batch_size + 15) // 16 * 16, ax1_0 * 16 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) // 64)
v2 = T.axis.spatial(28672, ax2_0 * 64 + (ax1_ax2_fused_0 * 512 + ax1_ax2_fused_1 * 128 + ax1_ax2_fused_2 * 128 + ax1_ax2_fused_3 * 4 + ax1_ax2_fused_4) % 64)
T.where(ax1_0 * 16 + (((ax1_ax2_fused_0 * 4 + ax1_ax2_fused_1 + ax1_ax2_fused_2) * 32 + ax1_ax2_fused_3) * 4 + ax1_ax2_fused_4) // 64 < batch_size)
T.reads(C_reindex_pad_shared[v0, v1, v2])
T.writes(C[v1, 0, v2])
C[v1, 0, v2] = C_reindex_pad_shared[v0, v1, v2]
# fmt: on
mod = tvm.IRModule({"main": before})
with Target("metal"):
mod = dl.ApplyDefaultSchedule(dl.gpu.Matmul())(mod)
tvm.ir.assert_structural_equal(mod["main"], expected)
if __name__ == "__main__":
tvm.testing.main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,287 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501
import tvm.testing
from tvm.ir import IRModule, assert_structural_equal
from tvm.s_tir import dlight as dl
from tvm.script import ir as I
from tvm.script import tirx as T
from tvm.target import Target
def _check(mod_before: IRModule, mod_after: IRModule):
target = Target("nvidia/geforce-rtx-3090-ti")
with target:
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.RMSNorm(),
)(mod_before)
assert_structural_equal(mod, mod_after)
def test_rms_norm_with_casting():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(var_data: T.handle, weight: T.Buffer((4096,), "float16"), var_T_cast: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int32()
data = T.match_buffer(var_data, (1, n, 4096), "float16")
T_cast = T.match_buffer(var_T_cast, (1, n, 4096), "float16")
# with T.sblock("root"):
T_cast_1 = T.sblock_alloc_buffer((1, n, 4096))
T_multiply = T.sblock_alloc_buffer((1, n, 4096))
T_multiply_red = T.sblock_alloc_buffer((1, n))
rsqrt = T.sblock_alloc_buffer((1, n))
T_cast_2 = T.sblock_alloc_buffer((4096,))
T_rms_norm = T.sblock_alloc_buffer((1, n, 4096))
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_cast"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(data[v_ax0, v_ax1, v_ax2])
T.writes(T_cast_1[v_ax0, v_ax1, v_ax2])
T_cast_1[v_ax0, v_ax1, v_ax2] = T.Cast("float32", data[v_ax0, v_ax1, v_ax2])
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_multiply"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(T_cast_1[v_ax0, v_ax1, v_ax2])
T.writes(T_multiply[v_ax0, v_ax1, v_ax2])
T_multiply[v_ax0, v_ax1, v_ax2] = T_cast_1[v_ax0, v_ax1, v_ax2] * T_cast_1[v_ax0, v_ax1, v_ax2]
for ax0, ax1, k2 in T.grid(1, n, 4096):
with T.sblock("T_multiply_red"):
v_ax0, v_ax1, v_k2 = T.axis.remap("SSR", [ax0, ax1, k2])
T.reads(T_multiply[v_ax0, v_ax1, v_k2])
T.writes(T_multiply_red[v_ax0, v_ax1])
with T.init():
T_multiply_red[v_ax0, v_ax1] = T.float32(0)
T_multiply_red[v_ax0, v_ax1] = T_multiply_red[v_ax0, v_ax1] + T_multiply[v_ax0, v_ax1, v_k2]
for ax0, ax1 in T.grid(1, n):
with T.sblock("rsqrt"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(T_multiply_red[v_ax0, v_ax1])
T.writes(rsqrt[v_ax0, v_ax1])
rsqrt[v_ax0, v_ax1] = T.rsqrt(T_multiply_red[v_ax0, v_ax1] * T.float32(0.000244140625) + T.float32(9.9999999999999995e-07))
for ax0 in range(4096):
with T.sblock("T_cast_1"):
v_ax0 = T.axis.spatial(4096, ax0)
T.reads(weight[v_ax0])
T.writes(T_cast_2[v_ax0])
T_cast_2[v_ax0] = T.Cast("float32", weight[v_ax0])
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_rms_norm"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(rsqrt[v_ax0, v_ax1], T_cast_1[v_ax0, v_ax1, v_ax2], T_cast_2[v_ax2])
T.writes(T_rms_norm[v_ax0, v_ax1, v_ax2])
T_rms_norm[v_ax0, v_ax1, v_ax2] = rsqrt[v_ax0, v_ax1] * T_cast_1[v_ax0, v_ax1, v_ax2] * T_cast_2[v_ax2]
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_cast_2"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(T_rms_norm[v_ax0, v_ax1, v_ax2])
T.writes(T_cast[v_ax0, v_ax1, v_ax2])
T_cast[v_ax0, v_ax1, v_ax2] = T.Cast("float16", T_rms_norm[v_ax0, v_ax1, v_ax2])
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(var_data: T.handle, weight: T.Buffer((4096,), "float16"), var_T_cast: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int32()
data = T.match_buffer(var_data, (1, n, 4096), "float16")
T_cast = T.match_buffer(var_T_cast, (1, n, 4096), "float16")
# with T.sblock("root"):
T_multiply_local = T.sblock_alloc_buffer((1, n, 4096), scope="local")
T_multiply_red_local = T.sblock_alloc_buffer((1, n), scope="local")
rsqrt_shared = T.sblock_alloc_buffer((1, n), scope="shared")
T_rms_norm_local = T.sblock_alloc_buffer((1, n, 4096), scope="local")
data_local = T.sblock_alloc_buffer((1, n, 4096), "float16", scope="local")
for ax0_ax1_fused in T.thread_binding(n, thread="blockIdx.x"):
for ax2_0 in T.thread_binding(512, thread="threadIdx.x"):
for ax2_1 in range(1):
for ax2_2 in T.vectorized(8):
with T.sblock("data_local"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(n, ax0_ax1_fused)
v2 = T.axis.spatial(4096, ax2_0 * 8 + ax2_1 * 8 + ax2_2)
T.reads(data[v0, v1, v2])
T.writes(data_local[v0, v1, v2])
data_local[v0, v1, v2] = data[v0, v1, v2]
for ax0 in range(8):
with T.sblock("T_multiply"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
v_ax2 = T.axis.spatial(4096, ax2_0 * 8 + ax0)
T.reads(data_local[v_ax0, v_ax1, v_ax2])
T.writes(T_multiply_local[v_ax0, v_ax1, v_ax2])
T_multiply_local[v_ax0, v_ax1, v_ax2] = T.Cast("float32", data_local[v_ax0, v_ax1, v_ax2]) * T.Cast("float32", data_local[v_ax0, v_ax1, v_ax2])
for ax0 in range(8):
with T.sblock("T_multiply_red"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
v_k2 = T.axis.reduce(4096, ax2_0 * 8 + ax0)
T.reads(T_multiply_local[v_ax0, v_ax1, v_k2])
T.writes(T_multiply_red_local[v_ax0, v_ax1])
with T.init():
T_multiply_red_local[v_ax0, v_ax1] = T.float32(0)
T_multiply_red_local[v_ax0, v_ax1] = T_multiply_red_local[v_ax0, v_ax1] + T_multiply_local[v_ax0, v_ax1, v_k2]
with T.sblock("rsqrt"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
T.reads(T_multiply_red_local[v_ax0, v_ax1])
T.writes(rsqrt_shared[v_ax0, v_ax1])
rsqrt_shared[v_ax0, v_ax1] = T.rsqrt(T_multiply_red_local[v_ax0, v_ax1] * T.float32(0.000244140625) + T.float32(9.9999999999999995e-07))
for ax0_0 in T.thread_binding(512, thread="threadIdx.x"):
for ax0_1, ax0_2 in T.grid(1, 8):
with T.sblock("T_rms_norm"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
v_ax2 = T.axis.spatial(4096, ax0_0 * 8 + ax0_1 * 8 + ax0_2)
T.reads(rsqrt_shared[v_ax0, v_ax1], data_local[v_ax0, v_ax1, v_ax2], weight[v_ax2])
T.writes(T_rms_norm_local[v_ax0, v_ax1, v_ax2])
T_rms_norm_local[v_ax0, v_ax1, v_ax2] = rsqrt_shared[v_ax0, v_ax1] * T.Cast("float32", data_local[v_ax0, v_ax1, v_ax2]) * T.Cast("float32", weight[v_ax2])
for ax0 in T.vectorized(8):
with T.sblock("T_cast_local"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(n, ax0_ax1_fused)
v2 = T.axis.spatial(4096, ax0_0 * 8 + ax0)
T.reads(T_rms_norm_local[v0, v1, v2])
T.writes(T_cast[v0, v1, v2])
T_cast[v0, v1, v2] = T.Cast("float16", T_rms_norm_local[v0, v1, v2])
# fmt: on
_check(Before, After)
def test_rms_norm_without_casting():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(var_data: T.handle, weight: T.Buffer((4096,), "float32"), var_T_cast: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int32()
data = T.match_buffer(var_data, (1, n, 4096))
T_cast = T.match_buffer(var_T_cast, (1, n, 4096))
# with T.sblock("root"):
T_multiply = T.sblock_alloc_buffer((1, n, 4096))
T_multiply_red = T.sblock_alloc_buffer((1, n))
rsqrt = T.sblock_alloc_buffer((1, n))
T_rms_norm = T.sblock_alloc_buffer((1, n, 4096))
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_multiply"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(data[v_ax0, v_ax1, v_ax2])
T.writes(T_multiply[v_ax0, v_ax1, v_ax2])
T_multiply[v_ax0, v_ax1, v_ax2] = data[v_ax0, v_ax1, v_ax2] * data[v_ax0, v_ax1, v_ax2]
for ax0, ax1, k2 in T.grid(1, n, 4096):
with T.sblock("T_multiply_red"):
v_ax0, v_ax1, v_k2 = T.axis.remap("SSR", [ax0, ax1, k2])
T.reads(T_multiply[v_ax0, v_ax1, v_k2])
T.writes(T_multiply_red[v_ax0, v_ax1])
with T.init():
T_multiply_red[v_ax0, v_ax1] = T.float32(0)
T_multiply_red[v_ax0, v_ax1] = T_multiply_red[v_ax0, v_ax1] + T_multiply[v_ax0, v_ax1, v_k2]
for ax0, ax1 in T.grid(1, n):
with T.sblock("rsqrt"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(T_multiply_red[v_ax0, v_ax1])
T.writes(rsqrt[v_ax0, v_ax1])
rsqrt[v_ax0, v_ax1] = T.rsqrt(T_multiply_red[v_ax0, v_ax1] * T.float32(0.000244140625) + T.float32(9.9999999999999995e-07))
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_rms_norm"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(rsqrt[v_ax0, v_ax1], data[v_ax0, v_ax1, v_ax2], weight[v_ax2])
T.writes(T_rms_norm[v_ax0, v_ax1, v_ax2])
T_rms_norm[v_ax0, v_ax1, v_ax2] = rsqrt[v_ax0, v_ax1] * data[v_ax0, v_ax1, v_ax2] * weight[v_ax2]
for ax0, ax1, ax2 in T.grid(1, n, 4096):
with T.sblock("T_cast_2"):
v_ax0, v_ax1, v_ax2 = T.axis.remap("SSS", [ax0, ax1, ax2])
T.reads(T_rms_norm[v_ax0, v_ax1, v_ax2])
T.writes(T_cast[v_ax0, v_ax1, v_ax2])
T_cast[v_ax0, v_ax1, v_ax2] = T_rms_norm[v_ax0, v_ax1, v_ax2]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(var_data: T.handle, weight: T.Buffer((4096,), "float32"), var_T_cast: T.handle):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
n = T.int32()
data = T.match_buffer(var_data, (1, n, 4096))
T_cast = T.match_buffer(var_T_cast, (1, n, 4096))
# with T.sblock("root"):
T_multiply_local = T.sblock_alloc_buffer((1, n, 4096), scope="local")
T_multiply_red_local = T.sblock_alloc_buffer((1, n), scope="local")
rsqrt_shared = T.sblock_alloc_buffer((1, n), scope="shared")
T_rms_norm_local = T.sblock_alloc_buffer((1, n, 4096), scope="local")
data_local = T.sblock_alloc_buffer((1, n, 4096), scope="local")
for ax0_ax1_fused in T.thread_binding(n, thread="blockIdx.x"):
for ax2_0 in T.thread_binding(512, thread="threadIdx.x"):
for ax2_1 in range(1):
for ax2_2 in T.vectorized(8):
with T.sblock("data_local"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(n, ax0_ax1_fused)
v2 = T.axis.spatial(4096, ax2_0 * 8 + ax2_1 * 8 + ax2_2)
T.reads(data[v0, v1, v2])
T.writes(data_local[v0, v1, v2])
data_local[v0, v1, v2] = data[v0, v1, v2]
for ax0 in range(8):
with T.sblock("T_multiply"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
v_ax2 = T.axis.spatial(4096, ax2_0 * 8 + ax0)
T.reads(data_local[v_ax0, v_ax1, v_ax2])
T.writes(T_multiply_local[v_ax0, v_ax1, v_ax2])
T_multiply_local[v_ax0, v_ax1, v_ax2] = data_local[v_ax0, v_ax1, v_ax2] * data_local[v_ax0, v_ax1, v_ax2]
for ax0 in range(8):
with T.sblock("T_multiply_red"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
v_k2 = T.axis.reduce(4096, ax2_0 * 8 + ax0)
T.reads(T_multiply_local[v_ax0, v_ax1, v_k2])
T.writes(T_multiply_red_local[v_ax0, v_ax1])
with T.init():
T_multiply_red_local[v_ax0, v_ax1] = T.float32(0)
T_multiply_red_local[v_ax0, v_ax1] = T_multiply_red_local[v_ax0, v_ax1] + T_multiply_local[v_ax0, v_ax1, v_k2]
with T.sblock("rsqrt"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
T.reads(T_multiply_red_local[v_ax0, v_ax1])
T.writes(rsqrt_shared[v_ax0, v_ax1])
rsqrt_shared[v_ax0, v_ax1] = T.rsqrt(T_multiply_red_local[v_ax0, v_ax1] * T.float32(0.000244140625) + T.float32(9.9999999999999995e-07))
for ax0_0 in T.thread_binding(512, thread="threadIdx.x"):
for ax0_1, ax0_2 in T.grid(1, 8):
with T.sblock("T_rms_norm"):
v_ax0 = T.axis.spatial(1, 0)
v_ax1 = T.axis.spatial(n, ax0_ax1_fused)
v_ax2 = T.axis.spatial(4096, ax0_0 * 8 + ax0_1 * 8 + ax0_2)
T.reads(rsqrt_shared[v_ax0, v_ax1], data_local[v_ax0, v_ax1, v_ax2], weight[v_ax2])
T.writes(T_rms_norm_local[v_ax0, v_ax1, v_ax2])
T_rms_norm_local[v_ax0, v_ax1, v_ax2] = rsqrt_shared[v_ax0, v_ax1] * data_local[v_ax0, v_ax1, v_ax2] * weight[v_ax2]
for ax0 in T.vectorized(8):
with T.sblock("T_cast_local"):
v0 = T.axis.spatial(1, 0)
v1 = T.axis.spatial(n, ax0_ax1_fused)
v2 = T.axis.spatial(4096, ax0_0 * 8 + ax0)
T.reads(T_rms_norm_local[v0, v1, v2])
T.writes(T_cast[v0, v1, v2])
T_cast[v0, v1, v2] = T_rms_norm_local[v0, v1, v2]
# fmt: on
_check(Before, After)
if __name__ == "__main__":
tvm.testing.main()
@@ -0,0 +1,190 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: E501, F401
import tvm
from tvm.ir import IRModule, assert_structural_equal
from tvm.s_tir import dlight as dl
from tvm.script import ir as I
from tvm.script import tirx as T
from tvm.target import Target
def _check(mod_before: IRModule, mod_after: IRModule):
target = Target("nvidia/geforce-rtx-3090-ti")
with target:
mod = dl.ApplyDefaultSchedule( # pylint: disable=not-callable
dl.gpu.Transpose(),
)(mod_before)
assert_structural_equal(mod, mod_after)
def test_transpose():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(rxplaceholder: T.Buffer((T.int64(512), T.int64(4096)), "float32"), T_transpose: T.Buffer((T.int64(4096), T.int64(512)), "float32")):
T.func_attr({"tirx.noalias": True})
for ax0, ax1 in T.grid(T.int64(4096), T.int64(512)):
with T.sblock("T_transpose"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T_transpose[v_ax0, v_ax1] = rxplaceholder[v_ax1, v_ax0]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(rxplaceholder: T.Buffer((T.int64(512), T.int64(4096)), "float32"), T_transpose: T.Buffer((T.int64(4096), T.int64(512)), "float32")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
rxplaceholder_shared = T.sblock_alloc_buffer((T.int64(512), T.int64(4096)), scope="shared")
for ax0_0_0 in T.thread_binding(T.int64(512), thread="blockIdx.y", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0 in T.thread_binding(T.int64(32), thread="blockIdx.x"):
for ax0_ax1_fused_0 in range(T.int64(1)):
for ax0_ax1_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(T.int64(16), thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.unroll(T.int64(1)):
with T.sblock("rxplaceholder_shared"):
v0 = T.axis.spatial(T.int64(512), ax1_0 * T.int64(16) + (ax0_ax1_fused_0 * T.int64(128) + ax0_ax1_fused_1 * T.int64(16) + ax0_ax1_fused_2 + ax0_ax1_fused_3) // T.int64(8))
v1 = T.axis.spatial(T.int64(4096), ax0_0_0 * T.int64(8) + (ax0_ax1_fused_0 * T.int64(128) + ax0_ax1_fused_1 * T.int64(16) + ax0_ax1_fused_2 + ax0_ax1_fused_3) % T.int64(8))
T.reads(rxplaceholder[v0, v1])
T.writes(rxplaceholder_shared[v0, v1])
T.sblock_attr({"buffer_dim_align": [[0, 0, 32, 1]]})
rxplaceholder_shared[v0, v1] = rxplaceholder[v0, v1]
for ax0_0_1 in T.thread_binding(T.int64(8), thread="threadIdx.y"):
for ax1_1 in T.thread_binding(T.int64(16), thread="threadIdx.x"):
for ax0_1_0 in range(T.int64(1)):
for ax0_1_1 in range(T.int64(1)):
with T.sblock("T_transpose"):
v0 = T.axis.spatial(T.int64(4096), ax0_0_0 * T.int64(8) + ax0_0_1 + ax0_1_0 + ax0_1_1)
v1 = T.axis.spatial(T.int64(512), ax1_0 * T.int64(16) + ax1_1)
T.reads(rxplaceholder_shared[v1, v0])
T.writes(T_transpose[v0, v1])
T_transpose[v0, v1] = rxplaceholder_shared[v1, v0]
# fmt: on
_check(Before, After)
def test_decode_transpose():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(rxplaceholder: T.Buffer((T.int64(512), T.int64(4096)), "uint32"), rxplaceholder_1: T.Buffer((T.int64(128), T.int64(4096)), "uint32"), T_transpose: T.Buffer((T.int64(4096), T.int64(4096)), "float32")):
T.func_attr({"tirx.noalias": True})
decode = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)))
for i, j in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(rxplaceholder[v_i // T.int64(8), v_j], rxplaceholder_1[v_i // T.int64(32), v_j])
T.writes(decode[v_i, v_j])
decode[v_i, v_j] = T.Cast("float32", T.bitwise_and(T.shift_right(rxplaceholder[v_i // T.int64(8), v_j], T.Cast("uint32", v_i % T.int64(8) * T.int64(4))), T.uint32(15))) * T.reinterpret("float32", T.shift_left(T.bitwise_and(rxplaceholder_1[v_i // T.int64(32), v_j], T.uint32(65535)), T.uint32(16))) + T.reinterpret("float32", T.shift_left(T.bitwise_and(T.shift_right(rxplaceholder_1[v_i // T.int64(32), v_j], T.uint32(16)), T.uint32(65535)), T.uint32(16)))
for ax0, ax1 in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("T_transpose"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(decode[v_ax1, v_ax0])
T.writes(T_transpose[v_ax0, v_ax1])
T_transpose[v_ax0, v_ax1] = decode[v_ax1, v_ax0]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(rxplaceholder: T.Buffer((T.int64(512), T.int64(4096)), "uint32"), rxplaceholder_1: T.Buffer((T.int64(128), T.int64(4096)), "uint32"), T_transpose: T.Buffer((T.int64(4096), T.int64(4096)), "float32")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
decode_shared = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)), scope="shared")
for ax0_0_0 in T.thread_binding(T.int64(64), thread="blockIdx.y", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0 in T.thread_binding(T.int64(256), thread="blockIdx.x"):
for ax0_ax1_fused_0 in range(T.int64(1)):
for ax0_ax1_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(T.int64(16), thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.unroll(T.int64(8)):
with T.sblock("decode_shared"):
v0 = T.axis.spatial(T.int64(4096), ax1_0 * T.int64(16) + (ax0_ax1_fused_0 * T.int64(1024) + ax0_ax1_fused_1 * T.int64(128) + ax0_ax1_fused_2 * T.int64(8) + ax0_ax1_fused_3) // T.int64(64))
v1 = T.axis.spatial(T.int64(4096), ax0_0_0 * T.int64(64) + (ax0_ax1_fused_0 * T.int64(1024) + ax0_ax1_fused_1 * T.int64(128) + ax0_ax1_fused_2 * T.int64(8) + ax0_ax1_fused_3) % T.int64(64))
T.reads(rxplaceholder[v0 // T.int64(8), v1], rxplaceholder_1[v0 // T.int64(32), v1])
T.writes(decode_shared[v0, v1])
T.sblock_attr({"buffer_dim_align": [[0, 0, 32, 1]]})
decode_shared[v0, v1] = T.Cast("float32", T.bitwise_and(T.shift_right(rxplaceholder[v0 // T.int64(8), v1], T.Cast("uint32", v0 % T.int64(8) * T.int64(4))), T.uint32(15))) * T.reinterpret("float32", T.shift_left(T.bitwise_and(rxplaceholder_1[v0 // T.int64(32), v1], T.uint32(65535)), T.uint32(16))) + T.reinterpret("float32", T.shift_left(T.bitwise_and(T.shift_right(rxplaceholder_1[v0 // T.int64(32), v1], T.uint32(16)), T.uint32(65535)), T.uint32(16)))
for ax0_0_1 in T.thread_binding(T.int64(8), thread="threadIdx.y"):
for ax1_1 in T.thread_binding(T.int64(16), thread="threadIdx.x"):
for ax0_1_0 in range(T.int64(2)):
for ax0_1_1 in T.vectorized(T.int64(4)):
with T.sblock("T_transpose"):
v0 = T.axis.spatial(T.int64(4096), ax0_0_0 * T.int64(64) + ax0_0_1 * T.int64(8) + ax0_1_0 * T.int64(4) + ax0_1_1)
v1 = T.axis.spatial(T.int64(4096), ax1_0 * T.int64(16) + ax1_1)
T.reads(decode_shared[v1, v0])
T.writes(T_transpose[v0, v1])
T_transpose[v0, v1] = decode_shared[v1, v0]
# fmt: on
_check(Before, After)
def test_decode_int3_transpose():
# fmt: off
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((T.int64(412), T.int64(4096)), "uint32"), B: T.Buffer((T.int64(103), T.int64(4096)), "float16"), T_transpose: T.Buffer((T.int64(4096), T.int64(4096)), "float16")):
T.func_attr({"tirx.noalias": True})
decode_1 = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)), "float16")
for i, j in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("decode"):
v_i, v_j = T.axis.remap("SS", [i, j])
T.reads(A[v_i // T.int64(10), v_j], B[v_i // T.int64(40), v_j])
T.writes(decode_1[v_i, v_j])
decode_1[v_i, v_j] = (T.Cast("float16", T.bitwise_and(T.shift_right(A[v_i // T.int64(10), v_j], T.Cast("uint32", v_i % T.int64(10)) * T.uint32(3)), T.uint32(7))) - T.float16(3)) * B[v_i // T.int64(40), v_j]
for ax0, ax1 in T.grid(T.int64(4096), T.int64(4096)):
with T.sblock("T_transpose"):
v_ax0, v_ax1 = T.axis.remap("SS", [ax0, ax1])
T.reads(decode_1[v_ax1, v_ax0])
T.writes(T_transpose[v_ax0, v_ax1])
T_transpose[v_ax0, v_ax1] = decode_1[v_ax1, v_ax0]
@I.ir_module(s_tir=True)
class After:
@T.prim_func(s_tir=True)
def main(A: T.Buffer((T.int64(412), T.int64(4096)), "uint32"), B: T.Buffer((T.int64(103), T.int64(4096)), "float16"), T_transpose: T.Buffer((T.int64(4096), T.int64(4096)), "float16")):
T.func_attr({"tirx.is_scheduled": True, "tirx.noalias": True})
# with T.sblock("root"):
decode_1_shared = T.sblock_alloc_buffer((T.int64(4096), T.int64(4096)), "float16", scope="shared")
for ax0_0_0 in T.thread_binding(T.int64(52), thread="blockIdx.y", annotations={"pragma_auto_unroll_max_step": 256, "pragma_unroll_explicit": 1}):
for ax1_0 in T.thread_binding(T.int64(256), thread="blockIdx.x"):
for ax0_ax1_fused_0 in range(T.int64(2)):
for ax0_ax1_fused_1 in T.thread_binding(T.int64(8), thread="threadIdx.y"):
for ax0_ax1_fused_2 in T.thread_binding(T.int64(16), thread="threadIdx.x"):
for ax0_ax1_fused_3 in T.unroll(T.int64(10)):
with T.sblock("decode_1_shared"):
v0 = T.axis.spatial(T.int64(4096), ax1_0 * T.int64(16) + (ax0_ax1_fused_0 * T.int64(1280) + ax0_ax1_fused_1 * T.int64(160) + ax0_ax1_fused_2 * T.int64(10) + ax0_ax1_fused_3) // T.int64(82))
v1 = T.axis.spatial(T.int64(4096), ax0_0_0 * T.int64(80) + (ax0_ax1_fused_0 * T.int64(1280) + ax0_ax1_fused_1 * T.int64(160) + ax0_ax1_fused_2 * T.int64(10) + ax0_ax1_fused_3) % T.int64(82))
T.where(ax0_0_0 * T.int64(80) + (((ax0_ax1_fused_0 * T.int64(8) + ax0_ax1_fused_1) * T.int64(16) + ax0_ax1_fused_2) * T.int64(10) + ax0_ax1_fused_3) % T.int64(82) < T.int64(4096) and ((ax0_ax1_fused_0 * T.int64(8) + ax0_ax1_fused_1) * T.int64(16) + ax0_ax1_fused_2) * T.int64(10) + ax0_ax1_fused_3 < T.int64(1312))
T.reads(A[v0 // T.int64(10), v1], B[v0 // T.int64(40), v1])
T.writes(decode_1_shared[v0, v1])
T.sblock_attr({"buffer_dim_align": [[0, 0, 32, 1]]})
decode_1_shared[v0, v1] = (T.Cast("float16", T.bitwise_and(T.shift_right(A[v0 // T.int64(10), v1], T.Cast("uint32", v0 % T.int64(10)) * T.uint32(3)), T.uint32(7))) - T.float16(3)) * B[v0 // T.int64(40), v1]
for ax0_0_1 in T.thread_binding(T.int64(8), thread="threadIdx.y"):
for ax1_1 in T.thread_binding(T.int64(16), thread="threadIdx.x"):
for ax0_1_0 in range(T.int64(3)):
for ax0_1_1 in T.vectorized(T.int64(4)):
with T.sblock("T_transpose"):
v0 = T.axis.spatial(T.int64(4096), (ax0_0_0 * T.int64(8) + ax0_0_1) * T.int64(10) + (ax0_1_0 * T.int64(4) + ax0_1_1))
v1 = T.axis.spatial(T.int64(4096), ax1_0 * T.int64(16) + ax1_1)
T.where((ax0_0_0 * T.int64(8) + ax0_0_1) * T.int64(10) + (ax0_1_0 * T.int64(4) + ax0_1_1) < T.int64(4096) and ax0_0_0 * T.int64(8) + ax0_0_1 < T.int64(410) and ax0_1_0 * T.int64(4) + ax0_1_1 < T.int64(10))
T.reads(decode_1_shared[v1, v0])
T.writes(T_transpose[v0, v1])
T_transpose[v0, v1] = decode_1_shared[v1, v0]
# fmt: on
_check(Before, After)
@@ -0,0 +1,65 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=missing-docstring
# ruff: noqa: F841
import pytest
import tvm
import tvm.testing
from tvm.script import tirx as T
from tvm.testing import env
@T.prim_func(s_tir=True)
def main(p0: T.Buffer((), "int32"), T_stack: T.Buffer((T.int64(3),), "int32")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
compile_engine_const = T.sblock_alloc_buffer((), "int32")
compile_engine_const_1 = T.sblock_alloc_buffer((), "int32")
with T.sblock("compile_engine_const"):
vi = T.axis.spatial(1, T.int64(0))
T.reads()
T.writes(compile_engine_const[()])
compile_engine_const[()] = 16
with T.sblock("compile_engine_const_1"):
vi = T.axis.spatial(1, T.int64(0))
T.reads()
T.writes(compile_engine_const_1[()])
compile_engine_const_1[()] = 20
for ax0 in range(T.int64(3)):
with T.sblock("T_stack"):
v_ax0 = T.axis.spatial(T.int64(3), ax0)
T.reads(compile_engine_const[()], p0[()], compile_engine_const_1[()])
T.writes(T_stack[v_ax0])
T_stack[v_ax0] = T.if_then_else(
v_ax0 == T.int64(2),
compile_engine_const[()],
T.if_then_else(v_ax0 == T.int64(1), p0[()], compile_engine_const_1[()]),
)
@pytest.mark.gpu
@pytest.mark.skipif(not env.has_cuda(), reason="need cuda")
def test_normalize_primfunc_with_scalar():
sch = tvm.s_tir.Schedule(main)
f_normalize_prim_func = tvm.get_global_func("s_tir.schedule.NormalizePrimFunc")
assert f_normalize_prim_func(sch)
if __name__ == "__main__":
tvm.testing.main()