B
     \                 @   s  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 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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Z-G d	d
 d
e.Z/dd Z0d/ddZ1dd Z2dd Z3dd Z4dd Z5dd Z6dd Z7dd Z8dd Z9dd  Z:d0d"d#Z;d$d% Z<d&d' Z=d(d) Z>e	?d*G d+d, d,e	j@ZAd-d. ZBdS )1    N)configirir_utilsutilsprangerewritestypestyping)internal_prange)mk_unique_var
next_labeladd_offset_to_labelsreplace_varsremove_delsremove_dead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)compute_cfg_from_blockscompute_use_defscompute_live_variables)range_iter_len)empty_inferredTc               @   sL   e Zd ZdZi 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.
    c             C   s   || _ || _|| _g | _d S )N)func_irparallel_optionsswapped_processed_stencils)selfr$   r%   r&    r)   7lib/python3.7/site-packages/numba/inline_closurecall.py__init__0   s    zInlineClosureCallPass.__init__c          	      s  d}t | jj }td}|d x|r| \}}xt|jD ]\}}t|t	j
rB|j}|j}	t|	t	jrB|	jdkrBtt| j|	}
tt| j|	j}t| j||||	|
rd}P t| j||||rd}P t| j||
|rBd}qBW q&W tr|rt| jj t| jj}|d t| |   fdd  D }g }xPt|d	d
 ddD ]:\}}|| tt| j|| | | j| j j!rLd}qLW |rt"| j |rt#| jj xt$| jj| jj%| jrʐqW t&| jj| j_|d dS )z&Run inline closure call pass.
        Fr#   ZSTARTcallTzstart inline arraycallc                s   g | ]}|t  | jfqS r)   )lenbody).0k)loopsr)   r*   
<listcomp>^   s    z-InlineClosureCallPass.run.<locals>.<listcomp>c             S   s   | d S )N   r)   )tupr)   r)   r*   <lambda>a   s    z+InlineClosureCallPass.run.<locals>.<lambda>)keyreverseZENDN)'listr$   blocksitems_make_debug_printpop	enumerater.   
isinstancer   AssigntargetvalueExpropr   r   r   func_inline_reduction_inline_closure_inline_stencilenable_inline_arraycallr   r   _debug_dumpr1   keyssortedappend_inline_arraycallr&   r%   Zcomprehension_fix_nested_arrayr   r   	arg_namesr   )r(   modified	work_listdebug_printlabelblockiinstrlhsexpr	call_namefunc_defcfgZsized_loopsvisitedr0   sr)   )r1   r*   run6   s^    




zInlineClosureCallPass.runc             C   st   t | jj  t |dkp|dk t|jdkr8tdt| j|jd  dd }t| j| jj	j
j||||d d	S )
N)reducebuiltins)r_   
_functools   zEinvalid reduce call, three arguments including initial value requiredr   c             S   s(   |}t |}x|D ]}| ||}qW |S )N)iter)fAvr]   itar)   r)   r*   reduce_func~   s
    
z<InlineClosureCallPass._inline_reduction.<locals>.reduce_func)rQ   T)r   r%   Z	reductionr-   args	TypeErrorcheck_reduce_funcr$   inline_closure_callfunc_idrD   __globals__)r(   rQ   rT   rU   rX   rY   ri   r)   r)   r*   rE   s   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)rq   znumba.stencil)rq   numbar3   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.stencilrp   r@   rA   r>   r   Globalnamekwsr   r'   rL   r-   rj   
ValueErrorr   r   r$   rB   rC   r   rn   rD   ro   codedict_fix_stencil_neighborhood_fix_stencil_index_offsetsloc_definitions)r(   rV   rY   rZ   rp   rW   rX   Zstencil_defZ	kernel_iroptionsZfixedZsfZ	sf_globalr)   r)   r*   rG      sH    






