diff --git a/src/irgen/mod.rs b/src/irgen/mod.rs index 4b6244b..5df0adb 100644 --- a/src/irgen/mod.rs +++ b/src/irgen/mod.rs @@ -681,7 +681,7 @@ impl IrgenFunc<'_> { let end_bid = self.alloc_bid(); let (cases, default_bid) = - self.translate_switch_body(&stmt.statement.node, end_bid)?; + self.translate_switch_body(&stmt.statement.node, end_bid, bid_continue)?; self.insert_block( mem::replace(context, Context::new(end_bid)), @@ -879,7 +879,7 @@ impl IrgenFunc<'_> { .map_err(|e| IrgenError::new(expr.write_string(), e))?, None => ir::Operand::constant(ir::Constant::unit()), }; - let value = self + let value: ir::Operand = self .translate_typecast(value, self.return_type.clone(), context) .map_err(|e| IrgenError::new(expr.write_string(), e))?; let end_bid = self.alloc_bid(); @@ -986,10 +986,61 @@ impl IrgenFunc<'_> { context, ), Expression::Conditional(cond) => self.translate_conditional(&cond.node, context), + Expression::SizeOfVal(sizeof) => { + let dtype = self.dtypeof_expr(&sizeof.node.0.node); + 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), + ))) + } + 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), + ))) + } + 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) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + let (_, align) = dtype + .size_align_of(self.structs) + .map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?; + Ok(ir::Operand::constant(ir::Constant::int( + align.try_into().unwrap(), + ir::Dtype::LONGLONG.clone().set_signed(false), + ))) + } + Expression::Comma(exprs) => self.translate_comma(exprs.deref(), context), _ => todo!("c"), } } + fn translate_comma( + &mut self, + exprs: &[Node], + 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, @@ -1089,13 +1140,34 @@ impl IrgenFunc<'_> { } } _ => { - // println!("merge failed: {} {}", lhs_dtype, rhs_dtype); + println!("merge failed: {} {}", lhs_dtype, rhs_dtype); todo!("merge") } } } } + 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 + } + } + _ => dtype, + } + } + fn translate_binary_op( &mut self, op: &BinaryOperator, @@ -1107,6 +1179,11 @@ impl IrgenFunc<'_> { BinaryOperator::Assign => { let lhs = self.translate_expr_lvalue(lhs, context)?; let rhs = self.translate_expr_rvalue(rhs, context)?; + let rhs = self.translate_typecast( + rhs, + lhs.dtype().get_pointer_inner().unwrap().clone(), + context, + )?; let _unused = context.insert_instruction(ir::Instruction::Store { ptr: lhs, value: rhs.clone(), @@ -1131,10 +1208,145 @@ impl IrgenFunc<'_> { })?; Ok(rhs) } + BinaryOperator::LogicalAnd => { + let lhs_dtype = self.dtypeof_expr(lhs); + let rhs_dtype = self.dtypeof_expr(rhs); + let operand_dtype = self.merge_dtype( + self.integer_promotion(lhs_dtype), + self.integer_promotion(rhs_dtype), + ); + + let tmp = self.alloc_tempid(); + let tmp = self.translate_alloc(tmp, &ir::Dtype::BOOL, None, context)?; + + let then_bid = self.alloc_bid(); + let else_bid = self.alloc_bid(); + let end_bid = self.alloc_bid(); + + let lhs = self.translate_expr_rvalue(lhs, context)?; + let lhs = self.translate_typecast(lhs, operand_dtype.clone(), context)?; + let condition1 = context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::NotEquals, + lhs, + rhs: ir::Operand::constant(ir::Constant::int(0, operand_dtype.clone())), + dtype: ir::Dtype::BOOL, + })?; + self.insert_block( + mem::replace(context, Context::new(end_bid)), + ir::BlockExit::ConditionalJump { + condition: condition1, + arg_then: ir::JumpArg::new(then_bid, Vec::new()), + arg_else: ir::JumpArg::new(else_bid, Vec::new()), + }, + ); + + let mut then_context = Context::new(then_bid); + let _unused = then_context.insert_instruction(ir::Instruction::Store { + ptr: tmp.clone(), + value: ir::Operand::constant(ir::Constant::int(1, ir::Dtype::BOOL)), + })?; + self.insert_block( + then_context, + ir::BlockExit::Jump { + arg: ir::JumpArg::new(end_bid, Vec::new()), + }, + ); + + let mut else_context = Context::new(else_bid); + let rhs = self.translate_expr_rvalue(rhs, &mut else_context)?; + let rhs = self.translate_typecast(rhs, operand_dtype.clone(), &mut else_context)?; + let condition2 = else_context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::NotEquals, + lhs: rhs, + rhs: ir::Operand::constant(ir::Constant::int(1, operand_dtype.clone())), + dtype: ir::Dtype::BOOL, + })?; + let _unused = else_context.insert_instruction(ir::Instruction::Store { + ptr: tmp.clone(), + value: condition2, + }); + self.insert_block( + else_context, + ir::BlockExit::Jump { + arg: ir::JumpArg::new(end_bid, Vec::new()), + }, + ); + + context.insert_instruction(ir::Instruction::Load { ptr: tmp }) + } + BinaryOperator::LogicalOr => { + let lhs_dtype = self.dtypeof_expr(lhs); + let rhs_dtype = self.dtypeof_expr(rhs); + let operand_dtype = self.merge_dtype( + self.integer_promotion(lhs_dtype), + self.integer_promotion(rhs_dtype), + ); + + let tmp = self.alloc_tempid(); + let tmp = self.translate_alloc(tmp, &ir::Dtype::BOOL, None, context)?; + + let then_bid = self.alloc_bid(); + let else_bid = self.alloc_bid(); + let end_bid = self.alloc_bid(); + + let lhs = self.translate_expr_rvalue(lhs, context)?; + let lhs = self.translate_typecast(lhs, operand_dtype.clone(), context)?; + let condition1 = context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::Equals, + lhs, + rhs: ir::Operand::constant(ir::Constant::int(0, operand_dtype.clone())), + dtype: ir::Dtype::BOOL, + })?; + self.insert_block( + mem::replace(context, Context::new(end_bid)), + ir::BlockExit::ConditionalJump { + condition: condition1, + arg_then: ir::JumpArg::new(then_bid, Vec::new()), + arg_else: ir::JumpArg::new(else_bid, Vec::new()), + }, + ); + + let mut then_context = Context::new(then_bid); + let _unused = then_context.insert_instruction(ir::Instruction::Store { + ptr: tmp.clone(), + value: ir::Operand::constant(ir::Constant::int(0, ir::Dtype::BOOL)), + })?; + self.insert_block( + then_context, + ir::BlockExit::Jump { + arg: ir::JumpArg::new(end_bid, Vec::new()), + }, + ); + + let mut else_context = Context::new(else_bid); + let rhs = self.translate_expr_rvalue(rhs, &mut else_context)?; + let rhs = self.translate_typecast(rhs, operand_dtype.clone(), &mut else_context)?; + let condition2 = else_context.insert_instruction(ir::Instruction::BinOp { + op: BinaryOperator::NotEquals, + lhs: rhs, + rhs: ir::Operand::constant(ir::Constant::int(0, operand_dtype.clone())), + dtype: ir::Dtype::BOOL, + })?; + let _unused = else_context.insert_instruction(ir::Instruction::Store { + ptr: tmp.clone(), + value: condition2, + }); + self.insert_block( + else_context, + ir::BlockExit::Jump { + arg: ir::JumpArg::new(end_bid, Vec::new()), + }, + ); + + context.insert_instruction(ir::Instruction::Load { ptr: tmp }) + } _ => { let lhs = self.translate_expr_rvalue(lhs, context)?; let rhs = self.translate_expr_rvalue(rhs, context)?; - let operand_dtype = self.merge_dtype(lhs.dtype(), rhs.dtype()); + let operand_dtype = self.merge_dtype( + self.integer_promotion(lhs.dtype()), + self.integer_promotion(rhs.dtype()), + ); let result_dtype = match op { BinaryOperator::Less | BinaryOperator::Greater @@ -1179,6 +1391,63 @@ impl IrgenFunc<'_> { })?; 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 = 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 dtype = lhs.dtype(); @@ -1246,6 +1515,7 @@ impl IrgenFunc<'_> { &mut self, stmt: &Statement, end_bid: ir::BlockId, + bid_continue: Option, ) -> Result<(Vec<(ir::Constant, ir::JumpArg)>, ir::BlockId), IrgenError> { let mut cases = Vec::new(); let mut default = None; @@ -1266,6 +1536,7 @@ impl IrgenFunc<'_> { &mut cases, &mut default, end_bid, + bid_continue, )?; } _ => panic!("is unsupported"), @@ -1285,6 +1556,7 @@ impl IrgenFunc<'_> { cases: &mut Vec<(ir::Constant, ir::JumpArg)>, default: &mut Option, end_bid: ir::BlockId, + bid_continue: Option, ) -> Result<(), IrgenError> { let stmt = if let Statement::Labeled(stmt) = stmt { &stmt.node @@ -1295,7 +1567,7 @@ impl IrgenFunc<'_> { }; let bid = self.alloc_bid(); - let case = self.translate_switch_body_label_statement(stmt, bid, end_bid)?; + let case = self.translate_switch_body_label_statement(stmt, bid, end_bid, bid_continue)?; if let Some(case) = case { if !case.is_integer_constant() { return Err(IrgenError::new( @@ -1335,6 +1607,7 @@ impl IrgenFunc<'_> { stmt: &LabeledStatement, bid: ir::BlockId, end_bid: ir::BlockId, + bid_continue: Option, ) -> Result, IrgenError> { let case = match &stmt.label.node { Label::Identifier(_) => panic!("`Label::Identifier` is unsupported"), @@ -1369,7 +1642,7 @@ impl IrgenFunc<'_> { .translate_decl(&decl.node, &mut context) .map_err(|e| IrgenError::new(decl.write_string(), e))?, BlockItem::Statement(stmt) => { - self.translate_stmt(&stmt.node, &mut context, None, None)?; + self.translate_stmt(&stmt.node, &mut context, bid_continue, None)?; } _ => panic!("is unsupported"), } @@ -1620,7 +1893,8 @@ impl IrgenFunc<'_> { dtype: ir::Dtype, context: &mut Context, ) -> Result { - if value.dtype() == dtype { + let value_dtype = value.dtype(); + if value_dtype.clone().set_const(false) == dtype.clone().set_const(false) { return Ok(value); } context.insert_instruction(ir::Instruction::TypeCast { @@ -1636,6 +1910,69 @@ impl IrgenFunc<'_> { ) -> Result { self.translate_typecast(value, ir::Dtype::BOOL, context) // TODO: Right? } + + fn dtypeof_expr(&self, expr: &Expression) -> ir::Dtype { + match expr { + Expression::Identifier(id) => self.lookup_symbol_table(&id.node.name).unwrap().dtype(), + Expression::Constant(_) => ir::Constant::try_from(expr).unwrap().dtype(), + Expression::UnaryOperator(unary) => { + let unary = &unary.node; + match unary.operator.node { + UnaryOperator::PreDecrement + | UnaryOperator::PreIncrement + | UnaryOperator::PostDecrement + | UnaryOperator::PostIncrement => self.dtypeof_expr(&unary.operand.node), + UnaryOperator::Negate => ir::Dtype::int(32), + _ => todo!("unary dtypeof_expr"), + } + } + Expression::BinaryOperator(binary) => { + let binary = &binary.node; + match binary.operator.node { + BinaryOperator::BitwiseAnd + | BinaryOperator::BitwiseOr + | BinaryOperator::BitwiseXor => self.integer_promotion(self.merge_dtype( + self.dtypeof_expr(&binary.lhs.node), + self.dtypeof_expr(&binary.rhs.node), + )), + BinaryOperator::LogicalAnd + | BinaryOperator::LogicalOr + | BinaryOperator::Equals + | BinaryOperator::NotEquals + | BinaryOperator::Less + | BinaryOperator::LessOrEqual + | BinaryOperator::Greater + | BinaryOperator::GreaterOrEqual => ir::Dtype::BOOL, + BinaryOperator::Assign => self + .dtypeof_expr(&binary.lhs.node) + .get_pointer_inner() + .cloned() + .unwrap(), + _ => todo!("binary dtypeof_expr"), + } + } + Expression::SizeOfTy(_) | Expression::SizeOfVal(_) | Expression::AlignOf(_) => { + ir::Dtype::int(64).set_signed(false) + } + Expression::Conditional(cond) => self.merge_dtype( + self.dtypeof_expr(&cond.node.then_expression.node), + self.dtypeof_expr(&cond.node.else_expression.node), + ), + Expression::Call(call) => { + let callee_dtype = self.dtypeof_expr(&call.node.callee.node); + let (ret_dtype, _) = callee_dtype + .get_pointer_inner() + .unwrap() + .get_function_inner() + .unwrap(); + ret_dtype.clone() + } + _ => { + println!("{}", expr.write_string()); + todo!("dtypeof_expr") + } + } + } } #[inline]