U
    ÷¾|e»:  ã                   @   sH  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 ddlmZ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)Úpformat)Údefaultdict)Úconfig)ÚirÚir_utilsÚerrors)Ú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)Úfunc_ir© r   úK/var/www/website-v5/atlas_env/lib/python3.8/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__%   s    z_CacheListVars.__init__c                 C   s*   | j  |¡}|d kr&| ¡  | j |< }|S r   )r   ÚgetÚ	list_vars)r   ÚinstZ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r†t	 
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	   Ú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 |_qV|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                    sn   dd„ |   ¡  ¡ D ƒ‰ d}|rjd}ˆ  ¡ D ]<\}}ttj‡ fdd„|D ƒtƒ ƒ}| |¡r*||O }d}q*qˆ S )z²Compute 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   )r8   Úv©Z	domfrontsr   r   Ú
<listcomp>p   s     z'_iterated_domfronts.<locals>.<listcomp>)Údominance_frontierr1   r   ÚoperatorÚor_r6   Ú
difference)r$   Z
keep_goingr9   r:   Úinnerr   r=   r   r   e   s    
r   c                 C   s,   t ƒ }| ¡ D ]\}}|r|| | O }q|S r   )r6   r1   )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-   r/   Ú_FreshVarHandler)r   r(   r3   r)   r4   r   r   r   r!   ‚   s
    r!   c                 C   s   |   ¡ ^}}|jS r   )ÚvaluesÚscope)r   ÚfirstÚ_r   r   r   Ú
_get_scopeŒ   s    rI   c                 C   sL   t tƒ}t| |tƒ ƒ t dt|ƒ¡ dd„ | ¡ D ƒ}t dt|ƒ¡ |S )zm
    Returns
    -------
    res : Set[str]
        The SSA violators in a dictionary of variable names.
    zdefs %sc                 S   s    h | ]\}}t |ƒd kr|’qS )é   )Úlenr7   r   r   r   Ú	<setcomp>›   s      z'_find_defs_violators.<locals>.<setcomp>zSSA violators %s)r   r-   Ú_run_block_analysisÚ_GatherDefsHandlerr   r    r   r1   )r   Údefsr&   r   r   r   r   ‘   s    r   c                 C   s4   |   ¡ D ]&\}}t d|¡ t|||ƒD ]}q(qd S )Nz"==== SSA block analysis pass on %s)r1   r   r    Ú_run_ssa_block_pass)r   r3   Úhandlerr5   ÚblkrH   r   r   r   rM       s    rM   c           	      C   s‚   i }|   ¡ D ]p\}}t d|¡ tj|j|jd�}g }||d< ||d< t|||ƒD ]}|d k	sbt‚| 	|¡ qR||_
|||< q|S )Nz!==== SSA block rewrite pass on %s)rF   Úlocr5   Úblock)r1   r   r    r   ÚBlockrF   rS   rP   ÚAssertionErrorÚappendr2   )	r   r3   rQ   r4   r5   rR   ÚnewblkZnewbodyÚstmtr   r   r   r/   §   s    
r/   c                 C   s   t t| ƒd�S )N)rF   )ÚdictrI   )r   r   r   r   r,   ¸   s    ÿr,   c                 c   sp   t  d|¡ |jD ]X}t  d|¡ t|tjƒr<| | |¡}n| | |¡}||k	rd|d k	rdt  d|¡ |V  qd S )Nz
Running %szon stmt: %szreplaced with: %s)r   r    r2   Ú
isinstancer   ÚAssignÚ	on_assignÚon_other)r3   rR   rQ   rY   Úretr   r   r   rP   ¾   s    
rP   c                   @   s    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   s   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   r3   Úassignr   r   r   r]   Î   s    z_BaseHandler.on_assignc                 C   s   dS )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   r3   rY   r   r   r   r^   à   s    z_BaseHandler.on_otherN©r   r   r   Ú__doc__r]   r^   r   r   r   r   r`   Ë   s   r`   c                   @   s   e Zd ZdZdd„ ZdS )rN   zEFind all defs

    ``states`` is a Mapping[str, List[ir.Assign]]
    c                 C   s   ||j j  |¡ d S r   )ÚtargetÚnamerW   ra   r   r   r   r]   ø   s    z_GatherDefsHandler.on_assignN)r   r   r   re   r]   r   r   r   r   rN   ó   s   rN   c                   @   s   e Zd Zdd„ ZejZdS )ÚUndefinedVariablec                 C   s   t dƒ‚d S )NzNot intended for instantiation)ÚNotImplementedErrorr   r   r   r   r   ý   s    zUndefinedVariable.__init__N)r   r   r   r   r   Ú	UNDEFINEDrf   r   r   r   r   rh   ü   s   rh   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )rD   z9Replaces assignment target with new fresh variables.
    c                 C   s®   |j j|d krª|d }|d }t|ƒdkrp|j }t d|¡ |j|jkr„d|j›d�}t tj	||j
d�¡ n|j|j j|j
d�}tj||j|j
d	�}||d
   |¡ |S )Nr(   rF   r)   r   zfirst assign: %sz	variable z is not in scope.©rS   ©rf   ÚvaluerS   r5   )rf   rg   rK   r   r    Ú	localvarsÚwarningsÚwarnr	   ÚNumbaIRAssumptionWarningrS   Úredefiner   r\   rm   rW   )r   r3   rb   rF   r)   Z	newtargetZwmsgr   r   r   r]     s&    
