use crate::{ir::*, symbols::{SymTab}};
use std::io::{Result, Write};
pub fn write_asm(p: &IrProg ,table: &mut SymTab, w: &mut impl Write) -> Result<()> {
for g in &p.global_vars {
match g {
IrStmt::DeclGlobal(vn, val) => {
writeln!(w, ".data")?;
writeln!(w, ".align 2")?;
writeln!(w, ".global {}", vn)?;
writeln!(w, "{}:", vn)?;
writeln!(w, " .word {}", val)?;
}
IrStmt::DeclGlobalArray(vn, indexes) => {
let mut memory = 4;
indexes.iter().for_each(|e| memory *= e);
writeln!(w, ".text")?;
writeln!(w, " .comm {},{},4", vn,memory)?
}
_ => unreachable!()
}
}
for f in &p.funcs {
let mut alloc_size = 0;
writeln!(w, ".text")?;
writeln!(w, ".align 2")?;
writeln!(w, ".global {}", f.name)?;
writeln!(w, "{}:", f.name)?;
writeln!(w, " addi sp, sp, -56")?;
writeln!(w, " sw s0, 0(sp)")?;
writeln!(w, " sw s1, 4(sp)")?;
writeln!(w, " sw s2, 8(sp)")?;
writeln!(w, " sw s3, 12(sp)")?;
writeln!(w, " sw s4, 16(sp)")?;
writeln!(w, " sw s5, 20(sp)")?;
writeln!(w, " sw s6, 24(sp)")?;
writeln!(w, " sw s7, 28(sp)")?;
writeln!(w, " sw s8, 32(sp)")?;
writeln!(w, " sw s9, 36(sp)")?;
writeln!(w, " sw s10, 40(sp)")?;
writeln!(w, " sw s11, 44(sp)")?;
for s in &f.stmts {
match s {
IrStmt::Neg(t1, t2) => {
writeln!(w, " neg {} , {}", t2,t1)?;
}
IrStmt::Ldc(x, t) => {
writeln!(w, " li {}, {}", t, x)?; }
IrStmt::Ret(t) => {
writeln!(w, " mv a0, {}", t)?;
writeln!(w, " lw s0, 0(sp)")?;
writeln!(w, " lw s1, 4(sp)")?;
writeln!(w, " lw s2, 8(sp)")?;
writeln!(w, " lw s3, 12(sp)")?;
writeln!(w, " lw s4, 16(sp)")?;
writeln!(w, " lw s5, 20(sp)")?;
writeln!(w, " lw s6, 24(sp)")?;
writeln!(w, " lw s7, 28(sp)")?;
writeln!(w, " lw s8, 32(sp)")?;
writeln!(w, " lw s9, 36(sp)")?;
writeln!(w, " lw s10, 40(sp)")?;
writeln!(w, " lw s11, 44(sp)")?;
writeln!(w, " addi sp, sp, {}", alloc_size + 56)?;
writeln!(w, " ret")?;
}
IrStmt::Add(t1, t2, t) => {
writeln!(w, " add {} ,{} ,{}", t, t2, t1)?;
}
IrStmt::Sub(t1, t2, t) => {
writeln!(w, " sub {} ,{} ,{}", t, t2, t1)?;
}
IrStmt::Div(t1, t2, t) => {
writeln!(w, " div {} ,{} ,{}", t, t2, t1)?; }
IrStmt::Mod(t1, t2, t) => {
writeln!(w, " mod {} ,{} ,{}", t, t2, t1)?; }
IrStmt::Mul(t1, t2, t) => {
writeln!(w, " mul {} ,{} ,{}", t, t2, t1)?; }
IrStmt::Or(t1, t2, t)=> {
writeln!(w, " or {} ,{} ,{}", t, t2, t1)?;
writeln!(w, " snez {} ,{}", t, t)?;
}
IrStmt::And(t1, t2, t) => {
writeln!(w, " snez {} ,{}", t, t2)?;
writeln!(w, " sub {} ,zero ,{}", t, t)?;
writeln!(w, " and {} ,{} ,{}", t, t, t1)?;
writeln!(w, " snez {} ,{}", t, t)?;
}
IrStmt::Equal(t1, t2, t, t3) => {
writeln!(w, " sub {} ,{} ,{}", t, t2, t1)?;
writeln!(w, " seqz {} ,{}", t3, t)?;
}
IrStmt::NotEqual(t1, t2, t, t3) => {
writeln!(w, " sub {} ,{} ,{}", t, t2, t1)?;
writeln!(w, " snez {} ,{}", t3, t)?
}
IrStmt::Lt(t1, t2, t) => {
writeln!(w, " slt {} ,{} ,{}", t, t2, t1)?;
}
IrStmt::Let(t1, t2, t, t3, t4, t5) => {
writeln!(w, " sub {} ,{} ,{}", t, t2, t1)?;
writeln!(w, " seqz {} ,{}", t3, t)?;
writeln!(w, " slt {} ,{} ,{}", t4, t2, t1)?;
writeln!(w, " or {} ,{} ,{}", t5, t3, t4)?;
writeln!(w, " snez {} ,{}", t5, t5)?;
}
IrStmt::Gt(t1, t2, t) => { writeln!(w, " sgt {} ,{} ,{}", t, t2, t1)?;
}
IrStmt::Get(t1, t2, t, t3, t4, t5) => { writeln!(w, " sub {} ,{} ,{}", t, t2, t1)?;
writeln!(w, " seqz {} ,{}", t3, t)?;
writeln!(w, " sgt {} ,{} ,{}", t4, t2, t1)?;
writeln!(w, " or {} ,{} ,{}", t5, t3, t4)?;
writeln!(w, " snez {} ,{}", t5, t5)?;
}
IrStmt::Assign(scope, id,t2) => {
let s = table.get(scope, id);
writeln!(w, " mv {} ,{}", s.reg.as_ref().unwrap(), t2)?;
},
IrStmt::Ref(_scope,_id) => {
},
IrStmt::Beq(t,l) => {
writeln!(w, " beqz {} ,{}", t, l)?;
},
IrStmt::Jmp(l) => {
writeln!(w, " j {}", l)?;
},
IrStmt::Label(label) => {
writeln!(w, "{}:", label)?;
},
IrStmt::Param(_, _, _) => {
}, IrStmt::Call(regs, label,r) => {
writeln!(w, " addi sp, sp, -60")?;
writeln!(w, " sw ra, 0(sp)")?;
writeln!(w, " sw t0, 4(sp)")?;
writeln!(w, " sw t1, 8(sp)")?;
writeln!(w, " sw t2, 12(sp)")?;
writeln!(w, " sw t3, 16(sp)")?;
writeln!(w, " sw t4, 20(sp)")?;
writeln!(w, " sw t5, 24(sp)")?;
writeln!(w, " sw t6, 28(sp)")?;
writeln!(w, " sw a0, 32(sp)")?;
writeln!(w, " sw a1, 36(sp)")?;
writeln!(w, " sw a2, 40(sp)")?;
writeln!(w, " sw a3, 44(sp)")?;
writeln!(w, " sw a4, 48(sp)")?;
writeln!(w, " sw a5, 52(sp)")?;
writeln!(w, " sw a6, 56(sp)")?;
writeln!(w, " sw a7, 60(sp)")?;
for pair in regs {
writeln!(w, " mv {} ,{}", pair.1, pair.0)?;
}
writeln!(w, " call {}", label)?;
writeln!(w, " lw ra, 0(sp)")?;
writeln!(w, " lw t0, 4(sp)")?;
writeln!(w, " lw t1, 8(sp)")?;
writeln!(w, " lw t2, 12(sp)")?;
writeln!(w, " lw t3, 16(sp)")?;
writeln!(w, " lw t4, 20(sp)")?;
writeln!(w, " lw t5, 24(sp)")?;
writeln!(w, " lw t6, 28(sp)")?;
writeln!(w, " lw a1, 36(sp)")?;
writeln!(w, " lw a2, 40(sp)")?;
writeln!(w, " lw a3, 44(sp)")?;
writeln!(w, " lw a4, 48(sp)")?;
writeln!(w, " lw a5, 52(sp)")?;
writeln!(w, " lw a6, 56(sp)")?;
writeln!(w, " lw a7, 60(sp)")?;
writeln!(w, " addi sp, sp, 60")?;
writeln!(w, " mv {} ,a0", r)?;
writeln!(w, " lw a0, 32(sp)")?;
},
IrStmt::Load(_,_,reg, base, offset) => {
writeln!(w, " lw {}, {}({})", reg, offset, base)?;
}
IrStmt::LoadSymbol(reg,vn) => {
writeln!(w, " la {}, {}", reg, vn)?;
}
IrStmt::Alloc(_,_,reg, size) => {
alloc_size += size;
writeln!(w, " addi sp, sp, -{}", size)?;
writeln!(w, " addi {}, sp, 0", reg)?;
}
_ => unreachable!()
}
}
}
Ok(())
}