Annotate low-level usages

This commit is contained in:
Richard Feldman 2020-06-21 21:05:57 -04:00
parent 52dfb75dc0
commit cad0a1421e
3 changed files with 75 additions and 89 deletions

View file

@ -1044,22 +1044,6 @@ fn call_with_args<'a, 'ctx, 'env>(
BasicValueEnum::IntValue(int_val) BasicValueEnum::IntValue(int_val)
} }
Symbol::LIST_LEN => {
debug_assert!(args.len() == 1);
BasicValueEnum::IntValue(load_list_len(env.builder, args[0].0.into_struct_value()))
}
Symbol::LIST_IS_EMPTY => {
debug_assert!(args.len() == 1);
let list_struct = args[0].0.into_struct_value();
let builder = env.builder;
let list_len = load_list_len(builder, list_struct);
let zero = env.ptr_int().const_zero();
let answer = builder.build_int_compare(IntPredicate::EQ, list_len, zero, "is_zero");
BasicValueEnum::IntValue(answer)
}
Symbol::INT_REM_UNSAFE => { Symbol::INT_REM_UNSAFE => {
debug_assert!(args.len() == 2); debug_assert!(args.len() == 2);
@ -1446,12 +1430,24 @@ fn run_low_level<'a, 'ctx, 'env>(
match op { match op {
ListLen => { ListLen => {
debug_assert!(args.len() == 1); debug_assert_eq!(args.len(), 1);
let arg = build_expr(env, layout_ids, scope, parent, &args[0].0); let arg = build_expr(env, layout_ids, scope, parent, &args[0].0);
BasicValueEnum::IntValue(load_list_len(env.builder, arg.into_struct_value())) BasicValueEnum::IntValue(load_list_len(env.builder, arg.into_struct_value()))
} }
ListIsEmpty => {
debug_assert_eq!(args.len(), 1);
let arg = build_expr(env, layout_ids, scope, parent, &args[0].0);
let list_struct = arg.into_struct_value();
let builder = env.builder;
let list_len = load_list_len(builder, list_struct);
let zero = env.ptr_int().const_zero();
let answer = builder.build_int_compare(IntPredicate::EQ, list_len, zero, "is_zero");
BasicValueEnum::IntValue(answer)
}
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte => { NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte => {
debug_assert_eq!(args.len(), 2); debug_assert_eq!(args.len(), 2);

View file

@ -6,6 +6,7 @@ pub enum LowLevel {
ListLen, ListLen,
ListGetUnsafe, ListGetUnsafe,
ListSetUnsafe, ListSetUnsafe,
ListIsEmpty,
NumAdd, NumAdd,
NumSub, NumSub,
NumMul, NumMul,

View file

@ -1,8 +1,8 @@
use roc_can::expr::Expr; use roc_can::expr::Expr;
use roc_collections::all::{ImMap, ImSet}; use roc_collections::all::{ImMap, ImSet};
use roc_module::ident::Lowercase; use roc_module::ident::Lowercase;
use roc_module::low_level::LowLevel;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::Located;
use roc_types::subs::Variable; use roc_types::subs::Variable;
// fake field names for container elements // fake field names for container elements
@ -618,25 +618,27 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
annotate_usage(&loc_expr.value, usage); annotate_usage(&loc_expr.value, usage);
} }
Call(fun, loc_args, _) => { Call(fun, loc_args, _) => {
if let Var(symbol) = fun.1.value { match fun.1.value {
// call by name Var(symbol) => {
special_case_builtins(usage, symbol, loc_args); // call by name
} else { usage.register_unique(symbol);
// unknown call
annotate_usage(&fun.1.value, usage);
for (_, arg) in loc_args { for (_, arg) in loc_args {
annotate_usage(&arg.value, usage); annotate_usage(&arg.value, usage);
}
}
_ => {
// unknown call
annotate_usage(&fun.1.value, usage);
for (_, arg) in loc_args {
annotate_usage(&arg.value, usage);
}
} }
} }
} }
RunLowLevel { op, args, ret_var } => { RunLowLevel { op, args, ret_var } => {
todo!( annotate_low_level_usage(usage, *op, args, *ret_var);
"TODO implement UNIQ RunLowLevel for {:?}({:?}) -> {:?}",
op,
args,
ret_var
);
} }
Closure(_, _, _, _, body) => { Closure(_, _, _, _, body) => {
annotate_usage(&body.0.value, usage); annotate_usage(&body.0.value, usage);
@ -701,75 +703,62 @@ fn get_access_chain<'a>(expr: &'a Expr, chain: &mut Vec<Lowercase>) -> Option<&'
} }
} }
fn special_case_builtins( fn annotate_low_level_usage(
usage: &mut VarUsage, usage: &mut VarUsage,
symbol: Symbol, op: LowLevel,
loc_args: &[(Variable, Located<Expr>)], args: &[(Variable, Expr)],
_ret_var: Variable,
) { ) {
use Expr::Var; use Expr::Var;
use LowLevel::*;
use Mark::*; use Mark::*;
use Usage::*; use Usage::*;
match symbol {
Symbol::LIST_GET => {
debug_assert!(loc_args.len() == 2);
let loc_list = &loc_args[0].1; match op {
let loc_index = &loc_args[1].1; ListLen | ListIsEmpty | ListGetUnsafe => {
match &args[0].1 {
if let Var(list_var) = loc_list.value { Var(list_var) => {
usage.register_with( usage.register_with(
list_var, *list_var,
&Access(Container::List, Seen, FieldAccess::list_access()), &Access(Container::List, Seen, FieldAccess::list_seen()),
); );
} else { }
annotate_usage(&loc_list.value, usage); list => {
annotate_usage(list, usage);
}
} }
annotate_usage(&loc_index.value, usage);
}
Symbol::LIST_SET => { for (_, arg) in &args[1..] {
debug_assert!(loc_args.len() == 3); annotate_usage(arg, usage);
let loc_list = &loc_args[0].1;
let loc_index = &loc_args[1].1;
let loc_value = &loc_args[2].1;
if let Var(list_var) = loc_list.value {
usage.register_with(
list_var,
&Update(
Container::List,
ImSet::default(),
FieldAccess::list_update(),
),
);
} else {
annotate_usage(&loc_list.value, usage);
}
annotate_usage(&loc_index.value, usage);
annotate_usage(&loc_value.value, usage);
}
Symbol::LIST_IS_EMPTY | Symbol::LIST_LEN => {
debug_assert!(loc_args.len() == 1);
let loc_list = &loc_args[0].1;
if let Var(list_var) = loc_list.value {
usage.register_with(
list_var,
&Access(Container::List, Seen, FieldAccess::list_seen()),
);
} else {
annotate_usage(&loc_list.value, usage);
} }
} }
_ => { ListSetUnsafe => {
usage.register_unique(symbol); match &args[0].1 {
Var(list_var) => {
usage.register_with(
*list_var,
&Update(
Container::List,
ImSet::default(),
FieldAccess::list_update(),
),
);
}
list => {
annotate_usage(list, usage);
}
}
for (_, arg) in loc_args { for (_, arg) in &args[1..] {
annotate_usage(&arg.value, usage); annotate_usage(arg, usage);
}
}
NumAdd | NumSub | NumMul | NumGt | NumGte | NumLt | NumLte | Eq | NotEq | And | Or
| Not => {
for (_, arg) in args {
annotate_usage(&arg, usage);
} }
} }
} }