mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 15:59:20 +03:00
new code gen for Cond
This commit is contained in:
parent
263e4b4b6c
commit
a7af366c3a
@ -52,16 +52,14 @@ pub fn build_expr<'a, B: Backend>(
|
||||
Bool(val) => builder.ins().bconst(types::B1, *val),
|
||||
Byte(val) => builder.ins().iconst(types::I8, *val as i64),
|
||||
Cond {
|
||||
cond_lhs,
|
||||
cond_rhs,
|
||||
cond,
|
||||
pass,
|
||||
fail,
|
||||
cond_layout,
|
||||
ret_layout,
|
||||
} => {
|
||||
let branch = Branch2 {
|
||||
cond_lhs,
|
||||
cond_rhs,
|
||||
cond,
|
||||
pass,
|
||||
fail,
|
||||
cond_layout,
|
||||
@ -269,8 +267,7 @@ pub fn build_expr<'a, B: Backend>(
|
||||
}
|
||||
|
||||
struct Branch2<'a> {
|
||||
cond_lhs: &'a Expr<'a>,
|
||||
cond_rhs: &'a Expr<'a>,
|
||||
cond: &'a Expr<'a>,
|
||||
cond_layout: &'a Layout<'a>,
|
||||
pass: &'a Expr<'a>,
|
||||
fail: &'a Expr<'a>,
|
||||
@ -296,24 +293,13 @@ fn build_branch2<'a, B: Backend>(
|
||||
|
||||
builder.declare_var(ret, ret_type);
|
||||
|
||||
let lhs = build_expr(env, scope, module, builder, branch.cond_lhs, procs);
|
||||
let rhs = build_expr(env, scope, module, builder, branch.cond_rhs, procs);
|
||||
let cond = build_expr(env, scope, module, builder, branch.cond, procs);
|
||||
let pass_block = builder.create_block();
|
||||
let fail_block = builder.create_block();
|
||||
|
||||
match branch.cond_layout {
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
// For floats, first do a `fcmp` comparison to get a bool answer about equality,
|
||||
// then use `brnz` to branch if that bool equality answer was nonzero (aka true).
|
||||
let is_eq = builder.ins().fcmp(FloatCC::Equal, lhs, rhs);
|
||||
|
||||
builder.ins().brnz(is_eq, pass_block, &[]);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
// For ints, we can compare and branch in the same instruction: `icmp`
|
||||
builder
|
||||
.ins()
|
||||
.br_icmp(IntCC::Equal, lhs, rhs, pass_block, &[]);
|
||||
Layout::Builtin(Builtin::Bool(_, _)) => {
|
||||
builder.ins().brnz(cond, pass_block, &[]);
|
||||
}
|
||||
other => panic!("I don't know how to build a conditional for {:?}", other),
|
||||
}
|
||||
@ -589,6 +575,20 @@ fn call_by_name<'a, B: Backend>(
|
||||
|
||||
builder.ins().ineg(num)
|
||||
}
|
||||
Symbol::INT_EQ => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
|
||||
builder.ins().icmp(IntCC::Equal, a, b)
|
||||
}
|
||||
Symbol::FLOAT_EQ => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
|
||||
builder.ins().fcmp(FloatCC::Equal, a, b)
|
||||
}
|
||||
Symbol::LIST_GET_UNSAFE => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
|
@ -46,22 +46,20 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||
Int(num) => env.context.i64_type().const_int(*num as u64, true).into(),
|
||||
Float(num) => env.context.f64_type().const_float(*num).into(),
|
||||
Cond {
|
||||
cond_lhs,
|
||||
cond_rhs,
|
||||
cond,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout,
|
||||
..
|
||||
} => {
|
||||
let cond = Branch2 {
|
||||
cond_lhs,
|
||||
cond_rhs,
|
||||
let conditional = Branch2 {
|
||||
cond,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout: ret_layout.clone(),
|
||||
};
|
||||
|
||||
build_branch2(env, scope, parent, cond, procs)
|
||||
build_branch2(env, scope, parent, conditional, procs)
|
||||
}
|
||||
Branches { .. } => {
|
||||
panic!("TODO build_branches(env, scope, parent, cond_lhs, branches, procs)");
|
||||
@ -251,8 +249,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||
}
|
||||
|
||||
struct Branch2<'a> {
|
||||
cond_lhs: &'a Expr<'a>,
|
||||
cond_rhs: &'a Expr<'a>,
|
||||
cond: &'a Expr<'a>,
|
||||
pass: &'a Expr<'a>,
|
||||
fail: &'a Expr<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
@ -269,9 +266,9 @@ fn build_branch2<'a, 'ctx, 'env>(
|
||||
let ret_layout = cond.ret_layout;
|
||||
let ret_type = basic_type_from_layout(env.context, &ret_layout);
|
||||
|
||||
let lhs = build_expr(env, scope, parent, cond.cond_lhs, procs);
|
||||
let rhs = build_expr(env, scope, parent, cond.cond_rhs, procs);
|
||||
let cond_expr = build_expr(env, scope, parent, cond.cond, procs);
|
||||
|
||||
/*
|
||||
match (lhs, rhs) {
|
||||
(FloatValue(lhs_float), FloatValue(rhs_float)) => {
|
||||
let comparison =
|
||||
@ -294,6 +291,17 @@ fn build_branch2<'a, 'ctx, 'env>(
|
||||
cond.cond_lhs, cond.cond_rhs
|
||||
),
|
||||
}
|
||||
*/
|
||||
|
||||
match cond_expr {
|
||||
IntValue(value) => build_phi2(
|
||||
env, scope, parent, value, cond.pass, cond.fail, ret_type, procs,
|
||||
),
|
||||
_ => panic!(
|
||||
"Tried to make a branch out of an invalid condition: cond_expr = {:?}",
|
||||
cond_expr,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
struct SwitchArgs<'a, 'ctx> {
|
||||
@ -600,6 +608,30 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
}
|
||||
Symbol::INT_EQ => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let int_val = env.builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
args[0].into_int_value(),
|
||||
args[1].into_int_value(),
|
||||
"cmp_i64",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
}
|
||||
Symbol::FLOAT_EQ => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let int_val = env.builder.build_float_compare(
|
||||
FloatPredicate::OEQ,
|
||||
args[0].into_float_value(),
|
||||
args[1].into_float_value(),
|
||||
"cmp_f64",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
}
|
||||
Symbol::LIST_GET_UNSAFE => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
|
@ -591,6 +591,7 @@ define_builtins! {
|
||||
6 INT_LOWEST: "lowest"
|
||||
7 INT_ADD: "#add"
|
||||
8 INT_SUB: "#sub"
|
||||
9 INT_EQ: "#eq"
|
||||
}
|
||||
3 FLOAT: "Float" => {
|
||||
0 FLOAT_FLOAT: "Float" imported // the Float.Float type alias
|
||||
@ -603,6 +604,7 @@ define_builtins! {
|
||||
7 FLOAT_LOWEST: "lowest"
|
||||
8 FLOAT_ADD: "#add"
|
||||
9 FLOAT_SUB: "#sub"
|
||||
10 FLOAT_EQ: "#eq"
|
||||
}
|
||||
4 BOOL: "Bool" => {
|
||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
||||
|
@ -150,8 +150,7 @@ pub enum Expr<'a> {
|
||||
// The left-hand side of the conditional comparison and the right-hand side.
|
||||
// These are stored separately because there are different machine instructions
|
||||
// for e.g. "compare float and jump" vs. "compare integer and jump"
|
||||
cond_lhs: &'a Expr<'a>,
|
||||
cond_rhs: &'a Expr<'a>,
|
||||
cond: &'a Expr<'a>,
|
||||
cond_layout: Layout<'a>,
|
||||
// What to do if the condition either passes or fails
|
||||
pass: &'a Expr<'a>,
|
||||
@ -575,6 +574,34 @@ fn from_can<'a>(
|
||||
branches,
|
||||
} => from_can_when(env, cond_var, expr_var, *loc_cond, branches, procs),
|
||||
|
||||
If {
|
||||
cond_var,
|
||||
branch_var,
|
||||
branches,
|
||||
final_else,
|
||||
} => {
|
||||
let mut expr = from_can(env, final_else.value, procs, None);
|
||||
|
||||
let ret_layout = Layout::from_var(env.arena, branch_var, env.subs, env.pointer_size)
|
||||
.expect("invalid ret_layout");
|
||||
let cond_layout = Layout::from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
.expect("invalid cond_layout");
|
||||
|
||||
for (loc_cond, loc_then) in branches.into_iter().rev() {
|
||||
let cond = from_can(env, loc_cond.value, procs, None);
|
||||
let then = from_can(env, loc_then.value, procs, None);
|
||||
expr = Expr::Cond {
|
||||
cond: env.arena.alloc(cond),
|
||||
cond_layout: cond_layout.clone(),
|
||||
pass: env.arena.alloc(then),
|
||||
fail: env.arena.alloc(expr),
|
||||
ret_layout: ret_layout.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
Record(ext_var, fields) => {
|
||||
let arena = env.arena;
|
||||
let mut field_bodies = Vec::with_capacity_in(fields.len(), arena);
|
||||
@ -785,6 +812,75 @@ fn from_can_when<'a>(
|
||||
let (loc_when_pat2, loc_else) = iter.next().unwrap();
|
||||
|
||||
match (&loc_when_pat1.value, &loc_when_pat2.value) {
|
||||
(NumLiteral(var, num), Underscore) => {
|
||||
let cond_lhs = from_can(env, loc_cond.value, procs, None);
|
||||
|
||||
let (fn_symbol, builtin, cond_rhs_expr) = match to_int_or_float(env.subs, *var)
|
||||
{
|
||||
IntOrFloat::IntType => (Symbol::INT_EQ, Builtin::Int64, Expr::Int(*num)),
|
||||
IntOrFloat::FloatType => {
|
||||
(Symbol::FLOAT_EQ, Builtin::Float64, Expr::Float(*num as f64))
|
||||
}
|
||||
};
|
||||
let cond_rhs = cond_rhs_expr;
|
||||
|
||||
let cond = arena.alloc(Expr::CallByName(
|
||||
fn_symbol,
|
||||
arena.alloc([
|
||||
(cond_lhs, Layout::Builtin(builtin.clone())),
|
||||
(cond_rhs, Layout::Builtin(builtin)),
|
||||
]),
|
||||
));
|
||||
|
||||
let pass = arena.alloc(from_can(env, loc_then.value, procs, None));
|
||||
let fail = arena.alloc(from_can(env, loc_else.value, procs, None));
|
||||
let ret_layout = Layout::from_var(arena, expr_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("TODO turn this into a RuntimeError {:?}", err)
|
||||
});
|
||||
|
||||
Expr::Cond {
|
||||
cond_layout: Layout::Builtin(Builtin::Bool(
|
||||
TagName::Global("False".into()),
|
||||
TagName::Global("True".into()),
|
||||
)),
|
||||
cond,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout,
|
||||
}
|
||||
}
|
||||
(FloatLiteral(float), Underscore) => {
|
||||
let cond_lhs = from_can(env, loc_cond.value, procs, None);
|
||||
let cond_rhs = Expr::Float(*float);
|
||||
|
||||
let cond = arena.alloc(Expr::CallByName(
|
||||
Symbol::FLOAT_EQ,
|
||||
arena.alloc([
|
||||
(cond_lhs, Layout::Builtin(Builtin::Float64)),
|
||||
(cond_rhs, Layout::Builtin(Builtin::Float64)),
|
||||
]),
|
||||
));
|
||||
|
||||
let pass = arena.alloc(from_can(env, loc_then.value, procs, None));
|
||||
let fail = arena.alloc(from_can(env, loc_else.value, procs, None));
|
||||
let ret_layout = Layout::from_var(arena, expr_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("TODO turn this into a RuntimeError {:?}", err)
|
||||
});
|
||||
|
||||
Expr::Cond {
|
||||
cond_layout: Layout::Builtin(Builtin::Bool(
|
||||
TagName::Global("False".into()),
|
||||
TagName::Global("True".into()),
|
||||
)),
|
||||
cond,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout,
|
||||
}
|
||||
}
|
||||
/*
|
||||
(NumLiteral(var, num), NumLiteral(_, _)) | (NumLiteral(var, num), Underscore) => {
|
||||
let cond_lhs = arena.alloc(from_can(env, loc_cond.value, procs, None));
|
||||
let (builtin, cond_rhs_expr) = match to_int_or_float(env.subs, *var) {
|
||||
@ -847,6 +943,7 @@ fn from_can_when<'a>(
|
||||
ret_layout,
|
||||
}
|
||||
}
|
||||
*/
|
||||
_ => {
|
||||
panic!("TODO handle more conds");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user