mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
invoke in mono
This commit is contained in:
parent
ca24f1cd38
commit
0ef70f55ea
4 changed files with 421 additions and 167 deletions
|
@ -31,6 +31,21 @@ pub fn occuring_variables(stmt: &Stmt<'_>) -> (MutSet<Symbol>, MutSet<Symbol>) {
|
|||
bound_variables.insert(*symbol);
|
||||
stack.push(cont);
|
||||
}
|
||||
|
||||
Invoke {
|
||||
symbol,
|
||||
call,
|
||||
pass,
|
||||
fail,
|
||||
..
|
||||
} => {
|
||||
occuring_variables_call(call, &mut result);
|
||||
result.insert(*symbol);
|
||||
bound_variables.insert(*symbol);
|
||||
stack.push(pass);
|
||||
stack.push(fail);
|
||||
}
|
||||
|
||||
Ret(symbol) => {
|
||||
result.insert(*symbol);
|
||||
}
|
||||
|
@ -77,6 +92,12 @@ pub fn occuring_variables(stmt: &Stmt<'_>) -> (MutSet<Symbol>, MutSet<Symbol>) {
|
|||
(result, bound_variables)
|
||||
}
|
||||
|
||||
fn occuring_variables_call(call: &crate::ir::Call<'_>, result: &mut MutSet<Symbol>) {
|
||||
// NOTE though the function name does occur, it is a static constant in the program
|
||||
// for liveness, it should not be included here.
|
||||
result.extend(call.arguments.iter().copied());
|
||||
}
|
||||
|
||||
pub fn occuring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
|
||||
use Expr::*;
|
||||
|
||||
|
@ -88,11 +109,7 @@ pub fn occuring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
|
|||
result.insert(*symbol);
|
||||
}
|
||||
|
||||
Call(crate::ir::Call { arguments, .. }) => {
|
||||
// NOTE thouth the function name does occur, it is a static constant in the program
|
||||
// for liveness, it should not be included here.
|
||||
result.extend(arguments.iter().copied());
|
||||
}
|
||||
Call(call) => occuring_variables_call(call, result),
|
||||
|
||||
Tag { arguments, .. }
|
||||
| Struct(arguments)
|
||||
|
@ -204,6 +221,11 @@ fn consume_expr(m: &VarMap, e: &Expr<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn consume_call(m: &VarMap, e: &crate::ir::Call<'_>) -> bool {
|
||||
// variables bound by a call (or invoke) must always be consumed
|
||||
true
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn new(arena: &'a Bump, param_map: &'a ParamMap<'a>) -> Self {
|
||||
let mut vars = MutMap::default();
|
||||
|
@ -406,6 +428,75 @@ impl<'a> Context<'a> {
|
|||
b
|
||||
}
|
||||
|
||||
fn visit_call(
|
||||
&self,
|
||||
z: Symbol,
|
||||
call_type: crate::ir::CallType<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
l: Layout<'a>,
|
||||
b: &'a Stmt<'a>,
|
||||
b_live_vars: &LiveVarSet,
|
||||
) -> &'a Stmt<'a> {
|
||||
use crate::ir::CallType::*;
|
||||
|
||||
match &call_type {
|
||||
LowLevel { op } => {
|
||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
|
||||
let v = Expr::Call(crate::ir::Call {
|
||||
call_type,
|
||||
arguments,
|
||||
});
|
||||
|
||||
&*self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
Foreign { .. } => {
|
||||
let ps = crate::borrow::foreign_borrow_signature(self.arena, arguments.len());
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
|
||||
let v = Expr::Call(crate::ir::Call {
|
||||
call_type,
|
||||
arguments,
|
||||
});
|
||||
|
||||
&*self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
ByName {
|
||||
name, arg_layouts, ..
|
||||
}
|
||||
| ByPointer {
|
||||
name, arg_layouts, ..
|
||||
} => {
|
||||
// get the borrow signature
|
||||
let ps = match self.param_map.get_symbol(*name) {
|
||||
Some(slice) => slice,
|
||||
None => Vec::from_iter_in(
|
||||
arg_layouts.iter().cloned().map(|layout| Param {
|
||||
symbol: Symbol::UNDERSCORE,
|
||||
borrow: false,
|
||||
layout,
|
||||
}),
|
||||
self.arena,
|
||||
)
|
||||
.into_bump_slice(),
|
||||
};
|
||||
|
||||
let v = Expr::Call(crate::ir::Call {
|
||||
call_type,
|
||||
arguments,
|
||||
});
|
||||
|
||||
let b = self.add_dec_after_application(arguments, ps, b, b_live_vars);
|
||||
let b = self.arena.alloc(Stmt::Let(z, v, l, b));
|
||||
|
||||
self.add_inc_before(arguments, ps, b, b_live_vars)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn visit_variable_declaration(
|
||||
&self,
|
||||
|
@ -442,54 +533,9 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
|
||||
Call(crate::ir::Call {
|
||||
ref call_type,
|
||||
call_type,
|
||||
arguments,
|
||||
}) => {
|
||||
use crate::ir::CallType::*;
|
||||
|
||||
match &call_type {
|
||||
LowLevel { op } => {
|
||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
|
||||
&*self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
Foreign { .. } => {
|
||||
let ps =
|
||||
crate::borrow::foreign_borrow_signature(self.arena, arguments.len());
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
|
||||
&*self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
ByName {
|
||||
name, arg_layouts, ..
|
||||
}
|
||||
| ByPointer {
|
||||
name, arg_layouts, ..
|
||||
} => {
|
||||
// get the borrow signature
|
||||
let ps = match self.param_map.get_symbol(*name) {
|
||||
Some(slice) => slice,
|
||||
None => Vec::from_iter_in(
|
||||
arg_layouts.iter().cloned().map(|layout| Param {
|
||||
symbol: Symbol::UNDERSCORE,
|
||||
borrow: false,
|
||||
layout,
|
||||
}),
|
||||
self.arena,
|
||||
)
|
||||
.into_bump_slice(),
|
||||
};
|
||||
|
||||
let b = self.add_dec_after_application(arguments, ps, b, b_live_vars);
|
||||
let b = self.arena.alloc(Stmt::Let(z, v, l, b));
|
||||
|
||||
self.add_inc_before(arguments, ps, b, b_live_vars)
|
||||
}
|
||||
}
|
||||
}
|
||||
}) => self.visit_call(z, call_type, arguments, l, b, b_live_vars),
|
||||
|
||||
EmptyArray
|
||||
| FunctionPointer(_, _)
|
||||
|
@ -505,12 +551,23 @@ impl<'a> Context<'a> {
|
|||
(new_b, live_vars)
|
||||
}
|
||||
|
||||
fn update_var_info_invoke(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
layout: &Layout<'a>,
|
||||
call: &crate::ir::Call<'a>,
|
||||
) -> Self {
|
||||
// is this value a constant?
|
||||
// TODO do function pointers also fall into this category?
|
||||
let persistent = call.arguments.is_empty();
|
||||
|
||||
// must this value be consumed?
|
||||
let consume = consume_call(&self.vars, call);
|
||||
|
||||
self.update_var_info_help(symbol, layout, persistent, consume)
|
||||
}
|
||||
|
||||
fn update_var_info(&self, symbol: Symbol, layout: &Layout<'a>, expr: &Expr<'a>) -> Self {
|
||||
let mut ctx = self.clone();
|
||||
|
||||
// can this type be reference-counted at runtime?
|
||||
let reference = layout.contains_refcounted();
|
||||
|
||||
// is this value a constant?
|
||||
// TODO do function pointers also fall into this category?
|
||||
let persistent = match expr {
|
||||
|
@ -519,7 +576,20 @@ impl<'a> Context<'a> {
|
|||
};
|
||||
|
||||
// must this value be consumed?
|
||||
let consume = consume_expr(&ctx.vars, expr);
|
||||
let consume = consume_expr(&self.vars, expr);
|
||||
|
||||
self.update_var_info_help(symbol, layout, persistent, consume)
|
||||
}
|
||||
|
||||
fn update_var_info_help(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
layout: &Layout<'a>,
|
||||
persistent: bool,
|
||||
consume: bool,
|
||||
) -> Self {
|
||||
// can this type be reference-counted at runtime?
|
||||
let reference = layout.contains_refcounted();
|
||||
|
||||
let info = VarInfo {
|
||||
reference,
|
||||
|
@ -527,6 +597,8 @@ impl<'a> Context<'a> {
|
|||
consume,
|
||||
};
|
||||
|
||||
let mut ctx = self.clone();
|
||||
|
||||
ctx.vars.insert(symbol, info);
|
||||
|
||||
ctx
|
||||
|
@ -634,6 +706,46 @@ impl<'a> Context<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
Invoke {
|
||||
symbol,
|
||||
call,
|
||||
pass,
|
||||
fail,
|
||||
layout,
|
||||
} => {
|
||||
// TODO this combines parts of Let and Switch. Did this happen correctly?
|
||||
let mut case_live_vars = collect_stmt(stmt, &self.jp_live_vars, MutSet::default());
|
||||
|
||||
case_live_vars.remove(symbol);
|
||||
|
||||
let fail = {
|
||||
// TODO should we use ctor info like Lean?
|
||||
let ctx = self.clone();
|
||||
let (b, alt_live_vars) = ctx.visit_stmt(fail);
|
||||
ctx.add_dec_for_alt(&case_live_vars, &alt_live_vars, b)
|
||||
};
|
||||
|
||||
case_live_vars.insert(*symbol);
|
||||
|
||||
let pass = {
|
||||
// TODO should we use ctor info like Lean?
|
||||
let ctx = self.clone();
|
||||
let ctx = ctx.update_var_info_invoke(*symbol, layout, call);
|
||||
let (b, alt_live_vars) = ctx.visit_stmt(pass);
|
||||
ctx.add_dec_for_alt(&case_live_vars, &alt_live_vars, b)
|
||||
};
|
||||
|
||||
let invoke = Invoke {
|
||||
symbol: *symbol,
|
||||
call: call.clone(),
|
||||
pass,
|
||||
fail,
|
||||
layout: layout.clone(),
|
||||
};
|
||||
let stmt = self.arena.alloc(invoke);
|
||||
|
||||
(stmt, case_live_vars)
|
||||
}
|
||||
Join {
|
||||
id: j,
|
||||
parameters: _,
|
||||
|
@ -765,6 +877,25 @@ pub fn collect_stmt(
|
|||
|
||||
vars
|
||||
}
|
||||
Invoke {
|
||||
symbol,
|
||||
call,
|
||||
pass,
|
||||
fail,
|
||||
..
|
||||
} => {
|
||||
vars = collect_stmt(pass, jp_live_vars, vars);
|
||||
vars = collect_stmt(fail, jp_live_vars, vars);
|
||||
|
||||
vars.remove(symbol);
|
||||
|
||||
let mut result = MutSet::default();
|
||||
occuring_variables_call(call, &mut result);
|
||||
|
||||
vars.extend(result);
|
||||
|
||||
vars
|
||||
}
|
||||
Ret(symbol) => {
|
||||
vars.insert(*symbol);
|
||||
vars
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue