1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::{
    backend::riscv::from_ir::{function::FunctionCompileContext, register_assign::RegisterAssign},
    ir::{
        quantity::Quantity,
        statement::{branch::BranchType, Branch},
    },
};

/// Emit assembly code for a [`Branch`].
pub fn emit_code(branch: &Branch, ctx: &mut FunctionCompileContext) -> String {
    let Branch {
        branch_type,
        operand1,
        operand2,
        success_label,
        failure_label,
    } = branch;
    let mut result = String::new();
    let branch_command = match branch_type {
        BranchType::EQ => "beq",
        BranchType::GE => "bge",
        BranchType::LT => "blt",
        BranchType::NE => "bne",
    };
    let operand1_register = match operand1 {
        Quantity::RegisterName(local) => {
            let logical_register_assign = ctx.local_assign.get(local).unwrap();
            match logical_register_assign {
                RegisterAssign::Register(register) => register.clone(),
                RegisterAssign::StackValue(stack_offset) => {
                    result.push_str(&format!("    lw t0, {stack_offset}(sp)\n"));
                    "t0".to_string()
                }
                RegisterAssign::StackRef(_) => unreachable!(),
                RegisterAssign::MultipleRegisters(_) => unreachable!(),
            }
        }
        Quantity::GlobalVariableName(_) => todo!(),
        Quantity::NumberLiteral(n) => {
            result.push_str(&format!("    li t0, {n}\n"));
            "t0".to_string()
        }
    };
    let operand2_register = match operand2 {
        Quantity::RegisterName(local) => {
            let logical_register_assign = ctx.local_assign.get(local).unwrap();
            match logical_register_assign {
                RegisterAssign::Register(register) => register.clone(),
                RegisterAssign::StackValue(stack_offset) => {
                    result.push_str(&format!("    lw t1, {stack_offset}(sp)\n"));
                    "t1".to_string()
                }
                RegisterAssign::StackRef(_) => unreachable!(),
                RegisterAssign::MultipleRegisters(_) => unreachable!(),
            }
        }
        Quantity::GlobalVariableName(_) => todo!(),
        Quantity::NumberLiteral(n) => {
            result.push_str(&format!("    li t1, {n}\n"));
            "t1".to_string()
        }
    };
    result.push_str(&format!(
        "    {branch_command} {operand1_register}, {operand2_register}, {success_label}\n"
    ));
    result.push_str(&format!("    j {failure_label}\n"));
    result
}