U
    ?hF                    @   s  d dl Zd dlZd dlZd dlZd dlm Z mZmZm	Z	m
Z
mZmZ d dlmZ d dlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z! d dlm"Z"m#Z#m$Z$ d dlm%Z% d dl&m'Z( d dl)Z*d dl+Z+d dl,ZdZ-d	d
 Z.dd Z/G dd de0Z1dd Z2G dd de0Z3d7ddZ4dd Z5dd Z6dd Z7dd Z8dd Z9dd  Z:d!d" Z;d#d$ Z<d%d& Z=d'd( Z>d8d*d+Z?d,d- Z@d.d/ ZAd0d1 ZBe
Cd2G d3d4 d4e
jDZEd5d6 ZFdS )9    N)typestypingerrorsirrewritesconfigir_utils)internal_prange)
next_labeladd_offset_to_labelsreplace_varsremove_delsrename_labelsfind_topo_ordermerge_adjacent_blocksGuardExceptionrequireguardget_definitionfind_callnamefind_build_sequenceget_np_ufunc_typget_ir_of_codesimplify_CFGcanonicalize_array_mathdead_code_elimination)compute_cfg_from_blockscompute_use_defscompute_live_variables)postproc)empty_inferredTc                 C   sH   | j  D ]8}|tjD ]&}t|jtjrd}tj	||j
dqq
dS )z8Checks the IR of a callee is supported for inlining
    z-The use of yield in a closure is unsupported.locN)blocksvalues
find_instsr   Assign
isinstancevalueYieldr   UnsupportedErrorr"   )func_irblkstmtmsg r/   O/var/www/html/venv/lib/python3.8/site-packages/numba/core/inline_closurecall.pycallee_ir_validator,   s
    r1   c                 C   s:   |  d| }| dd dd}| dd dd}|S )a  Creates a name for an inlined variable based on the function name and the
    variable name. It does this "safely" to avoid the use of characters that are
    illegal in python variable names as there are occasions when function
    generation needs valid python name tokens..<_>$_v)replace)Zfunction_namevar_nameinlined_namenew_namer/   r/   r0   _created_inlined_var_name6   s    r<   c                   @   sN   e Zd ZdZi dfddZdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dS )InlineClosureCallPasszInlineClosureCallPass class looks for direct calls to locally defined
    closures, and inlines the body of the closure function to the call site.
    Fc                 C   s"   || _ || _|| _g | _|| _d S N)r+   parallel_optionsswapped_processed_stencilstyped)selfr+   r?   r@   rB   r/   r/   r0   __init__I   s
    zInlineClosureCallPass.__init__c              
      s  t | j}|d d}t| jj }td}|d |r| \}}t	|j
D ]\}}t|tjrT|j}	t|	tjrT|	jdkrTtt| j|	}
tt| j|	j}t| j||||	|
rd} q:t| j||||rd} q:t| j||
|rTd}qTq:tr|rt| jj t| jj}|d t| |   fdd  D }g }t|d	d
 ddD ]>\}}|| tt | j|| | | j!| j"j#| j$rXd}qX|rt%| j |rt| jj}|& D ]}| jj|= qt'| j t(| jj| j_t)| jj |d dS )z&Run inline closure call pass.
        TFr=   ZSTARTcallzstart inline arraycallc                    s   g | ]}|t  | jfqS r/   )lenbody).0kloopsr/   r0   
<listcomp>|   s     z-InlineClosureCallPass.run.<locals>.<listcomp>c                 S   s   | d S )N   r/   )tupr/   r/   r0   <lambda>       z+InlineClosureCallPass.run.<locals>.<lambda>)keyreverseENDN)*r   ZPostProcessorr+   runlistr#   items_make_debug_printpop	enumeraterG   r'   r   r&   r(   Expropr   r   r   func_inline_reduction_inline_closure_inline_stencilenable_inline_arraycallr   r   _debug_dumprK   keyssortedappend_inline_arraycallr@   r?   comprehensionrB   _fix_nested_arrayZ
dead_nodesr   r   r   )rC   ppmodified	work_listdebug_printZ_labelblockiinstrexpr	call_namefunc_defcfgZsized_loopsvisitedrI   sZdeadr/   rJ   r0   rT   P   s    
         

  

zInlineClosureCallPass.runc              	   C   sx   t | jj  t |dkp|dk t|jdkr8tdt| j|jd  d
dd}t| j| jj	j
j||||td d	S )N)reducebuiltins)ru   
_functools)      z^invalid reduce call, two arguments are required (optional initial value can also be specified)r   c                 S   s6   t |}|d k	r|}nt|}|D ]}| ||}q"|S r>   )iternext)fAvitrt   ar/   r/   r0   reduce_func   s    z<InlineClosureCallPass._inline_reduction.<locals>.reduce_funcrj   callee_validatorT)N)r   r?   Z	reductionrF   args	TypeErrorcheck_reduce_funcr+   inline_closure_callfunc_idr\   __globals__r1   )rC   rj   rl   rm   ro   rp   r   r/   r/   r0   r]      s$    


 
   z'InlineClosureCallPass._inline_reductionc                 C   sx  ddl m} |j}|j}t|tjrb|jdkrbt|j|rb|jrT| j|jj7  _n
