diff --git a/src/asmgen/mod.rs b/src/asmgen/mod.rs index 8dc083e..cd785d0 100644 --- a/src/asmgen/mod.rs +++ b/src/asmgen/mod.rs @@ -21,7 +21,7 @@ impl Translate for Asmgen { fn translate(&mut self, source: &ir::TranslationUnit) -> Result { 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>, + ) { 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>, ) -> 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,18 +178,115 @@ 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), + }); - // TODO: Floating point or optimizations - for (i, dtype) in signature.params.iter().enumerate() { - 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)], - &mut insts, - ); + let mut num_int_args = 0; + let mut num_float_args = 0; + + if is_struct(&signature.ret, structs).is_some() { + num_int_args += 1; } + 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, 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, stack_offsets, @@ -239,6 +326,7 @@ impl Asmgen { bid: ir::BlockId, block: &ir::Block, context: &mut Context, + structs: &HashMap>, ) { for (iid, inst) in block.instructions.iter().enumerate() { let rid = ir::RegisterId::temp(bid, iid); @@ -355,51 +443,83 @@ impl Asmgen { }); } ast::BinaryOperator::Less => { - // 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), - }); + if is_integer(&operand_dtype) { + context.insts.push(asm::Instruction::RType { + instr: asm::RType::Slt { + is_signed: operand_dtype.is_int_signed(), + }, + rd, + 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 - context.insts.push(asm::Instruction::RType { - instr: asm::RType::Slt { - is_signed: operand_dtype.is_int_signed(), - }, - rd, - rs1: rs2, - rs2: Some(rs1), - }); + if is_integer(&operand_dtype) { + context.insts.push(asm::Instruction::RType { + instr: asm::RType::Slt { + is_signed: operand_dtype.is_int_signed(), + }, + rd, + 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 - context.insts.push(asm::Instruction::RType { - instr: asm::RType::Slt { - is_signed: operand_dtype.is_int_signed(), - }, - rd, - rs1: rs2, - rs2: Some(rs1), - }); + if is_integer(&operand_dtype) { + context.insts.push(asm::Instruction::RType { + instr: asm::RType::Slt { + is_signed: operand_dtype.is_int_signed(), + }, + rd, + 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 - context.insts.push(asm::Instruction::RType { - instr: asm::RType::Slt { - is_signed: operand_dtype.is_int_signed(), - }, - rd, - rs1, - rs2: Some(rs2), - }); + if is_integer(&operand_dtype) { + context.insts.push(asm::Instruction::RType { + instr: asm::RType::Slt { + is_signed: operand_dtype.is_int_signed(), + }, + rd, + 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,27 +611,81 @@ impl Asmgen { dtype: ptr_dtype, } => match ptr_rid { ir::RegisterId::Temp { .. } => { - let rs1 = get_lhs_register(ptr_dtype); - let rs2 = get_rhs_register(&value_dtype); - 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), - }); + 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); + 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, - ); + 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( + asm::SType::store(value_dtype), + asm::Register::S0, + rs2, + context.stack_offsets[ptr_rid], + &mut context.insts, + ); + } } _ => todo!(), }, @@ -540,31 +714,89 @@ impl Asmgen { dtype: ptr_dtype, } => { let value_dtype = ptr_dtype.get_pointer_inner().unwrap().clone(); - let rd = get_lhs_register(&value_dtype); - match ptr_rid { - ir::RegisterId::Temp { .. } => { - let rs1 = get_rhs_register(ptr_dtype); - self.translate_load_operand(ptr, rs1, context); - context.insts.push(asm::Instruction::IType { - instr: asm::IType::load(value_dtype.clone()), - rd, - rs1, - imm: asm::Immediate::Value(0), - }); - self.translate_store_result(&rid, value_dtype, rd, context); + 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!(), } - ir::RegisterId::Local { aid } => { - let rs1 = get_lhs_register(ptr_dtype); - self.translate_load( - asm::IType::load(value_dtype.clone()), - rd, - asm::Register::S0, - context.stack_offsets[ptr_rid], - &mut context.insts, - ); - self.translate_store_result(&rid, value_dtype, rd, context); + } else { + let rd = get_lhs_register(&value_dtype); + match ptr_rid { + ir::RegisterId::Temp { .. } => { + let rs1 = get_rhs_register(ptr_dtype); + self.translate_load_operand(ptr, rs1, context); + context.insts.push(asm::Instruction::IType { + instr: asm::IType::load(value_dtype.clone()), + rd, + rs1, + imm: asm::Immediate::Value(0), + }); + self.translate_store_result(&rid, value_dtype, rd, context); + } + ir::RegisterId::Local { aid } => { + let rs1 = get_lhs_register(ptr_dtype); + self.translate_load( + asm::IType::load(value_dtype.clone()), + rd, + asm::Register::S0, + context.stack_offsets[ptr_rid], + &mut context.insts, + ); + self.translate_store_result(&rid, value_dtype, rd, context); + } + _ => todo!(), } - _ => todo!(), } } _ => todo!(), @@ -574,15 +806,111 @@ 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 - self.translate_load_operand( - arg, - asm::Register::arg(asm::RegisterType::Integer, i), - context, + 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, 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 { ir::Operand::Constant(callee) => { context @@ -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>, ) -> Vec { 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>) -> 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 { + 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>) -> Option { + if matches!(dtype, ir::Dtype::Struct { .. }) { + let (size, _) = dtype.size_align_of(structs).unwrap(); + Some(size as u64) + } else { + None + } +}