This commit is contained in:
static
2025-06-14 07:33:15 +00:00
parent 9a8c8d4a1c
commit e300c93b51

View File

@@ -1,3 +1,4 @@
use core::f32;
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::ops::Deref; use std::ops::Deref;
@@ -7,23 +8,13 @@ use crate::ir::HasDtype;
use crate::opt::opt_utils; use crate::opt::opt_utils;
use crate::{Translate, asm, ir}; use crate::{Translate, asm, ir};
#[derive(Debug)] #[derive(Debug, Default)]
pub struct Asmgen { pub struct Asmgen {
functions: Vec<asm::Section<asm::Function>>, functions: Vec<asm::Section<asm::Function>>,
variables: Vec<asm::Section<asm::Variable>>, variables: Vec<asm::Section<asm::Variable>>,
phinode_counter: usize, phinode_counter: usize,
} }
impl Default for Asmgen {
fn default() -> Self {
Asmgen {
functions: Vec::new(),
variables: Vec::new(),
phinode_counter: 0,
}
}
}
impl Translate<ir::TranslationUnit> for Asmgen { impl Translate<ir::TranslationUnit> for Asmgen {
type Target = asm::Asm; type Target = asm::Asm;
type Error = (); type Error = ();
@@ -37,8 +28,8 @@ impl Translate<ir::TranslationUnit> for Asmgen {
Ok(asm::Asm { Ok(asm::Asm {
unit: asm::TranslationUnit { unit: asm::TranslationUnit {
functions: std::mem::replace(&mut self.functions, Vec::new()), functions: std::mem::take(&mut self.functions),
variables: std::mem::replace(&mut self.variables, Vec::new()), variables: std::mem::take(&mut self.variables),
}, },
}) })
} }
@@ -71,6 +62,15 @@ impl Asmgen {
unreachable!() unreachable!()
} }
} }
ir::Constant::Float { value, width } => {
if width == 32 {
asm::Directive::Word((*value as f32).to_bits())
} else if width == 64 {
asm::Directive::Quad(value.to_bits())
} else {
unreachable!()
}
}
_ => todo!(), _ => todo!(),
}; };
self.variables.push(asm::Section::new( self.variables.push(asm::Section::new(
@@ -111,8 +111,7 @@ impl Asmgen {
Some(asm::Label::new(name, *bid)), Some(asm::Label::new(name, *bid)),
context.insts, context.insts,
)); ));
for (label, insts) in std::mem::replace(&mut context.new_blocks, Vec::new()) for (label, insts) in std::mem::take(&mut context.new_blocks) {
{
blocks.push(asm::Block::new(Some(label), insts)); blocks.push(asm::Block::new(Some(label), insts));
} }
} }
@@ -160,46 +159,45 @@ impl Asmgen {
stack_allocation += 16; // s0, ra stack_allocation += 16; // s0, ra
for offset in stack_offsets.values_mut() { for offset in stack_offsets.values_mut() {
*offset = stack_allocation - *offset; *offset = offset.wrapping_sub(stack_allocation);
} }
let mut insts = vec![ let mut insts = vec![];
asm::Instruction::IType { self.translate_addi(
instr: asm::IType::ADDI, asm::Register::Sp,
rd: asm::Register::Sp, asm::Register::Sp,
rs1: asm::Register::Sp, !stack_allocation + 1,
imm: asm::Immediate::Value(!stack_allocation + 1), &mut insts,
}, );
asm::Instruction::SType { self.translate_store(
instr: asm::SType::SD, asm::SType::SD,
rs1: asm::Register::Sp, asm::Register::Sp,
rs2: asm::Register::S0, asm::Register::S0,
imm: asm::Immediate::Value(stack_allocation - 8), stack_allocation - 8,
}, &mut insts,
asm::Instruction::IType { );
instr: asm::IType::ADDI, self.translate_addi(
rd: asm::Register::S0, asm::Register::S0,
rs1: asm::Register::Sp, asm::Register::Sp,
imm: asm::Immediate::Value(stack_allocation), stack_allocation,
}, &mut insts,
asm::Instruction::SType { );
instr: asm::SType::SD, insts.push(asm::Instruction::SType {
rs1: asm::Register::S0, instr: asm::SType::SD,
rs2: asm::Register::Ra, rs1: asm::Register::S0,
imm: asm::Immediate::Value(!16 + 1), rs2: asm::Register::Ra,
}, imm: asm::Immediate::Value(!16 + 1),
]; });
// TODO: Floating point or optimizations // TODO: Floating point or optimizations
for (i, dtype) in signature.params.iter().enumerate() { for (i, dtype) in signature.params.iter().enumerate() {
insts.push(asm::Instruction::SType { self.translate_store(
instr: asm::SType::SD, asm::SType::SD,
rs1: asm::Register::S0, asm::Register::S0,
rs2: asm::Register::arg(asm::RegisterType::Integer, i), asm::Register::arg(asm::RegisterType::Integer, i),
imm: asm::Immediate::Value( stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)],
stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)], &mut insts,
), );
});
} }
Context { Context {
@@ -217,18 +215,19 @@ impl Asmgen {
rs1: asm::Register::S0, rs1: asm::Register::S0,
imm: asm::Immediate::Value(!16 + 1), imm: asm::Immediate::Value(!16 + 1),
}); });
context.insts.push(asm::Instruction::IType { self.translate_load(
instr: asm::IType::LD, asm::IType::LD,
rd: asm::Register::S0, asm::Register::S0,
rs1: asm::Register::Sp, asm::Register::Sp,
imm: asm::Immediate::Value(context.stack_allocation - 8), context.stack_allocation - 8,
}); &mut context.insts,
context.insts.push(asm::Instruction::IType { );
instr: asm::IType::ADDI, self.translate_addi(
rd: asm::Register::Sp, asm::Register::Sp,
rs1: asm::Register::Sp, asm::Register::Sp,
imm: asm::Immediate::Value(context.stack_allocation), context.stack_allocation,
}); &mut context.insts,
);
context context
.insts .insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Ret)); .push(asm::Instruction::Pseudo(asm::Pseudo::Ret));
@@ -259,24 +258,83 @@ impl Asmgen {
match op { match op {
ast::BinaryOperator::Multiply => { ast::BinaryOperator::Multiply => {
context.insts.push(asm::Instruction::RType { context.insts.push(asm::Instruction::RType {
instr: asm::RType::mul(operand_dtype), instr: if is_integer(&operand_dtype) {
asm::RType::mul(operand_dtype)
} else {
asm::RType::fmul(operand_dtype)
},
rd,
rs1,
rs2: Some(rs2),
})
}
ast::BinaryOperator::Divide => {
context.insts.push(asm::Instruction::RType {
instr: if is_integer(&operand_dtype) {
let is_signed = operand_dtype.is_int_signed();
asm::RType::div(operand_dtype, is_signed)
} else {
asm::RType::fdiv(operand_dtype)
},
rd,
rs1,
rs2: Some(rs2),
})
}
ast::BinaryOperator::Modulo => {
let is_signed: bool = operand_dtype.is_int_signed();
context.insts.push(asm::Instruction::RType {
instr: asm::RType::rem(operand_dtype, is_signed),
rd, rd,
rs1, rs1,
rs2: Some(rs2), rs2: Some(rs2),
}) })
} }
ast::BinaryOperator::Plus => context.insts.push(asm::Instruction::RType { ast::BinaryOperator::Plus => context.insts.push(asm::Instruction::RType {
instr: asm::RType::add(operand_dtype), instr: if is_integer(&operand_dtype) {
asm::RType::add(operand_dtype)
} else {
asm::RType::fadd(operand_dtype)
},
rd, rd,
rs1, rs1,
rs2: Some(rs2), rs2: Some(rs2),
}), }),
ast::BinaryOperator::Minus => context.insts.push(asm::Instruction::RType { ast::BinaryOperator::Minus => context.insts.push(asm::Instruction::RType {
instr: asm::RType::sub(operand_dtype), instr: if is_integer(&operand_dtype) {
asm::RType::sub(operand_dtype)
} else {
asm::RType::fsub(operand_dtype)
},
rd, rd,
rs1, rs1,
rs2: Some(rs2), rs2: Some(rs2),
}), }),
ast::BinaryOperator::ShiftLeft => {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::sll(operand_dtype),
rd,
rs1,
rs2: Some(rs2),
});
}
ast::BinaryOperator::ShiftRight => {
if operand_dtype.is_int_signed() {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::sra(operand_dtype),
rd,
rs1,
rs2: Some(rs2),
});
} else {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::srl(operand_dtype),
rd,
rs1,
rs2: Some(rs2),
});
}
}
ast::BinaryOperator::Equals => { ast::BinaryOperator::Equals => {
context.insts.push(asm::Instruction::RType { context.insts.push(asm::Instruction::RType {
instr: asm::RType::Xor, instr: asm::RType::Xor,
@@ -288,6 +346,14 @@ impl Asmgen {
.insts .insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd })) .push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
} }
ast::BinaryOperator::NotEquals => {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Xor,
rd,
rs1,
rs2: Some(rs2),
});
}
ast::BinaryOperator::Less => { ast::BinaryOperator::Less => {
// TODO: FLoating point // TODO: FLoating point
context.insts.push(asm::Instruction::RType { context.insts.push(asm::Instruction::RType {
@@ -310,42 +376,151 @@ impl Asmgen {
rs2: Some(rs1), rs2: Some(rs1),
}); });
} }
ast::BinaryOperator::LessOrEqual => {
// TODO: FLoating point
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Slt {
is_signed: operand_dtype.is_int_signed(),
},
rd,
rs1: rs2,
rs2: Some(rs1),
});
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
}
ast::BinaryOperator::GreaterOrEqual => {
// TODO: FLoating point
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Slt {
is_signed: operand_dtype.is_int_signed(),
},
rd,
rs1,
rs2: Some(rs2),
});
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
}
ast::BinaryOperator::BitwiseAnd => {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::And,
rd,
rs1,
rs2: Some(rs2),
})
}
ast::BinaryOperator::BitwiseOr => {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Or,
rd,
rs1,
rs2: Some(rs2),
})
}
ast::BinaryOperator::BitwiseXor => {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Xor,
rd,
rs1,
rs2: Some(rs2),
})
}
_ => {
println!("{:?}", op);
todo!()
}
}
self.translate_store_result(&rid, dtype.clone(), rd, context);
}
ir::Instruction::UnaryOp { op, operand, dtype } => {
let rs1 = get_lhs_register(&operand.dtype());
let rd = get_res_register(dtype);
self.translate_load_operand(operand, rs1, context);
match op {
ast::UnaryOperator::Minus => {
if is_integer(&operand.dtype()) {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::neg(
operand.dtype(),
rd,
rs1,
)));
} else {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::fneg(
operand.dtype(),
rd,
rs1,
)));
}
}
ast::UnaryOperator::Negate => context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rs1 })),
_ => todo!(), _ => todo!(),
} }
self.translate_store_result(&rid, dtype.clone(), rd, context); self.translate_store_result(&rid, dtype.clone(), rd, context);
} }
ir::Instruction::Store { ptr, value } => { ir::Instruction::Store { ptr, value } => {
let (ptr_rid, ptr_dtype) = ptr.get_register().unwrap();
let value_dtype = value.dtype().clone(); let value_dtype = value.dtype().clone();
match ptr_rid { match ptr {
ir::RegisterId::Temp { .. } => { ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => {
let rs1 = get_lhs_register(ptr_dtype); let rd = get_lhs_register(dtype);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::La {
rd: asm::Register::T0,
symbol: asm::Label(name.clone()),
}));
let rs2 = get_rhs_register(&value_dtype); let rs2 = get_rhs_register(&value_dtype);
self.translate_load_operand(ptr, rs1, context);
self.translate_load_operand(value, rs2, context); self.translate_load_operand(value, rs2, context);
context.insts.push(asm::Instruction::SType { context.insts.push(asm::Instruction::SType {
instr: asm::SType::store(value_dtype), instr: asm::SType::store(value_dtype),
rs1, rs1: rd,
rs2, rs2,
imm: asm::Immediate::Value(0), imm: asm::Immediate::Value(0),
}); });
} }
ir::RegisterId::Local { aid } => { ir::Operand::Register {
let rs2 = get_rhs_register(&value_dtype); rid: ptr_rid,
self.translate_load_operand(value, rs2, context); dtype: ptr_dtype,
context.insts.push(asm::Instruction::SType { } => match ptr_rid {
instr: asm::SType::store(value_dtype), ir::RegisterId::Temp { .. } => {
rs1: asm::Register::S0, let rs1 = get_lhs_register(ptr_dtype);
rs2, let rs2 = get_rhs_register(&value_dtype);
imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), self.translate_load_operand(ptr, rs1, context);
}); self.translate_load_operand(value, rs2, context);
} context.insts.push(asm::Instruction::SType {
instr: asm::SType::store(value_dtype),
rs1,
rs2,
imm: asm::Immediate::Value(0),
});
}
ir::RegisterId::Local { aid } => {
let rs2 = get_rhs_register(&value_dtype);
self.translate_load_operand(value, rs2, context);
self.translate_store(
asm::SType::store(value_dtype),
asm::Register::S0,
rs2,
context.stack_offsets[ptr_rid],
&mut context.insts,
);
}
_ => todo!(),
},
_ => todo!(), _ => todo!(),
} }
} }
ir::Instruction::Load { ptr } => match ptr { ir::Instruction::Load { ptr } => match ptr {
ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => { ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => {
let rd = get_lhs_register(&dtype); let rd = get_lhs_register(dtype);
context context
.insts .insts
.push(asm::Instruction::Pseudo(asm::Pseudo::La { .push(asm::Instruction::Pseudo(asm::Pseudo::La {
@@ -380,12 +555,13 @@ impl Asmgen {
} }
ir::RegisterId::Local { aid } => { ir::RegisterId::Local { aid } => {
let rs1 = get_lhs_register(ptr_dtype); let rs1 = get_lhs_register(ptr_dtype);
context.insts.push(asm::Instruction::IType { self.translate_load(
instr: asm::IType::load(value_dtype.clone()), asm::IType::load(value_dtype.clone()),
rd, rd,
rs1: asm::Register::S0, asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), context.stack_offsets[ptr_rid],
}); &mut context.insts,
);
self.translate_store_result(&rid, value_dtype, rd, context); self.translate_store_result(&rid, value_dtype, rd, context);
} }
_ => todo!(), _ => todo!(),
@@ -406,24 +582,41 @@ impl Asmgen {
context, context,
); );
} }
context
.insts match callee {
.push(asm::Instruction::Pseudo(asm::Pseudo::Call { ir::Operand::Constant(callee) => {
offset: asm::Label( context
callee .insts
.get_constant() .push(asm::Instruction::Pseudo(asm::Pseudo::Call {
.unwrap() offset: asm::Label(callee.get_global_variable_name().unwrap()),
.get_global_variable_name() }));
.unwrap(), }
), ir::Operand::Register { rid, .. } => {
})); self.translate_load_operand(callee, asm::Register::T0, context);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Jalr {
rs: asm::Register::T0,
}));
}
}
// TODO // TODO
self.translate_store_result( if is_integer(return_type) {
&rid, self.translate_store_result(
return_type.clone(), &rid,
asm::Register::A0, return_type.clone(),
context, asm::Register::A0,
); context,
);
} else if is_float(return_type) {
self.translate_store_result(
&rid,
return_type.clone(),
asm::Register::FA0,
context,
);
}
} }
ir::Instruction::TypeCast { ir::Instruction::TypeCast {
value, value,
@@ -431,9 +624,54 @@ impl Asmgen {
} => { } => {
let rs1 = get_lhs_register(&value.dtype()); let rs1 = get_lhs_register(&value.dtype());
self.translate_load_operand(value, rs1, context); self.translate_load_operand(value, rs1, context);
// TODO: Int <-> Float ...
self.translate_store_result(&rid, target_dtype.clone(), rs1, context); match (value.dtype(), target_dtype) {
(ir::Dtype::Int { .. }, ir::Dtype::Int { .. }) => {
self.translate_store_result(&rid, target_dtype.clone(), rs1, context)
}
(ir::Dtype::Float { .. }, ir::Dtype::Float { .. }) => {
let rd = get_rhs_register(target_dtype);
context.insts.push(asm::Instruction::RType {
instr: asm::RType::FcvtFloatToFloat {
from: asm::DataSize::try_from(value.dtype()).unwrap(),
to: asm::DataSize::try_from(target_dtype.clone()).unwrap(),
},
rd,
rs1,
rs2: None,
});
self.translate_store_result(&rid, target_dtype.clone(), rd, context);
}
(ir::Dtype::Int { .. }, ir::Dtype::Float { .. }) => {
let rd = get_rhs_register(target_dtype);
context.insts.push(asm::Instruction::RType {
instr: asm::RType::fcvt_int_to_float(
value.dtype(),
target_dtype.clone(),
),
rd,
rs1,
rs2: None,
});
self.translate_store_result(&rid, target_dtype.clone(), rd, context);
}
(ir::Dtype::Float { .. }, ir::Dtype::Int { .. }) => {
let rd = get_rhs_register(target_dtype);
context.insts.push(asm::Instruction::RType {
instr: asm::RType::fcvt_float_to_int(
value.dtype(),
target_dtype.clone(),
),
rd,
rs1,
rs2: None,
});
self.translate_store_result(&rid, target_dtype.clone(), rd, context);
}
_ => todo!(),
}
} }
ir::Instruction::Nop => (),
_ => todo!(), _ => todo!(),
} }
} }
@@ -533,7 +771,11 @@ impl Asmgen {
} }
ir::BlockExit::Return { value } => { ir::BlockExit::Return { value } => {
// TODO // TODO
self.translate_load_operand(value, asm::Register::A0, context); if is_integer(&value.dtype()) {
self.translate_load_operand(value, asm::Register::A0, context);
} else if is_float(&value.dtype()) {
self.translate_load_operand(value, asm::Register::FA0, context);
}
self.translate_epilogue(context); self.translate_epilogue(context);
} }
_ => todo!(), _ => todo!(),
@@ -548,9 +790,9 @@ impl Asmgen {
) { ) {
match operand { match operand {
ir::Operand::Constant(c) => match c { ir::Operand::Constant(c) => match c {
ir::Constant::Undef { dtype } => context ir::Constant::Undef { dtype } => {
.insts // Do nothing
.push(asm::Instruction::Pseudo(asm::Pseudo::Li { rd, imm: 0 })), }
ir::Constant::Int { ir::Constant::Int {
value, value,
width, width,
@@ -561,17 +803,68 @@ impl Asmgen {
rd, rd,
imm: *value as u64, imm: *value as u64,
})), })),
ir::Constant::Float { value, width } => {
if *width == 32 {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::T4,
imm: (**value as f32).to_bits() as u64,
}));
context.insts.push(asm::Instruction::RType {
instr: asm::RType::fmv_int_to_float(ir::Dtype::float(32)),
rd,
rs1: asm::Register::T4,
rs2: None,
});
} else if *width == 64 {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::T4,
imm: value.to_bits(),
}));
context.insts.push(asm::Instruction::RType {
instr: asm::RType::fmv_int_to_float(ir::Dtype::float(64)),
rd,
rs1: asm::Register::T4,
rs2: None,
});
} else {
unreachable!()
}
}
ir::Constant::GlobalVariable { name, dtype } => {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::La {
rd,
symbol: asm::Label(name.clone()),
}));
}
_ => { _ => {
println!("{c}"); println!("{c}");
todo!() todo!()
} }
}, },
ir::Operand::Register { rid, dtype } => context.insts.push(asm::Instruction::IType { ir::Operand::Register { rid, dtype } => {
instr: asm::IType::load(dtype.clone()), if let ir::RegisterId::Local { aid } = rid {
rd, self.translate_addi(
rs1: asm::Register::S0, rd,
imm: asm::Immediate::Value(context.stack_offsets[rid]), asm::Register::S0,
}), context.stack_offsets[rid],
&mut context.insts,
);
} else {
self.translate_load(
asm::IType::load(dtype.clone()),
rd,
asm::Register::S0,
context.stack_offsets[rid],
&mut context.insts,
);
}
}
} }
} }
@@ -582,17 +875,18 @@ impl Asmgen {
rs: asm::Register, rs: asm::Register,
context: &mut Context, context: &mut Context,
) { ) {
context.insts.push(asm::Instruction::SType { self.translate_store(
instr: asm::SType::store(dtype), asm::SType::store(dtype),
rs1: asm::Register::S0, asm::Register::S0,
rs2: rs, rs,
imm: asm::Immediate::Value(context.stack_offsets[rid]), context.stack_offsets[rid],
}) &mut context.insts,
);
} }
fn translate_phinode( fn translate_phinode(
&mut self, &mut self,
name: &String, name: &str,
arg: &ir::JumpArg, arg: &ir::JumpArg,
context: &Context, context: &Context,
) -> Vec<asm::Instruction> { ) -> Vec<asm::Instruction> {
@@ -606,29 +900,31 @@ impl Asmgen {
let mut phinode_insts = Vec::new(); let mut phinode_insts = Vec::new();
if phinode_stack_allocations > 0 { if phinode_stack_allocations > 0 {
phinode_insts.push(asm::Instruction::IType { self.translate_addi(
instr: asm::IType::ADDI, asm::Register::Sp,
rd: asm::Register::Sp, asm::Register::Sp,
rs1: asm::Register::Sp, !phinode_stack_allocations + 1,
imm: asm::Immediate::Value(!phinode_stack_allocations + 1), &mut phinode_insts,
}); );
} }
let bid = arg.bid; let bid = arg.bid;
for (aid, arg) in arg.args.iter().enumerate() { for (aid, arg) in arg.args.iter().enumerate() {
let rs1 = get_lhs_register(&arg.dtype()); let rs1 = get_lhs_register(&arg.dtype());
phinode_insts.push(asm::Instruction::IType { self.translate_load(
instr: asm::IType::load(arg.dtype()), asm::IType::load(arg.dtype()),
rd: rs1, rs1,
rs1: asm::Register::S0, asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[&ir::RegisterId::arg(bid, aid)]), context.stack_offsets[&ir::RegisterId::arg(bid, aid)],
}); &mut phinode_insts,
phinode_insts.push(asm::Instruction::SType { );
instr: asm::SType::store(arg.dtype()), self.translate_store(
rs1: asm::Register::Sp, asm::SType::store(arg.dtype()),
rs2: rs1, asm::Register::Sp,
imm: asm::Immediate::Value(phinode_stack_offsets[&aid]), rs1,
}); phinode_stack_offsets[&aid],
&mut phinode_insts,
);
} }
for (aid, arg) in arg.args.iter().enumerate() { for (aid, arg) in arg.args.iter().enumerate() {
@@ -643,6 +939,7 @@ impl Asmgen {
rd: rs1, rd: rs1,
imm: *value as u64, imm: *value as u64,
})), })),
ir::Constant::Undef { .. } => (), // DO nothing
_ => todo!(), _ => todo!(),
}, },
ir::Operand::Register { rid, .. } => { ir::Operand::Register { rid, .. } => {
@@ -652,45 +949,49 @@ impl Asmgen {
} = rid } = rid
{ {
if *arg_bid == bid { if *arg_bid == bid {
phinode_insts.push(asm::Instruction::IType { self.translate_load(
instr: asm::IType::load(arg.dtype()), asm::IType::load(arg.dtype()),
rd: rs1, rs1,
rs1: asm::Register::Sp, asm::Register::Sp,
imm: asm::Immediate::Value(phinode_stack_offsets[arg_aid]), phinode_stack_offsets[arg_aid],
}); &mut phinode_insts,
);
} else { } else {
phinode_insts.push(asm::Instruction::IType { self.translate_load(
instr: asm::IType::load(arg.dtype()), asm::IType::load(arg.dtype()),
rd: rs1, rs1,
rs1: asm::Register::S0, asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[rid]), context.stack_offsets[rid],
}); &mut phinode_insts,
);
} }
} else { } else {
phinode_insts.push(asm::Instruction::IType { self.translate_load(
instr: asm::IType::load(arg.dtype()), asm::IType::load(arg.dtype()),
rd: rs1, rs1,
rs1: asm::Register::S0, asm::Register::S0,
imm: asm::Immediate::Value(context.stack_offsets[rid]), context.stack_offsets[rid],
}); &mut phinode_insts,
);
} }
} }
} }
phinode_insts.push(asm::Instruction::SType { self.translate_store(
instr: asm::SType::store(arg.dtype()), asm::SType::store(arg.dtype()),
rs1: asm::Register::S0, asm::Register::S0,
rs2: rs1, rs1,
imm: asm::Immediate::Value(context.stack_offsets[&ir::RegisterId::arg(bid, aid)]), context.stack_offsets[&ir::RegisterId::arg(bid, aid)],
}); &mut phinode_insts,
);
} }
if phinode_stack_allocations > 0 { if phinode_stack_allocations > 0 {
phinode_insts.push(asm::Instruction::IType { self.translate_addi(
instr: asm::IType::ADDI, asm::Register::Sp,
rd: asm::Register::Sp, asm::Register::Sp,
rs1: asm::Register::Sp, phinode_stack_allocations,
imm: asm::Immediate::Value(phinode_stack_allocations), &mut phinode_insts,
}); );
} }
phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::J {
@@ -699,6 +1000,107 @@ impl Asmgen {
phinode_insts phinode_insts
} }
fn translate_addi(
&mut self,
rd: asm::Register,
rs1: asm::Register,
imm: u64,
insts: &mut Vec<asm::Instruction>,
) {
let imm_signed = imm as i64;
if (-2048..=2047).contains(&imm_signed) {
insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd,
rs1,
imm: asm::Immediate::Value(imm),
});
} else {
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::T3,
imm,
}));
insts.push(asm::Instruction::RType {
instr: asm::RType::add(ir::Dtype::int(64)),
rd,
rs1,
rs2: Some(asm::Register::T3),
});
}
}
fn translate_store(
&mut self,
instr: asm::SType,
rs1: asm::Register,
rs2: asm::Register,
imm: u64,
insts: &mut Vec<asm::Instruction>,
) {
let imm_signed = imm as i64;
if (-2048..=2047).contains(&imm_signed) {
insts.push(asm::Instruction::SType {
instr,
rs1,
rs2,
imm: asm::Immediate::Value(imm),
});
} else {
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::T3,
imm,
}));
insts.push(asm::Instruction::RType {
instr: asm::RType::add(ir::Dtype::int(64)),
rd: asm::Register::T3,
rs1,
rs2: Some(asm::Register::T3),
});
insts.push(asm::Instruction::SType {
instr,
rs1: asm::Register::T3,
rs2,
imm: asm::Immediate::Value(0),
});
}
}
fn translate_load(
&mut self,
instr: asm::IType,
rd: asm::Register,
rs1: asm::Register,
imm: u64,
insts: &mut Vec<asm::Instruction>,
) {
let imm_signed = imm as i64;
if (-2048..=2047).contains(&imm_signed) {
insts.push(asm::Instruction::IType {
instr,
rd,
rs1,
imm: asm::Immediate::Value(imm),
});
} else {
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::T3,
imm,
}));
insts.push(asm::Instruction::RType {
instr: asm::RType::add(ir::Dtype::int(64)),
rd: asm::Register::T3,
rs1,
rs2: Some(asm::Register::T3),
});
insts.push(asm::Instruction::IType {
instr,
rd,
rs1: asm::Register::T3,
imm: asm::Immediate::Value(0),
});
}
}
} }
fn get_lhs_register(dtype: &ir::Dtype) -> asm::Register { fn get_lhs_register(dtype: &ir::Dtype) -> asm::Register {
@@ -764,8 +1166,43 @@ fn get_constant_from_initializer(initializer: &ast::Initializer) -> ir::Constant
match initializer { match initializer {
ast::Initializer::Expression(expression) => match &expression.node { ast::Initializer::Expression(expression) => match &expression.node {
ast::Expression::Constant(constant) => ir::Constant::try_from(&constant.node).unwrap(), ast::Expression::Constant(constant) => ir::Constant::try_from(&constant.node).unwrap(),
ast::Expression::UnaryOperator(op) => {
let operand = match &op.node.operand.node {
ast::Expression::Constant(constant) => {
ir::Constant::try_from(&constant.node).unwrap()
}
_ => panic!(),
};
match op.node.operator.node {
ast::UnaryOperator::Minus => match operand {
ir::Constant::Int {
value,
width,
is_signed,
} => ir::Constant::Int {
value: !value + 1,
width,
is_signed,
},
ir::Constant::Float { value, width } => ir::Constant::Float {
value: -value,
width,
},
_ => panic!(),
},
_ => panic!(),
}
}
_ => panic!(), _ => panic!(),
}, },
_ => panic!(), _ => panic!(),
} }
} }
fn is_integer(dtype: &ir::Dtype) -> bool {
matches!(dtype, ir::Dtype::Int { .. } | ir::Dtype::Pointer { .. })
}
fn is_float(dtype: &ir::Dtype) -> bool {
matches!(dtype, ir::Dtype::Float { .. })
}