B
     \R                 @   s   d dl mZmZmZ d dlZd dlZd dlZd dlmZ e	dddgZ
G dd deZG d	d
 d
ed
dZG dd deZG dd deZdS )    )print_functiondivisionabsolute_importN)utilsZ
SETUP_LOOPZFOR_ITERZ
SETUP_WITHc               @   s$   e Zd Zdd Zdd Zdd ZdS )CFBlockc             C   s"   || _ g | _i | _i | _d| _d S )NF)offsetbodyoutgoing_jumpsincoming_jumpsterminating)selfr    r   0lib/python3.7/site-packages/numba/controlflow.py__init__   s
    zCFBlock.__init__c             C   s    | j t| jt| jf}d| S )Nz,block(offset:%d, outgoing: %s, incoming: %s))r   sortedr	   r
   )r   argsr   r   r   __repr__   s    zCFBlock.__repr__c             C   s
   t | jS )N)iterr   )r   r   r   r   __iter__    s    zCFBlock.__iter__N)__name__
__module____qualname__r   r   r   r   r   r   r   r      s   r   c               @   s$   e Zd ZdZdZdd Zdd ZdS )Loopz?
    A control flow loop, as detected by a CFGraph object.
    r   c             C   s   t |to|j| jkS )N)
isinstancer   header)r   otherr   r   r   __eq__1   s    zLoop.__eq__c             C   s
   t | jS )N)hashr   )r   r   r   r   __hash__4   s    zLoop.__hash__N)r   r   r   __doc__	__slots__r   r   r   r   r   r   r   $   s   r   )entriesexitsr   r   c               @   s$  e Zd ZdZdd Zdd ZdFd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dGd(d)ZdHd*d+ZdId,d-Zd.d/ ZdJd0d1Zd2d3 Zd4d5 ZdKd6d7Zd8d9 Zd:d; Zd<d= Z d>d? Z!d@dA Z"dBdC Z#dDdE Z$dS )LCFGraphzB
    Generic (almost) implementation of a Control Flow Graph.
    c             C   s0   t  | _tt | _tt | _i | _d | _d S )N)set_nodescollectionsdefaultdict_preds_succs
_edge_data_entry_point)r   r   r   r   r   =   s
    zCFGraph.__init__c             C   s   | j | dS )z
        Add *node* to the graph.  This is necessary before adding any
        edges from/to the node.  *node* can be any hashable object.
        N)r%   add)r   noder   r   r   add_nodeD   s    zCFGraph.add_nodeNc             C   s.   || j kst|| j kst| ||| dS )z
        Add an edge from node *src* to node *dest*, with optional
        per-edge *data*.
        If such an edge already exists, it is replaced (duplicate edges
        are not possible).
        N)r%   AssertionError	_add_edge)r   srcdestdatar   r   r   add_edgeK   s    zCFGraph.add_edgec             c   s,   x&| j | D ]}|| j||f fV  qW dS )z
        Yield (node, data) pairs representing the successors of node *src*.
        (*data* will be None if no data was specified when adding the edge)
        N)r)   r*   )r   r1   r2   r   r   r   
successorsV   s    zCFGraph.successorsc             c   s,   x&| j | D ]}|| j||f fV  qW dS )z
        Yield (node, data) pairs representing the predecessors of node *dest*.
        (*data* will be None if no data was specified when adding the edge)
        N)r(   r*   )r   r2   r1   r   r   r   predecessors^   s    zCFGraph.predecessorsc             C   s   || j kst|| _dS )z=
        Set the entry point of the graph to *node*.
        N)r%   r/   r+   )r   r-   r   r   r   set_entry_pointf   s    zCFGraph.set_entry_pointc             C   sV   | j dkrtd|   |   |   |   |   |   |   | 	  dS )z
        Compute various properties of the control flow graph.  The graph
        must have been fully populated, and its entry point specified.
        Nzno entry point defined!)
r+   RuntimeError_eliminate_dead_blocks_find_exit_points_find_dominators_find_back_edges_find_topo_order_find_descendents_find_loops_find_post_dominators)r   r   r   r   processm   s    
zCFGraph.processc             C   s   | j S )z
        Return a dictionary of {node -> set(nodes)} mapping each node to
        the nodes dominating it.

        A node D dominates a node N when any path leading to N must go through D.
        )_doms)r   r   r   r   
dominators}   s    zCFGraph.dominatorsc             C   s   | j S )z
        Return a dictionary of {node -> set(nodes)} mapping each node to
        the nodes post-dominating it.

        A node P post-dominates a node N when any path starting from N must go
        through P.
        )
_post_doms)r   r   r   r   post_dominators   s    zCFGraph.post_dominatorsc             C   s
   | j | S )zx
        Return the set of descendents of the given *node*, in topological
        order (ignoring back edges).
        )_descs)r   r-   r   r   r   descendents   s    zCFGraph.descendentsc             C   s   | j dk	st| j S )z.
        Return the entry point node.
        N)r+   r/   )r   r   r   r   entry_point   s    zCFGraph.entry_pointc             C   s   | j S )zG
        Return the computed set of exit nodes (may be empty).
        )_exit_points)r   r   r   r   exit_points   s    zCFGraph.exit_pointsc             C   s   | j | j S )z
        Return the set of nodes constituting the graph's backbone.
        (i.e. the nodes that every path starting from the entry point
         must go through).  By construction, it is non-empty: it contains
         at least the entry point.
        )rD   r+   )r   r   r   r   backbone   s    zCFGraph.backbonec             C   s   | j S )z
        Return a dictionary of {node -> loop} mapping each loop header
        to the loop (a Loop instance) starting with it.
        )_loops)r   r   r   r   loops   s    zCFGraph.loopsc                s    fdd j | D S )zm
        Return the list of Loop objects the *node* belongs to,
        from innermost to outermost.
        c                s   g | ]} j | qS r   )rL   ).0x)r   r   r   
<listcomp>   s    z$CFGraph.in_loops.<locals>.<listcomp>)	_in_loops)r   r-   r   )r   r   in_loops   s    zCFGraph.in_loopsc             C   s   | j S )zK
        Return the set of dead nodes (eliminated from the graph).
        )_dead_nodes)r   r   r   r   
dead_nodes   s    zCFGraph.dead_nodesc             C   s   | j S )z/
        Return the set of live nodes.
        )r%   )r   r   r   r   nodes   s    zCFGraph.nodesc             C   s   | j S )zb
        Return the sequence of nodes in topological order (ignoring back
        edges).
        )_topo_order)r   r   r   r   
topo_order   s    zCFGraph.topo_orderFc             c   s:   t |}| j}|rt|}x|D ]}||kr |V  q W dS )z
        Iterate over the *nodes* in topological order (ignoring back edges).
        The sort isn't guaranteed to be stable.
        N)r$   rV   reversed)r   rU   reverseitnr   r   r   	topo_sort   s    
zCFGraph.topo_sortc             C   s   ddl }|ptj}td|d | | td|d |j | j|d td|d |j | j|d tdt| j|d td	|d |j | j	|d td
|d |j | j
|d td|d |j |  |d dS )z3
        Dump extensive debug information.
        r   NzCFG adjacency lists:)filezCFG dominators:)streamzCFG post-dominators:zCFG back edges:z
CFG loops:zCFG node-to-loops:zCFG backbone:)pprintsysstdoutprint_dump_adj_listsrB   rD   r   _back_edgesrL   rQ   rK   )r   r]   r_   r   r   r   dump   s    

zCFGraph.dumpc             C   s2   | j | | | j| | || j||f< d S )N)r(   r,   r)   r*   )r   Zfrom_tor3   r   r   r   r0      s    zCFGraph._add_edgec             C   sl   x2| j |dD ] }| j| | | j||f= qW x2| j|dD ] }| j | | | j||f= qDW d S )Nr   )r)   popr(   remover*   )r   r-   succZpredr   r   r   _remove_node_edges   s    zCFGraph._remove_node_edgesc             c   sj   |d kr| j f}t }t|}xF|rd| }||kr |V  || x| j| D ]}|| qPW q W d S )N)r+   r$   listrg   r,   r)   append)r   r!   seenstackr-   ri   r   r   r   _dfs  s    
zCFGraph._dfsc             C   sR   t  }x|  D ]}|| qW | j| | _|| _x| jD ]}| | q<W dS )zx
        Eliminate all blocks not reachable from the entry point, and
        stash them into self._dead_nodes.
        N)r$   ro   r,   r%   rS   rj   )r   Zliver-   Zdeadr   r   r   r9     s    zCFGraph._eliminate_dead_blocksc             C   s6   t  }x$| jD ]}| j|s|| qW || _dS )z2
        Compute the graph's exit points.
        N)r$   r%   r)   getr,   rI   )r   rJ   r[   r   r   r   r:     s
    zCFGraph._find_exit_pointsc       
         s(  |rt | j}| j}| j}nt | jg}| j}| j}|s@tdi  x|D ]}t |g |< qJW g }x.| jD ]$}||krlt | j |< || qlW x|r"| }||krqt |g}|| }	|	r|t	
t j fdd|	D O }| | krt|t | k s
t| |< |||  qW  S )Nz5no entry points: dominator algorithm cannot be seededc                s   g | ]} | qS r   r   )rN   p)domsr   r   rP   J  s    z5CFGraph._find_dominators_internal.<locals>.<listcomp>)r$   rI   r)   r(   r+   r8   r%   rl   rg   	functoolsreduceintersectionlenr/   extend)
r   postr!   Zpreds_tableZsuccs_tableeZtodor[   Znew_domsZpredsr   )rr   r   _find_dominators_internal&  s>    



z!CFGraph._find_dominators_internalc             C   s   | j dd| _d S )NF)rx   )rz   rB   )r   r   r   r   r;   Q  s    zCFGraph._find_dominatorsc             C   s   t  }| j| x4| j D ]&}|jsx|jD ]}| || q0W qW | jdd| _	| j	|= x| j	 D ]}|
| qjW | | | j| d S )NT)rx   )objectrI   r,   rL   valuesr"   r   r0   rz   rD   discardrj   rh   )r   Z
dummy_exitloopbrr   r   r   r   r@   T  s    
zCFGraph._find_post_dominatorsc                s^   t  }xL| j D ]>\ }| j  |@ }t|dks8t| fdd|D  qW || _dS )zu
        Find back edges.  An edge (src, dest) is a back edge if and
        only if *dest* dominates *src*.
           c             3   s   | ]} |fV  qd S )Nr   )rN   r2   )r1   r   r   	<genexpr>s  s    z+CFGraph._find_back_edges.<locals>.<genexpr>N)r$   r)   itemsrB   rv   r/   updaterd   )r   
back_edgessuccsZbackr   )r1   r   r<   h  s    zCFGraph._find_back_edgesc                sF   | j | jg t  fdd  | j   | _d S )Nc                sF   | krB |  x$|  D ]}| |fkr | qW |  d S )N)r,   rl   )r-   r2   )_dfs_recr   
post_orderrm   r   r   r   r   |  s    
z*CFGraph._find_topo_order.<locals>._dfs_rec)r)   rd   r$   r+   rY   rV   )r   r   )r   r   r   rm   r   r   r=   v  s    
zCFGraph._find_topo_orderc             C   sj   i }xZt | jD ]L}t  ||< }x8| j| D ]*}||f| jkr.|| |||  q.W qW || _d S )N)rX   rV   r$   r)   rd   r,   r   rF   )r   Zdescsr-   Z
node_descsri   r   r   r   r>     s    
zCFGraph._find_descendentsc             C   sZ  i }xz| j D ]p\}}|}t|g}|g}x2|rZ| }||kr*|| || j|  q*W ||krt|| | q|||< qW i }xn| D ]b\}}t }	t }
x4|D ],}|	| j| |  |
| j| |  qW t	|||	|
d}|||< qW || _
tdd | jD }x@t| dd dD ](}x |jD ]}|| |j q0W q$W || _dS )zC
        Find the loops defined by the graph's back edges.
        )r   r   r!   r"   c             s   s   | ]}|g fV  qd S )Nr   )rN   r[   r   r   r   r     s    z&CFGraph._find_loops.<locals>.<genexpr>c             S   s
   t | jS )N)rv   r   )r~   r   r   r   <lambda>  s    z%CFGraph._find_loops.<locals>.<lambda>)keyN)rd   r$   rg   r,   rw   r(   r   r   r)   r   rL   dictr%   r   r|   r   rl   r   rQ   )r   Zbodiesr1   r2   r   r   Zqueuer[   rM   r!   r"   r~   rR   r   r   r   r?     s8    


zCFGraph._find_loopsc             C   s2   t dd | j D }dd l}|j||d d S )Nc             s   s"   | ]\}}|t t|fV  qd S )N)r   rk   )rN   r1   Zdestsr   r   r   r     s   z*CFGraph._dump_adj_lists.<locals>.<genexpr>r   )r^   )r   r)   r   r_   )r   r]   Z	adj_listsr_   r   r   r   rc     s    zCFGraph._dump_adj_lists)N)F)N)N)N)F)%r   r   r   r   r   r.   r4   r5   r6   r7   rA   rC   rE   rG   rH   rJ   rK   rM   rR   rT   rU   rW   r\   re   r0   rj   ro   r9   r:   rz   r;   r@   r<   r=   r>   r?   rc   r   r   r   r   r#   8   sD   
	
	





+
-r#   c               @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd.ddZdd Z	d/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eZeZeZeZd"d# ZeZeZd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd
S )0ControlFlowAnalysisz
    Attributes
    ----------
    - bytecode

    - blocks

    - blockseq

    - doms: dict of set
        Dominators

    - backbone: set of block offsets
        The set of block that is common to all possible code path.

    c             C   sF   || _ i | _i | _g | _d | _d | _d| _d | _g | _g | _	g | _
d S )NT)bytecodeblocks
liveblocksblockseqrr   rK   _force_new_block	_curblock_blockstackrL   _withs)r   r   r   r   r   r     s    zControlFlowAnalysis.__init__c             c   s    x| j D ]}| j| V  qW dS )z=
        Return all blocks in sequence of occurrence
        N)r   r   )r   ir   r   r   
iterblocks  s    zControlFlowAnalysis.iterblocksc             c   s*   x$| j D ]}|| jkr| j| V  qW dS )zB
        Return all live blocks in sequence of occurrence
        N)r   r   r   )r   r   r   r   r   iterliveblocks  s    
z"ControlFlowAnalysis.iterliveblocksc             c   s6   x0|j  D ]"\}}|| jkr| j| |fV  qW dS )zQ
        Yield (incoming block, number of stack pops) pairs for *block*.
        N)r
   r   r   r   )r   blockr   popsr   r   r   incoming_blocks  s    