ÿ
ýz_FreshVarHandler.on_assignc                 C   s   |S r   r   rc   r   r   r   r^     s    z_FreshVarHandler.on_otherNrd   r   r   r   r   rD     s   rD   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 )r0   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   )  s    z_FixSSAVars.__init__c                 C   sà   |j }t|tjƒr†|  ||| j |j ¡¡}|d k	rÜ|jtjk	rÜ|d |jj	krÜ|d |ji}t
|ƒ}t ||¡ tj|j||jd�S nVt|tjƒrÜ|  |||g¡}|d k	rÜ|jtjk	rÜ|d |jj	krÜtj|j|j|jd�S |S )Nr(   rl   )rm   r[   r   ÚInstÚ_fix_varrs   r   rf   rj   rg   r   r   Úreplace_vars_innerr\   rS   ÚVar)r   r3   rb   ÚrhsÚnewdefÚreplmapr   r   r   r]   ,  s6      ÿýýz_FixSSAVars.on_assignc                 C   s`   |   ||| j |¡¡}|d k	r\|jtjk	r\|d |jjkr\|d |ji}t|ƒ}t 	||¡ |S )Nr(   )
ru   rs   r   rf   r   rj   rg   r   r   Úreplace_vars_stmt)r   r3   rY   ry   rz   r   r   r   r^   K  s      
ÿz_FixSSAVars.on_otherc                 C   s.   dd„ |D ƒ}|d }||kr*|   ||¡S dS )z0Fix all variable uses in ``used_vars``.
        c                 S   s   g | ]
}|j ‘qS r   )rg   )r8   r9   r   r   r   r>   Y  s     z(_FixSSAVars._fix_var.<locals>.<listcomp>r(   N)Ú	_find_def)r   r3   rY   Ú	used_varsÚvarnamesZphivarr   r   r   ru   V  s    z_FixSSAVars._fix_varc                 C   s¬   t  d|d |¡ d}|d }|d | }|d | }|d }|  ||¡}t|ƒD ]:}	| j|	||d�}
|
|k rx|	} qŽqR|	|krR|d	 } qŽqR|dkr¨| j|||jd
�}|S )z?Find definition of ``stmt`` for the statement ``stmt``
        zfind_def var=%r stmt=%sr(   Nr5   r)   r*   rT   )Ústopéÿÿÿÿrk   )r   r    Ú_stmt_indexÚreversedÚ_find_def_from_toprS   )r   r3   rY   Zselected_defr5   Z
local_defsZ
local_phisrT   Zcur_posÚdefstmtZdef_posr   r   r   r|   ^  s,      ÿz_FixSSAVars._find_defc                 C   s:  t  d|¡ |d }|d }|d }|d }||krð|d }|d j}|j|d |d	�}	tj|	tjj|d	�|d
�}
t  d|
|¡ ||  d|
¡ ||  	|
¡ | 
|¡D ]B\}}| j|||d	�}t  d|¡ |
jj 	|j¡ |
jj 	|¡ q¨|
S | ¡ | }||k�rt|d |ƒ tS t  d||¡ | j|||d	�S dS )z—Find 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+   rF   rT   r(   rk   rl   zinsert phi node %s at %sr   zincoming_def %szidom %s from label %sN)r   r    rS   rr   r   r\   ÚExprÚphiÚinsertrW   ÚpredecessorsÚ_find_def_from_bottomrm   Úincoming_valuesrf   Úincoming_blocksÚimmediate_dominatorsÚ"_warn_about_uninitialized_variablerh   )r   r3   r5   rS   r$   r)   r*   r+   rF   ZfreshvarZphinodeÚpredrH   Zincoming_defÚidomr   r   r   rƒ   z  sB    
ý  ÿ
z_FixSSAVars._find_def_from_topc                 C   s@   t  d|¡ |d }|| }|r,|d }|S | j|||d�S dS )z<Find definition from within the block at ``label``.
        zfind_def_from_bottom label %rr)   r€   rk   N)r   r    rƒ   )r   r3   r5   rS   r)   rO   Zlastdefr   r   r   r‰   ¨  s    z!_FixSSAVars._find_def_from_bottomr€   c                 C   s<   t t|jƒƒd|… D ]}|j| |kr|  S qt|jƒS )z‘Find the positional index of the statement at ``block``.

        Assumptions:
        - no two statements can point to the same object.
        N)ÚrangerK   r2   )r   r„   rT   r   Úir   r   r   r�   ´  s    	
z_FixSSAVars._stmt_indexN)r€   )r   r   r   re   r   r]   r^   ru   r|   rƒ   r‰   r�   r   r   r   r   r0      s   .r0   c                 C   s$   t jr t tjd| › �|d�¡ d S )Nz Detected uninitialized variable rk   )r   ÚALWAYS_WARN_UNINIT_VARro   rp   r	   ÚNumbaWarning)r(   rS   r   r   r   r�   Ã  s    þÿr�   ))re   Úloggingr@   ro   Ú	functoolsr   r   Úpprintr   Úcollectionsr   Únumbar   Ú
numba.corer   r   r	   Únumba.core.analysisr
   Ú	getLoggerr   r   r   r   r   r"   r   r.   r!   rI   r   rM   r/   r,   rP   r`   rN   rh   rD   r0   r�   r   r   r   r   Ú<module>   s>   	

$
(	 $