|jj|_dS t	|dkpr|dk t	|| j
k | j
| t|jdkstdtt| j|jd }t	t|tjo|jd	k t| jjjj|j}t|j}	d
|	krt| j|	}
|
stdd|	kr:t| j|	}
|
s:td||d|	}|j|_td||j}|g| jj|j< ||_dS )Nr   )StencilFuncstencilT)r   znumba.stencils.stencil)r   numbarM   z5As a minimum Stencil requires a kernel as an argumentmake_functionneighborhoodzXstencil neighborhood option should be a tuple with constant structure such as ((-w, w),)index_offsetszYstencil index_offsets option should be a tuple with constant structure such as (offset, )Zconstant)Znumba.stencils.stencilr   targetr(   r'   r   Globalnamekwsr   rA   rd   rF   r   
ValueErrorr   r   r+   rZ   r[   r   r   r\   r   codedict_fix_stencil_neighborhood_fix_stencil_index_offsetsr"   _definitions)rC   rn   rp   rq   r   lhsro   Zstencil_defZ	kernel_iroptionsZfixedZsfZ	sf_globalr/   r/   r0   r_      sZ    





z%InlineClosureCallPass._inline_stencilc                 C   sh   t | j|d }tt|d g }|jD ].}t | j|}tt|d |t|j q(t||d< dS )z
        Extract the two-level tuple representing the stencil neighborhood
        from the program IR to provide a tuple to StencilFunc.
        r   rV   T)r   r+   r   hasattrrV   rd   tuple)rC   r   Zdims_build_tupleresZ
window_varZwin_build_tupler/   r/   r0   r      s    
z/InlineClosureCallPass._fix_stencil_neighborhoodc                 C   s0   t | j|d }tt|d t|j|d< dS )z
        Extract the tuple representing the stencil index offsets
        from the program IR to provide to StencilFunc.
        r   rV   T)r   r+   r   r   r   rV   )rC   r   Zoffset_tupler/   r/   r0   r      s    z0InlineClosureCallPass._fix_stencil_index_offsetsc              	   C   s>   t t|tjo|jdk t| j| jjjj	||||t
d dS )Nr   r   T)r   r'   r   rZ   r[   r   r+   r   r\   r   r1   )rC   rj   rl   rm   rq   r/   r/   r0   r^     s    
   z%InlineClosureCallPass._inline_closureN)__name__
__module____qualname____doc__rD   rT   r]   r_   r   r   r^   r/   r/   r/   r0   r=   D   s   K2
r=   c                 C   s   t t| |}|dkrtdt|tjtjfrRt|jtj	j
jsHtd|jj}nt|dsnt|dsntdt|dr~|jn|j}|jdkstd|S )zsChecks the function at func_var in func_ir to make sure it's amenable
    for inlining. Returns the function itselfNzMReduce function cannot be found for njit                             analysiszInvalid reduction functionr   __code__rx   z*Reduction function should take 2 arguments)r   r   r   r'   r   FreeVarr   r(   r   coreregistryZCPUDispatcherZpy_funcr   r   r   co_argcountr   )r+   func_varr   f_coder/   r/   r0   r     s(    


r   c                   @   sP   e Zd ZdZdddddeddfddZdddZdddZdd
dZdd Z	dS )InlineWorkera=   A worker class for inlining, this is a more advanced version of
    `inline_closure_call` in that it permits inlining from function type, Numba
    IR and code object. It also, runs the entire untyped compiler pipeline on
    the inlinee to ensure that it is transformed as though it were compiled
    directly.
    Nc	                 C   s  dd }	ddl m}
 ||||f}dd |D }t|rht|sh|	|d |	|d |	|d	 |	|d
 nt|rz|	|d |
j| _|| _|| _|| _|| _	|| _
|| _td| _||f}dd |D }t|rt|sd}t|| t| | _|| _|| _dS )a1  
        Instantiate a new InlineWorker, all arguments are optional though some
        must be supplied together for certain use cases. The methods will refuse
        to run if the object isn't configured in the manner needed. Args are the
        same as those in a numba.core.Compiler.state, except the validator which
        is a function taking Numba IR and validating it for use when inlining
        (this is optional and really to just provide better error messages about
        things which the inliner cannot handle like yield in closure).
        c                 S   s   | d krt d|d S )Nz{} must not be None)r   format)argr   r/   r/   r0   check@  s    z$InlineWorker.__init__.<locals>.checkr   )DefaultPassBuilderc                 S   s   g | ]}|d k	qS r>   r/   rH   xr/   r/   r0   rL   I  s     z)InlineWorker.__init__.<locals>.<listcomp>	targetctxlocalspipelineflags	typingctxr   c                 S   s   g | ]}|d kqS r>   r/   r   r/   r/   r0   rL   _  s     zKtypemap and calltypes must both be either None or have a value, got: %s, %sN)numba.core.compilerr   anyallZdefine_untyped_pipeline_compiler_pipeliner   r   r   r   r   	validatorrW   rk   r   !_permit_update_type_and_call_mapstypemap	calltypes)rC   r   r   r   r   r   r   r   r   r   r   Zcompiler_argsZcompiler_grouppairZpair_is_noner.   r/   r/   r0   rD   .  s6    




