# 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. # ruff: noqa: F401 """Test eliminate common subexpr pass""" import tvm import tvm.testing from tvm.ir import VDevice from tvm.relax.transform import RealizeVDevice from tvm.script.parser import ir as I from tvm.script.parser import relax as R from tvm.script.parser import tirx as T def verify(input, expected): tvm.ir.assert_structural_equal(RealizeVDevice()(input), expected) vdevices = [ VDevice("llvm"), VDevice("cuda", 0), VDevice("metal", 0, "global"), VDevice({"kind": "cuda", "arch": "sm_80"}, 0), ] def test_dataflow_binding(): @I.ir_module class Input: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), I.vdevice("cuda", 0), I.vdevice("metal", 0, "global"), I.vdevice({"kind": "cuda", "arch": "sm_80"}, 0), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tensor((2, 3), "float32"): with R.dataflow(): x1 = x y1 = y x2 = x1 y2 = y1 x2 = R.hint_on_device(x2, tvm.cpu()) lv0 = R.add(x2, y2) gv = R.multiply(lv0, z) R.output(gv) return gv @I.ir_module class Expect: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), I.vdevice("cuda", 0), I.vdevice("metal", 0, "global"), I.vdevice({"kind": "cuda", "arch": "sm_80"}, 0), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32", "llvm"), y: R.Tensor((2, 3), "float32", "llvm"), z: R.Tensor((2, 3), "float32", "llvm"), ) -> R.Tensor((2, 3), "float32", "llvm"): with R.dataflow(): x1: R.Tensor((2, 3), "float32", "llvm") = x y1: R.Tensor((2, 3), "float32", "llvm") = y x2: R.Tensor((2, 3), "float32", "llvm") = x1 y2: R.Tensor((2, 3), "float32", "llvm") = y1 x2: R.Tensor((2, 3), "float32", "llvm") = x2 lv0: R.Tensor((2, 3), "float32", "llvm") = R.add(x2, y2) gv: R.Tensor((2, 3), "float32", "llvm") = R.multiply(lv0, z) R.output(gv) return gv verify(Input, Expect) def test_binding(): @I.ir_module class Input: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tensor((2, 3), "float32"): x1 = x y1 = y x2 = x1 y2 = y1 x2 = R.hint_on_device(x2, tvm.cpu()) s = R.add(x2, y2) m = R.multiply(s, z) return m @I.ir_module class Expect: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32", "llvm"), y: R.Tensor((2, 3), "float32", "llvm"), z: R.Tensor((2, 3), "float32", "llvm"), ) -> R.Tensor((2, 3), "float32", "llvm"): x1: R.Tensor((2, 3), "float32", "llvm") = x y1: R.Tensor((2, 3), "float32", "llvm") = y x2: R.Tensor((2, 3), "float32", "llvm") = x1 y2: R.Tensor((2, 3), "float32", "llvm") = y1 x2: R.Tensor((2, 3), "float32", "llvm") = x2 s: R.Tensor((2, 3), "float32", "llvm") = R.add(x2, y2) m: R.Tensor((2, 3), "float32", "llvm") = R.multiply(s, z) return m verify(Input, Expect) def test_func_ret(): @I.ir_module class Input: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("cuda"), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tensor((2, 3), "float32", "cuda"): with R.dataflow(): lv0 = R.add(x, y) gv = R.multiply(lv0, z) R.output(gv) return gv @I.ir_module class Expect: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("cuda"), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32", "cuda"), y: R.Tensor((2, 3), "float32", "cuda"), z: R.Tensor((2, 3), "float32", "cuda"), ) -> R.Tensor((2, 3), "float32", "cuda"): with R.dataflow(): lv0: R.Tensor((2, 3), "float32", "cuda") = R.add(x, y) gv: R.Tensor((2, 3), "float32", "cuda") = R.multiply(lv0, z) R.output(gv) return gv verify(Input, Expect) def test_tuple_func_ret(): @I.ir_module class Input: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("cuda"), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tuple([R.Tensor((2, 3), "float32", "cuda"), R.Tensor((2, 3), "float32", "cuda")]): with R.dataflow(): lv0 = R.add(x, y) gv = R.multiply(lv0, z) R.output(gv) return (gv, gv) @I.ir_module class Expect: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("cuda"), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32", "cuda"), y: R.Tensor((2, 3), "float32", "cuda"), z: R.Tensor((2, 3), "float32", "cuda"), ) -> R.Tuple([R.Tensor((2, 3), "float32", "cuda"), R.Tensor((2, 3), "float32", "cuda")]): with R.dataflow(): lv0: R.Tensor((2, 3), "float32", "cuda") = R.add(x, y) gv: R.Tensor((2, 3), "float32", "cuda") = R.multiply(lv0, z) R.output(gv) return (gv, gv) verify(Input, Expect) def test_multi_device(): @I.ir_module class Input: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), I.vdevice("cuda", 0), I.vdevice("metal", 0, "global"), I.vdevice({"kind": "cuda", "arch": "sm_80"}, 0), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tensor((2, 3), "float32", "cuda"): with R.dataflow(): lv0 = R.add(x, y) lv0 = R.hint_on_device(lv0, tvm.cpu()) lv1 = R.to_vdevice(lv0, "cuda") lv2 = R.add(z, z) gv = R.multiply(lv1, lv2) R.output(gv) return gv @I.ir_module class Expect: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), I.vdevice("cuda", 0), I.vdevice("metal", 0, "global"), I.vdevice({"kind": "cuda", "arch": "sm_80"}, 0), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32", "llvm"), y: R.Tensor((2, 3), "float32", "llvm"), z: R.Tensor((2, 3), "float32", "cuda"), ) -> R.Tensor((2, 3), "float32", "cuda"): with R.dataflow(): lv0: R.Tensor((2, 3), "float32", "llvm") = R.add(x, y) lv0: R.Tensor((2, 3), "float32", "llvm") = lv0 lv1: R.Tensor((2, 3), "float32", "cuda") = R.to_vdevice(lv0, "cuda") lv2: R.Tensor((2, 3), "float32", "cuda") = R.add(z, z) gv: R.Tensor((2, 3), "float32", "cuda") = R.multiply(lv1, lv2) R.output(gv) return gv verify(Input, Expect) def test_insert_to_vdevice(): @I.ir_module class Input: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), I.vdevice("cuda", 0), I.vdevice("metal", 0, "global"), I.vdevice({"kind": "cuda", "arch": "sm_80"}, 0), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tensor((2, 3), "float32"): with R.dataflow(): lv0 = R.hint_on_device(y, tvm.cpu()) lv1 = R.add(x, lv0) lv2 = R.hint_on_device(lv1, tvm.cuda()) lv3 = R.add(lv2, lv2) lv4 = R.hint_on_device(z, tvm.cuda()) gv = R.multiply(lv3, lv4) R.output(gv) return gv @I.ir_module class Expect: I.module_attrs({"attr": 10}) I.module_global_infos( { "vdevice": [ I.vdevice("llvm"), I.vdevice("cuda", 0), I.vdevice("metal", 0, "global"), I.vdevice({"kind": "cuda", "arch": "sm_80"}, 0), ] } ) @R.function def foo( x: R.Tensor((2, 3), "float32", "llvm"), y: R.Tensor((2, 3), "float32", "llvm"), z: R.Tensor((2, 3), "float32", "cuda"), ) -> R.Tensor((2, 3), "float32", "cuda"): with R.dataflow(): lv0: R.Tensor((2, 3), "float32", "llvm") = y lv1: R.Tensor((2, 3), "float32", "llvm") = R.add(x, lv0) lv2: R.Tensor((2, 3), "float32", "cuda") = R.to_vdevice(lv1, "cuda") lv3: R.Tensor((2, 3), "float32", "cuda") = R.add(lv2, lv2) lv4: R.Tensor((2, 3), "float32", "cuda") = z gv: R.Tensor((2, 3), "float32", "cuda") = R.multiply(lv3, lv4) R.output(gv) return gv verify(Input, Expect) def test_input_module_is_unmodified(): def make_module(): @I.ir_module class Module: I.module_global_infos({"vdevice": [I.vdevice("llvm")]}) @R.function def foo( x: R.Tensor((2, 3), "float32"), y: R.Tensor((2, 3), "float32"), z: R.Tensor((2, 3), "float32"), ) -> R.Tensor((2, 3), "float32"): x1 = x y1 = y x2 = x1 y2 = y1 s: R.Tensor((2, 3), "float32", "llvm") = R.add(x2, y2) m = R.multiply(s, z) return m return Module original = make_module() expected = make_module() RealizeVDevice()(original) tvm.ir.assert_structural_equal(original, expected) if __name__ == "__main__": tvm.testing.main()