from compiler.assembly_generator import Locals, generate_assembly from compiler.ir import IRVar, LoadIntConst, LoadBoolConst, Copy, CondJump, Label, Instruction, Call from compiler.tokenizer import L from typing import List def test_assembly_generator_locals_initialization() -> None: variables = [IRVar('x'), IRVar('y'), IRVar('z')] locals = Locals(variables) assert locals.get_ref(variables[0]) == '-8(%rbp)' assert locals.get_ref(variables[1]) == '-16(%rbp)' assert locals.get_ref(variables[2]) == '-24(%rbp)' assert locals.stack_used() == 24 # 3 variables * 8 bytes # def test_assembly_generator_load_int_const() -> None: # ir_var = IRVar('x') # instructions: List[Instruction] = [ # LoadIntConst(L, 42, ir_var) # ] # asm = generate_assembly(instructions) # assert 'movq $42, -8(%rbp)' in asm # def test_assembly_generator_load_bool_const() -> None: # instructions: List[Instruction] = [ # LoadBoolConst(L, True, IRVar('a')), # LoadBoolConst(L, False, IRVar('b')) # ] # asm = generate_assembly(instructions) # assert 'movq $1, -8(%rbp)' in asm # True # assert 'movq $0, -16(%rbp)' in asm # False # def test_assembly_generator_copy() -> None: # src = IRVar('src') # dest = IRVar('dest') # instructions: List[Instruction] = [ # Copy(L, src, dest) # ] # asm = generate_assembly(instructions) # assert 'movq -8(%rbp), %rax' in asm # assert 'movq %rax, -16(%rbp)' in asm # def test_assembly_generator_cond_jump() -> None: # cond_var = IRVar('cond') # then_label = Label(L, 'Lthen') # else_label = Label(L, 'Lelse') # instructions: List[Instruction] = [ # CondJump(L, cond_var, then_label, else_label) # ] # asm = generate_assembly(instructions) # assert 'cmpq $0, -8(%rbp)' in asm # assert 'jne .LLthen' in asm # assert 'jmp .LLelse' in asm # def test_assembly_generator_function_prologue_epilogue() -> None: # instructions: List[Instruction] = [ # LoadIntConst(L, 0, IRVar('dummy')) # ] # asm = generate_assembly(instructions) # assert 'pushq %rbp' in asm # assert 'movq %rsp, %rbp' in asm # assert 'subq $8, %rsp' in asm # assert 'movq %rbp, %rsp' in asm # assert 'popq %rbp' in asm # assert 'ret' in asm # def test_assembly_generator_intrinsic_plus() -> None: # # IR: Call('+', [x, y], result) # x = IRVar('x') # y = IRVar('y') # result = IRVar('result') # instructions = [ # LoadIntConst(L, 3, x), # LoadIntConst(L, 5, y), # Call(L, IRVar('+'), [x, y], result) # ] # asm = generate_assembly(instructions) # assert 'addq' in asm # assert 'movq' in asm # assert 'callq' not in asm # Intrinsic should not use call # def test_assembly_generator_intrinsic_divide() -> None: # # IR: Call('/', [a, b], result) # a = IRVar('a') # b = IRVar('b') # instructions = [ # LoadIntConst(L, 10, a), # LoadIntConst(L, 2, b), # Call(L, IRVar('/'), [a, b], IRVar('result')) # ] # asm = generate_assembly(instructions) # assert 'idivq' in asm # assert 'cqto' in asm # def test_assembly_generator_function_call_one_arg() -> None: # # IR: Call(print_int, [x], _) # x = IRVar('x') # instructions = [ # LoadIntConst(L, 42, x), # Call(L, IRVar('print_int'), [x], IRVar('unused')) # ] # asm = generate_assembly(instructions) # assert 'movq -8(%rbp), %rdi' in asm # Assuming x is at -8(%rbp) # assert 'callq print_int' in asm # def test_assembly_generator_function_call_six_args() -> None: # # IR: Call(func, [a,b,c,d,e,f], _) # args = [IRVar(f'arg{i}') for i in range(6)] # instructions = [ # *[LoadIntConst(L, i, arg) for i, arg in enumerate(args)], # Call(L, IRVar('func'), args, IRVar('result')) # ] # asm = generate_assembly(instructions) # expected_regs = ['%rdi', '%rsi', '%rdx', '%rcx', '%r8', '%r9'] # for i, reg in enumerate(expected_regs): # assert f'movq -{8*(i+1)}(%rbp), {reg}' in asm # assert 'callq func' in asm # def test_assembly_generator_comparison_intrinsic() -> None: # # IR: Call('==', [x, y], result) # x = IRVar('x') # y = IRVar('y') # instructions = [ # LoadIntConst(L, 5, x), # LoadIntConst(L, 5, y), # Call(L, IRVar('=='), [x, y], IRVar('result')) # ] # asm = generate_assembly(instructions) # assert 'cmpq' in asm # assert 'sete' in asm