U
    zh&0                     @   s&  U d Z ddlZddlmZ ddlmZmZmZmZm	Z	m
Z
mZmZ ddlmZ ddlZddlZddlmZmZ ddlmZmZmZ ddlmZmZ d	d
lmZ d	dlmZ eeje e!e"f Z#e#dddZ$eG dd dZ%G dd dZ&eG dd dZ'ee'ed f Z(ee)d< G dd dZ*dS )a  This file implements the IndexPropagation ops handler, which wraps an
underlying handler to add a limited form of constant propagation, as well as
propagation of sympy expressions downstream of ops.index_expr calls.

For example, say we have the IR:

   tmp0 = ops.index_expr(x, torch.int32)
   tmp1 = ops.constant(2, torch.int32)
   tmp2 = ops.mul(tmp0, tmp1)
   tmp3 = ops.indirect_indexing(tmp2, x_size)
   tmp4 = ops.load("buf0", tmp3)

The underlying handler would just see:

   ops.load("buf0", x * 2)

This is limited by the set of operators handled in the sympy expression
printers. So simple operations like minimum and maximum cannot be translated to
SymPy expressions yet, despite sympy.Min and sympy.Max existing.

    N)	dataclass)AnyCallableDictLiteralOptionaloverloadTupleUnion)	TypeAlias)dtype_to_typeis_integer_dtype)FloorDivModularIndexingWhere)bound_sympyValueRanges   )generate_assert)Vvalc                 C   s"   t | tjr| jS t | tttfS N)
isinstancesympyZBasicZ	is_numberintfloatboolr    r   S/var/www/html/venv/lib/python3.8/site-packages/torch/_inductor/index_propagation.py_is_constant*   s    r    c                   @   s4   e Zd ZU dZeed< ejed< dd Zdd Z	dS )		TypedExprz'A SymPy expression with associated typeexprdtypec                 C   s
   t | jS r   )r    r"   selfr   r   r   is_constant7   s    zTypedExpr.is_constantc                 C   s    t | jrt| j| j| _d S r   )r    r"   r   r#   r$   r   r   r   __post_init__:   s    
zTypedExpr.__post_init__N)
__name__
__module____qualname____doc__	_ExprType__annotations__torchr#   r&   r'   r   r   r   r   r!   0   s
   

r!   c                   @   s~  e Zd ZdZeeedddZeeee	e
f ejedddZeeejef ejeddd	Zed&eejeej edddZeeedddZeeedddZeeeedddZeeeedddZeeeedddZeeedddZeeeedddZeeeee dddZeeeee dd d!Zeeeedd"d#Zeeeedd$d%Zd
S )'SymPyOpszAn ops handler where all IR values are SymPy expressions

    When a value cannot be represented as a SymPy expression, the method is
    either not defined, or returns NotImplemented

    )valuereturnc                 C   s   | S r   r   )r0   r   r   r   identityG   s    zSymPyOps.identity)r0   r#   r1   c                 C   s
   t | |S r   r!   r0   r#   r   r   r   constantK   s    zSymPyOps.constantc                 C   s
   t | |S r   r3   r4   r   r   r   
index_exprO   s    zSymPyOps.index_exprN)r0   r#   	src_dtyper1   c                 C   s   t | j|S r   )r!   r"   )r0   r#   r7   r   r   r   to_dtypeS   s    zSymPyOps.to_dtype)xr1   c                 C   s   t t| j| jS r   )r!   absr"   r#   r9   r   r   r   r:   Y   s    zSymPyOps.absc                 C   s   t | j| j | jS r   r!   r"   r#   r;   r   r   r   square]   s    zSymPyOps.square)r9   yr1   c                 C   s"   t | j|j}t| j|j |S r   r.   promote_typesr#   r!   r"   r9   r>   result_typer   r   r   adda   s    zSymPyOps.addc                 C   s"   t | j|j}t| j|j |S r   r?   rA   r   r   r   subf   s    zSymPyOps.subc                 C   s"   t | j|j}t| j|j |S r   r?   rA   r   r   r   mulk   s    zSymPyOps.mulc                 C   s   t | j | jS r   r<   r;   r   r   r   negp   s    zSymPyOps.negc                 C   s0   t | j|j}t|stS tt| j|j|S r   )r.   r@   r#   r   NotImplementedr!   r   r"   rA   r   r   r   floordivt   s    zSymPyOps.floordivc                 C   s<   t | j|j}t|stS t| jtd|j}t	||S Nr   )
r.   r@   r#   r   rG   r   r"   r   Integerr!   )r9   r>   rB   result_exprr   r   r   mod|   s
    zSymPyOps.modc                 C   sn   t | j|j}t|stS t| j}t|j}|jd k	rj|j|j	krjt
| jtd|j}t||S tS rI   )r.   r@   r#   r   rG   r   sympifyr"   Zis_nonnegativeZis_positiver   rJ   r!   )r9   r>   rB   Zx_exprZy_exprrK   r   r   r   	remainder   s    

zSymPyOps.remainderc                 C   s&   t | j|j}tt| j|j|S r   )r.   r@   r#   r!   r   ZMinr"   rA   r   r   r   minimum   s    zSymPyOps.minimumc                 C   s&   t | j|j}tt| j|j|S r   )r.   r@   r#   r!   r   ZMaxr"   rA   r   r   r   maximum   s    zSymPyOps.maximum)N)r(   r)   r*   r+   staticmethodr   r2   r
   r   r   r   r.   r#   r!   r5   r   Exprr6   r   r8   r:   r=   rC   rD   rE   rF   rH   rL   rN   rO   rP   r   r   r   r   r/   ?   sJ        r/   c                   @   s>   e Zd ZU eed< dZeed< eed dddZ	dd Z
d	S )
IndexPropVarr0   Fis_symbolic)r"   r1   c                 C   s   t | ddS )NTrT   )rS   r"   r   r   r   new_symbolic   s    zIndexPropVar.new_symbolicc                 C   s   | j rt| jtstdd S )Nz.Symbolic IndexPropVar must contain a TypedExpr)rT   r   r0   r!   AssertionErrorr$   r   r   r   r'      s     zIndexPropVar.__post_init__N)r(   r)   r*   r   r-   rT   r   rQ   r!   rW   r'   r   r   r   r   rS      s
   
rS   )IndexPropResult.rY   c                   @   sB  e Zd ZdZeeejejf dddZ	eje
jedddZeeef edd	d
ZedddZeed eedf eeef edddZeeeedf eeef edddZeeedf eeef edddZeeedf eeef edddZeedef dddZdd Zd!eeef eeedddZd S )"IndexPropagationzOps wrapper that tries to propagate constant and index_expr values through the computation.

    This aims to maximize the compile time simplification possible, and convert
    indirect indexing from arange into normal static indexing.

    )inneriter_rangesc                    s   || _ tjjj| _dd   fdd| D }tt| jj	 | | _	g }| D ]$\}}|
d|k |
||k  qZt|| j  | _d S )Nc                 S   s   t | tjrt| jS | S r   )r   r   rR   r   upper)vr   r   r   upper_bound   s    z.IndexPropagation.__init__.<locals>.upper_boundc                    s$   i | ]\}}|t d  |d qS )r   r   )r   .0kr^   r_   r   r   
<dictcomp>   s     z-IndexPropagation.__init__.<locals>.<dictcomp>r   )_innerr   graphZsizevars	shape_envitemstuple	itertoolschainvar_to_rangeappendZ
get_axiomsaxioms)r%   r[   r\   rl   rn   r9   sr   rc   r   __init__   s    
zIndexPropagation.__init__)r"   r#   r1   c                 C   s0   t |r"t||}| j||S | j||S r   )r    r   re   r5   r6   )r%   r"   r#   r   r   r   r   materialize_expr   s    z!IndexPropagation.materialize_exprar1   c                    sR   t |ttfr$t fdd|D S t |ts2|S |jrL |jj|jjS |jS )Nc                 3   s   | ]}  |V  qd S r   unwrapra   r^   r$   r   r   	<genexpr>   s     z*IndexPropagation.unwrap.<locals>.<genexpr>)	r   listri   rS   rT   rq   r0   r"   r#   r%   rs   r   r$   r   ru      s    
zIndexPropagation.unwrap)r1   c                    s,   t |ttfr$t fdd|D S t|S )Nc                 3   s   | ]}  |V  qd S r   )wraprv   r$   r   r   rw      s     z(IndexPropagation.wrap.<locals>.<genexpr>)r   rx   ri   rS   ry   r   r$   r   rz      s    zIndexPropagation.wrapindirect_indexing.)nameargskwargsr1   c                 C   s   d S r   r   r%   r|   r}   r~   r   r   r   fallback   s    zIndexPropagation.fallbackc                 C   s   d S r   r   r   r   r   r   r      s    c                    s@    fdd|D } fdd|  D } t j|||S )Nc                    s   g | ]}  |qS r   rt   ra   rs   r$   r   r   
<listcomp>   s     z-IndexPropagation.fallback.<locals>.<listcomp>c                    s   i | ]\}}|  |qS r   rt   r`   r$   r   r   rd      s      z-IndexPropagation.fallback.<locals>.<dictcomp>)rh   rz   getattrre   )r%   r|   r}   r~   new_args
new_kwargsr   r$   r   r      s    c                    s   t ttf tddd  fdd|D } fdd| D }tt|||}|tk	of| pf|jj	}|sz| 
|||S t|S )Nrr   c                 S   s   t | ts| S | jS r   )r   rS   r0   )rs   r   r   r   ru     s    
z0IndexPropagation.propagate_sympy.<locals>.unwrapc                    s   g | ]} |qS r   r   r   rt   r   r   r   	  s     z4IndexPropagation.propagate_sympy.<locals>.<listcomp>c                    s   i | ]\}}| |qS r   r   r`   rt   r   r   rd   
  s      z4IndexPropagation.propagate_sympy.<locals>.<dictcomp>)r
   r   rS   rh   r   r/   rG   r&   r"   
is_integerr   rW   )r%   r|   r}   r~   r   r   Znew_exprZis_valid_exprr   rt   r   propagate_sympy   s    z IndexPropagation.propagate_sympy)r|   r1   c                    s   t t td fdd}|S )N)r}   r~   r1   c                     s`   t t s | |S dd t| | D }tdd |D sR | |S  | |S )Nc                 S   s   g | ]}t |tr|qS r   )r   rS   r   r   r   r   r     s   
z?IndexPropagation.__getattr__.<locals>.inner.<locals>.<listcomp>c                 s   s   | ]}|j V  qd S r   rU   rv   r   r   r   rw      s     z>IndexPropagation.__getattr__.<locals>.inner.<locals>.<genexpr>)hasattrr/   r   rj   rk   valuesallr   )r}   r~   Zvar_argumentsr|   r%   r   r   r[     s    
z+IndexPropagation.__getattr__.<locals>.inner)r   rY   )r%   r|   r[   r   r   r   __getattr__  s    zIndexPropagation.__getattr__c                 C   s   | j j|| j| jd}t|S )a  
        Given some iter_ranges, return a function that given an expression, returns whether
        it is true or false using value ranges, guard knowledge and runtime_asserts.

        FIXME I think this may not be entirely right, as we may not be able to use all runtime_asserts
              If this is an issue, just use guards in `self.axioms`.

              The proper way of handling this would be to have a global shape_env that adds
              runtime_asserts as they happen in the code. Then, it shuld be used in SimplifyIndexing
              to perform wrap_expr and in CSEProxy.check_bounds to elide upper / lower bounds also
              for indirect_indexing
        )rn   rl   )rg   Z_maybe_evaluate_staticrn   rl   r   )r%   eZ	evaluatedr   r   r   statically_true'  s    z IndexPropagation.statically_trueT)indexsizecheckr1   c                    s   t |tr|jrt|jj} fdd} d|kpH  |k} |k }||}t|r 	d|ft
| | d |S  	d||fi jS )Nc                    s@     d| kr| S   | dk r(|  S t| dk |  | S d S )Nr   )r   r   rV   r%   r   r   r   	wrap_exprG  s
    z5IndexPropagation.indirect_indexing.<locals>.wrap_exprr   Zcheck_bounds)lowerr]   r{   )r   rS   rT   r   rM   r0   r"   r   r   r   dict)r%   r   r   r   r"   r   Zcan_prove_lowerZcan_prove_upperr   r   r   r{   ;  s     
z"IndexPropagation.indirect_indexingN)T)r(   r)   r*   r+   r   r   r   SymbolrR   rp   r.   r#   rq   r
   rS   ru   rY   rz   r   r   r	   strr   r   r   r   r   r   r{   r   r   r   r   rZ      sH   

 
 
 
 
	 
 
 
  rZ   )+r+   rj   dataclassesr   typingr   r   r   r   r   r   r	   r
   typing_extensionsr   r   r.   Ztorch._prims_commonr   r   Ztorch.utils._sympy.functionsr   r   r   Ztorch.utils._sympy.value_rangesr   r   utilsr   Zvirtualizedr   rR   r   r   r   r,   r    r!   r/   rS   rY   r-   rZ   r   r   r   r   <module>   s(   (c