mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-14 22:38:46 +00:00
HW2 (1)
grade-irgen-small.sh 스크립트에서 switch.c 예제까지 통과하는 상태
This commit is contained in:
972
src/irgen/mod.rs
972
src/irgen/mod.rs
@@ -38,8 +38,10 @@ use core::cmp::Ordering;
|
||||
use core::convert::TryFrom;
|
||||
use core::{fmt, mem};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt::Binary;
|
||||
use std::ops::Deref;
|
||||
|
||||
use ir::BlockExit;
|
||||
use itertools::izip;
|
||||
use lang_c::ast::*;
|
||||
use lang_c::driver::Parse;
|
||||
@@ -590,7 +592,921 @@ impl IrgenFunc<'_> {
|
||||
bid_continue: Option<ir::BlockId>,
|
||||
bid_break: Option<ir::BlockId>,
|
||||
) -> Result<(), IrgenError> {
|
||||
todo!()
|
||||
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();
|
||||
|
||||
for item in items {
|
||||
match &item.node {
|
||||
BlockItem::Declaration(decl) => self
|
||||
.translate_decl(&decl.node, context)
|
||||
.map_err(|e| IrgenError::new(decl.write_string(), e))?,
|
||||
BlockItem::StaticAssert(_) => {
|
||||
panic!("BlockItem::StaticAssert is unsupported")
|
||||
}
|
||||
BlockItem::Statement(stmt) => {
|
||||
self.translate_stmt(&stmt.node, context, bid_continue, bid_break)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.exit_scope();
|
||||
Ok(())
|
||||
}
|
||||
Statement::Expression(expr) => {
|
||||
if let Some(expr) = expr {
|
||||
let _unused = self
|
||||
.translate_expr_rvalue(&expr.node, context)
|
||||
.map_err(|e| IrgenError::new(expr.write_string(), e))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Statement::If(stmt) => {
|
||||
let stmt = &stmt.node;
|
||||
|
||||
let then_bid = self.alloc_bid();
|
||||
let else_bid = self.alloc_bid();
|
||||
let end_bid = self.alloc_bid();
|
||||
self.translate_condition(
|
||||
&stmt.condition.node,
|
||||
mem::replace(context, Context::new(end_bid)),
|
||||
then_bid,
|
||||
else_bid,
|
||||
)
|
||||
.map_err(|e| IrgenError::new(stmt.condition.write_string(), e))?;
|
||||
|
||||
let mut then_context = Context::new(then_bid);
|
||||
self.translate_stmt(
|
||||
&stmt.then_statement.node,
|
||||
&mut then_context,
|
||||
bid_continue,
|
||||
bid_break,
|
||||
)?;
|
||||
self.insert_block(
|
||||
then_context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(end_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
let mut else_context = Context::new(else_bid);
|
||||
if let Some(else_stmt) = &stmt.else_statement {
|
||||
self.translate_stmt(
|
||||
&else_stmt.node,
|
||||
&mut else_context,
|
||||
bid_continue,
|
||||
bid_break,
|
||||
)?;
|
||||
}
|
||||
self.insert_block(
|
||||
else_context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(end_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Statement::Switch(stmt) => {
|
||||
let stmt = &stmt.node;
|
||||
let value = self
|
||||
.translate_expr_rvalue(&stmt.expression.node, context)
|
||||
.map_err(|e| IrgenError::new(stmt.expression.write_string(), e))?;
|
||||
|
||||
let end_bid = self.alloc_bid();
|
||||
let (cases, default_bid) =
|
||||
self.translate_switch_body(&stmt.statement.node, end_bid)?;
|
||||
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(end_bid)),
|
||||
ir::BlockExit::Switch {
|
||||
value,
|
||||
default: ir::JumpArg::new(default_bid, Vec::new()),
|
||||
cases,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
Statement::While(stmt) => {
|
||||
let stmt = &stmt.node;
|
||||
|
||||
let cond_bid = self.alloc_bid();
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(cond_bid)),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(cond_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
let body_bid = self.alloc_bid();
|
||||
let end_bid = self.alloc_bid();
|
||||
self.translate_condition(
|
||||
&stmt.expression.node,
|
||||
mem::replace(context, Context::new(end_bid)),
|
||||
body_bid,
|
||||
end_bid,
|
||||
);
|
||||
|
||||
self.enter_scope();
|
||||
|
||||
let mut body_context = Context::new(body_bid);
|
||||
self.translate_stmt(
|
||||
&stmt.statement.node,
|
||||
&mut body_context,
|
||||
Some(cond_bid),
|
||||
Some(end_bid),
|
||||
)?;
|
||||
self.insert_block(
|
||||
body_context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(cond_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
self.exit_scope();
|
||||
Ok(())
|
||||
}
|
||||
Statement::DoWhile(stmt) => {
|
||||
let stmt = &stmt.node;
|
||||
|
||||
let body_bid = self.alloc_bid();
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(body_bid)),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(body_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
self.enter_scope();
|
||||
|
||||
let cond_bid = self.alloc_bid();
|
||||
let end_bid = self.alloc_bid();
|
||||
self.translate_stmt(&stmt.statement.node, context, Some(cond_bid), Some(end_bid))?;
|
||||
|
||||
self.exit_scope();
|
||||
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(cond_bid)),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(cond_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
self.translate_condition(
|
||||
&stmt.expression.node,
|
||||
mem::replace(context, Context::new(end_bid)),
|
||||
body_bid,
|
||||
end_bid,
|
||||
)
|
||||
.map_err(|e| IrgenError::new(stmt.expression.write_string(), e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Statement::For(stmt) => {
|
||||
let stmt = &stmt.node;
|
||||
|
||||
let init_bid = self.alloc_bid();
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(init_bid)),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(init_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
self.enter_scope();
|
||||
|
||||
self.translate_for_initializer(&stmt.initializer.node, context)
|
||||
.map_err(|e| IrgenError::new(stmt.initializer.write_string(), e))?;
|
||||
|
||||
let cond_bid = self.alloc_bid();
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(cond_bid)),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(cond_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
let body_bid = self.alloc_bid();
|
||||
let step_bid = self.alloc_bid();
|
||||
let end_bid = self.alloc_bid();
|
||||
|
||||
self.translate_opt_condition(
|
||||
&stmt.condition,
|
||||
mem::replace(context, Context::new(end_bid)),
|
||||
body_bid,
|
||||
end_bid,
|
||||
)
|
||||
.map_err(|e| IrgenError::new(stmt.condition.write_string(), e))?;
|
||||
|
||||
self.enter_scope();
|
||||
|
||||
let mut body_context = Context::new(body_bid);
|
||||
self.translate_stmt(
|
||||
&stmt.statement.node,
|
||||
&mut body_context,
|
||||
Some(step_bid),
|
||||
Some(end_bid),
|
||||
)?;
|
||||
|
||||
self.exit_scope();
|
||||
self.insert_block(
|
||||
body_context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(step_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
let mut step_context = Context::new(step_bid);
|
||||
if let Some(step_expr) = &stmt.step {
|
||||
let _unused = self
|
||||
.translate_expr_rvalue(&step_expr.node, &mut step_context)
|
||||
.map_err(|e| IrgenError::new(stmt.step.write_string(), e))?;
|
||||
}
|
||||
self.insert_block(
|
||||
step_context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(cond_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Statement::Continue => {
|
||||
let bid_continue = bid_continue.ok_or_else(|| {
|
||||
IrgenError::new(
|
||||
"continue;".to_string(),
|
||||
IrgenErrorMessage::Misc {
|
||||
message: "continue statement not within a loop".to_string(),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let next_context = Context::new(self.alloc_bid());
|
||||
self.insert_block(
|
||||
mem::replace(context, next_context),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(bid_continue, Vec::new()),
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
Statement::Break => {
|
||||
let bid_break = bid_break.ok_or_else(|| {
|
||||
IrgenError::new(
|
||||
"break;".to_string(),
|
||||
IrgenErrorMessage::Misc {
|
||||
message: "break statement not within a loop".to_string(),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let next_context = Context::new(self.alloc_bid());
|
||||
self.insert_block(
|
||||
mem::replace(context, next_context),
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(bid_break, Vec::new()),
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
Statement::Return(expr) => {
|
||||
let value = match expr {
|
||||
Some(expr) => self
|
||||
.translate_expr_rvalue(&expr.node, context)
|
||||
.map_err(|e| IrgenError::new(expr.write_string(), e))?,
|
||||
None => ir::Operand::constant(ir::Constant::unit()),
|
||||
};
|
||||
let value = self
|
||||
.translate_typecast(value, self.return_type.clone(), context)
|
||||
.map_err(|e| IrgenError::new(expr.write_string(), e))?;
|
||||
let end_bid = self.alloc_bid();
|
||||
self.insert_block(
|
||||
mem::replace(context, Context::new(end_bid)),
|
||||
ir::BlockExit::Return { value },
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
_ => todo!("e"),
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_decl(
|
||||
&mut self,
|
||||
decl: &Declaration,
|
||||
context: &mut Context,
|
||||
) -> Result<(), IrgenErrorMessage> {
|
||||
let (base_dtype, is_typedef) =
|
||||
ir::Dtype::try_from_ast_declaration_specifiers(&decl.specifiers)
|
||||
.map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?;
|
||||
assert!(!is_typedef);
|
||||
|
||||
for init_decl in &decl.declarators {
|
||||
let declarator = &init_decl.node.declarator.node;
|
||||
let name = name_of_declarator(declarator);
|
||||
let dtype = base_dtype
|
||||
.clone()
|
||||
.with_ast_declarator(declarator)
|
||||
.and_then(|dtype| dtype.deref().clone().resolve_typedefs(self.typedefs)) // TODO: Why?
|
||||
.map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?;
|
||||
match &dtype {
|
||||
ir::Dtype::Unit { .. } => todo!("f"),
|
||||
ir::Dtype::Int { .. }
|
||||
| ir::Dtype::Float { .. }
|
||||
| ir::Dtype::Pointer { .. }
|
||||
| ir::Dtype::Array { .. } => {
|
||||
let value = if let Some(initializer) = &init_decl.node.initializer {
|
||||
Some(self.translate_initializer(&initializer.node, context)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let _unused = self.translate_alloc(name, &dtype, value, context)?;
|
||||
}
|
||||
ir::Dtype::Function { .. } => todo!("g"),
|
||||
ir::Dtype::Struct { .. } => todo!("h"),
|
||||
ir::Dtype::Typedef { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn translate_initializer(
|
||||
&mut self,
|
||||
initializer: &Initializer,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
match initializer {
|
||||
Initializer::Expression(expr) => self.translate_expr_rvalue(&expr.node, context),
|
||||
Initializer::List(_) => panic!("Initializer::List is unsupported"),
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_expr_rvalue(
|
||||
&mut self,
|
||||
expr: &Expression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
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::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::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),
|
||||
_ => todo!("c"),
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_conditional(
|
||||
&mut self,
|
||||
cond: &ConditionalExpression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
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(), None, 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
|
||||
} 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_binary_op(
|
||||
&mut self,
|
||||
op: &BinaryOperator,
|
||||
lhs: &Expression,
|
||||
rhs: &Expression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
match op {
|
||||
BinaryOperator::Assign => {
|
||||
let lhs = self.translate_expr_lvalue(lhs, context)?;
|
||||
let rhs = self.translate_expr_rvalue(rhs, context)?;
|
||||
let _unused = context.insert_instruction(ir::Instruction::Store {
|
||||
ptr: lhs,
|
||||
value: rhs.clone(),
|
||||
})?;
|
||||
Ok(rhs)
|
||||
}
|
||||
BinaryOperator::AssignPlus => {
|
||||
let rhs = self.translate_binary_op(&BinaryOperator::Plus, lhs, rhs, context)?;
|
||||
let lhs = self.translate_expr_lvalue(lhs, context)?;
|
||||
let _unused = context.insert_instruction(ir::Instruction::Store {
|
||||
ptr: lhs,
|
||||
value: rhs.clone(),
|
||||
})?;
|
||||
Ok(rhs)
|
||||
}
|
||||
BinaryOperator::AssignMinus => {
|
||||
let rhs = self.translate_binary_op(&BinaryOperator::Minus, lhs, rhs, context)?;
|
||||
let lhs = self.translate_expr_lvalue(lhs, context)?;
|
||||
let _unused = context.insert_instruction(ir::Instruction::Store {
|
||||
ptr: lhs,
|
||||
value: rhs.clone(),
|
||||
})?;
|
||||
Ok(rhs)
|
||||
}
|
||||
_ => {
|
||||
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 result_dtype = match op {
|
||||
BinaryOperator::Less
|
||||
| BinaryOperator::Greater
|
||||
| BinaryOperator::LessOrEqual
|
||||
| BinaryOperator::GreaterOrEqual
|
||||
| BinaryOperator::Equals
|
||||
| BinaryOperator::NotEquals => ir::Dtype::BOOL,
|
||||
_ => operand_dtype.clone(),
|
||||
};
|
||||
let lhs = self.translate_typecast(lhs, operand_dtype.clone(), context)?;
|
||||
let rhs = self.translate_typecast(rhs, operand_dtype.clone(), context)?;
|
||||
context.insert_instruction(ir::Instruction::BinOp {
|
||||
op: op.clone(),
|
||||
lhs,
|
||||
rhs,
|
||||
dtype: result_dtype,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_unary_op(
|
||||
&mut self,
|
||||
op: &UnaryOperator,
|
||||
operand: &Expression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
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::Complement => {
|
||||
let lhs = self.translate_expr_rvalue(operand, 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 | UnaryOperator::Negate => {
|
||||
let operand = self.translate_expr_rvalue(operand, context)?;
|
||||
let dtype = operand.dtype();
|
||||
context.insert_instruction(ir::Instruction::UnaryOp {
|
||||
op: op.clone(),
|
||||
operand,
|
||||
dtype,
|
||||
})
|
||||
}
|
||||
_ => todo!("unary op"),
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_symbol_table(&self, name: &String) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
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}"),
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_array_to_pointer(
|
||||
&mut self,
|
||||
ptr: ir::Operand,
|
||||
array_inner: &ir::Dtype,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
todo!("array to pointer")
|
||||
}
|
||||
|
||||
fn translate_condition(
|
||||
&mut self,
|
||||
condition: &Expression,
|
||||
mut context: Context,
|
||||
then_bid: ir::BlockId,
|
||||
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)?;
|
||||
self.insert_block(
|
||||
context,
|
||||
ir::BlockExit::ConditionalJump {
|
||||
condition,
|
||||
arg_then: ir::JumpArg::new(then_bid, Vec::new()),
|
||||
arg_else: ir::JumpArg::new(else_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn translate_switch_body(
|
||||
&mut self,
|
||||
stmt: &Statement,
|
||||
end_bid: ir::BlockId,
|
||||
) -> Result<(Vec<(ir::Constant, ir::JumpArg)>, ir::BlockId), IrgenError> {
|
||||
let mut cases = Vec::new();
|
||||
let mut default = None;
|
||||
|
||||
let items = if let Statement::Compound(items) = stmt {
|
||||
items
|
||||
} else {
|
||||
panic!("`Statement` in the `switch` is unsupported except `Statement::Compound`")
|
||||
};
|
||||
|
||||
self.enter_scope();
|
||||
|
||||
for item in items {
|
||||
match &item.node {
|
||||
BlockItem::Statement(stmt) => {
|
||||
self.translate_switch_body_inner(
|
||||
&stmt.node,
|
||||
&mut cases,
|
||||
&mut default,
|
||||
end_bid,
|
||||
)?;
|
||||
}
|
||||
_ => panic!("is unsupported"),
|
||||
}
|
||||
}
|
||||
|
||||
self.exit_scope();
|
||||
|
||||
let default = default.unwrap_or(end_bid);
|
||||
|
||||
Ok((cases, default))
|
||||
}
|
||||
|
||||
fn translate_switch_body_inner(
|
||||
&mut self,
|
||||
stmt: &Statement,
|
||||
cases: &mut Vec<(ir::Constant, ir::JumpArg)>,
|
||||
default: &mut Option<ir::BlockId>,
|
||||
end_bid: ir::BlockId,
|
||||
) -> Result<(), IrgenError> {
|
||||
let stmt = if let Statement::Labeled(stmt) = stmt {
|
||||
&stmt.node
|
||||
} else {
|
||||
panic!(
|
||||
"`BlockItem::Statement` in the `Statement::Compound` of the `switch` is unsupported except `Statement::Labeled`"
|
||||
)
|
||||
};
|
||||
|
||||
let bid = self.alloc_bid();
|
||||
let case = self.translate_switch_body_label_statement(stmt, bid, end_bid)?;
|
||||
if let Some(case) = case {
|
||||
if !case.is_integer_constant() {
|
||||
return Err(IrgenError::new(
|
||||
stmt.label.write_string(),
|
||||
IrgenErrorMessage::Misc {
|
||||
message: "expression is not an integer constant expression".to_string(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
if cases.iter().any(|(c, _)| &case == c) {
|
||||
return Err(IrgenError::new(
|
||||
stmt.label.write_string(),
|
||||
IrgenErrorMessage::Misc {
|
||||
message: "duplicate case value".to_string(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
cases.push((case, ir::JumpArg::new(bid, Vec::new())));
|
||||
} else {
|
||||
if default.is_some() {
|
||||
return Err(IrgenError::new(
|
||||
stmt.label.write_string(),
|
||||
IrgenErrorMessage::Misc {
|
||||
message: "previous default already exists".to_string(),
|
||||
},
|
||||
));
|
||||
}
|
||||
*default = Some(bid);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn translate_switch_body_label_statement(
|
||||
&mut self,
|
||||
stmt: &LabeledStatement,
|
||||
bid: ir::BlockId,
|
||||
end_bid: ir::BlockId,
|
||||
) -> Result<Option<ir::Constant>, IrgenError> {
|
||||
let case = match &stmt.label.node {
|
||||
Label::Identifier(_) => panic!("`Label::Identifier` is unsupported"),
|
||||
Label::Case(expr) => {
|
||||
let constant = ir::Constant::try_from(&expr.node).map_err(|_| {
|
||||
IrgenError::new(
|
||||
expr.write_string(),
|
||||
IrgenErrorMessage::Misc {
|
||||
message: "case label does not reduce to an integer constant"
|
||||
.to_string(),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
Some(constant)
|
||||
}
|
||||
Label::Default => None,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let items = if let Statement::Compound(items) = &stmt.statement.node {
|
||||
items
|
||||
} else {
|
||||
panic!("`Statement` in the `label` is unsupported except `Sattement::Compound`")
|
||||
};
|
||||
self.enter_scope();
|
||||
let (last, items) = items
|
||||
.split_last()
|
||||
.expect("`Statement::Compound` has no item");
|
||||
let mut context = Context::new(bid);
|
||||
for item in items {
|
||||
match &item.node {
|
||||
BlockItem::Declaration(decl) => self
|
||||
.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)?;
|
||||
}
|
||||
_ => panic!("is unsupported"),
|
||||
}
|
||||
}
|
||||
|
||||
let stmt = if let BlockItem::Statement(stmt) = &last.node {
|
||||
&stmt.node
|
||||
} else {
|
||||
panic!(
|
||||
"`BlockItem` in the `Statement::Compound` of the `label` is unsupported except `BlockItem::Statement`"
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
stmt,
|
||||
&Statement::Break,
|
||||
"the last `BlockItem` in the `Statement::Compound` of the `label` must be `Statement::Break`"
|
||||
);
|
||||
|
||||
self.insert_block(
|
||||
context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(end_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
|
||||
self.exit_scope();
|
||||
|
||||
Ok(case)
|
||||
}
|
||||
|
||||
fn translate_for_initializer(
|
||||
&mut self,
|
||||
initializer: &ForInitializer,
|
||||
context: &mut Context,
|
||||
) -> Result<(), IrgenErrorMessage> {
|
||||
match initializer {
|
||||
ForInitializer::Empty => (),
|
||||
ForInitializer::Expression(expr) => {
|
||||
let _unused = self.translate_expr_rvalue(&expr.node, context)?;
|
||||
}
|
||||
ForInitializer::Declaration(decl) => {
|
||||
return self.translate_decl(&decl.node, context);
|
||||
}
|
||||
ForInitializer::StaticAssert(_) => {
|
||||
panic!("ForInitializer::StaticAssert is unsupported")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn translate_opt_condition(
|
||||
&mut self,
|
||||
condition: &Option<Box<Node<Expression>>>,
|
||||
context: Context,
|
||||
body_bid: ir::BlockId,
|
||||
end_bid: ir::BlockId,
|
||||
) -> Result<(), IrgenErrorMessage> {
|
||||
if let Some(condition) = condition {
|
||||
self.translate_condition(&condition.node, context, body_bid, end_bid)
|
||||
} else {
|
||||
self.insert_block(
|
||||
context,
|
||||
ir::BlockExit::Jump {
|
||||
arg: ir::JumpArg::new(body_bid, Vec::new()),
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_expr_lvalue(
|
||||
&mut self,
|
||||
expr: &Expression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
match expr {
|
||||
Expression::Identifier(identifier) => self.lookup_symbol_table(&identifier.node.name),
|
||||
Expression::UnaryOperator(unary) => match &unary.node.operator.node {
|
||||
UnaryOperator::Indirection => self.translate_expr_rvalue(&unary.node.operand.node, context),
|
||||
_ => Err(IrgenErrorMessage::Misc { message: "This error occurred at `IrgenFunc::translate_expr_lvalue`".to_string() })
|
||||
}
|
||||
Expression::BinaryOperator(binary) => match &binary.node.operator.node {
|
||||
BinaryOperator::Index => self.translate_index_op(&binary.node.lhs.node, &binary.node.rhs.node, context),
|
||||
_ => Err(IrgenErrorMessage::Misc { message: "binary operator expression cannot be used as l-value except index operator expression".to_string() }),
|
||||
}
|
||||
_ => todo!("expr lvalue")
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_index_op(
|
||||
&mut self,
|
||||
lhs: &Expression,
|
||||
rhs: &Expression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
todo!("index op")
|
||||
}
|
||||
|
||||
fn translate_func_call(
|
||||
&mut self,
|
||||
call: &CallExpression,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
let callee = self.translate_expr_rvalue(&call.callee.node, context)?;
|
||||
let function_pointer_type = callee.dtype();
|
||||
let function = function_pointer_type.get_pointer_inner().ok_or_else(|| {
|
||||
IrgenErrorMessage::NeedFunctionOrFunctionPointer {
|
||||
callee: callee.clone(),
|
||||
}
|
||||
})?;
|
||||
let (return_type, parameters) = function.get_function_inner().ok_or_else(|| {
|
||||
IrgenErrorMessage::NeedFunctionOrFunctionPointer {
|
||||
callee: callee.clone(),
|
||||
}
|
||||
})?;
|
||||
|
||||
let args = call
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|a| self.translate_expr_rvalue(&a.node, context))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
if args.len() != parameters.len() {
|
||||
return Err(IrgenErrorMessage::Misc {
|
||||
message: format!("too few arguments to function `{}`", "TODO"),
|
||||
});
|
||||
}
|
||||
let args = izip!(args, parameters)
|
||||
.map(|(a, p)| self.translate_typecast(a, p.clone(), context))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let return_type = return_type.clone().set_const(false);
|
||||
context.insert_instruction(ir::Instruction::Call {
|
||||
callee,
|
||||
args,
|
||||
return_type,
|
||||
})
|
||||
}
|
||||
|
||||
/// Translate initial parameter declarations of the functions to IR.
|
||||
@@ -666,7 +1582,59 @@ impl IrgenFunc<'_> {
|
||||
name_of_params: &[String],
|
||||
context: &mut Context,
|
||||
) -> Result<(), IrgenErrorMessage> {
|
||||
todo!()
|
||||
for (i, (dtype, var)) in izip!(&signature.params, name_of_params).enumerate() {
|
||||
let value = Some(ir::Operand::register(
|
||||
ir::RegisterId::arg(bid_init, i),
|
||||
dtype.clone(),
|
||||
));
|
||||
let _unused = self.translate_alloc(var.clone(), dtype, value, context)?;
|
||||
self.phinodes_init
|
||||
.push(Named::new(Some(var.clone()), dtype.clone()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn translate_alloc(
|
||||
&mut self,
|
||||
var: String,
|
||||
dtype: &ir::Dtype,
|
||||
value: Option<ir::Operand>,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
let rid = self.insert_alloc(Named::new(Some(var.clone()), dtype.clone()));
|
||||
let ptr = ir::Operand::register(rid, ir::Dtype::pointer(dtype.clone()));
|
||||
self.insert_symbol_table_entry(var, ptr.clone())?;
|
||||
|
||||
if let Some(value) = value {
|
||||
let value = self.translate_typecast(value, dtype.clone(), context)?;
|
||||
context.insert_instruction(ir::Instruction::Store { ptr, value })
|
||||
} else {
|
||||
Ok(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_typecast(
|
||||
&mut self,
|
||||
value: ir::Operand,
|
||||
dtype: ir::Dtype,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
if value.dtype() == dtype {
|
||||
return Ok(value);
|
||||
}
|
||||
context.insert_instruction(ir::Instruction::TypeCast {
|
||||
value,
|
||||
target_dtype: dtype,
|
||||
})
|
||||
}
|
||||
|
||||
fn translate_typecast_to_bool(
|
||||
&mut self,
|
||||
value: ir::Operand,
|
||||
context: &mut Context,
|
||||
) -> Result<ir::Operand, IrgenErrorMessage> {
|
||||
self.translate_typecast(value, ir::Dtype::BOOL, context) // TODO: Right?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user