U
    ,dG                    @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZmZmZ ddlmZ ddlZddlmZ ddlmZ ddlmZ ddl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% dd
lm&Z&m'Z' ddl(m)Z)m*Z* ddl+m,Z,m-Z- ddl.m/Z/m0Z0 ddl1m2Z2 ddl3m4Z4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZVmWZWmXZXmYZYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZa ddlbmcZcmdZdmeZemfZf ddlgmhZh ddlimjZjmkZk ddllmmZm ddlnmoZompZpmqZqmrZrmsZsmtZt ddl3muZu ddlZddlvZvddlvZwddlxmyZy ddlzZddl{m|Z| dZ}ej~e}ddZdd ZdZdd Zeued d! ZG d"d# d#eZd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? Zd@dA ZdBdC dDdC eeeeeeeeeeeedEZdFdG ZdHeiZe4dIdJ Ze4dKdL Ze4dMdN Ze4dOdP ZedQdRdSgZedNeedPeedLeedJeedLeedJedTZG dUdV dVeZG dWdX dXejejZdYdZ Zeeyje< G d[d\ d\eZG d]d^ d^eZd_d` ZG dadb dbZG dcdd ddZdedf ZG dgdh dhZddidjZdkdl ZG dmdn dnZG dodp dpZG dqdr drZdsdt ZG dudv dveZdwdx Zdydz Zd{d| Zd}d~ Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd ZeddddgddZdddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zee%je< dddZee je< dd Zee je< dd Zee!je< dddZdddZdd Zdd Zdd Zdd ZeddddgZdd Zdd ZddĄ Zِd ddƄZddȄ Zddʄ Zdd̄ Zdd΄ Zee%je< ddЄ Zdd҄ ZddԄ Zee%je< ddք Zddd؄ZdddڄZdd܄ Zee%je< ddބ Zee%je< dddZdd Zdd Zdd ZdddZee%je< dddZee%je< dddZee%je< dd Zee%je< dd Zee%je< dd Zee#je< dddZee%je< edd Ze/eG dd de0Zdd ZdS (  a  
This module transforms data-parallel operations such as Numpy calls into
'Parfor' nodes, which are nested loops that can be parallelized.
It also implements optimizations such as loop fusion, and extends the rest of
compiler analysis and optimizations to support Parfors.
This is similar to ParallelAccelerator package in Julia:
https://github.com/IntelLabs/ParallelAccelerator.jl
'Parallelizing Julia with a Non-invasive DSL', T. Anderson et al., ECOOP'17.
    N)reduce)defaultdictOrderedDict
namedtuple)contextmanager)make_dataclass)ir)impl_ret_untracked)typestypingutilserrorsr   analysispostprocrewrites	typeinferconfigir_utils)prangepndindex)datetime_minimumdatetime_maximum)as_dtypenumpy_version)infer_globalAbstractTemplate)StencilPass)register_jitablelower_builtin)+mk_unique_var
next_labelmk_allocget_np_ufunc_typmk_range_blockmk_loop_headerget_name_var_tablereplace_varsreplace_vars_inner
visit_varsvisit_vars_innerremove_deadcopy_propagateget_block_copiesapply_copy_propagatedprint_func_irfind_topo_orderget_stmt_writesrename_labelsget_call_tablesimplifysimplify_CFGhas_no_side_effectcanonicalize_array_mathadd_offset_to_labelsfind_callnamefind_build_sequenceguardrequireGuardExceptioncompile_to_numba_irget_definitionbuild_definitionsreplace_arg_nodesreplace_returns
is_getitem
is_setitemis_get_setitemindex_var_of_get_setitemset_index_var_of_get_setitemfind_potential_aliasesreplace_var_namestransfer_scope)compute_use_defscompute_live_mapcompute_dead_mapscompute_cfg_from_blocks)CFGraph)npydecl	signature)Function)random_int_argsrandom_1arg_sizerandom_2arg_sizelastrandom_3arg_sizelastrandom_callsassert_equiv)overload)array_analysis)stencilparforP   F)widthdrop_whitespacec                 C   s&   |   D ]}dd t|D  qd S )Nc                 S   s   g | ]}t |qS  print.0yr^   r^   8/tmp/pip-unpacked-wheel-eu7e0c37/numba/parfors/parfor.py
<listcomp>k   s     z!print_wrapped.<locals>.<listcomp>)
splitlines_txtwrapperwrap)xlr^   r^   rd   print_wrappedi   s    rk   c                   C   s   d S Nr^   r^   r^   r^   rd   init_pranger   s    rm   c                  C   s   dd } | S )Nc                   S   s   d S rl   r^   r^   r^   r^   rd   no_opw   s    z#init_prange_overload.<locals>.no_opr^   )rn   r^   r^   rd   init_prange_overloadu   s    ro   c                   @   s   e Zd Zdd ZdS )internal_prangec                 G   s   t | S rl   )range)clsargsr^   r^   rd   __new__}   s    zinternal_prange.__new__N)__name__
__module____qualname__rt   r^   r^   r^   rd   rp   {   s   rp   c                 C   sR   |j dkrdd }n:|j dkrFt|jtjtjfr<dd }qNdd }ndd }|S )Nr   c                 S   s   | d S Nr^   r^   in_arrr^   r^   rd   min_1   s    z min_parallel_impl.<locals>.min_1   c                 S   sR   t jj  tt|  t jj| j	}t jj
t| D ]}t|| | }q:|S rl   )numbaparforsparforrm   min_checkerlencpythonbuiltinsget_type_max_valuedtyperp   r   rz   valir^   r^   rd   r{      s    c                 S   sR   t jj  tt|  t jj| j	}t jj
t| D ]}t|| | }q:|S rl   )r}   r~   r   rm   r   r   r   r   r   r   rp   minr   r^   r^   rd   r{      s    c                 S   sL   t jj  tt|  t jj| j	}t 
| jD ]}t|| | }q4|S rl   )r}   r~   r   rm   r   r   r   r   r   r   r   shaper   r   r^   r^   rd   r{      s    ndim
isinstancer   r
   Z
NPDatetimeZNPTimedelta)return_typeargr{   r^   r^   rd   min_parallel_impl   s    




r   c                 C   sR   |j dkrdd }n:|j dkrFt|jtjtjfr<dd }qNdd }ndd }|S )Nr   c                 S   s   | d S rx   r^   ry   r^   r^   rd   max_1   s    z max_parallel_impl.<locals>.max_1r|   c                 S   sR   t jj  tt|  t jj| j	}t jj
t| D ]}t|| | }q:|S rl   )r}   r~   r   rm   max_checkerr   r   r   get_type_min_valuer   rp   r   r   r^   r^   rd   r      s    c                 S   sR   t jj  tt|  t jj| j	}t jj
t| D ]}t|| | }q:|S rl   )r}   r~   r   rm   r   r   r   r   r   r   rp   maxr   r^   r^   rd   r      s    c                 S   sL   t jj  tt|  t jj| j	}t 
| jD ]}t|| | }q4|S rl   )r}   r~   r   rm   r   r   r   r   r   r   r   r   r   r   r^   r^   rd   r      s    r   )r   r   r   r^   r^   rd   max_parallel_impl   s    




r   c                 C   sx   t jj  tt|  |  }t jj	|j
}tjd|}t jjt|D ] }tj||| }t||}qP|jS Nr   )r}   r~   r   rm   argmin_checkerr   ravelr   r   r   r   r   
IndexValuerp   r   indexrz   Ainit_valZivalr   Z	curr_ivalr^   r^   rd   argmin_parallel_impl   s    r   c                 C   sx   t jj  tt|  |  }t jj	|j
}tjd|}t jjt|D ] }tj||| }t||}qP|jS r   )r}   r~   r   rm   argmax_checkerr   r   r   r   r   r   r   r   rp   r   r   r   r^   r^   rd   argmax_parallel_impl   s    r   c                 C   sP   t jj  | jd }|jd }d}t jj|D ]}|| | ||  7 }q2|S r   )r}   r~   r   rm   r   rp   )abrj   msr   r^   r^   rd   dotvv_parallel_impl   s    

r   c                 C   s^   t jj  | j}|j\}}t|| j}t jj|D ] }|| | ||d d f  7 }q8|S rl   )	r}   r~   r   rm   r   npzerosr   rp   )r   r   rj   r   ncr   r^   r^   rd   dotvm_parallel_impl   s    
r   c           	      C   st   t jj  | j\}}|j}t|| j}t jj|D ]6}d}t	|D ]}|| ||f ||  7 }qH|||< q8|S r   )
r}   r~   r   rm   r   r   emptyr   rp   rq   )	r   r   r   r   rj   r   r   r   jr^   r^   rd   dotmv_parallel_impl   s    

r   c                 C   sX   t |tjjrTt |tjjrT|j|j  kr4dkr<n ntS |jdkrT|jdkrTtS d S )Nr|      )r   r
   npytypesArrayr   r   r   )r   ZatypZbtypr^   r^   rd   dot_parallel_impl  s    r   c                    sD   | d |j dkrdd }n$|j dkr4 fdd}n fdd}|S )Nr   c                 S   s   | d S rx   r^   ry   r^   r^   rd   sum_1  s    z sum_parallel_impl.<locals>.sum_1r|   c                    s8   t jj   }t jjt| D ]}|| | 7 }q"|S rl   r}   r~   r   rm   rp   r   r   Zzeror^   rd   r     s
    c                    s2   t jj   }t | jD ]}|| | 7 }q|S rl   r}   r~   r   rm   r   r   r   r   r^   rd   r     s
    r   )r   r   r   r^   r   rd   sum_parallel_impl  s    


r   c                    sD   | d |j dkrdd }n$|j dkr4 fdd}n fdd}|S )Nr|   r   c                 S   s   | d S rx   r^   ry   r^   r^   rd   prod_1)  s    z"prod_parallel_impl.<locals>.prod_1c                    s8   t jj   }t jjt| D ]}|| | 9 }q"|S rl   r   r   Zoner^   rd   r   ,  s
    c                    s2   t jj   }t | jD ]}|| | 9 }q|S rl   r   r   r   r^   rd   r   3  s
    r   )r   r   r   r^   r   rd   prod_parallel_impl%  s    


r   c                    sD   | d |j dkrdd }n$|j dkr4 fdd}n fdd}|S )Nr   c                 S   s   | d S rx   r^   ry   r^   r^   rd   mean_1A  s    z"mean_parallel_impl.<locals>.mean_1r|   c                    s@   t jj   }t jjt| D ]}|| | 7 }q"|t|  S rl   r   r   r   r^   rd   r   D  s
    c                    s8   t jj   }t | jD ]}|| | 7 }q|| j S rl   )r}   r~   r   rm   r   r   sizer   r   r^   rd   r   K  s
    r   )r   r   r   r^   r   rd   mean_parallel_impl<  s    


r   c                 C   s4   |j dkrdd }n|j dkr(dd }ndd }|S )Nr   c                 S   s   dS r   r^   ry   r^   r^   rd   var_1U  s    z var_parallel_impl.<locals>.var_1r|   c                 S   s`   |   }tjj  d}tjjt| D ](}| | | }|t|t	| 7 }q*|t|  S r   )
meanr}   r~   r   rm   rp   r   r   realconjrz   r   Zssdr   r   r^   r^   rd   r   X  s    c                 S   sX   |   }tjj  d}t| jD ](}| | | }|t|t	| 7 }q$|| j
 S r   )r   r}   r~   r   rm   r   r   r   r   r   r   r   r^   r^   rd   r   c  s    r   )r   r   r   r^   r^   rd   var_parallel_implS  s    




r   c                 C   s   dd }|S )Nc                 S   s   |   d S )Ng      ?)varry   r^   r^   rd   std_1p  s    z std_parallel_impl.<locals>.std_1r^   )r   r   r   r^   r^   rd   std_parallel_implo  s    r   c                    s   t | j  fdd} fdd} fdd}tdd |D rJd	d
 }ndd
 }t|dkrb|S t|dkrr|S t|dkr|S t|dkr|S td|d S )Nc                    s   t d| d S )Nr   r|   r   arange)stopr   r^   rd   arange_1w  s    z&arange_parallel_impl.<locals>.arange_1c                    s   t | |d S Nr|   r   startr   r   r^   rd   arange_2z  s    z&arange_parallel_impl.<locals>.arange_2c                    s   t | || S rl   r   )r   r   stepr   r^   rd   arange_3}  s    z&arange_parallel_impl.<locals>.arange_3c                 s   s   | ]}t |tjV  qd S rl   )r   r
   Complexrb   r   r^   r^   rd   	<genexpr>  s     z'arange_parallel_impl.<locals>.<genexpr>c           
      S   sx   t jj  ||  | }t|j}t|j}tt	t
||d}t||}t jj|D ]}	| |	|  ||	< q^|S r   )r}   r~   r   rm   mathceilr   imagintr   r   r   r   rp   )
r   r   r   r   Znitems_cnitems_rZnitems_initemsarrr   r^   r^   rd   arange_4  s    z&arange_parallel_impl.<locals>.arange_4c           	      S   sd   t jj  t||  | }tt|d}t	||}| }t jj
|D ]}| ||  ||< qJ|S r   )r}   r~   r   rm   r   r   r   r   r   r   rp   )	r   r   r   r   r   r   r   r   r   r^   r^   rd   r     s    r|   r         zparallel arange with types {})r   r   anyr   
ValueErrorformat)r   rs   r   r   r   r   r^   r   rd   arange_parallel_implt  s     


r   c                    sP   t | j dd } fdd}t|dkr.|S t|dkr>|S td|d S )Nc                 S   s   t | |dS )N2   )r   linspacer   r^   r^   rd   
linspace_2  s    z*linspace_parallel_impl.<locals>.linspace_2c                    s\   t jj  t| }|d }||  }| |d< t jj|D ]}| |||   ||< q>|S )Nr|   r   )r}   r~   r   rm   r   r   rp   )r   r   numr   divdeltar   r   r^   rd   
linspace_3  s    z*linspace_parallel_impl.<locals>.linspace_3r   r   zparallel linspace with types {})r   r   r   r   r   )r   rs   r   r   r^   r   rd   linspace_parallel_impl  s    

r   c                 C   s   t S rl   )r   rr   r^   r^   rd   <lambda>      r   c                 C   s   t S rl   )r   r   r^   r^   rd   r     r   )ZargminnumpyZargmaxr   r   r   r   r   Zaminr   Zamaxr   )sumr   )prodr   )r   r   )r   r   )Zstdr   )dotr   )r   r   )r   r   c                 C   s    |j dkrdd }ndd }|S )zParallel implementation of ndarray.fill.  The array on
       which to operate is retrieved from get_call_name and
       is passed along with the value to fill.
    r|   c                 S   s0   t jj  t jjt| D ]}|| |< qd S rl   r   r   r^   r^   rd   fill_1  s    
z"fill_parallel_impl.<locals>.fill_1c                 S   s*   t jj  t | jD ]}|| |< qd S rl   r   r   r^   r^   rd   r     s    
r   )r   r   r   r   r^   r^   rd   fill_parallel_impl  s    

r   fillc                 C   s   | dkrt dd S )Nr   zDzero-size array to reduction operation maximum which has no identityr   Zarr_sizer^   r^   rd   r     s    r   c                 C   s   | dkrt dd S )Nr   zDzero-size array to reduction operation minimum which has no identityr   r   r^   r^   rd   r     s    r   c                 C   s   | dkrt dd S )Nr   z*attempt to get argmin of an empty sequencer   r   r^   r^   rd   r     s    r   c                 C   s   | dkrt dd S )Nr   z*attempt to get argmax of an empty sequencer   r   r^   r^   rd   r     s    r   checker_implnamefunc)r   r   r   r   r   r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	LoopNestzThe LoopNest class holds information of a single loop including
    the index variable (of a non-negative integer value), and the
    range variable, e.g. range(r) is 0 to r-1 with step size 1.
    c                 C   s   || _ || _|| _|| _d S rl   )index_variabler   r   r   )selfr  r   r   r   r^   r^   rd   __init__	  s    zLoopNest.__init__c                 C   s   d | j| j| j| jS )Nz3LoopNest(index_variable = {}, range = ({}, {}, {})))r   r  r   r   r   r  r^   r^   rd   __repr__  s       zLoopNest.__repr__c                 C   sb   g }| | j t| jtjr*| | j t| jtjrD| | j t| jtjr^| | j |S rl   )appendr  r   r   r   Varr   r   )r  all_usesr^   r^   rd   	list_vars  s    zLoopNest.list_varsN)ru   rv   rw   __doc__r  r  r
  r^   r^   r^   rd   r    s   r  c                       sV   e Zd ZdZde d fdd
Zdd Zdd	 ZdddZdddZ	dd Z
  ZS )Parforr   F)no_sequential_loweringracesc	                   s   t t| jd|d t| j| _t|  jd7  _|| _|| _|| _|| _	d | _
|| _t|dksft|g| _|| _|	| _|
| _g | _i | _tjrd}t|| j|| d S )Nr   )oplocr|   z9Parallel for-loop #{} is produced from pattern '{}' at {})superr  r  type
id_counterid
loop_nests
init_block	loop_body	index_varparams	equiv_setr   AssertionErrorpatternsflagsr  r  redvarsreddictr   DEBUG_ARRAY_OPT_STATSr`   r   )r  r  r  r  r  r  r  patternr  r  r  fmt	__class__r^   rd   r  #  s4    
  zParfor.__init__c                 C   s,   dt | j t| j t| j t| j S )Nzid=)strr  reprr  r  r  r  r^   r^   rd   r  P  s
    zParfor.__repr__c                 C   sf   g }| j  D ] \}}|jD ]}|| 7 }qq| jD ]}|| 7 }q6| jjD ]}|| 7 }qP|S )zslist variables used (read/written) in this parfor by
        traversing the body and combining block uses.
        )r  itemsbodyr
  r  r  )r  r	  rj   r   stmtloopr^   r^   rd   r
  T  s    

zParfor.list_varsNc                 C   s8   |dk	r| j j}|| j _| j |}|dk	r4|| j _|S )zvget the shape classes for a given variable.
        If a typemap is specified then use it for type resolution
        N)r  typemapget_shape_classes)r  r   r+  Zsave_typemapresr^   r^   rd   r,  e  s    
zParfor.get_shape_classesc                 C   s   |pt j}td| jdd|d td| j|d td| j|d td| j|d | j	D ]}t||d q\td|d | j
| t| j D ]$\}}td	|f |d || qtd
| jdd|d d S )Nzbegin parfor {}   -)filezindex_var = z	params = zraces = zinit block:z	label %s:zend parfor {})sysstdoutr`   r   r  centerr  r  r  r  r  dumpsortedr  r'  )r  r0  loopnestoffsetblockr^   r^   rd   r4  w  s    

zParfor.dumpc                 C   s|   | j dkrd}t|| j D ]Z}||}|dkr>d}t|t|tjr|jtjkrd}t	
|||jtjf | jqdS )z?
        Check that Parfors params are of valid types.
        Nz?Cannot run parameter validation on a Parfor with params not setzDCannot validate parameter %s, there is no type information availablea  Use of a tuple (%s) of length %d in a parallel region exceeds the maximum supported tuple size.  Since Generalized Universal Functions back parallel regions and those do not support tuples, tuples passed to parallel regions are unpacked if their size is below a certain threshold, currently configured to be %d. This threshold can be modified using the Numba environment variable NUMBA_PARFOR_MAX_TUPLE_SIZE.)r  r   getr   r
   	BaseTuplecountr   ZPARFOR_MAX_TUPLE_SIZEr   UnsupportedParforsErrorr  )r  r+  msgptyr^   r^   rd   validate_params  s     


zParfor.validate_params)N)N)ru   rv   rw   r  setr  r  r
  r,  r4  r@  __classcell__r^   r^   r#  rd   r    s   -

r  c                 C   sT   |j }t| }|jdd}||| t| | |jd | _|rL||jd< g g fS )z/Recursive array analysis for parfor nodes.
    r   N)func_irwrap_parfor_blocks
equiv_setsr9  rununwrap_parfor_blocksr  )r   r  r+  rY   rC  Zparfor_blocksZbackup_equivsetr^   r^   rd   _analyze_parfor  s    

rH  c                   @   s   e Zd ZdZdd Zdd Zedd Zejdd Zd1d
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 d! Zd"d# Zd$d% Zd&d' Zd(d) Zd2d+d,Zd-d. Zd/d0 Zd	S )3ParforDiagnosticszHolds parfor diagnostic info, this is accumulated throughout the
    PreParforPass and ParforPass, also in the closure inlining!
    c                 C   s>   d | _ t | _d| _tt| _tt| _g | _i | _	d| _
d S )NZ__numba_parfor_gufuncF)r   dictreplaced_fnsinternal_namer   listfusion_infonested_fusion_infofusion_reports
hoist_info	has_setupr  r^   r^   rd   r    s    

zParforDiagnostics.__init__c                 C   s\   || _ | j jj| _| j j| _|| _| j| jkr6d| _nd| j| jf | _| 	 | _
d| _d S )NzInternal parallel functionzFunction %s, %sT)rC  func_idfunc_qualnamer   r  linefusion_enabledrL  purposeget_parforsinitial_parforsrR  )r  rC  rV  r^   r^   rd   setup  s    

zParforDiagnostics.setupc                 C   s   | j S rl   Z
_has_setupr  r^   r^   rd   rR    s    zParforDiagnostics.has_setupc                 C   s
   || _ d S rl   r[  )r  stater^   r^   rd   rR    s    Nc                 C   s   t |  S rl   )r   rX  r  blocksr^   r^   rd   count_parfors  s    zParforDiagnostics.count_parforsc                 C   s    t |}| || t| d S rl   )rD  _get_parforsrG  )r  r   parfors_listr^  r^   r^   rd   _get_nested_parfors  s    z%ParforDiagnostics._get_nested_parforsc                 C   sB   |  D ]4\}}|jD ]$}t|tr|| | || qqd S rl   )r'  r(  r   r  r  rb  )r  r^  ra  labelblkr)  r^   r^   rd   r`    s
    


zParforDiagnostics._get_parforsc                 C   s   g }|  | jj| |S rl   )r`  rC  r^  )r  ra  r^   r^   rd   rX    s    zParforDiagnostics.get_parforsc                 C   sv   g }| j  D ]b\}}|dg }|D ]H}t|jtjr&|jjdkr&tt	| j
|j}|d k	r&|dkr&|| q&q|S )Nhoistedcall)r   r   )rQ  r'  r9  r   valuer   Exprr  r:   r8   rC  r  )r  Zallocspf_iddatar)  instrf  r^   r^   rd   hoisted_allocations  s    z%ParforDiagnostics.hoisted_allocationsc                 C   s   t |}|i krg t fS t }| D ]}|D ]}|| q2q*t| }|| }|dkrft }t }ttt| |d D ]<}|	|}	|	dk	r|	||< q|	g kr|| qg ||< qg }
t
| D ]}|
||  q|
|fS )zf
        compute adjacency list of the fused loops
        and find the roots in of the lists
        Nr|   )copydeepcopyrA  valuesaddkeysrq   r   unionr9  r5  r  )r  Z_ar   Zvtxvri   Zpotential_rootsrootsZ	not_rootsr   rj   r^   r^   rd   compute_graph_info  s.    

"


z$ParforDiagnostics.compute_graph_infoc                    s(    fdd  |||dd\}}||fS )z
        Computes the number of fused and serialized loops
        based on a fusion adjacency list `fadj` and a nested
        parfors adjacency list `nadj` for the root, `root`
        c                    s\   || D ]J}|d7 }|| g kr2|t | | 7 }q | ||||\}}||7 }|}q||fS r   r   )fadjnadjrootnfusednserialknfns
count_rootr^   rd   r  +  s    z/ParforDiagnostics.get_stats.<locals>.count_rootr   r^   )r  rw  rx  ry  rz  r{  r^   r  rd   	get_stats%  s    
zParforDiagnostics.get_statsc                 C   sB   g }| ||  || D ]"}|| g kr| | || q|S )zf
        returns a list of nodes reachable in an adjacency list from a
        specified root
        )extendreachable_nodes)r  adjry  Zfusersr|  r^   r^   rd   r  8  s    z!ParforDiagnostics.reachable_nodesc              	   C   s  || d }|j d }td|jjd }| jjj}| | j\}}| | j\}	}
||	g}t	|t
r|d dkr|d d }|j|krtd|jd S g }|D ]B}|r|| D ]}|| || q|rtdt|d   S q|j D ]6}|jD ]*}|jj|krtd|jjd     S qq| jj D ]t}zV|j|}t|d ddD ]4}|j| }t	|tsVtd|jjd } qqVW n tk
r   Y nX q4|S )zX
        pd_id - the parfors id
        parfors_simple - the simple parfors map
        r   r|   internalr   )r  r   r  rU  rC  filenameru  rO  rN  r   tupler  sort_pf_by_liner   r  ro  r(  r^  r   rq   r  r   )r  ri  parfors_simplepfr!  rU  r  rx  nrootsrw  frootsZgraphsZreported_loctmpr  r|  rd  r)  idxr   r^   r^   rd   r  D  sD    






z!ParforDiagnostics.sort_pf_by_linec           	      C   s   t  }t| jdd dD ]}|jd }|jd }|j}t|tr|d dkr|d dkrdtt	|d	 d }|d	 d }d
|df }n,|d dkrd}n|d dkrd}ndst
d}|rt||j||f  |||f||j< q|S )Nc                 S   s   | j jS rl   )r  rU  ri   r^   r^   rd   r     r   z6ParforDiagnostics.get_parfors_simple.<locals>.<lambda>keyr   r   r|   r  .r   z%s %sz(internal parallel version)userzuser defined pranger   zinternal pndindexz5Parallel for-loop #%s: is produced from %s:
    %s
 
)rJ  r5  rY  r  r  r   r  joinreversedrM  r  rk   r  )	r  print_loop_searchr  r  Z	r_patternr!  r  Zreplfnr"  r^   r^   rd   get_parfors_simple~  s*    


z$ParforDiagnostics.get_parfors_simplec                 C   s   |  | j\}}|  | j\}}t|t|kr>t|}|}nt|}|}tt||D ]}|g  qXt }	|r|D ]}
||
 g krv|	|
 qv||	A }i }|D ]}| ||}d||f||< qi }|	D ]}| ||}d||f||< q|	 }|
| |S )Nfusenest)ru  rN  rO  r   rq   r  rA  rp  r  rm  update)r  r  rw  r  rx  _nrootslimr  ri   r  r   Z	all_rootsZfroots_linesrU  Znroots_lines	all_linesr^   r^   rd   get_all_lines  s4    
zParforDiagnostics.get_all_linesc                 C   s  | j jj}|  }| j jj}zt| }W n t	k
rF   d }Y nX |r|rt
dd |D }tt}| D ]8\}	}
||	 d j|krv| |	|}|| t|	 qvt
dgdd | D  }|d|tt|d    }g }|d |d|  ||d d	  d
}t
d| j jjd }t||D ]\}}||d }|d k	rfdd| }nd}|d}t|}|r||d ||}n||d ||}||||d    q8td| ntd d S )Nc                 S   s   g | ]}t |qS r^   rv  rb   ri   r^   r^   rd   re     s     z4ParforDiagnostics.source_listing.<locals>.<listcomp>r|   c                 S   s   g | ]}t |qS r^   rv  r  r^   r^   rd   re     s     r   
zParallel loop listing for %sr/  z	|loop #IDz{0:{1}}| {2}r   #,   zNo source available)rC  r  r  r_  rS  r   inspect	getsourcerf   OSErrorr   r   rM  r'  r  r  r%  ro  r   rU  	enumerater9  r  stripr   r`   )r  r  purpose_strr  r;  	func_namelinesZ	src_widthZmap_line_to_pfr|  rs  Z
match_lineZmax_pf_per_liner\   newlinesr"  ZlstartnorU  Zpf_idsZpfstrstrippedZsrclenrj   r^   r^   rd   source_listing  sF    





z ParforDiagnostics.source_listingc                    s  dt  j\}}j\}}t |t |krJt |}|}nt |}|}tt ||D ]}|g  qd fdd}	 fdd}
d}g }t| D ]V\}}|\}}}|dkr||kr|
d||d|}q|d	kr|	|||||}qdstqd S )
N+--c                    sN    fdd || g krJt d|   | ||d td |d }|S )Nc              	      s   t  | d d|df   || D ]}|| g krg }| |d  d d|df   | | g kr|kr| |}|D ](}| |d  d d|df   q| t d| q&| |||d  q&d S )Nr  %s%s %s
(parallel)r|   r  )rk   r  r  r  )fadj_nadj_nrootdepthr|  r=  fusedr   )facprint_greportedr  swordr^   rd   r    s    $&
zHParforDiagnostics.print_unoptimised.<locals>.print_nest.<locals>.print_gParallel region %s:r   r  r|   rk   r`   r  r  Ztherootr  	region_idr  r  r  )r  r  rd   
print_nest  s    z7ParforDiagnostics.print_unoptimised.<locals>.print_nestc                    s   g }t d|  | | d d|df   || g krvt||}|D ]$}| | d d|df   qP|d }t d| td |S )Nr  r  r  r  r|   r  )rk   r  r5  r  r  r`   )r?  ri  r  r  r  r=  r  r|  r  r^   rd   
print_fuse  s     "z7ParforDiagnostics.print_unoptimised.<locals>.print_fuser   r  fr  )	r   ru  rN  rO  rq   r  r5  r'  r  )r  r  rw  r  rx  r  r  r  ri   r  r  r  r  rU  infoopt_tyri  r  r^   r  rd   print_unoptimised  s.    
z#ParforDiagnostics.print_unoptimisedc                    s  dt  j\}}j\}}t |t |krJt |}|}nt |}|}tt ||D ]}|g  qdt  fdd}	 fdd}
d}g }t| D ]X\}}|\}}}|dkr||kr|
d||d|}q|d	kr|	|||||}qdst	qrt D ]j\}}d
}|d }|d }|d }|dkrl|d7 }t
||||||f  n|d7 }t
||||f  qnt
d d S )Nr  c                    st    fdd || g krpt d  t d|df  |ddd<  | ||d td	 d S )
Nc                    s   || D ]} | d d|df  }|| g krg }| | g krz|krzt | |}|d7 }|ddd |D 7 }|d7 }| t|  d	  t|7  < nt|d  | |||d
   d  d
7  < qd S )Nr  r  z(serial, fused with loop(s): r  c                 S   s   g | ]}t |qS r^   r%  r  r^   r^   rd   re   Q  s     zZParforDiagnostics.print_optimised.<locals>.print_nest.<locals>.print_g.<locals>.<listcomp>)r  r|   
serialized)r5  r  r  r  rk   r   )r  r  r  r  r|  r=  r  )r  r  r  r  r  summaryr  r^   rd   r  I  s    
zFParforDiagnostics.print_optimised.<locals>.print_nest.<locals>.print_gr  r  r  r   ry  r  r  r|   r  r  r  r  r  r  r  )r  r  r  rd   r  H  s    z5ParforDiagnostics.print_optimised.<locals>.print_nestc                    s   t d|   | d d|df  }g }|| g krft||}|d7 }|ddd |D 7 }|t|d	d
|< |d7 }t | td |d }|S )Nr  r  r  z	(parallelr  r  c                 S   s   g | ]}t |qS r^   r  r  r^   r^   rd   re   k  s     zIParforDiagnostics.print_optimised.<locals>.print_fuse.<locals>.<listcomp>r   r  r  r  r|   )rk   r5  r  r  r   r`   )r?  ri  r  r  r  r=  r  r  r^   rd   r  d  s    z5ParforDiagnostics.print_optimised.<locals>.print_fuser   r  r  r  z5
 
Parallel region %s (loop #%s) had %s loop(s) fusedry  r  r  zE and %s loop(s) serialized as part of the larger parallel loop (#%s).r  z&Parallel structure is already optimal.)r   ru  rN  rO  rq   r  rJ  r5  r'  r  rk   )r  r  rw  r  rx  r  r  r  ri   r  r  r  r  rU  r  r  ri  r  r|  rs  r=  ry  r  r  r^   r  rd   print_optimised4  sH    



z!ParforDiagnostics.print_optimisedc                 C   s  d}t d | j D ]\}}|dg }|D ]}t|jtjr.z|jj}|dkrd}|j	}t
|||f  ztj|j}	W n" tk
r   tj|j}	Y nX t|	}
|
r|jrt
d|
|jdk rdn|jd	     t
d
 d}W q. ttfk
r   Y q.X q.q|st
d d S )NFzAllocation hoisting:re  r   zThe memory allocation derived from the instruction at %s is hoisted out of the parallel loop labelled #%s (it will be performed before the loop is executed and reused inside the loop):z   Allocation:: r   r   r|   z0    - numpy.empty() is used for the allocation.
TzNo allocation hoisting found)r`   rQ  r'  r9  r   rg  r   rh  attrr  rk   ospathrelpathr  r   abspath	linecachegetlinesrU  r  KeyErrorAttributeError)r  foundri  rj  r)  rk  r  r=  r  r  r  r^   r^   rd   allocation_hoist  s2    

(
z"ParforDiagnostics.allocation_hoistc                 C   s   t d t d d}| jr| j D ]~\}}|dd }|dd }|sZ|sZt d|  q$t d|  |rt d d	d
 |D  d}|r$t d dd
 |D  d}q$|std td d S )Nr  zInstruction hoisting:Fre  not_hoistedzloop #%s has nothing to hoist.z	loop #%s:z  Has the following hoisted:c                 S   s   g | ]}t d | qS )    %sr_   ra   r^   r^   rd   re     s     z7ParforDiagnostics.instruction_hoist.<locals>.<listcomp>Tz   Failed to hoist the following:c                 S   s    g | ]\}}t d ||f qS )z
    %s: %sr_   rb   ri   rc   r^   r^   rd   re     s     zNo instruction hoisting foundzP--------------------------------------------------------------------------------)r`   rQ  r'  r9  rk   )r  Zhoist_info_printedri  rj  re  r  r^   r^   rd   instruction_hoist  s,    z#ParforDiagnostics.instruction_hoistr|   c               	      s   j std jjj} jj} j|kr4d}d}nd||f }d}d}d}d}d}	d}
d}d}d}d}d}|dkr~d}d}ntd	|d
krd}|dkrd}|dkrd}	d}
|dkrd}d}d}|dkr|sd S td tt	d  td| 
t	d tt	d  td |r$td
t	d  |}  }|rTtd|  tdt	   jjj}ztj|}W n" tk
r   tj|}Y nX |r || d  }dd |D }t|}|s|	rtstd
t	d d}t| nd}t| tt	d  |dkr fdd}|r` jD ],}|\}}}td||f  td|  q2 ji kr|	rtd  | jd!d" |	rֈ jrd#}nd$}td%||d&d'd |D  tt	d  td |
r* ji kr*td(
t	d td) d*}d+}| j|| tt	d  td  |}|r`td,
t	d  | tt	d  |rtd-
t	d  | tt	d  td tt	d  td |s|rtd.
d/d |r҈    |r !  ntd0|| d S )1Nzself.setup has not been calledzInternal parallel functions r  z Function %s, %s r  F)r|   r   r   r   Tz1Report level unknown, should be one of 1, 2, 3, 4)r   r   r   )r   r   r   r   z
 =z% Parallel Accelerator Optimizing: %s r  zLooking for parallel loopsr/  z
Found %s parallel loops.r  c                 S   s   g | ]
}|j qS r^   )r  r  r^   r^   rd   re     s     z*ParforDiagnostics.dump.<locals>.<listcomp>z Fusing loops zPAttempting fusion of parallel loops (combines loops with similar properties)...
z+Performing sequential lowering of loops...
r  c                    s8   t   fdd}| \}|| d S )Nc                    sF    fdd |D ]*}t d|f   |d t d qd S )Nc                    sL   | | D ]>}t  | d d|f   | | g kr| ||d  qd S )Nr  r  r|   rk   )r  ry  r  r|  )r  node_msgr  r  r^   rd   r  1  s    zYParforDiagnostics.dump.<locals>.dump_graph_indented.<locals>.print_graph.<locals>.print_gr  r|   r  r  )r  rt  r   )r  rj   r  root_msgr  )r  rd   print_graph0  s
    zHParforDiagnostics.dump.<locals>.dump_graph_indented.<locals>.print_graph)r   ru  )r   r  r  r  rt  r  r  )r  rj   r  r  rd   dump_graph_indented.  s    
z3ParforDiagnostics.dump.<locals>.dump_graph_indentedz#  Trying to fuse loops #%s and #%s:r  z
 
Fused loop summary:
z&has the following loops fused into it:z(fused)z4Following the attempted fusion of parallel for-loopsWith fusion disabledzL
{} there are {} parallel for-loop(s) (originating from loops labelled: {}).r  c                 S   s   g | ]}d | qS )z#%sr^   r  r^   r^   rd   re   P  s     z Optimising loop nests zNAttempting loop nest rewrites (optimising for the largest parallel loops)...
 zis a parallel loopz--> rewritten as a serial loopz Before Optimisation z After Optimisation zLoop invariant code motionr[   z+Function %s, %s, has no parallel for-loops.)"rR  RuntimeErrorrC  rS  rT  r  rL  r   rk   
_termwidthr3  r  r_  r  r  r  r  r  r  rX  r   sequential_parfor_loweringrP  rN  rV  r   r  rO  r  r`   r  r  r  r  ) r  levelr   rU  r  rW  r  Zprint_source_listingZprint_fusion_searchZprint_fusion_summaryZprint_loopnest_rewriteZprint_pre_optimisedZprint_post_optimisedZprint_allocation_hoistZprint_instruction_hoistZprint_internalr  r;  r  r  r~   
parfor_ids	n_parforsr=  r  reportl1l2after_fusionr  r  r  r^   r  rd   r4    s    







  



zParforDiagnostics.dumpc                 C   s   d}|t | j7 }|S )NzParforDiagnostics:
)r&  rK  r  r   r^   r^   rd   __str__|  s    zParforDiagnostics.__str__c                 C   s   d}|S )NrI  r^   r  r^   r^   rd   r    s    zParforDiagnostics.__repr__)N)r|   )ru   rv   rw   r  r  rZ  propertyrR  setterr_  rb  r`  rX  rl  ru  r  r  r  r  r  r  r  r  r  r  r4  r  r  r^   r^   r^   rd   rI    s6   


(:,,A`
 1rI  c                   @   s.   e Zd ZdZi dfddZdd Zdd ZdS )	PreParforPasszwPreprocessing for the Parfor pass. It mostly inlines parallel
    implementations of numpy functions if available.
    Nc	           	      C   sL   || _ || _|| _|| _|| _|| _|| _|d kr6t}|| _ddd| _	d S )Nr   )replaced_funcreplaced_dtype)
rC  r+  	calltypes	typingctx	targetctxoptionsswappedswap_functions_mapreplace_functions_mapstats)	r  rC  r+  r  r  r  r  r  r  r^   r^   rd   r    s    zPreParforPass.__init__c                 C   s@   t | j| j| j| j | jjr,| | jj t	| jj| j_dS )z(Run pre-parfor processing pass.
        N)
r6   rC  r+  r  r  r  r   _replace_parallel_functionsr^  r4   r  r^   r^   rd   rF    s    
 zPreParforPass.runc              	      s  j ddlm t| rΈ \} t jD ]\}t|t	j
r:|j}j|j |jtt	jrjdkr fdd}t|rjd  d7  <  qq:tt	jr:jdkr:jd	kr:jjj }t|tjjr:|j} j}|j}	t	|td
|	}
tjtj|
j< t	dt|	}t	
||
|	}t |}|dkr^d}t	|td|	}t!|j|j< t	
t	"||	||	}t	|td|	}t#tj}t$j%j&|}|'j(j|j fi  tj)&|j|j< t	j*|
d	|	}t	
|||	}t	|td|	}tj+|j|j< t	j,||gd|	}t	
|||	}t-j|j j|j j.|< ||_ j/d|  j/d|  j/d|  j/d| jd  d7  <  qq:qdS )z
        Replace functions with their parallel implementation in
        replace_functions_map if available.
        The implementation code is inlined to enable more optimization.
        r   )inline_closure_callrf  c                     s  t jj} tj}j|d }|d krt|dkrt|d tj	rtj
|d j tjjrt|d d }|d k	rjd|d  t|d k	 tfddjD }z|f| }W n   d }Y nX t|d k	 tjjjj}t|d< t|d< t|d< t|d }|d k	r0|j||j< j| |jj|j
j\}}t|d	d
}	|	D ]H}
|
 D ]8\}}|d dkrv||j |  j! j"g|<  qjqvqjdS )Nr   r|   r   c                 3   s   | ]} j |j V  qd S rl   )r+  r   r  r  r^   rd   r     s     zRPreParforPass._replace_parallel_functions.<locals>.replace_func.<locals>.<genexpr>r}   r   r   F)Ztopological_orderingrp   T)#r>   rC  r   r8   r  r9  r   r   r   r  r+  r   r
   r   r   replace_functions_ndarrayrs   insertr;   r  rm  rS  __globals__r}   r   r   replace_functions_checkers_mapr  r  r  r2   r'  ru   r(  r  )Zfunc_defcallnameZ	repl_funcZtypsnew_funcgcheck
new_blocks_
call_tablerf  r|  rs  r8  exprr   r  lhs_typr  r  Z	work_listr^   rd   replace_func  sb    


       z?PreParforPass._replace_parallel_functions.<locals>.replace_funcr  r|   getattrr   	$np_g_varr   boolZbool_z$np_typ_varz$dtype_attr_varz
$dtype_varr^   r  N)0r  numba.core.inline_closurecallr  rM  r'  popr  r(  r   r   Assigntargetr+  r   rg  rh  r  r:   r   r  r
   r   r   r   scoper  r  r   miscModuler   Globalr%  StringLiteralConstfind_templater}   corerQ   get_call_typer  	functionsr  ZDTyperf  rP   r  r  )r  r^  rc  instrlhsr  typr   r  r  g_np_varg_npg_np_assignZ	dtype_strZtyp_varZtyp_var_assignZdtype_attr_vartempZtfuncZdtype_attr_getattrZdtype_attr_assignZ	dtype_varZdtype_getattrZdtype_assignr^   r  rd   r    s    -	
  
  

 

z)PreParforPass._replace_parallel_functions)ru   rv   rw   r  r  rF  r  r^   r^   r^   rd   r    s    

r  c                 C   s*   t jjjjjD ]}|j| kr|  S qd S rl   )r}   r   r   Z	templatesZbuiltin_registryr"  r  )r  ftr^   r^   rd   r  %  s    
r  c                   @   s   e Zd ZdZe fddZdS )ParforPassStateszCThis class encapsulates all internal states of the ParforPass.
    c                 C   s   || _ || _|| _|| _|| _|| _|| _|
| _|
j| _	|
j
| _
|
j| _t| j| j | j| j| _tjt|j  || _|	| _d|	kri |	d< d S )Nr~   )rC  r+  r  r  r  r   r  diagnosticsrK  swapped_fnsrN  rO  rY   ArrayAnalysisr   _the_max_labelr  r   r^  rq  r  metadata)r  rC  r+  r  r   r  r  r  r  r0  r,  r^   r^   rd   r  /  s,       zParforPassStates.__init__N)ru   rv   rw   r  rI  r  r^   r^   r^   rd   r+  +  s   r+  c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )ConvertInplaceBinop0Parfor subpass to convert setitem on Arrays
    c                 C   s   || _ g | _dS zV
        Parameters
        ----------
        pass_states : ParforPassStates
        Npass_states	rewrittenr  r5  r^   r^   rd   r  L  s    zConvertInplaceBinop.__init__c              	   C   s  | j }t|}|D ]}|| }g }|j|}|jD ]}t|tjr|j}	|j	}
t|
tj
r|
jdkr|
j}|
j}|
j}|j|j }|j|j }t|tjjrt|tjjr| |||
j||}| jt||dd |t||	|g}t|tr|| q4|| q4||_qd S )Ninplace_binopoldnewreason)r5  r/   rY   get_equiv_setr(  r   r   r  r  rg  rh  r  r  r$  rhsr+  r   r
   r   r   _inplace_binop_to_parforZimmutable_fnr6  r  rJ  rM  r  )r  r^  r5  
topo_orderrc  r8  new_bodyr  r#  r$  r  r  r  rg  
target_typ	value_typ	new_instrr^   r^   rd   rF  U  sD    
   
zConvertInplaceBinop.runc              	   C   s  | j }|j}|j|j }|j}	t||}
|j|j }||}t|j|||\}}t	 }t||}t
|j|||\}}t|td|}|j|j|j< tj|||}t|j|||j|< |jt||| t|td|}|	|j|j< tj|||}t|	|||j|< |jt||| t|td|}|	|j|j< tj||||}|jt||| | j j|	|j}t||||j|< t||||}ttj|||	|j|< |j| t||
i |||d|j}||i|_tjdkrtd |   |S )generate parfor from setitem node with a boolean or slice array indices.
        The value can be either a scalar or an array variable, and if a boolean index
        is used for the latter case, the same index must be used for the value too.
        
