U
    +‰dM4  ã                   @   sÒ   d dl Z d dlmZ d dlmZ d dlmZ ddlmZ	 dd„ Z
G d	d
„ d
eƒZe d¡ ¡ ZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZedkrÎe  ¡  dS )é    N)Úir)Úbinding)ÚTestCaseé   )Úrefprune_protoc                 #   sB   ‡ fdd„}t j ¡ D ]&\}}| d¡rd|› ||ƒfV  qd S )Nc                    s(   ‡ ‡fdd„}dˆ j › dˆ j› |_|S )Nc                    s
   ˆ| ˆ ƒS ©N© )Úself)ÚfnÚgenerate_testr   ú@/tmp/pip-unpacked-wheel-stw2luzp/llvmlite/tests/test_refprune.pyÚwrapped   s    z-_iterate_cases.<locals>.wrap.<locals>.wrappedzgenerated test for Ú.)Ú
__module__Ú__name__Ú__doc__)r
   r   ©r   )r
   r   Úwrap
   s    z_iterate_cases.<locals>.wrapÚcaseZtest_)ÚprotoÚ__dict__ÚitemsÚ
startswith)r   r   ÚkZcase_fnr   r   r   Ú_iterate_cases	   s    
r   c                   @   s4   e Zd ZdZdd„ ZeeƒD ]\ZZeeƒ e< qdS )ÚTestRefPrunePrototypez-
    Test that the prototype is working.
    c                 C   s,   |ƒ \}}}t  ||¡ ¡ }|  ||¡ d S r   )r   ZFanoutAlgorithmÚrunÚassertEqual)r	   Úcase_genÚnodesÚedgesÚexpectedÚgotr   r   r   r      s    z#TestRefPrunePrototype.generate_testN)	r   r   Ú__qualname__r   r   r   Únamer   Úlocalsr   r   r   r   r      s   r   é   c                   @   sl   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eeƒD ]\ZZeeƒ e< qTdS )ÚTestRefPrunePasszß
    Test that the C++ implementation matches the expected behavior as for
    the prototype.

    This generates a LLVM module for each test case, runs the pruner and checks
    that the expected results are achieved.
    c                 C   s"   t  t  ¡ tg¡}t j||ddS )NÚ
NRT_incref©r$   ©r   ÚFunctionTypeÚVoidTypeÚptr_tyÚFunction©r	   ÚmÚfntyr   r   r   Úmake_incref/   s    zTestRefPrunePass.make_increfc                 C   s"   t  t  ¡ tg¡}t j||ddS )NÚ
NRT_decrefr)   r*   r/   r   r   r   Úmake_decref3   s    zTestRefPrunePass.make_decrefc                 C   s"   t  t  d¡d¡}t j||ddS )Né    r   Zswitcherr)   ©r   r+   ÚIntTyper.   r/   r   r   r   Úmake_switcher7   s    zTestRefPrunePass.make_switcherc                 C   s"   t  t  d¡d¡}t j||ddS )Nr   r   Zbrancherr)   r6   r/   r   r   r   Úmake_brancher;   s    zTestRefPrunePass.make_brancherc                 C   sÆ  t  ¡ }|  |¡}|  |¡}|  |¡}|  |¡}t  t  ¡ tg¡}t j	||dd}	|	j
\}
d|
_i }|D ]}|	 |¡||< qht  ¡ }| ¡ D ]2\}}| || ¡ || D ]<}|dkrÈ| ||
g¡ q¬|dkrà| ||
g¡ q¬tdƒ‚q¬t|ƒ}|dkr| ¡  qŒ|dkr&|\}| || ¡ qŒ|d	kr\|\}}| |d
¡}| ||| || ¡ qŒ|d	kr¸| |d
¡}|^}}|j||| d}t|ƒD ] \}}| | |¡|| ¡ q”qŒtdƒ‚qŒ|S )NÚmainr)   ZmemÚincrefÚdecrefZunreachabler   r   é   r   )Údefault)r   ÚModuler2   r4   r8   r9   r+   r,   r-   r.   Úargsr$   Zappend_basic_blockZ	IRBuilderr   Zposition_at_endÚcallÚAssertionErrorÚlenZret_voidÚbranchZcbranchÚswitchÚ	enumerateZadd_caseÚtype)r	   r   r    r0   Z	incref_fnZ	decref_fnZswitcher_fnZbrancher_fnr1   r
   ÚptrZbbmapÚbbZbuilderZjump_targetsÚactionÚ	n_targetsÚdstÚleftÚrightÚselÚheadÚtailÚswÚir   r   r   Úgenerate_ir?   sN    










zTestRefPrunePass.generate_irc                 C   s,   t  t|ƒ¡}t  ¡ }| ¡  | |¡ |S r   )ÚllvmÚparse_assemblyÚstrÚModulePassManagerÚadd_refprune_passr   )r	   ÚirmodÚmodÚpmr   r   r   Úapply_refpruneu   s
    
zTestRefPrunePass.apply_refprunec                 C   s
  i }|  ¡ D ]*\}}| d¡}| d¡}||dœ||< q|  ¡ D ]D\}}	| |¡r@|	d  d8  < || D ]}
||
 d  d8  < qjq@|jD ]}|jdkrŒ q qŒ|jD ]^}||j }	t|ƒ}| d¡}| d¡}| j|	d |d|› d	 | j|	d |d|› d	 q¦d S )
Nr;   r<   )r;   r<   r   r:   r(   r3   zBB )Úmsg)r   ÚcountÚgetZ	functionsr$   ÚblocksrW   r   )r	   r[   r!   r   Údr   ÚvsZn_increfZn_decrefÚstatsZdec_bbÚfrI   Útextr   r   r   Úcheck|   s(    








zTestRefPrunePass.checkc                 C   s4   |ƒ \}}}|   ||¡}|  |¡}|  |||¡ d S r   )rT   r]   rg   )r	   r   r   r    r!   rZ   Zoutmodr   r   r   r   –   s    
zTestRefPrunePass.generate_testN)r   r   r#   r   r2   r4   r8   r9   rT   r]   rg   r   r   r$   r   r%   r   r   r   r   r'   &   s   6r'   c                   @   s   e Zd ZdZdZddd„ZdS )ÚBaseTestByIRr   zG
declare void @NRT_incref(i8* %ptr)
declare void @NRT_decref(i8* %ptr)
Nc                 C   sj   t  | j› d|› ¡}t  ¡ }|d kr4| | j¡ n|j| j|d t  ¡ }| |¡ t  ¡ }||| fS )NÚ
©Úsubgraph_limit)rU   rV   ÚprologuerX   rY   Úrefprune_bitmaskZdump_refprune_statsr   )r	   rZ   rk   r[   r\   ÚbeforeÚafterr   r   r   rg   ©   s    ÿ
zBaseTestByIR.check)N)r   r   r#   rm   rl   rg   r   r   r   r   rh   ¡   s   rh   c                   @   sD   e Zd ZejjZdZdd„ ZdZ	dd„ Z
dZdd	„ Zd
Zdd„ ZdS )Ú	TestPerBBzv
define void @main(i8* %ptr) {
    call void @NRT_incref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S ©Nr=   )rg   Úper_bb_ir_1r   Ú
basicblock©r	   r[   rd   r   r   r   Útest_per_bb_1Â   s    zTestPerBB.test_per_bb_1zâ
define void @main(i8* %ptr) {
    call void @NRT_incref(i8* %ptr)
    call void @NRT_incref(i8* %ptr)
    call void @NRT_incref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s2   |   | j¡\}}|  |jd¡ |  dt|ƒ¡ d S )Né   zcall void @NRT_incref(i8* %ptr))rg   Úper_bb_ir_2r   rs   ÚassertInrW   rt   r   r   r   Útest_per_bb_2Ñ   s    zTestPerBB.test_per_bb_2zÌ
define void @main(i8* %ptr, i8* %other) {
    call void @NRT_incref(i8* %ptr)
    call void @NRT_incref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %other)
    ret void
}
c                 C   s2   |   | j¡\}}|  |jd¡ |  dt|ƒ¡ d S )Nr=   ú!call void @NRT_decref(i8* %other))rg   Úper_bb_ir_3r   rs   rx   rW   rt   r   r   r   Útest_per_bb_3á   s    zTestPerBB.test_per_bb_3zü
; reordered
define void @main(i8* %ptr, i8* %other) {
    call void @NRT_incref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %other)
    call void @NRT_incref(i8* %ptr)
    ret void
}
c                 C   s2   |   | j¡\}}|  |jd¡ |  dt|ƒ¡ d S )Nrv   rz   )rg   Úper_bb_ir_4r   rs   rx   rW   rt   r   r   r   Útest_per_bb_4ó   s    zTestPerBB.test_per_bb_4N)r   r   r#   rU   ÚRefPruneSubpassesZPER_BBrm   rr   ru   rw   ry   r{   r|   r}   r~   r   r   r   r   rp   ·   s   
rp   c                   @   sP   e Zd ZejjZdZdd„ ZdZ	dd„ Z
dZdd	„ Zd
Zdd„ ZdZdd„ ZdS )ÚTestDiamondz•
define void @main(i8* %ptr) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br label %bb_B
bb_B:
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S rq   )rg   Úper_diamond_1r   Údiamondrt   r   r   r   Útest_per_diamond_1  s    zTestDiamond.test_per_diamond_1zè
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    br label %bb_D
bb_C:
    br label %bb_D
bb_D:
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S rq   )rg   Úper_diamond_2r   r‚   rt   r   r   r   Útest_per_diamond_2  s    zTestDiamond.test_per_diamond_2a3  
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    br label %bb_D
bb_C:
    call void @NRT_decref(i8* %ptr)  ; reject because of decref in diamond
    br label %bb_D
