U
    9%em                     @   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
mZmZmZ ddl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eddZdd Zdd  Zd!d" Zi Zd#d$ ZdS )%z
Utils for IR analysis
    N)reduce)
namedtupledefaultdict   )CFGraph)typeserrorsirconsts)specialZuse_defs_resultzusemap,defmapc                 C   s@  i }i }|   D ] \}}t  ||< }t  ||< }|jD ]}t|tkrftt| }|||| q<t|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 |
 D ]}
|
j|kr||
j qq<qt||dS )z*
    Find variable use/def per block.
    c                 s   s   | ]}|j V  qd S Nname).0var r   R/var/www/html/Darija-Ai-API/env/lib/python3.8/site-packages/numba/core/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   ArgConstGlobalFreeVarAssertionErrortargetadd_use_defs_result)blocksvar_use_mapvar_def_mapoffsetir_blockZuse_setZdef_setstmtfuncZrhs_setr   r   r   r   compute_use_defs   s4    
r,   c           	         sv   dd fdd} fdd} fdd}i }|  D ]}t| ||< q@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 r   )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                    s.   d} |}||kr*| | |} |}qdS )z4Helper function to run fix-point algorithm.
        Nr   )fnr2   	old_point	new_point)r3   r   r   	fix_pointG   s    z#compute_live_map.<locals>.fix_pointc                    sV   D ]L}| | B }| |  |O  <   |D ]\}}| |  | | O  < q2qdS )zGFind all variable definition reachable at the entry of a block
        N)
successors)r2   r(   Zused_or_definedout_blk_)cfgr'   r&   r   r   	def_reachQ   s
    z#compute_live_map.<locals>.def_reachc                    sN   | D ]D}| | }  |D ],\}}|| @ }| |  ||  O  < qqdS )z?Find live variables.

        Push var usage backward.
        N)predecessors)r2   r(   Z	live_varsZinc_blk_dataZ	reachable)r;   def_reach_mapr'   r   r   liveness[   s
    z"compute_live_map.<locals>.liveness)keysr   r   )	r;   r%   r&   r'   r7   r<   r@   live_mapr(   r   )r;   r?   r3   r'   r&   r   compute_live_map<   s    



rC   Zdead_maps_resultzinternal,escaping,combinedc                    s  t t t tt t}| D ]\}}| || B }tfdd| |D }tdd |j D }	ttj	|
 t }
|
|	O }
||
 }||< || }| D ](\}}||| B } |  || O  < q|s |	||< q ttj	
 t }ttj	
 t }ttj	 
 t }ttj	|
 t }||B |B }|| }|rh|  sVn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 r   r   )r   r9   r>   )rB   r   r   r      s   z$compute_dead_maps.<locals>.<genexpr>c                 s   s   | ]}|j V  qd S r   r   r.   r   r   r   r      s   z#liveness info missing for vars: {0}c                 3   s"   | ]}||  | B fV  qd S r   r   )r   k)escaping_dead_mapinternal_dead_mapr   r   r      s   )ZinternalZescapingcombined)r   r   r   dictr8   
terminatorr   r   operatoror_r1   Zexit_pointsformatRuntimeError_dead_maps_result)r;   r%   rB   r'   Zexit_dead_mapr(   r)   Zcur_live_setZoutgoing_live_mapZterminator_livesetZcombined_livesetZinternal_setZescaping_live_setr9   Znew_live_setZall_varsZinternal_dead_varsZescaping_dead_varsZexit_dead_varsZ	dead_varsZmissing_varsmsgrG   r   )rE   rF   rB   r   compute_dead_mapsv   sZ    	


rP   c                    s   t t  fdd}d}| }||kr||D ]D} | || B }||| 8 }| |D ]\}	}
 |	  |O  < qTq*|}| }q 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 r   )r0   mapr-   r1   r   Zblock_entry_varsr   r   r3      s    z2compute_live_variables.<locals>.fix_point_progressN)r   r   r8   )r;   r%   r'   Zvar_dead_mapr3   r5   r6   r(   Zavailsuccr>   r   rR   r   compute_live_variables   s    	rT   c                 C   sf   t  }| D ]}|| q
|  D ](\}}|j}| D ]}||| q8q"|t|  |  |S r   )	r   add_noder   rI   Zget_targetsZadd_edgeZset_entry_pointminprocess)r%   r;   rD   btermr"   r   r   r   compute_cfg_from_blocks   s    rZ   c                 c   sv   t  }|   D ]6}t |jt |jB t |jB }||j ||O }q|   D ]}|j|krVt| |V  qVdS )zK
    A generator that yields toplevel loops given a control-flow-graph
    N)	r   Zloopsr1   r   entriesexitsdiscardheader_fix_loop_exit)r;   Zblocks_in_looploopZinsidersr   r   r   find_top_level_loops   s    

ra   c                    sR   |    ttj fdd|jD |j}|rJ|j|j| B }|j||dS |S dS )zf
    Fixes loop.exits for Py3.8 bytecode CFG changes.
    This is to handle `break` inside loops.
    c                    s   g | ]} | qS r   r   )r   rX   Zpostdomsr   r   
<listcomp>  s     z"_fix_loop_exit.<locals>.<listcomp>)r\   r   N)Zpost_dominatorsr   rJ   and_r\   r   _replace)r;   r`   r\   r   r   rb   r   r_   
  s    r_   	nullifiedz!condition, taken_br, rewrite_stmtc           +   
      s  ddl mmm}m} d fd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|   t	 }	t	 }
| j
 D ]N\}}|jD ]>}t|tjrt|jtjr|jjdkr||	|j< ||
|j< qq|| }g }|D ]\}}g }t|tjr|jdkr|}|j|jfD ]} }| |}t|tjr||j}|}n:z"|| |}|dkrtd}W n |k
r   Y nX t|sR|| qRt|dkr|||f| \}}|r|t||d n }z4| j}|| |jd }|dkrPtd}W n |k
rh   Y nX t|s|||\}}|r|t||d qdd |D }|D ]\}}}||kr|jD ]p}t|tjr|j|kr||| }|jr|j}tj ||j!d|_| j"|j#j$ }||} |j|| < qΐqt%| j
}!|!& }"|	 D ]\}#}||"krtq^dd |!'|D }$t(|$t(|#j)kr^t|$dkr|#j)|$d }%|#j*|% |
|# _nrg }&g }'t+|#j*|#j)D ].\}(})|)|"krqn|&|( |'|) q|#j*,  |#j*-|& |#j),  |#j)-|' q^|"D ]}*| j
|*= qF|rht./| | _0 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
    r   )get_definitionguard
find_constGuardExceptionc                    s   g }| j  D ]}|jd }t|tjr|} | |jj}|d k	rt|dd dkr | |j	}|d k	rt|tj
r|jtkr | |jd }|d k	r||||f q|S )Nopcallr   )r%   r1   r   r   r	   ZBranchcondr   getattrr+   r   r   boolargsappend)func_irZbranchesblkZbranch_or_jumpbranchpredfunction	conditionrg   rh   r   r   find_branches0  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locrk   r   r   )truebrfalsebrr	   ZJumpr|   r   )take_truebrrt   ZkeepZjmp)ru   r   r   do_pruneB  s    
z#dead_branch_prune.<locals>.do_prunec                    s   |\}}t |tj}t |tj}|s(|rz|||}W n tk
rN   Y dS X  dkr~|rb| jn| j}	td|	 | |||j ||}
d|
fS dS NFNr   
Pruning %sT)r   r   NoneTyper4   	Exceptionr~   r}   print)ru   rx   rt   condslhs_condrhs_condZlhs_noneZrhs_noner   killtakenDEBUGr   r   r   prune_by_typeI  s     
z(dead_branch_prune.<locals>.prune_by_typec           	         sp   |\}}z| ||}W n tk
r.   Y dS X  dkr^|rB| jn| j}td| | |||j  ||}d|fS r   )r4   r   r~   r}   r   )	ru   rx   rt   r   r   r   r   r   r   r   r   r   prune_by_value\  s    
z)dead_branch_prune.<locals>.prune_by_valuec                    s~   z,t |tjtjtjfs tdt|j}W n tk
rB   Y dS X  dkrl|rV| jn| j	}t
d| | | ||}d|fS )NzExpected constant Numba IR noder   r   r   T)r   r	   r   r    r   	TypeErrorrp   r   r~   r}   r   )ru   rv   rt   r   r   r   r   r   r   prune_by_predicateh  s    
z-dead_branch_prune.<locals>.prune_by_predicatec                   @   s   e Zd ZdS )z"dead_branch_prune.<locals>.UnknownN)__name__
__module____qualname__r   r   r   r   Unknownw  s   r   c                    sZ   |  }t |tjr|S t |tjrL|j}t |tjr:|S |dkrLtdS t|d  S )zC
        Resolves an input arg to a constant (if possible)
        NnoneZliteral_type)r   r   r   ZOmittedr   ro   )Zinput_arg_idxZinput_arg_tyval)r   called_argsr   r   resolve_input_arg_constz  s    
z2dead_branch_prune.<locals>.resolve_input_arg_constr   beforeP   -phiZbinopNr      TFc                 S   s   g | ]
}|j qS r   )rx   r   xr   r   r   rc     s     z%dead_branch_prune.<locals>.<listcomp>r{   c                 S   s   g | ]}|d  qS )r   r   r   r   r   r   rc     s     after)1numba.core.ir_utilsrg   rh   ri   rj   objectr   centerdumprH   r%   r   r   r   r	   r   r   Exprrl   lhsrhsr   indexr   r   rr   r-   rf   rn   rq   Zrewrite_stmtZtaken_brr   r|   _definitionsr"   r   rZ   Z
dead_nodesr=   r   Zincoming_blocksZincoming_valueszipclearextendr
   ZConstantInferenceZ_consts)+rs   r   ri   rj   rz   r   r   r   r   Zphi2lblZphi2asgnZlblrt   r*   Zbranch_infoZnullified_conditionsrx   Zconst_condsZpruneargZresolved_constarg_defZ
