diff --git a/src/asmgen/mod.rs b/src/asmgen/mod.rs index 3e0d2f6..c2a1ffe 100644 --- a/src/asmgen/mod.rs +++ b/src/asmgen/mod.rs @@ -61,6 +61,25 @@ impl Asmgen { )); } } + 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()), directives), + )); + } else { + let mut directives = Vec::new(); + + match dtype { + ir::Dtype::Array { inner, size } => directives.push(asm::Directive::Zero( + size * (get_dtype_size(inner, structs) as usize), + )), + _ => directives + .push(asm::Directive::Zero(get_dtype_size(dtype, structs) as usize)), + } + self.variables.push(asm::Section::new( vec![ asm::Directive::Globl(asm::Label(name.clone())), @@ -188,15 +207,19 @@ impl Asmgen { let mut num_int_args = 0; let mut num_float_args = 0; - if is_struct(&signature.ret, structs).is_some() { - num_int_args += 1; + if let Some(size) = is_struct(&signature.ret, structs) { + if size > 16 { + num_int_args += 1; + } } + let mut large_struct = HashMap::new(); + 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::SType::store(dtype.clone()), asm::Register::S0, asm::Register::arg(asm::RegisterType::Integer, num_int_args), stack_offset, @@ -212,6 +235,113 @@ impl Asmgen { &mut insts, ); num_float_args += 1; + } else if let Some(size) = is_struct(dtype, structs) { + if size > 16 { + let _ = large_struct.insert(i, num_int_args); + num_int_args += 1; + } else { + let struct_name = dtype.get_struct_name().unwrap().as_ref().unwrap().clone(); + let struct_dtype = structs[&struct_name].clone().unwrap(); + let fields = struct_dtype.get_struct_fields().unwrap().as_ref().unwrap(); + + let mut is_packing = false; + let mut packing_start_offset = 0; + let mut packing_size = 0; + + for field_dtype in fields { + let (offset, _) = struct_dtype + .get_offset_struct_field(field_dtype.name().unwrap(), structs) + .unwrap(); + let field_size = get_dtype_size(&field_dtype, structs); + if is_integer(&field_dtype) { + if !is_packing { + is_packing = true; + packing_start_offset = offset; + packing_size = field_size; + } else { + if offset == packing_start_offset + (packing_size as usize) + && packing_size + field_size <= 8 + { + packing_size += field_size; + } else { + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + stack_offset, + &mut insts, + ); + insts.push(asm::Instruction::SType { + instr: asm::SType::SD, + rs1: asm::Register::T5, + rs2: asm::Register::arg( + asm::RegisterType::Integer, + num_int_args, + ), + imm: asm::Immediate::Value(packing_start_offset as u64), + }); + num_int_args += 1; + packing_start_offset = offset; + packing_size = field_size; + } + } + } else if is_float(&field_dtype) { + if is_packing { + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + stack_offset, + &mut insts, + ); + insts.push(asm::Instruction::SType { + instr: asm::SType::SD, + rs1: asm::Register::T5, + rs2: asm::Register::arg( + asm::RegisterType::Integer, + num_int_args, + ), + imm: asm::Immediate::Value(packing_start_offset as u64), + }); + num_int_args += 1; + is_packing = false; + } + + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + stack_offset, + &mut insts, + ); + insts.push(asm::Instruction::SType { + instr: asm::SType::store(field_dtype.deref().clone()), + rs1: asm::Register::T5, + rs2: asm::Register::arg( + asm::RegisterType::FloatingPoint, + num_float_args, + ), + imm: asm::Immediate::Value(offset as u64), + }); + num_float_args += 1; + } else { + todo!() + } + } + + if is_packing { + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + stack_offset, + &mut insts, + ); + insts.push(asm::Instruction::SType { + instr: asm::SType::SD, + rs1: asm::Register::T5, + rs2: asm::Register::arg(asm::RegisterType::Integer, num_int_args), + imm: asm::Immediate::Value(packing_start_offset as u64), + }); + num_int_args += 1; + } + } } } @@ -237,46 +367,49 @@ impl Asmgen { 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, - ); + if size > 16 { + let reg_index = large_struct[&i]; - 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), - })), + self.translate_addi( + asm::Register::A0, + asm::Register::S0, + stack_offset, + &mut insts, + ); + + match reg_index { + 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, reg_index), + })), + } + + 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")), + })); } - - 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; } } @@ -441,6 +574,9 @@ impl Asmgen { rs1, rs2: Some(rs2), }); + context + .insts + .push(asm::Instruction::Pseudo(asm::Pseudo::Snez { rd, rs: rd })); } ast::BinaryOperator::Less => { if is_integer(&operand_dtype) { @@ -716,7 +852,7 @@ impl Asmgen { 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 { .. } => { + ir::RegisterId::Temp { .. } | ir::RegisterId::Arg { .. } => { let rs1 = get_rhs_register(ptr_dtype); self.translate_load_operand(ptr, rs1, context); self.translate_addi( @@ -773,7 +909,7 @@ impl Asmgen { } else { let rd = get_lhs_register(&value_dtype); match ptr_rid { - ir::RegisterId::Temp { .. } => { + ir::RegisterId::Temp { .. } | ir::RegisterId::Arg { .. } => { let rs1 = get_rhs_register(ptr_dtype); self.translate_load_operand(ptr, rs1, context); context.insts.push(asm::Instruction::IType { @@ -813,14 +949,18 @@ impl Asmgen { // 구조체 반환을 위한 공간 예약 if let Some(size) = is_struct(return_type, structs) { - num_int_args += 1; - struct_stack_allocations += ceil_to_multiple_of_16(size); + if size > 16 { + num_int_args += 1; + struct_stack_allocations += ceil_to_multiple_of_16(size); + } } for (i, arg) in args.iter().enumerate() { 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 size > 16 { + let _ = struct_stack_offsets.insert(i, struct_stack_allocations); + struct_stack_allocations += ceil_to_multiple_of_16(size); + } } } @@ -836,37 +976,39 @@ impl Asmgen { // 구조체 인수 복사 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, - ); - } + if size > 16 { + 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!(), - }, - _ => 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")), + })); } - 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")), - })); } } @@ -890,25 +1032,136 @@ impl Asmgen { ); 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; + if size > 16 { + 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 { + match arg { + ir::Operand::Register { rid, .. } => match rid { + ir::RegisterId::Temp { bid, iid } => { + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + context.stack_offsets[rid], + &mut context.insts, + ); + } + _ => todo!(), + }, + _ => todo!(), + } + + let struct_name = + dtype.get_struct_name().unwrap().as_ref().unwrap().clone(); + let struct_dtype = structs[&struct_name].clone().unwrap(); + let fields = + struct_dtype.get_struct_fields().unwrap().as_ref().unwrap(); + + let mut is_packing = false; + let mut packing_start_offset = 0; + let mut packing_size = 0; + + for field_dtype in fields { + let (offset, _) = struct_dtype + .get_offset_struct_field( + field_dtype.name().unwrap(), + structs, + ) + .unwrap(); + let field_size = get_dtype_size(&field_dtype, structs); + if is_integer(&field_dtype) { + if !is_packing { + is_packing = true; + packing_start_offset = offset; + packing_size = field_size; + } else { + // TODO: 조건 수정 필요 + if offset + == packing_start_offset + (packing_size as usize) + && packing_size + field_size <= 8 + { + packing_size += field_size; + } else { + context.insts.push(asm::Instruction::IType { + instr: asm::IType::LD, + rd: asm::Register::arg( + asm::RegisterType::Integer, + num_int_args, + ), + rs1: asm::Register::T5, + imm: asm::Immediate::Value( + packing_start_offset as u64, + ), + }); + num_int_args += 1; + packing_start_offset = offset; + packing_size = field_size; + } + } + } else if is_float(&field_dtype) { + if is_packing { + context.insts.push(asm::Instruction::IType { + instr: asm::IType::LD, + rd: asm::Register::arg( + asm::RegisterType::Integer, + num_int_args, + ), + rs1: asm::Register::T5, + imm: asm::Immediate::Value( + packing_start_offset as u64, + ), + }); + num_int_args += 1; + is_packing = false; + } + + context.insts.push(asm::Instruction::IType { + instr: asm::IType::load(field_dtype.deref().clone()), + rd: asm::Register::arg( + asm::RegisterType::FloatingPoint, + num_float_args, + ), + rs1: asm::Register::T5, + imm: asm::Immediate::Value(packing_start_offset as u64), + }); + num_float_args += 1; + } else { + todo!() + } + } + + if is_packing { + context.insts.push(asm::Instruction::IType { + instr: asm::IType::LD, + rd: asm::Register::arg( + asm::RegisterType::Integer, + num_int_args, + ), + rs1: asm::Register::T5, + imm: asm::Immediate::Value(packing_start_offset as u64), + }); + 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 + if let Some(size) = is_struct(return_type, structs) { + if size > 16 { + context + .insts + .push(asm::Instruction::Pseudo(asm::Pseudo::Mv { + rd: asm::Register::A0, + rs: asm::Register::Sp, + })); // For returned structure + } } match callee { @@ -945,29 +1198,86 @@ impl Asmgen { 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 size > 16 { + 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")), + })); + } else { + let struct_name = return_type + .get_struct_name() + .unwrap() + .as_ref() + .unwrap() + .clone(); + let struct_dtype = structs[&struct_name].clone().unwrap(); + let fields = + struct_dtype.get_struct_fields().unwrap().as_ref().unwrap(); + let mut num_int_fields = 0; + let mut num_float_fields = 0; + + for field_dtype in fields { + let (offset, _) = struct_dtype + .get_offset_struct_field(field_dtype.name().unwrap(), structs) + .unwrap(); + if is_integer(&field_dtype) { + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + context.stack_offsets[&rid], + &mut context.insts, + ); + context.insts.push(asm::Instruction::SType { + instr: asm::SType::store(field_dtype.deref().clone()), + rs1: asm::Register::T5, + rs2: asm::Register::arg( + asm::RegisterType::Integer, + num_int_fields, + ), + imm: asm::Immediate::Value(0), + }); + num_int_fields += 1; + } else if is_float(&field_dtype) { + self.translate_addi( + asm::Register::T5, + asm::Register::S0, + context.stack_offsets[&rid], + &mut context.insts, + ); + context.insts.push(asm::Instruction::SType { + instr: asm::SType::store(field_dtype.deref().clone()), + rs1: asm::Register::T5, + rs2: asm::Register::arg( + asm::RegisterType::FloatingPoint, + num_float_fields, + ), + imm: asm::Immediate::Value(0), + }); + num_float_fields += 1; + } else { + todo!() + } + } + } } if struct_stack_allocations > 0 { @@ -987,7 +1297,8 @@ impl Asmgen { self.translate_load_operand(value, rs1, context); match (value.dtype(), target_dtype) { - (ir::Dtype::Int { .. }, ir::Dtype::Int { .. }) => { + (ir::Dtype::Int { .. }, ir::Dtype::Int { .. }) + | (ir::Dtype::Int { .. }, ir::Dtype::Pointer { .. }) => { self.translate_store_result(&rid, target_dtype.clone(), rs1, context) } (ir::Dtype::Float { .. }, ir::Dtype::Float { .. }) => { @@ -1234,41 +1545,100 @@ impl Asmgen { } 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 + if size > 16 { + 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!(), - }, - 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, - ); + } + 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 { + 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::T5, + asm::Register::S0, + context.stack_offsets[rid], + &mut context.insts, + ); + } + _ => todo!(), + }, + _ => todo!(), + } + + let struct_name = + dtype.get_struct_name().unwrap().as_ref().unwrap().clone(); + let struct_dtype = structs[&struct_name].clone().unwrap(); + let fields = struct_dtype.get_struct_fields().unwrap().as_ref().unwrap(); + let mut num_int_fields = 0; + let mut num_float_fields = 0; + + for field_dtype in fields { + let (offset, _) = struct_dtype + .get_offset_struct_field(field_dtype.name().unwrap(), structs) + .unwrap(); + if is_integer(&field_dtype) { + context.insts.push(asm::Instruction::IType { + instr: asm::IType::load(field_dtype.deref().clone()), + rd: asm::Register::arg( + asm::RegisterType::Integer, + num_int_fields, + ), + rs1: asm::Register::T5, + imm: asm::Immediate::Value(offset as u64), + }); + num_int_fields += 1; + } else if is_float(&field_dtype) { + context.insts.push(asm::Instruction::IType { + instr: asm::IType::load(field_dtype.deref().clone()), + rd: asm::Register::arg( + asm::RegisterType::FloatingPoint, + num_float_fields, + ), + rs1: asm::Register::T5, + imm: asm::Immediate::Value(offset as u64), + }); + num_float_fields += 1; + } else { + todo!() } - _ => 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); } diff --git a/src/irgen/mod.rs b/src/irgen/mod.rs index 3bd00c6..65a34f6 100644 --- a/src/irgen/mod.rs +++ b/src/irgen/mod.rs @@ -2126,7 +2126,12 @@ impl IrgenFunc<'_> { lhs_dtype } } - _ => todo!("merge_dtype"), + (&ir::Dtype::Pointer { .. }, &ir::Dtype::Int { .. }) => lhs_dtype, + (&ir::Dtype::Int { .. }, &ir::Dtype::Pointer { .. }) => rhs_dtype, + _ => { + println!("{:?} {:?}", lhs_dtype, rhs_dtype); + todo!("merge_dtype") + } } }