zInlineWorker.__init__c                 C   s  dd }||}| j dk	r$|  | ||}|j}	|j| }
|
j}|j}ttj t|j	 }t
||d }t|}||_t|	 }t|	 }tj| | d t| t|}| d| t|dkst|d }i }t|jj D ]H}|j|krt|jj|j}|	j||jd}|j||jd |||j< q| d	| t|| | d
 t| |jj}t|||j| j|}| j r|dkrt!d| "|| |j}| d t| t#|| g }t$%|	|j}|j|d d |_t& }||j|< |'||f |jd| |_|j't$(||
j t)|}t*||
j+| |
j+j|j,kr||j,|
j+j kr|j,|
j+j -| |D ]6}|| }|	|_t.|| ||j|< |'||f q| d t| ||||fS )a   Inlines the callee_ir in the caller_ir at statement index i of block
        `block`, callee_freevars are the free variables for the callee_ir. If
        the callee_ir is derived from a function `func` then this is
        `func.__code__.co_freevars`. If `arg_typs` is given and the InlineWorker
        instance was initialized with a typemap and calltypes then they will be
        appropriately updated based on the arg_typs.
        c                 S   sn   |   }i |_| j D ]P\}}t | j| }g |_| j| jD ]}t |}|j| qB||j|< q|S r>   )copyr#   rV   deepcopyrG   rd   )Zthe_irZkernel_copyZblock_labelrl   	new_blockr-   Zscopyr/   r/   r0   copy_irs  s    
z'InlineWorker.inline_ir.<locals>.copy_irNrM   After relabelcallee_scopes = r   r!   var_dict = After local var renamez%arg_typs should have a value not NoneAfter arguments rename: After merge in)/r   scoperG   r(   r#   maxr   _the_max_labelr{   rb   r   r   minupdaterk   ra   _get_all_scopesrF   AssertionErrorr   	localvars_conr$   r   r<   r   unique_nameredefiner"   r   r\   _get_callee_argsr   r   update_type_and_call_maps_replace_args_withr   Blockr
   rd   Jumpr   _replace_returnsr   r   remove_add_definitions)rC   	caller_irrl   rm   	callee_irZcallee_freevarsarg_typsr   Zcallee_ir_originalr   rn   	call_exprcallee_blocks	max_label	min_labelcallee_scopescallee_scopevar_dictvarr:   new_varZcallee_funcr   
new_blocksr   	new_label
topo_orderlabelr/   r/   r0   	inline_irh  s    




 








zInlineWorker.inline_irc                 C   s(   |  |}|jj}| j||||||dS )a   Inlines the function in the caller_ir at statement index i of block
        `block`. If `arg_typs` is given and the InlineWorker instance was
        initialized with a typemap and calltypes then they will be appropriately
        updated based on the arg_typs.
        )r   )run_untyped_passesr   co_freevarsr   )rC   r   rl   rm   functionr   r   Zfreevarsr/   r/   r0   inline_function  s
    
zInlineWorker.inline_functionFc           
      C   s   ddl m}m} ddlm} ddlm} ddlm} | }d|_	| j
|_
| j|_| j|_| j|_| j|_||j_|j||_d|_d|_d|_|d|_d|_| |_i |_| | t|jjjjtj f |_!| "|}	|	#  |	$| |j	S )a&  
        Run the compiler frontend's untyped passes over the given Python
        function, and return the function's canonical Numba IR.

        Disable SSA transformation by default, since the call site won't be in
        SSA form and self.inline_ir depends on this being the case.
        r   )	StateDict_CompileStatus)ExtractByteCode)bytecode)ParforDiagnosticsNF)%r   r   r   Znumba.core.untyped_passesr   
numba.corer   numba.parfors.parforr   r+   r   r   r   r   r   
enable_ssaZFunctionIdentityfrom_functionr   r   r   Ztype_annotationstatusreturn_typeZparfor_diagnosticsmetadataZrun_passrF   bcpysig
parametersr   Zpyobjectr   r   finalizerT   )
rC   r\   r   r   r   r   r   r   statepmr/   r/   r0   r     s4    


zInlineWorker.run_untyped_passesc                 C   s   ddl m} ddlm} | js*d}t|ddlm} t	|j
|_tjj|| ||}t	|j
|_|| j| j||d\}}}	}
| |}t	|j
|_t|||	| j dd |D }|D ]}|| q| j| | j|	 dS )	z_ Updates the type and call maps based on calling callee_ir with
        arguments from arg_typsr   )reconstruct_ssa)PreLowerStripPhisz_InlineWorker instance not configured correctly, typemap or calltypes missing in initialization.typed_passesNc                 S   s   g | ]}| d r|qS zarg.
startswithrH   Zvnamer/   r/   r0   rL   7  s     
 z:InlineWorker.update_type_and_call_maps.<locals>.<listcomp>)Znumba.core.ssar  Znumba.core.typed_passesr  r   r   r   r  r   build_definitionsr#   r   r   r   analysisdead_branch_prunetype_inference_stager   r   Z_strip_phi_nodesr   rX   r   r   r   )rC   r   r   r  r  r.   r  	f_typemapZ_f_return_typef_calltypesr4   	arg_namesr   r/   r/   r0   r     s@          z&InlineWorker.update_type_and_call_maps)N)N)F)
r   r   r   r   r1   rD   r   r   r   r   r/   r/   r/   r0   r   &  s   
; 


*r   c           -   
      s  |j }|j| }|j}td}|d|d| t|dr<|jn|j}t|drR|jn|j}t	|t
jrddlm} |j|dd	}n
t||}|d
k	r|| |j}ttj t| j }t||d }t|}||_t| }t| }tj| |d t| t|}|d| t|dks.t|d }i }|jj  D ]>}|j!|j"krFt#|j$j%|j!}|j&||j'd}|||j!< qF|d| t(|| |d t| t)|||j| j'| }|d t| |r|r| *|}|d| t	|t+r.t,j-j. t,j/ _0t,j/f _1t+ fdd|D } n$t	|t2j3rH|j4dksLt|j5} t|j"t| ksjtt6||  |d t| |rJddlm7}! t8|j|_9t:j;j<=|| z|!>||||d
\}"}#}$}%W n0 t?k
r   |!>||||d
\}"}#}$}%Y nX t@||"|$| dd |"D }&|&D ]}'|"A|' q$||" |	|$ tB|| g }(t2C||j'})|j|d d
 |)_tD }*|)| j|*< |(E|*|)f |jd
| |_|jEt2F||j' tG|}+tH||jI|* |jIj!| j9kr|| j9|jIj! kr| j9|jIj! J| |+D ]6},||, }||_ tK| | || j|,< |(E|,|f q|d t|  |
d
k	rx|(D ]}|
E| qf||fS )a  Inline the body of `callee` at its callsite (`i`-th instruction of
    `block`)

    `func_ir` is the func_ir object of the caller function and `glbls` is its
    global variable environment (func_ir.func_id.func.__globals__).
    `block` is the IR block of the callsite and `i` is the index of the
    callsite's node. `callee` is either the called function or a
    make_function node. `typingctx`, `typemap` and `calltypes` are typing
    data structures of the caller, available if we are in a typed pass.
    `arg_typs` includes the types of the arguments at the callsite.
    `callee_validator` is an optional callable which can be used to validate the
    IR of the callee to ensure that it contains IR supported for inlining, it
    takes one argument, the func_ir of the callee

    Returns IR blocks of the callee and the variable renaming dictionary used
    for them to facilitate further processing of new blocks.
    r   zFound closure call: z with callee = r   closurer   )compilerT)Zinline_closuresNrM   r   r   r!   r   r   r   zcallee's closure = c                 3   s   | ]} |V  qd S r>   r/   r   Zcellgetr/   r0   	<genexpr>  s     z&inline_closure_call.<locals>.<genexpr>build_tuplezAfter closure renamer  c                 S   s   g | ]}| d r|qS r  r  r
  r/   r/   r0   rL     s     
 z'inline_closure_call.<locals>.<listcomp>r   )Lr   rG   r(   rW   r   r   r   r  __closure__r'   pytypesFunctionTyper   r  Zrun_frontendr   r#   r   r   r   r{   rb   r   r   r   r   ra   r   rF   r   r   r   r$   r   r   r<   r   r   r   r"   r   r   r   r   ctypesZ	pythonapiZ
PyCell_GetZ	py_objectrestypeZargtypesr   rZ   r[   rV   _replace_freevarsr  r  r   r   r   r  r  r  	Exceptionr   rX   r   r   r
   rd   r   r   r   r   r   r   )-r+   Zglblsrl   rm   calleer   r   r   r   r   rj   r   Zreplace_freevarsr   rn   r   rk   Zcallee_codeZcallee_closurer  r   r   r   r   r   r   r   r   r:   r   r   r  rV   r  r  Zf_return_typer  r4   r  r   r   r   r   r   r   r/   r  r0   r   >  s    


 





           






r   c                    s  | j dkr.t| j}| jrfd}t|| jn8| j dkrB| jg}n$t	| rV| 
 }ntd| j td}t|tjrtjj|}dd }fdd}	d	d
 }
| j dkrt| j}ni }tjj|||||	|
S t|dr|jn|j}|r|d| t|trPg }|D ]4}t|tjr.|| n|tj |d q|| }nrt|tjsjt|t!r "|}t|tj#st$|j dkst$ fdd|j%D }|| }nt&d||S dS )zGet arguments for calling 'callee', including the default arguments.
    keyword arguments are currently only handled when 'callee' is a function.
    rE   z,Calling a closure with *args is unsupported.getattrzUnsupported ir.Expr.{}z$inline_closure_call default handlingc                 S   s   |S r>   r/   indexparamdefaultr/   r/   r0   rO     rP   z"_get_callee_args.<locals>.<lambda>c                    s   t | S r>   )r   Constr   r!   r/   r0   rO     rP   c                 S   s   t d| |d S )Nz.Stararg not supported in inliner for arg {} {})NotImplementedErrorr   r   r/   r/   r0   stararg_handler  s     z)_get_callee_args.<locals>.stararg_handlerdefaultszdefaults = r(   r"   r  c                    s   g | ]}  |qS r/   r   r   r+   r/   r0   rL     s   z$_get_callee_args.<locals>.<listcomp>z)Unsupported defaults to make_function: {}N)'r[   rU   r   varargr   r*   r"   r(   r   Zis_operator_or_getitem	list_varsr   r   rW   r'   r  r  r   r   utilsZpysignaturer   r   r   Zfold_argumentsr   r'  __defaults__r   r   Varrd   r$  strr   rZ   r   rV   r%  )r   r  r"   r+   r   r.   rk   r   Znormal_handlerZdefault_handlerr&  r   Zcallee_defaultsZdefaults_listr   Zdefault_tupleZ
