diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index 22e76054ea..09890b5b12 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -763,18 +763,24 @@ pub fn listSwap( element_width: usize, index_1: usize, index_2: usize, + can_update_in_place: bool, ) callconv(.C) RocList { const size = list.len(); - if (index_1 >= size or index_2 >= size) { + if (index_1 == index_2 or index_1 >= size or index_2 >= size) { // Either index out of bounds so we just return return list; } - const newList = list.makeUnique(alignment, element_width); + const newList = blk: { + if (can_update_in_place) { + break :blk list; + } else { + break :blk list.makeUnique(alignment, element_width); + } + }; - if (newList.bytes) |source_ptr| { - swapElements(source_ptr, element_width, index_1, index_2); - } + const source_ptr = @ptrCast([*]u8, newList.bytes); + swapElements(source_ptr, element_width, index_1, index_2); return newList; } diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index e1558897e9..f47a6e7046 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -934,7 +934,9 @@ pub fn build_exp_call<'a, 'ctx, 'env>( CallType::LowLevel { op, update_mode } => { let bytes = update_mode.to_bytes(); let update_var = UpdateModeVar(&bytes); - let update_mode = func_spec_solutions.update_mode(update_var).ok(); + let update_mode = func_spec_solutions + .update_mode(update_var) + .unwrap_or(UpdateMode::Immutable); run_low_level( env, @@ -2229,13 +2231,13 @@ fn list_literal<'a, 'ctx, 'env>( } ListLiteralElement::Symbol(symbol) => { let val = load_symbol(scope, symbol); - let intval = val.into_int_value(); // here we'd like to furthermore check for intval.is_const(). // if all elements are const for LLVM, we could make the array a constant. // BUT morphic does not know about this, and could allow us to modify that // array in-place. That would cause a segfault. So, we'll have to find // constants ourselves and cannot lean on LLVM here. + is_all_constant = false; runtime_evaluated_elements.push((index, val)); @@ -4790,7 +4792,7 @@ fn run_low_level<'a, 'ctx, 'env>( layout: &Layout<'a>, op: LowLevel, args: &[Symbol], - update_mode: Option, + update_mode: UpdateMode, // expect_failed: *const (), ) -> BasicValueEnum<'ctx> { use LowLevel::*; @@ -4990,6 +4992,7 @@ fn run_low_level<'a, 'ctx, 'env>( index_1.into_int_value(), index_2.into_int_value(), element_layout, + update_mode, ), _ => unreachable!("Invalid layout {:?} in List.swap", list_layout), } @@ -5317,7 +5320,7 @@ fn run_low_level<'a, 'ctx, 'env>( index.into_int_value(), element, element_layout, - update_mode.unwrap(), + update_mode, ), _ => unreachable!("invalid dict layout"), } diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 2fe94d4cb5..93be451ddb 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -17,6 +17,16 @@ use morphic_lib::UpdateMode; use roc_builtins::bitcode; use roc_mono::layout::{Builtin, Layout, LayoutIds}; +fn pass_update_mode<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + update_mode: UpdateMode, +) -> BasicValueEnum<'ctx> { + match update_mode { + UpdateMode::Immutable => env.context.bool_type().const_zero().into(), + UpdateMode::InPlace => env.context.bool_type().const_int(1, false).into(), + } +} + fn list_returned_from_zig<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, output: BasicValueEnum<'ctx>, @@ -267,6 +277,7 @@ pub fn list_swap<'a, 'ctx, 'env>( index_1: IntValue<'ctx>, index_2: IntValue<'ctx>, element_layout: &Layout<'a>, + update_mode: UpdateMode, ) -> BasicValueEnum<'ctx> { call_bitcode_fn_returns_list( env, @@ -276,6 +287,7 @@ pub fn list_swap<'a, 'ctx, 'env>( layout_width(env, element_layout), index_1.into(), index_2.into(), + pass_update_mode(env, update_mode), ], bitcode::LIST_SWAP, )