Skip to content

Commit

Permalink
Merge pull request #131 from sezna/alex/if-exprs
Browse files Browse the repository at this point in the history
If expressions, `@equals` intrinsic, basic `List` codegen, and other associated changes
  • Loading branch information
sezna authored Jul 26, 2024
2 parents cb4aa5c + b2bbd80 commit 3b536fc
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 56 deletions.
12 changes: 12 additions & 0 deletions petr-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ pub enum Expression {
IntrinsicCall(IntrinsicCall),
Binding(ExpressionWithBindings),
TypeConstructor(petr_utils::TypeId, Box<[SpannedItem<Expression>]>),
If(If),
}

#[derive(Clone)]
Expand All @@ -149,6 +150,13 @@ pub struct Binding {
pub val: SpannedItem<Expression>,
}

#[derive(Clone)]
pub struct If {
pub condition: Box<SpannedItem<Expression>>,
pub then_branch: Box<SpannedItem<Expression>>,
pub else_branch: Option<Box<SpannedItem<Expression>>>,
}

#[derive(Clone)]
pub struct IntrinsicCall {
pub intrinsic: Intrinsic,
Expand All @@ -168,6 +176,7 @@ impl std::fmt::Display for Intrinsic {
Intrinsic::Divide => write!(f, "divide"),
Intrinsic::Malloc => write!(f, "malloc"),
Intrinsic::SizeOf => write!(f, "size_of"),
Intrinsic::Equals => write!(f, "eq"),
}
}
}
Expand All @@ -182,6 +191,7 @@ pub enum Intrinsic {
Divide,
Malloc,
SizeOf,
Equals,
}

#[derive(Clone)]
Expand Down Expand Up @@ -249,6 +259,7 @@ pub enum Operator {
Minus,
Star,
Slash,
Eq,
}

impl Operator {
Expand All @@ -258,6 +269,7 @@ impl Operator {
Operator::Minus => "-",
Operator::Star => "*",
Operator::Slash => "/",
Operator::Eq => "=",
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions petr-ast/src/pretty_print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,36 @@ impl PrettyPrint for Expression {
Expression::Variable(v) => format!("var({})", interner.get(v.id)),
Expression::IntrinsicCall(call) => call.pretty_print(interner, indentation),
Expression::Binding(binding) => binding.pretty_print(interner, indentation + 1),
Expression::If(if_expr) => if_expr.pretty_print(interner, indentation),
}
}
}

impl PrettyPrint for If {
fn pretty_print(
&self,
interner: &SymbolInterner,
indentation: usize,
) -> String {
let If {
condition,
then_branch,
else_branch,
} = self;
format!(
"{}if {} then {}{}",
" ".repeat(indentation),
condition.pretty_print(interner, indentation),
then_branch.pretty_print(interner, indentation),
if let Some(else_branch) = else_branch {
format!(" else {}", else_branch.pretty_print(interner, indentation))
} else {
Default::default()
}
)
}
}

impl PrettyPrint for ExpressionWithBindings {
fn pretty_print(
&self,
Expand Down Expand Up @@ -268,6 +294,7 @@ impl PrettyPrint for OperatorExpression {
Operator::Minus => "-",
Operator::Star => "*",
Operator::Slash => "/",
Operator::Eq => "=",
};
format!("{}({} {})", op, lhs, rhs)
}
Expand Down
1 change: 1 addition & 0 deletions petr-fmt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ impl Formattable for Expression {
Expression::FunctionCall(f) => f.format(ctx),
Expression::IntrinsicCall(i) => i.format(ctx),
Expression::Binding(binding) => binding.format(ctx),
Expression::If(_) => todo!(),
}
}
}
Expand Down
109 changes: 80 additions & 29 deletions petr-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod opcodes;

pub use error::LoweringError;
use opcodes::*;
pub use opcodes::{DataLabel, Intrinsic, IrOpcode, Reg, ReservedRegister};
pub use opcodes::{DataLabel, Intrinsic, IrOpcode, LabelId, Reg, ReservedRegister};

pub fn lower(checker: TypeChecker) -> Result<(DataSection, Vec<IrOpcode>)> {
let lowerer = Lowerer::new(checker)?;
Expand All @@ -43,6 +43,7 @@ pub struct Lowerer {
variables_in_scope: Vec<BTreeMap<SymbolId, Reg>>,
monomorphized_functions: IndexMap<MonomorphizedFunctionId, (FunctionSignature, Function)>,
errors: Vec<SpannedItem<LoweringError>>,
label_assigner: usize,
}

#[derive(Debug, Clone)]
Expand All @@ -65,6 +66,7 @@ impl Lowerer {
type_checker,
variables_in_scope: Default::default(),
monomorphized_functions: Default::default(),
label_assigner: 0,
errors: Default::default(),
};

Expand All @@ -85,7 +87,7 @@ impl Lowerer {

// insert jump to entry point as first instr
if let Some(entry_point) = self.entry_point {
program_section.push(IrOpcode::JumpImmediate(entry_point));
program_section.push(IrOpcode::JumpImmediateFunction(entry_point));
} else {
// TODO use diagnostics here
eprintln!("Warning: Generating IR for program with no entry point");
Expand Down Expand Up @@ -196,7 +198,7 @@ impl Lowerer {
let monomorphized_func_id = self.monomorphize_function((*func, arg_petr_types.into_boxed_slice()))?;

// jump to the function
buf.push(IrOpcode::JumpImmediate(monomorphized_func_id));
buf.push(IrOpcode::JumpImmediateFunction(monomorphized_func_id));

// after returning to this function, return the register
match return_destination {
Expand All @@ -211,7 +213,33 @@ impl Lowerer {
//
Ok(buf)
},
List { .. } => todo!(),
List { elements, .. } => {
let size_of_each_elements = elements
.iter()
.map(|el| self.to_ir_type(self.type_checker.expr_ty(el)).size().num_bytes() as u64)
.sum::<u64>();
let size_of_list = size_of_each_elements * elements.len() as u64;
let size_of_list_reg = self.fresh_reg();

let mut buf = vec![];
buf.push(IrOpcode::LoadImmediate(size_of_list_reg, size_of_list));
let ReturnDestination::Reg(return_reg) = return_destination;
buf.push(IrOpcode::Malloc(return_reg, size_of_list_reg));

let mut current_offset = 0;
let current_offset_reg = self.fresh_reg();
for el in elements {
// currently this only works for types that fit in a single register,
// will need work for larger types
let reg = self.fresh_reg();
buf.append(&mut self.lower_expr(el, ReturnDestination::Reg(reg))?);
buf.push(IrOpcode::LoadImmediate(current_offset_reg, current_offset));
buf.push(IrOpcode::Add(current_offset_reg, current_offset_reg, return_reg));
buf.push(IrOpcode::WriteRegisterToMemory(reg, current_offset_reg));
current_offset += self.to_ir_type(self.type_checker.expr_ty(el)).size().num_bytes() as u64;
}
Ok(buf)
},
Unit => todo!(),
Variable { name, ty: _ } => {
let var_reg = self
Expand Down Expand Up @@ -259,9 +287,33 @@ impl Lowerer {
}
Ok(buf)
},
If {
condition,
then_branch,
else_branch,
} => {
let mut buf = vec![];
let condition_reg = self.fresh_reg();
buf.append(&mut self.lower_expr(condition, ReturnDestination::Reg(condition_reg))?);
let else_label = self.new_label();
let end_label = self.new_label();
buf.push(IrOpcode::JumpIfFalseImmediate(condition_reg, else_label));
buf.append(&mut self.lower_expr(then_branch, return_destination.clone())?);
buf.push(IrOpcode::JumpImmediate(end_label));
buf.push(IrOpcode::Label(else_label));
buf.append(&mut self.lower_expr(else_branch, return_destination)?);
buf.push(IrOpcode::Label(end_label));
Ok(buf)
},
}
}

fn new_label(&mut self) -> LabelId {
let label: LabelId = self.label_assigner.into();
self.label_assigner += 1;
label
}

fn insert_literal_data(
&mut self,
lit: &petr_typecheck::Literal,
Expand Down Expand Up @@ -301,7 +353,7 @@ impl Lowerer {
},
Arrow(_) => todo!(),
ErrorRecovery => todo!(),
List(_) => todo!(),
List(ty) => IrTy::List(Box::new(self.to_ir_type(ty))),
Infer(_, span) => {
println!("Unable to infer ty: {ty:?}");
self.errors.push(span.with_item(LoweringError::UnableToInferType));
Expand Down Expand Up @@ -368,6 +420,15 @@ impl Lowerer {
}
Ok(buf)
},
Equals(lhs, rhs) => {
let lhs_reg = self.fresh_reg();
let rhs_reg = self.fresh_reg();
buf.append(&mut self.lower_expr(lhs, ReturnDestination::Reg(lhs_reg))?);
buf.append(&mut self.lower_expr(rhs, ReturnDestination::Reg(rhs_reg))?);
let ReturnDestination::Reg(return_reg) = return_destination;
buf.push(IrOpcode::Equal(return_reg, lhs_reg, rhs_reg));
Ok(buf)
},
}
}

Expand Down Expand Up @@ -462,17 +523,7 @@ impl Lowerer {
}
}

/*
impl MonomorphizedFunction {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
label: self.id,
concrete_types: self.params.iter().map(|(_name, ty)| ty.clone()).collect(),
}
}
}
*/

#[derive(Clone)]
enum ReturnDestination {
Reg(Reg),
}
Expand Down Expand Up @@ -598,7 +649,7 @@ mod tests {
4 ld v1 datalabel0
5 push v1
6 ppc
7 jumpi monomorphizedfunctionid0
7 fjumpi monomorphizedfunctionid0
8 cp v0 rr(func return value)
9 cp rr(func return value) v0
10 ret
Expand Down Expand Up @@ -635,7 +686,7 @@ mod tests {
11 cp v7 v3
12 push v7
13 ppc
14 jumpi monomorphizedfunctionid0
14 fjumpi monomorphizedfunctionid0
15 cp v5 rr(func return value)
16 cp rr(func return value) v5
17 ret
Expand All @@ -645,7 +696,7 @@ mod tests {
20 ld v2 datalabel1
21 push v2
22 ppc
23 jumpi monomorphizedfunctionid1
23 fjumpi monomorphizedfunctionid1
24 cp v0 rr(func return value)
25 cp rr(func return value) v0
26 ret
Expand Down Expand Up @@ -679,7 +730,7 @@ mod tests {
7 ld v2 datalabel1
8 push v2
9 ppc
10 jumpi monomorphizedfunctionid0
10 fjumpi monomorphizedfunctionid0
11 cp v0 rr(func return value)
12 cp rr(func return value) v0
13 ret
Expand Down Expand Up @@ -728,15 +779,15 @@ mod tests {
17 cp v13 v3
18 push v13
19 ppc
20 jumpi monomorphizedfunctionid0
20 fjumpi monomorphizedfunctionid0
21 cp v11 rr(func return value)
22 push v11
23 ppc
24 jumpi monomorphizedfunctionid0
24 fjumpi monomorphizedfunctionid0
25 cp v9 rr(func return value)
26 push v9
27 ppc
28 jumpi monomorphizedfunctionid0
28 fjumpi monomorphizedfunctionid0
29 cp v5 rr(func return value)
30 cp rr(func return value) v5
31 ret
Expand All @@ -746,7 +797,7 @@ mod tests {
34 ld v2 datalabel1
35 push v2
36 ppc
37 jumpi monomorphizedfunctionid1
37 fjumpi monomorphizedfunctionid1
38 cp v0 rr(func return value)
39 cp rr(func return value) v0
40 ret
Expand Down Expand Up @@ -803,19 +854,19 @@ mod tests {
22 cp v18 v10
23 push v18
24 ppc
25 jumpi monomorphizedfunctionid0
25 fjumpi monomorphizedfunctionid0
26 cp v16 rr(func return value)
27 push v16
28 ppc
29 jumpi monomorphizedfunctionid0
29 fjumpi monomorphizedfunctionid0
30 cp v14 rr(func return value)
31 push v14
32 ppc
33 jumpi monomorphizedfunctionid0
33 fjumpi monomorphizedfunctionid0
34 cp v12 rr(func return value)
35 push v12
36 ppc
37 jumpi monomorphizedfunctionid0
37 fjumpi monomorphizedfunctionid0
38 cp v5 rr(func return value)
39 cp rr(func return value) v5
40 ret
Expand All @@ -825,7 +876,7 @@ mod tests {
43 ld v2 datalabel1
44 push v2
45 ppc
46 jumpi monomorphizedfunctionid1
46 fjumpi monomorphizedfunctionid1
47 cp v0 rr(func return value)
48 cp rr(func return value) v0
49 ret
Expand Down
Loading

0 comments on commit 3b536fc

Please sign in to comment.