o
    i                      @  s   d Z ddlmZ ddlmZ ddl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	Ze
jd
e  ZG dd de
jZdddddd*ddZd+d d!Zd+d"d#Zd+d$d%Zd+d&d'Zd+d(d)ZdS ),z'Base class for TACKY optimization tests    )annotations)Path)ListOptionalSequence   )basic)asmparse)OpcodeRegister   chapter_c                   @  s8   e Zd ZdZdddZdd	d
ZdddZdddZdS )TackyOptimizationTesta7  Base class for TACKY (chapter 19) tests.

    There are two kinds of tests for these chapters. The first is the same kind of test we use
    in Parts I & II: we compile the test program, run it, and make sure it has the correct
    observable behavior. These test methods should call compile_and_run, defined in TestChapter.

    In the second kind of test, we still compile the program, run it, and validate its behavior,
    but we also inspect its assembly code to make sure it's been optimized. These test methods
    should call run_and_parse or run_and_parse_all, defined below.

    This class defines two test methods used in dead store elimination and whole pipeline tests:
    * store_eliminated_test: Test that stores of particular constants were eliminated
    * return_const_test: Test that the only thing this function does is return a specific consatnt

    Notes:
    * This class isn't designed to test intermediate stages
        (i.e. exit_stage should always be "run").
        TODO enforce this?
    * There are no invalid test programs for this chapter
    source_filer   returndict[str, asm.AssemblyFunction]c                 C  st   | j |dd}| j|jdd| d|j d t| |d}t|}t|g| g }| 	|| t
|S )a$  Compile and run a program, validate result, then return parsed assembly.

        The caller can then perform additional validation on the parsed assembly.

        Args:
            program_path: Absolute path to test program

        Returns: parsed assembly code for whole program
        z-s)cc_optr   zcompilation of z failed with error:
msgz.s)invoke_compilerassertEqual
returncodestderrr   print_stderrwith_suffixget_libsgcc_compile_and_runvalidate_runsr
   
parse_file)selfr   compile_resultasm_filelibsactual_result r%   g/home/gtoal/gtoal.com/languages/algol60/new-unicode-parser/lang/c/tests4/test_framework/tacky/common.pyrun_and_parse_all'   s   


z'TackyOptimizationTest.run_and_parse_allasm.AssemblyFunctionc                 C  s   |  |d S )a:  Compile and run a program, validate result, then return parsed assembly for 'target' function.

        The caller can then perform additional validation on the parsed assembly.

        Args:
            program_path: Absolute path to test program

        Returns: parsed assembly code for whole program
        target)r'   )r    r   r%   r%   r&   run_and_parseE   s   
z#TackyOptimizationTest.run_and_parseredundant_consts	List[int]Nonec                  sX   dd |D dfdd |  |} fd	d|jD }| j|td
|||dd dS )a  Make sure any stores of the form mov $const, <something> were eliminated.

        The test program should contain a single 'target' function.
        Args:
            source_file: absolute path to program under test
            redundant_consts: any constants that were sources of mov instructions in the
                original program but shouldn't be after dead store elimination
        c                 S  s   g | ]}t |qS r%   )r	   	Immediate).0cr%   r%   r&   
<listcomp>]   s    z?TackyOptimizationTest.store_eliminated_test.<locals>.<listcomp>iasm.AsmItemr   boolc                   s$   t | tjot| jo| jd  v S )Nr   )
isinstancer	   Instructionr4   operandsr2   )redundant_operandsr%   r&   is_dead_store_   s
   zBTackyOptimizationTest.store_eliminated_test.<locals>.is_dead_storec                   s   g | ]} |r|qS r%   r%   r/   r2   )r:   r%   r&   r1   k       z1Found dead store that should have been eliminatedbad_instructions	full_progprogram_pathr   Nr2   r3   r   r4   r*   instructionsassertFalse	build_msg)r    r   r+   
parsed_asmr>   r%   )r:   r9   r&   store_eliminated_testR   s   


z+TackyOptimizationTest.store_eliminated_testreturned_constintc                  sJ   dfdd |  |} fdd|jD }| j|td	|||d
d dS )zValidate that the function doesn't do anything except return a constant.

        The test program should contain a single 'target' function.
        r2   r3   r   r4   c                   sb   t | rdS | ttjjt tjjgkrdS  dkr/| ttjjtjjtjjgkr/dS dS )zMWe should optimize out everything except prologue, epilogue, and mov into EAXTr   F)	is_prologue_or_epiloguer	   r6   r   MOVr.   r   AXXORr8   )rH   r%   r&   ok|   s   z3TackyOptimizationTest.return_const_test.<locals>.okc                   s   g | ]} |s|qS r%   r%   r;   )rN   r%   r&   r1      r<   z;TackyOptimizationTest.return_const_test.<locals>.<listcomp>z5Found instruction that should have been optimized outr=   r   NrA   rB   )r    r   rH   rF   r>   r%   )rN   rH   r&   return_const_testv   s   

z'TackyOptimizationTest.return_const_testN)r   r   r   r   )r   r   r   r(   )r   r   r+   r,   r   r-   )r   r   rH   rI   r   r-   )__name__
__module____qualname____doc__r'   r*   rG   rO   r%   r%   r%   r&   r      s    


$r   N   )r>   r?   r@   max_prog_disp_lengthr   strr>   Optional[Sequence[asm.AsmItem]]r?   Optional[asm.AssemblyFunction]r@   Optional[Path]rU   rI   r   c                C  sz   | g}|rdd |D }| d || |r.t|j|kr%| d n	|dt|g |r8| d|  d|S )z?Utility function for validators to report invalid assembly codec                 S  s   g | ]}t |qS r%   )rV   r;   r%   r%   r&   r1      s    zbuild_msg.<locals>.<listcomp>zBad instructions:z1Complete assembly function: <too long, not shown>zComplete assembly function:z	Program: 
)appendextendlenrC   rV   join)r   r>   r?   r@   rU   	msg_linesprinted_instructionsr%   r%   r&   rE      s   	


rE   r2   r3   r4   c                 C  sv   t | tjrdS t| p:| jtjtjfv o| jd t	j
kp:| jtjko*| jd t	jkp:| jtjko:tdd | jD S )zIs this an instruction you might find in the function prologue or epilogue?

    These will be present even when everything else was optimized out.Fr      c                 s  s     | ]}|t jt jfv V  qd S N)r   SPBP)r/   or%   r%   r&   	<genexpr>   s    z*is_prologue_or_epilogue.<locals>.<genexpr>)r5   r	   Labelis_retopcoder   PUSHPOPr7   r   rd   SUBrc   rK   allr8   r%   r%   r&   rJ      s    rJ   c                 C  s&   t | tjp| jtjtjtjtjfv S rb   )	r5   r	   rg   ri   r   JMPJMPCCCALLCMOVr8   r%   r%   r&   is_control_flow   s   rr   c                 C  s   t | tjo| jtjtjfv S rb   )r5   r	   r6   ri   r   RETLEAVEr8   r%   r%   r&   rh      s   rh   c                 C  s   t | tjo| jtjkS rb   )r5   r	   r6   ri   r   rK   r8   r%   r%   r&   is_mov   s   ru   c                 C  s,   t | tjo| jtjko| jd | jd kS )zNIs this an instruction of the form xor %reg, %reg used to zero out a register?r   ra   )r5   r	   r6   ri   r   rM   r7   r8   r%   r%   r&   is_zero_instr   s
   
rv   )r   rV   r>   rW   r?   rX   r@   rY   rU   rI   r   rV   rA   )rS   
__future__r   pathlibr   typingr   r   r    r   parserr	   r
   
parser.asmr   r   CHAPTERTEST_DIRTestChapterr   rE   rJ   rr   rh   ru   rv   r%   r%   r%   r&   <module>   s*     


	
