o
    1&iB                     @   sL  d Z ddlZddlZddlZddlmZ ddlm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mZ dd	lmZ eeZd
d ZG dd dZdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Z dd Z!d d! Z"d"d# Z#G d$d% d%Z$G d&d' d'e$Z%G d(d) d)Z&G d*d+ d+e$Z'G d,d- d-e$Z(d.d/ Z)dS )0a  
Implement Dominance-Fronter-based SSA by Choi et al described in Inria SSA book

References:

- Static Single Assignment Book by Inria
  http://ssabook.gforge.inria.fr/latest/book.pdf
- Choi et al. Incremental computation of static single assignment form.
    N)reduce)copy)defaultdict)config)irir_utilserrors)
OrderedSet_lazy_pformat)compute_cfg_from_blocksc                 C   s   t | j| _| S )znApply SSA reconstruction algorithm on the given IR.

    Produces minimal SSA using Choi et al algorithm.
    )_run_ssablocks)Zfunc_ir r   9C:\wamp64\www\opt\env\Lib\site-packages\numba/core/ssa.pyreconstruct_ssa   s   r   c                   @   s   e Zd Zdd Zdd ZdS )_CacheListVarsc                 C   s
   i | _ d S N)_savedselfr   r   r   __init__%      
z_CacheListVars.__init__c                 C   s*   | j |}|d u r|  | j |< }|S r   )r   get	list_vars)r   instgotr   r   r   r   (   s   z_CacheListVars.getN)__name__
__module____qualname__r   r   r   r   r   r   r   $   s    r   c                 C   s   | si S t | }t|}t| |}t }|D ] }td| t| |\} }tdt| t| |||||} qt | }||krDt	
d| S )z7Run SSA reconstruction on IR blocks of a function.
    zFix SSA violator on var %szReplaced assignments: %szCFG mutated in SSA pass)r   _iterated_domfronts_find_defs_violatorsr   _loggerdebug_fresh_varsr
   _fix_ssa_varsr   ZCompilerError)r   cfgdf_plus	violatorscache_list_varsvarnamedefmapZcfg_postr   r   r   r   /   s&   

r   c                 C   sx   t | }||d< ||d< tt |d< }||d< t|||d< t| |t|}| D ]\}	}
||	 }|
|j |_q+|S )z=Rewrite all uses to ``varname`` given the definition map
    r)   r*   phimapr%   phi_locations)_make_statesr   list_compute_phi_locations_run_block_rewrite_FixSSAVarsitemsbody)r   r)   r*   r%   r&   r(   statesr+   	newblockslabelZphilistZcurblkr   r   r   r$   S   s   r$   c                    sp   dd |    D  d}|r6d}  D ]\}}ttj fdd|D t }||r3||O }d}q|s S )zCompute the iterated dominance frontiers (DF+ in literatures).

    Returns a dictionary which maps block label to the set of labels of its
    iterated dominance frontiers.
    c                 S   s   i | ]	\}}|t |qS r   )set.0kvsr   r   r   
<dictcomp>k   s    z'_iterated_domfronts.<locals>.<dictcomp>TFc                    s   g | ]} | qS r   r   )r9   vZ	domfrontsr   r   
<listcomp>p       z'_iterated_domfronts.<locals>.<listcomp>)Zdominance_frontierr2   r   operatoror_r7   
difference)r%   Z
keep_goingr:   r;   innerr   r>   r   r   e   s   
r   c                 C   s,   t  }| D ]\}}|r|| | O }q|S r   )r7   r2   )Ziterated_dfr*   r,   ZdeflabelZdefstmtsr   r   r   r/   w   s   r/   c                 C   s6   t | }||d< tt |d< }t| |t }||fS )z(Rewrite to put fresh variable names
    r)   r*   )r-   r   r.   r0   _FreshVarHandler)r   r)   r4   r*   r5   r   r   r   r#      s
   r#   c                 C   s   |   ^}}|jS r   )valuesscope)r   first_r   r   r   
_get_scope   s   rJ   c                 C   s   t t}t t}t||d}t| |t  tdt| t	dd |
 D }| }|
 D ]&\}}||vrV|D ]}	||	 }
dd || D }||
sU||  nq:q0tdt| |S )zm
    Returns
    -------
    res : Set[str]
        The SSA violators in a dictionary of variable names.
    )defsuseszdefs %sc                 S   s    g | ]\}}t |d kr|qS )   )lenr8   r   r   r   r?      s     z(_find_defs_violators.<locals>.<listcomp>c                 S   s   h | ]\}}|qS r   r   )r9   Z_assignr6   r   r   r   	<setcomp>   r@   z'_find_defs_violators.<locals>.<setcomp>zSSA violators %s)r   r.   r7   dict_run_block_analysis_GatherDefsHandlerr!   r"   r
   r	   r2   Z
