feat(parser,ir,backend): Support array
This commit is contained in:
+111
-44
@@ -1,6 +1,6 @@
|
||||
use std::{collections::BTreeMap, vec};
|
||||
|
||||
use crate::{ir::types::{BinaryOp, CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}};
|
||||
use crate::{ir::types::{CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}};
|
||||
use crate::ast::types::BinaryOp as AstBinaryOp;
|
||||
use crate::ast::types::UnaryOp as AstUnaryOp;
|
||||
pub struct Generator<'a> {
|
||||
@@ -41,8 +41,8 @@ impl<'a> Generator<'a> {
|
||||
let sig = self.sema.get_function_sig(function_id);
|
||||
Function {
|
||||
name: sig.name.clone(),
|
||||
parameter_types: sig.parameter_types.iter().map(|ty| (*ty).into()).collect(),
|
||||
return_type: sig.return_type.into(),
|
||||
parameter_types: sig.parameter_types.iter().map(|ty| ty.clone().into()).collect(),
|
||||
return_type: sig.return_type.clone().into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ impl<'a> Generator<'a> {
|
||||
let mut instrs = vec![];
|
||||
let var_type = if is_global { VariableType::Global } else { VariableType::Local };
|
||||
for value in var_decl.values {
|
||||
let var = self.var_manager.declare_symbol(value.symbol, var_type, var_decl.data_type.into());
|
||||
let var = self.var_manager.declare_symbol(value.symbol, var_type, self.sema.get_symbol_type(value.symbol).into());
|
||||
if is_global {
|
||||
instrs.push(IRInstr::Declare(var));
|
||||
}
|
||||
@@ -77,10 +77,10 @@ impl<'a> Generator<'a> {
|
||||
|
||||
fn generate_func_decl(&mut self, func_decl: HirFuncDeclStmt) -> Vec<IRInstr> {
|
||||
let parameters: Vec<Variable> = func_decl.params.iter()
|
||||
.map(|param| self.var_manager.declare_symbol(param.symbol, VariableType::Local, param.param_type.into()))
|
||||
.map(|param| self.var_manager.declare_symbol(param.symbol, VariableType::Local, param.param_type.clone().into()))
|
||||
.collect();
|
||||
let temp_parameters = parameters.iter().enumerate()
|
||||
.map(|(i, param)| self.var_manager.declare_param_temp(param.data_type, i))
|
||||
.map(|(i, param)| self.var_manager.declare_param_temp(param.data_type.clone(), i))
|
||||
.collect::<Vec<_>>();
|
||||
let mut body_instrs = vec![];
|
||||
self.func_exit = Some((self.request_label(), {
|
||||
@@ -100,7 +100,7 @@ impl<'a> Generator<'a> {
|
||||
}
|
||||
body_instrs.push(IRInstr::Entry);
|
||||
parameters.iter().zip(temp_parameters.iter()).for_each(|(param, temp_param)| {
|
||||
body_instrs.push(IRInstr::Move(*param, MoveRValue::Var(*temp_param)));
|
||||
body_instrs.push(IRInstr::Move(param.clone(), MoveRValue::Var(temp_param.clone())));
|
||||
});
|
||||
body_instrs.extend(block_instrs);
|
||||
let func_exit = self.func_exit.take().unwrap();
|
||||
@@ -108,7 +108,7 @@ impl<'a> Generator<'a> {
|
||||
body_instrs.push(IRInstr::Exit(func_exit.1));
|
||||
self.var_manager.clear_local_counter();
|
||||
let mut func = self.ir_function(func_decl.sig.id);
|
||||
func.parameter_types = temp_parameters.iter().map(|v| v.data_type).collect();
|
||||
func.parameter_types = temp_parameters.iter().map(|v| v.data_type.clone()).collect();
|
||||
vec![IRInstr::DefineFunc(func, temp_parameters, body_instrs)]
|
||||
}
|
||||
fn generate_block_stmt(&mut self, block_stmt: HirBlockStmt) -> Vec<IRInstr> {
|
||||
@@ -149,7 +149,7 @@ impl<'a> Generator<'a> {
|
||||
|
||||
fn generate_return_stmt(&mut self, return_stmt: HirReturnStmt) -> Vec<IRInstr> {
|
||||
let mut instrs = vec![];
|
||||
let func_exit = self.func_exit.unwrap();
|
||||
let func_exit = self.func_exit.clone().unwrap();
|
||||
match return_stmt.value {
|
||||
Some(expr) => {
|
||||
self.current_exit_label.push(None);
|
||||
@@ -269,26 +269,49 @@ impl<'a> Generator<'a> {
|
||||
HirExprValue::IntLit(i) => {
|
||||
// TODO: convert check
|
||||
let var = self.var_manager.declare_temp(IRType::I32);
|
||||
(vec![IRInstr::Move(var, MoveRValue::ConstInt(i as i32))], Some(var))
|
||||
(vec![IRInstr::Move(var.clone(), MoveRValue::ConstInt(i as i32))], Some(var))
|
||||
},
|
||||
HirExprValue::Var(symbol) => {
|
||||
let var = self.var_manager.get_symbol(symbol).unwrap();
|
||||
(vec![], Some(var))
|
||||
if var.data_type.is_array() {
|
||||
let ptr_ty = var.data_type.decay_to_ptr().unwrap();
|
||||
let dest = self.var_manager.declare_temp(ptr_ty);
|
||||
(vec![IRInstr::GetAddr(dest.clone(), var)], Some(dest))
|
||||
} else {
|
||||
(vec![], Some(var))
|
||||
}
|
||||
},
|
||||
HirExprValue::Assign { lvalue, rvalue } => {
|
||||
let var = if let HirExprValue::Var(symbol) = lvalue.value {
|
||||
self.var_manager.get_symbol(symbol).unwrap()
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let lvalue_ty: IRType = lvalue.ty.clone().into();
|
||||
self.current_exit_label.push(None);
|
||||
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
|
||||
self.current_exit_label.pop();
|
||||
instrs.push(IRInstr::Move(var, MoveRValue::Var(rvalue_var.unwrap())));
|
||||
let temp_var = self.var_manager.declare_temp(var.data_type);
|
||||
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(var)));
|
||||
let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?;
|
||||
instrs.extend(lvalue_instrs);
|
||||
if is_addr {
|
||||
instrs.push(IRInstr::Store(target.clone(), rvalue_var.unwrap()));
|
||||
} else {
|
||||
instrs.push(IRInstr::Move(target.clone(), MoveRValue::Var(rvalue_var.unwrap())));
|
||||
}
|
||||
let temp_var = self.var_manager.declare_temp(lvalue_ty);
|
||||
if is_addr {
|
||||
instrs.push(IRInstr::Load(temp_var.clone(), target));
|
||||
} else {
|
||||
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(target)));
|
||||
}
|
||||
(instrs, Some(temp_var))
|
||||
},
|
||||
HirExprValue::ArrayAccess { array, index } => {
|
||||
let result_ty: IRType = expr.ty.clone().into();
|
||||
let (mut instrs, addr) = self.generate_array_element_addr(*array, *index)?;
|
||||
if result_ty.is_array() {
|
||||
(instrs, Some(addr))
|
||||
} else {
|
||||
let dest = self.var_manager.declare_temp(result_ty);
|
||||
instrs.push(IRInstr::Load(dest.clone(), addr));
|
||||
(instrs, Some(dest))
|
||||
}
|
||||
},
|
||||
HirExprValue::UnaryOp { op, operand } => {
|
||||
let mut parent_is_logical = true;
|
||||
let exit_passdown = if matches!(op, AstUnaryOp::Not) {
|
||||
@@ -319,26 +342,26 @@ 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);
|
||||
instrs.push(IRInstr::Move(dest_var, MoveRValue::Var(operand_var)));
|
||||
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
|
||||
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);
|
||||
instrs.push(IRInstr::Unary(dest_var, UnaryOp::Neg, operand_var));
|
||||
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
|
||||
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);
|
||||
let dest_var = self.var_manager.declare_unamed_local(operand_var.data_type.clone());
|
||||
// child will do the cmp
|
||||
if !parent_is_logical {
|
||||
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
|
||||
let final_exit = self.request_label();
|
||||
instrs.push(IRInstr::Label(exit.1));
|
||||
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(1)));
|
||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(1)));
|
||||
instrs.push(IRInstr::Goto(final_exit));
|
||||
instrs.push(IRInstr::Label(exit.0));
|
||||
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(0)));
|
||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
|
||||
instrs.push(IRInstr::Goto(final_exit));
|
||||
instrs.push(IRInstr::Label(final_exit));
|
||||
|
||||
@@ -400,21 +423,21 @@ impl<'a> Generator<'a> {
|
||||
let convert_to;
|
||||
if op.is_logical() {
|
||||
// we dont really care since we use cmp
|
||||
convert_to = left_var.data_type;
|
||||
convert_to = left_var.data_type.clone();
|
||||
} else {
|
||||
convert_to = IRType::get_elevate_result(left_var.data_type, right_var.data_type).unwrap();
|
||||
convert_to = IRType::get_elevate_result(&left_var.data_type, &right_var.data_type).unwrap();
|
||||
}
|
||||
// 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);
|
||||
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(left_var)));
|
||||
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;
|
||||
}
|
||||
let result_type;
|
||||
match op {
|
||||
AstBinaryOp::Add | AstBinaryOp::Sub | AstBinaryOp::Mul | AstBinaryOp::Div | AstBinaryOp::Mod => {
|
||||
result_type = left_var.data_type;
|
||||
result_type = left_var.data_type.clone();
|
||||
},
|
||||
AstBinaryOp::Equal | AstBinaryOp::NotEqual | AstBinaryOp::Less | AstBinaryOp::Greater | AstBinaryOp::LessEqual | AstBinaryOp::GreaterEqual
|
||||
| AstBinaryOp::And | AstBinaryOp::Or => {
|
||||
@@ -448,17 +471,17 @@ impl<'a> Generator<'a> {
|
||||
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, MoveRValue::Var(right_var)));
|
||||
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(right_var)));
|
||||
right_var = temp_var;
|
||||
}
|
||||
if !op.is_logical() {
|
||||
if let Some((true_exit, false_exit)) = parent_exit {
|
||||
let final_exit = self.request_label();
|
||||
instrs.push(IRInstr::Label(true_exit));
|
||||
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(1)));
|
||||
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, MoveRValue::ConstInt(0)));
|
||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
|
||||
instrs.push(IRInstr::Label(final_exit));
|
||||
|
||||
|
||||
@@ -468,9 +491,9 @@ impl<'a> Generator<'a> {
|
||||
return Some((instrs, Some(dest_var)));
|
||||
} else {
|
||||
if op.is_cmp() {
|
||||
instrs.push(IRInstr::Cmp(dest_var, VariableOrIntLit::Var(left_var), op.into(), VariableOrIntLit::Var(right_var)));
|
||||
instrs.push(IRInstr::Cmp(dest_var.clone(), VariableOrIntLit::Var(left_var), op.into(), VariableOrIntLit::Var(right_var)));
|
||||
} else {
|
||||
instrs.push(IRInstr::Binary(dest_var, left_var, op.into(), right_var));
|
||||
instrs.push(IRInstr::Binary(dest_var.clone(), left_var, op.into(), right_var));
|
||||
}
|
||||
}
|
||||
// if !op.is_logical() {
|
||||
@@ -504,21 +527,61 @@ impl<'a> Generator<'a> {
|
||||
let ret_variable = if matches!(func_def.return_type, IRType::Void) {
|
||||
None
|
||||
} else {
|
||||
Some(self.var_manager.declare_temp(func_def.return_type))
|
||||
Some(self.var_manager.declare_temp(func_def.return_type.clone()))
|
||||
};
|
||||
instrs.push(IRInstr::FuncCall(func_def.clone(), arg_vars, ret_variable));
|
||||
instrs.push(IRInstr::FuncCall(func_def.clone(), arg_vars, ret_variable.clone()));
|
||||
(instrs, ret_variable)
|
||||
}
|
||||
};
|
||||
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, VariableOrIntLit::Var(var.unwrap()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
||||
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))
|
||||
} else {
|
||||
Some((instrs, var))
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_lvalue(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Variable, bool)> {
|
||||
match expr.value {
|
||||
HirExprValue::Var(symbol) => {
|
||||
let var = self.var_manager.get_symbol(symbol).unwrap();
|
||||
Some((vec![], var, false))
|
||||
}
|
||||
HirExprValue::ArrayAccess { array, index } => {
|
||||
let (instrs, addr) = self.generate_array_element_addr(*array, *index)?;
|
||||
Some((instrs, addr, true))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_array_element_addr(&mut self, array: HirExpr, index: HirExpr) -> Option<(Vec<IRInstr>, Variable)> {
|
||||
let elem_ty = array.ty.indexed_type().unwrap();
|
||||
let elem_size = elem_ty.element_size_in_bytes();
|
||||
let (mut instrs, base) = match array.value {
|
||||
HirExprValue::Var(symbol) => {
|
||||
let var = self.var_manager.get_symbol(symbol).unwrap();
|
||||
if var.data_type.is_array() {
|
||||
let ptr = self.var_manager.declare_temp(var.data_type.decay_to_ptr().unwrap());
|
||||
(vec![IRInstr::GetAddr(ptr.clone(), var)], ptr)
|
||||
} else {
|
||||
(vec![], var)
|
||||
}
|
||||
}
|
||||
HirExprValue::ArrayAccess { array, index } => self.generate_array_element_addr(*array, *index)?,
|
||||
_ => self.generate_expr(array).map(|(instrs, var)| (instrs, var.unwrap()))?,
|
||||
};
|
||||
self.current_exit_label.push(None);
|
||||
let (index_instrs, index_var) = self.generate_expr(index)?;
|
||||
self.current_exit_label.pop();
|
||||
instrs.extend(index_instrs);
|
||||
let addr_ty = IRType::Ptr(Box::new(elem_ty.into()));
|
||||
let dest = self.var_manager.declare_temp(addr_ty);
|
||||
instrs.push(IRInstr::GetElementPtr(dest.clone(), base, index_var.unwrap(), elem_size));
|
||||
Some((instrs, dest))
|
||||
}
|
||||
}
|
||||
|
||||
struct VariableManager {
|
||||
@@ -551,28 +614,28 @@ impl VariableManager {
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.variable_map.insert(symbol, variable);
|
||||
self.variable_map.insert(symbol, variable.clone());
|
||||
if matches!(var_type, VariableType::Local) {
|
||||
self.local_var_type.push(variable);
|
||||
self.local_var_type.push(variable.clone());
|
||||
}
|
||||
variable
|
||||
}
|
||||
pub fn declare_temp(&mut self, var_data_type: IRType) -> Variable {
|
||||
let var = Variable { index: self.local_counter, var_type: VariableType::Temp, data_type: var_data_type };
|
||||
self.local_counter += 1;
|
||||
self.local_var_type.push(var);
|
||||
self.local_var_type.push(var.clone());
|
||||
var
|
||||
}
|
||||
pub fn declare_unamed_local(&mut self, var_data_type: IRType) -> Variable {
|
||||
let var = Variable { index: self.local_counter, var_type: VariableType::Local, data_type: var_data_type };
|
||||
self.local_counter += 1;
|
||||
self.local_var_type.push(var);
|
||||
self.local_var_type.push(var.clone());
|
||||
var
|
||||
}
|
||||
pub fn declare_param_temp(&mut self, var_data_type: IRType, param_index: usize) -> Variable {
|
||||
let var = Variable { index: self.local_counter, var_type: VariableType::ParamTemp(param_index), data_type: var_data_type };
|
||||
self.local_counter += 1;
|
||||
self.local_var_type.push(var);
|
||||
self.local_var_type.push(var.clone());
|
||||
var
|
||||
}
|
||||
pub fn clear_local_counter(&mut self) {
|
||||
@@ -670,4 +733,8 @@ mod tests {
|
||||
fn test_func() {
|
||||
test_case("12-13,58-60");
|
||||
}
|
||||
#[test]
|
||||
fn test_array() {
|
||||
test_case("4-7,11,42,71,74-78,82,84,86,90,95,96,100,101,103");
|
||||
}
|
||||
}
|
||||
|
||||
+93
-8
@@ -30,6 +30,10 @@ pub enum IRInstr {
|
||||
CondGoto(Variable, usize, usize), // condition, true label, false label
|
||||
Label(usize),
|
||||
Move(Variable, MoveRValue),
|
||||
Load(Variable, Variable),
|
||||
Store(Variable, Variable),
|
||||
GetAddr(Variable, Variable),
|
||||
GetElementPtr(Variable, Variable, Variable, usize),
|
||||
}
|
||||
|
||||
impl Display for IRInstr {
|
||||
@@ -47,7 +51,11 @@ impl Display for IRInstr {
|
||||
}
|
||||
}
|
||||
IRInstr::Move(dest, src) => write!(f, "{} = {}", dest, src),
|
||||
IRInstr::Declare(var) => write!(f, "declare {} {}", var.data_type, var),
|
||||
IRInstr::Load(dest, addr) => write!(f, "{} = *{}", dest, addr),
|
||||
IRInstr::Store(addr, value) => write!(f, "*{} = {}", addr, value),
|
||||
IRInstr::GetAddr(dest, var) => write!(f, "{} = getaddr {}", dest, var),
|
||||
IRInstr::GetElementPtr(dest, base, index, elem_size) => write!(f, "{} = gep {}, {}, {}", dest, base, index, elem_size),
|
||||
IRInstr::Declare(var) => write!(f, "declare {}", var.to_decl_string()),
|
||||
IRInstr::DefineFunc(func, args, body) => {
|
||||
let body_str = body.iter().map(|instr| format!(" {}", instr)).collect::<Vec<_>>().join("\n");
|
||||
write!(f, "define {} {{\n{}\n}}", func.to_decl_string(args), body_str)
|
||||
@@ -59,11 +67,13 @@ impl Display for IRInstr {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum IRType {
|
||||
I32,
|
||||
I1,
|
||||
Void,
|
||||
Ptr(Box<IRType>),
|
||||
Array(Box<IRType>, Vec<usize>),
|
||||
}
|
||||
impl IRType {
|
||||
pub fn size_in_bytes(&self) -> usize {
|
||||
@@ -71,13 +81,47 @@ impl IRType {
|
||||
IRType::I32 => 4,
|
||||
IRType::I1 => 1,
|
||||
IRType::Void => 0,
|
||||
IRType::Ptr(_) => 4,
|
||||
IRType::Array(elem, dims) => elem.size_in_bytes() * dims.iter().product::<usize>(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_elevate_result(lhs: IRType, rhs: IRType) -> Option<IRType> {
|
||||
pub fn is_array(&self) -> bool {
|
||||
matches!(self, IRType::Array(_, _))
|
||||
}
|
||||
|
||||
pub fn decay_to_ptr(&self) -> Option<IRType> {
|
||||
match self {
|
||||
IRType::Array(elem, dims) => {
|
||||
let pointee = if dims.len() == 1 {
|
||||
(**elem).clone()
|
||||
} else {
|
||||
IRType::Array(elem.clone(), dims[1..].to_vec())
|
||||
};
|
||||
Some(IRType::Ptr(Box::new(pointee)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn element_type(&self) -> Option<IRType> {
|
||||
match self {
|
||||
IRType::Array(elem, dims) => {
|
||||
if dims.len() == 1 {
|
||||
Some((**elem).clone())
|
||||
} else {
|
||||
Some(IRType::Array(elem.clone(), dims[1..].to_vec()))
|
||||
}
|
||||
}
|
||||
IRType::Ptr(elem) => Some((**elem).clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> {
|
||||
if lhs == rhs {
|
||||
Some(lhs)
|
||||
} else if (lhs == IRType::I32 && rhs == IRType::I1) || (lhs == IRType::I1 && rhs == IRType::I32) {
|
||||
Some(lhs.clone())
|
||||
} else if (*lhs == IRType::I32 && *rhs == IRType::I1) || (*lhs == IRType::I1 && *rhs == IRType::I32) {
|
||||
Some(IRType::I32)
|
||||
} else {
|
||||
None
|
||||
@@ -90,6 +134,30 @@ impl Display for IRType {
|
||||
IRType::I32 => write!(f, "i32"),
|
||||
IRType::Void => write!(f, "void"),
|
||||
IRType::I1 => write!(f, "i1"),
|
||||
IRType::Ptr(elem) => write!(f, "{}*", elem),
|
||||
IRType::Array(elem, dims) => {
|
||||
write!(f, "{}", elem)?;
|
||||
for dim in dims {
|
||||
write!(f, "[{}]", dim)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IRType {
|
||||
pub fn base_type_and_dims(&self) -> (&IRType, &[usize]) {
|
||||
match self {
|
||||
IRType::Array(elem, dims) => (elem.as_ref(), dims.as_slice()),
|
||||
_ => (self, &[]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scalar_base_type(&self) -> &IRType {
|
||||
match self {
|
||||
IRType::Array(elem, _) => elem.scalar_base_type(),
|
||||
IRType::Ptr(elem) => elem.scalar_base_type(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,7 +188,7 @@ pub enum VariableType {
|
||||
Local,
|
||||
Temp,
|
||||
}
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone)]
|
||||
pub struct Variable {
|
||||
// pub name: String,
|
||||
pub index: usize,
|
||||
@@ -160,6 +228,19 @@ impl Display for Variable {
|
||||
write!(f, "{}{}", prefix, self.index)
|
||||
}
|
||||
}
|
||||
impl Variable {
|
||||
pub fn to_decl_string(&self) -> String {
|
||||
match &self.data_type {
|
||||
IRType::Array(_, _) => {
|
||||
let (base_type, dims) = self.data_type.base_type_and_dims();
|
||||
let dims_str = dims.iter().map(|dim| format!("[{}]", dim)).collect::<Vec<_>>().join("");
|
||||
format!("{} {}{}", base_type, self, dims_str)
|
||||
}
|
||||
IRType::Ptr(_) => format!("{}* {}", self.data_type.scalar_base_type(), self),
|
||||
_ => format!("{} {}", self.data_type, self),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
@@ -175,7 +256,11 @@ impl Function {
|
||||
}
|
||||
|
||||
pub fn to_decl_string(&self, args: &Vec<Variable>) -> String {
|
||||
let params_str = args.iter().zip(self.parameter_types.iter()).map(|(arg, param_type)| format!("{} {}", param_type, arg)).collect::<Vec<_>>().join(", ");
|
||||
let params_str = args.iter().zip(self.parameter_types.iter()).map(|(arg, param_type)| {
|
||||
let (base_type, dims) = param_type.base_type_and_dims();
|
||||
let dims_str = dims.iter().map(|dim| format!("[{}]", dim)).collect::<Vec<_>>().join("");
|
||||
format!("{} {}{}", base_type, arg, dims_str)
|
||||
}).collect::<Vec<_>>().join(", ");
|
||||
format!("{} @{}({})", self.return_type, self.name, params_str)
|
||||
}
|
||||
}
|
||||
@@ -269,4 +354,4 @@ impl From<AstBinaryOp> for CmpOp {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user