z%InlineClosureCallPass._inline_stencilc             C   sl   t | j|d }tt|d g }x8|jD ].}t | j|}tt|d |t|j q*W t||d< dS )z
        Extract the two-level tuple representing the stencil neighborhood
        from the program IR to provide a tuple to StencilFunc.
        rt   r:   T)r   r$   r   hasattrr:   rL   tuple)r(   r   Zdims_build_tupleZresZ
window_varZwin_build_tupler)   r)   r*   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.
        ru   r:   T)r   r$   r   r   r   r:   )r(   r   Zoffset_tupler)   r)   r*   r}      s    z0InlineClosureCallPass._fix_stencil_index_offsetsc             C   s<   t t|tjo|jdk t| j| jjjj	||||d dS )Nrs   )rQ   T)
r   r>   r   rB   rC   rm   r$   rn   rD   ro   )r(   rQ   rT   rU   rZ   r)   r)   r*   rF      s    
z%InlineClosureCallPass._inline_closureN)__name__
__module____qualname____doc__r+   r^   rE   rG   r|   r}   rF   r)   r)   r)   r*   r#   +   s   =.
r#   c             C   sd   t t| |}|d krtdt|ds8t|ds8tdt|drH|jn|j}|jdks`tdd S )NzMReduce function cannot be found for njit                             analysisrz   __code__zInvalid reduction function   z*Reduction function should take 2 arguments)r   r   ry   r   rz   r   co_argcountrk   )r$   func_varri   f_coder)   r)   r*   rl      s    


rl   c
       )   	      s  |j }
|j| }|j}td}|d|d| t|dr<|jn|j}t|drR|jn|j}t|drh|j	n|j
}t||}|j}ttjt| j }t||d }t|}||_t| }t| }|t_|d t| t|}|d	| t|dkst|d
 }i }xD|jj D ]4}|j|jkr|
jt|j|jd}|||j< qW |d| t || |d t| t!|j"}|r|d| t#|t$r|t!| }ndt#|t%j&st#|t'r| (|}t#|t%j)st|j|fdd|jD  }nt*d+||d t| |r| (|}|d| t#|t$rxt,j-j. t,j/ _0t,j/f _1t$ fdd|D }n$t#|t%j2r|j3dkst|j4}t|jt|kstt5|| |d t| |rrd
dl6m7} y|8|||d\}} }!W n, t9k
r&   |8|||d\}} }!Y nX t:|||!| dd |D }"x|"D ]}#|;|# qJW |<| |<|! t=|| g }$t%>|
|j}%|j|d d |%_t? }&|%| j|&< |$@|&|%f |jd| |_|j@t%A||j tB|}'tC||jD|& |jDj| jEkr4|| jE|jDj kr4| jE|jDj F| x>|'D ]6}(||( }|
|_ tG| | || j|(< |$@|(|f q:W |d t|  |	dkrx|$D ]}|	@| qW |S )aB  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.
    rm   zFound closure call: z with callee = rz   defaultsclosurer3   zAfter relabelzcallee_scopes = r   )r~   zvar_dict = zAfter local var renamezdefaults = c                s   g | ]}t j| d qS ))rA   r~   )r   Const)r/   rf   )r~   r)   r*   r2   (  s   z'inline_closure_call.<locals>.<listcomp>z)Unsupported defaults to make_function: {}zAfter arguments rename: zcallee's closure = c             3   s   | ]} |V  qd S )Nr)   )r/   x)cellgetr)   r*   	<genexpr>8  s    z&inline_closure_call.<locals>.<genexpr>build_tuplezAfter closure rename)compilerNc             S   s   g | ]}| d r|qS )zarg.)