dominatorsintersectionadd)r   r%   rK   rL   r4   r'   Zdomsr:   Z
use_blocksr6   domZ
def_labelsr   r   r   r       s&   

r    c                 C   s<   |   D ]\}}td| ||d< t|||D ]}qqd S )Nz"==== SSA block analysis pass on %sr6   )r2   r!   r"   _run_ssa_block_pass)r   r4   handlerr6   blkrI   r   r   r   rQ      s   rQ   c           	      C   s   i }|   D ]8\}}td| tj|j|jd}g }||d< ||d< t|||D ]}|d us1J || q)||_	|||< q|S )Nz!==== SSA block rewrite pass on %s)rG   locr6   block)
r2   r!   r"   r   ZBlockrG   rY   rV   appendr3   )	r   r4   rW   r5   r6   rX   ZnewblkZnewbodystmtr   r   r   r0      s   
r0   c                 C   s   t t| dS )N)rG   )rP   rJ   )r   r   r   r   r-      s   r-   c                 c   sr    t d| |jD ],}t d| t|tjr|| |}n|| |}||ur3|d ur3t d| |V  q
d S )Nz
Running %szon stmt: %szreplaced with: %s)r!   r"   r3   
isinstancer   Assign	on_assignon_other)r4   rX   rW   r\   retr   r   r   rV      s   
rV   c                   @       e Zd ZdZdd Zdd ZdS )_BaseHandlerzGA base handler for all the passes used here for the SSA algorithm.
    c                 C      dS )a  
        Called when the pass sees an ``ir.Assign``.

        Subclasses should override this for custom behavior

        Parameters
        -----------
        states : dict
        assign : numba.ir.Assign

        Returns
        -------
        stmt : numba.ir.Assign or None
            For rewrite passes, the return value is used as the replacement
            for the given statement.
        Nr   )r   r4   assignr   r   r   r_          z_BaseHandler.on_assignc                 C   rd   )a  
        Called when the pass sees an ``ir.Stmt`` that's not an assignment.

        Subclasses should override this for custom behavior

        Parameters
        -----------
        states : dict
        assign : numba.ir.Stmt

        Returns
        -------
        stmt : numba.ir.Stmt or None
            For rewrite passes, the return value is used as the replacement
            for the given statement.
        Nr   r   r4   r\   r   r   r   r`      rf   z_BaseHandler.on_otherNr   r   r   __doc__r_   r`   r   r   r   r   rc      s    rc   c                   @   rb   )rR   aZ  Find all defs and uses of variable in each block

    ``states["label"]`` is a int; label of the current block
    ``states["defs"]`` is a Mapping[str, List[Tuple[ir.Assign, int]]]:
        - a mapping of the name of the assignee variable to the assignment
          IR node and the block label.
    ``states["uses"]`` is a Mapping[Set[int]]
    c                 C   sX   |d |j j ||d f | D ]}|j}||j jkr)|d | |d  qd S )NrK   r6   rL   )targetnamer[   r   rT   )r   r4   re   varr:   r   r   r   r_     s   z_GatherDefsHandler.on_assignc                 C   s.   |  D ]}|j}|d | |d  qd S )NrL   r6   )r   rk   rT   )r   r4   r\   rl   r:   r   r   r   r`     s   z_GatherDefsHandler.on_otherNrh   r   r   r   r   rR     s    	rR   c                   @   s   e Zd Zdd ZejZdS )UndefinedVariablec                 C   s   t d)NzNot intended for instantiation)NotImplementedErrorr   r   r   r   r     s   zUndefinedVariable.__init__N)r   r   r   r   r   	UNDEFINEDrj   r   r   r   r   rm     s    
rm   c                   @   rb   )rE   z9Replaces assignment target with new fresh variables.
    c                 C   s   |j j|d krU|d }|d }t|dkr8|j }td| |j|jvr7d|jd}ttj	||j
d n
|j|j j|j
d}tj||j|j
d	}||d
  | |S )Nr)   rG   r*   r   zfirst assign: %sz	variable z is not in scope.rY   rj   valuerY   r6   )rj   rk   rN   r!   r"   Z	localvarswarningswarnr   ZNumbaIRAssumptionWarningrY   redefiner   r^   rr   r[   )r   r4   re   rG   r*   Z	newtargetZwmsgr   r   r   r_   &  s(   
z_FreshVarHandler.on_assignc                 C   s   |S r   r   rg   r   r   r   r`   <  s   z_FreshVarHandler.on_otherNrh   r   r   r   r   rE   #  s    rE   c                   @   sR   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dddZdS )r1   aF  Replace variable uses in IR nodes to the correct reaching variable
    and introduce Phi nodes if necessary. This class contains the core of
    the SSA reconstruction algorithm.

    See Ch 5 of the Inria SSA book for reference. The method names used here
    are similar to the names used in the pseudocode in the book.
    c                 C   s
   || _ d S r   )_cache_list_vars)r   r(   r   r   r   r   I  r   z_FixSSAVars.__init__c                 C   s   |j }t|tjrD| ||| j|j }|d urB|jtjurB|d |jj	krB|d |ji}t
|}t|| tj|j||jdS |S t|tjro| |||g}|d uro|jtjuro|d |jj	krotj|j|j|jdS |S )Nr)   rq   )rr   r]   r   ZInst_fix_varrv   r   rj   ro   rk   r   r   Zreplace_vars_innerr^   rY   ZVar)r   r4   re   rhsnewdefreplmapr   r   r   r_   L  s4   z_FixSSAVars.on_assignc                 C   s`   |  ||| j|}|d ur.|jtjur.|d |jjkr.|d |ji}t|}t	|| |S )Nr)   )
rw   rv   r   rj   r   ro   rk   r   r   Zreplace_vars_stmt)r   r4   r\   ry   rz   r   r   r   r`   k  s   z_FixSSAVars.on_otherc                 C   s.   dd |D }|d }||v r|  ||S dS )z0Fix all variable uses in ``used_vars``.
        c                 S   s   g | ]}|j qS r   )rk   )r9   r:   r   r   r   r?   y  s    z(_FixSSAVars._fix_var.<locals>.<listcomp>r)   N)	_find_def)r   r4   r\   Z	used_varsvarnamesZphivarr   r   r   rw   v  s
   z_FixSSAVars._fix_varc                 C   s   t d|d | d}|d }|d | }|d | }|d }| ||}t|D ]}	| j|	||d}
|
|k r;|	} n|	|v rE|d	 } nq)|du rS| j|||jd
}|S )z?Find definition of ``stmt`` for the statement ``stmt``
        zfind_def var=%r stmt=%sr)   Nr6   r*   r+   rZ   )stoprp   )r!   r"   _stmt_indexreversed_find_def_from_toprY   )r   r4   r\   Zselected_defr6   Z
local_defsZ
local_phisrZ   Zcur_posdefstmtZdef_posr   r   r   r{   ~  s*   z_FixSSAVars._find_defc                 C   s4  t d| |d }|d }|d }|d }||v rx|d }|d j}|j|d |d	}	tj|	tjj|d	|d
}
t d|
| || d|
 || 	|
 |
|D ]!\}}| j|||d	}t d| |
jj	|j |
jj	| qT|
S | | }||krt|d | tS t d|| | j|||d	S )zFind definition reaching block of ``label``.

        This method would look at all dominance frontiers.
        Insert phi node if necessary.
        zfind_def_from_top label %rr%   r*   r+   r,   rG   rZ   r)   rp   rq   zinsert phi node %s at %sr   zincoming_def %szidom %s from label %s)r!   r"   rY   ru   r   r^   Exprphiinsertr[   Zpredecessors_find_def_from_bottomrr   Zincoming_valuesrj   Zincoming_blocksZimmediate_dominators"_warn_about_uninitialized_variablerm   )r   r4   r6   rY   r%   r*   r+   r,   rG   ZfreshvarZphinodepredrI   Zincoming_defZidomr   r   r   r     s>   
z_FixSSAVars._find_def_from_topc                 C   s<   t d| |d }|| }|r|d }|S | j|||dS )z<Find definition from within the block at ``label``.
        zfind_def_from_bottom label %rr*   r~   rp   )r!   r"   r   )r   r4   r6   rY   r*   rK   Zlastdefr   r   r   r     s   z!_FixSSAVars._find_def_from_bottomr~   c                 C   s<   t t|jd| D ]}|j| |u r|  S qt|jS )zFind the positional index of the statement at ``block``.

        Assumptions:
        - no two statements can point to the same object.
        N)rangerN   r3   )r   r   rZ   r}   ir   r   r   r     s
   	
z_FixSSAVars._stmt_indexN)r~   )r   r   r   ri   r   r_   r`   rw   r{   r   r   r   r   r   r   r   r1   @  s    .r1   c                 C   s(   t jrttjd|  |d d S d S )Nz Detected uninitialized variable rp   )r   ZALWAYS_WARN_UNINIT_VARrs   rt   r   ZNumbaWarning)r)   rY   r   r   r   r     s   r   )*ri   loggingrA   rs   	functoolsr   r   collectionsr   Znumbar   Z
numba.corer   r   r   Znumba.core.utilsr	   r
   Znumba.core.analysisr   	getLoggerr   r!   r   r   r   r$   r   r/   r#   rJ   r    rQ   r0   r-   rV   rc   rR   rm   rE   r1   r   r   r   r   r   <module>   s@    	

$
( $