a
    .;bS                     @   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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d dlZd d	lmZ G d
d deZedd Z 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)typestypingutilsr   configir_utilsregistry)CallableTemplate	signatureinfer_globalAbstractTemplate)lower_builtin)register_jitable)NumbaValueError)literal_unroll)numpy_supportc                   @   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   5lib/python3.9/site-packages/numba/stencils/stencil.py__init__   s    zStencilFuncLowerer.__init__c                 C   s:   | j |ji |jd }|||j||}||jg |S r   )r   compile_for_argtysargsreturn_typeZcall_internalZfndescZadd_linking_libsZlibrary)r   contextbuildersigr   Zcres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 }t|D ]H}| j|jkr&td|j }tt|D ]}|| || kr8tdq8q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.)shaper   ndim
ValueErrorrangelen)ar   ZashapeargZargshapeir   r   r   !raise_if_incompatible_array_sizes$   s    
r-   c                 C   s   t | j| | j| S )z_ Called by stencil in Python mode to add the loop index to a
        user-specified slice.
    )slicestartstop)Z	the_sliceZaddendr   r   r   slice_addition;   s    r1   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getr4   _type_cacher   	_lower_me)r   r8   r9   r:   r   r   r   r   H   s    



zStencilFunc.__init__c              
   C   s2  g }|  D ]\}}|j}|j}g }	|jD ]}
t|
tjr|| t|dkrt	|||}t	||d |}|	t
|||
j| ng }|D ]}t	|||}||g7 }qtd}t	|||}tj||}|	t||| t	|||}t
|||
j|}|	| q,|	|
 q,|	|_q|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.
        r3   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blockrD   rE   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_setitemZ   s4    


z'StencilFunc.replace_return_with_setitemc           -      C   s.  i }g }	t jdkr*td|| t|j |du r8d}
n$d}
t||kr\tdt||f t|j}t	 }|j
 D ]b}|j}|j}g }|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v r |jjj|jv s>t|tjrF|jj|jv rFtd	t|tjrt|jtjr|jjd
v r|jjj|jv r|jjj|vr|jjdkr|jj}n|jj}||jjj |
rt|dsJ |j|v r|	||j g7 }	n&|j|v r|	||j g7 }	ntd|dkrt||d |}td}t|||}||j }t|t j!j"r.t|td|}t#$t%}t j&'|}|||j< t(d||}|)t||| tj*|||gd|}|+| j,|t j-gi ||< |)t||| |)ttj.|jj|||j| nNtj/t0j|||}|)t||| |)ttj.|jj|||j| qg }g }td}t|||} g }!g }"||j }t1|D ]}#td}t|||}|)tt|#||| |!|g7 }!t|||# |}||g7 }td}t|||}|"|g7 }"td}$t||$|}%tj.||!|# |}&|)t|&|%| t|t j2r||# }'n|dd }'t|'t j!j"rPt|td|}t#$t%}t j&'|}|||j< t(d||}|)t||| tj*||%||# gd|}|+| j,|'t j-gi ||< |)t||| n,tj/t0j|%||# |}|)t||| qtj3|"|}(|)t|(| | |)ttj.|jj| ||j| q|)| q||_qx|
r&dd t1|D }t|	dkrtd|	D ]})t|)t4s.t|)t5rt1t|)D ]|}*|)|* }+t|+tjrj|+j|v rj||+j }+t|+t6rt7||* d |+||* d< t8||* d |+||* d< ntdq:t|)},nNt|)t6rt7|d d |)|d d< t8|d d |)|d d< d},ntd|,|krtdq||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].
        r3   add_indices_to_kernelNTFD%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_getitemr`   namezDstencil kernel index is not constant, 'neighborhood' option requiredr   rB   r1   r   Zconst_indexZind_stencil_indexc                 S   s   g | ]}d d gqS )r   r   ).0_r   r   r   
<listcomp>1      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.)9r   DEBUG_ARRAY_OPTprintr   dump_blocksrP   r)   r'   Zget_tuple_tablesetvaluesrD   rE   rF   rG   r   rO   rK   ZConsttargetra   rM   op	arg_namesrJ   indexrX   addhasattrr   rI   rL   r   ZmiscZ	SliceTypenumbaZnjitr1   Z	functionsZ
DispatcherZGlobalrH   ZcallZget_call_typer<   intpr`   Zbinopoperatorr(   Z
ConstSizedrN   tuplelistintminmax)-r   ZkernelZindex_namesr&   r4   standard_indexedtypemap	calltypesZ
const_dictZkernel_constsZneed_to_calc_kernelZtuple_tablerelatively_indexedrU   rD   rE   rV   rW   Zstmt_index_varrX   ZtmpnameZtmpvarZstmt_index_var_typZsa_varZsa_funcZsa_func_typZg_saZslice_addition_callZacc_callrQ   Zsum_resultsrY   rZ   Zconst_index_varsZind_stencilsZdimZgetitemnameZ
getitemvarZgetitemcallZone_index_typr[   rn   r,   ZteZ	index_lenr   r   r   r]      sJ   




























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ddlm} || j| j| j|d i \}}}}t|tj	j
rtdtj	
||d j|d j}|||fS )Nr3   get_return_typer   zGThe first argument to a stencil kernel must be the primary input array.)typed_passesz:Stencil kernel must return a scalar and not a numpy array.)r   rf   rg   r   rh   r8   rP   rG   r   npytypesArrayr   
numba.corer~   Ztype_inference_stager<   r=   r&   Zlayout)r   argtysr~   rz   r   r{   rc   real_retr   r   r   r}   R  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)r5   strr7   r   dict_type_meZinsert_user_function)r   Z	typingctxZ_ty_clsr   r   r   r>   k  s    zStencilFunc._install_typec           
      C   s0   | j | \}}}}| j|||||g|R  }	|	S r   )r@   _stencil_wrapper)
r   r   kwtysr   sigretrc   resultrz   r{   new_funcr   r   r   r   u  s    
zStencilFunc.compile_for_argtysc                 C   s:  | j dur:t| j |d jkr:tdt| j |d jf |}d}d}d|v rl||d f7 }|d7 }|d }d|v r||d f7 }|d7 }|| jv r| j| \}}}}|S | |\}}	}
t|g|R  }d	d
| j	j
|}t|t v t f td}|jt|d}| 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   r^    outz
, out=Noner4   z, neighborhood=Nonez*def __numba_dummy_stencil({}{}):
    pass
,Z__numba_dummy_stencil)pysig)r4   r)   r&   r   r@   r}   r
   formatjoinr8   rm   execglobalslocalsevalreplacer   pysignaturer=   Zinsert_func_defnrA   )r   r   r   Zargtys_extra	sig_extrar   Z_sigrc   r   rz   r{   r   Z
dummy_textZ
dummy_funcr   r   r   r   |  s<    

zStencilFunc._type_mec           
      C   s   i }|  }i |_|j D ]d\}}t |j| }g |_|j| jD ].}t |}	|j|	 ||v rF|| ||	< qF||j|< q||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.
        )copyrP   rC   deepcopyrF   rH   )
r   r   r{   copy_calltypeskernel_copyZblock_labelrU   Z	new_blockrW   Zscopyr   r   r   copy_ir_with_calltypes  s    
z"StencilFunc.copy_ir_with_calltypesc           ?   
      sr  |  | j|\}}t|j |jd }	t|j|\}
}t|j}t|j|
||| d|v 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 }t|jD ]"}t
dt| |}||g7 }qt
d|}t
d|}d}|d urF|d|7 }dt| jv rd|d|7 }| jdg }|	|v rt	dtt|t|j dkrt	d| |||j| j|||\}}| jd u r|| _tjdkrtd t|j |  |j||}tjdkr*td| t|j d|d!|j|}g }t|jD ]Z}t"|| d t#r|| d }|| d }nd||}d||}|$||f qNt|dkr|d|	 7 }|D ]}||	kr|d| 7 }q|d7 }t
d|}|d||	7 }dd } |d u rt%&|jjj'}!d| jv rx| jd }"|jt(j))|"krbd}#t	|#d ||| |"|!}$nd!|||!}$|d"|$ 7 }n\d| jv r| jd }"t(j))|"}%| j*+|%|jsd}#t	|#d#|| |"}$|d"|$ 7 }d}&t|jD ]P}t|&D ]}'|d"7 }q
|d$|| || d |||| d 7 }|&d7 }&qt|&D ]}'|d"7 }qX|d%|7 }|d&|7 }tjdkrtd' t| t,|t- v t. f t/|}(|d urt01|(})|)|_2dd(l3m4}* |*5|(}+t6|+j t|+j},i }-||||g|j | }.|,7 D ]"\}/}0|/|.vr&t8|/|-|/< q&t9|+j|- t:|+j; d  t<|j |_t:|j; d }1 fd)d*|D }tjdkrtd+|  td, t|+j td- t|j |+j7 D ] \}2}3t=|3j>D ]\}}4t"|4t?j@r|4jAjB|kr|4jC}5|3jD}6t?E|6|5}7|3j>d | |7_>|3j>|d d  |3_>tF|j; }8|7$t?G|8|5 |j7 D ]\}9}:|:|+j|9< q|3|+j|1< |7|+j|2< |D ]};|+j|; $t?G|1|5 q qqq qqtH|+j|+_t6|+j t"|tIjJsJ |}<tK|<}=tjdkrFtd.|= t|+j tL|+j |*M| j*| jN|+|=d |*jOi }>|>S )/Nr   r   z6Cannot use the reserved word 'out' in stencil kernels.Z__sentinel__r3   name_var_tabler   z__numba_stencil_%s_%s-rc   rn   r4   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
c                 S   s@   t | s4t | rdS t | r<| dk r.dS dS nt| S d S )Nznp.nanr   z-np.infznp.inf)npZisfiniteZisnanZisinfr   )cvalr   r   r   cval_as_strJ  s    


z1StencilFunc._stencil_wrapper.<locals>.cval_as_strr   z-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 textcompilerc                    s   g | ]}|  qS r   r   rb   xZstencil_stub_last_labelr   r   rd     re   z0StencilFunc._stencil_wrapper.<locals>.<listcomp>zret_blocks w/ offsetsz"before replace sentinel stencil_irz#before replace sentinel kernel_copynew_stencil_param_types)Pr   r8   r   Zremove_argsrP   rm   Zcopy_propagateZget_name_var_tableZapply_copy_propagater   Zget_unused_var_namer   rf   rg   dtyper5   rh   hexr7   r   r(   r&   r   r   r   r;   r:   r?   r)   ri   r]   r4   r\   r   rG   rv   rH   r   Zas_dtyper!   r   typeofr<   Zcan_convertr   r   r   r   r   r   r   r   r   run_frontendZremove_delsrC   rL   Zreplace_var_namesrx   keysZadd_offset_to_labels	enumeraterF   r   rO   rk   ra   rE   rD   ZBlockrw   ZJumpZrename_labelsr   Typeru   Zfixup_var_define_in_scopeZ
compile_irr=   ZDEFAULT_FLAGS)?r   r   r   r   rz   r{   r   r   r   Z	first_argZin_cpsZout_cpsr   Zsentinel_nameZ	the_arrayZstencil_func_namerQ   r,   Zindex_var_namerR   Zneighborhood_namer   ry   Zkernel_sizer|   rS   Z	func_textZrangeslohiZother_arrayZ
shape_namer   Zreturn_type_namer   msgZout_initZcval_tyoffsetjZstencil_funcr   r   Z
stencil_irZ	var_tableZnew_var_dictZreserved_namesra   varZ	new_labelrT   rU   instrE   rD   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 ur:t| j |d jkr:tdt| j |d jd|v 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 |	|
|g|R  }|d u 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   rd   
  re   z(StencilFunc.__call__.<locals>.<listcomp>c                 S   s   g | ]}t j|qS r   r   r   r   r   r   rd     re   c                 S   s   g | ]}t j|qS r   r   r   r   r   r   rd     re   r3   r    )r4   r)   r&   r'   r   r   r   Z
from_dtyper   r   r   Z
map_layoutrt   r   rf   rg   r}   r   Zentry_point)r   r   kwargsr   ZrdtypeZrttypeZresult_typer   Zarray_types_fullr   rz   r{   r   r   r   r   r      s>    




zStencilFunc.__call__N)r!   r"   r#   r$   r6   r   r\   r]   r}   r>   r   r   r   r   r    r   r   r   r   r2   A   s   + N
(  @r2   constantc                 K   sX   t | tsd}| }n| }d }|D ]}|dvr td| q t||}|d urT||S |S )Nr   )r   r   r4   zUnknown stencil option )rG   r   r'   _stencil)Zfunc_or_moder:   r9   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"   ddl m} || }t| S )Nr   r   )r   r   r   r2   )r   r   r8   r9   r:   r   r   	decorated4  s    
z_stencil.<locals>.decorated)r'   )r9   r:   r   r   r   r   r   0  s    r   c                 C   s   t t tjjdS )z lowering for dummy stencil callsr   )lirZConstantZIntTyper   rr   Zbitwidth)r   r   r   r   r   r   r   stencil_dummy_lower;  s    r   )r   )&r   Znumpyr   Zllvmliter   r   r   r   r   r   r   r   r   Znumba.core.typing.templatesr	   r
   r   r   Znumba.core.imputilsr   Znumba.core.extendingr   Znumba.core.errorsr   Znumba.misc.specialr   rq   rs   Znumba.npr   objectr   r-   r1   r2   r   r   r   r   r   r   r   <module>   s2   $
     b