prune_statr   Z	pred_callZdeadcondr:   rn   r   Znullified_infoZ
branch_bitdefnsrepl_idxZnew_cfgZdead_blocksr   Znew_incomingidxZ
ic_val_tmpZ
ic_blk_tmpZic_valZic_blkZdeadr   )r   r   ru   r   r   rg   rh   r   dead_branch_prune#  s    











!






r   c                    s   d}|dkr<t d| jj dd t ddd |   fdd	 fd
d} fdd}ddlm m | j	 D ]F}|j
D ]:ttjrjttjr|| | || | qq|dkrt ddd |   t d dS )aP  
    This rewrites values known to be constant by their semantics as ir.Const
    nodes, this is to give branch pruning the best chance possible of killing
    branches. An example might be rewriting len(tuple) as the literal length.

    func_ir is the IR
    called_args are the actual arguments with which the function is called
    r   r   zrewrite_semantic_constants: r   r   r   *c                    s6   t ||j|_| j|jj }| }|j||< dS )zr
        Rewrites the stmt as a ir.Const new_val and fixes up the entries in
        func_ir._definitions
        N)r	   r   r|   r   r   r"   r   r   )rs   r*   new_valr   r   )r   r   r   rewrite_statementU  s    
z5rewrite_semantic_constants.<locals>.rewrite_statementc                    s\   t | dd dkrX| jdkrX || j}t|tjrX||j }t|tjrX||j	 d S )Nrl   ro   ndim)
ro   attrr   r   r	   r   r   r   ZArrayr   )r   rs   r   r   argtyrg   rh   r   r*   r   r   rewrite_array_ndim_  s    

z6rewrite_semantic_constants.<locals>.rewrite_array_ndimc                    s   t | dd dkr || j}|d k	rt|tjrt |dd tkr| j\} ||}t|tjr||j }t|t	j
r||j n6t|tjr|jdkr|j}t|t	j
r||j d S )Nrl   rm   r   Ztyped_getitem)ro   r+   r   r	   r   r-   rq   r   r   r   Z	BaseTuplecountr   rl   Zdtype)r   rs   r   r+   r   r   r   r   r   r   rewrite_tuple_leni  s"    
z5rewrite_semantic_constants.<locals>.rewrite_tuple_lenry   r   zP--------------------------------------------------------------------------------N)r   Zfunc_id	func_namer   r   r   rg   rh   r%   r1   r   r   r	   r   r   r   )rs   r   r   r   r   rt   r   )rg   rh   r   r*   r   r   rewrite_semantic_constantsD  s2    	 


r   c                 C   s(  ddl m} t }i }| j D ]}|jddD ]}||j| |j}t	|t
jt
jfr`|j}n||j| |}|tjkr0|j\}	| |	}
t	|
t
jr0|
j}|| |||j q0q |D ]d}|| }t	|tjo|jdk}|r|| }tj||dt	|tjtjfs|| }tj||dqdS )a3  An analysis to find `numba.literally` call inside the given IR.
    When an unsatisfied literal typing request is found, a `ForceLiteralArg`
    exception is raised.

    Parameters
    ----------

    func_ir : numba.ir.FunctionIR

    argtypes : Sequence[numba.types.Type]
        The argument types.
    r   )ir_utilsrm   )rl   Nr{   )
numba.corer   r   r%   r1   Z
find_exprsrh   rg   r+   r   r	   r   r    r   Zresolve_func_from_moduler   Z	literallyrq   r   r   r#   
setdefaultr|   r   ZInitialValueinitial_valuer   ZForceLiteralArgLiteral)rs   Zargtypesr   Zmarked_argsZ	first_locrt   Zassignr   Zfnobjr   ZdefargZargindexposZ	query_argZdo_raiser|   r   r   r   find_literally_calls  s<     


r   c                 C   sH   t  }|  D ]4}|jD ](}t|tkrtt| }||| qqq|S )a  
    Analyzes a dictionary of blocks to find variables that must be
    stack allocated with alloca.  For each statement in the blocks,
    determine if that statement requires certain variables to be
    stack allocated.  This function uses the extension point
    ir_extension_use_alloca to allow other IR node types like parfors
    to register to be processed by this analysis function.  At the
    moment, parfors are the only IR node types that may require
    something to be stack allocated.
    )r   r1   r   r   ir_extension_use_alloca)r%   Zuse_alloca_varsr)   r*   r+   r   r   r   must_use_alloca  s    

r   ) __doc__rJ   	functoolsr   collectionsr   r   Zcontrolflowr   r   r   r   r	   r
   Z
numba.miscr   r$   r   r,   rC   rN   rP   rT   rZ   ra   r_   rf   r   r   r   r   r   r   r   r   r   <module>   s0   
%7
H-
  #G0