o
    i>                     @  s*  U d Z ddlmZ ddlZddlmZ ddlmZmZm	Z	m
Z
mZ ddlmZ ddlmZmZ dd	lmZmZ dd
lmZ dZejde  Zded< ejrXeddZneddZdNddZG dd dejZG dd de
Z G dd de
Z!G dd de
Z"i d e  d!e  d"e  d#e  d$e  d%e  d&e  d'e  d(e  d)e  d*e  d+e  d,e  d-e!d.dd/d0e!d.dd/d1e!d2d.d/d3e!d4dd/e!d5dd/e!d6dd7e!d.dd/e" e" e"d8d9e" e"d:d9e"d;d9e"d<d9e!d.dd/e  d=Z#d>ed?< dOdCdDZ$dPdLdMZ%dS )QzRegister allocation tests    )annotationsN)Path)CallableListMapping
NamedTupleUnion   )basic)asmparse)OpcodeRegister)common   chapter_r   WRAPPER_SCRIPT	librarieszwrapper_osx.szwrapper_linux.siasm.AsmItemreturnboolc                   s2   t | tjrdS ddd t fdd	| jD S )z:Is this an instruction that accesses a value on the stack?Foperandasm.Operandr   r   c                 S  s   t | tjo| jtjkS N)
isinstancer   Memorybaser   BP)r    r   c/home/gtoal/gtoal.com/languages/algol60/new-unicode-parser/lang/c/tests4/test_framework/regalloc.pyis_stack    s   zuses_stack.<locals>.is_stackc                 3  s    | ]} |V  qd S r   r   ).0opr!   r   r    	<genexpr>#   s    zuses_stack.<locals>.<genexpr>N)r   r   r   r   )r   r   Labelanyoperands)r   r   r$   r    
uses_stack   s   
r)   c                   @  sp   e Zd ZdZedddZd ddZd!d
dZ	d"d#ddZddd$ddZ	ddd%ddZ
		d&d'ddZdS )(TestRegAlloca  Test class for register allocation.

    We'll generate a test method for each C program in the chapter_20/ directory.
    Each dynamically generated test calls one of the main test methods defined below:

    * basic_test: make sure the program behaves correctly but don't inspect the assembly code
    * no_spills_test: make sure we can allocate every register without spilling
    * spill_test: the number of spilled pesudos and the number of instructions that
        access the stack should both be below some upper bound
    r   r   c                 C  s   | j dS )z'Directory containing extra library coder   )test_dirjoinpathselfr   r   r    lib_path2   s   zTestRegAlloc.lib_pathNonec                 C  s,   dd | j dD }|D ]}|  qdS )zvDelete files produced during this test run (e.g. assembly and object files)

        Don't delete the wrapper scripts!c                 s  s<    | ]}|  s|jd vr|jdvr|jtjvr|V  qdS )).cz.h)wrapper_osxwrapper_linuxN)is_dirsuffixstemnamer
   ASSEMBLY_LIBS)r"   fr   r   r    r%   ;   s    

z(TestRegAlloc.tearDown.<locals>.<genexpr>*N)r+   rglobunlink)r.   garbage_filesr9   r   r   r    tearDown7   s   
	
zTestRegAlloc.tearDownprogram_pathc                 C  s&   t |dtg }| || dS )a  Test that the compiled program behaves correctly but don't inspect the assembly code.

        Compile the program, linking against the wrapper script (which defines main) and any extra
        libraries, then run it and validate the result.

        Tests that _do_ inspect the assembly code should first call basic_test to make sure
        the program behaves correctly, then parse the assembly file and perform further validation.

        Args:
            program_path: Absolute path to C or assembly file to compile and run
        r1   N)r
   get_libswith_suffixr   library_test_helper)r.   r?   
extra_libsr   r   r    
basic_testG   s   zTestRegAlloc.basic_testtarget
target_funstrasm.AssemblyFunctionc              
   C  sv   z| j |dd  W n tjy' } z| d|j  W Y d}~nd}~ww |d}| | t	|| }|S )a  Shared logic for register allocation tests that validate assembly code.
        1. Compile the file at program_path to assembly
        2. Call basic_test to make sure it behaves correctly
        3. Parse assembly file and return it
        The caller can then perform further validation on the parsed assembly code

        Args:
            program_path: Absolute path to C file under test
            target_fun: Name of function to parse/inspect
        Returns:
            Parsed assembly code for specified target fun
        z-s)cc_optzCompilation failed:
Nz.s)
invoke_compilercheck_returncode
subprocessCalledProcessErrorfailstderrrA   rD   r   
parse_file)r.   r?   rF   easm_file
parsed_asmr   r   r    run_and_parseV   s   

zTestRegAlloc.run_and_parserF   c                C  s>   | j ||d}dd |jD }| j|tjd|||dd dS )aQ  Test that we allocated every register in target_fun without spilling.
        First make sure behavior is correct, then examine parsed assembly
        to validate that we never access the stack

        Args:
            program_path: Absolute path to C file under test
            target_fun: Name of function to parse/inspect
        r?   rF   c                 S     g | ]}t |r|qS r   r)   r"   r   r   r   r    
<listcomp>       z/TestRegAlloc.no_spills_test.<locals>.<listcomp>1Found instructions that use operands on the stackbad_instructions	full_progr?   msgN)rT   instructionsassertFalser   	build_msg)r.   r?   rF   rS   r^   r   r   r    no_spills_testw   s   
zTestRegAlloc.no_spills_testmax_spilled_instructionsintmax_spilled_pseudosc             	   C  s   | j ||d}dd |jD }| jt||tjd| d|||dd tdd |D }| jt||tjd	| d
|||dd dS )ao  Test for a program with so many conflicts that it spills.
        First validate the compiled program's behavior, then make sure we don't
        have more than the expected number of distinct spilled pseudoregisters,
        or produce more than the expected number of instructions that access the stack

        Args:
            program_path: Absolute path to C file under test
            max_spilled_instructions: maximum number of instructions that access the stack
            max_spilled_pseudos: maximum number of distinct stack addresses accessed
            target_fun: Name of function to parse/inspect
        rV   c                 S  s$   g | ]}t |r|jtjkr|qS r   )r)   opcoder   MOVrY   r   r   r    rZ      s    z+TestRegAlloc.spill_test.<locals>.<listcomp>zShould only need zJ instructions involving spilled pseudo but found {len(spill_instructions)}r]   r`   c                 S  s,   g | ]}|j D ]}t|tjrt|qqS r   )r(   r   r   r   rG   )r"   r   r#   r   r   r    rZ      s    
zAt most zM pseudoregs should have been spilled, looks like {len(spilled_operands)} wereN)rT   rb   assertLessEquallenr   rd   set)r.   r?   rf   rh   rF   rS   spill_instructionsspilled_operandsr   r   r    
spill_test   s@   


zTestRegAlloc.spill_testr   	max_movesc              	     s   ddd | j ||d}dd	 |jD } fd
d	|jD }| j|tjd|||dd | jt||tjd| dt| |||dd dS )a  Test that we perform register coalescing properly.

        First validate the compiled program's behavior, then make sure we don't
        have more than the expected number of mov instructions where the source
        and destination are both registers. Also validate that there are no spills.

        Args:
            program_path: Absolute path to C file under test
            target_fun: Name of function to parse/inspect
            max_moves: maximum number of mov instructions between registers
        r   r   r   r   c                 S  s\   t | r,| jd | jd }}t|tjo+|tjtjfvo+t|tjo+|tjtjfvS dS )zCCheck whether this is a move between registers (other than RBP/RSP)r   r	   F)r   is_movr(   r   r   r   r   SP)r   srcdstr   r   r    is_mov_between_regs   s   

z9TestRegAlloc.coalescing_test.<locals>.is_mov_between_regsrU   c                 S  rW   r   rX   rY   r   r   r    rZ      r[   z0TestRegAlloc.coalescing_test.<locals>.<listcomp>c                   s   g | ]} |r|qS r   r   rY   rv   r   r    rZ      s
    r\   r]   r`   zExpected at most z move instructions but found Nr   r   r   r   )rT   rb   rc   r   rd   rk   rl   )r.   r?   rF   rq   rS   r^   mov_instructionsr   rw   r    coalescing_test   s8   

	
zTestRegAlloc.coalescing_testN)r   r   )r   r0   )r?   r   r   r0   )rE   )r?   r   rF   rG   r   rH   )r?   r   rF   rG   r   r0   )
r?   r   rf   rg   rh   rg   rF   rG   r   r0   )rE   r   )r?   r   rF   rG   rq   rg   r   r0   )__name__
__module____qualname____doc__propertyr/   r>   rD   rT   re   rp   rz   r   r   r   r    r*   &   s    

