|
10 | 10 | from unittest import mock |
11 | 11 |
|
12 | 12 | import pytest |
| 13 | +import torch |
13 | 14 |
|
14 | 15 | from executorch.backends.arm._passes import EnsureUniqueOutputNodesPass, RewriteConvPass |
15 | 16 | from executorch.backends.arm._passes.arm_pass_manager import ( |
|
18 | 19 | PassInsertions, |
19 | 20 | ) |
20 | 21 |
|
| 22 | +from executorch.backends.arm.operator_support.tosa_supported_operators import ( |
| 23 | + CheckResolvedTensorShapes, |
| 24 | +) |
21 | 25 | from executorch.backends.arm.vgf import backend, backend as vgf_backend, VgfCompileSpec |
22 | 26 | from executorch.backends.arm.vgf._passes import GroupIndependentCustomShadersPass |
23 | 27 | from executorch.backends.arm.vgf.backend import ( |
|
29 | 33 | vgf_compile, |
30 | 34 | ) |
31 | 35 | from executorch.exir.backend.backend_details import PreprocessResult |
| 36 | +from executorch.exir.backend.utils import WhyNoPartitionReporter |
| 37 | +from executorch.exir.dialects._ops import ops as exir_ops |
32 | 38 | from executorch.exir.pass_base import ExportPass |
| 39 | +from torch._subclasses.fake_tensor import FakeTensorMode |
33 | 40 | from torch.export.exported_program import ExportedProgram |
34 | 41 | from torch.fx import GraphModule |
| 42 | +from torch.fx.experimental.symbolic_shapes import ShapeEnv |
35 | 43 | from torch.fx.passes.infra.pass_base import PassResult |
36 | 44 |
|
37 | 45 |
|
@@ -540,3 +548,38 @@ def fake_converter_run(command, **kwargs): |
540 | 548 | assert not (artifact_path / "output.tosa.vgf").exists() |
541 | 549 |
|
542 | 550 | assert mock_run.call_count == 2 |
| 551 | + |
| 552 | + |
| 553 | +@pytest.mark.parametrize("dynamic", [False, True]) |
| 554 | +@pytest.mark.parametrize( |
| 555 | + "target,args", |
| 556 | + [ |
| 557 | + (exir_ops.edge.aten.view_copy.default, ([-1],)), |
| 558 | + (exir_ops.edge.aten.permute_copy.default, ([1, 0],)), |
| 559 | + (torch.ops.aten.sym_size.int, (0,)), |
| 560 | + (exir_ops.edge.aten.relu.default, ()), |
| 561 | + ], |
| 562 | +) |
| 563 | +def test_vgf_dynamic_shape_support(target, args, dynamic) -> None: |
| 564 | + shape_env = ShapeEnv() |
| 565 | + inputs = torch.empty((2, 3)) |
| 566 | + graph = torch.fx.Graph() |
| 567 | + x = graph.placeholder("x") |
| 568 | + with FakeTensorMode(shape_env=shape_env) as mode: |
| 569 | + x.meta["val"] = mode.from_tensor(inputs, static_shapes=not dynamic) |
| 570 | + node = graph.call_function(target, (x, *args)) |
| 571 | + node.meta["val"] = target(x.meta["val"], *args) |
| 572 | + |
| 573 | + checker = CheckResolvedTensorShapes( |
| 574 | + WhyNoPartitionReporter(), |
| 575 | + targets=( |
| 576 | + exir_ops.edge.aten.view_copy.default, |
| 577 | + exir_ops.edge.aten.permute_copy.default, |
| 578 | + ), |
| 579 | + reject_symbolic_scalars=True, |
| 580 | + ) |
| 581 | + expected_support = not dynamic or target == exir_ops.edge.aten.relu.default |
| 582 | + assert checker.is_node_supported({}, node) is expected_support |
| 583 | + |
| 584 | + default_checker = CheckResolvedTensorShapes(WhyNoPartitionReporter()) |
| 585 | + assert default_checker.is_node_supported({}, node) is (not dynamic) |
0 commit comments