Skip to content

Commit 95a0ef6

Browse files
Arm backend: enable dim_order (#7952)
Arm backend: enable dim_order (#7831) Add support for to_dim_order_copy With edge_compile_config.skip_dim_order = True removed, to_copy will be converted into to_dim_order_copy nodes. This commit moves our logic from to_copy into to_dim_order_copy. Signed-off-by: Oscar Andersson <[email protected]> (cherry picked from commit 135e875) Co-authored-by: Oscar Andersson <[email protected]>
1 parent 7c16c49 commit 95a0ef6

11 files changed

+72
-53
lines changed

backends/arm/operator_support/to_copy_support.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 Arm Limited and/or its affiliates.
1+
# Copyright 2024-2025 Arm Limited and/or its affiliates.
22
#
33
# This source code is licensed under the BSD-style license found in the
44
# LICENSE file in the root directory of this source tree.
@@ -22,7 +22,10 @@
2222

2323
@register_tosa_support_check
2424
class ToCopySupported(SupportedTOSAOperatorCheck):
25-
targets = [exir_ops.edge.aten._to_copy.default]
25+
targets = [
26+
exir_ops.edge.aten._to_copy.default,
27+
exir_ops.edge.dim_order_ops._to_dim_order_copy.default,
28+
]
2629

2730
tosa_specs = [
2831
TosaSpecification.create_from_string("TOSA-0.80.0+BI"),
@@ -110,7 +113,7 @@ def is_node_supported(self, node: fx.Node, tosa_spec: TosaSpecification) -> bool
110113
)
111114
return False
112115

113-
# Check memory format
116+
# Check memory format (to_copy)
114117
if "memory_format" in node.kwargs:
115118
if node.kwargs["memory_format"] in (torch.preserve_format,):
116119
logger.info(
@@ -119,4 +122,14 @@ def is_node_supported(self, node: fx.Node, tosa_spec: TosaSpecification) -> bool
119122
)
120123
return False
121124

125+
# Check dim_order (to_dim_order_copy)
126+
if "dim_order" in node.kwargs:
127+
dim_order = node.kwargs["dim_order"]
128+
if dim_order != list(range(len(dim_order))):
129+
logger.info(
130+
f"Argument {dim_order=} is not supported for "
131+
f"{node.target.name()} right now." # pyre-ignore[16]
132+
)
133+
return False
134+
122135
return True

backends/arm/operators/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
op_sum,
4040
op_tanh,
4141
op_to_copy,
42+
op_to_dim_order_copy,
4243
op_transpose,
4344
op_unsqueeze,
4445
op_upsample_nearest2d,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2025 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
# pyre-unsafe
7+
from typing import List
8+
9+
import serializer.tosa_serializer as ts
10+
import torch
11+
import tosa.Op as TosaOp
12+
13+
from executorch.backends.arm.operators.node_visitor import (
14+
NodeVisitor,
15+
register_node_visitor,
16+
)
17+
from executorch.backends.arm.tosa_mapping import TosaArg
18+
19+
20+
@register_node_visitor
21+
class ToDimOrderCopyVisitor(NodeVisitor):
22+
"""
23+
Implement the type cast functionality of _to_dim_order_copy.
24+
25+
Other features like setting of the dim_order or moving a tensor to a
26+
different device are not supported.
27+
28+
Also note that the node should not be quantized.
29+
"""
30+
31+
target = "dim_order_ops._to_dim_order_copy.default"
32+
33+
def define_node(
34+
self,
35+
node: torch.fx.Node,
36+
tosa_graph: ts.TosaSerializer,
37+
inputs: List[TosaArg],
38+
output: TosaArg,
39+
) -> None:
40+
tosa_graph.addOperator(TosaOp.Op().CAST, [inputs[0].name], [output.name])

backends/arm/test/models/test_mobilenet_v2_arm.py

+4-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from executorch.backends.arm.test import common, conftest
1313

1414
from executorch.backends.arm.test.tester.arm_tester import ArmTester
15-
from executorch.exir import EdgeCompileConfig
1615
from torchvision import models, transforms
1716
from torchvision.models.mobilenetv2 import MobileNet_V2_Weights
1817

@@ -45,10 +44,6 @@ class TestMobileNetV2(unittest.TestCase):
4544
"executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default",
4645
}
4746

48-
_edge_compile_config: EdgeCompileConfig = EdgeCompileConfig(
49-
_skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend.
50-
)
51-
5247
def test_mv2_tosa_MI(self):
5348
(
5449
ArmTester(
@@ -59,7 +54,7 @@ def test_mv2_tosa_MI(self):
5954
),
6055
)
6156
.export()
62-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
57+
.to_edge_transform_and_lower()
6358
.to_executorch()
6459
.run_method_and_compare_outputs(inputs=self.model_inputs)
6560
)
@@ -75,7 +70,7 @@ def test_mv2_tosa_BI(self):
7570
)
7671
.quantize()
7772
.export()
78-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
73+
.to_edge_transform_and_lower()
7974
.to_executorch()
8075
# atol=1.0 is a defensive upper limit
8176
# TODO MLETROCH-72
@@ -92,7 +87,7 @@ def test_mv2_u55_BI(self):
9287
)
9388
.quantize()
9489
.export()
95-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
90+
.to_edge_transform_and_lower()
9691
.to_executorch()
9792
.serialize()
9893
)
@@ -110,7 +105,7 @@ def test_mv2_u85_BI(self):
110105
)
111106
.quantize()
112107
.export()
113-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
108+
.to_edge_transform_and_lower()
114109
.to_executorch()
115110
.serialize()
116111
)