const_valsr/   )r+   r"   r0   r     sn    






    




r   c                    s    fdd}|S )Nc                     s*   t jr&t d ddd | D   d S )Nz:  c                 s   s   | ]}t |V  qd S r>   )r0  r   r/   r/   r0   r  %  s     z9_make_debug_print.<locals>.debug_print.<locals>.<genexpr>)r   DEBUG_INLINE_CLOSUREprintjoin)r   prefixr/   r0   rk   #  s    z&_make_debug_print.<locals>.debug_printr/   )r6  rk   r/   r5  r0   rW   "  s    rW   c                 C   s   t jr|   d S r>   )r   r2  dumpr*  r/   r/   r0   ra   )  s    ra   c                 C   s0   g }|   D ]\}}|j|kr||j q|S )z+Get all block-local scopes from an IR.
    )rV   r   rd   )r#   Z
all_scopesr   rl   r/   r/   r0   r   .  s
    
r   c                 C   s\   |   D ]N\}}|tj}|D ]4}t|jtjr |jj}|t|k sJt	|| |_q qdS )z@
    Replace ir.Arg(...) with real arguments from call site
    N)
rV   r%   r   r&   r'   r(   ZArgr!  rF   r   r#   r   r   rl   assignsr-   idxr/   r/   r0   r   8  s    r   c                 C   s   |   D ]t\}}|tj}|D ]Z}t|jtjr |jj}|t|k sJt	t|| tj
rf|| |_q t|| |j|_q qdS )zJ
    Replace ir.FreeVar(...) with real variables from parent function
    N)rV   r%   r   r&   r'   r(   r   r!  rF   r   r/  r$  r"   r8  r/   r/   r0   r  E  s    r  c           	      C   s   |   D ]\}}g }tt|jD ]}|j| }t|tjr|d t|jksRtt|j	||j
|j|< |jt||j
 |D ]}|jj|j	jkr|j	j	|_	qq"t|tjr"t|j	tjr"|j	jdkr"|| q"qdS )zN
    Return return statement by assigning directly to target, and a jump.
    rM   castN)rV   rangerF   rG   r'   r   Returnr   r&   r(   r"   rd   r   r   r   rZ   r[   )	r#   r   Zreturn_labelr   rl   Zcastsrm   r-   r;  r/   r/   r0   r   U  s"    

r   c                 C   s4   | j }|tj}|D ]}||jj |j qdS )zF
    Add variable definitions found in a block to parent func_ir.
    N)r   r%   r   r&   r   r   rd   r(   )r+   rl   Zdefinitionsr9  r-   r/   r/   r0   r   k  s    r   c                 C   s2  d}d}d}d}|t |jk r|j| }t|tjrT|r|r|j|jkrd}qnt|tjr|j}|j}t	t
| |dkrt|jd tjr|jd }|}|}	t|j}
nRt|tjrt|jtjr|s|j}|j}t| |}tt	t| | |}	i }
nq|d }qt|o| td|j|	  ||	|
fS )zLook for statement like "x = numpy.array(y)" or "x[..] = y"
    immediately after the closure call that creates list y (the i-th
    statement in block).  Return the statement index if found, or
    raise GuardException.
    NFr   T)arraynumpyrM   Zfind_array_call)rF   rG   r'   r   Delr(   r   r&   r   r   r   r   r/  r   r   SetItemr   r   _find_unsafe_empty_inferredrW   )r+   rl   	array_varZlist_var_dead_after_array_calllist_varrm   rn   r   ro   Zarray_stmt_index	array_kwsZ	array_defr/   r/   r0   _find_arraycallu  sJ    



rF  c                 C   sZ  t d}t| |}|d|d| tt|tjo6|jdk |j}t| |}|d|d| tt|tjon|jdk |j}t| |}|d|d	| tt|tj	o|jt
kp|jtjjjk t|j}	d
|jjg}
|	dkr
|
||jj< t| |jd dd}d|jd |fS |	dkrR|
||jj< t| |jd dd}t| |jd dd}|||fS tdS )zzFind the iterator's actual range if it is either range(n), or
    range(m, n), otherwise return raise GuardException.
    Zfind_iter_rangezrange_iter_var =  def = Zgetiterzrange_var = z range_def = rE   zfunc_var = z func_def = )z"array comprehension"z
closure ofrM   r   TZlhs_onlyrx   N)rW   r   r   r'   r   rZ   r[   r(   r\   r   r<  r   miscspecialZprangerF   r   r"   r   r   )r+   Zrange_iter_varr@   rk   Zrange_iter_defZ	range_var	range_defr   rq   nargsZswappingstopstartr/   r/   r0   _find_iter_range  s:    







