diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 16ea6a124a..d90d2eb43c 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -1044,22 +1044,6 @@ fn call_with_args<'a, 'ctx, 'env>( 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 => { debug_assert!(args.len() == 2); @@ -1446,12 +1430,24 @@ fn run_low_level<'a, 'ctx, 'env>( match op { ListLen => { - debug_assert!(args.len() == 1); + debug_assert_eq!(args.len(), 1); let arg = build_expr(env, layout_ids, scope, parent, &args[0].0); 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 => { debug_assert_eq!(args.len(), 2); diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 0119572017..97c598b2c6 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -6,6 +6,7 @@ pub enum LowLevel { ListLen, ListGetUnsafe, ListSetUnsafe, + ListIsEmpty, NumAdd, NumSub, NumMul, diff --git a/compiler/uniq/src/sharing.rs b/compiler/uniq/src/sharing.rs index 70d07112c4..d0c99d5d47 100644 --- a/compiler/uniq/src/sharing.rs +++ b/compiler/uniq/src/sharing.rs @@ -1,8 +1,8 @@ use roc_can::expr::Expr; use roc_collections::all::{ImMap, ImSet}; use roc_module::ident::Lowercase; +use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; -use roc_region::all::Located; use roc_types::subs::Variable; // 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); } Call(fun, loc_args, _) => { - if let Var(symbol) = fun.1.value { - // call by name - special_case_builtins(usage, symbol, loc_args); - } else { - // unknown call - annotate_usage(&fun.1.value, usage); + match fun.1.value { + Var(symbol) => { + // call by name + usage.register_unique(symbol); - for (_, arg) in loc_args { - annotate_usage(&arg.value, usage); + for (_, arg) in loc_args { + 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 } => { - todo!( - "TODO implement UNIQ RunLowLevel for {:?}({:?}) -> {:?}", - op, - args, - ret_var - ); + annotate_low_level_usage(usage, *op, args, *ret_var); } Closure(_, _, _, _, body) => { annotate_usage(&body.0.value, usage); @@ -701,75 +703,62 @@ fn get_access_chain<'a>(expr: &'a Expr, chain: &mut Vec) -> Option<&' } } -fn special_case_builtins( +fn annotate_low_level_usage( usage: &mut VarUsage, - symbol: Symbol, - loc_args: &[(Variable, Located)], + op: LowLevel, + args: &[(Variable, Expr)], + _ret_var: Variable, ) { use Expr::Var; + use LowLevel::*; use Mark::*; use Usage::*; - match symbol { - Symbol::LIST_GET => { - debug_assert!(loc_args.len() == 2); - let loc_list = &loc_args[0].1; - let loc_index = &loc_args[1].1; - - if let Var(list_var) = loc_list.value { - usage.register_with( - list_var, - &Access(Container::List, Seen, FieldAccess::list_access()), - ); - } else { - annotate_usage(&loc_list.value, usage); + match op { + ListLen | ListIsEmpty | ListGetUnsafe => { + match &args[0].1 { + Var(list_var) => { + usage.register_with( + *list_var, + &Access(Container::List, Seen, FieldAccess::list_seen()), + ); + } + list => { + annotate_usage(list, usage); + } } - annotate_usage(&loc_index.value, usage); - } - Symbol::LIST_SET => { - debug_assert!(loc_args.len() == 3); - - 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); + for (_, arg) in &args[1..] { + annotate_usage(arg, usage); } } - _ => { - usage.register_unique(symbol); + ListSetUnsafe => { + 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 { - annotate_usage(&arg.value, usage); + for (_, arg) in &args[1..] { + annotate_usage(arg, usage); + } + } + + NumAdd | NumSub | NumMul | NumGt | NumGte | NumLt | NumLte | Eq | NotEq | And | Or + | Not => { + for (_, arg) in args { + annotate_usage(&arg, usage); } } }