backends/arm/test/ops/test_add.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import torch
1313
from executorch.backends.arm.test import common, conftest
1414
from executorch.backends.arm.test.tester.arm_tester import ArmTester
15-
from executorch.exir import EdgeCompileConfig
1615
from executorch.exir.backend.compile_spec_schema import CompileSpec
1716
from parameterized import parameterized
1817

@@ -50,10 +49,6 @@ def __init__(self):
5049
def forward(self, x, y):
5150
return x + y
5251

53-
_edge_compile_config: EdgeCompileConfig = EdgeCompileConfig(
54-
_skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend.
55-
)
56-
5752
def _test_add_tosa_MI_pipeline(
5853
self, module: torch.nn.Module, test_data: Tuple[torch.Tensor]
5954
):
@@ -66,7 +61,7 @@ def _test_add_tosa_MI_pipeline(
6661
.export()
6762
.check_count({"torch.ops.aten.add.Tensor": 1})
6863
.check_not(["torch.ops.quantized_decomposed"])
69-
.to_edge(config=self._edge_compile_config)
64+
.to_edge()
7065
.partition()
7166
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
7267
.to_executorch()
@@ -86,7 +81,7 @@ def _test_add_tosa_BI_pipeline(
8681
.export()
8782
.check_count({"torch.ops.aten.add.Tensor": 1})
8883
.check(["torch.ops.quantized_decomposed"])
89-
.to_edge(config=self._edge_compile_config)
84+
.to_edge()
9085
.partition()
9186
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
9287
.to_executorch()

backends/arm/test/ops/test_linear.py

+3-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from executorch.backends.arm.test import common, conftest
1515

1616
from executorch.backends.arm.test.tester.arm_tester import ArmTester
17-
from executorch.exir import EdgeCompileConfig
1817
from executorch.exir.backend.compile_spec_schema import CompileSpec
1918
from parameterized import parameterized
2019

@@ -106,10 +105,6 @@
106105
class TestLinear(unittest.TestCase):
107106
"""tests the linear operation y = Ax + b"""
108107

109-
_edge_compile_config: EdgeCompileConfig = EdgeCompileConfig(
110-
_skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend.
111-
)
112-
113108
class Linear(torch.nn.Module):
114109
def __init__(
115110
self,
@@ -141,7 +136,7 @@ def _test_linear_tosa_MI_pipeline(
141136
.export()
142137
.check_count({"torch.ops.aten.linear.default": 1})
143138
.check_not(["torch.ops.quantized_decomposed"])
144-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
139+
.to_edge_transform_and_lower()
145140
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
146141
.to_executorch()
147142
.run_method_and_compare_outputs(inputs=test_data)
@@ -162,7 +157,7 @@ def _test_linear_tosa_BI_pipeline(
162157
.export()
163158
.check_count({"torch.ops.aten.linear.default": 1})
164159
.check(["torch.ops.quantized_decomposed"])
165-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
160+
.to_edge_transform_and_lower()
166161
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
167162
.to_executorch()
168163
.run_method_and_compare_outputs(inputs=test_data, qtol=1)
@@ -184,7 +179,7 @@ def _test_linear_tosa_ethosu_BI_pipeline(
184179
.export()
185180
.check_count({"torch.ops.aten.linear.default": 1})
186181
.check(["torch.ops.quantized_decomposed"])
187-
.to_edge_transform_and_lower(edge_compile_config=self._edge_compile_config)
182+
.to_edge_transform_and_lower()
188183
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
189184
.to_executorch()
190185
.serialize()

backends/arm/test/ops/test_maximum.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import torch
1313
from executorch.backends.arm.test import common
1414
from executorch.backends.arm.test.tester.arm_tester import ArmTester
15-
from executorch.exir import EdgeCompileConfig
1615
from executorch.exir.backend.compile_spec_schema import CompileSpec
1716
from parameterized import parameterized
1817

@@ -38,10 +37,6 @@ def __init__(self):
3837
def forward(self, x, y):
3938
return torch.maximum(x, y)
4039

41-
_edge_compile_config: EdgeCompileConfig = EdgeCompileConfig(
42-
_skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend.
43-
)
44-
4540
def _test_maximum_tosa_MI_pipeline(
4641
self, module: torch.nn.Module, test_data: Tuple[torch.Tensor]
4742
):
@@ -54,7 +49,7 @@ def _test_maximum_tosa_MI_pipeline(
5449
.export()
5550
.check_count({"torch.ops.aten.maximum.default": 1})
5651
.check_not(["torch.ops.quantized_decomposed"])
57-
.to_edge(config=self._edge_compile_config)
52+
.to_edge()
5853
.partition()
5954
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
6055
.to_executorch()
@@ -74,7 +69,7 @@ def _test_maximum_tosa_BI_pipeline(
7469
.export()
7570
.check_count({"torch.ops.aten.maximum.default": 1})
7671
.check(["torch.ops.quantized_decomposed"])
77-
.to_edge(config=self._edge_compile_config)
72+
.to_edge()
7873
.partition()
7974
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
8075
.to_executorch()

backends/arm/test/ops/test_minimum.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import torch
1313
from executorch.backends.arm.test import common
1414
from executorch.backends.arm.test.tester.arm_tester import ArmTester
15-
from executorch.exir import EdgeCompileConfig
1615
from executorch.exir.backend.compile_spec_schema import CompileSpec
1716
from parameterized import parameterized
1817

@@ -38,10 +37,6 @@ def __init__(self):
3837
def forward(self, x, y):
3938
return torch.minimum(x, y)
4039

41-
_edge_compile_config: EdgeCompileConfig = EdgeCompileConfig(
42-
_skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend.
43-
)
44-
4540
def _test_minimum_tosa_MI_pipeline(
4641
self, module: torch.nn.Module, test_data: Tuple[torch.Tensor]
4742
):
@@ -54,7 +49,7 @@ def _test_minimum_tosa_MI_pipeline(
5449
.export()
5550
.check_count({"torch.ops.aten.minimum.default": 1})
5651
.check_not(["torch.ops.quantized_decomposed"])
57-
.to_edge(config=self._edge_compile_config)
52+
.to_edge()
5853
.partition()
5954
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
6055
.to_executorch()
@@ -74,7 +69,7 @@ def _test_minimum_tosa_BI_pipeline(
7469
.export()
7570
.check_count({"torch.ops.aten.minimum.default": 1})
7671
.check(["torch.ops.quantized_decomposed"])
77-
.to_edge(config=self._edge_compile_config)
72+
.to_edge()
7873
.partition()
7974
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
8075
.to_executorch()

backends/arm/test/ops/test_sum.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import torch
1212
from executorch.backends.arm.test import common
1313
from executorch.backends.arm.test.tester.arm_tester import ArmTester
14-
from executorch.exir import EdgeCompileConfig
1514
from executorch.exir.backend.compile_spec_schema import CompileSpec
1615
from parameterized import parameterized
1716

@@ -50,10 +49,6 @@ class Sum(torch.nn.Module):
5049
def forward(self, x: torch.Tensor, dim: int, keepdim: bool):
5150
return x.sum(dim=dim, keepdim=keepdim)
5251

53-
_edge_compile_config: EdgeCompileConfig = EdgeCompileConfig(
54-
_skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend.
55-
)
56-
5752
def _test_sum_tosa_MI_pipeline(
5853
self, module: torch.nn.Module, test_data: tuple[exampledata_t]
5954
):
@@ -66,7 +61,7 @@ def _test_sum_tosa_MI_pipeline(
6661
.export()
6762
.check_count({"torch.ops.aten.sum.dim_IntList": 1})
6863
.check_not(["torch.ops.quantized_decomposed"])
69-
.to_edge(config=self._edge_compile_config)
64+
.to_edge()
7065
.partition()
7166
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
7267
.to_executorch()
@@ -86,7 +81,7 @@ def _test_sum_tosa_BI_pipeline(
8681
.export()
8782
.check_count({"torch.ops.aten.sum.dim_IntList": 1})
8883
.check(["torch.ops.quantized_decomposed"])
89-
.to_edge(config=self._edge_compile_config)
84+
.to_edge()
9085
.partition()
9186
.check_count({"torch.ops.higher_order.executorch_call_delegate": 1})
9287
.to_executorch()

backends/arm/test/tester/arm_tester.py

-3
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,6 @@ def to_edge(
218218
if config is not None:
219219
to_edge_stage.edge_compile_conf = config
220220

221-
# TODO(T182928844): Delegate dim order op to backend.
222-
to_edge_stage.edge_compile_conf._skip_dim_order = True
223221
return super().to_edge(to_edge_stage)
224222

225223
def partition(self, partition_stage: Optional[Partition] = None):
@@ -245,7 +243,6 @@ def to_edge_transform_and_lower(
245243
to_edge_and_lower_stage.partitioners = partitioners
246244
if edge_compile_config is not None:
247245
to_edge_and_lower_stage.edge_compile_conf = edge_compile_config
248-
to_edge_and_lower_stage.edge_compile_conf._skip_dim_order = True
249246
return super().to_edge_transform_and_lower(to_edge_and_lower_stage)
250247

251248
def to_executorch(self, to_executorch_stage: Optional[ToExecutorch] | None = None):

examples/arm/aot_arm_compiler.py

-2
Original file line numberDiff line numberDiff line change
@@ -511,15 +511,13 @@ def get_args():
511511
partitioner=[ArmPartitioner(compile_spec)],
512512
compile_config=EdgeCompileConfig(
513513
_check_ir_validity=False,
514-
_skip_dim_order=True,
515514
),
516515
)
517516
else:
518517
edge = to_edge_transform_and_lower(
519518
exported_program,
520519
compile_config=EdgeCompileConfig(
521520
_check_ir_validity=False,
522-
_skip_dim_order=True,
523521
),
524522
)
525523

0 commit comments

Comments
 (0)