rO  Fc           <         s  t d}tt|jdk tt|j}t| | j| \}	}
}d}d}d|krtt|d t	j
 t| |d }tt|t	jo|jdk t| |j}t| |	}|d|	d| t|t	jr|jdkrt| |j}tt|t	jo|jd	k tt|jd
k g }|jD ]} fdd||D }t|s0q| j| }|d| |t	jD ]}|j}t|t	jrP|jdkrPt| |j}t|t	jrP|jdkrP|jdkrPt| |j}|d|||k ||krP||||f qPqtt|dk |d
 \}}}tdd ||jD }|d||jt|gB  t||jt|gB k g }g }| j|j }|t	jD ]b}|j}t|t	jrl|jdkrt| |j}|d| ||j n|jdkrl||j qltt|dkot|dk |d
 }|d
 } tt|jdk | jtt|j }!|!j}"|!j}#|!j}$g }%g }&dd }'t t|!jd D ]P}(|!j|( }t|t	jr|j|ks|'|j|&r|&|j n
|%| qX|d|& t!t"| ||})|##d|$}*|)r|)d
 d
kr| }*n|%t$| |*t	j%d|$d|$ |##d|$}+|)rj|)\},}-}.|,d
kr2|-}/nt	jj&t'j(|-|,|$d}/|rt|.t	j)rd|._*t+|._nZ|r|##d |$}0d
d!l,m-}1 |%t$| |0t	j)d"|1|$d#|$ t	jj.|0|fd$|$d#}/nt/|%t$| |+|/|$ |##d%|$}2|%t$| |2t	jj0|+g|$d&|$ |##d'|$}3|##d(|$}4|r|r|##d)|$}5|##d|$}6|%t$| |5||$ |%t$| |6t	j1|5|j|$|$ |%t$| |4t	j)d*t2j3|$d#|$ d|6fg}n0|r|%t$| |4t	j)d+t4|$d#|$ g }nt/|%t$| |3t	jj.|4|2ft5||$d#|$ |&D ]}7|%t$| |7|3|$ q|%|" |%|!_|)r|)d
 d
kr<|j}"t|"t	j6s\t7|"j8}8| j|8 }9|9j}$|9j9d
t$| |*t	jj&t'j(| |)d
 |$d|$ n|j}$|j}"|jd
d }%|##d,|$}:|##d-|$};|%t$| |;t	j%d|$d|$ |%t$| |:t	jj&t'j:|*|;|$d|$ |%t$| |*|:|$ |%|" |%|_t t|jD ]@}(|j|( |krJ|d. t	j;|3|*|jj<d
 |jd/|j|(< qJ| j| j|
 }t|t	jrt|jt	jr|3|_|jg| j=|jj*< d0S )1a  Look for array(list) call in the exit block of a given loop, and turn
    list operations into array operations in the loop if the following
    conditions are met:
      1. The exit block contains an array call on the list;
      2. The list variable is no longer live after array call;
      3. The list is created in the loop entry block;
      4. The loop is created from an range iterator whose length is known prior
         to the loop;
      5. There is only one list_append operation on the list variable in the
         loop body;
      6. The block that contains list_append dominates the loop head, which
         ensures list length is the same as loop length;
    If any condition check fails, no modification will be made to the incoming
    IR.
    Zinline_arraycallrM   Ndtyper  zlist_var = rG  r;  
build_listr   c                    s   g | ]}|j  kqS r/   )header)rH   lrs   r/   r0   rL     s     z%_inline_arraycall.<locals>.<listcomp>zcheck loop body block rE   rd   zlist_def = c                 s   s   | ]\}}|V  qd S r>   r/   )rH   rS  br/   r/   r0   r    s     z$_inline_arraycall.<locals>.<genexpr>zpreds = Ziternextziter_def = Z
pair_firstc                 S   s,   t | tjr(|D ]}|j| jkr dS qdS )NTF)r'   r   r/  r   )valremovedr   r/   r/   r0   
is_removed<  s
    z%_inline_arraycall.<locals>.is_removedzremoved variables: r!  r(  size)fnr   rhsr"   r	   Zlen_func)length_of_iteratorr]  r!   r/   
size_tuplerV   r"   r>  
empty_funcZ	dtype_modemptyunsafe_empty_inferredZ
next_indexonezReplace append with SetItem)r   r!  r(   r"   T)>rW   r   rF   Zexitsr{   rz   rF  r#   r'   r   r/  r   rZ   r[   r(   rV   rG   Zin_loopsr   r%   r&   r\   attrrd   setZpredecessorsrR  entriesr   
terminatorr   r"   r<  r   rO  r   _new_definitionr$  Zbinopoperatorsubr   r   r	   Znumba.cpython.rangeobjr]  rE   r   r  r  npra  rb  rU   ZBranchr   ZtruebrinsertaddrA  r   r   )<r+   rr   rs   loopr@   Zenable_prangerB   rk   Z
exit_blockrD  Zarray_call_indexrE  Z	dtype_defZdtype_mod_defZlist_var_defZlist_append_stmtsr   Zin_visited_loopsrl   r-   ro   rq   Zlist_defZappend_block_labelZappend_blockZappend_stmtpredsZ	iter_varsZiter_first_varsZloop_headerZiter_defZiter_varZiter_first_varZ
loop_entryrg  r   r"   stmtsrW  rX  rm   rK  	index_varsize_varrN  rM  Zrange_func_defZsize_valZlen_func_varr]  size_tuple_varrC  r`  Zdtype_mod_varZ	dtype_varr   Zblock_idr,   Znext_index_varrc  r/   rT  r0   re     s    











 



          


  
 

 
 re   c                 C   sV   t  tt|tjo|jdk |j}t| |}tt|tj t	d|j
 |j
