use crate::mir::register::{Register, VirtualReg};
use crate::mir::types::MirType;
pub fn is_f32(ty: &MirType) -> bool {
matches!(ty, MirType::Scalar(crate::mir::types::ScalarType::F32))
}
pub fn is_float(ty: &MirType) -> bool {
matches!(
ty,
MirType::Scalar(crate::mir::types::ScalarType::F32 | crate::mir::types::ScalarType::F64)
)
}
pub fn load_float_operand_to_xmm<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
operand: &crate::mir::Operand,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
xmm: &str,
ty: &MirType,
) -> Result<(), std::io::Error> {
let mov_to_xmm = if is_f32(ty) { "movd" } else { "movq" };
match operand {
crate::mir::Operand::Register(_) => {
load_operand_to_rax(operand, writer, reg_alloc, stack_slots)?;
writeln!(writer, " {} %rax, %{}", mov_to_xmm, xmm)
}
crate::mir::Operand::Immediate(imm) => match imm {
crate::mir::instruction::Immediate::F32(v) => {
let bits = v.to_bits() as i64;
writeln!(writer, " movq ${}, %rax", bits)?;
writeln!(writer, " {} %rax, %{}", mov_to_xmm, xmm)
}
crate::mir::instruction::Immediate::F64(v) => {
let bits = v.to_bits() as i64;
writeln!(writer, " movq ${}, %rax", bits)?;
writeln!(writer, " {} %rax, %{}", mov_to_xmm, xmm)
}
_ => {
load_operand_to_rax(operand, writer, reg_alloc, stack_slots)?;
writeln!(writer, " {} %rax, %{}", mov_to_xmm, xmm)
}
},
}
}
pub fn store_xmm_to_register<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
xmm: &str,
reg: &VirtualReg,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
ty: &MirType,
) -> Result<(), std::io::Error> {
let mov_from_xmm = if is_f32(ty) { "movd" } else { "movq" };
writeln!(writer, " {} %{}, %rax", mov_from_xmm, xmm)?;
store_rax_to_register(reg, writer, reg_alloc, stack_slots)
}
pub fn load_register_to_rax<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
reg: &VirtualReg,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
) -> Result<(), std::io::Error> {
if let Some(phys) = reg_alloc.get_mapping(reg) {
writeln!(writer, " movq %{}, %rax", phys)?;
} else if let Some(offset) = stack_slots.get(reg) {
writeln!(writer, " movq {}(%rbp), %rax", offset)?;
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", reg),
));
}
Ok(())
}
pub fn store_rax_to_register<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
reg: &VirtualReg,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
) -> Result<(), std::io::Error> {
if let Some(phys) = reg_alloc.get_mapping(reg) {
writeln!(writer, " movq %rax, %{}", phys)?;
} else if let Some(offset) = stack_slots.get(reg) {
writeln!(writer, " movq %rax, {}(%rbp)", offset)?;
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", reg),
));
}
Ok(())
}
pub fn load_register_to_register<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
src: &VirtualReg,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
target_reg: &str,
) -> Result<(), std::io::Error> {
if let Some(phys) = reg_alloc.get_mapping(src) {
writeln!(writer, " movq %{}, %{}", phys, target_reg)?;
} else if let Some(offset) = stack_slots.get(src) {
writeln!(writer, " movq {}(%rbp), %{}", offset, target_reg)?;
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Virtual register {:?} has no mapping or stack slot", src),
));
}
Ok(())
}
pub fn load_operand_to_rax<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
operand: &crate::mir::Operand,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
) -> Result<(), std::io::Error> {
match operand {
crate::mir::Operand::Register(reg) => match reg {
Register::Virtual(v) => load_register_to_rax(v, writer, reg_alloc, stack_slots),
Register::Physical(p) => {
writeln!(writer, " movq %{}, %rax", p.name)?;
Ok(())
}
},
crate::mir::Operand::Immediate(imm) => match imm {
crate::mir::instruction::Immediate::I8(v) => {
writeln!(writer, " movq ${}, %rax", *v as i64)
}
crate::mir::instruction::Immediate::I16(v) => {
writeln!(writer, " movq ${}, %rax", *v as i64)
}
crate::mir::instruction::Immediate::I32(v) => {
writeln!(writer, " movq ${}, %rax", *v as i64)
}
crate::mir::instruction::Immediate::I64(v) => writeln!(writer, " movq ${}, %rax", v),
crate::mir::instruction::Immediate::F32(_)
| crate::mir::instruction::Immediate::F64(_) => {
writeln!(
writer,
" # Floating point immediates not yet implemented"
)?;
Ok(())
}
},
}
}
pub fn load_operand_to_register<
W: std::io::Write,
RA: crate::mir_codegen::regalloc::RegisterAllocator<PhysReg = &'static str>,
>(
operand: &crate::mir::Operand,
writer: &mut W,
reg_alloc: &RA,
stack_slots: &std::collections::HashMap<VirtualReg, i32>,
target_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, target_reg)
}
Register::Physical(p) => {
writeln!(writer, " movq %{}, %{}", p.name, target_reg)?;
Ok(())
}
},
crate::mir::Operand::Immediate(imm) => match imm {
crate::mir::instruction::Immediate::I8(v) => {
writeln!(writer, " movq ${}, %{}", *v as i64, target_reg)
}
crate::mir::instruction::Immediate::I16(v) => {
writeln!(writer, " movq ${}, %{}", *v as i64, target_reg)
}
crate::mir::instruction::Immediate::I32(v) => {
writeln!(writer, " movq ${}, %{}", *v as i64, target_reg)
}
crate::mir::instruction::Immediate::I64(v) => {
writeln!(writer, " movq ${}, %{}", v, target_reg)
}
crate::mir::instruction::Immediate::F32(_)
| crate::mir::instruction::Immediate::F64(_) => {
writeln!(
writer,
" # Floating point immediates not yet implemented"
)?;
Ok(())
}
},
}
}