mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
perform copy propagation
This commit is contained in:
parent
078c6df677
commit
f8143e3e53
4 changed files with 581 additions and 121 deletions
|
@ -256,7 +256,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
|
||||
match expr {
|
||||
Literal(literal) => build_exp_literal(env, literal),
|
||||
Alias(symbol) => load_symbol(env, scope, symbol),
|
||||
RunLowLevel(op, symbols) => run_low_level(env, scope, parent, *op, symbols),
|
||||
|
||||
FunctionCall {
|
||||
|
|
|
@ -93,7 +93,6 @@ pub fn occuring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
|
|||
|
||||
match expr {
|
||||
FunctionPointer(symbol, _)
|
||||
| Alias(symbol)
|
||||
| AccessAtIndex {
|
||||
structure: symbol, ..
|
||||
} => {
|
||||
|
@ -239,6 +238,11 @@ impl<'a> Context<'a> {
|
|||
return stmt;
|
||||
}
|
||||
|
||||
// if this symbol is never a reference, don't emit
|
||||
if !info.reference {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
self.arena.alloc(Stmt::Inc(symbol, stmt))
|
||||
}
|
||||
|
||||
|
@ -250,6 +254,11 @@ impl<'a> Context<'a> {
|
|||
return stmt;
|
||||
}
|
||||
|
||||
// if this symbol is never a reference, don't emit
|
||||
if !info.reference {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
self.arena.alloc(Stmt::Dec(symbol, stmt))
|
||||
}
|
||||
|
||||
|
@ -424,13 +433,8 @@ impl<'a> Context<'a> {
|
|||
),
|
||||
AccessAtIndex { structure: x, .. } => {
|
||||
let b = self.add_dec_if_needed(x, b, b_live_vars);
|
||||
// NOTE deviation from Lean. I think lean assumes all structure elements live on
|
||||
// the heap. Therefore any access to a Tag/Struct element must increment its
|
||||
// refcount. But in roc, structure elements can be unboxed.
|
||||
let info_x = self.get_var_info(x);
|
||||
// let info_z = self.get_var_info(z);
|
||||
let b = if info_x.consume {
|
||||
println!("inc on {}", z);
|
||||
self.add_inc(z, b)
|
||||
} else {
|
||||
b
|
||||
|
@ -489,7 +493,6 @@ impl<'a> Context<'a> {
|
|||
self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
Alias(_) => unreachable!("well, it should be unreachable!"),
|
||||
|
||||
EmptyArray | FunctionPointer(_, _) | Literal(_) | RuntimeErrorFunction(_) => {
|
||||
// EmptyArray is always stack-allocated
|
||||
|
@ -734,7 +737,8 @@ impl<'a> Context<'a> {
|
|||
(switch, case_live_vars)
|
||||
}
|
||||
|
||||
_ => todo!(),
|
||||
RuntimeError(_) | Inc(_,_) | Dec(_,_) => (stmt, MutSet::default()),
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -404,10 +404,6 @@ pub enum CallType {
|
|||
pub enum Expr<'a> {
|
||||
Literal(Literal<'a>),
|
||||
|
||||
/// A symbol will alias this symbol
|
||||
/// in the long term we should get rid of this using copy propagation
|
||||
Alias(Symbol),
|
||||
|
||||
// Functions
|
||||
FunctionPointer(Symbol, Layout<'a>),
|
||||
FunctionCall {
|
||||
|
@ -490,7 +486,6 @@ impl<'a> Expr<'a> {
|
|||
|
||||
match self {
|
||||
Literal(lit) => lit.to_doc(alloc),
|
||||
Alias(symbol) => alloc.text("alias ").append(symbol_to_doc(alloc, *symbol)),
|
||||
|
||||
FunctionPointer(symbol, _) => symbol_to_doc(alloc, *symbol),
|
||||
|
||||
|
@ -1049,7 +1044,12 @@ pub fn with_hole<'a>(
|
|||
LetNonRec(def, cont, _, _) => {
|
||||
// WRONG! this is introduces new control flow, and should call `from_can` again
|
||||
if let roc_can::pattern::Pattern::Identifier(symbol) = def.loc_pattern.value {
|
||||
let stmt = with_hole(env, cont.value, procs, layout_cache, assigned, hole);
|
||||
let mut stmt = with_hole(env, cont.value, procs, layout_cache, assigned, hole);
|
||||
|
||||
// this is an alias of a variable
|
||||
if let roc_can::expr::Expr::Var(original) = def.loc_expr.value {
|
||||
substitute_in_exprs(env.arena, &mut stmt, symbol, original);
|
||||
}
|
||||
|
||||
with_hole(
|
||||
env,
|
||||
|
@ -1060,7 +1060,51 @@ pub fn with_hole<'a>(
|
|||
env.arena.alloc(stmt),
|
||||
)
|
||||
} else {
|
||||
todo!()
|
||||
// this may be a destructure pattern
|
||||
let mono_pattern = from_can_pattern(env, layout_cache, &def.loc_pattern.value);
|
||||
|
||||
if let Pattern::Identifier(symbol) = mono_pattern {
|
||||
let hole = env
|
||||
.arena
|
||||
.alloc(from_can(env, cont.value, procs, layout_cache));
|
||||
with_hole(env, def.loc_expr.value, procs, layout_cache, symbol, hole)
|
||||
} else {
|
||||
let context = crate::exhaustive::Context::BadDestruct;
|
||||
match crate::exhaustive::check(
|
||||
def.loc_pattern.region,
|
||||
&[(
|
||||
Located::at(def.loc_pattern.region, mono_pattern.clone()),
|
||||
crate::exhaustive::Guard::NoGuard,
|
||||
)],
|
||||
context,
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(errors) => {
|
||||
for error in errors {
|
||||
env.problems.push(MonoProblem::PatternProblem(error))
|
||||
}
|
||||
} // TODO make all variables bound in the pattern evaluate to a runtime error
|
||||
// return Stmt::RuntimeError("TODO non-exhaustive pattern");
|
||||
}
|
||||
|
||||
// convert the continuation
|
||||
let mut stmt = from_can(env, cont.value, procs, layout_cache);
|
||||
|
||||
let outer_symbol = env.unique_symbol();
|
||||
stmt =
|
||||
store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt)
|
||||
.unwrap();
|
||||
|
||||
// convert the def body, store in outer_symbol
|
||||
with_hole(
|
||||
env,
|
||||
def.loc_expr.value,
|
||||
procs,
|
||||
layout_cache,
|
||||
outer_symbol,
|
||||
env.arena.alloc(stmt),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Var(symbol) => {
|
||||
|
@ -1840,24 +1884,12 @@ pub fn from_can<'a>(
|
|||
// return Stmt::RuntimeError("TODO non-exhaustive pattern");
|
||||
}
|
||||
|
||||
let layout = layout_cache
|
||||
.from_var(env.arena, def.expr_var, env.subs)
|
||||
.expect("invalid layout");
|
||||
|
||||
// convert the continuation
|
||||
let mut stmt = from_can(env, cont.value, procs, layout_cache);
|
||||
|
||||
let outer_symbol = env.unique_symbol();
|
||||
stmt = store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&mono_pattern,
|
||||
outer_symbol,
|
||||
layout,
|
||||
stmt,
|
||||
)
|
||||
.unwrap();
|
||||
stmt = store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt)
|
||||
.unwrap();
|
||||
|
||||
// convert the def body, store in outer_symbol
|
||||
with_hole(
|
||||
|
@ -2012,15 +2044,7 @@ fn from_can_when<'a>(
|
|||
|
||||
let guard_stmt = with_hole(env, loc_expr.value, procs, layout_cache, symbol, jump);
|
||||
|
||||
match store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&pattern,
|
||||
cond_symbol,
|
||||
cond_layout.clone(),
|
||||
guard_stmt,
|
||||
) {
|
||||
match store_pattern(env, procs, layout_cache, &pattern, cond_symbol, guard_stmt) {
|
||||
Ok(new_guard_stmt) => (
|
||||
pattern,
|
||||
Guard::Guard {
|
||||
|
@ -2037,15 +2061,7 @@ fn from_can_when<'a>(
|
|||
),
|
||||
}
|
||||
} else {
|
||||
match store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&pattern,
|
||||
cond_symbol,
|
||||
cond_layout.clone(),
|
||||
branch_stmt,
|
||||
) {
|
||||
match store_pattern(env, procs, layout_cache, &pattern, cond_symbol, branch_stmt) {
|
||||
Ok(new_branch_stmt) => (pattern, Guard::NoGuard, new_branch_stmt),
|
||||
Err(msg) => (
|
||||
Pattern::Underscore,
|
||||
|
@ -2068,6 +2084,363 @@ fn from_can_when<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
fn substitute(substitutions: &MutMap<Symbol, Symbol>, s: Symbol) -> Option<Symbol> {
|
||||
match substitutions.get(&s) {
|
||||
Some(new) => {
|
||||
debug_assert!(!substitutions.contains_key(new));
|
||||
Some(*new)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_in_exprs<'a>(arena: &'a Bump, stmt: &mut Stmt<'a>, from: Symbol, to: Symbol) {
|
||||
let mut subs = MutMap::default();
|
||||
subs.insert(from, to);
|
||||
|
||||
// TODO clean this up
|
||||
let ref_stmt = arena.alloc(stmt.clone());
|
||||
if let Some(new) = substitute_in_stmt_help(arena, ref_stmt, &subs) {
|
||||
*stmt = new.clone();
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_in_stmt_help<'a>(
|
||||
arena: &'a Bump,
|
||||
stmt: &'a Stmt<'a>,
|
||||
subs: &MutMap<Symbol, Symbol>,
|
||||
) -> Option<&'a Stmt<'a>> {
|
||||
use Stmt::*;
|
||||
|
||||
match stmt {
|
||||
Let(symbol, expr, layout, cont) => {
|
||||
let opt_cont = substitute_in_stmt_help(arena, cont, subs);
|
||||
let opt_expr = substitute_in_expr(arena, expr, subs);
|
||||
|
||||
if opt_expr.is_some() || opt_cont.is_some() {
|
||||
let cont = opt_cont.unwrap_or(cont);
|
||||
let expr = opt_expr.unwrap_or_else(|| expr.clone());
|
||||
|
||||
Some(arena.alloc(Let(*symbol, expr, layout.clone(), cont)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Join {
|
||||
id,
|
||||
parameters,
|
||||
remainder,
|
||||
continuation,
|
||||
} => {
|
||||
let opt_remainder = substitute_in_stmt_help(arena, remainder, subs);
|
||||
let opt_continuation = substitute_in_stmt_help(arena, continuation, subs);
|
||||
|
||||
if opt_remainder.is_some() || opt_continuation.is_some() {
|
||||
let remainder = opt_remainder.unwrap_or(remainder);
|
||||
let continuation = opt_continuation.unwrap_or_else(|| *continuation);
|
||||
|
||||
Some(arena.alloc(Join {
|
||||
id: *id,
|
||||
parameters,
|
||||
remainder,
|
||||
continuation,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Cond {
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branching_symbol,
|
||||
branching_layout,
|
||||
pass,
|
||||
fail,
|
||||
ret_layout,
|
||||
} => {
|
||||
let opt_pass = substitute_in_stmt_help(arena, pass, subs);
|
||||
let opt_fail = substitute_in_stmt_help(arena, fail, subs);
|
||||
|
||||
if opt_pass.is_some() || opt_fail.is_some() {
|
||||
let pass = opt_pass.unwrap_or(pass);
|
||||
let fail = opt_fail.unwrap_or_else(|| *fail);
|
||||
|
||||
Some(arena.alloc(Cond {
|
||||
cond_symbol: *cond_symbol,
|
||||
cond_layout: cond_layout.clone(),
|
||||
branching_symbol: *branching_symbol,
|
||||
branching_layout: branching_layout.clone(),
|
||||
pass,
|
||||
fail,
|
||||
ret_layout: ret_layout.clone(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout,
|
||||
} => {
|
||||
let opt_default = substitute_in_stmt_help(arena, default_branch, subs);
|
||||
|
||||
let mut did_change = false;
|
||||
|
||||
let opt_branches = Vec::from_iter_in(
|
||||
branches.iter().map(|(label, branch)| {
|
||||
match substitute_in_stmt_help(arena, branch, subs) {
|
||||
None => None,
|
||||
Some(branch) => {
|
||||
did_change = true;
|
||||
Some((*label, branch.clone()))
|
||||
}
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if opt_default.is_some() || did_change {
|
||||
let default_branch = opt_default.unwrap_or(default_branch);
|
||||
|
||||
let branches = if did_change {
|
||||
let new = Vec::from_iter_in(
|
||||
opt_branches.into_iter().zip(branches.iter()).map(
|
||||
|(opt_branch, branch)| match opt_branch {
|
||||
None => branch.clone(),
|
||||
Some(new_branch) => new_branch,
|
||||
},
|
||||
),
|
||||
arena,
|
||||
);
|
||||
|
||||
new.into_bump_slice()
|
||||
} else {
|
||||
branches
|
||||
};
|
||||
|
||||
Some(arena.alloc(Switch {
|
||||
cond_symbol: *cond_symbol,
|
||||
cond_layout: cond_layout.clone(),
|
||||
default_branch,
|
||||
branches,
|
||||
ret_layout: ret_layout.clone(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Ret(s) => match substitute(subs, *s) {
|
||||
Some(s) => Some(arena.alloc(Ret(s))),
|
||||
None => None,
|
||||
},
|
||||
Inc(symbol, cont) => match substitute_in_stmt_help(arena, cont, subs) {
|
||||
Some(cont) => Some(arena.alloc(Inc(*symbol, cont))),
|
||||
None => None,
|
||||
},
|
||||
Dec(symbol, cont) => match substitute_in_stmt_help(arena, cont, subs) {
|
||||
Some(cont) => Some(arena.alloc(Dec(*symbol, cont))),
|
||||
None => None,
|
||||
},
|
||||
|
||||
Jump(id, args) => {
|
||||
let mut did_change = false;
|
||||
let new_args = Vec::from_iter_in(
|
||||
args.iter().map(|s| match substitute(subs, *s) {
|
||||
None => *s,
|
||||
Some(s) => {
|
||||
did_change = true;
|
||||
s
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if did_change {
|
||||
let args = new_args.into_bump_slice();
|
||||
|
||||
Some(arena.alloc(Jump(*id, args)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeError(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_in_expr<'a>(
|
||||
arena: &'a Bump,
|
||||
expr: &'a Expr<'a>,
|
||||
subs: &MutMap<Symbol, Symbol>,
|
||||
) -> Option<Expr<'a>> {
|
||||
use Expr::*;
|
||||
|
||||
match expr {
|
||||
Literal(_) | FunctionPointer(_, _) | EmptyArray | RuntimeErrorFunction(_) => None,
|
||||
|
||||
FunctionCall {
|
||||
call_type,
|
||||
args,
|
||||
arg_layouts,
|
||||
layout,
|
||||
} => {
|
||||
let opt_call_type = match call_type {
|
||||
CallType::ByName(s) => substitute(subs, *s).map(CallType::ByName),
|
||||
CallType::ByPointer(s) => substitute(subs, *s).map(CallType::ByPointer),
|
||||
};
|
||||
|
||||
let mut did_change = false;
|
||||
let new_args = Vec::from_iter_in(
|
||||
args.iter().map(|s| match substitute(subs, *s) {
|
||||
None => *s,
|
||||
Some(s) => {
|
||||
did_change = true;
|
||||
s
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if did_change || opt_call_type.is_some() {
|
||||
let call_type = opt_call_type.unwrap_or(*call_type);
|
||||
|
||||
let args = new_args.into_bump_slice();
|
||||
|
||||
Some(FunctionCall {
|
||||
call_type,
|
||||
args,
|
||||
arg_layouts: *arg_layouts,
|
||||
layout: layout.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
RunLowLevel(op, args) => {
|
||||
let mut did_change = false;
|
||||
let new_args = Vec::from_iter_in(
|
||||
args.iter().map(|s| match substitute(subs, *s) {
|
||||
None => *s,
|
||||
Some(s) => {
|
||||
did_change = true;
|
||||
s
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if did_change {
|
||||
let args = new_args.into_bump_slice();
|
||||
|
||||
Some(RunLowLevel(*op, args))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Tag {
|
||||
tag_layout,
|
||||
tag_name,
|
||||
tag_id,
|
||||
union_size,
|
||||
arguments: args,
|
||||
} => {
|
||||
let mut did_change = false;
|
||||
let new_args = Vec::from_iter_in(
|
||||
args.iter().map(|s| match substitute(subs, *s) {
|
||||
None => *s,
|
||||
Some(s) => {
|
||||
did_change = true;
|
||||
s
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if did_change {
|
||||
let arguments = new_args.into_bump_slice();
|
||||
|
||||
Some(Tag {
|
||||
tag_layout: tag_layout.clone(),
|
||||
tag_name: tag_name.clone(),
|
||||
tag_id: *tag_id,
|
||||
union_size: *union_size,
|
||||
arguments,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Struct(args) => {
|
||||
let mut did_change = false;
|
||||
let new_args = Vec::from_iter_in(
|
||||
args.iter().map(|s| match substitute(subs, *s) {
|
||||
None => *s,
|
||||
Some(s) => {
|
||||
did_change = true;
|
||||
s
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if did_change {
|
||||
let args = new_args.into_bump_slice();
|
||||
|
||||
Some(Struct(args))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Array {
|
||||
elems: args,
|
||||
elem_layout,
|
||||
} => {
|
||||
let mut did_change = false;
|
||||
let new_args = Vec::from_iter_in(
|
||||
args.iter().map(|s| match substitute(subs, *s) {
|
||||
None => *s,
|
||||
Some(s) => {
|
||||
did_change = true;
|
||||
s
|
||||
}
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
||||
if did_change {
|
||||
let args = new_args.into_bump_slice();
|
||||
|
||||
Some(Array {
|
||||
elem_layout: elem_layout.clone(),
|
||||
elems: args,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
AccessAtIndex {
|
||||
index,
|
||||
structure,
|
||||
field_layouts,
|
||||
is_unwrapped,
|
||||
} => match substitute(subs, *structure) {
|
||||
Some(structure) => Some(AccessAtIndex {
|
||||
index: *index,
|
||||
field_layouts: *field_layouts,
|
||||
is_unwrapped: *is_unwrapped,
|
||||
structure,
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn store_pattern<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
|
@ -2075,15 +2448,13 @@ fn store_pattern<'a>(
|
|||
layout_cache: &mut LayoutCache<'a>,
|
||||
can_pat: &Pattern<'a>,
|
||||
outer_symbol: Symbol,
|
||||
layout: Layout<'a>,
|
||||
mut stmt: Stmt<'a>,
|
||||
) -> Result<Stmt<'a>, &'a str> {
|
||||
use Pattern::*;
|
||||
|
||||
match can_pat {
|
||||
Identifier(symbol) => {
|
||||
let expr = Expr::Alias(outer_symbol);
|
||||
stmt = Stmt::Let(*symbol, expr, layout, env.arena.alloc(stmt));
|
||||
substitute_in_exprs(env.arena, &mut stmt, *symbol, outer_symbol);
|
||||
}
|
||||
Underscore => {
|
||||
// do nothing
|
||||
|
@ -2134,15 +2505,7 @@ fn store_pattern<'a>(
|
|||
let symbol = env.unique_symbol();
|
||||
|
||||
// first recurse, continuing to unpack symbol
|
||||
stmt = store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
argument,
|
||||
symbol,
|
||||
arg_layout.clone(),
|
||||
stmt,
|
||||
)?;
|
||||
stmt = store_pattern(env, procs, layout_cache, argument, symbol, stmt)?;
|
||||
|
||||
// then store the symbol
|
||||
stmt = Stmt::Let(symbol, load, arg_layout.clone(), env.arena.alloc(stmt));
|
||||
|
@ -2244,15 +2607,7 @@ fn store_record_destruct<'a>(
|
|||
_ => {
|
||||
let symbol = env.unique_symbol();
|
||||
|
||||
stmt = store_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
guard_pattern,
|
||||
symbol,
|
||||
destruct.layout.clone(),
|
||||
stmt,
|
||||
)?;
|
||||
stmt = store_pattern(env, procs, layout_cache, guard_pattern, symbol, stmt)?;
|
||||
|
||||
stmt = Stmt::Let(symbol, load, destruct.layout.clone(), env.arena.alloc(stmt));
|
||||
}
|
||||
|
|
|
@ -125,14 +125,14 @@ mod test_mono {
|
|||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
let Test.2 = true;
|
||||
if Test.2 then
|
||||
let Test.0 = 1i64;
|
||||
jump Test.1 Test.0;
|
||||
let Test.3 = true;
|
||||
if Test.3 then
|
||||
let Test.1 = 1i64;
|
||||
jump Test.2 Test.1;
|
||||
else
|
||||
let Test.0 = 2i64;
|
||||
jump Test.1 Test.0;
|
||||
joinpoint Test.1 Test.0:
|
||||
let Test.1 = 2i64;
|
||||
jump Test.2 Test.1;
|
||||
joinpoint Test.2 Test.0:
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
|
@ -310,19 +310,19 @@ mod test_mono {
|
|||
indoc!(
|
||||
r#"
|
||||
procedure Num.32 (#Attr.2, #Attr.3):
|
||||
let Test.20 = 0i64;
|
||||
let Test.17 = lowlevel NotEq #Attr.3 Test.20;
|
||||
if Test.17 then
|
||||
let Test.18 = 1i64;
|
||||
let Test.19 = lowlevel NumDivUnchecked #Attr.2 #Attr.3;
|
||||
let Test.13 = Ok Test.18 Test.19;
|
||||
jump Test.14 Test.13;
|
||||
let Test.21 = 0i64;
|
||||
let Test.18 = lowlevel NotEq #Attr.3 Test.21;
|
||||
if Test.18 then
|
||||
let Test.19 = 1i64;
|
||||
let Test.20 = lowlevel NumDivUnchecked #Attr.2 #Attr.3;
|
||||
let Test.14 = Ok Test.19 Test.20;
|
||||
jump Test.15 Test.14;
|
||||
else
|
||||
let Test.15 = 0i64;
|
||||
let Test.16 = Struct {};
|
||||
let Test.13 = Err Test.15 Test.16;
|
||||
jump Test.14 Test.13;
|
||||
joinpoint Test.14 Test.13:
|
||||
let Test.16 = 0i64;
|
||||
let Test.17 = Struct {};
|
||||
let Test.14 = Err Test.16 Test.17;
|
||||
jump Test.15 Test.14;
|
||||
joinpoint Test.15 Test.13:
|
||||
ret Test.13;
|
||||
|
||||
let Test.11 = 1000i64;
|
||||
|
@ -440,14 +440,14 @@ mod test_mono {
|
|||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
let Test.3 = true;
|
||||
if Test.3 then
|
||||
let Test.0 = 1i64;
|
||||
jump Test.2 Test.0;
|
||||
let Test.4 = true;
|
||||
if Test.4 then
|
||||
let Test.2 = 1i64;
|
||||
jump Test.3 Test.2;
|
||||
else
|
||||
let Test.0 = 2i64;
|
||||
jump Test.2 Test.0;
|
||||
joinpoint Test.2 Test.0:
|
||||
let Test.2 = 2i64;
|
||||
jump Test.3 Test.2;
|
||||
joinpoint Test.3 Test.0:
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
|
@ -603,21 +603,52 @@ mod test_mono {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn list_push() {
|
||||
fn list_append_closure() {
|
||||
compiles_to_ir(
|
||||
r#"
|
||||
List.push [1] 2
|
||||
myFunction = \l -> List.append l 42
|
||||
|
||||
myFunction [ 1, 2 ]
|
||||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 (Test.2):
|
||||
let Test.6 = 42i64;
|
||||
let Test.5 = CallByName List.5 Test.2 Test.6;
|
||||
ret Test.5;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let Test.7 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret Test.7;
|
||||
|
||||
let Test.8 = 1i64;
|
||||
let Test.9 = 2i64;
|
||||
let Test.4 = Array [Test.8, Test.9];
|
||||
let Test.3 = CallByName Test.0 Test.4;
|
||||
dec Test.4;
|
||||
ret Test.3;
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_append() {
|
||||
compiles_to_ir(
|
||||
r#"
|
||||
List.append [1] 2
|
||||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let Test.3 = lowlevel ListPush #Attr.2 #Attr.3;
|
||||
let Test.3 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret Test.3;
|
||||
|
||||
let Test.4 = 1i64;
|
||||
let Test.1 = Array [Test.4];
|
||||
let Test.2 = 2i64;
|
||||
let Test.0 = CallByName List.5 Test.1 Test.2;
|
||||
dec Test.1;
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
|
@ -635,15 +666,26 @@ mod test_mono {
|
|||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let Test.3 = lowlevel ListPush #Attr.2 #Attr.3;
|
||||
ret Test.3;
|
||||
procedure Num.14 (#Attr.2, #Attr.3):
|
||||
let Test.5 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.5;
|
||||
|
||||
let Test.4 = 1i64;
|
||||
let Test.1 = Array [Test.4];
|
||||
let Test.2 = 2i64;
|
||||
let Test.0 = CallByName List.5 Test.1 Test.2;
|
||||
ret Test.0;
|
||||
procedure List.7 (#Attr.2):
|
||||
let Test.6 = lowlevel ListLen #Attr.2;
|
||||
ret Test.6;
|
||||
|
||||
let Test.10 = 1f64;
|
||||
let Test.1 = Array [Test.10];
|
||||
let Test.7 = 1i64;
|
||||
let Test.8 = 2i64;
|
||||
let Test.9 = 3i64;
|
||||
let Test.0 = Array [Test.7, Test.8, Test.9];
|
||||
let Test.3 = CallByName List.7 Test.0;
|
||||
dec Test.0;
|
||||
let Test.4 = CallByName List.7 Test.1;
|
||||
dec Test.1;
|
||||
let Test.2 = CallByName Num.14 Test.3 Test.4;
|
||||
ret Test.2;
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -806,8 +848,30 @@ mod test_mono {
|
|||
let Test.5 = 3.14f64;
|
||||
let Test.3 = Struct {Test.4, Test.5};
|
||||
let Test.0 = Index 0 Test.3;
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_with_record_pattern_list() {
|
||||
compiles_to_ir(
|
||||
r#"
|
||||
{ x } = { x: [ 1, 3, 4 ], y: 3.14 }
|
||||
|
||||
x
|
||||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
let Test.6 = 1i64;
|
||||
let Test.7 = 3i64;
|
||||
let Test.8 = 4i64;
|
||||
let Test.4 = Array [Test.6, Test.7, Test.8];
|
||||
let Test.5 = 3.14f64;
|
||||
let Test.3 = Struct {Test.4, Test.5};
|
||||
let Test.0 = Index 0 Test.3;
|
||||
inc Test.0;
|
||||
dec Test.3;
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
|
@ -832,9 +896,8 @@ mod test_mono {
|
|||
|
||||
let Test.2 = 10i64;
|
||||
let Test.11 = true;
|
||||
let Test.0 = alias Test.2;
|
||||
let Test.7 = 5i64;
|
||||
let Test.6 = CallByName Bool.5 Test.0 Test.7;
|
||||
let Test.6 = CallByName Bool.5 Test.2 Test.7;
|
||||
jump Test.5 Test.6;
|
||||
joinpoint Test.5 Test.12:
|
||||
let Test.10 = lowlevel And Test.12 Test.11;
|
||||
|
@ -852,27 +915,66 @@ mod test_mono {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn beans_example_1() {
|
||||
fn alias_variable() {
|
||||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
y = 10
|
||||
x = 5
|
||||
y = x
|
||||
|
||||
z = Num.add y y
|
||||
|
||||
z
|
||||
3
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Num.14 (#Attr.2, #Attr.3):
|
||||
let Test.3 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.3;
|
||||
let Test.0 = 5i64;
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
let Test.0 = 10i64;
|
||||
inc Test.0;
|
||||
let Test.1 = CallByName Num.14 Test.0 Test.0;
|
||||
ret Test.1;
|
||||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
x = 5
|
||||
y = x
|
||||
|
||||
y
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
let Test.0 = 5i64;
|
||||
ret Test.0;
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_store_variable() {
|
||||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
when 0 is
|
||||
1 -> 12
|
||||
a -> a
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
let Test.2 = 0i64;
|
||||
let Test.7 = true;
|
||||
let Test.8 = 1i64;
|
||||
let Test.9 = lowlevel Eq Test.8 Test.2;
|
||||
let Test.6 = lowlevel And Test.9 Test.7;
|
||||
if Test.6 then
|
||||
let Test.4 = 12i64;
|
||||
jump Test.3 Test.4;
|
||||
else
|
||||
jump Test.3 Test.2;
|
||||
joinpoint Test.3 Test.1:
|
||||
ret Test.1;
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue