U
    d%                     @   s<  d dl mZmZmZmZmZmZmZ d dlm	Z	 d dl
Z
d dlZ
d dlmZ d dlmZ eee
j ee
j f Zee
jef Zee
jj Zee
jj Zee ZdddhZed	d
dd Zed	d
eee
jjf e
jjedddZed	d
e
jjedddZed	d
G dd dZ ed	d
e
jj!dddZ"dS )    )ListTupleUnionDictAnySetMapping)	dataclassN)_get_qualified_name)compatibilitycall_modulecall_functionZcall_methodF)Zis_backward_compatiblec                 C   sL   t | tr| S | jr*d| jkr*d| j S | j}|r8|nd d| j S d S )Nacc_opsacc_ops. .)
isinstancestr
__module____name__)kmodule r   @/tmp/pip-unpacked-wheel-ua33x9lu/torch/fx/passes/tools_common.pyget_acc_ops_name   s    
r   )
submodulesnodereturnc                 C   s   |j tks(tddt d|j   |j dkrdt|jtsBt| |j }t|dt|}t	|S |j dkr|j}|j
dk	rd|j
krd	|j S t|S t|jtst|jS dS )
a,  
    Given a `node` returns its target typename.

    For "call_method" node, return node.target which is the name of that method being called.
    This could potential lead to conflict but should be okay because normally it's on a tensor.

    For "call_function" node, return typename of node.target.

    For "call_module" node, return typename of the module that node.target point to.

    If seeing "_VariableFunctionsClass" in the target name string, it will be replaced by
    "torch". e.g. _VariableFunctionsClass.relu would become torch.relu.
    zExpect op types of z, z, but found r   Z_base_class_originr   Nr   r   )opCALLABLE_NODE_OPSAssertionErrorjoinr   targetr   getattrtyper   r   r   r
   )r   r   ZsubmodZsubmod_typer"   r   r   r   get_node_target   s$    


r%   )r   r   c                 C   s"   | j dd}|dk	o t|tjS )a  Checks if the node output produces a Tensor or not.

    NOTE: This requires to run `ShapeProp` on the containing fx graph before
    calling this function. This is because it works by checking the `type`
    metadata on the node. This metadata is produced by the `ShapeProp`.
    r$   N)metaget
issubclasstorchTensor)r   type_r   r   r   is_node_output_tensorA   s    r,   c                   @   sh   e Zd ZdZejjedddZe	G dd dZ
deeef dd	d
Zeejjef dddZdS )FxNetAccFusionsFinderz
    Finds groups of connected ACC nodes that pass non-tensor data between each other.
    Such groups are called fusion groups.
    )r   	acc_nodesc                 C   s   || _ t|jj| _|| _d S N)r   listgraphnodesr.   )selfr   r.   r   r   r   __init__S   s    zFxNetAccFusionsFinder.__init__c                   @   s6   e Zd ZU eed< eed< eed< eed< dd ZdS )!FxNetAccFusionsFinder.FusionGrouptop_node_idxr2   inputsnodes_need_processc                    sR   | j krdS  j|  j |  j|  j fdd|jD  dS )z5
            Add a node to fusion group.
            Nc                    s$   h | ]}|j tkr| jkr|qS r   )r   r   r2   ).0nr3   r   r   	<setcomp>q   s   
 
z=FxNetAccFusionsFinder.FusionGroup.add_node.<locals>.<setcomp>)r2   r8   addr7   discardupdateall_input_nodes)r3   r   r   r;   r   add_nodef   s    

z*FxNetAccFusionsFinder.FusionGroup.add_nodeN)r   r   __qualname__int__annotations__NodeSetrA   r   r   r   r   FusionGroupX   s
   
rF   r5   )fusion_groupr7   c                 C   s\   |D ]R}|j tkrq| j||jk r(q||jkr8 dS | ||jr||  dS qdS )z
        Start from inputs and going reverse topological order. If any upstream node
        is in the fusion group, add all the nodes in this path to fusion group.
        TF)r   r   r2   indexr6   recursive_add_noder@   rA   )r3   rG   r7   argr   r   r   rI   x   s    	


z(FxNetAccFusionsFinder.recursive_add_node)r   c                 C   sr  i }t | j}|D ]X}||kr"q|jtkr.qd|jkr:q|| jkrFq| j| j||ht|j	|hd}|j
r0|j
 }| ||j d|jkr|jD ]4}|jtkrq||jkrq|| | ||j q|j	D ]V}|jtkrqd|jkrq||jkrq|| t|j| j||_| ||j qqjt|j| jksT|  j|j8  _q|jD ]}|j||< qZq|S )NZtensor_meta)r6   r2   r7   r8   )r0   r.   r   r   r&   rF   r2   rH   setr@   r8   poprI   r7   ZusersrA   minr6   )r3   resultr.   r   rG   userrJ   r:   r   r   r   __call__   s\    
















 

zFxNetAccFusionsFinder.__call__N)r   r   rB   __doc__r)   fxGraphModulerE   r4   r	   rF   r   NodeListrI   r   NoderP   r   r   r   r   r-   L   s   !
r-   )gmc           	         s   dd | j jD }tj }i  | D ]$\}}|s(|| fdd |< q(  D ]
}||= qV|rg }| D ]H\}}d}|D ]}| krd}q|rr|| fdd |< || qr|D ]
}||= qqb|| _ dS )	a  
    Replace the graph of the given GraphModule with one that contains the same nodes as the
    original, but in topologically sorted order.

    This is used by the merge_matmul transformation below, which disturbs the topologically sorted
    order of its input GraphModule, so that this order is restored before further transformation.

    Arguments:
        gm: The graph module to topologically sort. It is modified in-place.

    c                 S   s   i | ]}||j  qS r   )r@   copy)r9   r   r   r   r   
<dictcomp>   s      z"legalize_graph.<locals>.<dictcomp>c                    s    |  S r/   r   r:   Zvalue_remapr   r   <lambda>       z legalize_graph.<locals>.<lambda>TFc                    s    |  S r/   r   rY   rZ   r   r   r[      r\   N)	r1   r2   r)   rR   ZGraphitemsZ	node_copykeysappend)	rV   ZdependenciesZ	new_graphr   depsZcopied_nodeZcopied_this_roundZall_deps_copieddepr   rZ   r   legalize_graph   s*    

rb   )#typingr   r   r   r   r   r   r   Zdataclassesr	   r)   Ztorch.fxZtorch.fx.noder
   Ztorch.fx._compatibilityr   r*   ZTensorsZTensorOrTensorsrR   rU   rT   rE   r   ZNamesr   r   nnModuler%   boolr,   r-   rS   rb   r   r   r   r   <module>   s,   $


$#
 