chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
# 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.script import ir as I
|
||||
from tvm.script import relax as R
|
||||
from tvm.script import tirx as T
|
||||
|
||||
|
||||
def test_remove_unused_relax_parameter():
|
||||
"""A relax parameter may be removed
|
||||
|
||||
This is only allowed for internal function calls, where all
|
||||
callsites can be updated. For externally-exposed functions, the
|
||||
signature may not be modified.
|
||||
"""
|
||||
|
||||
@I.ir_module
|
||||
class Before:
|
||||
@R.function
|
||||
def main(A: R.Tensor, B: R.Tensor):
|
||||
return Before.func(A, B)
|
||||
|
||||
@R.function(private=True)
|
||||
def func(A: R.Tensor, B: R.Tensor) -> R.Tensor:
|
||||
return A
|
||||
|
||||
@I.ir_module
|
||||
class Expected:
|
||||
@R.function
|
||||
def main(A: R.Tensor, B: R.Tensor):
|
||||
return Expected.func(A)
|
||||
|
||||
@R.function(private=True)
|
||||
def func(A: R.Tensor) -> R.Tensor:
|
||||
return A
|
||||
|
||||
After = tvm.relax.transform.RemoveUnusedParameters()(Before)
|
||||
tvm.ir.assert_structural_equal(After, Expected)
|
||||
|
||||
|
||||
def test_replace_symbolic_variables():
|
||||
"""If a parameter is only required for its symbolic variables, provide them directly
|
||||
|
||||
The relax parameter `A` isn't used by the subroutine. However,
|
||||
its shape defines the symbolic variables `m` and `n`. When
|
||||
removing the `R.Tensor` argument, we may need to provide
|
||||
additional parameters to define the symbolic variables.
|
||||
|
||||
A `PrimType` carries only a dtype and defines no TIR var. Each free
|
||||
symbolic variable is therefore promoted through a 1-D `R.Shape`
|
||||
parameter, which actually *defines* the variable.
|
||||
"""
|
||||
|
||||
@I.ir_module
|
||||
class Before:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
return Before.func(A)
|
||||
|
||||
@R.function(private=True)
|
||||
def func(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
return R.zeros(R.shape([m, n]), dtype="float32")
|
||||
|
||||
@I.ir_module
|
||||
class Expected:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
out: R.Tensor([m, n], "float32") = Expected.func(R.shape([n]), R.shape([m]))
|
||||
return out
|
||||
|
||||
@R.function(private=True)
|
||||
def func(param_n: R.Shape(["n"]), param_m: R.Shape(["m"])) -> R.Tensor(
|
||||
["m", "n"], "float32"
|
||||
):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
return R.zeros(R.shape([m, n]), dtype="float32")
|
||||
|
||||
After = tvm.relax.transform.RemoveUnusedParameters()(Before)
|
||||
tvm.ir.assert_structural_equal(After, Expected)
|
||||
|
||||
|
||||
def test_no_extra_symbolic_variables():
|
||||
"""Don't add symbolic variables if they can be inferred.
|
||||
|
||||
Even though some cases require adding new parameters to provide
|
||||
symbolic variables, not every symbolic variable requires a
|
||||
distinct parameter.
|
||||
"""
|
||||
|
||||
@I.ir_module
|
||||
class Before:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
return Before.func(A)
|
||||
|
||||
@R.function(private=True)
|
||||
def func(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
zeros = R.zeros(R.shape([m, n]), dtype="float32")
|
||||
out = R.add(A, zeros)
|
||||
return out
|
||||
|
||||
Expected = Before
|
||||
|
||||
After = tvm.relax.transform.RemoveUnusedParameters()(Before)
|
||||
tvm.ir.assert_structural_equal(After, Expected)
|
||||
|
||||
|
||||
def test_remove_extra_prim_parameters():
|
||||
"""Remove unused scalar parameters.
|
||||
|
||||
The tensor parameter already defines the symbolic dimensions, while the
|
||||
dtype-only scalar parameters are unused by the private function.
|
||||
"""
|
||||
|
||||
@I.ir_module
|
||||
class Before:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
return Before.func(A, R.prim_value(m), R.prim_value(n))
|
||||
|
||||
@R.function(private=True)
|
||||
def func(
|
||||
A: R.Tensor(["m", "n"], "float32"),
|
||||
_m: R.Prim("int64"),
|
||||
_n: R.Prim("int64"),
|
||||
) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
zeros = R.zeros(R.shape([m, n]), dtype="float32")
|
||||
out = R.add(A, zeros)
|
||||
return out
|
||||
|
||||
@I.ir_module
|
||||
class Expected:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
return Expected.func(A)
|
||||
|
||||
@R.function(private=True)
|
||||
def func(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
zeros = R.zeros(R.shape([m, n]), dtype="float32")
|
||||
out = R.add(A, zeros)
|
||||
return out
|
||||
|
||||
After = tvm.relax.transform.RemoveUnusedParameters()(Before)
|
||||
tvm.ir.assert_structural_equal(After, Expected)
|
||||
|
||||
|
||||
def test_remove_extra_shape_variables():
|
||||
"""Remove parameters that only serve to define existing symbolic variables
|
||||
|
||||
If a `R.Shape` parameter provides a definition of a symbolic
|
||||
variable, but that symbolic variable can be determined from a
|
||||
different parameter, then the `R.Shape` parameter can be removed.
|
||||
"""
|
||||
|
||||
@I.ir_module
|
||||
class Before:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
return Before.func(A, R.shape([m, n]))
|
||||
|
||||
@R.function(private=True)
|
||||
def func(
|
||||
A: R.Tensor(["m", "n"], "float32"),
|
||||
_: R.Shape(["m", "n"]),
|
||||
) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
zeros = R.zeros(R.shape([m, n]), dtype="float32")
|
||||
out = R.add(A, zeros)
|
||||
return out
|
||||
|
||||
@I.ir_module
|
||||
class Expected:
|
||||
@R.function
|
||||
def main(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
return Expected.func(A)
|
||||
|
||||
@R.function(private=True)
|
||||
def func(A: R.Tensor(["m", "n"], "float32")) -> R.Tensor(["m", "n"], "float32"):
|
||||
m = T.int64()
|
||||
n = T.int64()
|
||||
zeros = R.zeros(R.shape([m, n]), dtype="float32")
|
||||
out = R.add(A, zeros)
|
||||
return out
|
||||
|
||||
After = tvm.relax.transform.RemoveUnusedParameters()(Before)
|
||||
tvm.ir.assert_structural_equal(After, Expected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tvm.testing.main()
|
||||
Reference in New Issue
Block a user