Merge pull request #3447 from rtfeldman/list-unsafe-append

`List.reserve` and `List.appendUnsafe`
This commit is contained in:
Richard Feldman 2022-07-08 14:39:58 -04:00 committed by GitHub
commit aea7892fae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 445 additions and 314 deletions

View File

@ -935,6 +935,20 @@ fn list_append(
with_new_heap_cell(builder, block, new_bag)
}
fn list_clone(
builder: &mut FuncDefBuilder,
block: BlockId,
update_mode_var: UpdateModeVar,
list: ValueId,
) -> Result<ValueId> {
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
let cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
let _unit = builder.add_update(block, update_mode_var, cell)?;
with_new_heap_cell(builder, block, bag)
}
fn lowlevel_spec(
builder: &mut FuncDefBuilder,
env: &Env,
@ -1029,7 +1043,24 @@ fn lowlevel_spec(
with_new_heap_cell(builder, block, bag)
}
ListAppend => {
ListWithCapacity => {
// essentially an empty list, capacity is not relevant for morphic
match layout {
Layout::Builtin(Builtin::List(element_layout)) => {
let type_id =
layout_spec(builder, element_layout, &WhenRecursive::Unreachable)?;
new_list(builder, block, type_id)
}
_ => unreachable!("empty array does not have a list layout"),
}
}
ListReserve => {
let list = env.symbols[&arguments[0]];
list_clone(builder, block, update_mode_var, list)
}
ListAppendUnsafe => {
let list = env.symbols[&arguments[0]];
let to_insert = env.symbols[&arguments[1]];

View File

@ -404,21 +404,41 @@ pub fn listMap4(
}
}
pub fn listWithCapacity(capacity: usize, alignment: u32, element_width: usize) callconv(.C) RocList {
pub fn listWithCapacity(
capacity: usize,
alignment: u32,
element_width: usize,
) callconv(.C) RocList {
var output = RocList.allocate(alignment, capacity, element_width);
output.length = 0;
return output;
}
pub fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width: usize, update_mode: UpdateMode) callconv(.C) RocList {
pub fn listReserve(
list: RocList,
alignment: u32,
spare: usize,
element_width: usize,
update_mode: UpdateMode,
) callconv(.C) RocList {
const old_length = list.len();
var output: RocList = undefined;
if (update_mode == .InPlace and list.capacity >= old_length + 1) {
output = list;
output.length += 1;
if ((update_mode == .InPlace or list.isUnique()) and list.capacity >= list.len() + spare) {
return list;
} else {
output = list.reallocate(alignment, old_length + 1, element_width);
var output = list.reallocate(alignment, old_length + spare, element_width);
output.length = old_length;
return output;
}
}
pub fn listAppendUnsafe(
list: RocList,
element: Opaque,
element_width: usize,
) callconv(.C) RocList {
const old_length = list.len();
var output = list;
output.length += 1;
if (output.bytes) |target| {
if (element) |source| {
@ -429,6 +449,11 @@ pub fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width:
return output;
}
fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width: usize, update_mode: UpdateMode) callconv(.C) RocList {
const with_capacity = listReserve(list, alignment, 1, element_width, update_mode);
return listAppendUnsafe(with_capacity, element, element_width);
}
pub fn listPrepend(list: RocList, alignment: u32, element: Opaque, element_width: usize) callconv(.C) RocList {
const old_length = list.len();
var output = list.reallocate(alignment, old_length + 1, element_width);

View File

@ -39,7 +39,8 @@ comptime {
exportListFn(list.listMap2, "map2");
exportListFn(list.listMap3, "map3");
exportListFn(list.listMap4, "map4");
exportListFn(list.listAppend, "append");
exportListFn(list.listAppendUnsafe, "append_unsafe");
exportListFn(list.listReserve, "reserve");
exportListFn(list.listPrepend, "prepend");
exportListFn(list.listWithCapacity, "with_capacity");
exportListFn(list.listSortWith, "sort_with");

View File

@ -52,6 +52,7 @@ interface List
dropIf,
sortAsc,
sortDesc,
reserve,
]
imports [
Bool.{ Bool },
@ -243,6 +244,17 @@ set = \list, index, value ->
## >>> [0, 1, 2]
## >>> |> List.append 3
append : List a, a -> List a
append = \list, element ->
list
|> List.reserve 1
|> List.appendUnsafe element
## Writes the element after the current last element unconditionally.
## In other words, it is assumed that
##
## - the list is owned (i.e. can be updated in-place
## - the list has at least one element of spare capacity
appendUnsafe : List a, a -> List a
## Add a single element to the beginning of a list.
##
@ -262,6 +274,9 @@ len : List a -> Nat
## Create a list with space for at least capacity elements
withCapacity : Nat -> List a
## Enlarge the list for at least capacity additional elements
reserve : List a, Nat -> List a
## Put two lists together.
##
## >>> List.concat [1, 2, 3] [4, 5]
@ -298,7 +313,7 @@ repeat = \value, count ->
repeatHelp : a, Nat, List a -> List a
repeatHelp = \value, count, accum ->
if count > 0 then
repeatHelp value (count - 1) (List.append accum value)
repeatHelp value (count - 1) (List.appendUnsafe accum value)
else
accum
@ -574,7 +589,7 @@ mapWithIndexHelp = \src, dest, func, index, length ->
if index < length then
elem = getUnsafe src index
mappedElem = func elem index
newDest = append dest mappedElem
newDest = List.appendUnsafe dest mappedElem
mapWithIndexHelp src newDest func (index + 1) length
else
@ -599,7 +614,7 @@ rangeHelp = \accum, start, end ->
if end <= start then
accum
else
rangeHelp (List.append accum start) (start + 1) end
rangeHelp (List.appendUnsafe accum start) (start + 1) end
## Sort with a custom comparison function
sortWith : List a, (a, a -> [LT, EQ, GT]) -> List a
@ -804,7 +819,11 @@ intersperse : List elem, elem -> List elem
intersperse = \list, sep ->
capacity = 2 * List.len list
init = List.withCapacity capacity
newList = List.walk list init (\acc, elem -> acc |> List.append elem |> List.append sep)
newList =
List.walk list init \acc, elem ->
acc
|> List.appendUnsafe elem
|> List.appendUnsafe sep
List.dropLast newList

View File

@ -359,8 +359,6 @@ pub const LIST_MAP: &str = "roc_builtins.list.map";
pub const LIST_MAP2: &str = "roc_builtins.list.map2";
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
pub const LIST_MAP4: &str = "roc_builtins.list.map4";
pub const LIST_APPEND: &str = "roc_builtins.list.append";
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist";
pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at";
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
@ -370,6 +368,9 @@ pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
pub const LIST_REPLACE: &str = "roc_builtins.list.replace";
pub const LIST_REPLACE_IN_PLACE: &str = "roc_builtins.list.replace_in_place";
pub const LIST_IS_UNIQUE: &str = "roc_builtins.list.is_unique";
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
pub const LIST_APPEND_UNSAFE: &str = "roc_builtins.list.append_unsafe";
pub const LIST_RESERVE: &str = "roc_builtins.list.reserve";
pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str";
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";

View File

@ -110,9 +110,10 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
LIST_UNREACHABLE => roc_unreachable,
LIST_LEN => list_len,
LIST_WITH_CAPACITY => list_with_capacity,
LIST_RESERVE => list_reserve,
LIST_APPEND_UNSAFE => list_append_unsafe,
LIST_GET_UNSAFE => list_get_unsafe,
LIST_REPLACE_UNSAFE => list_replace_unsafe,
LIST_APPEND => list_append,
LIST_IS_EMPTY => list_is_empty,
LIST_CONCAT => list_concat,
LIST_PREPEND => list_prepend,
@ -2069,6 +2070,14 @@ fn list_with_capacity(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_1(symbol, LowLevel::ListWithCapacity, var_store)
}
fn list_reserve(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::ListReserve, var_store)
}
fn list_append_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::ListAppendUnsafe, var_store)
}
/// List.getUnsafe : List elem, Int -> elem
fn list_get_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::ListGetUnsafe, var_store)
@ -2314,50 +2323,9 @@ fn list_drop_at(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::ListDropAt, var_store)
}
/// List.append : List elem, elem -> List elem
fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let elem_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::ListAppend,
args: vec![
(list_var, Var(Symbol::ARG_1)),
(elem_var, Var(Symbol::ARG_2)),
],
ret_var: list_var,
};
defn(
symbol,
vec![(list_var, Symbol::ARG_1), (elem_var, Symbol::ARG_2)],
var_store,
body,
list_var,
)
}
/// List.prepend : List elem, elem -> List elem
fn list_prepend(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let elem_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::ListPrepend,
args: vec![
(list_var, Var(Symbol::ARG_1)),
(elem_var, Var(Symbol::ARG_2)),
],
ret_var: list_var,
};
defn(
symbol,
vec![(list_var, Symbol::ARG_1), (elem_var, Symbol::ARG_2)],
var_store,
body,
list_var,
)
lowlevel_2(symbol, LowLevel::ListPrepend, var_store)
}
/// List.unreachable : [] -> a

View File

@ -8,10 +8,10 @@ use crate::llvm::build_dict::{
};
use crate::llvm::build_hash::generic_hash;
use crate::llvm::build_list::{
self, allocate_list, empty_polymorphic_list, list_append, list_concat, list_drop_at,
self, allocate_list, empty_polymorphic_list, list_append_unsafe, list_concat, list_drop_at,
list_get_unsafe, list_len, list_map, list_map2, list_map3, list_map4, list_prepend,
list_replace_unsafe, list_sort_with, list_sublist, list_swap, list_symbol_to_c_abi,
list_to_c_abi, list_with_capacity,
list_replace_unsafe, list_reserve, list_sort_with, list_sublist, list_swap,
list_symbol_to_c_abi, list_to_c_abi, list_with_capacity,
};
use crate::llvm::build_str::{str_from_float, str_from_int, str_from_utf8, str_from_utf8_range};
use crate::llvm::compare::{generic_eq, generic_neq};
@ -5509,14 +5509,24 @@ fn run_low_level<'a, 'ctx, 'env>(
list_concat(env, first_list, second_list, element_layout)
}
ListAppend => {
// List.append : List elem, elem -> List elem
ListAppendUnsafe => {
// List.appendUnsafe : List elem, elem -> List elem
debug_assert_eq!(args.len(), 2);
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
list_append(env, original_wrapper, elem, elem_layout, update_mode)
list_append_unsafe(env, original_wrapper, elem, elem_layout)
}
ListReserve => {
// List.reserve : List elem, Nat -> List elem
debug_assert_eq!(args.len(), 2);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let element_layout = list_element_layout!(list_layout);
let spare = load_symbol(scope, &args[1]);
list_reserve(env, list, spare, element_layout, update_mode)
}
ListSwap => {
// List.swap : List elem, Nat, Nat -> List elem

View File

@ -146,24 +146,42 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>(
result
}
/// List.append : List elem, elem -> List elem
pub fn list_append<'a, 'ctx, 'env>(
/// List.reserve : List elem, Nat -> List elem
pub fn list_reserve<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
original_wrapper: StructValue<'ctx>,
element: BasicValueEnum<'ctx>,
list: BasicValueEnum<'ctx>,
spare: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
call_list_bitcode_fn(
env,
&[
list_to_c_abi(env, original_wrapper.into()).into(),
list_to_c_abi(env, list).into(),
env.alignment_intvalue(element_layout),
pass_element_as_opaque(env, element, *element_layout),
spare,
layout_width(env, element_layout),
pass_update_mode(env, update_mode),
],
bitcode::LIST_APPEND,
bitcode::LIST_RESERVE,
)
}
/// List.appendUnsafe : List elem, elem -> List elem
pub fn list_append_unsafe<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
original_wrapper: StructValue<'ctx>,
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_list_bitcode_fn(
env,
&[
list_to_c_abi(env, original_wrapper.into()).into(),
pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout),
],
bitcode::LIST_APPEND_UNSAFE,
)
}
@ -807,6 +825,7 @@ pub fn store_list<'a, 'ctx, 'env>(
.build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len")
.unwrap();
// Store the capacity
struct_val = builder
.build_insert_value(
struct_val,

View File

@ -488,22 +488,27 @@ impl<'a> LowLevelCall<'a> {
backend.call_host_fn_after_loading_args(bitcode::LIST_CONCAT, 7, false);
}
ListAppend => {
// List.append : List elem, elem -> List elem
ListReserve => {
// List.reserve : List elem, Nat -> List elem
let list: Symbol = self.arguments[0];
let elem: Symbol = self.arguments[1];
let spare: Symbol = self.arguments[1];
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
let (elem_width, elem_align) = elem_layout.stack_size_and_alignment(TARGET_INFO);
let (elem_local, elem_offset, _) =
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
let (spare_local, spare_offset, _) = ensure_symbol_is_in_memory(
backend,
spare,
Layout::usize(TARGET_INFO),
backend.env.arena,
);
// Zig arguments Wasm types
// (return pointer) i32
// list: RocList i64, i32
// alignment: u32 i32
// element: Opaque i32
// spare: usize i32
// element_width: usize i32
// update_mode: UpdateMode i32
@ -519,6 +524,46 @@ impl<'a> LowLevelCall<'a> {
backend.code_builder.i32_const(elem_align as i32);
backend.code_builder.get_local(spare_local);
if spare_offset > 0 {
backend.code_builder.i32_const(spare_offset as i32);
backend.code_builder.i32_add();
}
backend.code_builder.i32_const(elem_width as i32);
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
backend.call_host_fn_after_loading_args(bitcode::LIST_RESERVE, 7, false);
}
ListAppendUnsafe => {
// List.append : List elem, elem -> List elem
let list: Symbol = self.arguments[0];
let elem: Symbol = self.arguments[1];
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
let elem_width = elem_layout.stack_size(TARGET_INFO);
let (elem_local, elem_offset, _) =
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
// Zig arguments Wasm types
// (return pointer) i32
// list: RocList i64, i32
// element: Opaque i32
// element_width: usize i32
// return pointer and list
backend.storage.load_symbols_for_call(
backend.env.arena,
&mut backend.code_builder,
&[list],
self.ret_symbol,
&WasmLayout::new(&self.ret_layout),
CallConv::Zig,
);
backend.code_builder.get_local(elem_local);
if elem_offset > 0 {
backend.code_builder.i32_const(elem_offset as i32);
@ -526,9 +571,8 @@ impl<'a> LowLevelCall<'a> {
}
backend.code_builder.i32_const(elem_width as i32);
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND, 7, false);
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND_UNSAFE, 4, false);
}
ListPrepend => {
// List.prepend : List elem, elem -> List elem

View File

@ -32,10 +32,11 @@ pub enum LowLevel {
StrGetScalarUnsafe,
ListLen,
ListWithCapacity,
ListReserve,
ListAppendUnsafe,
ListGetUnsafe,
ListReplaceUnsafe,
ListConcat,
ListAppend,
ListPrepend,
ListMap,
ListMap2,
@ -209,7 +210,7 @@ impl LowLevelWrapperType {
Symbol::LIST_GET => WrapperIsRequired,
Symbol::LIST_REPLACE => WrapperIsRequired,
Symbol::LIST_CONCAT => CanBeReplacedBy(ListConcat),
Symbol::LIST_APPEND => CanBeReplacedBy(ListAppend),
Symbol::LIST_APPEND_UNSAFE => CanBeReplacedBy(ListAppendUnsafe),
Symbol::LIST_PREPEND => CanBeReplacedBy(ListPrepend),
Symbol::LIST_MAP => WrapperIsRequired,
Symbol::LIST_MAP2 => WrapperIsRequired,

View File

@ -1272,6 +1272,8 @@ define_builtins! {
62 LIST_WITH_CAPACITY: "withCapacity"
63 LIST_ITERATE: "iterate"
64 LIST_UNREACHABLE: "unreachable"
65 LIST_RESERVE: "reserve"
66 LIST_APPEND_UNSAFE: "appendUnsafe"
}
6 RESULT: "Result" => {
0 RESULT_RESULT: "Result" // the Result.Result type alias

View File

@ -910,9 +910,8 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
ListSortWith => arena.alloc_slice_copy(&[owned, function, closure_data]),
// TODO when we have lists with capacity (if ever)
// List.append should own its first argument
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
ListAppendUnsafe => arena.alloc_slice_copy(&[owned, owned]),
ListReserve => arena.alloc_slice_copy(&[owned, irrelevant]),
ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),

View File

@ -65,16 +65,6 @@ fn roc_function<'a, 'b>(
run_roc_dylib!(arena.alloc(lib), main_fn_name, &Input, Output, errors)
}
fn rust_main(argument: &RocList<i64>, output: &mut RocCallResult<i64>) {
let mut answer = 0;
for x in argument.iter() {
answer += x;
}
*output = RocCallResult::new(answer);
}
fn create_input_list() -> RocList<i64> {
let numbers = Vec::from_iter(0..1_000);
@ -84,8 +74,8 @@ fn create_input_list() -> RocList<i64> {
pub fn criterion_benchmark(c: &mut Criterion) {
let arena = Bump::new();
let list_map_with_index_main = roc_function(&arena, ROC_LIST_MAP_WITH_INDEX);
let list_map_main = roc_function(&arena, ROC_LIST_MAP);
let list_map_with_index_main = roc_function(&arena, ROC_LIST_MAP_WITH_INDEX);
let input = &*arena.alloc(create_input_list());
@ -104,15 +94,6 @@ pub fn criterion_benchmark(c: &mut Criterion) {
list_map_with_index_main(black_box(input), &mut main_result);
})
});
let input = &*arena.alloc(create_input_list());
c.bench_function("rust", |b| {
b.iter(|| {
let mut main_result = RocCallResult::default();
rust_main(black_box(input), &mut main_result);
})
});
}
criterion_group!(benches, criterion_benchmark);

View File

@ -154,7 +154,7 @@ fn variously_sized_list_literals() {
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn list_append() {
fn list_append_basic() {
assert_evals_to!(
"List.append [1] 2",
RocList::from_slice(&[1, 2]),

View File

@ -1,7 +1,7 @@
procedure List.5 (#Attr.2, #Attr.3):
let List.279 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
let List.283 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
decref #Attr.2;
ret List.279;
ret List.283;
procedure Test.2 (Test.3):
let Test.7 : {} = Struct {};

View File

@ -1,6 +1,6 @@
procedure List.6 (#Attr.2):
let List.279 : U64 = lowlevel ListLen #Attr.2;
ret List.279;
let List.283 : U64 = lowlevel ListLen #Attr.2;
ret List.283;
procedure Test.1 (Test.5):
let Test.2 : I64 = 41i64;

View File

@ -1,22 +1,22 @@
procedure List.2 (List.75, List.76):
let List.284 : U64 = CallByName List.6 List.75;
let List.281 : Int1 = CallByName Num.22 List.76 List.284;
if List.281 then
let List.283 : {} = CallByName List.60 List.75 List.76;
let List.282 : [C {}, C {}] = TagId(1) List.283;
ret List.282;
procedure List.2 (List.77, List.78):
let List.288 : U64 = CallByName List.6 List.77;
let List.285 : Int1 = CallByName Num.22 List.78 List.288;
if List.285 then
let List.287 : {} = CallByName List.60 List.77 List.78;
let List.286 : [C {}, C {}] = TagId(1) List.287;
ret List.286;
else
let List.280 : {} = Struct {};
let List.279 : [C {}, C {}] = TagId(0) List.280;
ret List.279;
let List.284 : {} = Struct {};
let List.283 : [C {}, C {}] = TagId(0) List.284;
ret List.283;
procedure List.6 (#Attr.2):
let List.286 : U64 = lowlevel ListLen #Attr.2;
ret List.286;
let List.290 : U64 = lowlevel ListLen #Attr.2;
ret List.290;
procedure List.60 (#Attr.2, #Attr.3):
let List.285 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.285;
let List.289 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.289;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,6 +1,16 @@
procedure List.4 (#Attr.2, #Attr.3):
let List.279 : List U8 = lowlevel ListAppend #Attr.2 #Attr.3;
ret List.279;
procedure List.4 (List.88, List.89):
let List.285 : U64 = 1i64;
let List.284 : List U8 = CallByName List.65 List.88 List.285;
let List.283 : List U8 = CallByName List.66 List.284 List.89;
ret List.283;
procedure List.65 (#Attr.2, #Attr.3):
let List.287 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
ret List.287;
procedure List.66 (#Attr.2, #Attr.3):
let List.286 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
ret List.286;
procedure Test.20 (Test.22):
let Test.34 : {U8} = Struct {Test.22};

View File

@ -1,6 +1,6 @@
procedure List.6 (#Attr.2):
let List.279 : U64 = lowlevel ListLen #Attr.2;
ret List.279;
let List.283 : U64 = lowlevel ListLen #Attr.2;
ret List.283;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.190 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;

View File

@ -1,37 +1,37 @@
procedure List.2 (List.75, List.76):
let List.293 : U64 = CallByName List.6 List.75;
let List.289 : Int1 = CallByName Num.22 List.76 List.293;
if List.289 then
let List.291 : I64 = CallByName List.60 List.75 List.76;
let List.290 : [C {}, C I64] = TagId(1) List.291;
ret List.290;
procedure List.2 (List.77, List.78):
let List.297 : U64 = CallByName List.6 List.77;
let List.293 : Int1 = CallByName Num.22 List.78 List.297;
if List.293 then
let List.295 : I64 = CallByName List.60 List.77 List.78;
let List.294 : [C {}, C I64] = TagId(1) List.295;
ret List.294;
else
let List.288 : {} = Struct {};
let List.287 : [C {}, C I64] = TagId(0) List.288;
ret List.287;
let List.292 : {} = Struct {};
let List.291 : [C {}, C I64] = TagId(0) List.292;
ret List.291;
procedure List.6 (#Attr.2):
let List.294 : U64 = lowlevel ListLen #Attr.2;
ret List.294;
let List.298 : U64 = lowlevel ListLen #Attr.2;
ret List.298;
procedure List.60 (#Attr.2, #Attr.3):
let List.292 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.292;
let List.296 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.296;
procedure List.9 (List.201):
let List.286 : U64 = 0i64;
let List.279 : [C {}, C I64] = CallByName List.2 List.201 List.286;
let List.283 : U8 = 1i64;
let List.284 : U8 = GetTagId List.279;
let List.285 : Int1 = lowlevel Eq List.283 List.284;
if List.285 then
let List.202 : I64 = UnionAtIndex (Id 1) (Index 0) List.279;
let List.280 : [C Int1, C I64] = TagId(1) List.202;
ret List.280;
procedure List.9 (List.205):
let List.290 : U64 = 0i64;
let List.283 : [C {}, C I64] = CallByName List.2 List.205 List.290;
let List.287 : U8 = 1i64;
let List.288 : U8 = GetTagId List.283;
let List.289 : Int1 = lowlevel Eq List.287 List.288;
if List.289 then
let List.206 : I64 = UnionAtIndex (Id 1) (Index 0) List.283;
let List.284 : [C Int1, C I64] = TagId(1) List.206;
ret List.284;
else
let List.282 : Int1 = true;
let List.281 : [C Int1, C I64] = TagId(0) List.282;
ret List.281;
let List.286 : Int1 = true;
let List.285 : [C Int1, C I64] = TagId(0) List.286;
ret List.285;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,6 +1,16 @@
procedure List.4 (#Attr.2, #Attr.3):
let List.279 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
ret List.279;
procedure List.4 (List.88, List.89):
let List.285 : U64 = 1i64;
let List.284 : List I64 = CallByName List.65 List.88 List.285;
let List.283 : List I64 = CallByName List.66 List.284 List.89;
ret List.283;
procedure List.65 (#Attr.2, #Attr.3):
let List.287 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
ret List.287;
procedure List.66 (#Attr.2, #Attr.3):
let List.286 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
ret List.286;
procedure Test.0 ():
let Test.2 : List I64 = Array [1i64];

View File

@ -1,6 +1,16 @@
procedure List.4 (#Attr.2, #Attr.3):
let List.279 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
ret List.279;
procedure List.4 (List.88, List.89):
let List.285 : U64 = 1i64;
let List.284 : List I64 = CallByName List.65 List.88 List.285;
let List.283 : List I64 = CallByName List.66 List.284 List.89;
ret List.283;
procedure List.65 (#Attr.2, #Attr.3):
let List.287 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
ret List.287;
procedure List.66 (#Attr.2, #Attr.3):
let List.286 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
ret List.286;
procedure Test.1 (Test.2):
let Test.6 : I64 = 42i64;

View File

@ -1,27 +1,27 @@
procedure List.3 (List.83, List.84, List.85):
let List.282 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
let List.281 : List I64 = StructAtIndex 0 List.282;
inc List.281;
dec List.282;
ret List.281;
procedure List.3 (List.85, List.86, List.87):
let List.286 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
let List.285 : List I64 = StructAtIndex 0 List.286;
inc List.285;
dec List.286;
ret List.285;
procedure List.57 (List.80, List.81, List.82):
let List.287 : U64 = CallByName List.6 List.80;
let List.284 : Int1 = CallByName Num.22 List.81 List.287;
if List.284 then
let List.285 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
ret List.285;
procedure List.57 (List.82, List.83, List.84):
let List.291 : U64 = CallByName List.6 List.82;
let List.288 : Int1 = CallByName Num.22 List.83 List.291;
if List.288 then
let List.289 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
ret List.289;
else
let List.283 : {List I64, I64} = Struct {List.80, List.82};
ret List.283;
let List.287 : {List I64, I64} = Struct {List.82, List.84};
ret List.287;
procedure List.6 (#Attr.2):
let List.280 : U64 = lowlevel ListLen #Attr.2;
ret List.280;
let List.284 : U64 = lowlevel ListLen #Attr.2;
ret List.284;
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
let List.286 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.286;
let List.290 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.290;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.188 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;

View File

@ -1,22 +1,22 @@
procedure List.2 (List.75, List.76):
let List.284 : U64 = CallByName List.6 List.75;
let List.281 : Int1 = CallByName Num.22 List.76 List.284;
if List.281 then
let List.283 : I64 = CallByName List.60 List.75 List.76;
let List.282 : [C {}, C I64] = TagId(1) List.283;
ret List.282;
procedure List.2 (List.77, List.78):
let List.288 : U64 = CallByName List.6 List.77;
let List.285 : Int1 = CallByName Num.22 List.78 List.288;
if List.285 then
let List.287 : I64 = CallByName List.60 List.77 List.78;
let List.286 : [C {}, C I64] = TagId(1) List.287;
ret List.286;
else
let List.280 : {} = Struct {};
let List.279 : [C {}, C I64] = TagId(0) List.280;
ret List.279;
let List.284 : {} = Struct {};
let List.283 : [C {}, C I64] = TagId(0) List.284;
ret List.283;
procedure List.6 (#Attr.2):
let List.286 : U64 = lowlevel ListLen #Attr.2;
ret List.286;
let List.290 : U64 = lowlevel ListLen #Attr.2;
ret List.290;
procedure List.60 (#Attr.2, #Attr.3):
let List.285 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.285;
let List.289 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.289;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,10 +1,10 @@
procedure List.6 (#Attr.2):
let List.279 : U64 = lowlevel ListLen #Attr.2;
ret List.279;
let List.283 : U64 = lowlevel ListLen #Attr.2;
ret List.283;
procedure List.6 (#Attr.2):
let List.280 : U64 = lowlevel ListLen #Attr.2;
ret List.280;
let List.284 : U64 = lowlevel ListLen #Attr.2;
ret List.284;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.188 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;

View File

@ -1,26 +1,26 @@
procedure List.2 (List.75, List.76):
let List.284 : U64 = CallByName List.6 List.75;
let List.281 : Int1 = CallByName Num.22 List.76 List.284;
if List.281 then
let List.283 : Str = CallByName List.60 List.75 List.76;
let List.282 : [C {}, C Str] = TagId(1) List.283;
ret List.282;
procedure List.2 (List.77, List.78):
let List.288 : U64 = CallByName List.6 List.77;
let List.285 : Int1 = CallByName Num.22 List.78 List.288;
if List.285 then
let List.287 : Str = CallByName List.60 List.77 List.78;
let List.286 : [C {}, C Str] = TagId(1) List.287;
ret List.286;
else
let List.280 : {} = Struct {};
let List.279 : [C {}, C Str] = TagId(0) List.280;
ret List.279;
let List.284 : {} = Struct {};
let List.283 : [C {}, C Str] = TagId(0) List.284;
ret List.283;
procedure List.5 (#Attr.2, #Attr.3):
let List.285 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
ret List.285;
let List.289 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
ret List.289;
procedure List.6 (#Attr.2):
let List.287 : U64 = lowlevel ListLen #Attr.2;
ret List.287;
let List.291 : U64 = lowlevel ListLen #Attr.2;
ret List.291;
procedure List.60 (#Attr.2, #Attr.3):
let List.286 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.286;
let List.290 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.290;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,28 +1,28 @@
procedure List.2 (List.75, List.76):
let List.284 : U64 = CallByName List.6 List.75;
let List.281 : Int1 = CallByName Num.22 List.76 List.284;
if List.281 then
let List.283 : Str = CallByName List.60 List.75 List.76;
let List.282 : [C {}, C Str] = TagId(1) List.283;
ret List.282;
procedure List.2 (List.77, List.78):
let List.288 : U64 = CallByName List.6 List.77;
let List.285 : Int1 = CallByName Num.22 List.78 List.288;
if List.285 then
let List.287 : Str = CallByName List.60 List.77 List.78;
let List.286 : [C {}, C Str] = TagId(1) List.287;
ret List.286;
else
let List.280 : {} = Struct {};
let List.279 : [C {}, C Str] = TagId(0) List.280;
ret List.279;
let List.284 : {} = Struct {};
let List.283 : [C {}, C Str] = TagId(0) List.284;
ret List.283;
procedure List.5 (#Attr.2, #Attr.3):
inc #Attr.2;
let List.285 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
let List.289 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
decref #Attr.2;
ret List.285;
ret List.289;
procedure List.6 (#Attr.2):
let List.287 : U64 = lowlevel ListLen #Attr.2;
ret List.287;
let List.291 : U64 = lowlevel ListLen #Attr.2;
ret List.291;
procedure List.60 (#Attr.2, #Attr.3):
let List.286 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.286;
let List.290 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.290;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,27 +1,27 @@
procedure List.3 (List.83, List.84, List.85):
let List.280 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
let List.279 : List I64 = StructAtIndex 0 List.280;
inc List.279;
dec List.280;
ret List.279;
procedure List.3 (List.85, List.86, List.87):
let List.284 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
let List.283 : List I64 = StructAtIndex 0 List.284;
inc List.283;
dec List.284;
ret List.283;
procedure List.57 (List.80, List.81, List.82):
let List.285 : U64 = CallByName List.6 List.80;
let List.282 : Int1 = CallByName Num.22 List.81 List.285;
if List.282 then
let List.283 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
ret List.283;
procedure List.57 (List.82, List.83, List.84):
let List.289 : U64 = CallByName List.6 List.82;
let List.286 : Int1 = CallByName Num.22 List.83 List.289;
if List.286 then
let List.287 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
ret List.287;
else
let List.281 : {List I64, I64} = Struct {List.80, List.82};
ret List.281;
let List.285 : {List I64, I64} = Struct {List.82, List.84};
ret List.285;
procedure List.6 (#Attr.2):
let List.286 : U64 = lowlevel ListLen #Attr.2;
ret List.286;
let List.290 : U64 = lowlevel ListLen #Attr.2;
ret List.290;
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
let List.284 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.284;
let List.288 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.288;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,16 +1,16 @@
procedure List.28 (#Attr.2, #Attr.3):
let List.281 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
let List.285 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
let Bool.9 : Int1 = lowlevel ListIsUnique #Attr.2;
if Bool.9 then
ret List.281;
ret List.285;
else
decref #Attr.2;
ret List.281;
ret List.285;
procedure List.54 (List.196):
let List.280 : {} = Struct {};
let List.279 : List I64 = CallByName List.28 List.196 List.280;
ret List.279;
procedure List.54 (List.200):
let List.284 : {} = Struct {};
let List.283 : List I64 = CallByName List.28 List.200 List.284;
ret List.283;
procedure Num.46 (#Attr.2, #Attr.3):
let Num.188 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;

View File

@ -1,43 +1,43 @@
procedure List.2 (List.75, List.76):
let List.294 : U64 = CallByName List.6 List.75;
let List.291 : Int1 = CallByName Num.22 List.76 List.294;
if List.291 then
let List.293 : I64 = CallByName List.60 List.75 List.76;
let List.292 : [C {}, C I64] = TagId(1) List.293;
ret List.292;
procedure List.2 (List.77, List.78):
let List.298 : U64 = CallByName List.6 List.77;
let List.295 : Int1 = CallByName Num.22 List.78 List.298;
if List.295 then
let List.297 : I64 = CallByName List.60 List.77 List.78;
let List.296 : [C {}, C I64] = TagId(1) List.297;
ret List.296;
else
let List.290 : {} = Struct {};
let List.289 : [C {}, C I64] = TagId(0) List.290;
ret List.289;
let List.294 : {} = Struct {};
let List.293 : [C {}, C I64] = TagId(0) List.294;
ret List.293;
procedure List.3 (List.83, List.84, List.85):
let List.282 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
let List.281 : List I64 = StructAtIndex 0 List.282;
inc List.281;
dec List.282;
ret List.281;
procedure List.3 (List.85, List.86, List.87):
let List.286 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
let List.285 : List I64 = StructAtIndex 0 List.286;
inc List.285;
dec List.286;
ret List.285;
procedure List.57 (List.80, List.81, List.82):
let List.299 : U64 = CallByName List.6 List.80;
let List.296 : Int1 = CallByName Num.22 List.81 List.299;
if List.296 then
let List.297 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
ret List.297;
procedure List.57 (List.82, List.83, List.84):
let List.303 : U64 = CallByName List.6 List.82;
let List.300 : Int1 = CallByName Num.22 List.83 List.303;
if List.300 then
let List.301 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
ret List.301;
else
let List.295 : {List I64, I64} = Struct {List.80, List.82};
ret List.295;
let List.299 : {List I64, I64} = Struct {List.82, List.84};
ret List.299;
procedure List.6 (#Attr.2):
let List.300 : U64 = lowlevel ListLen #Attr.2;
ret List.300;
let List.304 : U64 = lowlevel ListLen #Attr.2;
ret List.304;
procedure List.60 (#Attr.2, #Attr.3):
let List.301 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.301;
let List.305 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.305;
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
let List.298 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.298;
let List.302 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.302;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.190 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;

View File

@ -1,43 +1,43 @@
procedure List.2 (List.75, List.76):
let List.294 : U64 = CallByName List.6 List.75;
let List.291 : Int1 = CallByName Num.22 List.76 List.294;
if List.291 then
let List.293 : I64 = CallByName List.60 List.75 List.76;
let List.292 : [C {}, C I64] = TagId(1) List.293;
ret List.292;
procedure List.2 (List.77, List.78):
let List.298 : U64 = CallByName List.6 List.77;
let List.295 : Int1 = CallByName Num.22 List.78 List.298;
if List.295 then
let List.297 : I64 = CallByName List.60 List.77 List.78;
let List.296 : [C {}, C I64] = TagId(1) List.297;
ret List.296;
else
let List.290 : {} = Struct {};
let List.289 : [C {}, C I64] = TagId(0) List.290;
ret List.289;
let List.294 : {} = Struct {};
let List.293 : [C {}, C I64] = TagId(0) List.294;
ret List.293;
procedure List.3 (List.83, List.84, List.85):
let List.282 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
let List.281 : List I64 = StructAtIndex 0 List.282;
inc List.281;
dec List.282;
ret List.281;
procedure List.3 (List.85, List.86, List.87):
let List.286 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
let List.285 : List I64 = StructAtIndex 0 List.286;
inc List.285;
dec List.286;
ret List.285;
procedure List.57 (List.80, List.81, List.82):
let List.299 : U64 = CallByName List.6 List.80;
let List.296 : Int1 = CallByName Num.22 List.81 List.299;
if List.296 then
let List.297 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
ret List.297;
procedure List.57 (List.82, List.83, List.84):
let List.303 : U64 = CallByName List.6 List.82;
let List.300 : Int1 = CallByName Num.22 List.83 List.303;
if List.300 then
let List.301 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
ret List.301;
else
let List.295 : {List I64, I64} = Struct {List.80, List.82};
ret List.295;
let List.299 : {List I64, I64} = Struct {List.82, List.84};
ret List.299;
procedure List.6 (#Attr.2):
let List.300 : U64 = lowlevel ListLen #Attr.2;
ret List.300;
let List.304 : U64 = lowlevel ListLen #Attr.2;
ret List.304;
procedure List.60 (#Attr.2, #Attr.3):
let List.301 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.301;
let List.305 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
ret List.305;
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
let List.298 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.298;
let List.302 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.302;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.190 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;