From ebcebdff0d93b23015cfde1960cdc21e5519ecc4 Mon Sep 17 00:00:00 2001 From: static Date: Tue, 8 Apr 2025 15:23:34 +0000 Subject: [PATCH] HW2 (6) --- src/irgen/mod.rs | 874 ++++++++++++++++++++--------------------------- 1 file changed, 370 insertions(+), 504 deletions(-) diff --git a/src/irgen/mod.rs b/src/irgen/mod.rs index 564591e..3bd00c6 100644 --- a/src/irgen/mod.rs +++ b/src/irgen/mod.rs @@ -591,12 +591,6 @@ impl IrgenFunc<'_> { bid_break: Option, ) -> Result<(), IrgenError> { match stmt { - Statement::Labeled(stmt) => Err(IrgenError::new( - stmt.node.label.write_string(), - IrgenErrorMessage::Misc { - message: "label statement not within a switch".to_string(), - }, - )), Statement::Compound(items) => { self.enter_scope(); @@ -887,7 +881,7 @@ impl IrgenFunc<'_> { ); Ok(()) } - _ => todo!("e"), + _ => todo!("translate_stmt"), } } @@ -1004,43 +998,35 @@ impl IrgenFunc<'_> { context: &mut Context, ) -> Result { match expr { - Expression::Identifier(identifier) => { - let ptr = self.lookup_symbol_table(&identifier.node.name)?; - let ptr_dtype = ptr.dtype(); - let ptr_inner = ptr_dtype.get_pointer_inner().unwrap(); - if ptr_inner.get_function_inner().is_some() { - Ok(ptr) - } else if let Some(array_inner) = ptr_inner.get_array_inner() { - self.convert_array_to_pointer(ptr, array_inner, context) - } else { - context.insert_instruction(ir::Instruction::Load { ptr }) - } - } + Expression::Identifier(identifier) => self.translate_lvalue_to_rvalue( + self.lookup_symbol_table(&identifier.node.name)?, + context, + ), Expression::Constant(constant) => Ok(ir::Operand::constant( ir::Constant::try_from(&constant.node).unwrap(), )), - Expression::Cast(cast) => { - let target_dtype = ir::Dtype::try_from(&cast.node.type_name.node) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - let target_dtype = target_dtype - .resolve_typedefs(self.typedefs) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - let operand = self.translate_expr_rvalue(&cast.node.expression.node, context)?; - self.translate_typecast(operand, target_dtype, context) + Expression::Member(member) => { + let lvalue = self.translate_member_op( + &member.node.operator.node, + &member.node.expression.node, + &member.node.identifier.node, + context, + )?; + self.translate_lvalue_to_rvalue(lvalue, context) } Expression::Call(call) => self.translate_func_call(&call.node, context), - Expression::BinaryOperator(binary) => self.translate_binary_op( - &binary.node.operator.node, - &binary.node.lhs.node, - &binary.node.rhs.node, - context, - ), - Expression::UnaryOperator(unary) => self.translate_unary_op( - &unary.node.operator.node, - &unary.node.operand.node, - context, - ), - Expression::Conditional(cond) => self.translate_conditional(&cond.node, context), + Expression::SizeOfTy(sizeof) => { + let dtype = ir::Dtype::try_from(&sizeof.node.0.node) + .and_then(|dtype| dtype.resolve_typedefs(self.typedefs)) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + let (size, _) = dtype + .size_align_of(self.structs) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + Ok(ir::Operand::constant(ir::Constant::int( + size.try_into().unwrap(), + ir::Dtype::LONGLONG.set_signed(false), + ))) + } Expression::SizeOfVal(sizeof) => { let dtype = self.dtypeof_expr(&sizeof.node.0.node); let (size, _) = dtype @@ -1048,28 +1034,12 @@ impl IrgenFunc<'_> { .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; Ok(ir::Operand::constant(ir::Constant::int( size.try_into().unwrap(), - ir::Dtype::LONGLONG.clone().set_signed(false), - ))) - } - Expression::SizeOfTy(sizeof) => { - let dtype = ir::Dtype::try_from(&sizeof.node.0.node) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - let dtype = dtype - .resolve_typedefs(self.typedefs) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - let (size, _) = dtype - .size_align_of(self.structs) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - Ok(ir::Operand::constant(ir::Constant::int( - size.try_into().unwrap(), - ir::Dtype::LONGLONG.clone().set_signed(false), + ir::Dtype::LONGLONG.set_signed(false), ))) } Expression::AlignOf(alignof) => { let dtype = ir::Dtype::try_from(&alignof.node.0.node) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - let dtype = dtype - .resolve_typedefs(self.typedefs) + .and_then(|dtype| dtype.resolve_typedefs(self.typedefs)) .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; let (_, align) = dtype .size_align_of(self.structs) @@ -1079,166 +1049,197 @@ impl IrgenFunc<'_> { ir::Dtype::LONGLONG.clone().set_signed(false), ))) } - Expression::Comma(exprs) => self.translate_comma(exprs.deref(), context), - Expression::Member(member) => { - let member = &member.node; - let ptr = self.translate_member_op( - &member.operator.node, - &member.expression.node, - &member.identifier.node, - context, - )?; - if let Some(inner) = ptr.dtype().get_pointer_inner().unwrap().get_array_inner() { - context.insert_instruction(ir::Instruction::GetElementPtr { - ptr, - offset: ir::Operand::constant(ir::Constant::int(0, ir::Dtype::int(32))), - dtype: ir::Dtype::pointer(inner.clone()), - }) - } else { - context.insert_instruction(ir::Instruction::Load { ptr }) - } + Expression::UnaryOperator(unary) => self.translate_unary_op( + &unary.node.operator.node, + &unary.node.operand.node, + context, + ), + Expression::Cast(cast) => { + let target_dtype = ir::Dtype::try_from(&cast.node.type_name.node) + .and_then(|dtype| dtype.resolve_typedefs(self.typedefs)) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + let operand = self.translate_expr_rvalue(&cast.node.expression.node, context)?; + self.translate_typecast(operand, target_dtype, context) } - _ => todo!("c"), + Expression::BinaryOperator(binary) => self.translate_binary_op( + &binary.node.operator.node, + &binary.node.lhs.node, + &binary.node.rhs.node, + context, + ), + Expression::Conditional(cond) => self.translate_conditional(&cond.node, context), + Expression::Comma(exprs) => { + let operands = exprs + .iter() + .map(|e| self.translate_expr_rvalue(&e.node, context)) + .collect::, _>>()?; + Ok(operands.last().unwrap().clone()) + } + _ => todo!("translate_expr_rvalue"), } } - fn translate_comma( + fn translate_lvalue_to_rvalue( &mut self, - exprs: &[Node], + lvalue: ir::Operand, context: &mut Context, ) -> Result { - let operands = exprs - .iter() - .map(|e| self.translate_expr_rvalue(&e.node, context)) - .collect::, _>>()?; - Ok(operands.last().unwrap().clone()) - } - - fn translate_conditional( - &mut self, - cond: &ConditionalExpression, - context: &mut Context, - ) -> Result { - let then_bid = self.alloc_bid(); - let else_bid = self.alloc_bid(); - let end_bid = self.alloc_bid(); - - self.translate_condition( - &cond.condition.node, - mem::replace(context, Context::new(end_bid)), - then_bid, - else_bid, - )?; - - let mut then_context = Context::new(then_bid); - let then_val = self.translate_expr_rvalue(&cond.then_expression.node, &mut then_context)?; - - let mut else_context = Context::new(else_bid); - let else_val = self.translate_expr_rvalue(&cond.else_expression.node, &mut else_context)?; - - // println!("conditional: {} {}", cond.then_expression.write_string(), cond.else_expression.write_string()); - let merged_dtype = self.merge_dtype(then_val.dtype(), else_val.dtype()); - let then_val = - self.translate_typecast(then_val, merged_dtype.clone(), &mut then_context)?; - let else_val = - self.translate_typecast(else_val, merged_dtype.clone(), &mut else_context)?; - - let var = self.alloc_tempid(); - let ptr = self.translate_alloc(var, &merged_dtype.clone(), context)?; - - let _unused = then_context.insert_instruction(ir::Instruction::Store { - ptr: ptr.clone(), - value: then_val, - })?; - self.insert_block( - then_context, - ir::BlockExit::Jump { - arg: ir::JumpArg::new(end_bid, Vec::new()), - }, - ); - - let _unused = else_context.insert_instruction(ir::Instruction::Store { - ptr: ptr.clone(), - value: else_val, - })?; - self.insert_block( - else_context, - ir::BlockExit::Jump { - arg: ir::JumpArg::new(end_bid, Vec::new()), - }, - ); - - let r = context.insert_instruction(ir::Instruction::Load { ptr: ptr.clone() })?; - // println!("ptr: {}, rtype: {}", ptr.dtype(), r.dtype()); - Ok(r) - } - - fn merge_dtype(&self, lhs_dtype: ir::Dtype, rhs_dtype: ir::Dtype) -> ir::Dtype { - if lhs_dtype == rhs_dtype { - lhs_dtype + let dtype = lvalue.dtype().get_pointer_inner().unwrap().clone(); + if dtype.get_function_inner().is_some() { + Ok(lvalue) + } else if let Some(inner) = dtype.get_array_inner().cloned() { + context.insert_instruction(ir::Instruction::GetElementPtr { + ptr: lvalue, + offset: ir::Operand::constant(ir::Constant::int(0, ir::Dtype::int(32))), + dtype: ir::Dtype::pointer(inner.clone()), + }) } else { - match (&lhs_dtype, &rhs_dtype) { - (&ir::Dtype::DOUBLE, _) => lhs_dtype, - (_, &ir::Dtype::DOUBLE) => rhs_dtype, - (&ir::Dtype::FLOAT, _) => lhs_dtype, - (_, &ir::Dtype::FLOAT) => rhs_dtype, - ( - ir::Dtype::Int { - width: lhs_width, - is_signed: lhs_is_signed, - is_const: lhs_is_const, - }, - ir::Dtype::Int { - width: rhs_width, - is_signed: rhs_is_signed, - is_const: rhs_is_const, - }, - ) => { - if lhs_is_signed == rhs_is_signed { - if lhs_width > rhs_width { - lhs_dtype - } else { - rhs_dtype - } - } else if !lhs_is_signed { - if lhs_width >= rhs_width { - lhs_dtype - } else { - rhs_dtype - } - } else if lhs_width <= rhs_width { - rhs_dtype - } else { - lhs_dtype - } - } - _ => { - println!("merge failed: {} {}", lhs_dtype, rhs_dtype); - todo!("merge") - } - } + context.insert_instruction(ir::Instruction::Load { ptr: lvalue }) } } - fn integer_promotion(&self, dtype: ir::Dtype) -> ir::Dtype { - match &dtype { - ir::Dtype::Int { - width, - is_signed, - is_const, - } => { - if *width < 32 { - ir::Dtype::Int { - width: 32, - is_signed: true, - is_const: *is_const, - } - } else { - dtype - } + fn lookup_symbol_table(&self, name: &String) -> Result { + for layer in self.symbol_table.iter().rev() { + if let Some(ptr) = layer.get(name) { + return Ok(ptr.clone()); } - _ => dtype, } + Err(IrgenErrorMessage::RequireLvalue { + message: format!("Undefined symbol {name}"), + }) + } + + fn translate_member_op( + &mut self, + op: &MemberOperator, + expr: &Expression, + id: &Identifier, + context: &mut Context, + ) -> Result { + let ptr = match op { + MemberOperator::Direct => self.translate_expr_lvalue(expr, context)?, + MemberOperator::Indirect => self.translate_expr_rvalue(expr, context)?, + }; + let struct_dtype = ptr.dtype().get_pointer_inner().unwrap().clone(); + let (field_offset, field_dtype) = struct_dtype + .get_offset_struct_field(&id.name, self.structs) + .expect("no field"); + context.insert_instruction(ir::Instruction::GetElementPtr { + ptr, + offset: ir::Operand::constant(ir::Constant::int( + field_offset.try_into().unwrap(), + ir::Dtype::int(32), + )), + dtype: ir::Dtype::pointer(field_dtype), + }) + } + + fn translate_unary_op( + &mut self, + op: &UnaryOperator, + operand: &Expression, + context: &mut Context, + ) -> Result { + match op { + UnaryOperator::PostIncrement => { + let (old, _) = self.translate_addition(operand, BinaryOperator::Plus, context)?; + Ok(old) + } + UnaryOperator::PostDecrement => { + let (old, _) = self.translate_addition(operand, BinaryOperator::Minus, context)?; + Ok(old) + } + UnaryOperator::PreIncrement => { + let (_, new) = self.translate_addition(operand, BinaryOperator::Plus, context)?; + Ok(new) + } + UnaryOperator::PreDecrement => { + let (_, new) = self.translate_addition(operand, BinaryOperator::Minus, context)?; + Ok(new) + } + UnaryOperator::Address => self.translate_expr_lvalue(operand, context), + UnaryOperator::Indirection => { + let operand = self.translate_expr_rvalue(operand, context)?; + context.insert_instruction(ir::Instruction::Load { ptr: operand }) + } + UnaryOperator::Plus | UnaryOperator::Minus => { + let operand = self.translate_expr_rvalue(operand, context)?; + let (operand, dtype) = self.translate_integer_promotion(operand, context)?; + context.insert_instruction(ir::Instruction::UnaryOp { + op: op.clone(), + operand, + dtype, + }) + } + UnaryOperator::Complement => { + let operand = self.translate_expr_rvalue(operand, context)?; + let (operand, dtype) = self.translate_integer_promotion(operand, context)?; + context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::BitwiseXor, + lhs: operand, + rhs: ir::Operand::constant(ir::Constant::int(u128::MAX, dtype.clone())), + dtype, + }) + } + UnaryOperator::Negate => { + let operand = self.translate_expr_rvalue(operand, context)?; + let (operand, dtype) = self.translate_integer_promotion(operand, context)?; + context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::Equals, + lhs: operand, + rhs: self.constant_zero(dtype), + dtype: ir::Dtype::BOOL, + }) + } + _ => todo!("translate_unary_op"), + } + } + + fn translate_addition( + &mut self, + operand: &Expression, + op: BinaryOperator, + context: &mut Context, + ) -> Result<(ir::Operand, ir::Operand), IrgenErrorMessage> { + let operand_rvalue = self.translate_expr_rvalue(operand, context)?; + let dtype = operand_rvalue.dtype(); + let new_operand_rvalue = if let Some(inner) = dtype.get_pointer_inner() { + let (size, _) = ir::Dtype::size_align_of(inner, self.structs) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + context.insert_instruction(ir::Instruction::GetElementPtr { + ptr: operand_rvalue.clone(), + offset: ir::Operand::constant(ir::Constant::int( + size.try_into().unwrap(), + ir::Dtype::int(32), + )), + dtype: dtype.clone(), + })? + } else { + context.insert_instruction(ir::Instruction::BinOp { + op, + lhs: operand_rvalue.clone(), + rhs: ir::Operand::constant(ir::Constant::int(1, dtype.clone())), + dtype: dtype.clone(), + })? + }; + let operand_lvalue = self.translate_expr_lvalue(operand, context)?; + let _unused = context.insert_instruction(ir::Instruction::Store { + ptr: operand_lvalue, + value: new_operand_rvalue.clone(), + })?; + Ok((operand_rvalue, new_operand_rvalue)) + } + + fn translate_integer_promotion( + &mut self, + operand: ir::Operand, + context: &mut Context, + ) -> Result<(ir::Operand, ir::Dtype), IrgenErrorMessage> { + let dtype = self.integer_promotion(operand.dtype()); + Ok(( + self.translate_typecast(operand, dtype.clone(), context)?, + dtype, + )) } fn translate_binary_op( @@ -1249,6 +1250,10 @@ impl IrgenFunc<'_> { context: &mut Context, ) -> Result { match op { + BinaryOperator::Index => { + let lvalue = self.translate_index_op(lhs, rhs, context)?; + self.translate_lvalue_to_rvalue(lvalue, context) + } BinaryOperator::Assign => self.translate_assign(lhs, rhs, None, context), BinaryOperator::AssignMultiply => { self.translate_assign(lhs, rhs, Some(BinaryOperator::Multiply), context) @@ -1428,18 +1433,6 @@ impl IrgenFunc<'_> { context.insert_instruction(ir::Instruction::Load { ptr: tmp }) } - BinaryOperator::Index => { - let ptr = self.translate_index_op(lhs, rhs, context)?; - if let Some(inner) = ptr.dtype().get_pointer_inner().unwrap().get_array_inner() { - context.insert_instruction(ir::Instruction::GetElementPtr { - ptr, - offset: ir::Operand::constant(ir::Constant::int(0, ir::Dtype::int(32))), - dtype: ir::Dtype::pointer(inner.clone()), - }) - } else { - context.insert_instruction(ir::Instruction::Load { ptr }) - } - } _ => { let lhs = self.translate_expr_rvalue(lhs, context)?; let rhs = self.translate_expr_rvalue(rhs, context)?; @@ -1468,6 +1461,44 @@ impl IrgenFunc<'_> { } } + fn translate_index_op( + &mut self, + lhs: &Expression, + rhs: &Expression, + context: &mut Context, + ) -> Result { + let lhs: ir::Operand = self.translate_expr_rvalue(lhs, context)?; + let lhs_dtype = lhs.dtype(); + let (dtype, inner_dtype) = if let Some(inner) = lhs_dtype.get_array_inner() { + (ir::Dtype::pointer(inner.clone()), inner.clone()) + } else if let Some(inner) = lhs_dtype.get_pointer_inner() { + // println!("hi~ {}", lhs_inner_dtype); + (lhs_dtype.clone(), inner.clone()) + } else { + panic!("WTF") + }; + let rhs = self.translate_expr_rvalue(rhs, context)?; + let rhs_dtype = rhs.dtype(); + let (inner_size, _) = inner_dtype + .size_align_of(self.structs) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + let offset = context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::Multiply, + lhs: rhs, + rhs: ir::Operand::constant(ir::Constant::int( + inner_size.try_into().unwrap(), + rhs_dtype.clone(), + )), + dtype: rhs_dtype.clone(), + })?; + // println!("asdfasdf {}", dtype); + context.insert_instruction(ir::Instruction::GetElementPtr { + ptr: lhs.clone(), + offset, + dtype, + }) + } + fn translate_assign( &mut self, lhs: &Expression, @@ -1486,188 +1517,70 @@ impl IrgenFunc<'_> { lhs.dtype().get_pointer_inner().unwrap().clone(), context, )?; - let _unused = context.insert_instruction(ir::Instruction::Store { - ptr: lhs.clone(), + let _unused: ir::Operand = context.insert_instruction(ir::Instruction::Store { + ptr: lhs, value: rhs.clone(), })?; Ok(rhs) } - fn translate_unary_op( + fn translate_conditional( &mut self, - op: &UnaryOperator, - operand: &Expression, + cond: &ConditionalExpression, context: &mut Context, ) -> Result { - match op { - UnaryOperator::PreIncrement => { - let lhs = self.translate_expr_rvalue(operand, context)?; - let dtype = lhs.dtype(); - let rhs = context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::Plus, - lhs, - rhs: ir::Operand::constant(ir::Constant::int(1, dtype.clone())), - dtype: dtype.clone(), - })?; - let lhs = self.translate_expr_lvalue(operand, context)?; - let _unused = context.insert_instruction(ir::Instruction::Store { - ptr: lhs, - value: rhs.clone(), - })?; - Ok(rhs) - } - UnaryOperator::PreDecrement => { - let lhs = self.translate_expr_rvalue(operand, context)?; - let dtype = lhs.dtype(); - let rhs = context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::Minus, - lhs, - rhs: ir::Operand::constant(ir::Constant::int(1, dtype.clone())), - dtype: dtype.clone(), - })?; - let lhs = self.translate_expr_lvalue(operand, context)?; - let _unused = context.insert_instruction(ir::Instruction::Store { - ptr: lhs, - value: rhs.clone(), - })?; - Ok(rhs) - } - UnaryOperator::PostIncrement => { - let lhs = self.translate_expr_rvalue(operand, context)?; - let dtype = lhs.dtype(); - let rhs = if let Some(inner) = dtype.get_pointer_inner() { - let (size, _) = ir::Dtype::size_align_of(inner, self.structs) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - context.insert_instruction(ir::Instruction::GetElementPtr { - ptr: lhs.clone(), - offset: ir::Operand::constant(ir::Constant::int( - size.try_into().unwrap(), - ir::Dtype::int(32), - )), - dtype: dtype.clone(), - })? - } else { - context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::Plus, - lhs: lhs.clone(), - rhs: ir::Operand::constant(ir::Constant::int(1, dtype.clone())), - dtype: dtype.clone(), - })? - }; - let lhs_lvalue = self.translate_expr_lvalue(operand, context)?; - let _unused = context.insert_instruction(ir::Instruction::Store { - ptr: lhs_lvalue, - value: rhs.clone(), - })?; - Ok(lhs) - } - UnaryOperator::PostDecrement => { - let lhs = self.translate_expr_rvalue(operand, context)?; - let dtype = lhs.dtype(); - let rhs = context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::Minus, - lhs: lhs.clone(), - rhs: ir::Operand::constant(ir::Constant::int(1, dtype.clone())), - dtype: dtype.clone(), - })?; - let lhs_lvalue = self.translate_expr_lvalue(operand, context)?; - let _unused = context.insert_instruction(ir::Instruction::Store { - ptr: lhs_lvalue, - value: rhs.clone(), - })?; - Ok(lhs) - } - UnaryOperator::Address => { - let t = self.translate_expr_lvalue(operand, context)?; - // println!("{}", t.dtype()); - Ok(t) - } - UnaryOperator::Indirection => { - let operand = self.translate_expr_rvalue(operand, context)?; - context.insert_instruction(ir::Instruction::Load { ptr: operand }) - } - UnaryOperator::Complement => { - let lhs = self.translate_expr_rvalue(operand, context)?; - let lhs_dtype = lhs.dtype(); - let lhs = - self.translate_typecast(lhs, self.integer_promotion(lhs_dtype), context)?; - let dtype = lhs.dtype(); - context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::BitwiseXor, - lhs, - rhs: ir::Operand::constant(ir::Constant::int(u128::MAX, dtype.clone())), - dtype: dtype.clone(), - }) - } - UnaryOperator::Plus | UnaryOperator::Minus => { - let operand = self.translate_expr_rvalue(operand, context)?; - let operand_dtype = operand.dtype(); - let operand = self.translate_typecast( - operand, - self.integer_promotion(operand_dtype), - context, - )?; - let dtype = operand.dtype(); - context.insert_instruction(ir::Instruction::UnaryOp { - op: op.clone(), - operand, - dtype, - }) - } - UnaryOperator::Negate => { - let lhs = self.translate_expr_rvalue(operand, context)?; - let lhs_dtype = lhs.dtype(); - let lhs = self.translate_typecast( - lhs, - self.integer_promotion(lhs_dtype.clone()), - context, - )?; - let lhs_dtype = lhs.dtype(); - let rhs = ir::Operand::constant(match &lhs_dtype { - ir::Dtype::Int { .. } => ir::Constant::int(0, lhs_dtype.clone()), - ir::Dtype::Float { .. } => ir::Constant::float(0.0, lhs_dtype.clone()), - _ => todo!(), - }); - context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::Equals, - lhs, - rhs, - dtype: ir::Dtype::BOOL, - }) - } - _ => todo!("unary op"), - } - } + let then_bid = self.alloc_bid(); + let else_bid = self.alloc_bid(); + let end_bid = self.alloc_bid(); - fn lookup_symbol_table(&self, name: &String) -> Result { - for layer in self.symbol_table.iter().rev() { - if let Some(ptr) = layer.get(name) { - return Ok(ptr.clone()); - } - } - Err(IrgenErrorMessage::RequireLvalue { - message: format!("Undefined symbol {name}"), - }) - } + self.translate_condition( + &cond.condition.node, + mem::replace(context, Context::new(end_bid)), + then_bid, + else_bid, + )?; - fn convert_array_to_pointer( - &mut self, - ptr: ir::Operand, - array_inner: &ir::Dtype, - context: &mut Context, - ) -> Result { - context.insert_instruction(ir::Instruction::GetElementPtr { + let mut then_context = Context::new(then_bid); + let then_val = self.translate_expr_rvalue(&cond.then_expression.node, &mut then_context)?; + + let mut else_context = Context::new(else_bid); + let else_val = self.translate_expr_rvalue(&cond.else_expression.node, &mut else_context)?; + + // println!("conditional: {} {}", cond.then_expression.write_string(), cond.else_expression.write_string()); + let merged_dtype = self.merge_dtype(then_val.dtype(), else_val.dtype()); + let then_val = + self.translate_typecast(then_val, merged_dtype.clone(), &mut then_context)?; + let else_val = + self.translate_typecast(else_val, merged_dtype.clone(), &mut else_context)?; + + let var = self.alloc_tempid(); + let ptr = self.translate_alloc(var, &merged_dtype.clone(), context)?; + + let _unused = then_context.insert_instruction(ir::Instruction::Store { ptr: ptr.clone(), - offset: ir::Operand::constant(ir::Constant::int(0, ir::Dtype::int(32))), - dtype: ir::Dtype::pointer( - ptr.dtype() - .get_pointer_inner() - .unwrap() - .get_array_inner() - .cloned() - .unwrap(), - ), - }) + value: then_val, + })?; + self.insert_block( + then_context, + ir::BlockExit::Jump { + arg: ir::JumpArg::new(end_bid, Vec::new()), + }, + ); + + let _unused = else_context.insert_instruction(ir::Instruction::Store { + ptr: ptr.clone(), + value: else_val, + })?; + self.insert_block( + else_context, + ir::BlockExit::Jump { + arg: ir::JumpArg::new(end_bid, Vec::new()), + }, + ); + + let r = context.insert_instruction(ir::Instruction::Load { ptr: ptr.clone() })?; + // println!("ptr: {}, rtype: {}", ptr.dtype(), r.dtype()); + Ok(r) } fn translate_condition( @@ -1678,7 +1591,7 @@ impl IrgenFunc<'_> { else_bid: ir::BlockId, ) -> Result<(), IrgenErrorMessage> { let condition = self.translate_expr_rvalue(condition, &mut context)?; - let condition = self.translate_typecast_to_bool(condition, &mut context)?; + let condition = self.translate_typecast(condition, ir::Dtype::BOOL, &mut context)?; self.insert_block( context, ir::BlockExit::ConditionalJump { @@ -1926,85 +1839,6 @@ impl IrgenFunc<'_> { } } - fn translate_member_op( - &mut self, - op: &MemberOperator, - expr: &Expression, - id: &Identifier, - context: &mut Context, - ) -> Result { - match op { - MemberOperator::Direct => { - let expr = self.translate_expr_lvalue(expr, context)?; - let struct_dtype = expr.dtype().get_pointer_inner().unwrap().clone(); - let (field_offset, field_dtype) = struct_dtype - .get_offset_struct_field(&id.name, self.structs) - .expect("no field"); - context.insert_instruction(ir::Instruction::GetElementPtr { - ptr: expr, - offset: ir::Operand::constant(ir::Constant::int( - field_offset.try_into().unwrap(), - ir::Dtype::int(32), - )), - dtype: ir::Dtype::pointer(field_dtype), - }) - } - MemberOperator::Indirect => { - let expr = self.translate_expr_rvalue(expr, context)?; - let struct_dtype = expr.dtype().get_pointer_inner().unwrap().clone(); - let (field_offset, field_dtype) = struct_dtype - .get_offset_struct_field(&id.name, self.structs) - .expect("no field"); - context.insert_instruction(ir::Instruction::GetElementPtr { - ptr: expr, - offset: ir::Operand::constant(ir::Constant::int( - field_offset.try_into().unwrap(), - ir::Dtype::int(32), - )), - dtype: ir::Dtype::pointer(field_dtype), - }) - } - } - } - - fn translate_index_op( - &mut self, - lhs: &Expression, - rhs: &Expression, - context: &mut Context, - ) -> Result { - let lhs: ir::Operand = self.translate_expr_rvalue(lhs, context)?; - let lhs_dtype = lhs.dtype(); - let (dtype, inner_dtype) = if let Some(inner) = lhs_dtype.get_array_inner() { - (ir::Dtype::pointer(inner.clone()), inner.clone()) - } else if let Some(inner) = lhs_dtype.get_pointer_inner() { - // println!("hi~ {}", lhs_inner_dtype); - (lhs_dtype.clone(), inner.clone()) - } else { - panic!("WTF") - }; - let rhs = self.translate_expr_rvalue(rhs, context)?; - let rhs_dtype = rhs.dtype(); - let (inner_size, _) = inner_dtype - .size_align_of(self.structs) - .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; - let offset = context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::Multiply, - lhs: rhs, - rhs: ir::Operand::constant(ir::Constant::int( - inner_size.try_into().unwrap(), - rhs_dtype.clone(), - )), - dtype: rhs_dtype.clone(), - })?; - // println!("asdfasdf {}", dtype); - context.insert_instruction(ir::Instruction::GetElementPtr { - ptr: lhs.clone(), - offset, - dtype, - }) - } - fn translate_func_call( &mut self, call: &CallExpression, @@ -2033,7 +1867,7 @@ impl IrgenFunc<'_> { message: format!("too few arguments to function `{}`", "TODO"), }); } - let args = izip!(args, parameters) + let args: Vec = izip!(args, parameters) .map(|(a, p)| self.translate_typecast(a, p.clone(), context)) .collect::, _>>()?; @@ -2150,35 +1984,31 @@ impl IrgenFunc<'_> { dtype: ir::Dtype, context: &mut Context, ) -> Result { - let value_dtype = value.dtype(); - if value_dtype.clone().set_const(false) == dtype.clone().set_const(false) { + let dtype = dtype.set_const(false); + let value_dtype = value.dtype().set_const(false); + if dtype == value_dtype { return Ok(value); } - context.insert_instruction(ir::Instruction::TypeCast { - value, - target_dtype: dtype, - }) + + match &dtype { + &ir::Dtype::BOOL => context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::NotEquals, + lhs: value, + rhs: self.constant_zero(value_dtype), + dtype: ir::Dtype::BOOL, + }), + _ => context.insert_instruction(ir::Instruction::TypeCast { + value, + target_dtype: dtype, + }), + } } - fn translate_typecast_to_bool( - &mut self, - value: ir::Operand, - context: &mut Context, - ) -> Result { - let value_dtype = value.dtype(); - if value_dtype == ir::Dtype::BOOL { - return Ok(value); - } - let rhs = ir::Operand::constant(match &value_dtype { - ir::Dtype::Int { .. } => ir::Constant::int(0, value_dtype.clone()), - ir::Dtype::Float { .. } => ir::Constant::float(0.0, value_dtype.clone()), - _ => todo!(), - }); - context.insert_instruction(ir::Instruction::BinOp { - op: BinaryOperator::NotEquals, - lhs: value, - rhs, - dtype: ir::Dtype::BOOL, + fn constant_zero(&self, dtype: ir::Dtype) -> ir::Operand { + ir::Operand::constant(match &dtype { + ir::Dtype::Int { .. } => ir::Constant::int(0, dtype), + ir::Dtype::Float { .. } => ir::Constant::float(0.0, dtype), + _ => todo!("constant_zero"), }) } @@ -2212,10 +2042,7 @@ impl IrgenFunc<'_> { | UnaryOperator::Minus | UnaryOperator::Complement => self.dtypeof_expr(&unary.operand.node), UnaryOperator::Negate => ir::Dtype::INT, - _ => { - println!("{}", unary.write_string()); - todo!("unary dtypeof_expr") - } + _ => todo!("dtypeof_expr"), } } Expression::BinaryOperator(binary) => { @@ -2253,10 +2080,7 @@ impl IrgenFunc<'_> { | BinaryOperator::AssignBitwiseAnd | BinaryOperator::AssignBitwiseXor | BinaryOperator::AssignBitwiseOr => self.dtypeof_expr(&binary.lhs.node), - _ => { - println!("{}", binary.write_string()); - todo!("binary dtypeof_expr") - } + _ => todo!("dtypeof_expr"), } } Expression::Conditional(cond) => self.merge_dtype( @@ -2264,10 +2088,52 @@ impl IrgenFunc<'_> { self.dtypeof_expr(&cond.node.else_expression.node), ), Expression::Comma(comma) => self.dtypeof_expr(&comma.last().unwrap().node), - _ => { - println!("{}", expr.write_string()); - todo!("dtypeof_expr") + _ => todo!("dtypeof_expr"), + } + } + + fn merge_dtype(&self, lhs_dtype: ir::Dtype, rhs_dtype: ir::Dtype) -> ir::Dtype { + let lhs_dtype = lhs_dtype.set_const(false); + let rhs_dtype = rhs_dtype.set_const(false); + if lhs_dtype == rhs_dtype { + return lhs_dtype; + } + + match (&lhs_dtype, &rhs_dtype) { + (&ir::Dtype::DOUBLE, _) | (_, &ir::Dtype::DOUBLE) => ir::Dtype::DOUBLE, + (&ir::Dtype::FLOAT, _) | (_, &ir::Dtype::FLOAT) => ir::Dtype::FLOAT, + ( + ir::Dtype::Int { + width: lhs_width, + is_signed: lhs_is_signed, + .. + }, + ir::Dtype::Int { + width: rhs_width, + is_signed: rhs_is_signed, + .. + }, + ) => { + if lhs_is_signed == rhs_is_signed || !lhs_is_signed { + if lhs_width >= rhs_width { + lhs_dtype + } else { + rhs_dtype + } + } else if lhs_width <= rhs_width { + rhs_dtype + } else { + lhs_dtype + } } + _ => todo!("merge_dtype"), + } + } + + fn integer_promotion(&self, dtype: ir::Dtype) -> ir::Dtype { + match dtype { + ir::Dtype::Int { width, .. } if width < 32 => ir::Dtype::INT, + _ => dtype, } } }