U
    yht(                     @   s  d dl Z d dlZd dlmZ d dlmZ d dlmZmZm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZ eeZeej dd	d
gZeddeedddZeeegef e	e ddddZe	e e	e e	e dddZeddeeeddd	ZeddG dd
 d
ZdS )    N)Queue)wraps)CallableDictList)GraphModule)compatibility)
PassResultpass_result_wrapper this_before_that_pass_constraintPassManagerF)Zis_backward_compatible)fnreturnc                    s:    dkrdS t   fdd}t s6t j|_|S )a+  
    Wrapper for passes which currently do not return a PassResult.
    This wrapper makes them return a PassResult containing the modified object
    and True for the "modified" flag.

    Args:
        fn (Callable[Module, Any])

    Returns:
        wrapped_fn (Callable[Module, PassResult])
    Nc                    sB    | }|d krt | dS t|t r(|S t|tjr>t |dS d S )NT)r	   
isinstancennModule)Zgmresr    T/var/www/html/venv/lib/python3.8/site-packages/torch/fx/passes/infra/pass_manager.py
wrapped_fn"   s    

z'pass_result_wrapper.<locals>.wrapped_fn)r   inspect
isfunctiontype__name__)r   r   r   r   r   r
      s    	
)
constraintpassesr   c                 C   sn   t |D ]`\}}t ||d d  D ]B\}}| ||r8q$td| d| d| d| d| d| dq$qd S )	N   z,pass schedule constraint violated. Expected z before z but found z
 at index z and z	 at indexz in pass list.)	enumerateRuntimeError)r   r   iajbr   r   r   "_validate_pass_schedule_constraint1   s    
(r$   )r   constraintsr   c                    sF  t |dkr| S dd | D }t| d t }| D ]`}| D ]@}||krJq<|D ],}|||sN|| |  |  d7  < qNq< | dkr4|| q4t| d}g }| s| }	||	 d||	< ||	 D ]2}
||
 s҈ |
  d8  <  |
 dkr||
 qqtt	 fdd 
 }t |dkrBd	| }t||S )
z
    Args
        passes: Passes that we are ordering
        constraints: Constraints applied on these passes

    Returns
        A sorted list of callables and a boolean of if a circular dependency
        existed
    r   c                 S   s   i | ]
}|g qS r   r   .0pr   r   r   
<dictcomp>N   s      z,_topological_sort_passes.<locals>.<dictcomp>r   FTc                    s    |  dkS )Nr   r   )r(   Zindegree_mapr   r   <lambda>m       z*_topological_sort_passes.<locals>.<lambda>z:Circular dependency detected within the following passes: )lendictfromkeysr   appendputemptygetlistfilterkeysr   )r   r%   graph
candidatesr!   r#   r   visitedZsorted_passesr(   nZcycle_passeserrorr   r*   r   _topological_sort_passes>   s>    



r<   )thisthatr   c                    s   t t d fdd}|S )a  
    Defines a partial order ('depends on' function) where `this` must occur
    before `that`.

    For example, the following pass list and constraint list would be invalid.
    ```
    passes = [pass_b, pass_a]

    constraints = [
        this_before_that_pass_constraint(pass_a, pass_b)
    ]
    ```

    Args:
        this (Callable): pass which should occur first
        that (Callable): pass which should occur later

    Returns:
        depends_on (Callable[[Object, Object], bool]
    r!   r#   c                    s   |  kr|krdS dS )NFTr   r?   r>   r=   r   r   
depends_on   s    z4this_before_that_pass_constraint.<locals>.depends_on)r   )r=   r>   rA   r   r@   r   r   t   s    c                   @   s   e Zd ZU dZeeejgef  e	d< eeeege
f  e	d< dZe
e	d< dZee	d< de
e
d	d
dZedddZedddZdd Zdd ZeddddZejddddZejedddZdS )r   ad  
    Construct a PassManager.

    Collects passes and constraints. This defines the pass schedule, manages
    pass constraints and pass execution.

    Args:
        passes (Optional[List[Callable]]): List of passes. A pass is a
            callable which modifies an object and returns a PassResult
        constraint (Optional[List[Callable]]): List of constraints. A
            constraint is a callable which takes two passes (A, B) and returns
            True if A depends on B and False otherwise. See implementation of
            `this_before_that_pass_constraint` for example.
        steps (int): Max number of times we run the passes (default = 1).
        run_checks_after_each_pass (bool): Whether to run checks and linting
            after each pass
        suppress_check_failures (bool): Whether to raise errors when running
            checks
    r   r%   F
_validatedr   stepsN)run_checks_after_each_passsuppress_check_failuresc                 C   s.   |pg | _ |pg | _|r|| _|| _|| _d S N)r   r%   rC   rD   rE   )selfr   r%   rC   rD   rE   r   r   r   __init__   s    

zPassManager.__init__)_passc                 C   s   | j | d| _dS )z>
        Adds a pass into the current list of passes.
        FN)r   r0   rB   )rG   rI   r   r   r   add_pass   s    zPassManager.add_pass)r   c                 C   s   | j | d| _dS )zI
        Adds a constraint into the current list of constraints.
        FN)r%   r0   rB   rG   r   r   r   r   add_constraint   s    zPassManager.add_constraintc                 C   s,   | j r
dS | jD ]}t|| j qd| _ dS )z
        Validates that current pass schedule defined by `self.passes` is valid
        according to all constraints in `self.constraints`
        NT)rB   r%   r$   r   rK   r   r   r   validate_constraints   s
    
z PassManager.validate_constraintsc                 C   s   t | j| j| _d| _dS )ab  
        Finds a valid traversal order based on the given constraints and orders
        the passes based on this order.

        If a circular dependency exists between the constraints and steps = 1,
        then we will raise an error because if steps != 1 this means that we
        will re-run the passes, allowing for circular dependencies.
        TN)r<   r   r%   rB   )rG   r   r   r   solve_constraints   s    	zPassManager.solve_constraints)checkr   c                 C   s8   t |}tt|j dkr(tdt| d| dS )z
        Adds a function which takes runs various checks on a given graph module.
        This function is run before and after each pass if the
        `run_checks_after_each_pass` flag is enabled.
        r   zEPassManager check function should only take in one variable, a modulerO   N)r   	signaturer-   r4   
parametersvalues	TypeErrorsetattr)rG   rO   sigr   r   r   
add_checks   s    
zPassManager.add_checks)moduler   c                 C   s   d S rF   r   )rG   rW   r   r   r   rO      s    zPassManager.checkc                 C   sX  | j s|   | | d}t| jD ]$}d}t| jD ]\}}t|rR|j	nt
|j	}td| zv||}t|tst|dstd| dd |j}|p|j}t|trtd||j |  | jr| | W q: tk
r4 }	 z6dd	 | jd
| D }
d| d|
 }t||	W 5 d
}	~	X Y q:X q:|p@|}|s& qNq&t||S )a}  
        Runs a list of passes in the order based on `self.passes` on the given
        graph module. Each time a pass is run, checks and linting will be run on
        the graph module if `run_checks_after_each_pass` is set.

        If the module is a graph module, we will run the list of passes until
        the graph stops changing, or until `steps` number of times.
        FzRunning pass '%s'graph_modulezThe result of the pass z should be type PassResult.z)Please wrap it with pass_result_wrapper()zGraph after pass '%s': %sc                 S   s&   g | ]}t |r|jnt|jqS r   )r   r   r   r   r&   r   r   r   
<listcomp>$  s   z(PassManager.__call__.<locals>.<listcomp>Nz$An error occurred when running the 'z#' pass after the following passes: )rB   rN   rO   rangerC   r   r   r   r   r   r   loggerdebugr   r	   hasattrrS   rX   modifiedr   r7   Z	recompilerD   	Exception)rG   rW   Zoverall_modified_r^   r    r   fn_namer   eZprev_pass_namesmsgr   r   r   __call__   sJ    

 



zPassManager.__call__)NNNFF)r   
__module____qualname____doc__r   r   r   r   r	   __annotations__boolrB   rC   intrH   rJ   rL   rM   rN   rV   rO   rd   r   r   r   r   r      s*   
     )r   loggingqueuer   	functoolsr   typingr   r   r   Ztorch.nnr   Ztorch.fx.graph_moduler   Ztorch.fx._compatibilityr   Ztorch.fx.passes.infra.pass_baser	   	getLoggerr   r[   setLevelWARNING__all__r
   ri   r$   r<   r   r   r   r   r   r   <module>   s2   

  6