1111import logging
1212import os
1313from collections import defaultdict
14- from typing import Any , Dict , List , Optional , Sequence , Set , TextIO , Type , Union
14+ from typing import Any , Callable , Dict , List , Optional , Sequence , Set , TextIO , Type , Union
1515
1616import torch
1717import torch ._export
3030from executorch .exir .backend .partitioner import Partitioner
3131from executorch .exir .capture ._config import EdgeCompileConfig , ExecutorchBackendConfig
3232from executorch .exir .delegate import executorch_call_delegate , is_lowered_module
33+ from executorch .exir .dialects ._ops import ops as exir_ops
3334from executorch .exir .emit import emit_program , EmitterOutput
3435from executorch .exir .emit ._emitter import _DelegateDebugIdentifierMap
3536from executorch .exir .error import ExportError
@@ -132,15 +133,19 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
132133
133134
134135from executorch .exir ._program_utils import ( # noqa: E402
136+ _disambiguate_mutation_outputs ,
137+ _get_mutation_output_clone_op ,
135138 _get_updated_graph_signature ,
136139 _get_updated_range_constraints ,
140+ _set_mutation_output_clone_op ,
137141)
138142
139143
140144def _transform (
141145 self ,
142146 * passes : PassType ,
143147 override_verifiers : None | list [Type [Verifier ]] = None ,
148+ mutation_output_clone_op : Callable [..., torch .Tensor ] | None = None ,
144149) -> "ExportedProgram" :
145150 """
146151 Transforms the program according to the provided passes.
@@ -150,6 +155,8 @@ def _transform(
150155 *passes: A sequence of passes to apply to the program
151156 override_verifiers: Optional list of verifier classes to use instead of the default verifiers.
152157 This is needed if the transforms yields illegal graph that the default verifier cannot handle.
158+ mutation_output_clone_op: Clone operator for the transformed graph's dialect and layout mode.
159+ Defaults to ATen cloning or the contract recorded during Edge conversion.
153160
154161 Returns:
155162 ExportedProgram: A new ExportedProgram with the transformations applied, or self if no changes were made
@@ -160,14 +167,19 @@ def _transform(
160167 ), f"Expected all passes to be of PassType, not list or Verifier. Use override_verifiers kwarg instead. Got: { list (passes )} "
161168
162169 return _transform_with_pass_manager (
163- self , ExportedProgramPassManager (list (passes )), override_verifiers
170+ self ,
171+ ExportedProgramPassManager (list (passes )),
172+ override_verifiers ,
173+ mutation_output_clone_op = mutation_output_clone_op ,
164174 )
165175
166176
167177def _transform_with_pass_manager (
168178 self : ExportedProgram ,
169179 pass_manager : Union [ExportedProgramPassManager , GraphModulePassManager ],
170180 override_verifiers : None | list [Type [Verifier ]] = None ,
181+ * ,
182+ mutation_output_clone_op : Callable [..., torch .Tensor ] | None = None ,
171183) -> "ExportedProgram" :
172184 """
173185 Transforms the program using the provided pass_manager.
@@ -184,7 +196,11 @@ def _transform_with_pass_manager(
184196 ExportedProgram: A new ExportedProgram with the transformations applied, or self if no changes were made
185197 """
186198 if isinstance (pass_manager , ExportedProgramPassManager ):
187- res = pass_manager (self , override_verifiers )
199+ res = pass_manager (
200+ self ,
201+ override_verifiers ,
202+ mutation_output_clone_op = mutation_output_clone_op ,
203+ )
188204 if not res .modified :
189205 return self
190206 return res .exported_program
@@ -193,20 +209,30 @@ def _transform_with_pass_manager(
193209 if not res .modified :
194210 return self
195211 return _update_exported_program_graph_module (
196- self , res .graph_module , override_verifiers
212+ self ,
213+ res .graph_module ,
214+ override_verifiers ,
215+ mutation_output_clone_op = mutation_output_clone_op ,
197216 )
198217
199218
200219def _update_exported_program_graph_module (
201220 exported_program : ExportedProgram ,
202221 gm : torch .fx .GraphModule ,
203222 override_verifiers : None | list [Type [Verifier ]] = None ,
223+ * ,
224+ mutation_output_clone_op : Callable [..., torch .Tensor ] | None = None ,
204225) -> "ExportedProgram" :
226+ clone_op = _get_mutation_output_clone_op (exported_program , mutation_output_clone_op )
227+ _disambiguate_mutation_outputs (
228+ exported_program .graph_signature , gm , clone_op = clone_op
229+ )
205230 transformed_ep = ExportedProgram (
206231 root = gm ,
207232 graph = gm .graph ,
208233 graph_signature = _get_updated_graph_signature (
209- exported_program .graph_signature , gm
234+ exported_program .graph_signature ,
235+ gm ,
210236 ),
211237 state_dict = exported_program .state_dict ,
212238 range_constraints = _get_updated_range_constraints (
@@ -219,6 +245,7 @@ def _update_exported_program_graph_module(
219245 )
220246 transformed_ep .graph_module .meta .update (exported_program .graph_module .meta )
221247 transformed_ep .graph_module .meta .update (gm .meta )
248+ _set_mutation_output_clone_op (transformed_ep .graph_module , clone_op )
222249 return transformed_ep
223250
224251
@@ -707,11 +734,21 @@ def _to_edge(ep, config: EdgeCompileConfig) -> "ExirExportedProgram":
707734 assert new_gm_res is not None
708735 new_gm = new_gm_res .graph_module
709736
737+ clone_op = (
738+ exir_ops .edge .aten .clone .default
739+ if config ._skip_dim_order
740+ else exir_ops .edge .dim_order_ops ._clone_dim_order .default
741+ )
742+ _disambiguate_mutation_outputs (
743+ new_ep .exported_program .graph_signature , new_gm , clone_op = clone_op
744+ )
745+ _set_mutation_output_clone_op (new_gm , clone_op )
710746 new_ep .exported_program = ExportedProgram (
711747 root = new_gm ,
712748 graph = new_gm .graph ,
713749 graph_signature = _get_updated_graph_signature (
714- new_ep .exported_program .graph_signature , new_gm
750+ new_ep .exported_program .graph_signature ,
751+ new_gm ,
715752 ),
716753 state_dict = new_ep .exported_program .state_dict ,
717754 range_constraints = new_ep .exported_program .range_constraints ,
@@ -848,10 +885,20 @@ def _generate_edge_program(
848885 assert gm_res is not None
849886 gm = gm_res .graph_module
850887
888+ clone_op = (
889+ exir_ops .edge .aten .clone .default
890+ if config ._skip_dim_order
891+ else exir_ops .edge .dim_order_ops ._clone_dim_order .default
892+ )
893+ _disambiguate_mutation_outputs (program .graph_signature , gm , clone_op = clone_op )
894+ _set_mutation_output_clone_op (gm , clone_op )
851895 edge_program = ExportedProgram (
852896 root = gm ,
853897 graph = gm .graph ,
854- graph_signature = _get_updated_graph_signature (program .graph_signature , gm ),
898+ graph_signature = _get_updated_graph_signature (
899+ program .graph_signature ,
900+ gm ,
901+ ),
855902 state_dict = program .state_dict ,
856903 range_constraints = program .range_constraints ,
857904 module_call_graph = program .module_call_graph ,
@@ -1612,6 +1659,11 @@ def transform(
16121659 """
16131660
16141661 compile_config = compile_config or self .compile_config
1662+ clone_op = (
1663+ exir_ops .edge .aten .clone .default
1664+ if compile_config ._skip_dim_order
1665+ else exir_ops .edge .dim_order_ops ._clone_dim_order .default
1666+ )
16151667 new_programs : Dict [str , ExportedProgram ] = {}
16161668
16171669 # Cast passes parameter upfront.
@@ -1640,11 +1692,17 @@ def transform(
16401692
16411693 # Depending on the passes parameter, call the corresponding transform function.
16421694 if passes_seq is not None :
1643- new_programs [name ] = _transform (program , * passes_seq )
1695+ new_programs [name ] = _transform (
1696+ program , * passes_seq , mutation_output_clone_op = clone_op
1697+ )
16441698 elif passes_dict is not None :
1645- new_programs [name ] = _transform (program , * passes_dict [name ])
1699+ new_programs [name ] = _transform (
1700+ program , * passes_dict [name ], mutation_output_clone_op = clone_op
1701+ )
16461702 elif pass_manager is not None :
1647- new_programs [name ] = _transform_with_pass_manager (program , pass_manager )
1703+ new_programs [name ] = _transform_with_pass_manager (
1704+ program , pass_manager , mutation_output_clone_op = clone_op
1705+ )
16481706
16491707 # Verify the correctness of model graph after each transformation.
16501708 EXIREdgeDialectVerifier (edge_compile_config = compile_config )(
0 commit comments