z#ControlFlowAnalysis.incoming_blocksNc             C   s   | j jd d d S )N)r]   )graphre   )r   r]   r   r   r   re     s    zControlFlowAnalysis.dumpc                s  xF   D ]:}d|j }t |d }|d k	r6|| q
|jr
t|q
W xBt j jdd  D ](\}} j| }|js`|j	s`d|j|< q`W t
 }x jD ]}|| qW x: j D ],}x&|j D ]\}	}
||j|	|
 qW qW |t j |  | _xBt jD ]2}x*|j D ]\}	}
|
 j|	 j|j< q$W qW t fdd j D  _x*t jD ]}| jkrtP qtW td j }t }xP j D ]B}x: jD ]0\}}||  kr|k rn n
|| qW qW ||  _d S )Nzop_%sr   r   c             3   s   | ]}| j | fV  qd S )N)r   )rN   r   )r   r   r   r     s   z*ControlFlowAnalysis.run.<locals>.<genexpr>zNo live block that exits!?) 
_iter_instopnamegetattrZis_jumpr/   zipr   r   r	   r   r#   r.   r|   r   r4   r   r7   minrA   r   r   Z
itervaluesr
   r   rU   r   rX   rK   r$   keysrL   r,   )r   instfnamefnZcurZnxtZblkr   r   outr   ZlastblkrK   Zinloopblockssry   r   )r   r   run  sF    

 

zControlFlowAnalysis.runr   c             C   s   || j j|< dS )z
        Register a jump (conditional or not) to *target* offset.
        *pops* is the number of stack pops implied by the jump (default 0).
        N)r   r	   )r   targetr   r   r   r   jump5  s    zControlFlowAnalysis.jumpc             c   s>   x8| j D ].}| |r | | | jj|j |V  qW d S )N)r   _use_new_block_start_new_blockr   r   rl   r   )r   r   r   r   r   r   <  s
    

zControlFlowAnalysis._iter_instc             C   s4   |j | jjkrd}n|jtkr$d}n| j}d| _|S )NTF)r   r   labelsr   NEW_BLOCKERSr   )r   r   Zresr   r   r   r   C  s    
z"ControlFlowAnalysis._use_new_blockc             C   s,   t |j| _| j| j|j< | j|j d S )N)r   r   r   r   r   rl   )r   r   r   r   r   r   N  s    z$ControlFlowAnalysis._start_new_blockc             C   s<   |  }| j| | j|j|f | |j d| _d S )NT)get_jump_targetr   rl   rL   r   r   nextr   )r   r   endr   r   r   op_SETUP_LOOPS  s
    z!ControlFlowAnalysis.op_SETUP_LOOPc             C   s<   |  }| j| | j|j|f | |j d| _d S )NT)r   r   rl   r   r   r   r   r   )r   r   r   r   r   r   op_SETUP_WITH]  s
    z!ControlFlowAnalysis.op_SETUP_WITHc             C   s   | j   d S )N)r   rg   )r   r   r   r   r   op_POP_BLOCKg  s    z ControlFlowAnalysis.op_POP_BLOCKc             C   s$   |  |  |  |j d| _d S )NT)r   r   r   r   )r   r   r   r   r   op_FOR_ITERj  s    zControlFlowAnalysis.op_FOR_ITERc             C   s$   |  |  |  |j d| _d S )NT)r   r   r   r   )r   r   r   r   r   _op_ABSOLUTE_JUMP_IFo  s    z(ControlFlowAnalysis._op_ABSOLUTE_JUMP_IFc             C   s(   |  |  | j |jdd d| _d S )Nr   )r   T)r   r   r   r   )r   r   r   r   r   _op_ABSOLUTE_JUMP_OR_POPy  s    z,ControlFlowAnalysis._op_ABSOLUTE_JUMP_OR_POPc             C   s   |  |  d| _d S )NT)r   r   r   )r   r   r   r   r   op_JUMP_ABSOLUTE  s    z$ControlFlowAnalysis.op_JUMP_ABSOLUTEc             C   s   |  |  d| _d S )NT)r   r   r   )r   r   r   r   r   op_JUMP_FORWARD  s    z#ControlFlowAnalysis.op_JUMP_FORWARDc             C   s   d| j _d| _d S )NT)r   r   r   )r   r   r   r   r   op_RETURN_VALUE  s    z#ControlFlowAnalysis.op_RETURN_VALUEc             C   s   d| j _d| _d S )NT)r   r   r   )r   r   r   r   r   op_RAISE_VARARGS  s    z$ControlFlowAnalysis.op_RAISE_VARARGSc             C   s   |  | jd  d| _d S )NT)r   r   r   )r   r   r   r   r   op_BREAK_LOOP  s    z!ControlFlowAnalysis.op_BREAK_LOOP)N)r   )r   r   r   r   r   r   r   r   re   r   r   r   r   r   r   r   r   r   r   Zop_POP_JUMP_IF_FALSEZop_POP_JUMP_IF_TRUEZop_JUMP_IF_FALSEZop_JUMP_IF_TRUEr   Zop_JUMP_IF_FALSE_OR_POPZop_JUMP_IF_TRUE_OR_POPr   r   r   r   r   r   r   r   r   r     s8   
6


r   )Z
__future__r   r   r   r&   rs   r`   Znumbar   	frozensetr   r{   r   
namedtupler   r#   r   r   r   r   r   <module>   s   
   