fix(sema, ir): Potential elvate bugs
This commit is contained in:
@@ -205,6 +205,12 @@ impl Parser {
|
||||
self.advance(1);
|
||||
return Ok(vec![]);
|
||||
}
|
||||
if self.peek().value == TokenValue::TypeIdent(TypeIdent::Void)
|
||||
&& self.peek_n(1).value == TokenValue::RParen
|
||||
{
|
||||
self.advance(2);
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let mut params = vec![];
|
||||
loop {
|
||||
@@ -328,6 +334,30 @@ impl Parser {
|
||||
Ok(Some(self.parse_expr()?))
|
||||
}
|
||||
|
||||
fn skip_initializer_list(&mut self) -> Result<(), ParseProcessError> {
|
||||
let mut depth = 0usize;
|
||||
loop {
|
||||
let token = self.next().clone();
|
||||
match token.value {
|
||||
TokenValue::LBrace => depth += 1,
|
||||
TokenValue::RBrace => {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
TokenValue::Eof => {
|
||||
self.diagnostics.add_from_frontend_error(
|
||||
ParseError::ExpectedBefore(TokenValue::Eof, "`}`"),
|
||||
token.span,
|
||||
);
|
||||
return Err(ParseProcessError::ErrorInMatch);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_declarator_to_var_value(
|
||||
&mut self,
|
||||
init_declarator: InitDeclarator,
|
||||
|
||||
@@ -59,6 +59,10 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
|
||||
if self.peek().value == TokenValue::Semicolon {
|
||||
self.advance(1);
|
||||
return Ok(Statement::Block(BlockStmt { statements: vec![] }));
|
||||
}
|
||||
match self.parse_var_decl_stmt(ParseType::TryParse) {
|
||||
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
|
||||
+93
-28
@@ -84,7 +84,7 @@ impl<'a> Generator<'a> {
|
||||
}
|
||||
} else if let Some(init) = value.value {
|
||||
self.current_exit_label.push(None);
|
||||
let (init_instrs, init_var) = match self.generate_expr(init) {
|
||||
let (mut init_instrs, init_var) = match self.generate_expr(init) {
|
||||
Some(res) => res,
|
||||
None => {
|
||||
self.current_exit_label.pop();
|
||||
@@ -93,8 +93,9 @@ impl<'a> Generator<'a> {
|
||||
};
|
||||
self.current_exit_label.pop();
|
||||
let target = self.var_manager.get_symbol(value.symbol).unwrap();
|
||||
let init_var = self.coerce_value(&mut init_instrs, init_var.unwrap(), &target.data_type);
|
||||
instrs.extend(init_instrs);
|
||||
instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var.unwrap())));
|
||||
instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,19 +109,26 @@ impl<'a> Generator<'a> {
|
||||
let value = Self::const_init_value(operand)?;
|
||||
match op {
|
||||
AstUnaryOp::Add => Some(value),
|
||||
AstUnaryOp::Sub => value.checked_neg(),
|
||||
AstUnaryOp::Sub => Some(value.wrapping_neg()),
|
||||
AstUnaryOp::Not => Some((value == 0) as i32),
|
||||
}
|
||||
}
|
||||
HirExprValue::BinaryOp { lhs, op, rhs } => {
|
||||
let lhs = Self::const_init_value(lhs)?;
|
||||
match op {
|
||||
AstBinaryOp::And if lhs == 0 => return Some(0),
|
||||
AstBinaryOp::Or if lhs != 0 => return Some(1),
|
||||
_ => {}
|
||||
}
|
||||
let rhs = Self::const_init_value(rhs)?;
|
||||
match op {
|
||||
AstBinaryOp::Add => lhs.checked_add(rhs),
|
||||
AstBinaryOp::Sub => lhs.checked_sub(rhs),
|
||||
AstBinaryOp::Mul => lhs.checked_mul(rhs),
|
||||
AstBinaryOp::Div => lhs.checked_div(rhs),
|
||||
AstBinaryOp::Mod => lhs.checked_rem(rhs),
|
||||
AstBinaryOp::Add => Some(lhs.wrapping_add(rhs)),
|
||||
AstBinaryOp::Sub => Some(lhs.wrapping_sub(rhs)),
|
||||
AstBinaryOp::Mul => Some(lhs.wrapping_mul(rhs)),
|
||||
AstBinaryOp::Div if rhs != 0 => Some(lhs.wrapping_div(rhs)),
|
||||
AstBinaryOp::Div => None,
|
||||
AstBinaryOp::Mod if rhs != 0 => Some(lhs.wrapping_rem(rhs)),
|
||||
AstBinaryOp::Mod => None,
|
||||
AstBinaryOp::Equal => Some((lhs == rhs) as i32),
|
||||
AstBinaryOp::NotEqual => Some((lhs != rhs) as i32),
|
||||
AstBinaryOp::Less => Some((lhs < rhs) as i32),
|
||||
@@ -214,7 +222,7 @@ impl<'a> Generator<'a> {
|
||||
match return_stmt.value {
|
||||
Some(expr) => {
|
||||
self.current_exit_label.push(None);
|
||||
let (value_instrs, value_var) = match self.generate_expr(expr) {
|
||||
let (mut value_instrs, value_var) = match self.generate_expr(expr) {
|
||||
Some(res) => res,
|
||||
None => {
|
||||
self.current_exit_label.pop();
|
||||
@@ -222,8 +230,10 @@ impl<'a> Generator<'a> {
|
||||
}
|
||||
};
|
||||
self.current_exit_label.pop();
|
||||
let target = func_exit.1.unwrap();
|
||||
let value_var = self.coerce_value(&mut value_instrs, value_var.unwrap(), &target.data_type);
|
||||
instrs.extend(value_instrs);
|
||||
instrs.push(IRInstr::Move(func_exit.1.unwrap(), MoveRValue::Var(value_var.unwrap())));
|
||||
instrs.push(IRInstr::Move(target, MoveRValue::Var(value_var)));
|
||||
}
|
||||
None => {},
|
||||
}
|
||||
@@ -387,6 +397,35 @@ impl<'a> Generator<'a> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
fn coerce_value(&mut self, instrs: &mut Vec<IRInstr>, var: Variable, target_type: &IRType) -> Variable {
|
||||
if &var.data_type == target_type {
|
||||
return var;
|
||||
}
|
||||
|
||||
match (&var.data_type, target_type) {
|
||||
(IRType::I1, IRType::I32) => {
|
||||
let dest = self.var_manager.declare_unamed_local(IRType::I32);
|
||||
let true_label = self.request_label();
|
||||
let false_label = self.request_label();
|
||||
let final_label = self.request_label();
|
||||
instrs.push(IRInstr::CondGoto(var, true_label, false_label));
|
||||
instrs.push(IRInstr::Label(true_label));
|
||||
instrs.push(IRInstr::Move(dest.clone(), MoveRValue::ConstInt(1)));
|
||||
instrs.push(IRInstr::Goto(final_label));
|
||||
instrs.push(IRInstr::Label(false_label));
|
||||
instrs.push(IRInstr::Move(dest.clone(), MoveRValue::ConstInt(0)));
|
||||
instrs.push(IRInstr::Goto(final_label));
|
||||
instrs.push(IRInstr::Label(final_label));
|
||||
dest
|
||||
}
|
||||
(IRType::I32, IRType::I1) => {
|
||||
let dest = self.var_manager.declare_temp(IRType::I1);
|
||||
instrs.push(IRInstr::Cmp(dest.clone(), VariableOrIntLit::Var(var), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
||||
dest
|
||||
}
|
||||
_ => var,
|
||||
}
|
||||
}
|
||||
fn generate_expr(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Option<Variable>)> {
|
||||
// there may be some expr that doesn't produce value, like void func call
|
||||
let (mut instrs, var) = match expr.value {
|
||||
@@ -414,6 +453,7 @@ impl<'a> Generator<'a> {
|
||||
self.current_exit_label.push(None);
|
||||
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
|
||||
self.current_exit_label.pop();
|
||||
let rvalue_var = self.coerce_value(&mut instrs, rvalue_var.unwrap(), &lvalue_ty);
|
||||
let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?;
|
||||
instrs.extend(lvalue_instrs);
|
||||
if is_addr {
|
||||
@@ -509,17 +549,22 @@ impl<'a> Generator<'a> {
|
||||
let operand_var = operand_var.unwrap();
|
||||
let dest_var = match op {
|
||||
AstUnaryOp::Add => {
|
||||
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
|
||||
let target_ty = if operand_var.data_type == IRType::I1 { IRType::I32 } else { operand_var.data_type.clone() };
|
||||
let operand_var = self.coerce_value(&mut instrs, operand_var, &target_ty);
|
||||
let dest_var = self.var_manager.declare_temp(target_ty);
|
||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::Var(operand_var)));
|
||||
dest_var
|
||||
},
|
||||
AstUnaryOp::Sub => {
|
||||
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
|
||||
let target_ty = if operand_var.data_type == IRType::I1 { IRType::I32 } else { operand_var.data_type.clone() };
|
||||
let operand_var = self.coerce_value(&mut instrs, operand_var, &target_ty);
|
||||
let dest_var = self.var_manager.declare_temp(target_ty);
|
||||
instrs.push(IRInstr::Unary(dest_var.clone(), UnaryOp::Neg, operand_var));
|
||||
dest_var
|
||||
},
|
||||
AstUnaryOp::Not => {
|
||||
let dest_var = self.var_manager.declare_unamed_local(operand_var.data_type.clone());
|
||||
let dest_ty = if parent_is_logical { IRType::I1 } else { IRType::I32 };
|
||||
let dest_var = self.var_manager.declare_unamed_local(dest_ty);
|
||||
// child will do the cmp
|
||||
if !parent_is_logical {
|
||||
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
|
||||
@@ -626,9 +671,7 @@ impl<'a> Generator<'a> {
|
||||
// do implicit convert if needed
|
||||
// TODO: further check
|
||||
if !op.is_logical() && convert_to != left_var.data_type {
|
||||
let temp_var = self.var_manager.declare_temp(convert_to.clone());
|
||||
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(left_var)));
|
||||
left_var = temp_var;
|
||||
left_var = self.coerce_value(&mut instrs, left_var, &convert_to);
|
||||
}
|
||||
let result_type;
|
||||
match op {
|
||||
@@ -640,7 +683,13 @@ impl<'a> Generator<'a> {
|
||||
result_type = IRType::I1;
|
||||
}
|
||||
}
|
||||
let dest_var = self.var_manager.declare_temp(result_type);
|
||||
let dest_var = if op.is_logical() && parent_exit.is_none() {
|
||||
self.var_manager.declare_unamed_local(IRType::I32)
|
||||
} else if op.is_logical() {
|
||||
self.var_manager.declare_unamed_local(result_type)
|
||||
} else {
|
||||
self.var_manager.declare_temp(result_type)
|
||||
};
|
||||
match op {
|
||||
AstBinaryOp::And | AstBinaryOp::Or => {
|
||||
instrs.push(IRInstr::Label(exit.unwrap().1));
|
||||
@@ -666,9 +715,7 @@ impl<'a> Generator<'a> {
|
||||
// true_exit:
|
||||
instrs.extend(right_instrs);
|
||||
if !op.is_logical() && convert_to != right_var.data_type {
|
||||
let temp_var = self.var_manager.declare_temp(convert_to);
|
||||
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(right_var)));
|
||||
right_var = temp_var;
|
||||
right_var = self.coerce_value(&mut instrs, right_var, &convert_to);
|
||||
}
|
||||
if !op.is_logical() {
|
||||
if let Some((true_exit, false_exit)) = parent_exit {
|
||||
@@ -684,6 +731,17 @@ impl<'a> Generator<'a> {
|
||||
}
|
||||
}
|
||||
if op.is_logical() {
|
||||
if parent_exit.is_none() {
|
||||
let (true_exit, _, false_exit) = exit.unwrap();
|
||||
let final_exit = self.request_label();
|
||||
instrs.push(IRInstr::Label(true_exit));
|
||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(1)));
|
||||
instrs.push(IRInstr::Goto(final_exit));
|
||||
instrs.push(IRInstr::Label(false_exit));
|
||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
|
||||
instrs.push(IRInstr::Goto(final_exit));
|
||||
instrs.push(IRInstr::Label(final_exit));
|
||||
}
|
||||
return Some((instrs, Some(dest_var)));
|
||||
} else {
|
||||
if op.is_cmp() {
|
||||
@@ -713,12 +771,13 @@ impl<'a> Generator<'a> {
|
||||
let mut arg_vars = vec![];
|
||||
let func_def = self.ir_function(func_id);
|
||||
|
||||
for arg in args.into_iter() {
|
||||
for (arg, param_type) in args.into_iter().zip(func_def.parameter_types.iter()) {
|
||||
self.current_exit_label.push(None);
|
||||
let (arg_instrs, arg_var) = self.generate_expr(arg)?;
|
||||
let (mut arg_instrs, arg_var) = self.generate_expr(arg)?;
|
||||
self.current_exit_label.pop();
|
||||
let arg_var = self.coerce_value(&mut arg_instrs, arg_var.unwrap(), param_type);
|
||||
instrs.extend(arg_instrs);
|
||||
arg_vars.push(arg_var.unwrap());
|
||||
arg_vars.push(arg_var);
|
||||
}
|
||||
let ret_variable = if matches!(func_def.return_type, IRType::Void) {
|
||||
None
|
||||
@@ -730,10 +789,15 @@ impl<'a> Generator<'a> {
|
||||
}
|
||||
};
|
||||
if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() {
|
||||
let cmp_var = self.var_manager.declare_temp(IRType::I1);
|
||||
instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone().unwrap()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
||||
instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit));
|
||||
Some((instrs, var))
|
||||
let var = var.clone().unwrap();
|
||||
if matches!(var.data_type, IRType::Array(_, _) | IRType::Ptr(_)) {
|
||||
instrs.push(IRInstr::Goto(true_exit));
|
||||
} else {
|
||||
let cmp_var = self.var_manager.declare_temp(IRType::I1);
|
||||
instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
||||
instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit));
|
||||
}
|
||||
Some((instrs, Some(var)))
|
||||
} else {
|
||||
Some((instrs, var))
|
||||
}
|
||||
@@ -777,12 +841,13 @@ impl<'a> Generator<'a> {
|
||||
let (index_instrs, index_var) = self.generate_expr(index)?;
|
||||
self.current_exit_label.pop();
|
||||
instrs.extend(index_instrs);
|
||||
let index_var = self.coerce_value(&mut instrs, index_var.unwrap(), &IRType::I32);
|
||||
let addr_ty = IRType::Ptr(Box::new(elem_ty.into()));
|
||||
let dest = self.var_manager.declare_temp(addr_ty);
|
||||
let elem_size_var = self.var_manager.declare_temp(IRType::I32);
|
||||
let offset = self.var_manager.declare_temp(IRType::I32);
|
||||
instrs.push(IRInstr::Move(elem_size_var.clone(), MoveRValue::ConstInt(elem_size as i32)));
|
||||
instrs.push(IRInstr::Binary(offset.clone(), index_var.unwrap(), AstBinaryOp::Mul.into(), elem_size_var));
|
||||
instrs.push(IRInstr::Binary(offset.clone(), index_var, AstBinaryOp::Mul.into(), elem_size_var));
|
||||
instrs.push(IRInstr::Binary(dest.clone(), base, AstBinaryOp::Add.into(), offset));
|
||||
Some((instrs, dest))
|
||||
}
|
||||
|
||||
+3
-2
@@ -124,10 +124,11 @@ impl IRType {
|
||||
}
|
||||
|
||||
pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> {
|
||||
if matches!((lhs, rhs), (IRType::I32 | IRType::I1, IRType::I32 | IRType::I1)) {
|
||||
return Some(IRType::I32);
|
||||
}
|
||||
if lhs == rhs {
|
||||
Some(lhs.clone())
|
||||
} else if (*lhs == IRType::I32 && *rhs == IRType::I1) || (*lhs == IRType::I1 && *rhs == IRType::I32) {
|
||||
Some(IRType::I32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ pub enum SemaError {
|
||||
ReturnExpressionOnVoidFunction,
|
||||
#[error("array dimension must be a positive integer literal")]
|
||||
InvalidArrayDimension,
|
||||
#[error("subscripted value is not an array or pointer")]
|
||||
NotSubscriptable,
|
||||
#[error("subscripted value of type `{0}` is not an array or pointer")]
|
||||
NotSubscriptable(SemaType),
|
||||
#[error("initializer element is not constant")]
|
||||
InitializerNotConstant,
|
||||
}
|
||||
|
||||
+3
-2
@@ -13,10 +13,11 @@ pub enum SemaType {
|
||||
|
||||
impl SemaType {
|
||||
pub fn get_elevate_result(lhs: &SemaType, rhs: &SemaType) -> Option<SemaType> {
|
||||
if matches!((lhs, rhs), (SemaType::I32 | SemaType::I1, SemaType::I32 | SemaType::I1)) {
|
||||
return Some(SemaType::I32);
|
||||
}
|
||||
if lhs == rhs {
|
||||
Some(lhs.clone())
|
||||
} else if (*lhs == SemaType::I32 && *rhs == SemaType::I1) || (*lhs == SemaType::I1 && *rhs == SemaType::I32) {
|
||||
Some(SemaType::I32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user