Skip to content

Commit 4f73732

Browse files
Arm backend: Share operator dtype support checks (#24495)
Signed-off-by: Sebastian Larsson <sebastian.larsson@arm.com>
1 parent 0287ce1 commit 4f73732

9 files changed

Lines changed: 115 additions & 300 deletions

File tree

‎backends/arm/BUCK‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ fbcode_target(
1818
"constants.py",
1919
],
2020
deps = [
21+
"//caffe2:torch",
2122
"//executorch/exir/dialects:lib",
2223
],
2324
)

‎backends/arm/constants.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from typing import Any, cast, Final
77

8+
import torch
89
from executorch.exir.dialects._ops import ops as exir_ops
910

1011
exir_ops = cast(Any, exir_ops)
@@ -30,6 +31,15 @@
3031
)
3132
PER_CHANNEL_QDQ_OPS: Final = (QUANT_PER_CHANNEL_OP, DEQUANT_PER_CHANNEL_OP)
3233

34+
INT_DTYPES: Final = (torch.bool, torch.int8, torch.int16, torch.int32)
35+
FP_DTYPES: Final = (
36+
torch.float16,
37+
torch.float32,
38+
torch.bfloat16,
39+
torch.float8_e4m3fn,
40+
torch.float8_e5m2,
41+
)
42+
3343
NHWC_ORDER: Final = (0, 2, 3, 1)
3444
NHWC_INVERSE_ORDER: Final = (0, 3, 1, 2)
3545
NNHWC_ORDER: Final = (0, 1, 3, 4, 2)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright 2026 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+
"""Provide shared dtype checks for TOSA operator support."""
6+
7+
import torch
8+
from executorch.backends.arm.constants import FP_DTYPES, INT_DTYPES
9+
from executorch.backends.arm.tosa import TosaSpecification
10+
from executorch.exir.backend.utils import WhyNoPartitionReporter
11+
12+
13+
def is_indexing_dtype_supported(
14+
node: torch.fx.Node,
15+
values_dtype: torch.dtype,
16+
tosa_spec: TosaSpecification,
17+
reporter: WhyNoPartitionReporter,
18+
) -> bool:
19+
"""Check value dtypes for indexing against TOSA profiles and extensions.
20+
21+
Supported integer dtypes and bool require the INT profile. Supported
22+
floating-point dtypes allow the FP profile or the INT profile via
23+
quantization. BF16 and FP8 also require their corresponding extensions.
24+
25+
Args:
26+
node (torch.fx.Node): Operator node used in rejection messages.
27+
values_dtype (torch.dtype): Dtype of the values being indexed.
28+
tosa_spec (TosaSpecification): Active TOSA profiles and extensions.
29+
reporter (WhyNoPartitionReporter): Reporter for rejection reasons.
30+
31+
Returns:
32+
bool: True if the dtype is supported; otherwise, False.
33+
34+
"""
35+
if values_dtype in INT_DTYPES:
36+
if not tosa_spec.support_integer():
37+
reporter.report_reject(
38+
node,
39+
f"{node.target}: dtype {values_dtype} requires INT profile.",
40+
)
41+
return False
42+
elif values_dtype in FP_DTYPES:
43+
if values_dtype == torch.bfloat16 and not tosa_spec.support_extension("bf16"):
44+
reporter.report_reject(
45+
node,
46+
f"{node.target}: dtype {values_dtype} requires bf16 extension.",
47+
)
48+
return False
49+
if values_dtype == torch.float8_e4m3fn and not tosa_spec.support_extension(
50+
"fp8e4m3"
51+
):
52+
reporter.report_reject(
53+
node,
54+
f"{node.target}: dtype {values_dtype} requires fp8e4m3 extension.",
55+
)
56+
return False
57+
if values_dtype == torch.float8_e5m2 and not tosa_spec.support_extension(
58+
"fp8e5m2"
59+
):
60+
reporter.report_reject(
61+
node,
62+
f"{node.target}: dtype {values_dtype} requires fp8e5m2 extension.",
63+
)
64+
return False
65+
else:
66+
reporter.report_reject(
67+
node,
68+
f"{node.target}: unsupported values dtype {values_dtype}; "
69+
f"expected one of {INT_DTYPES + FP_DTYPES}.",
70+
)
71+
return False
72+
73+
return True

