Skip to content

Commit 90f88b7

Browse files
authored
Migrate to Graph.materialize_symints; stop passing raw SymInts (pytorch#21919)
Differential Revision: D109610966 Pull Request resolved: pytorch#21919
1 parent 8b93850 commit 90f88b7

11 files changed

Lines changed: 321 additions & 105 deletions

‎backends/arm/_passes/convert_full_like_to_full_pass.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ def call_operator(self, op, args, kwargs, meta):
4242
return super().call_operator(op, args, kwargs, meta)
4343

4444
tensor = args[0].data
45-
full_args = (list(tensor.shape), args[1])
45+
# Each entry is an int (static dim) or an aten.sym_size.int ProxyValue (dynamic dim).
46+
size_args = self.call_size_operator_all(args[0], meta, edge_dialect=True)
47+
full_args = (size_args, args[1])
4648
full_kwargs = {"dtype": tensor.dtype}
4749
return super().call_operator(
4850
exir_ops.edge.aten.full.default, full_args, full_kwargs, meta

‎backends/arm/_passes/decompose_linear_pass.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,23 @@ def call(self, graph_module):
5656
# weights have shape (Co, Ci)
5757
weights_reshaped_shape = [weights_shape[0], weights_shape[1], 1, 1]
5858

59+
# Materialize SymInts into FX nodes; one call shares
60+
# the symbol subgraph across all three shape lists.
5961
with graph_module.graph.inserting_before(node):
62+
n_in, n_w = (
63+
len(input_reshaped_shape),
64+
len(weights_reshaped_shape),
65+
)
66+
all_sizes = graph_module.graph.materialize_symints(
67+
[
68+
*input_reshaped_shape,
69+
*weights_reshaped_shape,
70+
*output_shape,
71+
]
72+
)
73+
input_reshaped_shape = all_sizes[:n_in]
74+
weights_reshaped_shape = all_sizes[n_in : n_in + n_w]
75+
output_size = all_sizes[n_in + n_w :]
6076
# Reshape input to 4D with shape (N, Ci, 1, 1)
6177
input_reshaped = create_node(
6278
graph=graph_module.graph,
@@ -103,7 +119,7 @@ def call(self, graph_module):
103119
output = create_node(
104120
graph=graph_module.graph,
105121
op_target=exir_ops.edge.aten.view_copy.default,
106-
args=(conv, list(output_shape)),
122+
args=(conv, output_size),
107123
kwargs={},
108124
from_node=node,
109125
inherit_qparams=False,

‎backends/arm/_passes/decompose_select.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,18 @@ def call(self, graph_module: torch.fx.GraphModule):
5656
index = size_at_dim - abs(index)
5757

5858
with graph_module.graph.inserting_before(node):
59+
# ``Graph.create_node`` rejects raw SymInts in call_function
60+
# args; ``materialize_symints`` lifts symbolic ``index`` /
61+
# ``index + 1`` (from negative-index wrap-around against a
62+
# dynamic shape) into graph nodes in a single call (shares
63+
# producer-discovery + hash-cons). Static ints pass through.
64+
start_arg, end_arg = graph_module.graph.materialize_symints(
65+
[index, index + 1]
66+
)
5967
slice_node = create_node(
6068
graph_module.graph,
6169
slice_op,
62-
(input_node, dim, index, index + 1),
70+
(input_node, dim, start_arg, end_arg),
6371
from_node=node,
6472
inherit_qparams=False,
6573
)

‎backends/arm/_passes/insert_dynamic_padding.py‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
from typing import Set, Type
77

8-
import torch
9-
108
from executorch.backends.arm._passes import ArmOpTargetedPass
119
from executorch.backends.arm.tosa.dialect.shape import is_shape_op_node
1210

@@ -41,7 +39,7 @@ def _is_dynamic_padding(
4139
return (isinstance(padding, ProxyValue) and is_shape_op_node(padding.node)) or (
4240
(
4341
isinstance(padding, (list, tuple))
44-
and any(isinstance(p, torch.SymInt) for p in padding)
42+
and any(isinstance(p, ProxyValue) for p in padding)
4543
)
4644
)
4745

‎backends/arm/_passes/rewrite_conv_pass.py‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,29 @@ def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901
817817
dilation,
818818
)
819819

820+
# Compute fake tensor BEFORE materializing SymInts into FX nodes,
821+
# since the underlying op expects ints/SymInts (not FX Nodes).
822+
bias_fake_tensor = get_first_fake_tensor(bias) if bias else None
823+
tosa_node_fake_tensor = target_op(
824+
input_tensor_for_tosa_fake,
825+
weight_fake_tensor,
826+
bias_fake_tensor,
827+
*conv_args[3:],
828+
)
829+
830+
# ``Graph.create_node`` rejects raw SymInts in call_function args.
831+
# If ``pad`` contains symbolic entries, materialize them into FX
832+
# nodes so the TOSA conv node references the producing graph
833+
# subgraph instead of holding raw SymInts.
834+
if isinstance(pad, (list, tuple)) and any(
835+
isinstance(p, torch.SymInt) for p in pad
836+
):
837+
with graph_module.graph.inserting_before(node):
838+
materialized_pad = graph_module.graph.materialize_symints(pad)
839+
new_conv_args = list(conv_args)
840+
new_conv_args[4] = materialized_pad
841+
conv_args = tuple(new_conv_args)
842+
820843
with graph_module.graph.inserting_after(node):
821844
tosa_op = create_node(
822845
graph=graph_module.graph,
@@ -825,13 +848,6 @@ def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901
825848
from_node=node,
826849
inherit_qparams=True,
827850
)
828-
bias_fake_tensor = get_first_fake_tensor(bias) if bias else None
829-
tosa_node_fake_tensor = target_op(
830-
input_tensor_for_tosa_fake,
831-
weight_fake_tensor,
832-
bias_fake_tensor,
833-
*conv_args[3:],
834-
)
835851
tosa_op.meta["val"] = tosa_node_fake_tensor
836852

837853
node_replacement, node_replacement_fake_tensor = (

‎backends/arm/_passes/size_adjust_input_pass.py‎

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ def _get_slice_adjustment(
8383
if exact_values is not None:
8484
adjustments = {max(value - pad, 0) for value in exact_values}
8585
if len(adjustments) == 1:
86-
adjustment = next(iter(adjustments))
87-
return adjustment if adjustment > 0 else None
86+
exact_adjustment = next(iter(adjustments))
87+
return exact_adjustment if exact_adjustment > 0 else None
8888

8989
if pad >= stride - 1:
9090
return None
9191

92-
adjustment: SymIntLike | None = None # type: ignore[no-redef]
92+
adjustment: SymIntLike | None = None
9393
for threshold in range(pad + 1, stride):
9494
term = (remainder + stride - threshold) // stride
9595
adjustment = term if adjustment is None else adjustment + term
@@ -272,10 +272,29 @@ def call(self, graph_module: torch.fx.GraphModule) -> PassResult:
272272

273273
parent_node = node.args[0]
274274
with graph_module.graph.inserting_before(node):
275+
# ``Graph.create_node`` rejects raw SymInts in
276+
# call_function args. Aggregate every slice arg across
277+
# all entries and lift via a single ``materialize_symints``
278+
# call -- the helper walks the graph once for producer
279+
# discovery, so a single call amortises that cost and lets
280+
# symints with shared sub-expressions get hash-consed into
281+
# one subgraph. Plain ints pass through unchanged.
282+
flat = [a for args in slice_args for a in args]
283+
materialized = iter(graph.materialize_symints(flat))
284+
# Pop exactly len(args) values from the materialized iterator
285+
# and pack them back into a tuple -- regroups the flat list
286+
# of lifted values into the original (dim, start, end) shape.
287+
lifted_slice_args = [
288+
tuple(next(materialized) for _ in args) for args in slice_args
289+
]
290+
275291
last_node = cast(torch.fx.Node, parent_node)
276-
for args in slice_args:
292+
for args in lifted_slice_args:
277293
slice_node = create_node(
278-
graph, slice_op, (last_node,) + args, from_node=node
294+
graph,
295+
slice_op,
296+
(last_node,) + args,
297+
from_node=node,
279298
)
280299
last_node = slice_node
281300
node.replace_input_with(cast(torch.fx.Node, parent_node), last_node)

‎backends/arm/test/passes/test_decompose_select_pass.py‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,18 @@ def test_decompose_select_negative_symbolic_index_uses_symbolic_sub() -> None:
6363

6464
slice_node = slice_nodes[0]
6565
assert slice_node.args[1] == 1
66-
assert slice_node.args[2] != -1
67-
assert isinstance(slice_node.args[2], torch.SymInt)
68-
assert isinstance(slice_node.args[3], torch.SymInt)
69-
assert str(slice_node.args[2]).endswith(" - 1")
70-
assert str(slice_node.args[3]) in str(slice_node.args[2])
66+
# Start/end are now FX nodes (materialized from SymInts) rather than raw
67+
# SymInts, since Graph.create_node rejects raw symbolic leaves in
68+
# call_function args. The original SymInt is preserved in meta['val'].
69+
start_arg, end_arg = slice_node.args[2], slice_node.args[3]
70+
assert isinstance(start_arg, torch.fx.Node)
71+
assert isinstance(end_arg, torch.fx.Node)
72+
start_val = start_arg.meta["val"]
73+
end_val = end_arg.meta["val"]
74+
assert isinstance(start_val, torch.SymInt)
75+
assert isinstance(end_val, torch.SymInt)
76+
assert str(start_val).endswith(" - 1")
77+
assert str(end_val) in str(start_val)
7178
assert squeeze_nodes[0].args == (slice_node, [1])
7279

7380
result.graph_module.graph.lint()

0 commit comments

Comments
 (0)