If expressions

This commit is contained in:
mars 2022-03-26 18:10:15 -06:00
parent 916b2a653e
commit de051f71b8
2 changed files with 98 additions and 7 deletions

View File

@ -129,4 +129,20 @@ mod tests {
let code_fn = jit_fn::<(i64, i64), i64>(source);
assert_eq!(code_fn((2, 3)), 34);
}
#[test]
fn if_expr() {
let source = r#"
min(i64 a, i64 b) i64 {
if a > b {
b
} else {
a
}
}
"#;
let code_fn = jit_fn::<(i64, i64), i64>(source);
assert_eq!(code_fn((2, 4)), 2);
assert_eq!(code_fn((5, 3)), 3);
}
}

View File

@ -106,6 +106,7 @@ impl<'a> FunctionTranslator<'a> {
pub fn translate_expr(&mut self, expr: &ast::Expr) -> Value {
use ast::Expr::*;
match expr {
If(if_expr) => self.translate_if_expr(if_expr),
Local(name) => {
let var = self
.get_local(name)
@ -125,6 +126,52 @@ impl<'a> FunctionTranslator<'a> {
}
}
pub fn translate_if_expr(&mut self, if_expr: &ast::IfExpr) -> Value {
let ast::IfExpr {
test_expr,
then_body,
else_body,
} = if_expr;
let test_val = self.translate_expr(test_expr);
let then_block = self.builder.create_block();
let else_block = self.builder.create_block();
let merge_block = self.builder.create_block();
self.builder.append_block_param(merge_block, self.int);
self.builder.ins().brz(test_val, else_block, &[]);
self.builder.ins().jump(then_block, &[]);
let mut translate_branch = |block, body| {
self.builder.switch_to_block(block);
self.builder.seal_block(block);
let val = self.translate_branch_body(body).unwrap();
self.builder.ins().jump(merge_block, &[val]);
};
translate_branch(then_block, then_body);
translate_branch(else_block, else_body);
self.builder.switch_to_block(merge_block);
self.builder.seal_block(merge_block);
self.builder.block_params(merge_block)[0]
}
pub fn translate_branch_body(&mut self, branch_body: &ast::BranchBody) -> Option<Value> {
for stmt in branch_body.statements.iter() {
self.translate_statement(stmt);
}
if let Some(tail_expr) = &branch_body.tail_expr {
Some(self.translate_expr(tail_expr))
} else {
None
}
}
pub fn translate_binary_op(
&mut self,
op: &ast::BinaryOp,
@ -153,14 +200,42 @@ impl<'a> FunctionTranslator<'a> {
let lhs = self.translate_expr(lhs);
// TODO refactor ast to separate binary ops into types
if let Some(val) = self.translate_bool_op(op, lhs, rhs) {
val
} else {
use ast::BinaryOp::*;
let ins = self.builder.ins();
match op {
Add => ins.iadd(lhs, rhs),
Sub => ins.isub(lhs, rhs),
Mul => ins.imul(lhs, rhs),
Div => ins.udiv(lhs, rhs),
_ => unimplemented!("Binary operation: {:#?}", op),
}
}
}
pub fn translate_bool_op(
&mut self,
op: &ast::BinaryOp,
lhs: Value,
rhs: Value,
) -> Option<Value> {
use ast::BinaryOp::*;
let ins = self.builder.ins();
match op {
Add => ins.iadd(lhs, rhs),
Sub => ins.isub(lhs, rhs),
Mul => ins.imul(lhs, rhs),
Div => ins.udiv(lhs, rhs),
_ => unimplemented!("Binary operation: {:#?}", op),
if let Some(cmp) = match op {
Eq => Some(IntCC::Equal),
Neq => Some(IntCC::NotEqual),
Less => Some(IntCC::SignedLessThan),
LessEq => Some(IntCC::SignedLessThanOrEqual),
Greater => Some(IntCC::SignedGreaterThan),
GreaterEq => Some(IntCC::SignedGreaterThanOrEqual),
_ => None,
} {
let val = self.builder.ins().icmp(cmp, lhs, rhs);
Some(self.builder.ins().bint(self.int, val))
} else {
None
}
}