bb_D:
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S ©Nr   )rg   Úper_diamond_3r   r‚   rt   r   r   r   Útest_per_diamond_3/  s    zTestDiamond.test_per_diamond_3a5  
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_incref(i8* %ptr)     ; extra incref will not affect prune
    br label %bb_D
bb_C:
    br label %bb_D
bb_D:
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S rq   )rg   Úper_diamond_4r   r‚   rt   r   r   r   Útest_per_diamond_4C  s    zTestDiamond.test_per_diamond_4a0  
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    br label %bb_D
bb_C:
    br label %bb_D
bb_D:
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S )Nrv   )rg   Úper_diamond_5r   r‚   rt   r   r   r   Útest_per_diamond_5X  s    zTestDiamond.test_per_diamond_5N)r   r   r#   rU   r   ZDIAMONDrm   r   rƒ   r„   r…   r‡   rˆ   r‰   rŠ   r‹   rŒ   r   r   r   r   r€   ú   s   r€   c                   @   sD   e Zd ZdZejjZdZdd„ Z	dZ
dd„ ZdZd	d
„ Zdd„ ZdS )Ú
TestFanoutz6More complex cases are tested in TestRefPrunePass
    zí
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_decref(i8* %ptr)
    ret void
bb_C:
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S )Né   )rg   Úfanout_1r   Úfanoutrt   r   r   r   Útest_fanout_1q  s    zTestFanout.test_fanout_1a'  
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_decref(i8* %ptr)
    ret void
bb_C:
    call void @NRT_decref(i8* %ptr)
    br label %bb_B                      ; illegal jump to other decref
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S r†   )rg   Úfanout_2r   r   rt   r   r   r   Útest_fanout_2ƒ  s    zTestFanout.test_fanout_2a}  
define void @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    ret void
bb_C:
    call void @NRT_decref(i8* %ptr)
    call void @NRT_decref(i8* %ptr)
    ret void
}
c                 C   s"   |   | j¡\}}|  |jd¡ d S )Né   ©rg   Úfanout_3r   r   rt   r   r   r   Útest_fanout_3™  s    zTestFanout.test_fanout_3c                 C   s&   | j | jdd\}}|  |jd¡ d S )Nr   rj   r   r•   rt   r   r   r   Útest_fanout_3_limited  s    z TestFanout.test_fanout_3_limitedN)r   r   r#   r   rU   r   ZFANOUTrm   r   r‘   r’   r“   r–   r—   r˜   r   r   r   r   r   ]  s   r   c                   @   sD   e Zd ZejjZdZdd„ ZdZ	dd„ Z
dZdd	„ Zd
Zdd„ ZdS )ÚTestFanoutRaisezí
define i32 @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_decref(i8* %ptr)
    ret i32 0
bb_C:
    ret i32 1, !ret_is_raise !0
}

!0 = !{i1 true}
c                 C   s"   |   | j¡\}}|  |jd¡ d S rq   )rg   Úfanout_raise_1r   Úfanout_raisert   r   r   r   Útest_fanout_raise_1¶  s    z#TestFanoutRaise.test_fanout_raise_1a  
define i32 @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_decref(i8* %ptr)
    ret i32 0
bb_C:
    ret i32 1, !ret_is_a_raise !0           ; bad metadata
}

!0 = !{i1 true}
c                 C   s"   |   | j¡\}}|  |jd¡ d S r†   )rg   Úfanout_raise_2r   r›   rt   r   r   r   Útest_fanout_raise_2É  s    z#TestFanoutRaise.test_fanout_raise_2zÿ
define i32 @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    call void @NRT_decref(i8* %ptr)
    ret i32 0
bb_C:
    ret i32 1, !ret_is_raise !0
}

!0 = !{i32 1}       ; ok; use i32
c                 C   s"   |   | j¡\}}|  |jd¡ d S rq   )rg   Úfanout_raise_3r   r›   rt   r   r   r   Útest_fanout_raise_3Ü  s    z#TestFanoutRaise.test_fanout_raise_3a7  
define i32 @main(i8* %ptr, i1 %cond) {
bb_A:
    call void @NRT_incref(i8* %ptr)
    br i1 %cond, label %bb_B, label %bb_C
bb_B:
    ret i32 1, !ret_is_raise !0    ; BAD; all tails are raising without decref
bb_C:
    ret i32 1, !ret_is_raise !0    ; BAD; all tails are raising without decref
}

!0 = !{i32 1}
c                 C   s"   |   | j¡\}}|  |jd¡ d S r†   )rg   Úfanout_raise_4r   r›   rt   r   r   r   Útest_fanout_raise_4î  s    z#TestFanoutRaise.test_fanout_raise_4N)r   r   r#   rU   r   ZFANOUT_RAISErm   rš   rœ   r   rž   rŸ   r    r¡   r¢   r   r   r   r   r™   ¤  s   r™   Ú__main__)ZunittestZllvmliter   r   rU   Zllvmlite.testsr   Ú r   r   r   r   r7   Z
as_pointerr-   r'   rh   rp   r€   r   r™   r   r:   r   r   r   r   Ú<module>   s   {CcGO