use crate::mir::register::{Register, VirtualReg};
use crate::mir_codegen::regalloc::RegisterAllocator;
pub fn load_register_to_register<W: std::io::Write>(
src: &VirtualReg,
writer: &mut W,
reg_alloc: &crate::mir_codegen::riscv::regalloc::RiscVRegAlloc,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
dest_reg: &str,
) -> Result<(), std::io::Error> {
if let Some(phys) = reg_alloc.get_mapping(src) {
writeln!(writer, " mv {}, {}", dest_reg, phys)?;
} else if let Some(offset) = stack_slots.get(src) {
writeln!(writer, " ld {}, {}(fp)", dest_reg, offset)?;
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", src),
));
}
Ok(())
}
pub fn store_register_to_register<W: std::io::Write>(
src_reg: &str,
dst: &VirtualReg,
writer: &mut W,
reg_alloc: &crate::mir_codegen::riscv::regalloc::RiscVRegAlloc,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
) -> Result<(), std::io::Error> {
if let Some(phys) = reg_alloc.get_mapping(dst) {
writeln!(writer, " mv {}, {}", phys, src_reg)?;
} else if let Some(offset) = stack_slots.get(dst) {
writeln!(writer, " sd {}, {}(fp)", src_reg, offset)?;
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", dst),
));
}
Ok(())
}
pub fn load_operand_to_register<W: std::io::Write>(
operand: &crate::mir::Operand,
writer: &mut W,
reg_alloc: &crate::mir_codegen::riscv::regalloc::RiscVRegAlloc,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
dest_reg: &str,
) -> Result<(), std::io::Error> {
match operand {
crate::mir::Operand::Register(reg) => match reg {
Register::Virtual(v) => {
load_register_to_register(v, writer, reg_alloc, stack_slots, dest_reg)
}
Register::Physical(p) => {
writeln!(writer, " mv {}, {}", dest_reg, p.name)?;
Ok(())
}
},
crate::mir::Operand::Immediate(imm) => {
match imm {
crate::mir::instruction::Immediate::I8(v) => {
writeln!(writer, " li {}, {}", dest_reg, *v as i64)?;
}
crate::mir::instruction::Immediate::I16(v) => {
writeln!(writer, " li {}, {}", dest_reg, *v as i64)?;
}
crate::mir::instruction::Immediate::I32(v) => {
writeln!(writer, " li {}, {}", dest_reg, *v as i64)?;
}
crate::mir::instruction::Immediate::I64(v) => {
if *v == 0 {
writeln!(writer, " mv {}, zero", dest_reg)?;
} else {
writeln!(writer, " li {}, {}", dest_reg, v)?;
}
}
crate::mir::instruction::Immediate::F32(_)
| crate::mir::instruction::Immediate::F64(_) => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"RISC-V: Floating-point immediates not yet implemented. Use integer types or load from memory instead.",
));
}
}
Ok(())
}
}
}
#[allow(dead_code)]
pub fn emit_int_binary_op<W: std::io::Write>(
op: &crate::mir::IntBinOp,
writer: &mut W,
) -> Result<(), std::io::Error> {
match op {
crate::mir::IntBinOp::Add => writeln!(writer, " add")?,
crate::mir::IntBinOp::Sub => writeln!(writer, " sub")?,
crate::mir::IntBinOp::Mul => writeln!(writer, " mul")?,
crate::mir::IntBinOp::SDiv => writeln!(writer, " div")?,
crate::mir::IntBinOp::UDiv => writeln!(writer, " divu")?,
crate::mir::IntBinOp::SRem => writeln!(writer, " rem")?,
crate::mir::IntBinOp::URem => writeln!(writer, " remu")?,
crate::mir::IntBinOp::And => writeln!(writer, " and")?,
crate::mir::IntBinOp::Or => writeln!(writer, " or")?,
crate::mir::IntBinOp::Xor => writeln!(writer, " xor")?,
crate::mir::IntBinOp::Shl => writeln!(writer, " sll")?,
crate::mir::IntBinOp::AShr => writeln!(writer, " sra")?,
crate::mir::IntBinOp::LShr => writeln!(writer, " srl")?,
}
Ok(())
}
pub fn load_fp_operand_to_register<W: std::io::Write>(
operand: &crate::mir::Operand,
writer: &mut W,
reg_alloc: &crate::mir_codegen::riscv::regalloc::RiscVRegAlloc,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
dest_fp_reg: &str,
is_f32: bool,
) -> Result<(), std::io::Error> {
match operand {
crate::mir::Operand::Register(reg) => match reg {
Register::Virtual(v) => {
if let Some(offset) = stack_slots.get(v) {
if is_f32 {
writeln!(writer, " flw {}, {}(fp)", dest_fp_reg, offset)?;
} else {
writeln!(writer, " fld {}, {}(fp)", dest_fp_reg, offset)?;
}
} else if let Some(phys) = reg_alloc.get_mapping(v) {
if is_f32 {
writeln!(writer, " fmv.w.x {}, {}", dest_fp_reg, phys)?;
} else {
writeln!(writer, " fmv.d.x {}, {}", dest_fp_reg, phys)?;
}
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", v),
));
}
}
Register::Physical(p) => {
if is_f32 {
writeln!(writer, " fmv.w.x {}, {}", dest_fp_reg, p.name)?;
} else {
writeln!(writer, " fmv.d.x {}, {}", dest_fp_reg, p.name)?;
}
}
},
crate::mir::Operand::Immediate(imm) => {
match imm {
crate::mir::instruction::Immediate::F32(v) => {
let bits = v.to_bits();
writeln!(writer, " li t0, {}", bits)?;
writeln!(writer, " fmv.w.x {}, t0", dest_fp_reg)?;
}
crate::mir::instruction::Immediate::F64(v) => {
let bits = v.to_bits();
writeln!(writer, " li t0, {}", bits)?;
writeln!(writer, " fmv.d.x {}, t0", dest_fp_reg)?;
}
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Expected floating-point immediate for FP operation",
));
}
}
}
}
Ok(())
}
pub fn store_fp_register_to_register<W: std::io::Write>(
src_fp_reg: &str,
dst: &VirtualReg,
writer: &mut W,
reg_alloc: &crate::mir_codegen::riscv::regalloc::RiscVRegAlloc,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
is_f32: bool,
) -> Result<(), std::io::Error> {
if let Some(phys) = reg_alloc.get_mapping(dst) {
if is_f32 {
writeln!(writer, " fmv.x.w {}, {}", phys, src_fp_reg)?;
} else {
writeln!(writer, " fmv.x.d {}, {}", phys, src_fp_reg)?;
}
} else if let Some(offset) = stack_slots.get(dst) {
if is_f32 {
writeln!(writer, " fsw {}, {}(fp)", src_fp_reg, offset)?;
} else {
writeln!(writer, " fsd {}, {}(fp)", src_fp_reg, offset)?;
}
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", dst),
));
}
Ok(())
}
pub fn emit_int_cmp_op<W: std::io::Write>(
op: &crate::mir::IntCmpOp,
writer: &mut W,
) -> Result<(), std::io::Error> {
match op {
crate::mir::IntCmpOp::Eq => {
writeln!(writer, " xor a0, a0, a1")?;
writeln!(writer, " seqz a0, a0")?; }
crate::mir::IntCmpOp::Ne => {
writeln!(writer, " xor a0, a0, a1")?;
writeln!(writer, " snez a0, a0")?; }
crate::mir::IntCmpOp::SLt => writeln!(writer, " slt a0, a0, a1")?,
crate::mir::IntCmpOp::SLe => {
writeln!(writer, " sgt a0, a0, a1")?; writeln!(writer, " xori a0, a0, 1")?; }
crate::mir::IntCmpOp::SGt => writeln!(writer, " sgt a0, a0, a1")?,
crate::mir::IntCmpOp::SGe => {
writeln!(writer, " slt a0, a0, a1")?; writeln!(writer, " xori a0, a0, 1")?; }
crate::mir::IntCmpOp::ULt => writeln!(writer, " sltu a0, a0, a1")?,
crate::mir::IntCmpOp::ULe => {
writeln!(writer, " sgtu a0, a0, a1")?; writeln!(writer, " xori a0, a0, 1")?; }
crate::mir::IntCmpOp::UGt => writeln!(writer, " sgtu a0, a0, a1")?,
crate::mir::IntCmpOp::UGe => {
writeln!(writer, " sltu a0, a0, a1")?; writeln!(writer, " xori a0, a0, 1")?; }
}
Ok(())
}