
    i}                     p   S SK r S SKrS SKJrJr  S SKJr  S SKJrJ	r	J
r
JrJrJrJrJr  S SKrS SKJr  S SKJr  S SKJr  S SKJr  S S	KJr  S S
KJr  S SKJr  S SKJ r J!r!J"r"  S SK#J$r$  S SK%J&r&  S SK'J(r(  S SK)J*r*  \RV                  RX                  RZ                  R\                  r/\RV                  RX                  R`                  R\                  r1\" SS9S\
\Rd                  RL                     S\
\Rd                  RL                     S\34S j5       r4S\Rd                  Rj                  S\Rd                  Rj                  S\34S jr6S\Rd                  Rj                  SS4S jr7S\Rd                  Rj                  S\*S\Rp                  Rr                  S\\Rd                  RL                  \\Rd                  RL                     \\Rd                  RL                     4   4S jr:S\S\\;   4S  jr<S\S!\;SS4S" jr=S#\Rd                  RL                  S\34S$ jr>S%\Rd                  R~                  S\\Rd                  RL                     4S& jr@S%\Rd                  R~                  S\\Rd                  RL                     4S' jrAS\Rd                  Rj                  SS4S( jrBS\Rd                  Rj                  S\;4S) jrCS*\SS4S+ jrDS*\SS4S, jrES#\Rd                  RL                  S\34S- jrF " S. S/5      rG " S0 S15      rH " S2 S35      rI " S4 S5\(5      rJS\Rd                  Rj                  S\	\;\\;\\   \K4   4   4S6 jrLg)7    N)defaultdictOrderedDict)	lru_cache)AnyDictIterableListOptionalSetTupleUnion)ExportedProgram)duplicate_constant_node)setting_python_recursive_limit)executorch_call_delegate)ops)create_submodule_from_nodes)tabulate)	is_bufferis_lifted_tensor_constantis_param)has_free_symbols)Node)OperatorSupportBase)SourcePartition)maxsize	node_left
node_rightreturnc                 z   [        U [        R                  R                  5      (       a  [        U[        R                  R                  5      (       a  U R                  UR                  :X  a{  U R
                  UR
                  :X  aa  [        U R                  5      [        UR                  5      :X  a5  [        S [        U R                  UR                  5       5       5      (       d  g g[        [        U 5      5      [        [        U5      5      :w  a  g[        X5       H  u  p#[        X#5      (       a  M    g   g)Nc              3   <   #    U  H  u  p[        X5      v   M     g 7fN)is_same_node).0arg_left	arg_rights      \/var/www/html/ai-image-ml/venv/lib/python3.13/site-packages/executorch/exir/backend/utils.py	<genexpr>is_same_node.<locals>.<genexpr>2   s&      ,'H X11,s   FT)
isinstancetorchfxr   targetoplenall_input_nodesallziplistr#   )r   r   n_leftn_rights       r'   r#   r#   &   s     )UXX]]++
:uxx}}0U0U!2!22.Y../3z7Q7Q3RR +.--z/I/I,     tI3tJ'7#88"99OF00  :     
graph_leftgraph_rightc                    [        [        U R                  R                  5      5      [        [        UR                  R                  5      5      :w  a  g[	        S5         [        U R                  R                  UR                  R                  5       H  u  p#[        X#5      (       a  M    S S S 5        g   S S S 5        g! , (       d  f       g= f)NFi0u  T)r/   r3   graphnodesr   r2   r#   )r7   r8   r   r   s       r'   is_identical_graphr<   C   s     4
  &&'(C[5F5F5L5L0M,NN	'	.%(""K$5$5$;$;&
!I !77 
/	.&
 
/  
/	. s   AC +C 5C  
Cgraph_modulec                 p   U R                   R                   H  nUR                  [        :X  ar  UR                  S   R
                  S:X  aS  [        UR                  R                  5       5      nU H(  nUR                  S   4UR                  SS  -   Ul        M*     M  M  UR                  [        :X  d  M  [        UR                  R                  5       5      nUS   R
                  S:X  d  M  US   nUR                  S   /4Ul        M     U R                   R                  5         U R                  5         g )Nr   placeholder   output)r:   r;   r-   T_QuantPerTensorargsr.   r3   userskeysT_DQuantPerTensoreliminate_dead_code	recompile)r=   node
node_usersdequant_nodeoutput_nodes        r'   #remove_first_quant_and_last_dequantrM   U   s     ""((;;**yy|-/!$**//"34
$.L)-1,:K:KAB:O(OL% %/ 0
 [[--djjoo/0J!}8+(m%)YYq\N#4  ) **,r6   	partitionreplacement_opc                    / n/ n/ n/ nUR                    Vs/ s H  owUR                  ;  d  M  UPM     nnUR                    H  nUR                   HP  n	[        U	[        R
                  R                  5      (       d  M.  XR                   ;  d  M?  UR                  U	5        MR     UR                  R                  5        H%  n
XR                   ;  d  M  UR                  U5        M'     M     U H  nUR                  [        :X  d  M  X7/-  nM      U H?  nUR                  R                  5        H  n
U
R                  [        :X  d  M  XJ/-  nM      MA     [        U5      S:  d   S5       e[        U5      S:  d   S5       eX8-   U-   n[        XSSS9u  pU R                  R!                  U5         U R                  R#                  UUR                  UR$                  S9nUR'                  U5        U R                  R)                  U5        UR*                  Ul        SSS5        U R-                  5         WX44$ s  snf ! , (       d  f       N'= f)	a  
Replaces partition with the op specified by replacement_op. It's also expected that
the nodes contained in partition are sourced from a quantized module as this function
searches for the quantization pattern to consume along with the nodes in the partition,
to be then replaced by replacement_op.

Args:
    graph_module: The graph module from which this partition was sourced.
    partition: Partition to be replaced.
    replacement_op: The op to replace paritition with.
Returns:
    Tuple: First element in the tuple is the new replaced module. The second and third
    node lists in the returned tuple consist of the dq and q nodes that were consumed
    along with this partition to be replaced by the replacement_op.
r@   z2Dequant nodes missing in node list to be replaced.z0Quant nodes missing in node list to be replaced.to_be_replacedT)skip_legalize_graph)kwargsN)r;   paramsrC   r*   r+   r,   r   appendrD   rE   r-   rF   rB   r/   r   r:   inserting_beforecall_functionrS   replace_all_uses_with
erase_nodemetarH   )r=   rN   rO   dequant_nodesquant_nodesinput_nodesoutput_nodesrI   partition_nodesarguser	node_list	submodulecall_module_nodereplaced_ops                  r'   #replace_quantized_partition_with_oprf   k   s   * MKKL(1XyGWGW;WtOX
 99C#uxx}}--3oo3M""3'  JJOO%D??*##D) &   ;;++V#M 
 JJOO%D{{..v% & 
 }"X$XX"{q T"TT  /+=I"=!1t#I
 
			,	,-=	>"((66!!#** 7 

 	..{;%%&67+00 
? 44a YJ 
?	>s   H9H90A-H>>
Itagged_exported_programcopied_nodesc                 r   U R                   R                   H  nUR                  S:X  d  M  UR                  U;   d  M'  [	        5       nUR
                   H.  nUR                  UR                  R                  SS5      5        M0     [        U5      S:X  d  M  UR                  5       UR                  S'   M     g)a  
Assign new tag to the copied nodes.

Before the pass
constant_0 (tag_10) ------------------> op_b (tag_10)
constant_0_copy (tag_10) -------------> op_a (tag_11)

After the pass
constant_0 (tag_10) ------------------> op_b (tag_10)
constant_0_copy (tag_11) -------------> op_a (tag_11)

r?   delegation_tagNr@   )r:   r;   r.   namesetrD   addrZ   getr/   pop)rg   rh   rI   	users_tagra   s        r'   _assign_new_tagrq      s      (--3377m#yyL(E	 JJDMM$))--0@$"GH ' y>Q&2;--/DII./ 4r6   tagc                 `   [        5       nU R                  R                   H  nUR                  R	                  SS5      U:X  d  M%  UR
                  S:X  d  M7  UR                   Hz  nUR                  R	                  SS5      nXQ:w  d  M&  UR                  R	                  SS5      (       a  [        SU SU S	U S
U S3	5      eUR                  UR                  5        M|     M     [        5       nU H  nUR                  [        X5      5      nM     UR                  U5      n[        X5        g)a  
If the constants node is shared by different tagged nodes, like
constant_0 ----> op_b (tag_10)
|-------------> op_a (tag_11)

we make default as constant_0 is duplicated to constant_0_1, constant_0_2, unless the node is tagged with "no_copy"
constant_0 ------------------> op_b (tag_10)
constant_0_copy -------------> op_a (tag_11)

backend can estimate how much they want to duplicate the constant node, either error out or default to duplicate
rj    r?   Nno_copyFzconstant data node (z) is tagged with (z) but has user (z) which has tag ())rl   r:   r;   rZ   rn   r.   rD   RuntimeErrorrm   rk   unionr   rq   )	rg   rr   candidate_nodesrI   ra   rp   rh   candidate_nodecandidate_node_with_copiess	            r'   _maybe_duplicate_constant_nodesr|      s!    eO'--3399==)2.#5ww-' JJD $		.> EI '99==E::"."6tf<NseScdhciiz  |E  {F  FG  !H#  ,//		: ' 4 5L)#))#$;L
 *
 "1!6!6|!D+Hr6   rI   c                    U R                   [        R                  :H  =(       ac    [        U R                  5      S:H  =(       aD    U R                  S   R                   [
        :H  =(       a    [        U R                  S   [        5      $ )z
Check if the node is the getitem followed by executorch_call_delegate node. These getitems node
are just for getting the result from delegate because the input/output to delegates are flattened
   r   r@   )r-   operatorgetitemr/   rC   r   r*   intrI   s    r'   '_get_item_from_executorch_call_delegater      se     	x''' 	*		Na	*IIaL#;;	* tyy|S)	r6   r:   c                     U R                    Vs/ s H?  nUR                  S:X  d  M  UR                  [        :w  d  M+  [	        U5      (       a  M=  UPMA     sn$ s  snf )z:
Returns a list of non lowered nodes in the graph module.
rW   )r;   r.   r-   r   r   r:   rI   s     r'   get_non_lowered_nodesr     s\     KKD77o% 	 KK33 	 9>	 	  s   AAAAc                     U R                    Vs/ s H9  nUR                  S:X  d  M  UR                  R                  S5      (       d  M7  UPM;     sn$ s  snf )z/
Returns the list of delegates from the graph.
get_attrlowered_module_)r;   r.   rk   
startswithr   s     r'   get_delegatesr     sQ     KKD77j  	%)YY%9%9:K%L 	  s   AA	Ac                 ,    [        [        U 5      5        g)z#
Print the formatted graph string.
N)printformat_delegated_graph)r=   s    r'   print_delegated_graphr     s     

 
./r6   c                    U R                   R                   Vs0 s HW  nUR                  S:X  d  M  UR                  R	                  S5      (       d  M7  UR                  [        XR                  5      _MY     nnSnSnU R                   R                   H  nXC UR                  5        S3-  nUR                  S:X  d  M,  UR                  R	                  S5      (       d  MN  X!R                     nXCS-   SUR                   S3-  nXCS-   S3-  nUR                  R                   R                   H  nUUS	-   UR                  5        S3-  nM      M     U$ s  snf )
a
  
Return the formatted graph string of including lowered_module (both backend id and original graph) together with the graph module. Example output:
graph():
    %arg0_1 : [num_users=2] = placeholder[target=arg0_1]
    %arg1_1 : [num_users=2] = placeholder[target=arg1_1]
    %arg2_1 : [num_users=2] = placeholder[target=arg2_1]
    %lowered_module_0 : [num_users=1] = get_attr[target=lowered_module_0]
        backend_id: BackendWithCompilerDemo
        lowered graph():
            %arg0_1 : [num_users=1] = placeholder[target=arg0_1]
            %arg1_1 : [num_users=1] = placeholder[target=arg1_1]
            %arg2_1 : [num_users=1] = placeholder[target=arg2_1]
            %aten_mm_default : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.mm.default](args = (%arg0_1, %arg1_1), kwargs = {})
            %aten_add_tensor : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.add.Tensor](args = (%aten_mm_default, %arg2_1), kwargs = {})
            return [aten_add_tensor]
    %executorch_call_delegate : [num_users=1] = call_function[target=torch.ops.higher_order.executorch_call_delegate](args = (%lowered_module_0, %arg0_1, %arg1_1, %arg2_1), kwargs = {})
    %getitem : [num_users=1] = call_function[target=operator.getitem](args = (%executorch_call_delegate, 0), kwargs = {})
    %aten_sub_tensor : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.sub.Tensor](args = (%getitem, %arg0_1), kwargs = {})
    %lowered_module_1 : [num_users=1] = get_attr[target=lowered_module_1]
        backend_id: BackendWithCompilerDemo
        lowered graph():
            %aten_sub_tensor : [num_users=1] = placeholder[target=aten_sub_tensor]
            %arg1_1 : [num_users=1] = placeholder[target=arg1_1]
            %arg2_1 : [num_users=1] = placeholder[target=arg2_1]
            %aten_mm_default_1 : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.mm.default](args = (%aten_sub_tensor, %arg1_1), kwargs = {})
            %aten_add_tensor_1 : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.add.Tensor](args = (%aten_mm_default_1, %arg2_1), kwargs = {})
            return [aten_add_tensor_1]
    %executorch_call_delegate_1 : [num_users=1] = call_function[target=torch.ops.higher_order.executorch_call_delegate](args = (%lowered_module_1, %aten_sub_tensor, %arg1_1, %arg2_1), kwargs = {})
    %getitem_1 : [num_users=1] = call_function[target=operator.getitem](args = (%executorch_call_delegate_1, 0), kwargs = {})
    return [getitem_1]
r   r   z  z	graph():

r~   zbackend_id: zlowered graph():
   )	r:   r;   r.   rk   r   getattrformat_node
backend_idoriginal_module)r=   rI   lowered_module_dictindentgraph_format_strlowered_modulenode_in_lowered_modules          r'   r   r   &  sa   D !&&,,,D77j  	4%)YY%9%9:K%L 	4		7<33,  
 F#""((ht'7'7'9&:"==77j TYY%9%9:K%L%L0;NA:,l>;T;T:UUW XXA:,.@ AA*8*H*H*N*N*T*T& zl#9#E#E#G"HK  +U ) #s   EE$Eedge_programc                    [        5       nU R                  R                   H  nUR                  S:X  d  M  [	        X5      (       d"  [        X5      (       d  [        X5      (       d  MG  UR                   HP  nUR                  U R                  R                  ;   d  M)  [        R                  " S5        UR                  U5        MR     M     U R                  R                   H  nUR                  S:X  d  M  [	        X5      (       d"  [        X5      (       d  [        X5      (       d  MG  X!;  d  MN  [        5       nUR                   H5  nUR                  R                  SS5      nUc  M$  UR                  U5        M7     [!        U5      S:  a  [        R                  " SU S35        [!        U5      S:  d  M  UR#                  5       UR                  S'   M     g)	a  
Util function for partitioners. This function tags the const/param/buffers nodes
whose users all belong within the same partition. This should be called after tagging all other nodes.
Any const/param/buffer which is used as input to a subgraph, will be tagged with the same tag as that
subgraph. Throw error when const/param/buffers is used across different partitions. That is the
underlying data will be owned by multiple delegates.
r?   z@The buffer node is a mutated buffer node, which is not constant.rj   Nr@   <The data node is used across multiple partitions, including . If the data is too large and it's not preferred to copy, please tag the constant node like node.['no_copy'] = True and they won't be copied.r   )rl   r:   r;   r.   r   r   r   rD   rk   graph_signaturebuffers_to_mutatelogginginform   rZ   rn   r/   ro   )r   mutated_bufferrI   	node_user	user_tagsra   user_tags          r'   tag_constant_datar   Z  sm    UN""((77m#\((,,(<<!ZZ	>>\%A%A%S%SSLLZ #&&t, ( ) ""((77m#\((,,(<<)E	 JJD#yy}}-=tDH+!h/ ' y>A%LLVW`Va b_ _ y>A%2;--/DII./+ )r6   c                 Z   U R                   R                   GH  nSnUR                  S:X  aK  [        X5      (       a;  UR                   H+  nUR
                  U R                  R                  ;   d  M)  Sn  O   U(       d  Mj  [        5       nUR                   H5  nUR                  R                  SS5      nUc  M$  UR                  U5        M7     [        U5      S:  a  [        R                  " SU S35        [        U5      S	:  d  M  UR                  5       UR                  S'   GM     g)
a  
Util function for partitioners. This function tags the mutated buffer nodes
whose users all belong within the same partition. This should be called after tagging all other nodes.
Any buffer which is used as input to a subgraph, will be tagged with the same tag as that
subgraph. Throw error when buffers is used across different partitions. That is the
underlying data will be owned by multiple delegates.
Fr?   Trj   Nr@   r   r   r   )r:   r;   r.   r   rD   rk   r   r   rl   rZ   rn   rm   r/   r   r   ro   )r   rI   is_mutated_buffer_noder   r   ra   r   s          r'   tag_mutated_bufferr     s     ""((!&77m#	,(E(E!ZZ	>>\%A%A%S%SS-1* (
 "!I

99==)94@'MM(+ # 9~!RS\R] ^[ [ 9~!.7mmo		*+/ )r6   c                 F    [        U R                  S   R                  5      $ )z%
Check if the node shape is dynamic.
val)r   rZ   shaper   s    r'   is_shape_dynamicr     s    
 DIIe,2233r6   c                       \ rS rSrSrSS\4S jjrS\\\	\
\	   4   \\\
\	   4   4   4S jr   SS\\\\\   4      S	\\\	\\\	      4      S
\\\	\4      S\\	\4   4S jjrSrg)DelegateMappingBuilderi  aK  
Profiling helper class for building Delegate Mappings.
Delegate Mappings are mappings from delegate debug identifiers to node
debug handles. Specifically this is used to log within backend delegates

Args:
    generated_identifiers (bool, optional): Whether identifier keys are
        generated automatically. Defaults to False.
generated_identifiersc                 F    Xl         [        [        5      U l        SU l        g )Nr   )_generated_identifiersr   rl   _debug_handle_map_next_index)selfr   s     r'   __init__DelegateMappingBuilder.__init__  s$    &;#
  	 !"r6   r   c           
          U R                   R                  5        VVs0 s H  u  pU[        [        U5      5      _M     snn$ s  snnf )a  
Returns:
   Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]:
        A map of delegate debug identifier to a list of debug handles
        The keys (identifier) are either integers or strings
        The values are a sorted tuple of integer debug handles
)r   itemstuplesorted)r   kvs      r'   get_delegate_mapping+DelegateMappingBuilder.get_delegate_mapping  s=     150F0F0L0L0NO0N5##0NOOOs   !ANr;   handles
identifierc                    U R                   (       a  Ub  [        SU S35      eUb  X0R                  ;   a  [        S5      eUSLUSL-  (       d  [        S5      eUc>  U R                   (       a"  U R                  nU =R                  S-  sl        O[        S5      eUbD  [	        U[
        5      (       a  UOU/ Vs1 s H  nUR                  R                  S5      iM      nnO [	        U[        [
        45      (       a  UOU/nU Vs1 s H	  ofc  M  UiM     nn[        U5      S	:X  a  [        S
5      eXpR                  U'   U$ s  snf s  snf )a  
Add a new delegate mapping entry

If self._generated_identifiers = False:
    - A new identifier must be provided, else an exception is thrown

If self._generated_identifiers = True:
    - New identifiers are generated incrementally, 0 indexed
    - Identifiers cannot be manually provided, else an exception is thrown

Args:
    nodes (Union[Node, List[Node]]): A (list of) Node(s)
    handles (Union[int, List[Optional[int]]]): A (list of) debug handle(s)
    identifier (Optional[Union[int, str]]):
        Debug identifier corresponding to the Node(s)

Note: Exactly one of nodes and handles must be provided
Note: If a debug handle is missing or None, it is skipped

Returns:
    Union[int, str]:
        Delegate debug identifier inserted
NzEBuilders using generated identifiers can't manually add identifiers: z. Failed to add or update entryzjThis delegate debug identifier was already inserted. Duplicate delegate debug identifiers are not allowed.zOnly one of nodes or handles must be provided. Either both were provided or neither were provided. Failed to add or update entry.r@   z6No identifier provided. Failed to add or update entry.debug_handler   z2No valid debug handles found. Failed to add entry.)
r   	Exceptionr   r   r*   r	   rZ   rn   r   r/   )r   r;   r   r   rI   new_debug_handleshandlefiltered_debug_handless           r'   insert_delegate_mapping_entry4DelegateMappingBuilder.insert_delegate_mapping_entry  s   > &&:+AWXbWc  dC  D  !j4J4J&J| 
 d"wd':; T 
 **!--
  A% L 
  '1&=&=UE7J!JD 		n-J  ! &gt}==G9  "3"
!2vF!2 	 "
 %&!+PQQ .Dz*%!"
s   :%EEE)r   r   r   )F)NNN)__name__
__module____qualname____firstlineno____doc__boolr   r   r   r   r   strr   r
   r   r	   r   __static_attributes__ r6   r'   r   r     s    "d "P	tCsO$d3c
?&;;	<P 48=A04	MdDJ./0M %T(3-%8 89:M U38_-	M
 
sCxM Mr6   r   c                       \ rS rSrSrS\R                  4S jrS\R                  R                  S\SS4S	 jrS\4S
 jrSrg)WhyNoPartitioni%  aW  
Simple helper class for partitioners to log why a node was not lowered.

Example usage:

    # In your backend partitioner file(s)
    why = WhyNoPartition(logger=your_backend_logger)

    # hypothetical function that checks if a node can be lowered
    if not can_be_lowered(node):
        why(node, "This node was not lowered because ...")
loggerc                 ,    Xl         S U l        SU l        g )Nrt   r   rI   reason)r   r   s     r'   r   WhyNoPartition.__init__3  s    -1	r6   rI   r   r   Nc                 R    Xl         X l        U R                  R                  U 5        g r"   )rI   r   r   debugr   rI   r   s      r'   __call__WhyNoPartition.__call__8  s    	$r6   c                 <    SU R                    SU R                   S3$ )NzWhyNoPartition: Node z was not partitioned because .)rI   r   r   s    r'   __str__WhyNoPartition.__str__=  s!    &tyyk1Nt{{m[\]]r6   r   )r   r   r   r   r   r   Loggerr   r+   r,   r   r   r   r   r   r   r6   r'   r   r   %  sG    w~~ 
 UXX]]  C  D  
^ ^r6   r   c                   |    \ rS rSrSrS rS\R                  R                  S\	4S jr
S\	4S jrS	\S
\	S\4S jrSrg)WhyNoPartitionReporteriA  a  
Helper class for partitioners to gather why nodes were not lowered in a single report.
If a node is reported multiple times, only the first report is included.

Example usage:

    # In your backend partitioner file(s)
    reporter = WhyNoPartitionReporter()

    # hypothetical function that checks if a node can be lowered
    if not can_be_lowered(node):
        reporter.report_reject(node, "This node was not lowered because ...")

    # Back in partitioner
    logger.info(reporter.get_table_report())
c                 "    [        5       U l        g r"   )r   _rejected_nodesr   s    r'   r   WhyNoPartitionReporter.__init__S  s    M 	r6   rI   r   c                 @    XR                   ;  a  X R                   U'   gg)zNReport a node that was rejected from a partition, along with a reason for why.Nr   r   s      r'   report_reject$WhyNoPartitionReporter.report_rejectX  s!    +++)/  & ,r6   r   c                    / nU R                    H  nUR                  S:X  d  UR                  S:X  a  M%  [        UR                  SS5      =n(       d  UR                  nUR                  R                  SS5      nUR                  UR                  X4U R                   U   /5        M     [        U5      S:  a  [        U/ SQS	S
S9$ g)u  Returns a string containing a table listing all rejected nodes.
The table looks something like this:
╒══════════════════════════╤══════════════════════════╤═════════════════════════════════════╤═════════════════════════════════════╕
│ Node name                │ Target                   │ Torch func                          │ Reason                              │
╞══════════════════════════╪══════════════════════════╪═════════════════════════════════════╪═════════════════════════════════════╡
│ aten_convolution_default │ aten.convolution.default │ ('conv2d_1', 'builtin_function_or_m │ Convolution needs to have           │
│                          │                          │ ethod.conv2d')                      │ kernel_y<=64,                       │
│                          │                          │                                     │ kernel_x*kernel_y<=4096, got kernel │
│                          │                          │                                     │ (2, 65)                             │
╘══════════════════════════╧══════════════════════════╧═════════════════════════════════════╧═════════════════════════════════════╛
r?   rA   _opNtorch_fn-r   )z	Node nameTargetz
Torch funcReason
fancy_grid#   )tablefmtmaxcolwidthszNo nodes rejected.)
r   r.   r   r-   rZ   rn   rU   rk   r/   r   )r   reject_reportrI   r-   r   s        r'   get_table_report'WhyNoPartitionReporter.get_table_report]  s     ((Dww-'477h+>%dkk5$??F?yy}}Z5H  Fd.B.B4.HI ) }!?%	  (r6   operator_supportmessagec                     [        XU5      $ )zHWrap the operator_support, reporting rejects with the specified message.)ReportRejected)r   r   r   s      r'   
wrap_check!WhyNoPartitionReporter.wrap_check}  s     .g>>r6   r   N)r   r   r   r   r   r   r+   r,   r   r   r   r   r   r  r   r   r6   r'   r   r   A  sQ    "

0%((-- 0 0
(# (@? 3?>A?	?r6   r   c                   d    \ rS rSrSrS\S\4S jrS\R                  R                  S\4S jrS	rg
)r   i  zeClass for wrapping a OperatorSupportBase, reporting rejects with the specified message to `reporter`.r   reporterc                 (    Xl         X l        X0l        g r"   )r   r  r   )r   r   r  r   s       r'   r   ReportRejected.__init__  s     !1 r6   rI   r   c                     U R                   R                  X5      nU(       d%  U R                  R                  X R                  5        U$ r"   )r   is_node_supportedr  r   r   )r   
submodulesrI   is_supporteds       r'   r   ReportRejected.is_node_supported  s7    ,,>>zPMM''ll;r6   )r   r   r  N)r   r   r   r   r   r   r   r   r+   r,   r   r   r  r   r   r6   r'   r   r     s7    o- )%((-- D r6   r   c                 p   SSK Jn  0 nU R                  R                   H  nUR                  S:X  d  M  UR
                  R                  S5      (       d  M7  [        XR
                  S5      nUc  MR  [        XA5      (       d  Md  UR                  UR                  UR                  4X#R
                  '   M     U$ )a  
Extracts the payload for delegates from a graph module that has been lowered
to one or more backends.

This function iterates through all lowered modules (delegates) in the graph
and returns a dictionary mapping each delegate's name to a tuple containing:
- backend_id: The name/identifier of the backend
- compile_specs: A list of backend-specific compilation specifications
- processed_bytes: The delegate blob created by the backend's preprocess method

Args:
    graph_module: A torch.fx.GraphModule that may contain lowered backend modules.
        This is typically obtained from an EdgeProgramManager or ExecutorchProgram
        via `.exported_program().graph_module`.

Returns:
    Dict[str, Tuple[str, List[Any], bytes]]: A dictionary where:
        - Keys are the delegate names (e.g., "lowered_module_0", "lowered_module_1")
        - Values are tuples of (backend_id, compile_specs, processed_bytes)

Example:
    >>> edge = to_edge(export(model, inputs))
    >>> edge = edge.to_backend(MyPartitioner())
    >>> payloads = get_delegated_payload(edge.exported_program().graph_module)
    >>> for name, (backend_id, specs, data) in payloads.items():
    ...     print(f"{name}: backend={backend_id}, data_size={len(data)}")
r   )LoweredBackendModuler   r   N)&executorch.exir.lowered_backend_moduler  r:   r;   r.   rk   r   r   r*   r   compile_specsprocessed_bytes)r=   r  delegate_payloadsrI   r   s        r'   get_delegated_payloadr    s    < LAC ""((77j TYY%9%9:K%L%L$\99dCN)j/ / #--"00"220!)), ) r6   )Mr   r   collectionsr   r   	functoolsr   typingr   r   r   r	   r
   r   r   r   r+   'executorch.exir.backend.backend_detailsr   Kexecutorch.exir.backend.canonical_partitioners.duplicate_constant_node_passr   executorch.exir.commonr   executorch.exir.delegater   executorch.exir.dialects._opsr   exir_opsr  r   r   torch._export.utilsr   r   r   %torch.fx.experimental.symbolic_shapesr   torch.fx.noder    torch.fx.passes.operator_supportr   *torch.fx.passes.utils.source_matcher_utilsr   edgequantized_decomposedquantize_per_tensordefaultrB   dequantize_per_tensorrF   r,   r   r#   GraphModuler<   rM   _opsOpOverloadPacketrf   r   rq   r|   r   Graphr   r   r   r   r   r   r   r   r   r   r   bytesr  r   r6   r'   <module>r+     s)     0  I I I  C B = 9 N  N N B  @ F==55IIQQ MM66LLTT  4&' 
 8$$38883G3G	$((&&	,J5((&&J5J5 JJ//J5 588==$uxx}}-tEHHMM/BBC	J5ZB,Bc(B6$I,$I	$I 
$IN
%((-- 
D 

 
D4G 
 D,? 0(<(< 0 01)=)= 1# 1h+BO +B +B\>_ > >D4588== 4T 4o od^ ^8@? @?F( (/((&&/	#uS$s)U*+
+,/r6   