From 9a8c8d4a1c92fae012e6cb303dc31c5dc26a1c97 Mon Sep 17 00:00:00 2001 From: static Date: Sat, 14 Jun 2025 05:07:56 +0000 Subject: [PATCH] HW7 (2) --- src/asmgen/mod.rs | 369 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 322 insertions(+), 47 deletions(-) diff --git a/src/asmgen/mod.rs b/src/asmgen/mod.rs index cac3b9a..f81b26d 100644 --- a/src/asmgen/mod.rs +++ b/src/asmgen/mod.rs @@ -11,6 +11,7 @@ use crate::{Translate, asm, ir}; pub struct Asmgen { functions: Vec>, variables: Vec>, + phinode_counter: usize, } impl Default for Asmgen { @@ -18,6 +19,7 @@ impl Default for Asmgen { Asmgen { functions: Vec::new(), variables: Vec::new(), + phinode_counter: 0, } } } @@ -46,18 +48,47 @@ struct Context { insts: Vec, stack_offsets: HashMap, stack_allocation: u64, + new_blocks: Vec<(asm::Label, Vec)>, } impl Asmgen { fn translate_decl(&mut self, name: &String, decl: &ir::Declaration) { match decl { - ir::Declaration::Variable { dtype, initializer } => todo!(), + 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!() + } + } + _ => 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]), + )); + } + } ir::Declaration::Function { signature, definition, } => { if let Some(definition) = definition { - let mut context = self.translate_prologue(definition); + let mut context = self.translate_prologue(signature, definition); self.translate_block( name, definition.bid_init, @@ -80,6 +111,10 @@ impl Asmgen { Some(asm::Label::new(name, *bid)), context.insts, )); + for (label, insts) in std::mem::replace(&mut context.new_blocks, Vec::new()) + { + blocks.push(asm::Block::new(Some(label), insts)); + } } self.functions.push(asm::Section::new( @@ -98,11 +133,19 @@ impl Asmgen { } } - fn translate_prologue(&mut self, definition: &ir::FunctionDefinition) -> Context { + fn translate_prologue( + &mut self, + signature: &ir::FunctionSignature, + definition: &ir::FunctionDefinition, + ) -> Context { let mut stack_allocation = 0; let mut stack_offsets = HashMap::new(); 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)); + } 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())); @@ -116,7 +159,11 @@ impl Asmgen { stack_allocation += 16; // s0, ra - let insts = vec![ + for offset in stack_offsets.values_mut() { + *offset = stack_allocation - *offset; + } + + let mut insts = vec![ asm::Instruction::IType { instr: asm::IType::ADDI, rd: asm::Register::Sp, @@ -142,10 +189,24 @@ impl Asmgen { imm: asm::Immediate::Value(!16 + 1), }, ]; + + // TODO: Floating point or optimizations + for (i, dtype) in signature.params.iter().enumerate() { + insts.push(asm::Instruction::SType { + instr: asm::SType::SD, + rs1: asm::Register::S0, + rs2: asm::Register::arg(asm::RegisterType::Integer, i), + imm: asm::Immediate::Value( + stack_offsets[&ir::RegisterId::arg(definition.bid_init, i)], + ), + }); + } + Context { insts, stack_offsets, stack_allocation, + new_blocks: Vec::new(), } } @@ -274,7 +335,7 @@ impl Asmgen { self.translate_load_operand(value, rs2, context); context.insts.push(asm::Instruction::SType { instr: asm::SType::store(value_dtype), - rs1: asm::Register::Sp, + rs1: asm::Register::S0, rs2, imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), }); @@ -282,34 +343,87 @@ impl Asmgen { _ => todo!(), } } - ir::Instruction::Load { ptr } => { - let (ptr_rid, ptr_dtype) = ptr.get_register().unwrap(); - 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, rs1, context); - } - ir::RegisterId::Local { aid } => { - let rs1 = get_lhs_register(ptr_dtype); - context.insts.push(asm::Instruction::IType { - instr: asm::IType::load(value_dtype.clone()), - rd, - rs1: asm::Register::Sp, - imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), - }); - self.translate_store_result(&rid, value_dtype, rs1, context); - } - _ => todo!(), + ir::Instruction::Load { ptr } => match ptr { + ir::Operand::Constant(ir::Constant::GlobalVariable { name, 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()), + })); + context.insts.push(asm::Instruction::IType { + instr: asm::IType::load(dtype.clone()), + rd, + rs1: asm::Register::T0, + imm: asm::Immediate::Value(0), + }); + self.translate_store_result(&rid, dtype.clone(), rd, context); } + ir::Operand::Register { + rid: ptr_rid, + 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); + } + ir::RegisterId::Local { aid } => { + let rs1 = get_lhs_register(ptr_dtype); + context.insts.push(asm::Instruction::IType { + instr: asm::IType::load(value_dtype.clone()), + rd, + rs1: asm::Register::S0, + imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), + }); + self.translate_store_result(&rid, value_dtype, rd, context); + } + _ => todo!(), + } + } + _ => todo!(), + }, + ir::Instruction::Call { + callee, + args, + return_type, + } => { + for (i, arg) in args.iter().enumerate() { + // TODO: FloatingPoint + self.translate_load_operand( + arg, + asm::Register::arg(asm::RegisterType::Integer, i), + context, + ); + } + context + .insts + .push(asm::Instruction::Pseudo(asm::Pseudo::Call { + offset: asm::Label( + callee + .get_constant() + .unwrap() + .get_global_variable_name() + .unwrap(), + ), + })); + // TODO + self.translate_store_result( + &rid, + return_type.clone(), + asm::Register::A0, + context, + ); } ir::Instruction::TypeCast { value, @@ -326,17 +440,33 @@ impl Asmgen { match &block.exit { ir::BlockExit::Jump { arg } => { - // TODO: Phinode - context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { - offset: asm::Label::new(name, arg.bid), - })); + context + .insts + .append(&mut self.translate_phinode(name, arg, context)); } ir::BlockExit::ConditionalJump { condition, arg_then, arg_else, } => { - // TODO: Phinode + 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 label = asm::Label(format!("{name}_P{}", self.phinode_counter)); + self.phinode_counter += 1; + context.new_blocks.push((label.clone(), phinode_insts)); + label + }; + 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 label = asm::Label(format!("{name}_P{}", self.phinode_counter)); + self.phinode_counter += 1; + context.new_blocks.push((label.clone(), phinode_insts)); + label + }; let rs1 = get_lhs_register(&condition.dtype()); self.translate_load_operand(condition, rs1, context); @@ -351,18 +481,26 @@ impl Asmgen { instr: asm::BType::Bne, rs1, rs2: asm::Register::Zero, - imm: asm::Label::new(name, arg_else.bid), + imm: arg_else_label, }); context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { - offset: asm::Label::new(name, arg_then.bid), - })); + offset: arg_then_label, + })); // TODO: 최적화 가능? } ir::BlockExit::Switch { value, default, cases, } => { - // TODO: Phinode + 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 label = asm::Label(format!("{name}_P{}", self.phinode_counter)); + self.phinode_counter += 1; + context.new_blocks.push((label.clone(), phinode_insts)); + label + }; let rs1 = get_lhs_register(&value.dtype()); let rs2 = get_rhs_register(&value.dtype()); @@ -370,17 +508,28 @@ impl Asmgen { for (case, arg) in cases { self.translate_load_operand(&ir::Operand::constant(case.clone()), rs2, context); + + 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 label = asm::Label(format!("{name}_P{}", self.phinode_counter)); + self.phinode_counter += 1; + context.new_blocks.push((label.clone(), phinode_insts)); + label + }; + context.insts.push(asm::Instruction::BType { instr: asm::BType::Beq, rs1, rs2, - imm: asm::Label::new(name, arg.bid), + imm: case_label, }); } context.insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { - offset: asm::Label::new(name, default.bid), - })); + offset: default_label, + })); // TODO: 최적화 가능? } ir::BlockExit::Return { value } => { // TODO @@ -399,6 +548,9 @@ impl Asmgen { ) { match operand { ir::Operand::Constant(c) => match c { + ir::Constant::Undef { dtype } => context + .insts + .push(asm::Instruction::Pseudo(asm::Pseudo::Li { rd, imm: 0 })), ir::Constant::Int { value, width, @@ -409,12 +561,15 @@ impl Asmgen { rd, imm: *value as u64, })), - _ => todo!(), + _ => { + println!("{c}"); + todo!() + } }, ir::Operand::Register { rid, dtype } => context.insts.push(asm::Instruction::IType { instr: asm::IType::load(dtype.clone()), rd, - rs1: asm::Register::Sp, + rs1: asm::Register::S0, imm: asm::Immediate::Value(context.stack_offsets[rid]), }), } @@ -429,11 +584,121 @@ impl Asmgen { ) { context.insts.push(asm::Instruction::SType { instr: asm::SType::store(dtype), - rs1: asm::Register::Sp, + rs1: asm::Register::S0, rs2: rs, imm: asm::Immediate::Value(context.stack_offsets[rid]), }) } + + fn translate_phinode( + &mut self, + name: &String, + arg: &ir::JumpArg, + context: &Context, + ) -> 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())); + } + + let mut phinode_insts = Vec::new(); + if phinode_stack_allocations > 0 { + phinode_insts.push(asm::Instruction::IType { + instr: asm::IType::ADDI, + rd: asm::Register::Sp, + rs1: asm::Register::Sp, + imm: asm::Immediate::Value(!phinode_stack_allocations + 1), + }); + } + + let bid = arg.bid; + for (aid, arg) in arg.args.iter().enumerate() { + let rs1 = get_lhs_register(&arg.dtype()); + phinode_insts.push(asm::Instruction::IType { + instr: asm::IType::load(arg.dtype()), + rd: rs1, + rs1: asm::Register::S0, + imm: asm::Immediate::Value(context.stack_offsets[&ir::RegisterId::arg(bid, aid)]), + }); + phinode_insts.push(asm::Instruction::SType { + instr: asm::SType::store(arg.dtype()), + rs1: asm::Register::Sp, + rs2: rs1, + imm: asm::Immediate::Value(phinode_stack_offsets[&aid]), + }); + } + + for (aid, arg) in arg.args.iter().enumerate() { + let rs1 = get_lhs_register(&arg.dtype()); + match arg { + ir::Operand::Constant(c) => match c { + ir::Constant::Int { + value, + width, + is_signed, + } => phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::Li { + rd: rs1, + imm: *value as u64, + })), + _ => todo!(), + }, + ir::Operand::Register { rid, .. } => { + if let ir::RegisterId::Arg { + bid: arg_bid, + aid: arg_aid, + } = rid + { + if *arg_bid == bid { + phinode_insts.push(asm::Instruction::IType { + instr: asm::IType::load(arg.dtype()), + rd: rs1, + rs1: asm::Register::Sp, + imm: asm::Immediate::Value(phinode_stack_offsets[arg_aid]), + }); + } else { + phinode_insts.push(asm::Instruction::IType { + instr: asm::IType::load(arg.dtype()), + rd: rs1, + rs1: asm::Register::S0, + imm: asm::Immediate::Value(context.stack_offsets[rid]), + }); + } + } else { + phinode_insts.push(asm::Instruction::IType { + instr: asm::IType::load(arg.dtype()), + rd: rs1, + rs1: asm::Register::S0, + imm: asm::Immediate::Value(context.stack_offsets[rid]), + }); + } + } + } + phinode_insts.push(asm::Instruction::SType { + instr: asm::SType::store(arg.dtype()), + rs1: asm::Register::S0, + rs2: rs1, + imm: asm::Immediate::Value(context.stack_offsets[&ir::RegisterId::arg(bid, aid)]), + }); + } + + if phinode_stack_allocations > 0 { + phinode_insts.push(asm::Instruction::IType { + instr: asm::IType::ADDI, + rd: asm::Register::Sp, + rs1: asm::Register::Sp, + imm: asm::Immediate::Value(phinode_stack_allocations), + }); + } + + phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { + offset: asm::Label::new(name, bid), + })); + + phinode_insts + } } fn get_lhs_register(dtype: &ir::Dtype) -> asm::Register { @@ -494,3 +759,13 @@ fn upgrade_dtype(dtype: &ir::Dtype) -> ir::Dtype { _ => dtype.clone(), } } + +fn get_constant_from_initializer(initializer: &ast::Initializer) -> ir::Constant { + match initializer { + ast::Initializer::Expression(expression) => match &expression.node { + ast::Expression::Constant(constant) => ir::Constant::try_from(&constant.node).unwrap(), + _ => panic!(), + }, + _ => panic!(), + } +}