startswith)r/   Zvnamer)   r)   r*   r2   N  s    zAfter merge in)Hscoper.   rA   r;   r   rz   r   r   __defaults__r   __closure__r   r9   maxr   Z
_max_labelrJ   r   r   minrI   _get_all_scopesr-   AssertionErrorZ	localvarsZ_convaluesrw   co_freevarsZdefiner   r~   r   r8   rj   r>   r   r   Varstrr   r   NotImplementedErrorformatctypesZ	pythonapiZ
PyCell_GetZ	py_objectZrestypeZargtypesrB   rC   r:   _replace_freevarsrr   r   Ztype_inference_stageBaseExceptionr   r<   update_replace_args_withZBlockr   rL   Jumpr   _replace_returnsr@   r   remove_add_definitions))r$   ZglblsrT   rU   callee	typingctxZarg_typstypemap	calltypesrQ   r   rV   Z	call_exprrR   Zcallee_codeZcallee_defaultsZcallee_closureZ	callee_irZcallee_blocksZ	max_labelZ	min_labelZcallee_scopesZcallee_scopeZvar_dictvarnew_varrj   r   r   r:   r   Z	f_typemapZf_return_typeZf_calltypesrO   rh   Z
new_blocksZ	new_blockZ	new_labelZ
topo_orderrS   r)   )r   r~   r*   rm      s    





















rm   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 )N)r   )r/   r   r)   r)   r*   r   |  s    z9_make_debug_print.<locals>.debug_print.<locals>.<genexpr>)r   DEBUG_INLINE_CLOSUREprintjoin)rj   )prefixr)   r*   rR   z  s    z&_make_debug_print.<locals>.debug_printr)   )r   rR   r)   )r   r*   r;   y  s    r;   c             C   s   t jr|   d S )N)r   r   dump)r$   r)   r)   r*   rI     s    rI   c             C   s4   g }x*|   D ]\}}|j|kr||j qW |S )z+Get all block-local scopes from an IR.
    )r:   r   rL   )r9   Z
all_scopesrS   rT   r)   r)   r*   r     s
    
r   c             C   sd   x^|   D ]R\}}|tj}x<|D ]4}t|jtjr$|jj}|t|k sNt	|| |_q$W q
W dS )z@
    Replace ir.Arg(...) with real arguments from call site
    N)
r:   
find_instsr   r?   r>   rA   ZArgindexr-   r   )r9   rj   rS   rT   assignsstmtidxr)   r)   r*   r     s    
r   c             C   s   x|   D ]x\}}|tj}xb|D ]Z}t|jtjr$|jj}|t|k sNt	t|| tj
rj|| |_q$t|| |j|_q$W q
W dS )zJ
    Replace ir.FreeVar(...) with real variables from parent function
    N)r:   r   r   r?   r>   rA   ZFreeVarr   r-   r   r   r   r~   )r9   rj   rS   rT   r   r   r   r)   r)   r*   r     s    
r   c       	      C   s   x|   D ]\}}g }xtt|jD ]}|j| }t|tjr|d t|jksVtt|j	||j
|j|< |jt||j
 xX|D ]}|jj|j	jkr|j	j	|_	qW q&t|tjr&t|j	tjr&|j	jdkr&|| q&W q
W dS )zN
    Return return statement by assigning directly to target, and a jump.
    r3   castN)r:   ranger-   r.   r>   r   ZReturnr   r?   rA   r~   rL   r   r@   rw   rB   rC   )	r9   r@   Zreturn_labelrS   rT   ZcastsrU   r   r   r)   r)   r*   r     s    

&r   c             C   s8   | j }|tj}x |D ]}||jj |j qW dS )zF
    Add variable definitions found in a block to parent func_ir.
    N)r   r   r   r?   r@   rw   rL   rA   )r$   rT   Zdefinitionsr   r   r)   r)   r*   r     s    
r   c             C   s6  d}d}d}d}d}x|t |jk r
|j| }t|tjrX|rV|rV|j|jkrVd}P nt|tjr|j}|j}	t	t
| |	dkrt|	jd tjr|	jd }|}|}
t|	j}nPt|tjrt|jtjr|s|j}|j}t| |}tt	t| | |}
i }nP |d }qW 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numpyr3   Zfind_array_call)r-   r.   r>   r   DelrA   rw   r?   r@   r   r   rj   r   r{   rx   SetItemr   r   _find_unsafe_empty_inferredr;   )r$   rT   	array_vararray_call_indexZlist_var_dead_after_array_calllist_varrU   rV   rW   rX   Zarray_stmt_index	array_kwsZ	array_defr)   r)   r*   _find_arraycall  sF    


