If expressions
This commit is contained in:
parent
916b2a653e
commit
de051f71b8
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue