This commit is contained in:
static
2025-06-16 04:34:26 +00:00
parent e300c93b51
commit 3232e30b46

View File

@@ -21,7 +21,7 @@ impl Translate<ir::TranslationUnit> for Asmgen {
fn translate(&mut self, source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> {
for (name, decl) in &source.decls {
self.translate_decl(name, decl);
self.translate_decl(name, decl, &source.structs);
}
// println!("{:?}", self.functions);
@@ -43,43 +43,31 @@ struct Context {
}
impl Asmgen {
fn translate_decl(&mut self, name: &String, decl: &ir::Declaration) {
fn translate_decl(
&mut self,
name: &String,
decl: &ir::Declaration,
structs: &HashMap<String, Option<ir::Dtype>>,
) {
match decl {
ir::Declaration::Variable { dtype, initializer } => {
if let Some(initializer) = initializer {
let constant = get_constant_from_initializer(initializer);
let value = match constant {
ir::Constant::Int { value, width, .. } => {
if width == 8 {
asm::Directive::Byte(value as u8)
} else if width == 16 {
asm::Directive::Half(value as u16)
} else if width == 32 {
asm::Directive::Word(value as u32)
} else if width == 64 {
asm::Directive::Quad(value as u64)
} else {
unreachable!()
let mut directives = initializer_to_directives(initializer);
if let ir::Dtype::Array { inner, size } = dtype {
if *size != directives.len() {
directives.push(asm::Directive::Zero(
(size - directives.len())
* (get_dtype_size(&inner, structs) as usize),
));
}
}
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!(),
};
self.variables.push(asm::Section::new(
vec![
asm::Directive::Globl(asm::Label(name.clone())),
asm::Directive::Section(asm::SectionType::Data),
asm::Directive::Type(asm::Label(name.clone()), asm::SymbolType::Object),
],
asm::Variable::new(asm::Label(name.clone()), vec![value]),
asm::Variable::new(asm::Label(name.clone()), directives),
));
}
}
@@ -88,12 +76,13 @@ impl Asmgen {
definition,
} => {
if let Some(definition) = definition {
let mut context = self.translate_prologue(signature, definition);
let mut context = self.translate_prologue(signature, definition, structs);
self.translate_block(
name,
definition.bid_init,
&definition.blocks[&definition.bid_init],
&mut context,
structs,
);
let mut blocks = vec![asm::Block::new(
Some(asm::Label(name.clone())),
@@ -106,7 +95,7 @@ impl Asmgen {
}
context.insts = Vec::new();
self.translate_block(name, *bid, block, &mut context);
self.translate_block(name, *bid, block, &mut context, structs);
blocks.push(asm::Block::new(
Some(asm::Label::new(name, *bid)),
context.insts,
@@ -136,6 +125,7 @@ impl Asmgen {
&mut self,
signature: &ir::FunctionSignature,
definition: &ir::FunctionDefinition,
structs: &HashMap<String, Option<ir::Dtype>>,
) -> Context {
let mut stack_allocation = 0;
let mut stack_offsets = HashMap::new();
@@ -143,20 +133,20 @@ impl Asmgen {
for (bid, block) in &definition.blocks {
for (aid, dtype) in block.phinodes.iter().enumerate() {
let _ = stack_offsets.insert(ir::RegisterId::arg(*bid, aid), stack_allocation);
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype));
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype, structs));
}
for (iid, inst) in block.instructions.iter().enumerate() {
let _ = stack_offsets.insert(ir::RegisterId::temp(*bid, iid), stack_allocation);
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(&inst.dtype()));
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(&inst.dtype(), structs));
}
}
for (aid, dtype) in definition.allocations.iter().enumerate() {
let _ = stack_offsets.insert(ir::RegisterId::local(aid), stack_allocation);
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype));
stack_allocation += ceil_to_multiple_of_16(get_dtype_size(dtype, structs));
}
stack_allocation += 16; // s0, ra
stack_allocation += 32; // s0, ra, a0, (padding)
for offset in stack_offsets.values_mut() {
*offset = offset.wrapping_sub(stack_allocation);
@@ -188,17 +178,114 @@ impl Asmgen {
rs2: asm::Register::Ra,
imm: asm::Immediate::Value(!16 + 1),
});
insts.push(asm::Instruction::SType {
instr: asm::SType::SD,
rs1: asm::Register::S0,
rs2: asm::Register::A0,
imm: asm::Immediate::Value(!24 + 1),
});
let mut num_int_args = 0;
let mut num_float_args = 0;
if is_struct(&signature.ret, structs).is_some() {
num_int_args += 1;
}
// TODO: Floating point or optimizations
for (i, dtype) in signature.params.iter().enumerate() {
let stack_offset = stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)];
if is_integer(dtype) {
self.translate_store(
asm::SType::SD,
asm::Register::S0,
asm::Register::arg(asm::RegisterType::Integer, i),
stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)],
asm::Register::arg(asm::RegisterType::Integer, num_int_args),
stack_offset,
&mut insts,
);
num_int_args += 1;
} else if is_float(dtype) {
self.translate_store(
asm::SType::store(dtype.clone()),
asm::Register::S0,
asm::Register::arg(asm::RegisterType::FloatingPoint, num_float_args),
stack_offset,
&mut insts,
);
num_float_args += 1;
}
}
insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd: asm::Register::Sp,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(!16 + 1),
});
insts.push(asm::Instruction::SType {
instr: asm::SType::SD,
rs1: asm::Register::Sp,
rs2: asm::Register::A1,
imm: asm::Immediate::Value(0),
});
insts.push(asm::Instruction::SType {
instr: asm::SType::SD,
rs1: asm::Register::Sp,
rs2: asm::Register::A2,
imm: asm::Immediate::Value(8),
});
for (i, dtype) in signature.params.iter().enumerate() {
let stack_offset = stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)];
if let Some(size) = is_struct(dtype, structs) {
self.translate_addi(
asm::Register::A0,
asm::Register::S0,
stack_offset,
&mut insts,
);
match i {
0 => insts.push(asm::Instruction::IType {
instr: asm::IType::LD,
rd: asm::Register::A1,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(!24 + 1),
}),
1 => insts.push(asm::Instruction::IType {
instr: asm::IType::LD,
rd: asm::Register::A1,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(0),
}),
2 => insts.push(asm::Instruction::IType {
instr: asm::IType::LD,
rd: asm::Register::A1,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(8),
}),
_ => insts.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd: asm::Register::A1,
rs: asm::Register::arg(asm::RegisterType::Integer, i),
})),
}
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
insts.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
}));
num_int_args += 1;
}
}
insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd: asm::Register::Sp,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(16),
});
Context {
insts,
@@ -239,6 +326,7 @@ impl Asmgen {
bid: ir::BlockId,
block: &ir::Block,
context: &mut Context,
structs: &HashMap<String, Option<ir::Dtype>>,
) {
for (iid, inst) in block.instructions.iter().enumerate() {
let rid = ir::RegisterId::temp(bid, iid);
@@ -355,7 +443,7 @@ impl Asmgen {
});
}
ast::BinaryOperator::Less => {
// TODO: FLoating point
if is_integer(&operand_dtype) {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Slt {
is_signed: operand_dtype.is_int_signed(),
@@ -364,9 +452,17 @@ impl Asmgen {
rs1,
rs2: Some(rs2),
});
} else {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::flt(operand_dtype),
rd,
rs1,
rs2: Some(rs2),
});
}
}
ast::BinaryOperator::Greater => {
// TODO: FLoating point
if is_integer(&operand_dtype) {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Slt {
is_signed: operand_dtype.is_int_signed(),
@@ -375,9 +471,17 @@ impl Asmgen {
rs1: rs2,
rs2: Some(rs1),
});
} else {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::flt(operand_dtype),
rd,
rs1: rs2,
rs2: Some(rs1),
});
}
}
ast::BinaryOperator::LessOrEqual => {
// TODO: FLoating point
if is_integer(&operand_dtype) {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Slt {
is_signed: operand_dtype.is_int_signed(),
@@ -386,12 +490,20 @@ impl Asmgen {
rs1: rs2,
rs2: Some(rs1),
});
} else {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::flt(operand_dtype),
rd,
rs1: rs2,
rs2: Some(rs1),
});
}
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
}
ast::BinaryOperator::GreaterOrEqual => {
// TODO: FLoating point
if is_integer(&operand_dtype) {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::Slt {
is_signed: operand_dtype.is_int_signed(),
@@ -400,6 +512,14 @@ impl Asmgen {
rs1,
rs2: Some(rs2),
});
} else {
context.insts.push(asm::Instruction::RType {
instr: asm::RType::flt(operand_dtype),
rd,
rs1,
rs2: Some(rs2),
});
}
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Seqz { rd, rs: rd }))
@@ -491,6 +611,33 @@ impl Asmgen {
dtype: ptr_dtype,
} => match ptr_rid {
ir::RegisterId::Temp { .. } => {
if let Some(size) = is_struct(&value_dtype, structs) {
let rs1 = get_lhs_register(ptr_dtype);
self.translate_load_operand(ptr, rs1, context);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd: asm::Register::A0,
rs: rs1,
}));
self.translate_addi(
asm::Register::A1,
asm::Register::S0,
context.stack_offsets[value.get_register().unwrap().0],
&mut context.insts,
);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context.insts.push(asm::Instruction::Pseudo(
asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
},
));
} else {
let rs1 = get_lhs_register(ptr_dtype);
let rs2 = get_rhs_register(&value_dtype);
self.translate_load_operand(ptr, rs1, context);
@@ -502,7 +649,33 @@ impl Asmgen {
imm: asm::Immediate::Value(0),
});
}
}
ir::RegisterId::Local { aid } => {
if let Some(size) = is_struct(&value_dtype, structs) {
self.translate_addi(
asm::Register::A0,
asm::Register::S0,
context.stack_offsets[ptr_rid],
&mut context.insts,
);
self.translate_addi(
asm::Register::A1,
asm::Register::S0,
context.stack_offsets[value.get_register().unwrap().0],
&mut context.insts,
);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context.insts.push(asm::Instruction::Pseudo(
asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
},
));
} else {
let rs2 = get_rhs_register(&value_dtype);
self.translate_load_operand(value, rs2, context);
self.translate_store(
@@ -513,6 +686,7 @@ impl Asmgen {
&mut context.insts,
);
}
}
_ => todo!(),
},
_ => todo!(),
@@ -540,6 +714,63 @@ impl Asmgen {
dtype: ptr_dtype,
} => {
let value_dtype = ptr_dtype.get_pointer_inner().unwrap().clone();
if let Some(size) = is_struct(&value_dtype, structs) {
match ptr_rid {
ir::RegisterId::Temp { .. } => {
let rs1 = get_rhs_register(ptr_dtype);
self.translate_load_operand(ptr, rs1, context);
self.translate_addi(
asm::Register::A0,
asm::Register::S0,
context.stack_offsets[&rid],
&mut context.insts,
);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd: asm::Register::A1,
rs: rs1,
}));
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context.insts.push(asm::Instruction::Pseudo(
asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
},
));
}
ir::RegisterId::Local { aid } => {
self.translate_addi(
asm::Register::A0,
asm::Register::S0,
context.stack_offsets[&rid],
&mut context.insts,
);
self.translate_addi(
asm::Register::A1,
asm::Register::S0,
context.stack_offsets[ptr_rid],
&mut context.insts,
);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context.insts.push(asm::Instruction::Pseudo(
asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
},
));
}
_ => todo!(),
}
} else {
let rd = get_lhs_register(&value_dtype);
match ptr_rid {
ir::RegisterId::Temp { .. } => {
@@ -567,6 +798,7 @@ impl Asmgen {
_ => todo!(),
}
}
}
_ => todo!(),
},
ir::Instruction::Call {
@@ -574,13 +806,109 @@ impl Asmgen {
args,
return_type,
} => {
let mut num_int_args = 0;
let mut num_float_args = 0;
let mut struct_stack_allocations = 0;
let mut struct_stack_offsets = HashMap::new();
// 구조체 반환을 위한 공간 예약
if let Some(size) = is_struct(return_type, structs) {
num_int_args += 1;
struct_stack_allocations += ceil_to_multiple_of_16(size);
}
for (i, arg) in args.iter().enumerate() {
// TODO: FloatingPoint
if let Some(size) = is_struct(&arg.dtype(), structs) {
let _ = struct_stack_offsets.insert(i, struct_stack_allocations);
struct_stack_allocations += ceil_to_multiple_of_16(size);
}
}
if struct_stack_allocations > 0 {
self.translate_addi(
asm::Register::Sp,
asm::Register::Sp,
!struct_stack_allocations + 1,
&mut context.insts,
);
}
// 구조체 인수 복사
for (i, arg) in args.iter().enumerate() {
if let Some(size) = is_struct(&arg.dtype(), structs) {
self.translate_addi(
asm::Register::A0,
asm::Register::Sp,
struct_stack_offsets[&i],
&mut context.insts,
);
match arg {
ir::Operand::Register { rid, .. } => match rid {
ir::RegisterId::Temp { bid, iid } => {
self.translate_addi(
asm::Register::A1,
asm::Register::S0,
context.stack_offsets[rid],
&mut context.insts,
);
}
_ => todo!(),
},
_ => todo!(),
}
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
}));
}
}
for (i, arg) in args.iter().enumerate() {
let dtype = arg.dtype();
if is_integer(&dtype) {
self.translate_load_operand(
arg,
asm::Register::arg(asm::RegisterType::Integer, i),
asm::Register::arg(asm::RegisterType::Integer, num_int_args),
context,
);
num_int_args += 1;
} else if is_float(&dtype) {
self.translate_load_operand(
arg,
asm::Register::arg(
asm::RegisterType::FloatingPoint,
num_float_args,
),
context,
);
num_float_args += 1;
} else if let Some(size) = is_struct(&dtype, structs) {
self.translate_addi(
asm::Register::arg(asm::RegisterType::Integer, num_int_args),
asm::Register::Sp,
struct_stack_offsets[&i],
&mut context.insts,
);
num_int_args += 1;
} else {
todo!();
}
}
if is_struct(return_type, structs).is_some() {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Mv {
rd: asm::Register::A0,
rs: asm::Register::Sp,
})); // For returned structure
}
match callee {
@@ -616,6 +944,39 @@ impl Asmgen {
asm::Register::FA0,
context,
);
} else if let Some(size) = is_struct(return_type, structs) {
self.translate_addi(
asm::Register::A0,
asm::Register::S0,
context.stack_offsets[&rid],
&mut context.insts,
);
self.translate_addi(
asm::Register::A1,
asm::Register::Sp,
0,
&mut context.insts,
);
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
}));
}
if struct_stack_allocations > 0 {
context.insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd: asm::Register::Sp,
rs1: asm::Register::Sp,
imm: asm::Immediate::Value(struct_stack_allocations),
});
}
}
ir::Instruction::TypeCast {
@@ -672,6 +1033,102 @@ impl Asmgen {
}
}
ir::Instruction::Nop => (),
ir::Instruction::GetElementPtr { ptr, offset, .. } => {
let offset_dtype = offset.dtype();
let rs2 = get_rhs_register(&offset_dtype);
self.translate_load_operand(offset, rs2, context);
match ptr {
ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::La {
rd: asm::Register::T0,
symbol: asm::Label(name.clone()),
}));
let rd = get_lhs_register(&ptr.dtype());
context.insts.push(asm::Instruction::RType {
instr: asm::RType::add(ptr.dtype()),
rd,
rs1: asm::Register::T0,
rs2: Some(rs2),
});
self.translate_store_result(&rid, ptr.dtype(), rd, context);
}
ir::Operand::Register {
rid: ptr_rid,
dtype: ptr_dtype,
} => match ptr_rid {
ir::RegisterId::Temp { .. } => {
let rs1 = get_lhs_register(ptr_dtype);
let rs2 = get_rhs_register(&offset_dtype);
self.translate_load_operand(ptr, rs1, context);
self.translate_load_operand(offset, rs2, context);
context.insts.push(asm::Instruction::RType {
instr: asm::RType::add(ptr_dtype.clone()),
rd: rs1,
rs1,
rs2: Some(rs2),
});
self.translate_store_result(&rid, ptr.dtype(), rs1, context);
}
ir::RegisterId::Local { aid } => {
let rd = get_lhs_register(&ptr.dtype());
let rs2 = get_rhs_register(&offset_dtype);
self.translate_load_operand(offset, rs2, context);
let stack_offset = context.stack_offsets[ptr_rid];
let imm_signed = stack_offset as i64;
if (-2048..=2047).contains(&imm_signed) {
context.insts.push(asm::Instruction::IType {
instr: asm::IType::ADDI,
rd,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(stack_offset),
});
context.insts.push(asm::Instruction::RType {
instr: asm::RType::add(ptr_dtype.clone()),
rd,
rs1: rd,
rs2: Some(rs2),
});
self.translate_store_result(
&rid,
ptr_dtype.clone(),
rd,
context,
);
} else {
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::T3,
imm: stack_offset,
}));
context.insts.push(asm::Instruction::RType {
instr: asm::RType::add(ir::Dtype::int(64)),
rd: asm::Register::T3,
rs1: asm::Register::S0,
rs2: Some(asm::Register::T3),
});
context.insts.push(asm::Instruction::RType {
instr: asm::RType::add(ptr_dtype.clone()),
rd,
rs1: rd,
rs2: Some(rs2),
});
self.translate_store_result(
&rid,
ptr_dtype.clone(),
rd,
context,
);
}
}
_ => todo!(),
},
_ => todo!(),
}
}
_ => todo!(),
}
}
@@ -680,7 +1137,7 @@ impl Asmgen {
ir::BlockExit::Jump { arg } => {
context
.insts
.append(&mut self.translate_phinode(name, arg, context));
.append(&mut self.translate_phinode(name, arg, context, structs));
}
ir::BlockExit::ConditionalJump {
condition,
@@ -690,7 +1147,7 @@ impl Asmgen {
let arg_then_label = if arg_then.args.is_empty() {
asm::Label::new(name, arg_then.bid)
} else {
let phinode_insts = self.translate_phinode(name, arg_then, context);
let phinode_insts = self.translate_phinode(name, arg_then, context, structs);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
@@ -699,7 +1156,7 @@ impl Asmgen {
let arg_else_label = if arg_else.args.is_empty() {
asm::Label::new(name, arg_else.bid)
} else {
let phinode_insts = self.translate_phinode(name, arg_else, context);
let phinode_insts = self.translate_phinode(name, arg_else, context, structs);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
@@ -733,7 +1190,7 @@ impl Asmgen {
let default_label = if default.args.is_empty() {
asm::Label::new(name, default.bid)
} else {
let phinode_insts = self.translate_phinode(name, default, context);
let phinode_insts = self.translate_phinode(name, default, context, structs);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
@@ -750,7 +1207,7 @@ impl Asmgen {
let case_label = if arg.args.is_empty() {
asm::Label::new(name, arg.bid)
} else {
let phinode_insts = self.translate_phinode(name, arg, context);
let phinode_insts = self.translate_phinode(name, arg, context, structs);
let label = asm::Label(format!("{name}_P{}", self.phinode_counter));
self.phinode_counter += 1;
context.new_blocks.push((label.clone(), phinode_insts));
@@ -771,10 +1228,47 @@ impl Asmgen {
}
ir::BlockExit::Return { value } => {
// TODO
if is_integer(&value.dtype()) {
let dtype = value.dtype();
if is_integer(&dtype) {
self.translate_load_operand(value, asm::Register::A0, context);
} else if is_float(&value.dtype()) {
} else if is_float(&dtype) {
self.translate_load_operand(value, asm::Register::FA0, context);
} else if let Some(size) = is_struct(&dtype, structs) {
context.insts.push(asm::Instruction::IType {
instr: asm::IType::load(ir::Dtype::pointer(ir::Dtype::unit())), // TODO: ok?
rd: asm::Register::A0,
rs1: asm::Register::S0,
imm: asm::Immediate::Value(!24 + 1),
});
match value {
ir::Operand::Constant(constant) => match constant {
ir::Constant::Undef { .. } => (), // DO nothing
_ => todo!(),
},
ir::Operand::Register { rid, .. } => match rid {
ir::RegisterId::Temp { bid, iid } => {
self.translate_addi(
asm::Register::A1,
asm::Register::S0,
context.stack_offsets[rid],
&mut context.insts,
);
}
_ => todo!(),
},
_ => todo!(),
}
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Li {
rd: asm::Register::A2,
imm: size,
}));
context
.insts
.push(asm::Instruction::Pseudo(asm::Pseudo::Call {
offset: asm::Label(String::from("memcpy")),
}));
}
self.translate_epilogue(context);
}
@@ -889,13 +1383,15 @@ impl Asmgen {
name: &str,
arg: &ir::JumpArg,
context: &Context,
structs: &HashMap<String, Option<ir::Dtype>>,
) -> Vec<asm::Instruction> {
let mut phinode_stack_offsets = HashMap::new();
let mut phinode_stack_allocations = 0;
for (aid, arg) in arg.args.iter().enumerate() {
let _ = phinode_stack_offsets.insert(aid, phinode_stack_allocations);
phinode_stack_allocations += ceil_to_multiple_of_16(get_dtype_size(&arg.dtype()));
phinode_stack_allocations +=
ceil_to_multiple_of_16(get_dtype_size(&arg.dtype(), structs));
}
let mut phinode_insts = Vec::new();
@@ -1131,14 +1627,9 @@ fn ceil_to_multiple_of_16(x: u64) -> u64 {
(x + 15) & !15
}
fn get_dtype_size(dtype: &ir::Dtype) -> u64 {
((match dtype {
ir::Dtype::Unit { .. } => 0,
ir::Dtype::Int { width, .. } => std::cmp::max(8, *width),
ir::Dtype::Float { width, .. } => *width,
ir::Dtype::Pointer { .. } => 64,
_ => todo!(),
}) / 8) as u64
fn get_dtype_size(dtype: &ir::Dtype, structs: &HashMap<String, Option<ir::Dtype>>) -> u64 {
let (size, _) = dtype.size_align_of(structs).unwrap();
return size as u64;
}
fn upgrade_dtype(dtype: &ir::Dtype) -> ir::Dtype {
@@ -1162,6 +1653,65 @@ fn upgrade_dtype(dtype: &ir::Dtype) -> ir::Dtype {
}
}
fn constant_to_directive(constant: ir::Constant) -> asm::Directive {
match constant {
ir::Constant::Int { value, width, .. } => match width {
8 => asm::Directive::Byte(value as u8),
16 => asm::Directive::Half(value as u16),
32 => asm::Directive::Word(value as u32),
64 => asm::Directive::Quad(value as u64),
_ => unreachable!(),
},
ir::Constant::Float { value, width } => match width {
32 => asm::Directive::Word((*value as f32).to_bits()),
64 => asm::Directive::Quad(value.to_bits()),
_ => unreachable!(),
},
_ => todo!(),
}
}
fn expression_to_constant(expression: &ast::Expression) -> ir::Constant {
match expression {
ast::Expression::Constant(constant) => ir::Constant::try_from(&constant.node).unwrap(),
ast::Expression::UnaryOperator(unary_op) => {
let operand = expression_to_constant(&unary_op.node.operand.node);
match unary_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!(),
}
}
fn initializer_to_directives(initializer: &ast::Initializer) -> Vec<asm::Directive> {
match initializer {
ast::Initializer::Expression(expression) => vec![constant_to_directive(
expression_to_constant(&expression.node),
)],
ast::Initializer::List(list) => list
.iter()
.flat_map(|item| initializer_to_directives(&item.node.initializer.node))
.collect(),
}
}
fn get_constant_from_initializer(initializer: &ast::Initializer) -> ir::Constant {
match initializer {
ast::Initializer::Expression(expression) => match &expression.node {
@@ -1206,3 +1756,12 @@ fn is_integer(dtype: &ir::Dtype) -> bool {
fn is_float(dtype: &ir::Dtype) -> bool {
matches!(dtype, ir::Dtype::Float { .. })
}
fn is_struct(dtype: &ir::Dtype, structs: &HashMap<String, Option<ir::Dtype>>) -> Option<u64> {
if matches!(dtype, ir::Dtype::Struct { .. }) {
let (size, _) = dtype.size_align_of(structs).unwrap();
Some(size as u64)
} else {
None
}
}