# 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. import tvm import tvm.testing from tvm import relax from tvm.script import ir as I from tvm.script import relax as R @I.ir_module class Module: @R.function def fused_relax_nn_attention_cutlass( q: R.Tensor((32, 8, 16, 8), dtype="float16"), k: R.Tensor((32, 8, 16, 8), dtype="float16"), v: R.Tensor((32, 8, 16, 8), dtype="float16"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): R.func_attr( { "Codegen": "cutlass", "WorkspaceSize": 65536, "global_symbol": "fused_relax_nn_attention_cutlass", } ) @R.function def gv( q_1: R.Tensor((32, 8, 16, 8), dtype="float16"), k_1: R.Tensor((32, 8, 16, 8), dtype="float16"), v_1: R.Tensor((32, 8, 16, 8), dtype="float16"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): R.func_attr( {"Composite": "cutlass.attention", "Primitive": True, "WorkspaceSize": 65536} ) with R.dataflow(): gv_2: R.Tensor((32, 8, 16, 8), dtype="float16") = R.nn.attention( q_1, k_1, v_1, scale=None ) R.output(gv_2) return gv_2 gv1: R.Tensor((32, 8, 16, 8), dtype="float16") = gv(q, k, v) return gv1 @R.function def entry_a( q: R.Tensor((32, 8, 16, 8), dtype="float16"), k: R.Tensor((32, 8, 16, 8), dtype="float16"), v: R.Tensor((32, 8, 16, 8), dtype="float16"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): cls = Module with R.dataflow(): gv: R.Tensor((32, 8, 16, 8), dtype="float16") = cls.fused_relax_nn_attention_cutlass( q, k, v ) R.output(gv) return gv @R.function def entry_b( q: R.Tensor((32, 8, 16, 8), dtype="float16"), k: R.Tensor((32, 8, 16, 8), dtype="float16"), v: R.Tensor((32, 8, 16, 8), dtype="float16"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): cls = Module with R.dataflow(): gv: R.Tensor((32, 8, 16, 8), dtype="float16") = cls.fused_relax_nn_attention_cutlass( q, k, v ) + R.const(1, dtype="float16") R.output(gv) return gv @I.ir_module class Expected: @R.function def fused_relax_nn_attention_cutlass1( q: R.Tensor((32, 8, 16, 8), dtype="float16"), k: R.Tensor((32, 8, 16, 8), dtype="float16"), v: R.Tensor((32, 8, 16, 8), dtype="float16"), workspace: R.Tensor((65536,), dtype="uint8"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): R.func_attr( { "Codegen": "cutlass", "global_symbol": "fused_relax_nn_attention_cutlass1", } ) @R.function def gv( q_1: R.Tensor((32, 8, 16, 8), dtype="float16"), k_1: R.Tensor((32, 8, 16, 8), dtype="float16"), v_1: R.Tensor((32, 8, 16, 8), dtype="float16"), workspace_1: R.Tensor((65536,), dtype="uint8"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): R.func_attr({"Composite": "cutlass.attention", "Primitive": True}) with R.dataflow(): gv_2: R.Tensor((32, 8, 16, 8), dtype="float16") = R.nn.attention( q_1, k_1, v_1, scale=None ) R.output(gv_2) return gv_2 gv1: R.Tensor((32, 8, 16, 8), dtype="float16") = gv(q, k, v, workspace) return gv1 @R.function def entry_a( q: R.Tensor((32, 8, 16, 8), dtype="float16"), k: R.Tensor((32, 8, 16, 8), dtype="float16"), v: R.Tensor((32, 8, 16, 8), dtype="float16"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): cls = Expected with R.dataflow(): workspace_main: R.Tensor((65536,), dtype="uint8") = R.builtin.alloc_tensor( R.shape([65536]), R.dtype("uint8"), R.prim_value(0) ) gv: R.Tensor((32, 8, 16, 8), dtype="float16") = cls.fused_relax_nn_attention_cutlass1( q, k, v, workspace_main ) R.output(gv) return gv @R.function def entry_b( q: R.Tensor((32, 8, 16, 8), dtype="float16"), k: R.Tensor((32, 8, 16, 8), dtype="float16"), v: R.Tensor((32, 8, 16, 8), dtype="float16"), ) -> R.Tensor((32, 8, 16, 8), dtype="float16"): cls = Expected with R.dataflow(): workspace_main: R.Tensor((65536,), dtype="uint8") = R.builtin.alloc_tensor( R.shape([65536]), R.dtype("uint8"), R.prim_value(0) ) gv: R.Tensor((32, 8, 16, 8), dtype="float16") = cls.fused_relax_nn_attention_cutlass1( q, k, v, workspace_main ) + R.const(1, dtype="float16") R.output(gv) return gv def test_single_attention(): rewritten = relax.transform.AllocateWorkspace()(Module) tvm.ir.assert_structural_equal(rewritten, Expected) if __name__ == "__main__": tvm.testing.main()