B
     \                 @   s   d dl Z d dlZd dlm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 d dlmZ d dlmZ d dlmZ d d	lmZ d dlZG d
d deZedd ZG dd deZdddZ dd Z!ee dd Z"dS )    N)ir)compilertypesir_utilsr   typingnumpy_supportutils)config)CallableTemplate	signatureinfer_globalAbstractTemplate)registry)lower_builtin)register_jitable)exec_c               @   s    e Zd ZdZdd Zdd ZdS )StencilFuncLowererzMCallable class responsible for lowering calls to a specific StencilFunc.
    c             C   s
   || _ d S )N)stencilFunc)selfZsf r   ,lib/python3.7/site-packages/numba/stencil.py__init__   s    zStencilFuncLowerer.__init__c             C   s:   | j |ji |jd }|||j||}||jg |S )N)r   compile_for_argtysargsreturn_typeZcall_internalZfndescZadd_linking_libsZlibrary)r   contextbuildersigr   ZcresZresr   r   r   __call__   s
    
zStencilFuncLowerer.__call__N)__name__
__module____qualname____doc__r   r   r   r   r   r   r      s   r   c             G   s`   | j }xT|D ]L}| j|jkr$td|j }x,tt|D ]}|| || kr8tdq8W qW d S )Nz\Secondary stencil array does not have same number  of dimensions as the first stencil input.zaSecondary stencil array has some dimension smaller the same dimension in the first stencil input.)shapendim
ValueErrorrangelen)ar   ZashapeargZargshapeir   r   r   !raise_if_incompatible_array_sizes#   s    
r+   c               @   sd   e Zd ZdZdZdd Zdd Zdd Zd	d
 Zdd Z	dd Z
dd Zdd Zdd Zdd ZdS )StencilFuncz@
    A special type to hold stencil information for the IR.
    r   c             C   s   t | j| _t |  jd7  _|| _|| _|| _g | _tjj	| _
tjj| _| j
  | j  | | j
 | jd| _i | _t| | _d S )N   neighborhood)type
id_counterid	kernel_irmodeoptionskwsr   Z
cpu_targetZtyping_context
_typingctxZtarget_context
_targetctxZrefresh_install_typegetr.   _type_cacher   	_lower_me)r   r2   r3   r4   r   r   r   r   8   s    



zStencilFunc.__init__c          
   C   sB  g }x6|  D ](\}}|j}|j}g }	x|jD ]}
t|
tjr&|| t|dkrt	|||}t	||d |}|	t
|||
j| ng }x$|D ]}t	|||}||g7 }qW td}t	|||}tj||}|	t||| t	|||}t
|||
j|}|	| q4|	|
 q4W |	|_qW |S )z
        Find return statements in the IR and replace them with a SetItem
        call of the value "returned" by the kernel into the result array.
        Returns the block labels that contained return statements.
        r-   r   stencil_index)itemsscopelocbody
isinstancer   ZReturnappendr'   VarSetItemvaluer   mk_unique_varExprbuild_tupleAssign)r   blocks
index_varsout_name
ret_blockslabelblockr>   r?   new_bodystmtZrvarZivarZvar_index_varsZone_var	index_vars_index_names_index_var
tuple_callZsir   r   r   replace_return_with_setitemJ   s4    



z'StencilFunc.replace_return_with_setitemc       $      C   s  i }g }t jdkr*td|| t|j |dkr8d}n$d}t||kr\tdt||f t|j}	t	 }
x|j
 D ]}|j}|j}g }x|jD ]}t|tjrt|jtjrt jdkrtd|jj|jj |jj||jj< t|tjr(t|jtjr(|jjdkr(|jjj|jksFt|tjrN|jj|jkrNtd	t|tjrt|jtjr|jjd
kr|jjj|jkr|jjj|kr|jjdkr|jj}n|jj}|
|jjj |r&t|dst|j|	kr ||	|j g7 }n&|j|kr|||j g7 }ntd|dkrt||d |}td}t|||}tj t!j|||}|"t||| |"ttj#|jj|||j| q$g }g }td}t|||}g }g }xt$|D ]}td}t|||}|"tt|||| ||g7 }t||| |}||g7 }td}t|||}||g7 }td}t|||}tj#||| |}|"t||| tj t!j||| |}|"t||| qW tj%||}|"t||| |"ttj#|jj|||j| q|"| qW ||_q|W |rdd t$|D }t|dkr`tdx |D ]} t| t&st| t'rxt$t| D ]|}!| |! }"t|"tjr|"j|kr||"j }"t|"t(rt)||! d |"||! d< t*||! d |"||! d< ntdqW t| }#nNt| t(rdt)|d d | |d d< t*|d d | |d d< d}#ntd|#|krhtdqhW ||
fS )z
        Transforms the stencil kernel as specified by the user into one
        that includes each dimension's index variable as part of the getitem
        calls.  So, in effect array[-1] becomes array[index0-1].
        r-   add_indices_to_kernelNTFzD%d dimensional neighborhood specified for %d dimensional input arrayzremembering in const_dict)setitemZstatic_setitemz?Assignments to arrays passed to stencil kernels is not allowed.)getitemZstatic_getitemrY   namezDstencil kernel index is not constant, 'neighborhood' option requiredr   r<   Zconst_indexZind_stencil_indexc             S   s   g | ]}d d gqS )r   r   ).0_r   r   r   