t kS )NrE   rB  )rb  r   r'   r   rZ   r[   r\   r   r   rW   r(   )r+   ro   r  Z
callee_defr/   r/   r0   rB    s    
rB  c                    s   j  t }t tdd   D }t| j|fdd fddfdd}tj D ]0}j | }|jD ]}t	||r|j
| qqvd	S )
zLook for assignment like: a[..] = b, where both a and b are numpy arrays,
    and try to eliminate array b by expanding a with an extra dimension.
    c                 S   s   g | ]}|t  fqS r/   )re  )rH   r   r/   r/   r0   rL     s     z%_fix_nested_array.<locals>.<listcomp>c                    sP   t | }td| | t|tjrHtt|r4|S |jdkrH |jS t	dS )zFind numpy array definition such as
            arr = numba.unsafe.ndarray.empty_inferred(...).
        If it is arr = b[...], find array definition of b recursively.
        find_array_defgetitemN)
r   rW   r'   r   rZ   r   rB  r[   r(   r   )ZarrZarr_def)rt  r+   r/   r0   rt    s    


z)_fix_nested_array.<locals>.find_array_defc                    sl  t d}  D ]P\}}|j}|j}t }tt|D ]&}|| }	t|	tj	r8|
|	jj |	j| kr8g }
|D ]}|j|ks|j| kr|jj| kr||jd |
| qr||jd t|j}t|tjrN|j}|d|}t|j|}t|||}g }||d|  || |||d  ||_|
| qrtqr|
    S q8qtdS )zDouble check if all variables in varlist are defined before
        expr is used. Try to move constant definition when the check fails.
        Bails out by raising GuardException if it can't be moved.
        fix_dependenciesz already definedz not yet definedr   N)rW   rV   r   rG   re  r<  rF   r'   r   r&   rm  r   r   r(   defmaprd   r   r$  r"   r   rh  extendr   )ro   Zvarlistrk   r   rl   r   rG   Zdefinedrm   instZnew_varlistr   Zvar_defr"   r   Z	new_constZ
new_vardefnew_body)r#   r+   livemapusedefsr/   r0   rv    sP    

   
z+_fix_nested_array.<locals>.fix_dependenciesc                    s  t t| tj t t| jtj td}|d|  | j} |}|d| t| j}|d| t t|tj	 |j
dkrt|j}t t|tj	 t t| t|jd }t t|tj	o|j
dk |d| fd	d
|jD }|d| t|jd }t t|tj	o |j
dk |d| ||}| j|7  _d|_
tj|_t|dd|_| j|_|jd= |jd= |jd= |jd= dS )a  For assignment like lhs[idx] = rhs, where both lhs and rhs are
        arrays, do the following:
        1. find the definition of rhs, which has to be a call to
           numba.unsafe.ndarray.empty_inferred
        2. find the source array creation for lhs, insert an extra dimension of
           size of b.
        3. replace the definition of
           rhs = numba.unsafe.ndarray.empty_inferred(...) with rhs = lhs[idx]
        fix_array_assignzfound SetItem: zfound lhs_def: zfound rhs_def: r;  r   r  z
dim_def = c                    s   g | ]}t  |d dqS )TrH  r)  r   r*  r/   r0   rL   M  s   z?_fix_nested_array.<locals>.fix_array_assign.<locals>.<listcomp>zextra_dims = zsize_tuple_def = ru  TrH  r\   r   r+  r   )r   r'   r   rA  r(   r/  rW   r   r   rZ   r[   rB  r   rV   ri  ru  r[  r!  Z_kws)r-   rk   r   Zlhs_defZrhs_defZdim_defZ
extra_dimsZsize_tuple_def)rt  rv  r+   r/   r0   r}  0  sJ    









z+_fix_nested_array.<locals>.fix_array_assignN)r#   r   r   r   rb   r   rw  r   rG   r   r   )r+   rr   Zempty_deadmapr}  r   rl   r-   r/   )r#   rt  rv  r+   r{  r|  r0   rg     s    -3


rg   c                 C   s   |g| j |j< tj|||dS )N)r(   r   r"   )r   r   r   r&   )r+   r   r(   r"   r/   r/   r0   rh  j  s    rh  zafter-inferencec                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )RewriteArrayOfConstszThe RewriteArrayOfConsts class is responsible for finding
    1D array creations from a constant list, and rewriting it into
    direct initialization of array elements without creating the list.
    c                    s   |j | _ tt| j|| d S r>   )r   superr~  rD   )rC   r  r   r   	__class__r/   r0   rD   u  s    zRewriteArrayOfConsts.__init__c                 C   s6   t |dkrdS || _tt||| j||| _| jd k	S )Nr   F)rF   
crnt_blockr   _inline_const_arraycallr   rz  )rC   r+   rl   r   r   r/   r/   r0   matchy  s      zRewriteArrayOfConsts.matchc                 C   s   | j | j_| jS r>   )rz  r  rG   rC   r/   r/   r0   apply  s    
zRewriteArrayOfConsts.apply)r   r   r   r   rD   r  r  __classcell__r/   r/   r  r0   r~  o  s   r~  c                    s.  t d| j fdd}G dd dt}| }| jD ]}t|tjr"t|jtjr|jj	|j
kr|j
|jj	 |j| q@nt|jtjr|j}	|	jdkr|  dd |	jD |_|jj	g|_
|j| q@n:|	jd	kr|	 krt||j|	|j|j
|jrd
|_q@nt|tjr|j}
|
|jkrR|j| q@n|
|j
kr|j|
 |j
|
 |j| |j
g krg }|jD ]N}t|tjr|jj	|jkst|tjr|j|jkrڐq|| q||_g |_d
|_q@|j| ||r@|  q@|jr*|jS dS )a|  Look for array(list) call where list is a constant list created by
    build_list, and turn them into direct array creation and initialization, if
    the following conditions are met:
      1. The build_list call immediate precedes the array call;
      2. The list variable is no longer live after array call;
    If any condition check fails, no modification will be made.
    Zinline_const_arraycallc              
      s  t t|}t|o(|d dko(|d dk t|jd j|k  | j}tt|tjo`|j	dk |j
}|jd }| j }	d| d| |	j}
t|\}}t|}d|}d|}tj}t|d}||j< ||j< |t|tj||d	| |t|tjj|g|d
| t|
}d|}ttj}||fd|i ||j< |t|tjdtj|d	| d|}tjt|j< tdt|}|t||| d|}||j< t|
}|dkrd}tj |||}|t||| tjj!|||gi |d	}t"#|	|| |< |t| || t$|D ]r}d|}tj}||j< |t|t||| t%| ||| |}t"#tj&|	||
 |< || q\|'| dS )zCheck to see if the given "array_var" is created from a list
        of constants, and try to inline the list definition as array
        initialization.

        Extra statements produced with be appended to "stmts".
        rM   r?  r   r>  zinline array_var = z list_var = rZ  r^  r!   r_  r`  rP  ra  z	$np_g_varrk  z$np_typ_varboolZbool_r!  T)(r   r   r   r   r   r   r'   r   ZArrayCompatiblendimr"   rP  r   rF   r   ZintpZUniTuplerd   rh  r   r$  rZ   r  ZDTyper   rk  ra  Zresolve_function_typer   rI  Moduler0  r  rE   r   	signaturer<  rA  nonerx  )rC  ro   rp  r,  delsZcallnameZret_typer"   rD  Z	array_typrP  seqr4   rZ  rr  rs  Zsize_typZsize_tuple_typZnptyper`  ZfntyZg_np_varZg_npZtyp_varZ	dtype_strZnp_typ_getattrZ
empty_callrm   rq  Z	index_typsetitemr   contextrk   r+   r   r   r/   r0   inline_array  s     




 	


 




 
z-_inline_const_arraycall.<locals>.inline_arrayc                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	z&_inline_const_arraycall.<locals>.Statez
        This class is used to hold the state in the following loop so as to make
        it easy to reset the state of the variables tracking the various
        statement kinds
        c                 S   s(   g | _ g | _g | _g | _g | _d| _d S )NF)r,  	dead_vars
list_itemsrp  r  ri   r  r/   r/   r0   rD     s    z/_inline_const_arraycall.<locals>.State.__init__c                 S   s   g | _ g | _g | _g | _dS )zV
            Resets the internal state of the variables used for tracking
            N)r,  r  r  r  r  r/   r/   r0   reset  s    z,_inline_const_arraycall.<locals>.State.resetc                    s   t  fdd| D S )z
            Returns True if the list being analysed is used between the
            build_list and the array call.
            c                    s   g | ]}|j  jkqS r/   )r   r,  r   r  r/   r0   rL     s     zH_inline_const_arraycall.<locals>.State.list_var_used.<locals>.<listcomp>)r   r,  )rC   ry  r/   r  r0   list_var_used  s    z4_inline_const_arraycall.<locals>.State.list_var_usedN)r   r   r   r   rD   r  r  r/   r/   r/   r0   State  s   	r  rQ  c                 S   s   g | ]
}|j qS r/   )r   r   r/   r/   r0   rL   &  s     z+_inline_const_arraycall.<locals>.<listcomp>rE   TN)rW   r   objectrG   r'   r   r&   r(   r/  r   r,  rd   r   rp  rZ   r[   r  rV   r  r   r  ri   r@  r  r   r  )rl   r+   r  r   r   r  r  r  ry  ro   Zremoved_varrG   r/   r  r0   r    sr    `'

  




r  )NNNNNNNT)FF)Gr   r  r   r  Znumba.core.analysisr   r   r   r   r   r   r   r   r   r	   Znumba.core.ir_utilsr
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Znumba.np.unsafe.ndarrayr    rb  r?  rk  ri  Znumba.misc.specialr`   r1   r<   r  r=   r   r   r   r   rW   ra   r   r   r  r   r   rF  rO  re   rB  rg   rh  Zregister_rewriteZRewriter~  r  r/   r/   r/   r0   <module>   sh   $P
 K              
  E

1"  
  