‎backends/arm/operator_support/gather_support.py‎

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
from executorch.backends.arm._passes.prepare_gather_indices_pass import (
3939
is_safe_int32_to_int64_gather_boundary,
4040
)
41+
from executorch.backends.arm.operator_support.dtype_support import (
42+
is_indexing_dtype_supported,
43+
)
4144
from executorch.backends.arm.operator_support.tosa_supported_operators import (
4245
register_tosa_support_check,
4346
SupportedTOSAOperatorCheck,
@@ -52,9 +55,10 @@ class GatherSupported(SupportedTOSAOperatorCheck):
5255

5356
targets = [exir_ops.edge.aten.gather.default]
5457

55-
def is_node_tosa_supported( # noqa: C901
58+
def is_node_tosa_supported(
5659
self, node: fx.Node, tosa_spec: TosaSpecification
5760
) -> bool: # type: ignore[override, misc]
61+
"""Return True if the gather node passes the TOSA support checks."""
5862
if len(node.args) != 3:
5963
self.reporter.report_reject(
6064
node,
@@ -111,62 +115,4 @@ def is_node_tosa_supported( # noqa: C901
111115
)
112116
return False
113117

114-
# ---- values dtype ----
115-
values_dtype = x_val.dtype
116-
# ints (and bool via casts) require INT profile
117-
if values_dtype in (torch.bool, torch.int8, torch.int16, torch.int32):
118-
if not tosa_spec.support_integer():
119-
self.reporter.report_reject(
120-
node,
121-
f"{node.target}: dtype {values_dtype} requires INT profile.",
122-
)
123-
return False
124-
# fp16/fp32/bf16/fp8: either FP profile, or INT profile (via quantization)
125-
elif values_dtype in (
126-
torch.float16,
127-
torch.float32,
128-
torch.bfloat16,
129-
torch.float8_e4m3fn,
130-
torch.float8_e5m2,
131-
):
132-
if values_dtype == torch.bfloat16 and not tosa_spec.support_extension(
133-
"bf16"
134-
):
135-
self.reporter.report_reject(
136-
node,
137-
f"{node.target}: dtype {values_dtype} requires bf16 extension.",
138-
)
139-
return False
140-
if values_dtype == torch.float8_e4m3fn and not tosa_spec.support_extension(
141-
"fp8e4m3"
142-
):
143-
self.reporter.report_reject(
144-
node,
145-
f"{node.target}: dtype {values_dtype} requires fp8e4m3 extension.",
146-
)
147-
return False
148-
if values_dtype == torch.float8_e5m2 and not tosa_spec.support_extension(
149-
"fp8e5m2"
150-
):
151-
self.reporter.report_reject(
152-
node,
153-
f"{node.target}: dtype {values_dtype} requires fp8e5m2 extension.",
154-
)
155-
return False
156-
if not (tosa_spec.support_float() or tosa_spec.support_integer()):
157-
self.reporter.report_reject(
158-
node,
159-
f"{node.target}: dtype {values_dtype} requires FP profile or "
160-
"INT profile (with quantization).",
161-
)
162-
return False
163-
else:
164-
self.reporter.report_reject(
165-
node,
166-
f"{node.target}: unsupported values dtype {values_dtype}; "
167-
"expected bool/int8/int16/int32/float16/bfloat16/float32/"
168-
"float8_e4m3fn/float8_e5m2.",
169-
)
170-
return False
171-
172-
return True
118+
return is_indexing_dtype_supported(node, x_val.dtype, tosa_spec, self.reporter)

‎backends/arm/operator_support/index_select_support.py‎

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
import torch
1919
import torch.fx as fx
2020

21+
from executorch.backends.arm.operator_support.dtype_support import (
22+
is_indexing_dtype_supported,
23+
)
2124
from executorch.backends.arm.operator_support.tosa_supported_operators import (
2225
register_tosa_support_check,
2326
SupportedTOSAOperatorCheck,
@@ -35,6 +38,7 @@ class IndexSelectSupported(SupportedTOSAOperatorCheck):
3538
def is_node_tosa_supported(
3639
self, node: fx.Node, tosa_spec: TosaSpecification
3740
) -> bool: # type: ignore[override, misc]
41+
"""Return True if the index_select node passes the support checks."""
3842
if len(node.args) != 3:
3943
self.reporter.report_reject(
4044
node,
@@ -67,62 +71,4 @@ def is_node_tosa_supported(
6771
)
6872
return False
6973

70-
# Dtype constraints
71-
values_dtype = x_val.dtype
72-
# ints (and bool via casts) require INT profile
73-
if values_dtype in (torch.bool, torch.int8, torch.int16, torch.int32):
74-
if not tosa_spec.support_integer():
75-
self.reporter.report_reject(
76-
node,
77-
f"{node.target}: dtype {values_dtype} requires INT profile.",
78-
)
79-
return False
80-
# fp16/fp32/bf16/fp8: either FP profile, or INT profile (via quantization)
81-
elif values_dtype in (
82-
torch.float16,
83-
torch.float32,
84-
torch.bfloat16,
85-
torch.float8_e4m3fn,
86-
torch.float8_e5m2,
87-
):
88-
if values_dtype == torch.bfloat16 and not tosa_spec.support_extension(
89-
"bf16"
90-
):
91-
self.reporter.report_reject(
92-
node,
93-
f"{node.target}: dtype {values_dtype} requires bf16 extension.",
94-
)
95-
return False
96-
if values_dtype == torch.float8_e4m3fn and not tosa_spec.support_extension(
97-
"fp8e4m3"
98-
):
99-
self.reporter.report_reject(
100-
node,
101-
f"{node.target}: dtype {values_dtype} requires fp8e4m3 extension.",
102-
)
103-
return False
104-
if values_dtype == torch.float8_e5m2 and not tosa_spec.support_extension(
105-
"fp8e5m2"
106-
):
107-
self.reporter.report_reject(
108-
node,
109-
f"{node.target}: dtype {values_dtype} requires fp8e5m2 extension.",
110-
)
111-
return False
112-
if not (tosa_spec.support_float() or tosa_spec.support_integer()):
113-
self.reporter.report_reject(
114-
node,
115-
f"{node.target}: dtype {values_dtype} requires FP profile or "
116-
"INT profile (with quantization).",
117-
)
118-
return False
119-
else:
120-
self.reporter.report_reject(
121-
node,
122-
f"{node.target}: unsupported values dtype {values_dtype}; "
123-
"expected bool/int8/int16/int32/float16/bfloat16/float32/"
124-
"float8_e4m3fn/float8_e5m2.",
125-
)
126-
return False
127-
128-
return True
74+
return is_indexing_dtype_supported(node, x_val.dtype, tosa_spec, self.reporter)

‎backends/arm/operator_support/index_tensor_support.py‎

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
import torch.fx as fx
1717
from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor
1818
from executorch.backends.arm.common.type import ensure_type
19+
from executorch.backends.arm.operator_support.dtype_support import (
20+
is_indexing_dtype_supported,
21+
)
1922
from executorch.backends.arm.operator_support.tosa_supported_operators import (
2023
register_tosa_support_check,
2124
SupportedTOSAOperatorCheck,
@@ -178,58 +181,6 @@ def is_node_tosa_supported(
178181
if not self._are_shapes_supported(node, input_val, index_vals):
179182
return False
180183

181-
values_dtype = input_val.dtype
182-
if values_dtype in (torch.bool, torch.int8, torch.int16, torch.int32):
183-
if not tosa_spec.support_integer():
184-
self.reporter.report_reject(
185-
node,
186-
f"{node.target}: dtype {values_dtype} requires INT profile.",
187-
)
188-
return False
189-
elif values_dtype in (
190-
torch.float16,
191-
torch.float32,
192-
torch.bfloat16,
193-
torch.float8_e4m3fn,
194-
torch.float8_e5m2,
195-
):
196-
if values_dtype == torch.bfloat16 and not tosa_spec.support_extension(
197-
"bf16"
198-
):
199-
self.reporter.report_reject(
200-
node,
201-
f"{node.target}: dtype {values_dtype} requires bf16 extension.",
202-
)
203-
return False
204-
if values_dtype == torch.float8_e4m3fn and not tosa_spec.support_extension(
205-
"fp8e4m3"
206-
):
207-
self.reporter.report_reject(
208-
node,
209-
f"{node.target}: dtype {values_dtype} requires fp8e4m3 extension.",
210-
)
211-
return False
212-
if values_dtype == torch.float8_e5m2 and not tosa_spec.support_extension(
213-
"fp8e5m2"
214-
):
215-
self.reporter.report_reject(
216-
node,
217-
f"{node.target}: dtype {values_dtype} requires fp8e5m2 extension.",
218-
)
219-
return False
220-
if not (tosa_spec.support_float() or tosa_spec.support_integer()):
221-
self.reporter.report_reject(
222-
node,
223-
f"{node.target}: dtype {values_dtype} requires FP profile or "
224-
"INT profile (with quantization).",
225-
)
226-
return False
227-
else:
228-
self.reporter.report_reject(
229-
node,
230-
f"{node.target}: unsupported values dtype {values_dtype}; "
231-
"expected bool/int8/int16/int32/float16/bfloat16/float32/float8_e4m3fn/float8_e5m2.",
232-
)
233-
return False
234-
235-
return True
184+
return is_indexing_dtype_supported(
185+
node, input_val.dtype, tosa_spec, self.reporter
186+
)

0 commit comments

Comments
 (0)