<listcomp>   s    z5StencilFunc.add_indices_to_kernel.<locals>.<listcomp>z=Stencil kernel with no accesses to relatively indexed arrays.zCstencil kernel index is not constant,'neighborhood' option requiredz/Non-tuple or non-integer used as stencil index.z2Stencil index does not match array dimensionality.)+r	   DEBUG_ARRAY_OPTprintr   dump_blocksrJ   r'   r%   Zget_tuple_tablesetvaluesr>   r?   r@   rA   r   rI   rE   ZConsttargetrZ   rG   op	arg_namesrD   indexrR   addhasattrAssertionErrorrC   rF   ZbinopoperatorrB   rY   r&   rH   tuplelistintminmax)$r   ZkernelZindex_namesr$   r.   standard_indexedZ
const_dictZkernel_constsZneed_to_calc_kernelZtuple_tablerelatively_indexedrO   r>   r?   rP   rQ   Zstmt_index_varrR   ZtmpnameZtmpvarZacc_callrK   Zsum_resultsrS   rT   Zconst_index_varsZind_stencilsZdimZgetitemnameZ
getitemvarZgetitemcallrU   rf   r*   ZteZ	index_lenr   r   r   rW   u   s    


















z!StencilFunc.add_indices_to_kernelc             C   s   t jdkr"td| t| jj t|d tj	j
s<tdt| j| j|d i \}}}t|tj	j
rntdtj	
||d j|d j}|||fS )Nr-   get_return_typer   zGThe first argument to a stencil kernel must be the primary input array.z:Stencil kernel must return a scalar and not a numpy array.)r	   r^   r_   r   r`   r2   rJ   rA   r   npytypesArrayr%   r   Ztype_inference_stager6   r$   Zlayout)r   argtystypemapr   	calltypesreal_retr   r   r   rr     s"    

zStencilFunc.get_return_typec             C   s2   t dt| j tft| | jd}|| | dS )zmConstructs and installs a typing class for a StencilFunc object in
        the input typing context.
        ZStencilFuncTyping_)keyZgenericN)r/   strr1   r   dict_type_meZinsert_user_function)r   Z	typingctxZ_ty_clsr   r   r   r8   3  s
    
zStencilFunc._install_typec       
      C   s.   | j | \}}}}| j|||||f| }	|	S )N)r:   _stencil_wrapper)
r   ru   kwtysr   sigretr\   resultrv   rw   new_funcr   r   r   r   =  s    
zStencilFunc.compile_for_argtysc             C   s2  | j dk	r:t| j |d jkr:tdt| j |d jf |}d}d}d|krl||d f7 }|d7 }|d }d|kr||d f7 }|d7 }|| jkr| j| \}}}}|S | |\}}	}
t|f| }d	d
| j	j
|}t|t kt f td}t||_| j| j| |fg |||	|
f| j|< |S )z
        Implement AbstractTemplate.generic() for the typing class
        built by StencilFunc._install_type().
        Return the call-site signature.
        Nr   zD%d dimensional neighborhood specified for %d dimensional input array outz
, out=Noner.   z, neighborhood=Nonez*def __numba_dummy_stencil({}{}):
    pass
,Z__numba_dummy_stencil)r.   r'   r$   r%   r:   rr   r   formatjoinr2   re   r   globalslocalsevalr   pysignaturepysigr7   Zinsert_func_defnr;   )r   ru   r~   Zargtys_extra	sig_extrar   Z_sigr\   rx   rv   rw   r   Z
dummy_textZ
dummy_funcr   r   r   r|   D  s6    

zStencilFunc._type_mec       
      C   s   i }|  }i |_xv|j D ]h\}}t |j| }g |_x>|j| jD ].}t |}	|j|	 ||krJ|| ||	< qJW ||j|< qW ||fS )a  
        Create a copy of a given IR along with its calltype information.
        We need a copy of the calltypes because copy propagation applied
        to the copied IR will change the calltypes and make subsequent
        uses of the original IR invalid.
        )copyrJ   r=   deepcopyr@   rB   )
r   r   rw   copy_calltypeskernel_copyZblock_labelrO   Z	new_blockrQ   Zscopyr   r   r   copy_ir_with_calltypesl  s    
z"StencilFunc.copy_ir_with_calltypesc       =   
      sh  |  | j|\}}t|j |jd }	t|j|\}
}t|j}t|j|
||| d|krjt	dt
d|}tjdkrtd|| |d }tjdkrtd||jt|j| t|j dtt|d	d
| jf }g }x0t|jD ]"}t
dt| |}||g7 }qW t
d|}t
d|}d}|d k	rJ|d|7 }dt| jkrh|d|7 }| jdg }|	|krt	dtt|t|j dkrt	d| |||j| j|\}}| jd kr|| _tjdkrtd t|j |  |j||}tjdkr*td| t|j d|d!|j|}g }xht|jD ]Z}t"|| d t#r|| d }|| d }nd||}d||}|$||f qPW t|dkr|d|	 7 }x$|D ]}||	kr|d| 7 }qW |d7 }t
d|}|d||	7 }|d krt%&|jjj'} d| jkrp| jd }!|jt(j))|!kr^t	dd|||!| }"nd||| }"|d |" 7 }nXd| jkr| jd }!t(j))|!}#| j*+|#|jsd}$t	|$d!||!}"|d |" 7 }d}%xbt|jD ]T}xt|%D ]}&|d 7 }qW |d"|| || d |||| d 7 }|%d7 }%qW xt|%D ]}&|d 7 }qVW |d#|7 }|d$|7 }tjdkrtd% t| t,|t- kt. f t/|}'|d k	rt01|'}(|(|_2t34|'})t5|)j t|)j}*i }+||||g|j | },x.|*6 D ]"\}-}.|-|,krt7|-|+|-< qW t8|)j|+ t9|)j: d  t;|j |_t9|j: d }/ fd&d'|D }tjdkrtd(|  td) t|)j td* t|j x|)j6 D ]\}0}1xt<|1j=D ]\}}2t"|2t>j?r|2j@jA|kr|2jB}3|1jC}4t>D|4|3}5|1j=d | |5_=|1j=|d d  |1_=tE|j: }6|5$t>F|6|3 x"|j6 D ]\}7}8|8|)j|7< qW |1|)j|/< |5|)j|0< x&|D ]}9|)j|9 $t>F|/|3 qW P qW qP qW tG|)j|)_t5|)j t"|tHjIstJ|}:tK|:};tjdkrHtd+|; t|)j t3L| j*| jM|)|;d t3jNi }<|<S ),Nr   r   z6Cannot use the reserved word 'out' in stencil kernels.Z__sentinel__r-   name_var_tabler}   z__numba_stencil_%s_%s-r\   rf   r.   r   z	, {}=Nonestandard_indexingzYThe first argument to a stencil kernel must use relative indexing, not standard indexing.z[Standard indexing requested for an array name not present in the stencil kernel definition.zAfter add_indices_to_kernelz!After replace_return_with_setitemzdef {}({}{}):
r   z	{}[{}][0]z	{}[{}][1]z&    raise_if_incompatible_array_sizes(z)
Z
full_shapez    {} = {}.shape
cvalz-cval type does not match stencil return type.z"{} = np.full({}, {}, dtype=np.{})
z{} = np.zeros({}, dtype=np.{})
z    z{}[:] = {}
z.for {} in range(-min(0,{}),{}[{}]-max(0,{})):
z{} = 0
z    return {}
znew stencil func textc                s   g | ]}|  qS r   r   )r[   x)stencil_stub_last_labelr   r   r]   l  s    z0StencilFunc._stencil_wrapper.<locals>.<listcomp>zret_blocks w/ offsetsz"before replace sentinel stencil_irz#before replace sentinel kernel_copynew_stencil_param_types)Or   r2   r   Zremove_argsrJ   re   Zcopy_propagateZget_name_var_tableZapply_copy_propagater%   Zget_unused_var_namer	   r^   r_   dtyper/   r`   hexr1   replacer&   r$   rz   r   r{   r5   r4   r9   r'   ra   rW   r.   rV   r   rA   rm   rB   r   Zas_dtyper   r   typeofr6   Zcan_convertr   r   r   r   r   r   r   r   run_frontendZremove_delsr=   rF   Zreplace_var_namesro   keysZadd_offset_to_labels	enumerater@   r   rI   rc   rZ   r?   r>   ZBlockrn   ZJumpZrename_labelsr   ZTyperi   rl   Z
compile_irr7   ZDEFAULT_FLAGS)=r   r   r   r   rv   rw   r   r   r   Z	first_argZin_cpsZout_cpsr   Zsentinel_nameZ	the_arrayZstencil_func_namerK   r*   Zindex_var_namerL   Zneighborhood_namer   rp   Zkernel_sizerq   rM   Z	func_textZrangeslohiZother_arrayZ
shape_nameZreturn_type_namer   Zout_initZcval_tymsgoffsetjZstencil_funcr   Z
stencil_irZ	var_tableZnew_var_dictZreserved_namesrZ   varZ	new_labelrN   rO   Zinstr?   r>   Z
prev_blockZbody_first_labellbZ	ret_blockarray_typesr   r   r   )r   r   r}     s`   
























zStencilFunc._stencil_wrapperc             O   s   | j d k	r:t| j |d jkr:tdt| j |d jd|kr|d }|j}t|}tj	
||jt|}tdd |D }tdd |D |g }nd }tdd |D }|}tjdkrtd	||| | |\}	}
}| j|d |	|
|f| }|d kr|j| S |j||f  S d S )
Nr   zD{} dimensional neighborhood specified for {} dimensional input arrayr   c             S   s   g | ]}t j|qS r   )r   r   )r[   r   r   r   r   r]     s    z(StencilFunc.__call__.<locals>.<listcomp>c             S   s   g | ]}t j|qS r   )r   r   )r[   r   r   r   r   r]     s    c             S   s   g | ]}t j|qS r   )r   r   )r[   r   r   r   r   r]     s    r-   r   )r.   r'   r$   r%   r   r   r   Z
from_dtyper   rs   rt   Z
map_layoutrk   r	   r^   r_   rr   r}   Zentry_point)r   r   kwargsr   ZrdtypeZrttypeZresult_typer   Zarray_types_fullrx   rv   rw   r   r   r   r   r     s0    




zStencilFunc.__call__N)r   r    r!   r"   r0   r   rV   rW   rr   r8   r   r|   r   r}   r   r   r   r   r   r,   1   s   + (
(  0r,   constantc             K   s\   t | tsd}| }n| }d }x |D ]}|dkr"td| q"W t||}|d k	rX||S |S )Nr   )r   r   r.   zUnknown stencil option )rA   rz   r%   _stencil)Zfunc_or_moder4   r3   funcZoptionwrapperr   r   r   stencil  s    


r   c                s&    dkrt d   fdd}|S )Nr   zUnsupported mode style c                s   t | }t| S )N)r   r   r,   )r   r2   )r3   r4   r   r   	decorated  s    
z_stencil.<locals>.decorated)r%   )r3   r4   r   r   )r3   r4   r   r     s    r   c             C   s   t t tjjdS )z lowering for dummy stencil callsr   )lirZConstantZIntTyper   ZintpZbitwidth)r   r   r   r   r   r   r   stencil_dummy_lower  s    r   )r   )#r   ZnumpyZnpZllvmliter   r   Znumbar   r   r   r   r   r   r	   Znumba.typing.templatesr
   r   r   r   Znumba.targetsr   Znumba.targets.imputilsr   Znumba.extendingr   Z	numba.sixr   rj   objectr   r+   r,   r   r   r   r   r   r   r   <module>   s*   $     *