%'Ar*   c                   @  s   e Zd ZU dZded< dS )NoSpillTestrE   rG   rF   N)r{   r|   r}   rF   __annotations__r   r   r   r    r     s   
 r   c                   @  s*   e Zd ZU ded< ded< dZded< dS )	SpillTestrg   rh   rf   rE   rG   rF   N)r{   r|   r}   r   rF   r   r   r   r    r     s   
 r   c                   @  s&   e Zd ZU dZded< dZded< dS )CoalesceTestrE   rG   rF   r   rg   rq   N)r{   r|   r}   rF   r   rq   r   r   r   r    r     s   
 r   ztrivially_colorable.czuse_all_hardregs.czpreserve_across_fun_call.cztrack_arg_registers.czmany_pseudos_fewer_conflicts.czcmp_no_updates.czcopy_no_interference.czsame_instr_no_interference.czloop.czdbl_trivially_colorable.czfourteen_pseudos_interfere.cztrack_dbl_arg_registers.czstore_pointer_in_register.czforce_spill.c   )rf   rh   zforce_spill_mixed_ints.czrewrite_regression_test.c
   ztest_spill_metric.c         )rh   rf      )rq            )ztest_spill_metric_2.czoptimistic_coloring.czforce_spill_doubles.czbriggs_coalesce.czgeorge_coalesce.czcoalesce_prevents_spill.czbriggs_coalesce_hardreg.czbriggs_dont_coalesce.czgeorge_dont_coalesce.czgeorge_dont_coalesce_2.czno_george_test_for_pseudos.czgeorge_off_by_one.cz9Mapping[str, Union[CoalesceTest, NoSpillTest, SpillTest]]REGALLOC_TESTSprogramno_coalescingCallable[[TestRegAlloc], None]c                   s   t j}|du rtS djv r|rdfdd}|S t|tr0| d fd	d}|S t|trA|dfd
d}|S |dfdd}|S )z/Generate test method for a single test program.Nwith_coalescingr.   r*   r   r0   c                   s   |    d S r   )rD   r-   )r   r   r    testm  s   z make_regalloc_test.<locals>.testc                   s   | j  jd d S )NrU   )re   rF   r-   )nospilltest_infor   r   r    r   u  s   
c                   s   | j  jjjd d S )N)rf   rh   rF   )rp   rf   rh   rF   r-   )r   spilltest_infor   r    r   ~  s   
c                   s   | j  jjd d S )N)rF   rq   )rz   rF   rq   r-   )r   tir   r    r     s
   
)r.   r*   r   r0   )	r   getr7   r
   make_test_runpartsr   r   r   )r   r   	test_infor   r   )r   r   r   r   r    make_regalloc_test]  s"   
#

r   compileroptions	List[str]extra_credit_flagsbasic.ExtraCreditint_onlyr0   c           
      C  s   t tdt t td|  t td| t tdd |rdg}nddg}dd	 |D }|D ]'}t||r4q+|td
}d| }	tt|	drIJ t t|	t|| q+dS )a  Dynamically add test methods and attributes to TestRegAlloc.

    Args:
        compiler: absolute path to compiler under test
        options: extra command-line arguments to pass through to compiler
        extra_credit_flags: extra credit features to test, represented as a bit vector
        int_only: the reader skipped Part II;
            only include tests that rely on Part I language features
        no_coalescing: the reader hasn't implemented register coalescing yet, so don't test for it
    r+   ccr   
exit_stageNr   	all_typesc                 S  s$   g | ]}t | d D ]}|qqS )z*.c)TEST_DIRr;   )r"   subdirpr   r   r    rZ     s   $ z#configure_tests.<locals>.<listcomp> test_)	setattrr*   r   r
   excluded_extra_creditrelative_torA   getattrr   )
r   r   r   r   r   subdirs	all_testsr   keyr7   r   r   r    configure_tests  s$   
r   rx   )r   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r0   )&r~   
__future__r   rL   pathlibr   typingr   r   r   r   r   r   r
   parserr   r   
parser.asmr   r   tackyr   CHAPTERr   r,   resolver   IS_OSXr   r)   TestChapterr*   r   r   r   r   r   r   r   r   r   r    <module>   s    
 p	

96