B
     \\A                 @   s   d Z ddlZddlmZ ddlmZmZ ddlmZ ddl	m
Z
 ddlmZmZ edd	Zi Zd
d Zdd ZeddZdd Zdd Zdd Zdd Zdd ZdS )z
Utils for IR analysis
    N)reduce)
namedtupledefaultdict)ir)CFGraph)typesconstsZuse_defs_resultzusemap,defmapc             C   sP  i }i }x8|   D ]*\}}t  ||< }t  ||< }x|jD ]}t|tkrntt| }|||| qDt|tjrt|jtj	rtdd |j
 D }	nPt|jtjrt|jjg}	n2t|jtjtjtjtjfrd}	ntdt|j|jj|	kr||jj x*|
 D ]}
|
j|kr||
j qW qDW qW t||dS )z*
    Find variable use/def per block.
    c             s   s   | ]}|j V  qd S )N)name).0var r   -lib/python3.7/site-packages/numba/analysis.py	<genexpr>(   s    z#compute_use_defs.<locals>.<genexpr>r   Zunreachable)ZusemapZdefmap)itemssetbodytypeir_extension_usedefs
isinstancer   AssignvalueZInst	list_varsZVarr	   ZArgConstZGlobalZFreeVarAssertionErrortargetadd_use_defs_result)blocksvar_use_mapvar_def_mapoffsetir_blockZuse_setZdef_setZstmtfuncZrhs_setr   r   r   r   compute_use_defs   s2    
r#   c       	         sz   dd fdd} fdd} fdd}i }x |  D ]}t| ||< qBW tt|| ||| |S )	z
    Find variables that must be alive at the ENTRY of each block.
    We use a simple fix-point algorithm that iterates until the set of
    live variables is unchanged for each block.
    c             S   s   t dd |  D S )zFHelper function to determine if a fix-point has been reached.
        c             s   s   | ]}t |V  qd S )N)len)r
   vr   r   r   r   E   s    z?compute_live_map.<locals>.fix_point_progress.<locals>.<genexpr>)tuplevalues)dctr   r   r   fix_point_progressB   s    z,compute_live_map.<locals>.fix_point_progressc                s2   d} |}x ||kr,| | |} |}qW dS )z4Helper function to run fix-point algorithm.
        Nr   )fnr(   	old_point	new_point)r)   r   r   	fix_pointG   s    
z#compute_live_map.<locals>.fix_pointc                s^   xXD ]P}| | B }| |  |O  < x*  |D ]\}}| |  | | O  < q6W qW dS )zGFind all variable definition reachable at the entry of a block
        N)
successors)r(   r    Zused_or_definedout_blk_)cfgr   r   r   r   	def_reachQ   s
    
z#compute_live_map.<locals>.def_reachc                sV   xP| D ]H}| | }x:  |D ],\}}|| @ }| |  ||  O  < qW qW dS )z?Find live variables.

        Push var usage backward.
        N)Zpredecessors)r(   r    Z	live_varsZinc_blk_dataZ	reachable)r1   def_reach_mapr   r   r   liveness[   s
    
z"compute_live_map.<locals>.liveness)keysr   r   )	r1   r   r   r   r-   r2   r5   live_mapr    r   )r1   r4   r)   r   r   r   compute_live_map<   s    



r8   Zdead_maps_resultzinternal,escaping,combinedc                s  t t t tt t}x| D ]\}}| || B }tfdd| |D }tdd |j D }	ttj	|
 t }
|
|	O }
||
 }||< || }x4| D ](\}}||| B } |  || O  < qW |s"|	||< q"W ttj	
 t }ttj	
 t }ttj	 
 t }ttj	|
 t }||B |B }|| }|rp|  s^nd|}t|t fdd|D }t |dS )z
    Compute the end-of-live information for variables.
    `live_map` contains a mapping of block offset to all the living
    variables at the ENTRY of the block.
    c             3   s   | ]\}}| | fV  qd S )Nr   )r
   r/   r3   )r7   r   r   r      s   z$compute_dead_maps.<locals>.<genexpr>c             s   s   | ]}|j V  qd S )N)r	   )r
   r%   r   r   r   r      s   z#liveness info missing for vars: {0}c             3   s"   | ]}||  | B fV  qd S )Nr   )r
   k)escaping_dead_mapinternal_dead_mapr   r   r      s   )ZinternalZescapingcombined)r   r   r   dictr.   
terminatorr   r   operatoror_r'   Zexit_pointsformatRuntimeError_dead_maps_result)r1   r   r7   r   Zexit_dead_mapr    r!   Zcur_live_setZoutgoing_live_mapZterminator_livesetZcombined_livesetZinternal_setZescaping_live_setr/   Znew_live_setZall_varsZinternal_dead_varsZescaping_dead_varsZexit_dead_varsZ	dead_varsZmissing_varsmsgr<   r   )r:   r;   r7   r   compute_dead_mapsv   sL    	


rE   c                s   t t  fdd}d}| }xh||krxP|D ]H} | || B }||| 8 }x&| |D ]\}	}
 |	  |O  < qZW q.W |}| }q W  S )z
    Compute the live variables at the beginning of each block
    and at each yield point.
    The ``var_def_map`` and ``var_dead_map`` indicates the variable defined
    and deleted at each block, respectively.
    c                  s   t tt  S )N)r&   mapr$   r'   r   )block_entry_varsr   r   r)      s    z2compute_live_variables.<locals>.fix_point_progressN)r   r   r.   )r1   r   r   Zvar_dead_mapr)   r+   r,   r    ZavailZsuccr3   r   )rG   r   compute_live_variables   s    	


rH   c             C   sr   t  }x| D ]}|| qW x8|  D ],\}}|j}x| D ]}||| q@W q(W |t|  |  |S )N)	r   Zadd_noder   r>   Zget_targetsZadd_edgeZset_entry_pointminZprocess)r   r1   r9   bZtermr   r   r   r   compute_cfg_from_blocks   s    
rK   c             c   sx   t  }xF|   D ]6}t |jt |jB t |jB }||j ||O }qW x$|   D ]}|j|kr\|V  q\W dS )zK
    A generator that yields toplevel loops given a control-flow-graph
    N)r   Zloopsr'   r   entriesZexitsdiscardheader)r1   Zblocks_in_loopZloopZinsidersr   r   r   find_top_level_loops   s    
rO   c          
      s  ddl mmm}m} d fdd}fdd fdd	} fd
d}G dd dtfdd} dkrtddd t  |}g }	x|D ]\}
}g }t	|
t
jr|
jdkr|}x|
j|
jgD ]v} }|jjkr||j}|}n:y"||}|dkr&td}W n |k
r>   Y nX t	|s|| qW t|dkr||
|f| \}}|r|	|
|f qW dd |	D }x|D ]\}}}||krxp|jD ]f}t	|t
jr|j|kr|	|| d }t
j||jd|_j|jj }||}|j||< qW qW tj}x| D ]}j|= qDW |	rht !_" dkrtddd t  dS )z
    Removes dead branches based on constant inference from function args.
    This directly mutates the IR.

    func_ir is the IR
    called_args are the actual arguments with which the function is called
       )get_definitionguard
find_constGuardExceptionr   c                s^   g }xT| j  D ]F}|jd }t|tjr|} | |jj}|d k	r||||f qW |S )N)	r   r'   r   r   r   ZBranchcondr	   append)func_irZbranchesblkZbranch_or_jumpbranch	condition)rQ   rR   r   r   find_branches  s    
z(dead_branch_prune.<locals>.find_branchesc                s<   | r
 j n j}tj| jd}||jd< | j kr8dS dS )N)locrU   rP   r   )truebrfalsebrr   ZJumpr]   r   )take_truebrrY   ZkeepZjmp)rZ   r   r   do_prune#  s    
z#dead_branch_prune.<locals>.do_prunec                sx   |\}}t |tj}t |tj}|s(|rt|||} dkrb|rF| jn| j}	td|	 | |||j ||}
d|
fS dS )Nr   z
Pruning %sT)FN)r   r   NoneTyper*   r_   r^   print)rZ   r[   rY   condslhs_condrhs_condZlhs_noneZrhs_noner`   killtaken)DEBUGra   r   r   prune_by_type*  s    
z(dead_branch_prune.<locals>.prune_by_typec       	         sT   |\}}| ||} dkrB|r&| jn| j}td| | |||j  ||}d|fS )Nr   z
Pruning %sT)r*   r_   r^   rc   )	rZ   r[   rY   rd   re   rf   r`   rg   rh   )ri   ra   r   r   prune_by_value:  s    
z)dead_branch_prune.<locals>.prune_by_valuec               @   s   e Zd ZdS )z"dead_branch_prune.<locals>.UnknownN)__name__
__module____qualname__r   r   r   r   UnknownC  s   ro   c                sf   j | }| }t|tjr$|S t|tjrX|j}t|tjrF|S |dkrXtdS t|d  S )zC
        Resolves an input arg to a constant (if possible)
        NnoneZliteral_type)	arg_namesindexr   r   rb   ZOmittedr   getattr)Z	input_argidxZinput_arg_tyval)ro   called_argsrX   r   r   resolve_input_arg_constF  s    
z2dead_branch_prune.<locals>.resolve_input_arg_constZbeforeP   -ZbinopNrp      c             S   s   g | ]}|d  qS )r   r   )r
   xr   r   r   
<listcomp>  s    z%dead_branch_prune.<locals>.<listcomp>)r]   Zafter)#Zir_utilsrQ   rR   rS   rT   objectrc   centerdumpr   r   ZExpropZlhsZrhsr	   rq   r   rb   rW   r$   r   r   r   rr   r   r]   Z_definitionsr   rK   r   Z
dead_nodesr   ZConstantInferenceZ_consts)rX   rv   rS   rT   r\   rj   rk   rw   Zbranch_infoZnullified_conditionsr[   rY   Zconst_condsZpruneargZresolved_constZ
prune_statrh   Zdeadcondr0   rV   r{   Z
branch_bitZdefnsZrepl_idxr1   Zdeadr   )ri   ro   rZ   rv   ra   rX   rQ   rR   r   dead_branch_prune  sh    	







r   )__doc__r?   	functoolsr   collectionsr   r   Znumbar   Znumba.controlflowr   r   r   r   r   r#   r8   rC   rE   rH   rK   rO   r   r   r   r   r   <module>   s    
%7
H-