$value_varz$target_var$expr_out_var)r8  r  r|   zparfor from inplace_binop)!r5  r  r+  r   r   r   Block	get_shape_mk_parfor_loopsr    _make_index_varr  r   rh  getitemrP   r  r(  r  r  binopr  Zunify_pairsSetItemr
   noner  r  r  r   DEBUG_ARRAY_OPTr`   r4  )r  r  r  r  r  rg  r5  r  arr_typel_typr  rC  	size_vars
index_vars	loopnests
body_label
body_blockr  index_var_typ	value_vargetitem_callZ
target_varexpr_out_varZ
binop_exprZunified_typesetitem_noder   r^   r^   rd   r?  z  sz    
     
  
  
   
 
z,ConvertInplaceBinop._inplace_binop_to_parforc                 C   s   t j}| jj|t|i S rl   operatorrL  r5  r  resolve_function_typer  r  rs   Zfntyr^   r^   rd   _type_getitem  s    z!ConvertInplaceBinop._type_getitemN)ru   rv   rw   r  r  rF  r?  ra  r^   r^   r^   rd   r1  I  s
   	%@r1  c                 C   s   t | tjr| jS | jS rl   )r   r   rN  r   r  r  r^   r^   rd   get_index_var  s    rb  c                   @   s2   e Zd ZdZdd Zdd ZdddZd	d
 ZdS )ConvertSetItemPassr2  c                 C   s   || _ g | _dS r3  r4  r7  r^   r^   rd   r    s    zConvertSetItemPass.__init__c              
   C   s<  | j }t|}|D ]"}|| }g }|j|}|jD ]}t|tjtjfr$|j	}	|j
}
t|}|j}|j|
j }|j|j }|j|j }t|tjjr$t|tjjrt|jtjr|j|jkrt|tjr| ||	|
||}| jt||dd |}nxt|tjjr$tt|j|j}t|tjr$|jdkr$|jj|jkr$| ||	|
||j}| jt||dd |}n| |}t|tj!rt"t#t$dd |j}nt|tj%j&rd}nd}|d k	r$t|tjjr||jkr$| j||	|
|||d	}| jt||d
d |}|| q6||_qd S )NZmasked_assign_broadcast_scalarr9  rL  Zmasked_assign_arrayc                 S   s   t | tjjS rl   )r   r
   r  	SliceTyper  r^   r^   rd   r     r   z(ConvertSetItemPass.run.<locals>.<lambda>r|   r   )r   slice)'r5  r/   rY   r=  r(  r   r   StaticSetItemrN  r  r  rb  rg  r+  r   r
   r   r   r   Booleanr   Number_setitem_to_parforr6  r  rJ  r:   r>   rC  rh  r  r   rI  r:  r   rM  filterr  rd  )r  r^  r5  r@  rc  r8  rA  r  r#  r  r  r   rg  rB  	index_typrC  rD  Zval_defr   Zsliced_dimsr^   r^   rd   rF    s    

      


    zConvertSetItemPass.runNc           #   	   C   s  | j }|j}|j|j }	|	j}
|j|j }t||}|rt|tj	sVt|tj
sVt|}t|td|}tj|||}tj|	|j}||j|j< | |	|f|j|< |t||| |}n t|tjst||}|j}g }g }|D ]B}t|td|}|| tj|j|j< |t|d|d qt }t||}t|j|||\}}t||i |||d|j}|r||i|_ |}d}nt }t||}t }t||}||||||i|_ t|td|}||j|j< tj|||}|j!"t|||t#||||g |j|j } t| tj$j%rt|td|}!| j|j|!j< tj|||}t&| j| ||j|< |j!t||!| n|}!t'|||!|}"t&tj(|j|j ||
|j|"< |j!|" |r|j!t)|| t*j+dkrt,d	 |-  |S )
rE  z$subarrparfor_indexr   r|   )setitemr  Nz	$mask_varrF  zparfor from setitem).r5  r  r+  r   r   r   rH  r   r
   r:  rd  r  r  r   rh  rL  r   Z	arraydeclZget_array_index_typeresultra  r  r  r  ZArrayCompatiblerI  uintpr  r    rK  r  r  r  r(  r  Branchr   r   rP   rN  rO  Jumpr   rP  r`   r4  )#r  r  r  r  r   rg  r   r5  r  rQ  rR  rk  r  rS  Z
subarr_varrZ  Z
subarr_typZbool_typrU  rT  size_varr  rV  rW  rX  r   Z
true_block	end_label
true_label	end_blockmask_varmask_valrC  rY  r\  r^   r^   rd   ri  !  s    


    
    
 
  
z%ConvertSetItemPass._setitem_to_parforc                 C   s   t j}| jj|t|i S rl   r]  r`  r^   r^   rd   ra    s    z ConvertSetItemPass._type_getitem)N)ru   rv   rw   r  r  rF  ri  ra  r^   r^   r^   rd   rc    s
   	R
^rc  c           
      C   s   t |}|j}|dks|rt|td|}tjtj|| |j	< tj
t||}t|||}	|j|	 |tjtj|fS |dkr|d tjfS tjd|ddS )a   When generating a SetItem call to an array in a parfor, the general
    strategy is to generate a tuple if the array is more than 1 dimension.
    If it is 1 dimensional then you can use a simple variable.  This routine
    is also used when converting pndindex to parfor but pndindex requires a
    tuple even if the iteration space is 1 dimensional.  The pndindex use of
    this function will use force_tuple to make the output index a tuple even
    if it is one dimensional.
    r|   z$parfor_index_tuple_varr   z,Parfor does not handle arrays of dimension 0r  N)r   r  r   r  r   r
   
containersUniTuplero  r   rh  build_tuplerM  r  r(  r  r   UnsupportedRewriteError)
r+  r  rT  rW  force_tuplendimsr  	tuple_var
tuple_calltuple_assignr^   r^   rd   rK    s,    	 
rK  c                 C   sV   g }g }|D ]@}t |td|}|| tj| |j< |t|d|d q||fS )zN
    Create loop index variables and build LoopNest objects for a parfor.
    rl  r   r|   )r   r  r   r  r
   ro  r   r  )r+  rS  r  r  rU  rT  rr  r  r^   r^   rd   rJ    s    
rJ  c                   @   sP   e 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S )ConvertNumpyPassz]
    Convert supported Numpy functions, as well as arrayexpr nodes, to
    parfor nodes.
    c                 C   s   || _ g | _d S rl   r4  r7  r^   r^   rd   r    s    zConvertNumpyPass.__init__c              	   C   s  | j }t|}g }|D ]}|| }g }|j|}|jD ]}	t|	tjr|	j}
|	j	}| j j
|j }| |rt| j|
r| |||
}|d k	r| jt|	|dd |}	n@t|
tjr|
jdkr| |||
|}| jt|	|dd |}	||j ||	 q8||_qd S )NZnumpy_allocatorr9  	arrayexpr)r5  r/   rY   r=  r(  r   r   r  rg  r  r+  r   _is_C_or_F_orderr:   _is_supported_npycall_numpy_to_parforr6  r  rJ  rh  r  _arrayexpr_to_parfor)r  r^  r5  r@  
avail_varsrc  r8  rA  r  r#  r  r$  r  rD  r^   r^   rd   rF    sL    

   zConvertNumpyPass.runc                 C   s`   t |tjjr"|jdko |jdkS |tkrX| jj| }t |tjjoV|jdkoV|jdkS dS d S )NCr   F	r   r
   r   r   layoutr   r%  r5  r+  r  Zarr_namer%  r^   r^   rd   _is_C_order  s    zConvertNumpyPass._is_C_orderc                 C   st   t |tjjr,|jdks"|jdko*|jdkS |tkrl| jj| }t |tjjoj|jdksb|jdkoj|jdkS dS d S )Nr  Fr   Fr  r  r^   r^   rd   r    s    z!ConvertNumpyPass._is_C_or_F_orderc                 C   s  | j }|j}|j}|j}|j|j }	|	j}
||}t|j|||\}}t	
||}t|j|j|j|t||
|||j|j 	|_t }t	
||}t	|td|}|
|j|j< t|j|||\}}|jt|j|j|j|j||||||| dt|jf}t||i ||||d |j}t	||||}ttj|j|j ||
|j|< |j| ||i|_ t!j"dkr~t#d |$  |S )zegenerate parfor from arrayexpr node, which is essentially a
        map with recursive tree.
        rG  zarray expression {}r   r|   zparfor from arrayexpr)%r5  r  r  r  r+  r   r   rI  rJ  r   rH  r!   r  r  r  r(  r    r  r   rK  r  _arrayexpr_tree_to_irrC  r   repr_arrayexprr  r  rN  rP   r
   rO  r  r  r   rP  r`   r4  )r  r  r$  r  r  r5  r  r  r  rQ  rR  rS  rT  rU  r  rV  rW  r[  r  rX  patr   r\  r^   r^   rd   r    sx    
     
    
  

z%ConvertNumpyPass._arrayexpr_to_parforc                 C   sN   t | jj|\}}t|tr&|ds*dS |dkr6dS |dkrJ|tkrJdS dS )zLcheck if we support parfor translation for
        this Numpy call.
        r   Fr   onesTnumpy.random)r8   r5  rC  r   r%  
startswithrV   )r  r  	call_namemod_namer^   r^   rd   r  -  s    z&ConvertNumpyPass._is_supported_npycallc                 C   s`   t | jj|\}}|j}t|j}|dks2|dkrF| ||||||S tjd| |j	dd S )Nr  r  zparfor translation failed for rx  )
r8   r5  rC  rs   rJ  kws_numpy_map_to_parforr   r|  r  )r  r  r$  r  r  r  rs   r  r^   r^   rd   r  ;  s    
 z!ConvertNumpyPass._numpy_to_parforc                 C   s  | j }|j}|j}	|j|j }
|
j}||}|dkrLtjdkrHt	d dS t
|j|||	\}}t||	}t|j|j|j|t||||	|j|j 	|_t }t||	}t|td|	}||j|j< t|j|||\}}|dkrt|d|	}n|dkrt|d|	}nf|tkrjt|| t||j\}}|j| |j|jj t |||j|< |}ntd |t!|||	}|j"| t#||||	}t$t%j&|j|j |||j|< |j"| t'||i |	||d	 |d
f|j(}||i|_)tjdkrt	d |*  |S )z8generate parfor from Numpy calls that are maps.
        Nr|   z3Could not convert numpy map to parfor, unknown sizerG  r   r   r  z,Map of numpy.{} to parfor is not implemented{} functionzNumPy mappingzgenerated parfor for numpy map:)+r5  r  r  r+  r   r   rI  r   rP  r`   rJ  r   rH  r!   r  r  r  r(  r    r  r   rK  r  rV   _remove_size_arg_get_call_arg_typesr  r   r!  r   ContextNotImplementedErrorr   r  r  rN  rP   r
   rO  r  r  r  r4  )r  r  r  r$  rs   r  r  r5  r  r  rQ  rR  rS  rT  rU  r  rV  rW  r[  r  rX  rg  new_arg_typsnew_kw_typesZvalue_assignr\  r   r^   r^   rd   r  F  s    

     
   


   
 
  

z%ConvertNumpyPass._numpy_map_to_parforN)ru   rv   rw   r  r  rF  r  r  r  r  r  r  r^   r^   r^   rd   r    s   &:r  c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )ConvertReducePassz:
    Find reduce() calls and convert them to parfors.
    c                 C   s   || _ g | _d S rl   r4  r7  r^   r^   rd   r    s    zConvertReducePass.__init__c              	   C   s   | j }t|}|D ]}|| }g }|j|}|jD ]}d }	t|tjr|j}
|j	}|j
}tt|j|}|dksx|dkrt| j|||j|
}	|	r| jt|	|dd |	}|| q4||_qd S )N)r   r   )r   
_functoolsr   )r;  r:  r<  )r5  r/   rY   r=  r(  r   r   r  r  r  rg  r:   r8   rC  _reduce_to_parforrs   r6  r  rJ  )r  r^  r5  r@  rc  r8  rA  r  r#  r   r  r$  r  r  r^   r^   rd   rF    s<    

 zConvertReducePass.runc              
      s  | j }|j}|d }|d }t|j|j}	d}
d}tt|j|j|	}|rT|\}}
}}|d }||dkrl|n|
}|dkr~dS t	|j|||\ } }|rt
dt fdd|D  |}t||}|jt||| t }| ||| ||\}}|rt
d|d }|
dk	rt| }t| }t||}|||< t|td|}||j|j< tj|
||}|jt|||t||||g t||||||d	|d
f|j}tj dkrt!d |"  |S )zy
        Convert a reduce call to a parfor.
        The call arguments should be (call_name, array, init_value).
        r   r|   Nr   unreachablec                 3   s   | ]}|r|n d  V  qdS r   Nr^   r  rT  r^   rd   r     s     z6ConvertReducePass._reduce_to_parfor.<locals>.<genexpr>	$mask_valr  	reductionzparfor from reduction)#r5  r  r>   rC  r   r:   
_find_maskr+  rI  rJ  r  r  r   rH  r(  r  r  r    _mk_reduction_bodyr   rq  r   r  r   rh  rL  r  rp  r  r   r  r   rP  r`   r4  )r  r  r$  rs   r  r5  r  r  rz   arr_defrv  mask_indicesZmask_query_resultmask_typr   rS  rU  Z
mask_indexacc_varr  rV  r  r  rt  false_labelrW  maskrw  r   r^   r  rd   r    sp        
 z#ConvertReducePass._reduce_to_parforc                 C   sH  ddl m} | j}t|j|}	||j|	}
|j|j }|j}t	||}t
|j|||\}}t|td|}||j|j< tj|||}t||||j|< |t||| t|
|jjjj|j|j||f|j|j}|j}t }t	||}|||< t|j }|j| }|j|j |j|_t|||g t ||| ||fS )zZ
        Produce the body blocks for a reduction function indicated by call_name.
        r   )check_reduce_funcz$val)!r  r  r5  r>   rC  r+  r   r   r   rH  rK  r  r   rh  rL  rP   r  r  r  r=   rS  r   r  r  r  r^  r    r   rq  r(  r  r@   rA   )r  r  r  r  rT  rz   r  r  r5  Zreduce_funcZfcoderQ  Zin_typrW  r  Zindex_var_typeZtmp_varrZ  Zreduce_f_irr  rs  ru  Zfirst_reduce_labelZfirst_reduce_blockr^   r^   rd   r    sR         


z$ConvertReducePass._mk_reduction_bodyN)ru   rv   rw   r  r  rF  r  r  r^   r^   r^   rd   r    s
   Cr  c                   @   sP   e 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S )ConvertLoopPassz*Build Parfor nodes from prange loops.
    c                 C   s   || _ g | _d S rl   r4  r7  r^   r^   rd   r  $	  s    zConvertLoopPass.__init__c           :         sr  | j 
t \}}t }t }t| |j|j| 		fdd	 D }g }t	|dd dD ]\}t
jdksft
jdkrqftjd }	 |	 jD ]}
t|
tjrt|
jtjr|
jjdkr| |
jjj|r fd	djD }|
jj}| |
jjj|\}} j jd d
 }d t|D ]H\}}t|tjr8t|jtjr8|jjdkr8|jj|} qq8d k	st|d | ||d d   }td j i
j\}}|d }t fdd|D !  |	 j"}|
j#}
j$%j}t&||}| ' |	 |||_ fdd|D t( }t&|||< t  }|D ]}|)|j| }q^t  }jD ]}|)| }q|*|}|*
fdd|D }|D ]6}| jd
 }t|tj+r|jjkr||_qfddd }d } 
fdd}!d}"|dkr<|,|d s@tt-|!|d }#|#rb|#\}$}}%} n|d }$t|$tj.s|t
j|$j }&t|&t/j0rt.|t1d|t/j2
jj< t3d|$dg	gn,|4| d kr|$n|}'t5
j|'||\	t
	dkst}(| r,t6fdd| D t7  })t&||}*t8
j||*dd\}+|*j|)j },|,|)_| r|(d }-n}-|d k	rxtdt( }.t9|.t7  d  }/t7|/}0t:|/}1t&||}*|*|.< t.|t1d|}2|%
j|2j< tj;||-|}3|*j<t|3|2|t=|2|0|1|g n<d}4d}5|d }6t
|dkrj|d }4|d }6t
|dkr|d }4|d }6z
j>?|d }5W n& t@k
r   tAjBd|
j#d Y nX t|5tjCstAjBd!|
j#d |5j}5|5dkrtAjBd"|
j#d t.|t1d|t|4tDr2|4dkr2t/j2}+n
t/jE}+d#}"t3|4|6|5g	|+
jj< t7 }7||7 j |7 _fd$dD }8tF|8 |"r| G tH	||| r|-n|d%||f
jI|d&	}9|9g j _ j j<|  j jJt+tjd | | jKJtL|9d'd( |D ]}|jkr2 M| q2tNjOdkrtPd) |9Q  qqfd S )*Nc                    s"   g | ]} | t  | jfqS r^   )r   r(  )rb   r|  )loopsr^   rd   re   0	  s     z'ConvertLoopPass.run.<locals>.<listcomp>c                 S   s   | d S r   r^   )tupr^   r^   rd   r   3	  r   z%ConvertLoopPass.run.<locals>.<lambda>r  r|   r   rf  c                    s"   g | ]}| kr|j kr|qS r^   )headerrb   rj   )r^  r*  r^   rd   re   B	  s     
r  Z
pair_firstc                 3   s   | ]\}}| kr|V  qd S rl   r^   )rb   trs  )
loop_indexr^   rd   r   `	  s      z&ConvertLoopPass.run.<locals>.<genexpr>c                    s   i | ]}| | qS r^   r^   r  r^  r^   rd   
<dictcomp>i	  s      z'ConvertLoopPass.run.<locals>.<dictcomp>c                    s$   h | ]}t  j| tjjs|qS r^   )r   r+  r
   r  r  r  )r5  r^   rd   	<setcomp>|	  s    z&ConvertLoopPass.run.<locals>.<setcomp>c                     s   t  }   D ]>}|tjD ],}t|jtjr"|jj| kr"| 	|j
j q"qg }g }  D ]}|jD ]v}tdd | D }|| @ rl|| rqltt|tj |j}tt|tjo|jdk ||jj || qlqb||fS )zfind expressions that involve getitem using the
                        index variable. Return both the arrays and expressions.
                        c                 s   s   | ]}|j V  qd S rl   r   r  r^   r^   rd   r   	  s     zCConvertLoopPass.run.<locals>.find_indexed_arrays.<locals>.<genexpr>rL  Zstatic_getitem)rm  ro  Z
find_instsr   r  r   rg  r  r   rp  r  r(  rA  r
  issubsetr;   rh  r  r  )indicesr8  rk  Zarrsexprslvr  )r  loop_index_varsr^   rd   find_indexed_arrays	  s.    



z0ConvertLoopPass.run.<locals>.find_indexed_arraysc           	         s   t j| }t|o0t|tjo0|jdko0|jdk |j}t	j
fddjD  }  \}}t|jgt|k t|j|k t j|j}tjj|}td|D ]}|d |_q|S )zFind the case where size_var is defined by A[M].shape,
                        where M is a boolean array.
                        r  r   c                    s   g | ]} | qS r^   r^   r  )live_mapr^   rd   re   	  s     zDConvertLoopPass.run.<locals>.find_mask_from_size.<locals>.<listcomp>r  r   )r>   rC  r;   r   r   rh  r  r  rg  rA  rr  exitsr   rM  r  r+  r  )	rr  Zsize_defZarr_var	live_varsZ
index_arrsZindex_exprsr  rn  r  )r  r  r*  r5  r^   rd   find_mask_from_size	  s"    
z0ConvertLoopPass.run.<locals>.find_mask_from_sizeTr   rl  c                 3   s   | ]}|r|n d  V  qdS r  r^   r  r  r^   rd   r   	  s   )r}  r  r  r   r   z,Only known step size is supported for prangerx  z/Only constant step size is supported for prangez4Only constant step size of 1 is supported for prangeFc                    s   i | ]
}| qS r^   r^   rb   rs  )r  r^   rd   r  .
  s      r   )r  r*  )Zold_loopr;  r<  zparfor from loop)Rr5  r2   rM   rJ   rK   usemapdefmapr  rq  r5  r   entriesr  rM  r(  r   r   r  rg  rh  r  _is_parallel_loopr   r   rs   _get_loop_kindr  r  r  r  r,   r+  rA  rp  r  r  rY   r=  rH  _get_prange_init_blockr    rr  intersectionrq  Z	has_shaper:   r  r
   Integerr   ro  r  rI  rJ  r  r   rK  r7   r   rL  r  rp  rC  r>   r  r   r|  r  r   Zintpr&   _replace_loop_access_indicesr  r  r  r6  rJ  r  r   rP  r`   r4  ):r  r^  r  r  cfgusedefsZsized_loopsZmoved_blocksr   entryrk  Zbody_labelsrs   Z	loop_kindZloop_replacingZheader_bodyZhbir)  Zli_indexZcpsr  r  r  r  rs  ZbodydefsblZ
exit_livesr  rj   Z	last_instrv  r  r  Zunsigned_indexrn  rz   r  Z
in_arr_typrS  Z
orig_indexfirst_body_blockrW  rX  r(  Zorig_index_varrV  labelsrt  r  r  rw  r   r   rr  first_body_labelZindex_var_mapr   r^   )r^  r  r  rT  r  r*  r  r  r  r  r5  rd   rF  (	  s   
	




 




      





  
 $
zConvertLoopPass.runc                 C   sh   ||krdS || }t |dkof|d dkpf|d tkpf|d dkpf|d tkpf|d dkpf|d tkS )NFr   r   rp   r   )r   r   rp   r   r  func_varr  rf  r^   r^   rd   r  O
  s    $



z!ConvertLoopPass._is_parallel_loopc                 C   s   | j }||kst|| }t|dks*td}|d dksF|d tkrz$d|j| d |j| d ff}W q tk
r   d}Y qX n|d dks|d tkrd}|S )	z(see if prange is user prange or internalr   )r  r  rp   r  r  )r  )r  r  r   )r   r  )r5  r  r   rp   r-  r  r   )r  r  r  r5  rf  kindr^   r^   rd   r  X
  s    $zConvertLoopPass._get_loop_kindc                 C   sT  d}d}g }t |jD ]\}}t|tjrZt|jtjrZ|jjdkrZ| |jj	j
|rZ|}t|tjrt|jtjr|jjdkr| |jj	j
|r|}q|dkrP|dkrPdd |D }	g }
tt|d |D ]H}|j| }dd | D }|	|@ r|	|O }	|
| q|| q|  |
  |jd| |
 |j|d d  |_|S )z
        If there is init_prange, find the code between init_prange and prange
        calls. Remove the code from entry_block and return it.
        r  rf  c                 S   s   h | ]
}|j qS r^   r  r  r^   r^   rd   r  
  s     z9ConvertLoopPass._get_prange_init_block.<locals>.<setcomp>r|   c                 S   s   h | ]
}|j qS r^   r  r  r^   r^   rd   r  
  s     N)r  r(  r   r   r  rg  rh  r  _is_prange_initr   r   r  r  rq   r
  r  reverse)r  Zentry_blockr  Zprange_argsZinit_call_indZprange_call_indZ	init_bodyr   rk  Zarg_related_varsZsaved_nodesZ	inst_varsr^   r^   rd   r  l
  sD    



z&ConvertLoopPass._get_prange_init_blockc                 C   s8   ||krdS || }t |dko6|d dkp6|d tkS )NFr   rm   )r   rm   r  r^   r^   rd   r  
  s    zConvertLoopPass._is_prange_initc              	      s  | |j t| t|}W 5 Q R X |d }t }|D ]L}|| }|jD ]6}	t|	tjrt|	j	tj
r||kr|	j	j|kr|	jj|kr| |	jj | |	jj nR|j  fdd}
|
|	jjt|
|kr|
|	jj|
|	j	jkrtjd|	jjdt|	rlt|	}|dkrqNtt| jj|dd}|j|ksR|dk	r\|j|kr\t|	| t| j||| t|	trN| |	j|| qNq:||8 }dS )	z
        Replace array access indices in a loop body with a new index.
        index_set has all the variables that are equivalent to loop index.
        r   c                    s:   ddl m} z | jW S  |jk
r4   |  Y S X d S )Nr   )r   )
numba.corer   	get_exactunversioned_nameNotDefinedError)r   r   r  r^   rd   unver
  s
    z;ConvertLoopPass._replace_loop_access_indices.<locals>.unverz Overwrite of parallel loop indexrx  NT)Zlhs_only)rp  r   dummy_return_in_loop_bodyr/   rA  r(  r   r   r  rg  r  r  r  mapr   r|  r  rD   rE   r:   r>   r5  rC  rF   _replace_multi_dim_indr  r  r  )r  r  	index_set	new_indexr  first_labelZadded_indicesrj   r8  r)  r  r   Zind_defr^   r  rd   r  
  sX    


.


 


z,ConvertLoopPass._replace_loop_access_indicesc                    sr   | j }t|dk	 tt|j|j tjtjf t|j	|}tt|t
joR|jdk  fdd|jD |_dS )zq
        replace individual indices in multi-dimensional access variable, which
        is a build_tuple
        Nr{  c                    s   g | ]}|j  krn|qS r^   r  r  r  r  r^   rd   re   
  s   z:ConvertLoopPass._replace_multi_dim_ind.<locals>.<listcomp>)r5  r;   r   r+  r   r
   Tuplerz  r>   rC  r   rh  r  r'  )r  Zind_varr  r  r5  Zind_def_noder^   r  rd   r  
  s    
z&ConvertLoopPass._replace_multi_dim_indN)ru   rv   rw   r  r  rF  r  r  r  r  r  r  r^   r^   r^   rd   r  !	  s     )	'Fr  c                 C   s  t t|tjo|jdk |j}|j}| |j }| |j }|j}t t|t	j
j t|t	j
jrt|jt	jr||jkr|||jdfS t|t	jrt||\}}	t |	dkot||k d}
g }d}|D ]}| |j }t|t	j
jrt|jt	jr|}|j}|d qt|t	j
jrDt|jt	jrD|}|j}|d qt|t	jr|
d7 }
|| qt |ov|
|d k ||||fS tdS )zcheck if an array is of B[...M...], where M is a
    boolean array, and other indices (if available) are ints.
    If found, return B, M, M's type, and a tuple representing mask indices.
    Otherwise, raise GuardException.
    rL  Nr{  r   r|   )r;   r   r   rh  r  rg  r   r   r   r
   r   r   r   rg  r:  r9   r   r  r  r<   )r+  rC  r  rg  r   rC  rk  r   seqr  Zcount_constsr  rv  indr  r^   r^   rd   r  
  sN    


r  c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )
ParforPasszParforPass class is responsible for converting NumPy
    calls in Numba intermediate representation to Parfors, which
    will lower into either sequential or parallel loops during lowering
    stage.
    c                 C   s*   | j | jj tjt| jj d S rl   )rY   rF  rC  r^  r   r/  r  find_max_labelr  r^   r^   rd   _pre_run)  s    zParforPass._pre_runc                 C   s  |    | jjr:t| j| j| j| j| j| j	| j
}|  | jjrTt| | jj | jjrnt| | jj | jjrt| | jj | jjrt| | jj | jjrt| | jj | j| j| jj t| jd t| jj}t| j| j| j| jd  t| j| j| j| jd  | jjr|dkrt| jj| j_t  | j_!| j| jj t"| j| jj| jdd t| jd | #| j| jj| j| j t| jd t"| j| jj| j t| jd | #| j| jj| j| j t| jd	 t| j| j| j| jd  t$| jji i | j t| jd
 t| j| j| j| jd  t| jd t%j&dkrvt'dt(| j)  t'd| j t%j&dkr| jj) D ]:\}}g }|j*}|j+D ]}|,| t-|t.j/r|j0}|j1}	|j2}
| j|	j3 }t'd|	j3|t4| |t5j6kst-|t5j7rt.8|t9d|}t5:|	j3| j|j3< t.;|	j3|}t./|||}|,| t.<|gd|}t=t5j>| j|j3 | j|< |,| t.<|	gd|}t=t5j>|| j|< |,| q||_+q| jj?rt@| jjA| jB| j tCrtD| j| j| j| j| j ntE| jj| jj| jF\}}|D ]"}tG| j||jH| j\|_I|_Jq*|D ]}|K| j qRt%jLr| jjMjN}tO|}|dkr| jjrdnd}t'dP|||| nt'dP| dS )zgrun parfor conversion pass: replace Numpy calls
        with Parfors when possible and optimize the IR.zafter parfor passr~   r   F)up_directionzafter maximize fusion downzafter first fusezafter maximize fusion upzafter fusionzafter push call varszafter optimizationr|   zvariable types: zcall types: r   zAdding print for assignment to str_varNr   After fusionr  z0{}, function {} has {} parallel for-loop(s) #{}.zFunction {} has no Parfor.)Qr  r  stencilr   rC  r+  r  rY   r  r  r  rF  rm  rc  r^  r   r  r  r  r   r  r8  r1  r,  rZ  Zfusionr.   simplify_parfor_body_CFGr3   r0  r?   _definitionsrJ  rE  maximize_fusionfuse_parforspush_call_varsr   rP  r`   r5  r'  r  r(  r  r   r   r  r  r  rg  r   r  r
   Znumber_domainLiteralr  r   r  r  PrintrP   rO  Zis_generatorfix_generator_typesgenerator_infor   r  lower_parfor_sequentialget_parfor_paramsrO  get_parfor_reductionsr  r  r  r@  r   rS  rT  r   r   )r  Zstencil_passr  block_labelr8  Z	new_blockr  r)  r  r$  r>  r  r  Z	lhs_constZ
str_assignZ	str_printZir_printr  r~   r>  r   r  r^   r^   rd   rF  0  s    
  





     

   zParforPass.runc                 C   s   t | j| j|S )zcheck if an array is of B[...M...], where M is a
        boolean array, and other indices (if available) are ints.
        If found, return B, M, M's type, and a tuple representing mask indices.
        Otherwise, raise GuardException.
        )r  r+  rC  )r  r  r^   r^   rd   r    s    zParforPass._find_maskc                 C   s   t | j|||S )zV
        Create loop index variables and build LoopNest objects for a parfor.
        )rJ  r+  )r  rS  r  r  r^   r^   rd   rJ    s    zParforPass._mk_parfor_loopsc                 C   sF  |  D ]6\}}||}d}|rd}g }	d}
|
t|jd k r(|j|
 }|j|
d  }t|trt|tr||}||_||_t|||| jd ||\}}| j	j
| |d k	rd}| j	j|j |jg |	| | |||| |
d7 }
q0|	| t|tr| |||| |
d7 }
q0|	|jd  |	|_q qd S )NTFr   r|   r~   r   r  )r'  r=  r   r(  r   r  r  try_fuser0  r,  rP  r  rN  r  r  fuse_recursive_parfor)r  rY   r^  rC  r+  rc  r8  r  Zfusion_happenedrA  r   r)  	next_stmtZ
fused_nodeZfuse_reportr^   r^   rd   r    sD    


  



zParforPass.fuse_parforsc                 C   sf   t |}t| j|| j t| jd| t| j| j| j| j}|	|| | 
|||| t| d S )Nz$after recursive maximize fusion down)rD  r  rC  r+  r.   rY   r.  r  r  rF  r  rG  )r  r   r  rC  r+  r^  Zarr_analysisr^   r^   rd   r    s     z ParforPass.fuse_recursive_parforN)
ru   rv   rw   r  r  rF  r  rJ  r  r  r^   r^   r^   rd   r  !  s    	$r  c                 C   s   t |j}|dd t| |_| tt kr6g |_| tkrVt	|jdkrV|j  | t
krvt	|jdkrv|j  | dkrt	|jdkr|j  t	|jdkr|j }|j  |j| | dkrt	|jdkr|j  dS )	z%remove size argument from args or kwsr   r  r   r   randintr   
triangularN)rJ  r  r  r  r'  rS   rR   rs   rU   r   rT   r  )r  r  r  Zdt_argr^   r^   rd   r    s,    






r  c                 C   sN   g }| j D ]}|||j  q
i }| jD ]\}}||j ||< q*t||fS rl   )rs   r  r   r  r  )r  r+  r  r   r  r   r^   r^   rd   r    s    
r  c           !         sz   |j  }|j}|j}g }t|tr|\}}g }|D ]J}t|td|}| |j < |t| | |||||||	|
7 }|	| q6|t
jkrR |d j  }t|dkr |d j  }||||fi }tj||d |d |}|tjkr0t|d |d | \}}n$|||fi }tj||d |}|||< |j}|	t||| tjD ]@}t||rXt ||
|d}t|t||} |  |j < t| |}t|tjr*|jdkr*|jdkr*t|td|}tj t! |j < t"d	t!|}t|||}tj#|d|}|	| tj$||d
|} |j  %|t fdd|D i }|||< |j}|	t||| |	t||| qXnt|tjr |j  } t| tj&r| j'}t(||||	||| ||
}n| }|}|	t||| n2t|tj)r6t*+ ,|j-}|	t||| t|dkr^t.j/d|dd|jd 0|j d | |j < |S )zgenerate IR from array_expr's expr tree recursively. Assign output to
    expr_out_var and returns the whole IR as a list of Assign nodes.
    z$arg_out_varr   r   r|   rx  r  sqrtz$math_g_varr   r^   c                 3   s   | ]} |j  V  qd S rl   r  r   r+  r^   rd   r   r  s     z(_arrayexpr_tree_to_ir.<locals>.<genexpr>z.Don't know how to translate array expression 'r   'N)1r   r  r  r   r  r   r  r   r  r  rO   Zsupported_array_operatorsr   r_  rh  rM  r^  truediv_gen_np_divideZunaryr   r  rY   Z	MAP_TYPES_find_func_varrm  rn  r>   r  r  r
   r  r  r   r  r  rf  r!  r   r   _gen_arrayexpr_getitemr  r   r  Zresolve_value_typerg  r   r|  r  )!rC  r  r+  r  r  r  r[  r  parfor_index_tuple_varall_parfor_indicesr  rR  r  r  out_irr  Zarr_expr_argsZarg_varsr   Zarg_out_varZel_typ1Zel_typ2func_typir_exprTZfunc_var_namer  Zfunc_var_defZ
g_math_varZg_mathZg_math_assignZcall_typvar_typr^   r  rd   r  )  s    

   
&

  

r  c                 C   s   | j }| j}t|td|}tjt||j	< t
dt|}t|||}tj|d|}	t|td|}
ttj}|||
j	< t|	|
|}tj|
| |gd|}|t || j	 ||j	 gi }|||g ||fS )zgenerate np.divide() instead of / for array_expr to get numpy error model
    like inf for division by zero (test_division_by_zero).
    r  r   dividez	$div_attrr^   )r  r  r   r  r   r
   r  r  r   r   r  r  rh  r  r"   r  rf  r!  r   r  r  )Zarg1Zarg2r  r+  r  r  r&  r'  r(  Zdiv_attr_callZattr_varZfunc_var_typZattr_assignZdiv_callr  r^   r^   rd   r    s&    

  r  c
               	      sR  |j }
|}||j }||j j}t|} |p4g } fdd|D }|dkrt|jtd|
}t	j
j|jddd}|||j< tdtj||g|||}|j| |}td|j }t|jtd	|
}t	j||j< t|||
}|	| |}n(|dkr|d
 }ntdd |D r"|| }t|jtd|
}t	jt	j|||j< td|j }t|jtd	|
}t	j||j< t|||
}|	| g }tt|D ]>}|| }|| }|dkr|| n||||   qtt|}tj||
}t|||
}|	| |}tj|||
}t |||j ||j ||< |S )a  if there is implicit dimension broadcast, generate proper access variable
    for getitem. For example, if indices are (i1,i2,i3) but shape is (c1,0,c3),
    generate a tuple with (i1,0,i3) for access.  Another example: for (i1,i2,i3)
    and (c1,c2) generate (i2,i3).
    c                    s   g | ]}  |qS r^   )Zget_equiv_constr  r  r^   rd   re     s     z*_gen_arrayexpr_getitem.<locals>.<listcomp>r   z$ravelr|   r  )r   r   r  r   z$const_ind_0r  c                 S   s   g | ]}|d k	qS rl   r^   r  r^   r^   rd   re     s     z$parfor_index_tuple_var_bcast)!r  r   r   r   rI  r   r  r  r   r
   r   r   r   r   Zgen_np_callr   r   r(  r  r  ro  r  r  r   ry  rz  r  rq   rM  rh  r{  rL  rP   ) r  r   r  r  rR  r  r  r+  r  r  r  r  r  r~  Znum_indicesrS  Zsize_constsZ	ravel_varZ	ravel_typZstmtsZ
const_nodeZ	const_varZconst_assignZ
ind_offsetr  rT  r   rr  Z
size_constr  r  r  r^   r  rd   r    sh    







r  c                 C   s@   |D ](}| | }t |tr|j|kr|  S qtjd|ddS )zAfind variable in typemap which represents the function func.
    zufunc call variable not foundrx  N)r   rQ   Z
typing_keyr   r|  )r+  r   r  r  rs  r  r^   r^   rd   r     s
    
r  c           
   
   C   s   t jt |j d}i }tt|j j}|j	 D ]*\}}	t
||	|||||d\}}|	||< q:||_|r|t|j|_t|d t||||d  t|d d S )NFr  z after parfor sequential loweringr~   z after parfor sequential simplify)r   r/  r  r  r^  nextiterro  r  r'  _lower_parfor_sequential_blockr1   r.   r3   )
r  rC  r+  r  r0  parfor_foundr  r  r  r8  r^   r^   rd   r    s*         


r  c              
   C   s  t |j}|dkrd}|j| }|jj}	t||	}
|jd | |
_|j|d d  |_t }|
jt||	 t	|j|||< |
|| < t } t
|j}t|D ]}|j| }t }t }t||j|j|j|||	}||jd _|jd j}|||< t|||||	}|j|jd _|||< |dkrL|jjt||	 | |jd _n||| jd _||jd _|}qt|j }|j| jt||	 t|j }||jd _|j D ]2\}}t|||||||d\}}t	||||< qt |j}q
| |fS )Nr  Tr|   r   r  )_find_first_parforr(  r  r  r   rH  r    r  rq  rI   r   r  rq   r#   r   r   r   r  r$   r  ZfalsebrZtruebrr   r  rq  r   r'  r  )r  r8  r  r+  r  r  r  r   rk  r  Z
prev_blockZ
init_labelr~  r6  Zrange_labelZheader_labelZrange_blockZphi_varZheader_blockZprev_header_labelZbody_last_labelZbody_first_labelrj   r   r^   r^   rd   r    sz    




 

     
r  c                 C   s.   t | D ] \}}t|tr|js|  S qdS Nr  )r  r   r  r  r(  r   rk  r^   r^   rd   r  f  s    
r  c                 C   s   t  }g }t  }t| \}}t| }|D ]}	| |	 }
t|
jD ]~\}}t|
j|
j}|
jd| |_td|ij	d }||O }t
||||}t|
j||j\|_|_||j || q>|||	 O }q(||fS )zfind variables used in body of parfors from outside and save them.
    computed as live variables at entry of first block.
    Nr   )rA  rJ   r/   _find_parforsr(  r   rH  r  r  r  get_parfor_params_inner#_combine_params_races_for_ssa_namesr  r  rp  r  r  )r^  options_fusionrN  r  r~   pre_defsr  Zall_defsr@  rc  r8  r   r   Zdummy_blockbefore_defsr  r^   r^   rd   r  m  s6    	     r  c                    s`   fddt |}tt|}|D ], t fdd|D rN|  q& qTq&||B |fS )zReturns `(params|races1, races1)`, where `races1` contains all variables
    in `races` are NOT referring to the same unversioned (SSA) variables in
    `params`.
    c                    s.   z  | jW S  tjk
r(   |  Y S X d S rl   )r  r  r   r  )r|  r  r^   rd   	unversion  s    z6_combine_params_races_for_ssa_names.<locals>.unversionc                 3   s   | ]} |kV  qd S rl   r^   )rb   pv)rvr%  r^   rd   r     s     z6_combine_params_races_for_ssa_names.<locals>.<genexpr>)rA  rM  r  r   discard)r  r  r  Zraces1Zunver_paramsr^   )r'  r  r%  rd   r!    s    r!  c                 C   s   t | }t|}t|}t|||j|j}t|||\}}	t|}
|
dkrtj	rr|rXdnd}t
d|| j|
| t||| j< t|  t| }|d }|d }|j| |B }|| |@ }|S )Nr   r  r  z2{}, parallel for-loop {} has nested Parfor(s) #{}.r|   )rD  rM   rJ   rK   r  r  r  r   r   r   r`   r   r  rM  rG  r5  rq  )r   r#  r"  rN  r^  r  r  r  r  r  r  r  Zkeylistr  Zfirst_non_init_blockr$  r  r^   r^   rd   r     s2       r   c                 c   s*   t | D ]\}}t|tr||fV  qd S rl   )r  r   r  r  r^   r^   rd   r    s    
r  c                 C   s|   t | j }g }| j D ]B}|jD ]6}t|tjtjfr&t	|j
| jj
kr&||jj
 q&qtt|t|@ }t|S )zhget arrays that are written to inside the parfor and need to be passed
    as parameters to gufunc.
    )r   r  rq  ro  r(  r   r   rf  rN  rb  r   r  r  r  rM  rA  r5  )r   parfor_params
last_labeloutputsrd  r)  r^   r^   rd   get_parfor_outputs  s    
r,  _RedVarInfor   reduce_nodesredopT)frozenc	                 C   s8  |dkri }|dkrg }|dkr(t t}|dkr8t t}|dkrDi }t|}	t|	}
|
dd }
t| t|
D ]}t|j| jD ]}t|t	j
rj|jj|ks|jj|krj|j}|j}|j|kr|n||j }g }t|t	jr|jg}n"t|t	jrdd |j D }|| | |D ]}|||< q&t|}|j|kr\||j ||j< || | t|trt| |||||d||	 qqp| D ]\}}|j}||kr||kr||   t||| | }|dk	r|| t|| tt|}|dk	r|\}}nd}d}t|||d||< q||fS )zfind variables that are updated using their previous values and an array
    item accessed with parfor index, e.g. s = s+A[i]
    Nr|   c                 S   s   g | ]
}|j qS r^   r  r  r^   r^   rd   re     s     z)get_parfor_reductions.<locals>.<listcomp>)r   r.  r/  )r   rM  rD  r/   rG  r  r  r(  r   r   r  r  r   rg  r  rh  r
  r  rm  rn  r  r  r   r'  r  get_reduce_nodes%check_conflicting_reduction_operatorsr:   get_reduction_initr-  )rC  r   r)  r  Z
reductionsZreduce_varnamesZ
param_usesZparam_nodesZvar_to_paramr^  r@  rc  r)  r$  r>  Z	cur_paramZ	used_varsrs  Zstmt_cpparam
param_namer.  Zgri_outr   r/  r^   r^   rd   r     s~    





    





r   c                 C   sn   d}|D ]`}t |tjrt |jtjr|jjdkr|dkrD|jj}q||jjkrd| j }t	||j
qdS )zIn prange, a user could theoretically specify conflicting
       reduction operators.  For example, in one spot it is += and
       another spot *=.  Here, we raise an exception if multiple
       different reduction operators are used in one prange.
    Nr8  zCReduction variable %s has multiple conflicting reduction operators.)r   r   r  rg  rh  r  fnr  r   r|  r  )r4  nodesZfirst_red_funcnoder=  r^   r^   rd   r2  3  s    

r2  c                 C   s   t t| dk ttdd | d j}t t|tjo>|jdk |j	t
jksZ|j	t
jkrdd|j	fS |j	t
jks||j	t
jkrd|j	fS dS )z^
    Get initial value for known reductions.
    Currently, only += and *= are supported.
    r|   c                 S   s   t | jtjS rl   )r   rg  r   rh  r  r^   r^   rd   r   N  r   z$get_reduction_init.<locals>.<lambda>r  r8  r   )NN)r;   r   rM  rj  rg  r   r   rh  r  r6  r^  iaddisubimulitruediv)r7  Zacc_exprr^   r^   rd   r3  F  s    


r3  c                 C   s   | j dks| j dkrh| jtjks,| jtjkr:td| jtjtj	tj
tjtjtjtjtjg}| j|kS | j dkrtt|| }|dkrdS dS )Nr8  rM  zParallel floordiv reductions are not supported. If all divisors are integers then a floordiv reduction can in some cases be parallelized as a multiply reduction followed by a floordiv of the resulting product.rf  ))r   r   )r   r   )r   numba.np.npdatetime_helpers)r   r=  TF)r  r6  r^  	ifloordivfloordivr   ZNumbaValueErrorr  r9  r:  r;  r<  rp  submulr
  r:   r8   )ri   rC  Zsuppsr  r^   r^   rd   supported_reductionW  s(    

rB  c                    s  d}i  d fdd	| j | j}t|D ]b\}}|j}|j}| |j < t|tjrj|j  krj|}t|tjr,t	fdd|
 D }	|	kr,|d t|k rt||d  tjr||d  jj|ks|j|krtd|d	t||std| d
 fddt|D }
fdd|
D }t|dks@tdd |
D }
t|
}t|jd |j||d < t|| ||d } qq,|S )z
    Get nodes that combine the reduction variable with a sentinel variable.
    Recognizes the first node that combines the reduction variable with another
    variable.
    NTc                    s:     | jd }t|tjr"|S |s.|d kr2| S |S d S rl   )r9  r   r   r   r  )r   Zvaronlyr   )defslookupr^   rd   rD  |  s    z get_reduce_nodes.<locals>.lookupc                 3   s   | ]} |d j V  qdS )TNr  r  rD  r^   rd   r     s     z#get_reduce_nodes.<locals>.<genexpr>r|   zUse of reduction variable z? other than in a supported reduction function is not permitted.z& in an unsupported reduction function.c                    s   g | ]}|j  |d fqS Tr  r  rE  r^   rd   re     s     z$get_reduce_nodes.<locals>.<listcomp>c                    s   g | ]\}}|j  kr|qS r^   r  r  r  r^   rd   re     s     
 c                 S   s"   g | ]\}}||j kr||fqS r^   r  r  r^   r^   rd   re     s     
 z#initr   )T)r   r  r  r  rg  r   r   r  rh  rA  r
  r   r  r   rB  get_expr_argsr  rJ  r  r  r'   )Zreduction_noder7  rC  r.  r  r   r)  r$  r>  Zin_varsrs   Znon_red_argsZreplace_dictr^   )rC  rD  r   rd   r1  s  sH    
$

r1  c                 C   sB   | j dkr| j| jgS | j dkr0dd | jD S td| dS )z-
    Get arguments of an expression node
    )rM  r8  rf  c                 S   s   g | ]}|qS r^   r^   r  r^   r^   rd   re     s     z!get_expr_args.<locals>.<listcomp>zget arguments for expression {}N)r  r$  r>  rs   r  r   )r  r^   r^   rd   rG    s
    

rG  c                 C   s   | j D ]}|d dkr|d d }tt|D ](}t|| tjr.t|| ||||< q.|d d }tt|D ](}t|| tjrpt|| ||||< qpqd S )Nr   r  r|   )r  rq   r   r   r   r  r)   )r   callbackcbdatar!  left_lengthsr   right_lengthsr^   r^   rd   visit_parfor_pattern_vars  s     
 
 rL  c                 C   s   t jdkr&td|  tdt|  | jD ]n}t|j|||_t|j	t
jr^t|j	|||_	t|jt
jr|t|j|||_t|jt
jr,t|j|||_q,td| ji|| t| || t| j|| d S )Nr|   zvisiting parfor vars for:zcbdata: r  )r   rP  r`   r5  r'  r  r)   r  r   r   r   r  r   r   r(   r  rL  r  )r   rH  rI  rj   r^   r^   rd   visit_vars_parfor  s    


rM  c                 C   s"  |dkrt  }|dkrt  }t| }t|\}}t|}t| }t|  | }| | }	|	 
 D ]}
|	|
j8 }	ql|D ]@}||	kr||| |  |||  q||| |  qdd | jD }|dd | jD O }|dd | jD O }|||  |t| O }tj||dS )zzlist variables written in this parfor by recursively
    calling compute_use_defs() on body and combining block defs.
    Nc                 S   s"   h | ]}t |jtjr|jjqS r^   r   r   r   r  r   r  r^   r^   rd   r    s      zparfor_defs.<locals>.<setcomp>c                 S   s"   h | ]}t |jtjr|jjqS r^   r   r   r   r  r   r  r^   r^   rd   r    s      c                 S   s"   h | ]}t |jtjr|jjqS r^   r   r   r   r  r   r  r^   r^   rd   r    s      )r  r  )rA  rD  rJ   rM   r   rq  rG  r@  Z
dominatorsr  ro  r(  r  r  get_parfor_pattern_varsr   Z_use_defs_result)r   Zuse_setZdef_setr^  usesrC  r  r*  r@  Zdefinitely_executedr*  rc  	loop_varsr^   r^   rd   parfor_defs  s<    rT  c                 C   s0   |t | jO }t| }|t|O }t|  dS )zx
    Reduction variables for parfors and the reduction variables within
    nested parfors must be stack allocated.
    N)rA  r  rD  r   Zmust_use_allocarG  )r   Z
alloca_setr^  r^   r^   rd   _parfor_use_alloca  s    rU  c                 C   s<  t | }t|}t|}t|||j|j}t||||j}dd | jD }|dd | jD O }|dd | jD O }|dd | jD O }t }|	 D ]h}	|j
|	  |M  < |j
|	  |8  < ||j
|	 O }|j|	  |M  < |j|	  |8  < ||j|	 O }qG dd dt}
t|
|}||j
|j t|  ||B S )z~insert dels in parfor. input: dead variable set right after parfor.
    returns the variables for which del was inserted.
    c                 S   s"   h | ]}t |jtjr|jjqS r^   rN  r  r^   r^   rd   r  )  s      z%parfor_insert_dels.<locals>.<setcomp>c                 S   s"   h | ]}t |jtjr|jjqS r^   rO  r  r^   r^   rd   r  ,  s      c                 S   s"   h | ]}t |jtjr|jjqS r^   rP  r  r^   r^   rd   r  /  s      c                 S   s   h | ]}|j jqS r^   r  r   r  r^   r^   rd   r  2  s     c                   @   s   e Zd Zdd ZdS )z'parfor_insert_dels.<locals>.DummyFuncIRc                 S   s
   || _ d S rl   r  r]  r^   r^   rd   r  C  s    z0parfor_insert_dels.<locals>.DummyFuncIR.__init__N)ru   rv   rw   r  r^   r^   r^   rd   DummyFuncIRA  s   rW  )rD  rM   rJ   rK   r  r  rL   r  rA  rq  r  Zescapingobjectr   ZPostProcessorZ_patch_var_delsrG  )r   Zcurr_dead_setr^  r  r  r  Zdead_maprS  Zdead_setrc  rW  Z	post_procr^   r^   rd   parfor_insert_dels  s8    rY  c           
      C   sN   t |\}}t|| j|| \}}| D ] }d}	|	r(t| |||||}	q0q(dS )zm
    Reorder statements to maximize parfor fusion. Push all parfors up or down
    so they are adjacent.
    TN)r2   rG   	arg_namesro  maximize_fusion_inner)
rC  r^  r+  r  r  r  	alias_maparg_aliasesr8  order_changedr^   r^   rd   r  O  s$    r  c                 C   s   d}d}|t |jd k r|j| }|j|d  }	|rHt||	| |||nt|	|| |||}
|
rz|	|j|< ||j|d < d}|d7 }q|S )NFr   r   r|   T)r   r(  _can_reorder_stmts)rC  r8  r  r\  r]  r  r^  r   r)  r  Zcan_reorderr^   r^   rd   r[  g  s0    

     

r[  c                 C   sF   t  }| D ]6}||kr$||| }||kr6||}|| q
|S rl   )rA  rr  rp  )Zthe_setr\  r]  retr   r^   r^   rd   expand_aliases{  s    
ra  c           
      C   s   t | trt |tst |tjst |tjrJt|jt |sJtt	||jrt
dd |  D ||}t
t| ||}t
dd | D ||}t
t|||}	t||@ |	|@ B dkrdS dS )zw
    Check dependencies to determine if a parfor can be reordered in the IR block
    with a non-parfor statement.
    c                 S   s   h | ]
}|j qS r^   r  r  r^   r^   rd   r    s     z%_can_reorder_stmts.<locals>.<setcomp>c                 S   s   h | ]
}|j qS r^   r  r  r^   r^   rd   r    s     r   TF)r   r  r   r  r  r5   rg  rA  r:   is_assert_equivra  r
  get_parfor_writesr0   r   )
r)  r  rC  r  r\  r]  Zstmt_accessesZstmt_writesZnext_accessesZnext_writesr^   r^   rd   r_    sD    



    r_  c                 C   s   t | |\}}|dkS )NrW   )r8   )rC  r  r  r  r^   r^   rd   rb    s    rb  c                 C   sl   t | tstt }| j }| j|d< | D ]6}|jD ]*}|	t
| t |tr:|	t| q:q0|S r  )r   r  r  rA  r  rm  r  ro  r(  r  r0   rc  )r   Zwritesr^  r8  r)  r^   r^   rd   rc    s    



rc  FusionReportfirstsecondmessagec                    s  t d|d| d}t|jt|jkr~t d d}d}||jt|jf }	||jt|jf }
t|j|j||	|
f }d|fS t|j} fdd}fd	d
}t|D ]}|j| }|j| }||j|jr||j|jr||j|jst d| d}|d||j||j||jf 7 }|d||j||j||jf 7 }t|j|j|| }d|f  S qt	|j
|_t|||\}}}}|st||||||d }nd}|s|rt d d}t|j|j||j|jf }d|fS t|j}t }|j D ]}||O }qt|j}td|jijd }|j D ]}||O }q2||s~t d d}t|j|j||j|jf }d|fS t||S )zItry to fuse parfors and return a fused parfor, otherwise return None
    ztry_fuse: trying to fuse 
r  Nz/try_fuse: parfors number of dimensions mismatchz4- fusion failed: number of loops mismatched, %s, %s.z(parallel loop #%s has a nest of %s loopsc                    s   | |kp  | |S rl   )is_equiv)ri   rc   r  r^   rd   rh    s    ztry_fuse.<locals>.is_equivc                    s>   t | tjs| S | j} d kr:|  d kr: d |  }|S | S )z.get original variable name by user if possibleZvar_rename_map)r   r   r  r   )rs  Zuser_varname)r0  r^   rd   get_user_varname  s    z"try_fuse.<locals>.get_user_varnamez/try_fuse: parfor dimension correlation mismatchz7- fusion failed: loop dimension mismatched in axis %s. zslice(%s, %s, %s) != zslice(%s, %s, %s)r   Tz1try_fuse: parfor cross iteration dependency foundzK- fusion failed: cross iteration dependency found between loops #%s and #%sz)try_fuse: parfor2 depends on parfor1 bodyzT- fusion failed: parallel loop %s has a dependency on the body of parallel loop %s. )dprintr   r  r  rd  rq   r   r   r   r?   r^  r  has_cross_iter_deprJ   r  rA  r  ro  r  r  
isdisjointfuse_parfors_inner)r  parfor1parfor2r0  rC  r+  r  r=  r"  r  r  r~  rh  ri  r   Znest1Znest2Zp1_cross_depZp1_ipZp1_iaZ	p1_non_iaZp2_cross_depZp1_body_usedefsZp1_body_defsrC  Z
p2_usedefsZp2_usesrR  r^   )r  r0  rd   r    sz    




  



r  c                 C   sV  | j j|j j t|j }|j| j}t| j }t| j }| j| j| | j|j | j| t	| j
}|jj| ji}t|D ]}| j
| j||j
| jj< qt| j| t| |d}	t|	}	t| |	 tdd | D }
t| j|
 | j|j tjr*td|j| j d}||j| j}t| j|j|}| |fS )N)entry_labelc                 s   s   | ]}|j V  qd S rl   r  r  r^   r^   rd   r   ,  s     z%fuse_parfors_inner.<locals>.<genexpr>z1Parallel for-loop #{} is fused into for-loop #{}.zE- fusion succeeded: parallel for-loop #{} is fused into for-loop #{}.)r  r(  r  r   r  rq  r   r  r  r   r  r  r   rq   r  r&   rD  r1   rG  rA  ro  remove_duplicate_definitionsr  r   r   r`   r   r  rd  )rn  ro  Zparfor2_first_labelZparfor2_first_blockZparfor1_first_labelZparfor1_last_labelr~  Z
index_dictr   r^  namesetr=  r  r^   r^   rd   rm    s<    

 rm  c           	      C   sp   |   D ]b\}}|j}g }t }|D ]>}t|tjrX|jj}||krX||krNq$|| |	| q$||_qdS )zsRemove duplicated definition for variables in the given nameset, which
    is often a result of parfor fusion.
    N)
r'  r(  rA  r   r   r  r  r   rp  r  )	r^  rr  rc  r8  r(  rA  Zdefinedrk  r   r^   r^   rd   rq  :  s    
rq  c              	      s  dd | j D t }|d kr"i }|d kr0t }|d kr>t }dd   fdd}| j D ]}|jD ]x}	t|	tjtjfrt|	j	j
 tjjrn||	j|	j	j
||||rnd|||f    S qnqnt|	tjrnt|	jtjr|	jj
kr|	j	j
 qnqnt|	jtjrn|	jj}
|
dkrtt|	jjj
 tjjrn||	jj|	jjj
||||rnd|||f    S qnn<|
d	krtfd
d|	j D rd|||f    S dd |	j D }|r||sn||	j	j
 qnqbd|||fS )Nc                 S   s   h | ]}|j jqS r^   rV  r  r^   r^   rd   r  b  s     z%has_cross_iter_dep.<locals>.<setcomp>c                 S   sh   t | trt| } d| kr4||kr&dS || dS ||kr@dS t| }||kr\| ||< dS || | kS )aA  Returns True if there is a reason to prevent fusion based
           on the rules described above.
           new_position will be a list or tuple of booleans that
           says whether the index in that spot is a parfor index
           or not.  array_accessed is the array on which the access
           is occurring.TF)r   rM  r  rp  r   )Znew_positionarray_accessedindex_positionsindexed_arraysnon_indexed_arraysZnpsizer^   r^   rd   add_check_position  s    

z.has_cross_iter_dep.<locals>.add_check_positionc           
         s   t | tjrt | j tjrtt| }|dk	rz|\}}t fdd|D rtfdd|D }	|	||||S dS qdS q| jkrd||||S | j krdS d||||S ndS t	
ddS )	zLooks at the indices of a getitem or setitem to see if there
           is a reason that they would prevent fusion.
           Returns True if fusion should be prohibited, False otherwise.
        Nc                    s    g | ]}|j kp|j  kqS r^   r  r  )derived_from_indicesr  r^   rd   re     s   
z;has_cross_iter_dep.<locals>.check_index.<locals>.<listcomp>c                    s   g | ]}|j  kqS r^   r  r  )r  r^   rd   re     s     TrF  )FzjSome code path in the parfor fusion cross-iteration dependency checker check_index didn't return a result.)r   r   r  r   r
   r:  r:   r9   allr   ZInternalError)
Z
stmt_indexrs  rt  ru  rv  rx  Zfbs_resZind_seqr  Znew_index_positionsrw  rC  r  r+  )rx  rd   check_index  sD    


z'has_cross_iter_dep.<locals>.check_indexTr  rf  c                    s    g | ]}t  |j tjjqS r^   )r   r   r
   r   r   r  r  r^   rd   re   $  s   z&has_cross_iter_dep.<locals>.<listcomp>c                 S   s   g | ]
}|j qS r^   r  r  r^   r^   rd   re   )  s     F)r  rA  r  ro  r(  r   r   rN  rf  r  r   r
   r   r   r   r  rg  r  rp  rh  r  r   r
  rl  )r   rC  r+  rt  ru  rv  rx  r{  r   r)  r  Zrhs_varsr^   rz  rd   rk  N  sh    0G


rk  c                  G   s   t jdkrt|   d S r   )r   rP  r`   )r   r^   r^   rd   rj  6  s    
rj  c                 C   s`   t  }| jD ]N}|d dkr|d d }|d d }|| D ]}t|tjr<||j q<q|S )z: get the variables used in parfor pattern information
    r   r  r|   )rA  r  r   r   r  rp  r   )r   outr!  rJ  rK  rs  r^   r^   rd   rQ  :  s    
rQ  c           #   	   C   s  t | j t| j}W 5 Q R X |d }i }	t| j| j| j||	| t|	 }
|D ]}||krdqV| j| jD ]r}t|t	j
rt|jt	jr|jjdkr|jjj| jjkrqptdd | D }||
@ }|D ]}|	|d qqpqV|D ]4}||krq| j| }|	 }t|j| j||| q| j }t| }t|||\}}t	|t	dd}|| j| t|}t|}t|||j|j}t| }| D ]\}}g }dd	 |j D }||D ]\}}||| O }qt |jD ]}||@ } | D ]}!|||! O }qt|t	j!t	j"frXt#|j| jjkrX|j$j|krX|j$j|krXq|d
d	 | D O }|| q|%  ||_q||j || j  t&| ||||| t'| j(jdk}"| j) D ]}|"t'|jdkM }"q|"rdS | S )z7 remove dead code inside parfor including get/sets
    r   rL  c                 s   s   | ]}|j V  qd S rl   r  r  r^   r^   rd   r   f  s     z%remove_dead_parfor.<locals>.<genexpr>Nparfors_dummyr  c                 S   s   h | ]
}|j qS r^   r  r  r^   r^   rd   r    s     z%remove_dead_parfor.<locals>.<setcomp>c                 S   s   h | ]
}|j qS r^   r  r  r^   r^   rd   r    s     )*r  r  r/   _update_parfor_get_setitemsr(  r  rA  rq  r   r   r  rg  rh  r  r   r   r
  r  rm  r   _add_liveness_return_blockrq  Locr  rM   rJ   rK   r  r  r'  
terminator
successorsr  rf  rN  rb  r  r  remove_dead_parfor_recursiver   r  ro  )#r   livesZlives_n_aliasesr]  r\  rC  r+  r  r  Zfirst_block_saved_valuesZ
saved_arrsrj   r)  varnamesZrm_arrsr   r8  saved_valuesr^  r*  return_labelr  Zjumpr  r  r  Z	alias_setrc  rA  Zin_livesZout_blk_dataZalias_livesrs  Zis_emptyr^   r^   rd   remove_dead_parforH  s    
 

 




     r  c           	      C   s  | D ]}t |tjtjfrht|j|jkrh|jj|krh||jjg D ]}||d qF|j	||jj< qt |tj
rt |j	tjr|j	}|jdkrt |jtjr|jj|jkr||j	j||_	q| D ]2}||jd ||jg D ]}||d qqqdS )zS
    replace getitems of a previously set array in a block of parfor loop body
    NrL  )r   r   rf  rN  rb  r   r  r9  r  rg  r  rh  r  r   r  r
  )	Z
block_bodyr  r\  r  r  r)  wr>  rs  r^   r^   rd   r~    s*    
r~  c              	   C   s   | j  }t| }|dks"tt| }t|||\}	}
|| j}t	|t
dtdd}tj||j< t|||	tdd}|| j| | j|d< |d jt|tdd t|||||| ||
j |d j  || j  dS )zIcreate a dummy function from parfor and call remove dead recursively
    r   z$branchcondr}  r  N)r  rm  r   rq  r  r   r  r  r   r  r   r  r
   booleanr   rp  r(  r  r  rq  r*   r  )r   r  r]  r\  rC  r+  r^  r  r*  r  r  r  Z
branchcondbranchr^   r^   rd   r    s"    


 r  c                    s   t |  }|d }| | j | | jt | |< ttd }tj	
tjd||j<  fdd|D }tj| }| | jt||  | | jt|  ||fS )Nr|   z
$tuple_varr   c                    s   g | ]}t | qS r^   )r   r  r  r  r  r^   rd   re   	  s     z._add_liveness_return_block.<locals>.<listcomp>)r   rq  r  r  r   rH  r  r   r
   ry  rz  ro  r   rh  r{  r(  r  r  Return)r^  r  r+  r*  r  r  r  r  r^   r  rd   r    s    

 
r  c                 C   s(   t | }t|||||| t|  d S rl   )rD  r   rG   rG  )r   rs   r+  rC  r\  r]  r^  r^   r^   rd   find_potential_aliases_parfor  s         r  c           	   
   C   s   d}|   D ]}|jD ]}t|tr|d7 }|}|jt|j  }|j}t	dd}t
|td|}|jttd||| |jt|| t|j|_|jt|j  }|j  t|j qq|S )z%simplify CFG of body loops in parforsr   r|   r}  r  $const)ro  r(  r   r  r  r   rq  r  r   r  r  r   r  r  r  r  r4   r  r  )	r^  r  r8  r)  r   Z
last_blockr  r  constr^   r^   rd   r    s"    


r  c                 C   s   | j  }|dkrt| }|dks*t| j|d< |d jt	||d j
 | D ]4}t|jdksx|jd jsZ|jt	||j
 qZ|S )z5wrap parfor blocks for analysis/optimization like CFGNr   r  )r  rm  r   rq  r  r  r(  r  r   rq  r  ro  r   Zis_terminator)r   rp  r^  r8  r^   r^   rd   rD  1  s    

rD  c                 C   s   |dk	r$t | }|| || _t | j }t| jjd tjsJt	| jj  | j
 D ]0}t|jd tjr`|jd j|kr`|j  q`dS )zb
    unwrap parfor blocks after analysis/optimization.
    Allows changes to the parfor loop.
    Nr  )r   rq  r  r  r   r  r(  r   rq  r  ro  r  )r   r^  Zinit_block_labelr  r8  r^   r^   rd   rG  A  s    
rG  c                 C   s   t | }t||\}}t||\}}t|  |d }| j D ]&}|dd || D O }||| O }q>t| j }	||	 |d @ }
tjdkrt	d|
d| |
|fS )z&find copies generated/killed by parforr   c                 S   s   h | ]\}}|qS r^   r^   )rb   rj   r   r^   r^   rd   r  j  s     z$get_copies_parfor.<locals>.<setcomp>r|   zcopy propagate parfor gens:kill_set)
rD  r+   r,   rG  r  rq  r   r   rP  r`   )r   r+  r^  in_copies_parforout_copies_parforZin_gen_copiesZin_extra_killr  rc  r*  Zgensr^   r^   rd   get_copies_parfor]  s    
r  c                 C   s  t | jD ],\}}|d dkr
dt|d |f| j|< q
| jD ].}t|j||_t|j||_t|j||_q>t| }	g }
| D ](\}}|
	t
||| t
dd q|
|	d j |	d _t|	|\}}t|	||||| t|  |	d jt|
d |	d _dS )z*apply copy propagate recursively in parforr   r  r|   dummyr  N)r  r  r'   r  r   r   r   rD  r'  r  r   r  r  r(  r+   r-   rG  r   )r   Zvar_dictZname_var_tabler+  r  Zsave_copiesr   r!  rj   r^  Zassign_listZlhs_namer>  r  r  r^   r^   rd   apply_copies_parfory  s0    


 r  c              
      s  |   D ]}g }t  i }|jD ]} fdd}	|st|tr|jjD ]}
|	|
 qJ|j }t||dd |	| q n|	| |
 D ]}|t|j |7 }q|	| q ||_t|dkr| D ]\}}|| ||< qd|i}t|| qdS )zpush call variables to right before their call site.
    assuming one global/getattr is created for each call site and control flow
    doesn't change it.
    c                    s   t | tjr| j}| j}t |tjr<| |j<  |j nDt |tjr|j	dkr|jjksj|jjkr| |j<  |j d S )Nr  )
r   r   r  rg  r  r  r   rp  rh  r  )r)  r>  r$  
block_defssaved_getattrssaved_globalsr^   rd   process_assign  s    


z&push_call_vars.<locals>.process_assignT)nestedr   N)ro  rA  r(  r   r  r  r  rm  r  r  r
  _get_saved_call_nodesr   r   r'  rH   )r^  r  r  r+  r  r8  rA  rename_dictr)  r  r   Zpblocksrs  r|  Ztemp_blocksr^   r  rd   r    s8    




  r  c                 C   s~   g }| |krr| |ks| |krrdd }| |krF|||  d||| d} q| |kr|||  d||| ||  j j j} q|  |S )al   Implement the copying of globals or getattrs for the purposes noted in
        push_call_vars.  We make a new var and assign to it a copy of the
        global or getattr.  We remember this new assignment node and add an
        entry in the renaming dictionary so that for this block the original
        var name is replaced by the new var name we created.
    c                 S   sn   t | tjstt| jjt|| jj}tt	
| j|| j}|| || jj |jj|| jj< d S rl   )r   r   r  r  r  r  r  r   r  rm  rn  rg  r  rp  r   )objZvar_baser7  r  r  Zrenamed_varZrenamed_assignr^   r^   rd   rename_global_or_getattr  s    

z7_get_saved_call_nodes.<locals>.rename_global_or_getattrz$push_global_to_blockZ_PA_DONEz$push_getattr_to_block)rg  r   r  )fnamer  r  r  r  r7  r  r^   r^   rd   r    s*    
  
  r  c                 C   s   t | tr| d }t |ts2t|dr.|j}nd}| d }t|dkrZd|t|d S d| d }d|dd	 |D S nLt | t	j
jjr| j}|d
rd| S |S nt | t	j
jjrt| jS dS dS )zMExtract operators from arrayexpr to represent it abstractly as a string.
    r   ru   r  r|   z({}({}))r  z({})c                 S   s   g | ]}t |qS r^   )r  r  r^   r^   rd   re     s     z"repr_arrayexpr.<locals>.<listcomp>$z'%s' (temporary variable)N)r   r  r%  hasattrru   r   r   r  r  r}   r   r   r  r   r  r  r&  rg  )r  Zoprrs   r   r^   r^   rd   r    s&    




r  c                 C   s,   g }| j D ]}|||  q
t||_dS )zpostproc updates generator_info with live variables after transformations
    but generator variables have types in return_type that are updated here.
    N)Z
state_varsr  r  Zstate_types)r  r   r+  Znew_state_typesrs  r^   r^   rd   r    s
    

r  c                 C   s@   |d kri }|d kri }t | }t|||\}}t|  ||fS rl   )rD  r2   rG  )r   r  Zreverse_call_tabler^  r^   r^   rd   get_parfor_call_table  s    r  c                 C   s,   |d kri }t | }t||}t|  |S rl   )rD  r   Zget_tuple_tablerG  )r   Ztuple_tabler^  r^   r^   rd   get_parfor_tuple_table*  s    r  c                 C   s.   |d krt  }t| }t||}t|  |S rl   )rA  rD  r   Zget_array_accessesrG  )r   Zaccessesr^  r^   r^   rd   get_parfor_array_accesses6  s    r  c                 C   s6   t | }t||}|| |d< || t| | d S r   )rD  r7   r  rG  )r   r7  r^  r^   r^   rd   parfor_add_offset_to_labelsC  s    


r  c                 C   s   t | }t|}t|  |S rl   )rD  r   r  rG  )r   r^  Z	max_labelr^   r^   rd   parfor_find_max_labelO  s    
r  c                    s   |j }t| }dd | jD }t| }|| j  fdd|D }|| j}||| j || _||_ |  ||_ ||| _t|  d S )Nc                 S   s   g | ]
}|j qS r^   )r  r  r^   r^   rd   re   [  s     z$parfor_typeinfer.<locals>.<listcomp>c              	      s&   g | ]}t t jd  dd| qS )r|   F)r  Zuse_literal_type)r   r  r  r  rx  r^   rd   re   a  s     )	r^  rD  r  r   rq  r  r(  Zbuild_constraintrG  )r   ZtypeinfererZsave_blocksr^  rT  Zfirst_blockZindex_assignsZsave_first_block_bodyr^   rx  rd   parfor_typeinferX  s    


r  c                 C   s0   |dkrt t}t| j| td| ji| |S )z)get variable definition table for parforsNr   )r   rM  r?   r  r  )r   Zdefinitionsr^   r^   rd   build_parfor_definitionsm  s
    r  c              	   c   sh   t |  }| | j}t|tdtdd}| | jt	|tdd dV  | | j
  dS )zLadds dummy return to last block of parfor loop body for CFG computation
    r  r}  r  N)r   rq  r  r   r  r   r  r(  r  r  r  )r  r*  r  r  r^   r^   rd   r  z  s    

r  c                   @   s   e Zd Zdd ZdS )ReduceInferc                 C   sF   |rt t|dkrtdt|d tjs2t t|d jf| S )Nr   zlen(args) != 3r|   )	r  r   r   ZNumbaAssertionErrorr   r
   r   rP   r   )r  rs   r  r^   r^   rd   generic  s
    
zReduceInfer.genericN)ru   rv   rw   r  r^   r^   r^   rd   r    s   r  c                  C   s   t jrd} t| dS )zKCheck if the platform supports parallel=True and raise if it does not.
    zDThe 'parallel' target is not currently supported on 32 bit hardware.N)r   Z	IS_32BITSr   r<  )r=  r^   r^   rd   ensure_parallel_support  s    r  )F)NNNNN)NN)T)T)NNN)N)N)F)NN)N)N)N(   r  r
   Zpytypesr1  r   r  textwraprm  r  r  	functoolsr   collectionsr   r   r   
contextlibr   r^  Zdataclassesr   Zllvmliter   ZlirZnumba.core.imputilsr	   Znumba.core.irr}   r  r   r   r   r   r   r   r   r   r   r   r   Znumba.np.npdatetime_helpersr   r   Znumba.np.numpy_supportr   r   Znumba.core.typing.templatesr   r   Znumba.stencils.stencilparforr   Znumba.core.extendingr   r   Znumba.core.ir_utilsr   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   Znumba.core.analysisrJ   rK   rL   rM   Znumba.core.controlflowrN   Znumba.core.typingrO   rP   Znumba.core.types.functionsrQ   Znumba.parfors.array_analysisrR   rS   rT   rU   rV   rW   rX   r   r   Znumba.parforsrY   Znumba.cpython.builtinsZnumba.stencilsrZ   r  TextWrapperrg   rk   r  rm   ro   rX  rp   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r  r   r   r   r   r   r  r  rh  ZStmtr  rH  Zarray_analysis_extensionsrI  r  r  r+  r1  rb  rc  rK  rJ  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r!  r   r  r,  r-  r   r2  r3  rB  r1  rG  rL  rM  Zvisit_vars_extensionsrT  Zir_extension_usedefsrU  Zir_extension_use_allocarY  Zir_extension_insert_delsr  r[  ra  r_  rb  rc  rd  r  rm  rq  rk  rj  rQ  r  r~  Zremove_dead_extensionsr  r  r  Zalias_analysis_extensionsr  rD  rG  r  Zcopy_propagate_extensionsr  Zapply_copy_propagate_extensionsr  r  r  r  r  Zcall_table_extensionsr  Ztuple_table_extensionsr  Zarray_accesses_extensionsr  Zadd_offset_to_labels_extensionsr  Zfind_max_label_extensionsr  Ztypeinfer_extensionsr  Zbuild_defs_extensionsr  r  r  r^   r^   r^   rd   <module>   s  	4. 
" - 




 
     V  v B
 ^    R1 U(qMG#       
R5


4

.

 

Z+  
 if!
*


8!
	


	




	