mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge pull request #1432 from rtfeldman/morphic-lowlevel
Morphic lowlevel
This commit is contained in:
commit
4a5df543a5
7 changed files with 73 additions and 44 deletions
|
@ -1009,7 +1009,25 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// input: RocList,
|
pub fn listSetInPlace(
|
||||||
|
bytes: ?[*]u8,
|
||||||
|
length: usize,
|
||||||
|
alignment: u32,
|
||||||
|
index: usize,
|
||||||
|
element: Opaque,
|
||||||
|
element_width: usize,
|
||||||
|
dec: Dec,
|
||||||
|
) callconv(.C) ?[*]u8 {
|
||||||
|
// INVARIANT: bounds checking happens on the roc side
|
||||||
|
//
|
||||||
|
// at the time of writing, the function is implemented roughly as
|
||||||
|
// `if inBounds then LowLevelListGet input index item else input`
|
||||||
|
// so we don't do a bounds check here. Hence, the list is also non-empty,
|
||||||
|
// because inserting into an empty list is always out of bounds
|
||||||
|
|
||||||
|
return listSetInPlaceHelp(bytes, length, alignment, index, element, element_width, dec);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn listSet(
|
pub fn listSet(
|
||||||
bytes: ?[*]u8,
|
bytes: ?[*]u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
|
@ -1028,23 +1046,34 @@ pub fn listSet(
|
||||||
const ptr: [*]usize = @ptrCast([*]usize, @alignCast(8, bytes));
|
const ptr: [*]usize = @ptrCast([*]usize, @alignCast(8, bytes));
|
||||||
|
|
||||||
if ((ptr - 1)[0] == utils.REFCOUNT_ONE) {
|
if ((ptr - 1)[0] == utils.REFCOUNT_ONE) {
|
||||||
|
return listSetInPlaceHelp(bytes, length, alignment, index, element, element_width, dec);
|
||||||
// the element we will replace
|
|
||||||
var element_at_index = (bytes orelse undefined) + (index * element_width);
|
|
||||||
|
|
||||||
// decrement its refcount
|
|
||||||
dec(element_at_index);
|
|
||||||
|
|
||||||
// copy in the new element
|
|
||||||
@memcpy(element_at_index, element orelse undefined, element_width);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
} else {
|
} else {
|
||||||
return listSetClone(bytes, length, alignment, index, element, element_width, dec);
|
return listSetImmutable(bytes, length, alignment, index, element, element_width, dec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn listSetClone(
|
inline fn listSetInPlaceHelp(
|
||||||
|
bytes: ?[*]u8,
|
||||||
|
length: usize,
|
||||||
|
alignment: u32,
|
||||||
|
index: usize,
|
||||||
|
element: Opaque,
|
||||||
|
element_width: usize,
|
||||||
|
dec: Dec,
|
||||||
|
) ?[*]u8 {
|
||||||
|
// the element we will replace
|
||||||
|
var element_at_index = (bytes orelse undefined) + (index * element_width);
|
||||||
|
|
||||||
|
// decrement its refcount
|
||||||
|
dec(element_at_index);
|
||||||
|
|
||||||
|
// copy in the new element
|
||||||
|
@memcpy(element_at_index, element orelse undefined, element_width);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn listSetImmutable(
|
||||||
old_bytes: ?[*]u8,
|
old_bytes: ?[*]u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
|
@ -1053,8 +1082,6 @@ inline fn listSetClone(
|
||||||
element_width: usize,
|
element_width: usize,
|
||||||
dec: Dec,
|
dec: Dec,
|
||||||
) ?[*]u8 {
|
) ?[*]u8 {
|
||||||
@setCold(true);
|
|
||||||
|
|
||||||
const data_bytes = length * element_width;
|
const data_bytes = length * element_width;
|
||||||
|
|
||||||
var new_bytes = utils.allocateWithRefcount(data_bytes, alignment);
|
var new_bytes = utils.allocateWithRefcount(data_bytes, alignment);
|
||||||
|
|
|
@ -30,6 +30,7 @@ comptime {
|
||||||
exportListFn(list.listConcat, "concat");
|
exportListFn(list.listConcat, "concat");
|
||||||
exportListFn(list.listDrop, "drop");
|
exportListFn(list.listDrop, "drop");
|
||||||
exportListFn(list.listSet, "set");
|
exportListFn(list.listSet, "set");
|
||||||
|
exportListFn(list.listSetInPlace, "set_in_place");
|
||||||
exportListFn(list.listSwap, "swap");
|
exportListFn(list.listSwap, "swap");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,3 +65,4 @@ pub const LIST_REVERSE: &str = "roc_builtins.list.reverse";
|
||||||
pub const LIST_SORT_WITH: &str = "roc_builtins.list.sort_with";
|
pub const LIST_SORT_WITH: &str = "roc_builtins.list.sort_with";
|
||||||
pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
||||||
pub const LIST_SET: &str = "roc_builtins.list.set";
|
pub const LIST_SET: &str = "roc_builtins.list.set";
|
||||||
|
pub const LIST_SET_IN_PLACE: &str = "roc_builtins.list.set_in_place";
|
||||||
|
|
|
@ -42,7 +42,9 @@ use inkwell::values::{
|
||||||
};
|
};
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use inkwell::{AddressSpace, IntPredicate};
|
use inkwell::{AddressSpace, IntPredicate};
|
||||||
use morphic_lib::{CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions};
|
use morphic_lib::{
|
||||||
|
CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar,
|
||||||
|
};
|
||||||
use roc_builtins::bitcode;
|
use roc_builtins::bitcode;
|
||||||
use roc_collections::all::{ImMap, MutMap, MutSet};
|
use roc_collections::all::{ImMap, MutMap, MutSet};
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
|
@ -826,8 +828,21 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CallType::LowLevel { op, update_mode: _ } => {
|
CallType::LowLevel { op, update_mode } => {
|
||||||
run_low_level(env, layout_ids, scope, parent, layout, *op, arguments)
|
let bytes = update_mode.to_bytes();
|
||||||
|
let update_var = UpdateModeVar(&bytes);
|
||||||
|
let update_mode = func_spec_solutions.update_mode(update_var).ok();
|
||||||
|
|
||||||
|
run_low_level(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
scope,
|
||||||
|
parent,
|
||||||
|
layout,
|
||||||
|
*op,
|
||||||
|
arguments,
|
||||||
|
update_mode,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CallType::HigherOrderLowLevel {
|
CallType::HigherOrderLowLevel {
|
||||||
|
@ -4190,6 +4205,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
op: LowLevel,
|
op: LowLevel,
|
||||||
args: &[Symbol],
|
args: &[Symbol],
|
||||||
|
update_mode: Option<UpdateMode>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
use LowLevel::*;
|
use LowLevel::*;
|
||||||
|
|
||||||
|
@ -4648,27 +4664,6 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
wrapper_struct,
|
wrapper_struct,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ListSetInPlace => {
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
|
||||||
let (index, _) = load_symbol_and_layout(scope, &args[1]);
|
|
||||||
let (element, _) = load_symbol_and_layout(scope, &args[2]);
|
|
||||||
|
|
||||||
match list_layout {
|
|
||||||
Layout::Builtin(Builtin::EmptyList) => {
|
|
||||||
// no elements, so nothing to remove
|
|
||||||
empty_list(env)
|
|
||||||
}
|
|
||||||
Layout::Builtin(Builtin::List(element_layout)) => list_set(
|
|
||||||
env,
|
|
||||||
layout_ids,
|
|
||||||
list,
|
|
||||||
index.into_int_value(),
|
|
||||||
element,
|
|
||||||
element_layout,
|
|
||||||
),
|
|
||||||
_ => unreachable!("invalid dict layout"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListSet => {
|
ListSet => {
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
let (index, _) = load_symbol_and_layout(scope, &args[1]);
|
let (index, _) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
@ -4686,6 +4681,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
index.into_int_value(),
|
index.into_int_value(),
|
||||||
element,
|
element,
|
||||||
element_layout,
|
element_layout,
|
||||||
|
update_mode.unwrap(),
|
||||||
),
|
),
|
||||||
_ => unreachable!("invalid dict layout"),
|
_ => unreachable!("invalid dict layout"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use inkwell::context::Context;
|
||||||
use inkwell::types::{BasicType, BasicTypeEnum, PointerType};
|
use inkwell::types::{BasicType, BasicTypeEnum, PointerType};
|
||||||
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
|
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
|
||||||
use inkwell::{AddressSpace, IntPredicate};
|
use inkwell::{AddressSpace, IntPredicate};
|
||||||
|
use morphic_lib::UpdateMode;
|
||||||
use roc_builtins::bitcode;
|
use roc_builtins::bitcode;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||||
|
|
||||||
|
@ -350,6 +351,7 @@ pub fn list_set<'a, 'ctx, 'env>(
|
||||||
index: IntValue<'ctx>,
|
index: IntValue<'ctx>,
|
||||||
element: BasicValueEnum<'ctx>,
|
element: BasicValueEnum<'ctx>,
|
||||||
element_layout: &'a Layout<'a>,
|
element_layout: &'a Layout<'a>,
|
||||||
|
update_mode: UpdateMode,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||||
|
|
||||||
|
@ -359,6 +361,11 @@ pub fn list_set<'a, 'ctx, 'env>(
|
||||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let symbol = match update_mode {
|
||||||
|
UpdateMode::InPlace => bitcode::LIST_SET_IN_PLACE,
|
||||||
|
UpdateMode::Immutable => bitcode::LIST_SET,
|
||||||
|
};
|
||||||
|
|
||||||
let new_bytes = call_bitcode_fn(
|
let new_bytes = call_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
&[
|
&[
|
||||||
|
@ -370,7 +377,7 @@ pub fn list_set<'a, 'ctx, 'env>(
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||||
],
|
],
|
||||||
&bitcode::LIST_SET,
|
&symbol,
|
||||||
);
|
);
|
||||||
|
|
||||||
store_list(env, new_bytes.into_pointer_value(), length)
|
store_list(env, new_bytes.into_pointer_value(), length)
|
||||||
|
|
|
@ -18,7 +18,6 @@ pub enum LowLevel {
|
||||||
ListLen,
|
ListLen,
|
||||||
ListGetUnsafe,
|
ListGetUnsafe,
|
||||||
ListSet,
|
ListSet,
|
||||||
ListSetInPlace,
|
|
||||||
ListSingle,
|
ListSingle,
|
||||||
ListRepeat,
|
ListRepeat,
|
||||||
ListReverse,
|
ListReverse,
|
||||||
|
@ -125,7 +124,6 @@ impl LowLevel {
|
||||||
| ListLen
|
| ListLen
|
||||||
| ListGetUnsafe
|
| ListGetUnsafe
|
||||||
| ListSet
|
| ListSet
|
||||||
| ListSetInPlace
|
|
||||||
| ListDrop
|
| ListDrop
|
||||||
| ListSingle
|
| ListSingle
|
||||||
| ListRepeat
|
| ListRepeat
|
||||||
|
|
|
@ -760,7 +760,6 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
match op {
|
match op {
|
||||||
ListLen | StrIsEmpty | StrCountGraphemes => arena.alloc_slice_copy(&[borrowed]),
|
ListLen | StrIsEmpty | StrCountGraphemes => arena.alloc_slice_copy(&[borrowed]),
|
||||||
ListSet => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
ListSet => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||||
ListSetInPlace => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
|
||||||
ListGetUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
ListGetUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
ListConcat => arena.alloc_slice_copy(&[owned, owned]),
|
ListConcat => arena.alloc_slice_copy(&[owned, owned]),
|
||||||
StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
|
StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue