diff --git a/src/asmgen/mod.rs b/src/asmgen/mod.rs index f81b26d..8dc083e 100644 --- a/src/asmgen/mod.rs +++ b/src/asmgen/mod.rs @@ -1,3 +1,4 @@ +use core::f32; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::ops::Deref; @@ -7,23 +8,13 @@ use crate::ir::HasDtype; use crate::opt::opt_utils; use crate::{Translate, asm, ir}; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Asmgen { functions: Vec>, variables: Vec>, phinode_counter: usize, } -impl Default for Asmgen { - fn default() -> Self { - Asmgen { - functions: Vec::new(), - variables: Vec::new(), - phinode_counter: 0, - } - } -} - impl Translate for Asmgen { type Target = asm::Asm; type Error = (); @@ -37,8 +28,8 @@ impl Translate for Asmgen { Ok(asm::Asm { unit: asm::TranslationUnit { - functions: std::mem::replace(&mut self.functions, Vec::new()), - variables: std::mem::replace(&mut self.variables, Vec::new()), + functions: std::mem::take(&mut self.functions), + variables: std::mem::take(&mut self.variables), }, }) } @@ -71,6 +62,15 @@ impl Asmgen { 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!(), }; self.variables.push(asm::Section::new( @@ -111,8 +111,7 @@ impl Asmgen { Some(asm::Label::new(name, *bid)), 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)); } } @@ -160,46 +159,45 @@ impl Asmgen { stack_allocation += 16; // s0, ra for offset in stack_offsets.values_mut() { - *offset = stack_allocation - *offset; + *offset = offset.wrapping_sub(stack_allocation); } - let mut insts = vec![ - asm::Instruction::IType { - instr: asm::IType::ADDI, - rd: asm::Register::Sp, - rs1: asm::Register::Sp, - imm: asm::Immediate::Value(!stack_allocation + 1), - }, - asm::Instruction::SType { - instr: asm::SType::SD, - rs1: asm::Register::Sp, - rs2: asm::Register::S0, - imm: asm::Immediate::Value(stack_allocation - 8), - }, - asm::Instruction::IType { - instr: asm::IType::ADDI, - rd: asm::Register::S0, - rs1: asm::Register::Sp, - imm: asm::Immediate::Value(stack_allocation), - }, - asm::Instruction::SType { - instr: asm::SType::SD, - rs1: asm::Register::S0, - rs2: asm::Register::Ra, - imm: asm::Immediate::Value(!16 + 1), - }, - ]; + let mut insts = vec![]; + self.translate_addi( + asm::Register::Sp, + asm::Register::Sp, + !stack_allocation + 1, + &mut insts, + ); + self.translate_store( + asm::SType::SD, + asm::Register::Sp, + asm::Register::S0, + stack_allocation - 8, + &mut insts, + ); + self.translate_addi( + asm::Register::S0, + asm::Register::Sp, + stack_allocation, + &mut insts, + ); + insts.push(asm::Instruction::SType { + instr: asm::SType::SD, + rs1: asm::Register::S0, + rs2: asm::Register::Ra, + 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)], - ), - }); + 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, + ); } Context { @@ -217,18 +215,19 @@ impl Asmgen { rs1: asm::Register::S0, imm: asm::Immediate::Value(!16 + 1), }); - context.insts.push(asm::Instruction::IType { - instr: asm::IType::LD, - rd: asm::Register::S0, - rs1: asm::Register::Sp, - imm: asm::Immediate::Value(context.stack_allocation - 8), - }); - context.insts.push(asm::Instruction::IType { - instr: asm::IType::ADDI, - rd: asm::Register::Sp, - rs1: asm::Register::Sp, - imm: asm::Immediate::Value(context.stack_allocation), - }); + self.translate_load( + asm::IType::LD, + asm::Register::S0, + asm::Register::Sp, + context.stack_allocation - 8, + &mut context.insts, + ); + self.translate_addi( + asm::Register::Sp, + asm::Register::Sp, + context.stack_allocation, + &mut context.insts, + ); context .insts .push(asm::Instruction::Pseudo(asm::Pseudo::Ret)); @@ -259,24 +258,83 @@ impl Asmgen { match op { ast::BinaryOperator::Multiply => { 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, rs1, rs2: Some(rs2), }) } 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, rs1, rs2: Some(rs2), }), 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, rs1, 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 => { context.insts.push(asm::Instruction::RType { instr: asm::RType::Xor, @@ -288,6 +346,14 @@ impl Asmgen { .insts .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 => { // TODO: FLoating point context.insts.push(asm::Instruction::RType { @@ -310,42 +376,151 @@ impl Asmgen { 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!(), } self.translate_store_result(&rid, dtype.clone(), rd, context); } ir::Instruction::Store { ptr, value } => { - let (ptr_rid, ptr_dtype) = ptr.get_register().unwrap(); let value_dtype = value.dtype().clone(); - match ptr_rid { - ir::RegisterId::Temp { .. } => { - let rs1 = get_lhs_register(ptr_dtype); + 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()), + })); 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, + rs1: rd, rs2, imm: asm::Immediate::Value(0), }); } - ir::RegisterId::Local { aid } => { - let rs2 = get_rhs_register(&value_dtype); - self.translate_load_operand(value, rs2, context); - context.insts.push(asm::Instruction::SType { - instr: asm::SType::store(value_dtype), - rs1: asm::Register::S0, - rs2, - imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), - }); - } + 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(&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, + ); + } + _ => todo!(), + }, _ => todo!(), } } ir::Instruction::Load { ptr } => match ptr { ir::Operand::Constant(ir::Constant::GlobalVariable { name, dtype }) => { - let rd = get_lhs_register(&dtype); + let rd = get_lhs_register(dtype); context .insts .push(asm::Instruction::Pseudo(asm::Pseudo::La { @@ -380,12 +555,13 @@ impl Asmgen { } ir::RegisterId::Local { aid } => { let rs1 = get_lhs_register(ptr_dtype); - context.insts.push(asm::Instruction::IType { - instr: asm::IType::load(value_dtype.clone()), + self.translate_load( + asm::IType::load(value_dtype.clone()), rd, - rs1: asm::Register::S0, - imm: asm::Immediate::Value(context.stack_offsets[ptr_rid]), - }); + asm::Register::S0, + context.stack_offsets[ptr_rid], + &mut context.insts, + ); self.translate_store_result(&rid, value_dtype, rd, context); } _ => todo!(), @@ -406,24 +582,41 @@ impl Asmgen { context, ); } - context - .insts - .push(asm::Instruction::Pseudo(asm::Pseudo::Call { - offset: asm::Label( - callee - .get_constant() - .unwrap() - .get_global_variable_name() - .unwrap(), - ), - })); + + match callee { + ir::Operand::Constant(callee) => { + context + .insts + .push(asm::Instruction::Pseudo(asm::Pseudo::Call { + offset: asm::Label(callee.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 - self.translate_store_result( - &rid, - return_type.clone(), - asm::Register::A0, - context, - ); + if is_integer(return_type) { + self.translate_store_result( + &rid, + return_type.clone(), + 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 { value, @@ -431,9 +624,54 @@ impl Asmgen { } => { let rs1 = get_lhs_register(&value.dtype()); 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!(), } } @@ -533,7 +771,11 @@ impl Asmgen { } ir::BlockExit::Return { value } => { // 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); } _ => todo!(), @@ -548,9 +790,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::Undef { dtype } => { + // Do nothing + } ir::Constant::Int { value, width, @@ -561,17 +803,68 @@ impl Asmgen { rd, 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}"); todo!() } }, - ir::Operand::Register { rid, dtype } => context.insts.push(asm::Instruction::IType { - instr: asm::IType::load(dtype.clone()), - rd, - rs1: asm::Register::S0, - imm: asm::Immediate::Value(context.stack_offsets[rid]), - }), + ir::Operand::Register { rid, dtype } => { + if let ir::RegisterId::Local { aid } = rid { + self.translate_addi( + rd, + 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, context: &mut Context, ) { - context.insts.push(asm::Instruction::SType { - instr: asm::SType::store(dtype), - rs1: asm::Register::S0, - rs2: rs, - imm: asm::Immediate::Value(context.stack_offsets[rid]), - }) + self.translate_store( + asm::SType::store(dtype), + asm::Register::S0, + rs, + context.stack_offsets[rid], + &mut context.insts, + ); } fn translate_phinode( &mut self, - name: &String, + name: &str, arg: &ir::JumpArg, context: &Context, ) -> Vec { @@ -606,29 +900,31 @@ impl Asmgen { 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), - }); + self.translate_addi( + asm::Register::Sp, + asm::Register::Sp, + !phinode_stack_allocations + 1, + &mut phinode_insts, + ); } 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]), - }); + self.translate_load( + asm::IType::load(arg.dtype()), + rs1, + asm::Register::S0, + context.stack_offsets[&ir::RegisterId::arg(bid, aid)], + &mut phinode_insts, + ); + self.translate_store( + asm::SType::store(arg.dtype()), + asm::Register::Sp, + rs1, + phinode_stack_offsets[&aid], + &mut phinode_insts, + ); } for (aid, arg) in arg.args.iter().enumerate() { @@ -643,6 +939,7 @@ impl Asmgen { rd: rs1, imm: *value as u64, })), + ir::Constant::Undef { .. } => (), // DO nothing _ => todo!(), }, ir::Operand::Register { rid, .. } => { @@ -652,45 +949,49 @@ impl Asmgen { } = 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]), - }); + self.translate_load( + asm::IType::load(arg.dtype()), + rs1, + asm::Register::Sp, + phinode_stack_offsets[arg_aid], + &mut phinode_insts, + ); } 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]), - }); + self.translate_load( + asm::IType::load(arg.dtype()), + rs1, + asm::Register::S0, + context.stack_offsets[rid], + &mut phinode_insts, + ); } } 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]), - }); + self.translate_load( + asm::IType::load(arg.dtype()), + rs1, + asm::Register::S0, + context.stack_offsets[rid], + &mut phinode_insts, + ); } } } - 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)]), - }); + self.translate_store( + asm::SType::store(arg.dtype()), + asm::Register::S0, + rs1, + context.stack_offsets[&ir::RegisterId::arg(bid, aid)], + &mut phinode_insts, + ); } 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), - }); + self.translate_addi( + asm::Register::Sp, + asm::Register::Sp, + phinode_stack_allocations, + &mut phinode_insts, + ); } phinode_insts.push(asm::Instruction::Pseudo(asm::Pseudo::J { @@ -699,6 +1000,107 @@ impl Asmgen { phinode_insts } + + fn translate_addi( + &mut self, + rd: asm::Register, + rs1: asm::Register, + imm: u64, + insts: &mut Vec, + ) { + 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, + ) { + 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, + ) { + 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 { @@ -764,8 +1166,43 @@ 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(), + 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!(), } } + +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 { .. }) +}