mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
improve reset/reuse insertion
This commit is contained in:
parent
c85cee3bc0
commit
edca61e2d6
@ -366,7 +366,7 @@ pub enum Expr<'a> {
|
||||
RuntimeError(&'a str),
|
||||
}
|
||||
|
||||
fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> &'a Expr<'a> {
|
||||
fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> Expr<'a> {
|
||||
use Expr::*;
|
||||
|
||||
match body {
|
||||
@ -397,22 +397,86 @@ fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> &'a Expr<'a> {
|
||||
)),
|
||||
);
|
||||
|
||||
env.arena.alloc(Switch {
|
||||
Switch {
|
||||
cond_symbol: *cond_symbol,
|
||||
branches: new_branches.into_bump_slice(),
|
||||
default_branch: new_default_branch,
|
||||
ret_layout: ret_layout.clone(),
|
||||
cond: *cond,
|
||||
cond_layout: cond_layout.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Cond {
|
||||
cond_symbol,
|
||||
branch_symbol,
|
||||
cond_layout,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout,
|
||||
} => {
|
||||
let stack_size = cond_layout.stack_size(env.pointer_size);
|
||||
|
||||
let new_pass = (
|
||||
pass.0,
|
||||
&*env
|
||||
.arena
|
||||
.alloc(function_d(env, *cond_symbol, stack_size as _, pass.1)),
|
||||
);
|
||||
|
||||
let new_fail = (
|
||||
fail.0,
|
||||
&*env
|
||||
.arena
|
||||
.alloc(function_d(env, *cond_symbol, stack_size as _, fail.1)),
|
||||
);
|
||||
|
||||
Cond {
|
||||
cond_symbol: *cond_symbol,
|
||||
branch_symbol: *branch_symbol,
|
||||
cond_layout: cond_layout.clone(),
|
||||
ret_layout: ret_layout.clone(),
|
||||
pass: new_pass,
|
||||
fail: new_fail,
|
||||
}
|
||||
}
|
||||
|
||||
Store(stores, body) => {
|
||||
let new_body = function_r(env, body);
|
||||
|
||||
env.arena.alloc(Store(stores, new_body))
|
||||
Store(stores, env.arena.alloc(new_body))
|
||||
}
|
||||
|
||||
_ => body,
|
||||
DecAfter(symbol, body) => {
|
||||
let new_body = function_r(env, body);
|
||||
|
||||
DecAfter(*symbol, env.arena.alloc(new_body))
|
||||
}
|
||||
|
||||
CallByName { .. }
|
||||
| CallByPointer(_, _, _)
|
||||
| RunLowLevel(_, _)
|
||||
| Tag { .. }
|
||||
| Struct(_)
|
||||
| Array { .. }
|
||||
| AccessAtIndex { .. } => {
|
||||
// TODO
|
||||
// how often are `when` expressions in one of the above?
|
||||
body.clone()
|
||||
}
|
||||
|
||||
Int(_)
|
||||
| Float(_)
|
||||
| Str(_)
|
||||
| Bool(_)
|
||||
| Byte(_)
|
||||
| Load(_)
|
||||
| EmptyArray
|
||||
| LoadWithoutIncrement(_)
|
||||
| FunctionPointer(_, _)
|
||||
| RuntimeError(_)
|
||||
| RuntimeErrorFunction(_) => body.clone(),
|
||||
|
||||
Reset(_, _) | Reuse(_, _) => unreachable!("reset/reuse should not have been inserted yet!"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,7 +486,12 @@ fn function_d<'a>(
|
||||
stack_size: usize,
|
||||
body: &'a Expr<'a>,
|
||||
) -> Expr<'a> {
|
||||
if let Some(reused) = function_s(env, z, stack_size, body) {
|
||||
let symbols = symbols_in_expr(body);
|
||||
if symbols.contains(&z) {
|
||||
return body.clone();
|
||||
}
|
||||
|
||||
if let Ok(reused) = function_s(env, z, stack_size, body) {
|
||||
Expr::Reset(z, env.arena.alloc(reused))
|
||||
} else {
|
||||
body.clone()
|
||||
@ -440,17 +509,286 @@ fn function_s<'a>(
|
||||
w: Symbol,
|
||||
stack_size: usize,
|
||||
body: &'a Expr<'a>,
|
||||
) -> Option<&'a Expr<'a>> {
|
||||
) -> Result<&'a Expr<'a>, &'a Expr<'a>> {
|
||||
use Expr::*;
|
||||
|
||||
match body {
|
||||
Expr::Tag { tag_layout, .. }
|
||||
if tag_layout.stack_size(env.pointer_size) as usize <= stack_size =>
|
||||
{
|
||||
Some(env.arena.alloc(Expr::Reuse(w, body)))
|
||||
Tag { tag_layout, .. } => {
|
||||
if tag_layout.stack_size(env.pointer_size) as usize <= stack_size {
|
||||
Ok(env.arena.alloc(Expr::Reuse(w, body)))
|
||||
} else {
|
||||
Err(body)
|
||||
}
|
||||
}
|
||||
|
||||
Array { .. } | Struct(_) => {
|
||||
// TODO
|
||||
Err(body)
|
||||
}
|
||||
|
||||
Switch {
|
||||
cond_symbol,
|
||||
branches,
|
||||
cond,
|
||||
cond_layout,
|
||||
default_branch,
|
||||
ret_layout,
|
||||
} => {
|
||||
// we can re-use `w` in each branch
|
||||
let mut has_been_reused = false;
|
||||
let mut new_branches = Vec::with_capacity_in(branches.len(), env.arena);
|
||||
for (tag, stores, branch) in branches.iter() {
|
||||
match function_s(env, *cond_symbol, stack_size as _, branch) {
|
||||
Ok(new_branch) => {
|
||||
has_been_reused = true;
|
||||
new_branches.push((*tag, *stores, new_branch.clone()));
|
||||
}
|
||||
Err(new_branch) => {
|
||||
new_branches.push((*tag, *stores, new_branch.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let new_default_branch = (
|
||||
default_branch.0,
|
||||
match function_s(env, *cond_symbol, stack_size, default_branch.1) {
|
||||
Ok(new) => {
|
||||
has_been_reused = true;
|
||||
new
|
||||
}
|
||||
Err(new) => new,
|
||||
},
|
||||
);
|
||||
let result = env.arena.alloc(Switch {
|
||||
cond_symbol: *cond_symbol,
|
||||
branches: new_branches.into_bump_slice(),
|
||||
default_branch: new_default_branch,
|
||||
ret_layout: ret_layout.clone(),
|
||||
cond: *cond,
|
||||
cond_layout: cond_layout.clone(),
|
||||
});
|
||||
|
||||
if has_been_reused {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(result)
|
||||
}
|
||||
}
|
||||
|
||||
Cond {
|
||||
cond_symbol,
|
||||
branch_symbol,
|
||||
cond_layout,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout,
|
||||
} => {
|
||||
let mut has_been_reused = false;
|
||||
let new_pass = (
|
||||
pass.0,
|
||||
match function_s(env, *cond_symbol, stack_size, pass.1) {
|
||||
Ok(new) => {
|
||||
has_been_reused = true;
|
||||
new
|
||||
}
|
||||
Err(new) => new,
|
||||
},
|
||||
);
|
||||
|
||||
let new_fail = (
|
||||
fail.0,
|
||||
match function_s(env, *cond_symbol, stack_size, fail.1) {
|
||||
Ok(new) => {
|
||||
has_been_reused = true;
|
||||
new
|
||||
}
|
||||
Err(new) => new,
|
||||
},
|
||||
);
|
||||
|
||||
let result = env.arena.alloc(Cond {
|
||||
cond_symbol: *cond_symbol,
|
||||
branch_symbol: *branch_symbol,
|
||||
cond_layout: cond_layout.clone(),
|
||||
ret_layout: ret_layout.clone(),
|
||||
pass: new_pass,
|
||||
fail: new_fail,
|
||||
});
|
||||
|
||||
if has_been_reused {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(result)
|
||||
}
|
||||
}
|
||||
|
||||
DecAfter(symbol, expr) => {
|
||||
let new_expr = function_s(env, w, stack_size, expr)?;
|
||||
|
||||
Ok(env.arena.alloc(DecAfter(*symbol, new_expr)))
|
||||
}
|
||||
|
||||
Store(stores, expr) => {
|
||||
let new_expr = function_s(env, w, stack_size, expr)?;
|
||||
|
||||
Ok(env.arena.alloc(Store(*stores, new_expr)))
|
||||
}
|
||||
|
||||
CallByName { .. } | CallByPointer(_, _, _) | RunLowLevel(_, _) | AccessAtIndex { .. } => {
|
||||
// TODO
|
||||
// how often are `Tag` expressions in one of the above?
|
||||
Err(body)
|
||||
}
|
||||
|
||||
Int(_)
|
||||
| Float(_)
|
||||
| Str(_)
|
||||
| Bool(_)
|
||||
| Byte(_)
|
||||
| Load(_)
|
||||
| EmptyArray
|
||||
| LoadWithoutIncrement(_)
|
||||
| FunctionPointer(_, _)
|
||||
| RuntimeError(_)
|
||||
| RuntimeErrorFunction(_) => Err(body),
|
||||
|
||||
Reset(_, _) | Reuse(_, _) => {
|
||||
unreachable!("reset/reuse should not have been introduced yet")
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn symbols_in_expr<'a>(initial: &Expr<'a>) -> MutSet<Symbol> {
|
||||
use Expr::*;
|
||||
let mut result = MutSet::default();
|
||||
let mut stack = vec![initial];
|
||||
|
||||
while let Some(expr) = stack.pop() {
|
||||
match expr {
|
||||
FunctionPointer(symbol, _) | LoadWithoutIncrement(symbol) | Load(symbol) => {
|
||||
result.insert(*symbol);
|
||||
}
|
||||
|
||||
Reset(symbol, expr) | Reuse(symbol, expr) => {
|
||||
result.insert(*symbol);
|
||||
stack.push(expr)
|
||||
}
|
||||
|
||||
Cond {
|
||||
cond_symbol,
|
||||
branch_symbol,
|
||||
pass,
|
||||
fail,
|
||||
..
|
||||
} => {
|
||||
result.insert(*cond_symbol);
|
||||
result.insert(*branch_symbol);
|
||||
|
||||
for (symbol, _, expr) in pass.0.iter() {
|
||||
result.insert(*symbol);
|
||||
stack.push(expr)
|
||||
}
|
||||
|
||||
for (symbol, _, expr) in fail.0.iter() {
|
||||
result.insert(*symbol);
|
||||
stack.push(expr)
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
cond,
|
||||
cond_symbol,
|
||||
branches,
|
||||
default_branch,
|
||||
..
|
||||
} => {
|
||||
stack.push(cond);
|
||||
result.insert(*cond_symbol);
|
||||
|
||||
for (_, stores, expr) in branches.iter() {
|
||||
stack.push(expr);
|
||||
|
||||
for (symbol, _, expr) in stores.iter() {
|
||||
result.insert(*symbol);
|
||||
stack.push(expr)
|
||||
}
|
||||
}
|
||||
|
||||
stack.push(default_branch.1);
|
||||
for (symbol, _, expr) in default_branch.0.iter() {
|
||||
result.insert(*symbol);
|
||||
stack.push(expr)
|
||||
}
|
||||
}
|
||||
|
||||
Store(stores, body) => {
|
||||
for (symbol, _, expr) in stores.iter() {
|
||||
result.insert(*symbol);
|
||||
stack.push(&expr)
|
||||
}
|
||||
|
||||
stack.push(body)
|
||||
}
|
||||
|
||||
DecAfter(symbol, body) => {
|
||||
result.insert(*symbol);
|
||||
stack.push(body);
|
||||
}
|
||||
|
||||
CallByName { name, args, .. } => {
|
||||
result.insert(*name);
|
||||
for (expr, _) in args.iter() {
|
||||
stack.push(expr);
|
||||
}
|
||||
}
|
||||
|
||||
CallByPointer(function, args, _) => {
|
||||
stack.push(function);
|
||||
stack.extend(args.iter());
|
||||
}
|
||||
|
||||
RunLowLevel(_, args) => {
|
||||
for (expr, _) in args.iter() {
|
||||
stack.push(expr);
|
||||
}
|
||||
}
|
||||
|
||||
Tag { arguments, .. } => {
|
||||
for (expr, _) in arguments.iter() {
|
||||
stack.push(expr);
|
||||
}
|
||||
}
|
||||
|
||||
Struct(arguments) => {
|
||||
for (expr, _) in arguments.iter() {
|
||||
stack.push(expr);
|
||||
}
|
||||
}
|
||||
|
||||
Array { elems, .. } => {
|
||||
for expr in elems.iter() {
|
||||
stack.push(expr);
|
||||
}
|
||||
}
|
||||
|
||||
AccessAtIndex { expr, .. } => {
|
||||
stack.push(expr);
|
||||
}
|
||||
|
||||
Int(_)
|
||||
| Float(_)
|
||||
| Str(_)
|
||||
| Bool(_)
|
||||
| Byte(_)
|
||||
| EmptyArray
|
||||
| RuntimeError(_)
|
||||
| RuntimeErrorFunction(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MonoProblem {
|
||||
PatternProblem(crate::pattern::Error),
|
||||
@ -466,7 +804,7 @@ impl<'a> Expr<'a> {
|
||||
let mut layout_cache = LayoutCache::default();
|
||||
|
||||
let result = from_can(env, can_expr, procs, &mut layout_cache);
|
||||
function_r(env, env.arena.alloc(result)).clone()
|
||||
function_r(env, env.arena.alloc(result))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user