mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Boolean and/or in cranelift
This commit is contained in:
parent
e6bee2656d
commit
f44fea42bb
4 changed files with 98 additions and 51 deletions
|
@ -5,6 +5,7 @@ use bumpalo::Bump;
|
|||
use cranelift::frontend::Switch;
|
||||
use cranelift::prelude::{
|
||||
AbiParam, ExternalName, FloatCC, FunctionBuilder, FunctionBuilderContext, IntCC, MemFlags,
|
||||
Variable,
|
||||
};
|
||||
use cranelift_codegen::ir::entities::{StackSlot, Value};
|
||||
use cranelift_codegen::ir::stackslot::{StackSlotData, StackSlotKind};
|
||||
|
@ -38,6 +39,7 @@ pub struct Env<'a> {
|
|||
pub cfg: TargetFrontendConfig,
|
||||
pub interns: Interns,
|
||||
pub malloc: FuncId,
|
||||
pub variable_counter: &'a mut u32,
|
||||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
|
@ -47,15 +49,23 @@ impl<'a> Env<'a> {
|
|||
pub fn ptr_sized_int(&self) -> Type {
|
||||
Type::int(self.cfg.pointer_bits() as u16).unwrap()
|
||||
}
|
||||
|
||||
/// Cranelift creates variables by index.
|
||||
/// For nested conditionals, we need unique variables
|
||||
pub fn fresh_variable(&mut self) -> Variable {
|
||||
let result = cranelift::frontend::Variable::with_u32(*self.variable_counter);
|
||||
*self.variable_counter += 1;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_expr<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
scope: &Scope,
|
||||
module: &mut Module<B>,
|
||||
builder: &mut FunctionBuilder,
|
||||
expr: &Expr<'a>,
|
||||
procs: &Procs<'a>,
|
||||
expr: &'a Expr<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Value {
|
||||
use roc_mono::expr::Expr::*;
|
||||
|
||||
|
@ -459,18 +469,18 @@ struct Branch2<'a> {
|
|||
}
|
||||
|
||||
fn build_branch2<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
scope: &Scope,
|
||||
module: &mut Module<B>,
|
||||
builder: &mut FunctionBuilder,
|
||||
branch: Branch2<'a>,
|
||||
procs: &Procs<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Value {
|
||||
let ret_layout = branch.ret_layout;
|
||||
let ret_type = type_from_layout(env.cfg, &ret_layout);
|
||||
// Declare a variable which each branch will mutate to be the value of that branch.
|
||||
// At the end of the expression, we will evaluate to this.
|
||||
let ret = cranelift::frontend::Variable::with_u32(0);
|
||||
let ret = env.fresh_variable();
|
||||
|
||||
// The block we'll jump to once the switch has completed.
|
||||
let ret_block = builder.create_block();
|
||||
|
@ -530,12 +540,12 @@ struct SwitchArgs<'a> {
|
|||
}
|
||||
|
||||
fn build_switch<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
scope: &Scope,
|
||||
module: &mut Module<B>,
|
||||
builder: &mut FunctionBuilder,
|
||||
switch_args: SwitchArgs<'a>,
|
||||
procs: &Procs<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Value {
|
||||
let mut switch = Switch::new();
|
||||
let SwitchArgs {
|
||||
|
@ -633,7 +643,7 @@ fn build_switch<'a, B: Backend>(
|
|||
}
|
||||
|
||||
pub fn declare_proc<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
module: &mut Module<B>,
|
||||
symbol: Symbol,
|
||||
proc: &Proc<'a>,
|
||||
|
@ -667,14 +677,14 @@ pub fn declare_proc<'a, B: Backend>(
|
|||
// TODO trim down these arguments
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn define_proc_body<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
ctx: &mut Context,
|
||||
module: &mut Module<B>,
|
||||
fn_id: FuncId,
|
||||
scope: &Scope,
|
||||
sig: Signature,
|
||||
proc: Proc<'a>,
|
||||
procs: &Procs<'a>,
|
||||
proc: &'a Proc<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) {
|
||||
let args = proc.args;
|
||||
let cfg = env.cfg;
|
||||
|
@ -721,11 +731,11 @@ pub fn define_proc_body<'a, B: Backend>(
|
|||
|
||||
fn build_arg<'a, B: Backend>(
|
||||
(arg, _): &'a (Expr<'a>, Layout<'a>),
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
scope: &Scope,
|
||||
module: &mut Module<B>,
|
||||
builder: &mut FunctionBuilder,
|
||||
procs: &Procs<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Value {
|
||||
build_expr(env, scope, module, builder, arg, procs)
|
||||
}
|
||||
|
@ -733,13 +743,13 @@ fn build_arg<'a, B: Backend>(
|
|||
#[inline(always)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn call_by_name<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
symbol: Symbol,
|
||||
args: &'a [(Expr<'a>, Layout<'a>)],
|
||||
scope: &Scope,
|
||||
module: &mut Module<B>,
|
||||
builder: &mut FunctionBuilder,
|
||||
procs: &Procs<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Value {
|
||||
match symbol {
|
||||
Symbol::INT_ADD | Symbol::NUM_ADD => {
|
||||
|
@ -810,6 +820,30 @@ fn call_by_name<'a, B: Backend>(
|
|||
|
||||
builder.ins().fcmp(FloatCC::Equal, a, b)
|
||||
}
|
||||
Symbol::BOOL_OR => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let branch2 = Branch2 {
|
||||
cond: &args[0].0,
|
||||
cond_layout: &Layout::Builtin(Builtin::Bool),
|
||||
pass: &Expr::Bool(true),
|
||||
fail: &args[1].0,
|
||||
ret_layout: &Layout::Builtin(Builtin::Bool),
|
||||
};
|
||||
build_branch2(env, scope, module, builder, branch2, procs)
|
||||
}
|
||||
Symbol::BOOL_AND => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let branch2 = Branch2 {
|
||||
cond: &args[0].0,
|
||||
cond_layout: &Layout::Builtin(Builtin::Bool),
|
||||
pass: &args[1].0,
|
||||
fail: &Expr::Bool(false),
|
||||
ret_layout: &Layout::Builtin(Builtin::Bool),
|
||||
};
|
||||
build_branch2(env, scope, module, builder, branch2, procs)
|
||||
}
|
||||
Symbol::LIST_GET_UNSAFE => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
|
@ -868,14 +902,10 @@ fn call_by_name<'a, B: Backend>(
|
|||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
let wrapper_ptr = clone_list(env, builder, module, wrapper_ptr, elem_layout);
|
||||
|
||||
list_set_in_place(
|
||||
env,
|
||||
wrapper_ptr,
|
||||
build_arg(&args[1], env, scope, module, builder, procs),
|
||||
build_arg(&args[2], env, scope, module, builder, procs),
|
||||
elem_layout,
|
||||
builder,
|
||||
);
|
||||
let arg1 = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
let arg2 = build_arg(&args[2], env, scope, module, builder, procs);
|
||||
|
||||
list_set_in_place(env, wrapper_ptr, arg1, arg2, elem_layout, builder);
|
||||
|
||||
wrapper_ptr
|
||||
}
|
||||
|
@ -892,14 +922,11 @@ fn call_by_name<'a, B: Backend>(
|
|||
let list_val = build_expr(env, scope, module, builder, list_expr, procs);
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => list_set_in_place(
|
||||
env,
|
||||
list_val,
|
||||
build_arg(&args[1], env, scope, module, builder, procs),
|
||||
build_arg(&args[2], env, scope, module, builder, procs),
|
||||
elem_layout,
|
||||
builder,
|
||||
),
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
let arg1 = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
let arg2 = build_arg(&args[2], env, scope, module, builder, procs);
|
||||
list_set_in_place(env, list_val, arg1, arg2, elem_layout, builder)
|
||||
}
|
||||
_ => {
|
||||
unreachable!("Invalid List layout for List.set: {:?}", list_layout);
|
||||
}
|
||||
|
@ -949,7 +976,7 @@ fn call_malloc<B: Backend>(
|
|||
}
|
||||
|
||||
fn list_set_in_place<'a>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a>,
|
||||
wrapper_ptr: Value,
|
||||
elem_index: Value,
|
||||
elem: Value,
|
||||
|
|
|
@ -35,6 +35,7 @@ pub struct Env<'a, 'ctx, 'env> {
|
|||
pub pointer_bytes: u32,
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn build_expr<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
|
@ -816,12 +817,14 @@ fn build_basic_phi2<'a, 'ctx, 'env>(
|
|||
|
||||
// build then block
|
||||
builder.position_at_end(then_block);
|
||||
let then_val = pass;
|
||||
builder.build_unconditional_branch(cont_block);
|
||||
|
||||
let then_block = builder.get_insert_block().unwrap();
|
||||
|
||||
// build else block
|
||||
builder.position_at_end(else_block);
|
||||
let else_val = fail;
|
||||
builder.build_unconditional_branch(cont_block);
|
||||
|
||||
let else_block = builder.get_insert_block().unwrap();
|
||||
|
@ -831,7 +834,7 @@ fn build_basic_phi2<'a, 'ctx, 'env>(
|
|||
|
||||
let phi = builder.build_phi(ret_type, "branch");
|
||||
|
||||
phi.add_incoming(&[(&pass, then_block), (&fail, else_block)]);
|
||||
phi.add_incoming(&[(&then_val, then_block), (&else_val, else_block)]);
|
||||
|
||||
phi.as_basic_value()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue