Merge pull request #1432 from rtfeldman/morphic-lowlevel

Morphic lowlevel
This commit is contained in:
Richard Feldman 2021-06-22 23:46:51 -04:00 committed by GitHub
commit 4a5df543a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 44 deletions

View file

@ -1009,7 +1009,25 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
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(
bytes: ?[*]u8,
length: usize,
@ -1028,7 +1046,21 @@ pub fn listSet(
const ptr: [*]usize = @ptrCast([*]usize, @alignCast(8, bytes));
if ((ptr - 1)[0] == utils.REFCOUNT_ONE) {
return listSetInPlaceHelp(bytes, length, alignment, index, element, element_width, dec);
} else {
return listSetImmutable(bytes, length, alignment, index, element, element_width, dec);
}
}
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);
@ -1039,12 +1071,9 @@ pub fn listSet(
@memcpy(element_at_index, element orelse undefined, element_width);
return bytes;
} else {
return listSetClone(bytes, length, alignment, index, element, element_width, dec);
}
}
inline fn listSetClone(
inline fn listSetImmutable(
old_bytes: ?[*]u8,
length: usize,
alignment: u32,
@ -1053,8 +1082,6 @@ inline fn listSetClone(
element_width: usize,
dec: Dec,
) ?[*]u8 {
@setCold(true);
const data_bytes = length * element_width;
var new_bytes = utils.allocateWithRefcount(data_bytes, alignment);

View file

@ -30,6 +30,7 @@ comptime {
exportListFn(list.listConcat, "concat");
exportListFn(list.listDrop, "drop");
exportListFn(list.listSet, "set");
exportListFn(list.listSetInPlace, "set_in_place");
exportListFn(list.listSwap, "swap");
}

View file

@ -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_CONCAT: &str = "roc_builtins.list.concat";
pub const LIST_SET: &str = "roc_builtins.list.set";
pub const LIST_SET_IN_PLACE: &str = "roc_builtins.list.set_in_place";

View file

@ -42,7 +42,9 @@ use inkwell::values::{
};
use inkwell::OptimizationLevel;
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_collections::all::{ImMap, MutMap, MutSet};
use roc_module::ident::TagName;
@ -826,8 +828,21 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
)
}
CallType::LowLevel { op, update_mode: _ } => {
run_low_level(env, layout_ids, scope, parent, layout, *op, arguments)
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();
run_low_level(
env,
layout_ids,
scope,
parent,
layout,
*op,
arguments,
update_mode,
)
}
CallType::HigherOrderLowLevel {
@ -4190,6 +4205,7 @@ fn run_low_level<'a, 'ctx, 'env>(
layout: &Layout<'a>,
op: LowLevel,
args: &[Symbol],
update_mode: Option<UpdateMode>,
) -> BasicValueEnum<'ctx> {
use LowLevel::*;
@ -4648,27 +4664,6 @@ fn run_low_level<'a, 'ctx, 'env>(
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 => {
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let (index, _) = load_symbol_and_layout(scope, &args[1]);
@ -4686,6 +4681,7 @@ fn run_low_level<'a, 'ctx, 'env>(
index.into_int_value(),
element,
element_layout,
update_mode.unwrap(),
),
_ => unreachable!("invalid dict layout"),
}

View file

@ -13,6 +13,7 @@ use inkwell::context::Context;
use inkwell::types::{BasicType, BasicTypeEnum, PointerType};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::{AddressSpace, IntPredicate};
use morphic_lib::UpdateMode;
use roc_builtins::bitcode;
use roc_mono::layout::{Builtin, Layout, LayoutIds};
@ -350,6 +351,7 @@ pub fn list_set<'a, 'ctx, 'env>(
index: IntValue<'ctx>,
element: BasicValueEnum<'ctx>,
element_layout: &'a Layout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
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),
);
let symbol = match update_mode {
UpdateMode::InPlace => bitcode::LIST_SET_IN_PLACE,
UpdateMode::Immutable => bitcode::LIST_SET,
};
let new_bytes = call_bitcode_fn(
env,
&[
@ -370,7 +377,7 @@ pub fn list_set<'a, 'ctx, 'env>(
layout_width(env, element_layout),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
&bitcode::LIST_SET,
&symbol,
);
store_list(env, new_bytes.into_pointer_value(), length)

View file

@ -18,7 +18,6 @@ pub enum LowLevel {
ListLen,
ListGetUnsafe,
ListSet,
ListSetInPlace,
ListSingle,
ListRepeat,
ListReverse,
@ -125,7 +124,6 @@ impl LowLevel {
| ListLen
| ListGetUnsafe
| ListSet
| ListSetInPlace
| ListDrop
| ListSingle
| ListRepeat

View file

@ -760,7 +760,6 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
match op {
ListLen | StrIsEmpty | StrCountGraphemes => arena.alloc_slice_copy(&[borrowed]),
ListSet => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
ListSetInPlace => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
ListGetUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
ListConcat => arena.alloc_slice_copy(&[owned, owned]),
StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),