diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index 0183945e30..35b061baf5 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -152,6 +152,10 @@ pub fn listMapWithIndex(list: RocList, transform: Opaque, caller: Caller2, align } } +pub fn listMap2(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, old_element_width: usize, new_element_width: usize) callconv(.C) RocList { + unreachable; +} + pub fn listKeepIf(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, element_width: usize, inc: Inc, dec: Dec) callconv(.C) RocList { if (list.bytes) |source_ptr| { const size = list.len(); diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index e20d376b88..0ede0afcf4 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -7,6 +7,7 @@ const list = @import("list.zig"); comptime { exportListFn(list.listMap, "map"); + exportListFn(list.listMap2, "map2"); exportListFn(list.listMapWithIndex, "map_with_index"); exportListFn(list.listKeepIf, "keep_if"); exportListFn(list.listWalk, "walk"); diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 125099af96..bb136a82e3 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -63,6 +63,7 @@ pub const DICT_WALK: &str = "roc_builtins.dict.walk"; pub const SET_FROM_LIST: &str = "roc_builtins.dict.set_from_list"; pub const LIST_MAP: &str = "roc_builtins.list.map"; +pub const LIST_MAP2: &str = "roc_builtins.list.map2"; pub const LIST_MAP_WITH_INDEX: &str = "roc_builtins.list.map_with_index"; pub const LIST_KEEP_IF: &str = "roc_builtins.list.keep_if"; pub const LIST_KEEP_OKS: &str = "roc_builtins.list.keep_oks"; diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 506dec1253..2c4833b6f3 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -7,8 +7,8 @@ use crate::llvm::build_hash::generic_hash; use crate::llvm::build_list::{ allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat, list_contains, list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map, - list_map_with_index, list_prepend, list_repeat, list_reverse, list_set, list_single, list_sum, - list_walk, list_walk_backwards, + list_map2, list_map_with_index, list_prepend, list_repeat, list_reverse, list_set, list_single, + list_sum, list_walk, list_walk_backwards, }; use crate::llvm::build_str::{ str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, str_from_utf8, @@ -3719,6 +3719,33 @@ fn run_low_level<'a, 'ctx, 'env>( _ => unreachable!("invalid list layout"), } } + ListMap2 => { + debug_assert_eq!(args.len(), 3); + + let (list1, list1_layout) = load_symbol_and_layout(scope, &args[0]); + let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]); + + let (func, func_layout) = load_symbol_and_layout(scope, &args[2]); + + match (list1_layout, list2_layout) { + ( + Layout::Builtin(Builtin::List(_, element1_layout)), + Layout::Builtin(Builtin::List(_, element2_layout)), + ) => list_map2( + env, + layout_ids, + func, + func_layout, + list1, + list2, + element1_layout, + element2_layout, + ), + (Layout::Builtin(Builtin::EmptyList), _) + | (_, Layout::Builtin(Builtin::EmptyList)) => empty_list(env), + _ => unreachable!("invalid list layout"), + } + } ListMapWithIndex => { // List.map : List before, (before -> after) -> List after debug_assert_eq!(args.len(), 2); diff --git a/compiler/gen/src/llvm/build_list.rs b/compiler/gen/src/llvm/build_list.rs index b9ebfa7b3a..e9f3c092d2 100644 --- a/compiler/gen/src/llvm/build_list.rs +++ b/compiler/gen/src/llvm/build_list.rs @@ -1230,6 +1230,93 @@ fn list_map_generic<'a, 'ctx, 'env>( ) } +pub fn list_map2<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout_ids: &mut LayoutIds<'a>, + transform: BasicValueEnum<'ctx>, + transform_layout: &Layout<'a>, + list1: BasicValueEnum<'ctx>, + list2: BasicValueEnum<'ctx>, + element1_layout: &Layout<'a>, + element2_layout: &Layout<'a>, +) -> BasicValueEnum<'ctx> { + let builder = env.builder; + + let return_layout = match transform_layout { + Layout::FunctionPointer(_, ret) => ret, + Layout::Closure(_, _, ret) => ret, + _ => unreachable!("not a callable layout"), + }; + + let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic); + + let list1_i128 = complex_bitcast( + env.builder, + list1, + env.context.i128_type().into(), + "to_i128", + ); + + let list2_i128 = complex_bitcast( + env.builder, + list2, + env.context.i128_type().into(), + "to_i128", + ); + + let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr"); + env.builder.build_store(transform_ptr, transform); + + let argument_layouts = [element1_layout.clone(), element2_layout.clone()]; + let stepper_caller = + build_transform_caller(env, layout_ids, transform_layout, &argument_layouts) + .as_global_value() + .as_pointer_value(); + + let a_width = env + .ptr_int() + .const_int(element1_layout.stack_size(env.ptr_bytes) as u64, false); + + let b_width = env + .ptr_int() + .const_int(element2_layout.stack_size(env.ptr_bytes) as u64, false); + + let c_width = env + .ptr_int() + .const_int(return_layout.stack_size(env.ptr_bytes) as u64, false); + + let alignment = return_layout.alignment_bytes(env.ptr_bytes); + let alignment_iv = env.ptr_int().const_int(alignment as u64, false); + + let dec_a = build_dec_wrapper(env, layout_ids, element1_layout); + let dec_b = build_dec_wrapper(env, layout_ids, element2_layout); + + let output = call_bitcode_fn( + env, + &[ + list1_i128, + list2_i128, + env.builder + .build_bitcast(transform_ptr, u8_ptr, "to_opaque"), + stepper_caller.into(), + alignment_iv.into(), + a_width.into(), + b_width.into(), + c_width.into(), + dec_a.as_global_value().as_pointer_value().into(), + dec_b.as_global_value().as_pointer_value().into(), + ], + bitcode::LIST_MAP2, + ); + + complex_bitcast( + env.builder, + output, + collection(env.context, env.ptr_bytes).into(), + "from_i128", + ) +} + /// List.concat : List elem, List elem -> List elem pub fn list_concat<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>,