r   c             C   sH  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 t|j}	d
|jjg}
|	dkr|
||jj< t| |jd dd}d|jd |fS |	dkr@|
||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 = z def = Zgetiterzrange_var = z range_def = r,   zfunc_var = z func_def = )z"array comprehension"z
closure ofr3   r   T)lhs_onlyr   N)r;   r   r   r>   r   rB   rC   rA   rD   rv   r   r-   rj   r~   rw   r   )r$   Zrange_iter_varr&   rR   Zrange_iter_defZ	range_var	range_defr   rZ   nargsZswappingstopstartr)   r)   r*   _find_iter_range  s0    





r   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 g }x|jD ]} fd
d||D }t|sq| j| }|d| x|t	jD ]}|j}|j}t|t	jr@|jdkr@t| |j}t|t	jr@|jdkr@|jdkr@t| |j}|d|||k ||kr@||||f q@W qW 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 }xr|t	jD ]b}|j}t|t	jrf|jdkrt| |j}|d| ||j n|jdkrf||j qfW tt|dkot|dk |d }|d } tt|jdk | jtt|j }!|!j}"|!j}#|!j}$g }%g }&dd }'xftt|!jd D ]P}(|!j|( }t|t	jr|j|ks|'|j|&r|&|j n
|%| qVW |d|& t t!| ||})t	
|#t"d|$}*|)r|)d dkr| }*n|%t#| |*t	j$d|$d|$ t	
|#t"d|$}+|)rv|)\},}-}.|,dkr>|-}/nt	jj%t&j'|-|,|$d}/|rt|.t	j(rd|._)t*|._nHt	
|#t"d |$}0|%t#| |0t	j(d!t+|$d"|$ t	jj,|0|fd#|$d"}/|%t#| |+|/|$ t	
|#t"d$|$}1|%t#| |1t	jj-|+g|$d%|$ t	
|#t"d&|$}2t	
|#t"d'|$}3|r|rt	
|#t"d(|$}4t	
|#t"d|$}5|%t#| |4||$ |%t#| |5t	j.|4|j|$|$ |%t#| |3t	j(d)t/j0|$d"|$ d|5fg}
n$|%t#| |3t	j(d*t1|$d"|$ g }
|%t#| |2t	jj,|3|1ft2|
|$d"|$ x"|&D ]}6|%t#| |6|2|$ qW |%|" |%|!_|)r|)d dkrX|j}"t|"t	j3slt4|"j5}7| j|7 }8|8j}$|8j6dt#| |*t	jj%t&j'| |)d |$d|$ n|j}$|j}"|jdd }%t	
|#t"d+|$}9t	
|#t"d,|$}:|%t#| |:t	j$d|$d|$ |%t#| |9t	jj%t&j7|*|:|$d|$ |%t#| |*|9|$ |%|" |%|_xRtt|jD ]@}(|j|( |krh|d- t	j8|2|*|jj9d |jd.|j|(< qhW | j| j|	 }t|t	jrt|jt	jr|2|_|jg| j:|jj)< d/S )0a  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_arraycallr3   Ndtypegetattrzlist_var = z def = r   
build_listc                s   g | ]}|j  kqS r)   )header)r/   l)r\   r)   r*   r2   A  s    z%_inline_arraycall.<locals>.<listcomp>zcheck loop body block r,   rL   zlist_def = r   c             s   s   | ]\}}|V  qd S )Nr)   )r/   r   br)   r)   r*   r   \  s    z$_inline_arraycall.<locals>.<genexpr>zpreds = Ziternextziter_def = Z
pair_firstc             S   s.   t | tjr*x|D ]}|j| jkrdS qW dS )NTF)r>   r   r   rw   )valremovedr   r)   r)   r*   
is_removed}  s
    
z%_inline_arraycall.<locals>.is_removedzremoved variables: r   )rA   r~   size)fnrW   Zrhsr~   r
   Zlen_funcr!   )r~   r)   
size_tuple)r:   r~   r   
empty_funcZ	dtype_modemptyunsafe_empty_inferredZ
next_indexonezReplace append with SetItem)r@   r   rA   r~   T);r;   r   r-   Zexitsnextrc   r   r9   r>   r   r   r   rB   rC   rA   r.   Zin_loopsallr   r?   r@   rD   attrrL   setZpredecessorsr   entries
terminatorr   r~   r   r   r   r   _new_definitionr   Zbinopoperatorsubrv   rw   r
   r!   r,   r   r   npr   r   r8   ZBranchr   Ztruebrinsertaddr   rj   r   );r$   r[   r\   Zloopr&   Zenable_prangerR   Z
exit_blockr   r   r   Z	dtype_defZdtype_mod_defZlist_var_defZlist_append_stmtsrS   Zin_visited_loopsrT   r   rW   rX   rZ   Zlist_defZappend_block_labelZappend_blockZappend_stmtZpredsZ	iter_varsZiter_first_varsZloop_headerZiter_defZiter_varZiter_first_varZ
loop_entryr   r   r~   stmtsr   r   rU   r   	index_varsize_varr   r   Zrange_func_defZsize_valZlen_func_varsize_tuple_varr   r   Zdtype_mod_varZ	dtype_varr   Zblock_idZblkZnext_index_varr   r)   )r\   r*   rM     s    






(








 






 rM   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 )Nr,   r   )r   r   r>   r   rB   rC   rD   r   rv   r;   rA   )r$   rX   r   Z
callee_defr)   r)   r*   r     s    
r   c                s   j  t }t tdd   D }t| j|fdd fddfdd}xBtj D ]4}j | }x$|jD ]}t	||r|j
| qW qxW d	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)   )r   )r/   rS   r)   r)   r*   r2     s    z%_fix_nested_array.<locals>.<listcomp>c                sP    | }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   r;   r>   r   rB   r   r   rC   rA   r   )ZarrZarr_def)r   r$   r)   r*   r     s    


z)_fix_nested_array.<locals>.find_array_defc                sz  t d}xf  D ]X\}}|j}|j}t }x:tt|D ](}|| }	t|	tj	r@|
|	jj |	j| kr@g }
x|D ]}|j|ks|j| kr|jj| kr||jd |
| q|||jd t|j}t|tjr^|j}t|td|}t|j|}t|||}g }||d|  || |||d  ||_|
| q|tq|W |
S q@W qW 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)r;   r:   r   r.   r   r   r-   r>   r   r?   r   r@   rw   rA   defmaprL   r   r   r~   r   r   r   extendr   )rX   ZvarlistrR   rS   rT   r   r.   ZdefinedrU   instZnew_varlistr   Zvar_defr~   r   Z	new_constZ
new_vardefnew_body)r9   r$   livemapusedefsr)   r*   r   &  sD    




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|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 )T)r   )r   )r/   r   )r$   r)   r*   r2   m  s    z?_fix_nested_array.<locals>.fix_array_assign.<locals>.<listcomp>zextra_dims = zsize_tuple_def = r   T)r   rD   rj   Zvarargrx   )r   r>   r   r   rA   r   r;   r@   r   rB   rC   r   rj   r:   r   Z_kws)r   rR   rW   Zlhs_defZrhs_defZdim_defZ
extra_dimsZsize_tuple_def)r   r   r$   r)   r*   r   S  s@    







z+_fix_nested_array.<locals>.fix_array_assignN)r9   r   r   r{   rJ   r    r   r   r.   r   r   )r$   r[   Zempty_deadmapr   rS   rT   r   r)   )r9   r   r   r$   r   r   r*   rN     s    --

rN   c             C   s   |g| j |j< tj|||dS )N)rA   r@   r~   )r   rw   r   r?   )r$   r   rA   r~   r)   r)   r*   r     s    r   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|f|| d S )N)r   superr   r+   )r(   Zpipelinerj   rx   )	__class__r)   r*   r+     s    zRewriteArrayOfConsts.__init__c             C   s6   t |dkrdS || _tt||| j||| _| jd kS )Nr   F)r-   
crnt_blockr   _inline_const_arraycallr   r   )r(   r$   rT   r   r   r)   r)   r*   match  s    zRewriteArrayOfConsts.matchc             C   s   | j | j_| jS )N)r   r   r.   )r(   r)   r)   r*   apply  s    
zRewriteArrayOfConsts.apply)r   r   r   r   r+   r   r   __classcell__r)   r)   )r   r*   r     s   r   c                s>  t d| j fdd}G dd dt}| }x| jD ]}t|tjr,t|jtjr|jj	|j
kr|j
|jj	 |j| qDnt|jtjr
|j}	|	jdkr|  dd |	jD |_|jj	g|_
|j| qDn@|	jd	kr
|	 kr
|j}
t||j|	|j|j
|jr
d
|_qDnt|tjr
|j}||jkr\|j| qDn||j
kr
|j| |j
| |j| |j
g kr
g }xX|jD ]N}t|tjr|jj	|jkst|tjr|j|jkrq|| qW ||_g |_d
|_qD|j| ||rD|  qDW |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 preceeds 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|}ttd|}ttd|}tj}t|d}||j< ||j< |t|tj||d	| |t|tjj|g|d
| t|
}ttd|}ttj}||fd|i}||j< |t|tjdtj|d	| ttd|}tjt|j< tdt|}|t||| ttd|}||j< t |
}|dkrd}tj!|||}|t||| tjj"|||gi |d	}t#$|	|| |< |t| || xt%|D ]x}ttd|}tj}||j< |t|t||| t&| ||| |}t#$tj'|	||
 |< || q|W |(| 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".
        r3   r   r   r   zinline array_var = z list_var = r   r   )r~   )r:   r~   r   r   r   z	$np_g_varr   z$np_typ_varboolZbool_r   T))r   r   r   rj   rw   Zreturn_typer>   r   ZArrayCompatiblendimr~   r   r   r-   r   r   r   ZintpZUniTuplerL   r   r   rB   r   ZDTyper   r   r   Zresolve_function_typerv   ZmiscZModuler   r   r,   r	   Z	signaturer   r   Znoner   ) r   rX   r   	list_varsdelsZcallnameZret_typer~   r   Z	array_typr   seq_r   r   r   Zsize_typZsize_tuple_typZnptyper   ZfntyZsigZg_np_varZg_npZtyp_varZ	dtype_strZnp_typ_getattrZ
empty_callrU   r   Z	index_typsetitem)r   contextrR   r$   r   r   r)   r*   inline_array  sp     
















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_itemsr   r  rP   )r(   r)   r)   r*   r+     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)   r*   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)   )rw   r  )r/   r   )r(   r)   r*   r2   ,  s    zH_inline_const_arraycall.<locals>.State.list_var_used.<locals>.<listcomp>)anyr  )r(   r   r)   )r(   r*   list_var_used'  s    z4_inline_const_arraycall.<locals>.State.list_var_usedN)r   r   r   r   r+   r  r  r)   r)   r)   r*   State  s   	r  r   c             S   s   g | ]
}|j qS r)   )rw   )r/   r   r)   r)   r*   r2   <  s    z+_inline_const_arraycall.<locals>.<listcomp>r,   TN)r;   r   objectr.   r>   r   r?   rA   r   rw   r  rL   r@   r   rB   rC   r  r:   r  r   r  rP   r   r
  r   r  )rT   r$   r  r   r   r	  r  stater   rX   Zarr_varZremoved_varr.   r)   )r   r  rR   r$   r   r   r*   r     sh    \&


r   )NNNNN)F)Cr   Zpytypesr   rr   r   r   r   r   r   r   r	   Znumba.parforr
   Znumba.ir_utilsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Znumba.analysisr   r   r    Znumba.targets.rangeobjr!   Znumba.unsafe.ndarrayr"   r   r   r   r   rH   r  r#   rl   rm   r;   rI   r   r   r   r   r   r   r   rM   r   rN   r   Zregister_rewriteZRewriter   r   r)   r)   r)   r*   <module>   sF   (T /  
 
	2
 n
x
