mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Moved over to incrementing_elem_loop from incrementing_index_loop
This commit is contained in:
parent
dedbd5b3bd
commit
f2a8065adc
2 changed files with 95 additions and 145 deletions
|
@ -1,9 +1,9 @@
|
||||||
use crate::layout_id::LayoutIds;
|
use crate::layout_id::LayoutIds;
|
||||||
use crate::llvm::build_list::{
|
use crate::llvm::build_list::{
|
||||||
allocate_list, build_basic_phi2, clone_nonempty_list, empty_list, empty_polymorphic_list,
|
allocate_list, build_basic_phi2, clone_nonempty_list, empty_list, empty_polymorphic_list,
|
||||||
incrementing_index_loop, list_append, list_concat, list_get_unsafe, list_is_not_empty,
|
incrementing_elem_loop, list_append, list_concat, list_get_unsafe, list_is_not_empty,
|
||||||
list_join, list_len, list_map, list_prepend, list_repeat, list_reverse, list_set, list_single,
|
list_join, list_len, list_map, list_prepend, list_repeat, list_reverse, list_set, list_single,
|
||||||
load_list_ptr,
|
load_list_ptr, store_list,
|
||||||
};
|
};
|
||||||
use crate::llvm::compare::{build_eq, build_neq};
|
use crate::llvm::compare::{build_eq, build_neq};
|
||||||
use crate::llvm::convert::{
|
use crate::llvm::convert::{
|
||||||
|
@ -1674,9 +1674,9 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
// List.reverse : List elem -> List elem
|
// List.reverse : List elem -> List elem
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
let list = &args[0];
|
let (list, list_layout) = load_symbol_and_layout(env, scope, &args[0]);
|
||||||
|
|
||||||
list_reverse(env, parent, scope, list)
|
list_reverse(env, parent, list, list_layout)
|
||||||
}
|
}
|
||||||
ListConcat => {
|
ListConcat => {
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
@ -1719,9 +1719,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
let (list, outer_list_layout) = load_symbol_and_layout(env, scope, &args[0]);
|
let (list, outer_list_layout) = load_symbol_and_layout(env, scope, &args[0]);
|
||||||
let outer_wrapper_struct = list.into_struct_value();
|
|
||||||
|
|
||||||
list_join(env, parent, outer_wrapper_struct, outer_list_layout)
|
list_join(env, parent, list, outer_list_layout)
|
||||||
}
|
}
|
||||||
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumSin | NumCos | NumToFloat => {
|
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumSin | NumCos | NumToFloat => {
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
@ -2000,14 +1999,9 @@ fn str_concat<'a, 'ctx, 'env>(
|
||||||
let combined_str_ptr = allocate_list(env, &CHAR_LAYOUT, combined_str_len);
|
let combined_str_ptr = allocate_list(env, &CHAR_LAYOUT, combined_str_len);
|
||||||
|
|
||||||
// FIRST LOOP
|
// FIRST LOOP
|
||||||
let first_loop = |first_index| {
|
let first_str_ptr = load_list_ptr(builder, first_str_wrapper, ptr_type);
|
||||||
let first_str_ptr = load_list_ptr(builder, first_str_wrapper, ptr_type);
|
|
||||||
|
|
||||||
// The pointer to the element in the first list
|
|
||||||
let first_str_char_ptr = unsafe {
|
|
||||||
builder.build_in_bounds_gep(first_str_ptr, &[first_index], "load_index")
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let first_loop = |first_index, first_str_elem| {
|
||||||
// The pointer to the element in the combined list
|
// The pointer to the element in the combined list
|
||||||
let combined_str_elem_ptr = unsafe {
|
let combined_str_elem_ptr = unsafe {
|
||||||
builder.build_in_bounds_gep(
|
builder.build_in_bounds_gep(
|
||||||
|
@ -2017,18 +2011,17 @@ fn str_concat<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_str_elem = builder.build_load(first_str_char_ptr, "get_elem");
|
|
||||||
|
|
||||||
// Mutate the new array in-place to change the element.
|
// Mutate the new array in-place to change the element.
|
||||||
builder.build_store(combined_str_elem_ptr, first_str_elem);
|
builder.build_store(combined_str_elem_ptr, first_str_elem);
|
||||||
};
|
};
|
||||||
|
|
||||||
let index_name = "#index";
|
let index_name = "#index";
|
||||||
|
|
||||||
let index_alloca = incrementing_index_loop(
|
let index_alloca = incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
first_str_ptr,
|
||||||
first_str_len,
|
first_str_len,
|
||||||
index_name,
|
index_name,
|
||||||
None,
|
None,
|
||||||
|
@ -2039,14 +2032,9 @@ fn str_concat<'a, 'ctx, 'env>(
|
||||||
builder.build_store(index_alloca, ctx.i64_type().const_int(0, false));
|
builder.build_store(index_alloca, ctx.i64_type().const_int(0, false));
|
||||||
|
|
||||||
// SECOND LOOP
|
// SECOND LOOP
|
||||||
let second_loop = |second_index| {
|
let second_str_ptr = load_list_ptr(builder, second_str_wrapper, ptr_type);
|
||||||
let second_str_ptr = load_list_ptr(builder, second_str_wrapper, ptr_type);
|
|
||||||
|
|
||||||
// The pointer to the element in the second list
|
|
||||||
let second_str_char_ptr = unsafe {
|
|
||||||
builder.build_in_bounds_gep(second_str_ptr, &[second_index], "load_index")
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let second_loop = |second_index, second_str_elem| {
|
||||||
// The pointer to the element in the combined str.
|
// The pointer to the element in the combined str.
|
||||||
// Note that the pointer does not start at the index
|
// Note that the pointer does not start at the index
|
||||||
// 0, it starts at the index of first_str_len. In that
|
// 0, it starts at the index of first_str_len. In that
|
||||||
|
@ -2065,55 +2053,22 @@ fn str_concat<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let second_str_elem = builder.build_load(second_str_char_ptr, "get_elem");
|
|
||||||
|
|
||||||
// Mutate the new array in-place to change the element.
|
// Mutate the new array in-place to change the element.
|
||||||
builder.build_store(combined_str_char_ptr, second_str_elem);
|
builder.build_store(combined_str_char_ptr, second_str_elem);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_index_loop(
|
incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
second_str_ptr,
|
||||||
second_str_len,
|
second_str_len,
|
||||||
index_name,
|
index_name,
|
||||||
Some(index_alloca),
|
Some(index_alloca),
|
||||||
second_loop,
|
second_loop,
|
||||||
);
|
);
|
||||||
|
|
||||||
let ptr_bytes = env.ptr_bytes;
|
store_list(env, combined_str_ptr, combined_str_len)
|
||||||
let int_type = ptr_int(ctx, ptr_bytes);
|
|
||||||
let ptr_as_int = builder.build_ptr_to_int(combined_str_ptr, int_type, "list_cast_ptr");
|
|
||||||
|
|
||||||
let struct_type = collection(ctx, ptr_bytes);
|
|
||||||
|
|
||||||
let mut struct_val;
|
|
||||||
|
|
||||||
// Store the pointer
|
|
||||||
struct_val = builder
|
|
||||||
.build_insert_value(
|
|
||||||
struct_type.get_undef(),
|
|
||||||
ptr_as_int,
|
|
||||||
Builtin::WRAPPER_PTR,
|
|
||||||
"insert_ptr",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Store the length
|
|
||||||
struct_val = builder
|
|
||||||
.build_insert_value(
|
|
||||||
struct_val,
|
|
||||||
combined_str_len,
|
|
||||||
Builtin::WRAPPER_LEN,
|
|
||||||
"insert_len",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
builder.build_bitcast(
|
|
||||||
struct_val.into_struct_value(),
|
|
||||||
collection(ctx, ptr_bytes),
|
|
||||||
"cast_collection",
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
build_basic_phi2(
|
build_basic_phi2(
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::llvm::build::{load_symbol, load_symbol_and_layout, Env, InPlace, Scope};
|
use crate::llvm::build::{Env, InPlace};
|
||||||
use crate::llvm::convert::{basic_type_from_layout, collection, get_ptr_type, ptr_int};
|
use crate::llvm::convert::{basic_type_from_layout, collection, get_ptr_type, ptr_int};
|
||||||
use inkwell::builder::Builder;
|
use inkwell::builder::Builder;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::types::{BasicTypeEnum, PointerType};
|
use inkwell::types::{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 roc_module::symbol::Symbol;
|
|
||||||
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
||||||
|
|
||||||
/// List.single : a -> List a
|
/// List.single : a -> List a
|
||||||
|
@ -193,7 +192,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
|
||||||
pub fn list_join<'a, 'ctx, 'env>(
|
pub fn list_join<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
outer_list_wrapper: StructValue<'ctx>,
|
outer_list: BasicValueEnum<'ctx>,
|
||||||
outer_list_layout: &Layout<'a>,
|
outer_list_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
// List.join is implemented as follows:
|
// List.join is implemented as follows:
|
||||||
|
@ -221,6 +220,7 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
let inner_list_type =
|
let inner_list_type =
|
||||||
basic_type_from_layout(env.arena, ctx, &inner_list_layout, env.ptr_bytes);
|
basic_type_from_layout(env.arena, ctx, &inner_list_layout, env.ptr_bytes);
|
||||||
|
|
||||||
|
let outer_list_wrapper = outer_list.into_struct_value();
|
||||||
let outer_list_len = list_len(builder, outer_list_wrapper);
|
let outer_list_len = list_len(builder, outer_list_wrapper);
|
||||||
let outer_list_ptr = {
|
let outer_list_ptr = {
|
||||||
let elem_ptr_type = get_ptr_type(&inner_list_type, AddressSpace::Generic);
|
let elem_ptr_type = get_ptr_type(&inner_list_type, AddressSpace::Generic);
|
||||||
|
@ -240,12 +240,7 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
builder.build_store(list_len_sum_alloca, ctx.i64_type().const_int(0, false));
|
builder.build_store(list_len_sum_alloca, ctx.i64_type().const_int(0, false));
|
||||||
|
|
||||||
// List Sum Loop
|
// List Sum Loop
|
||||||
let sum_loop = |sum_index| {
|
let sum_loop = |_, inner_list: BasicValueEnum<'ctx>| {
|
||||||
let inner_list_wrapper_ptr = unsafe {
|
|
||||||
builder.build_in_bounds_gep(outer_list_ptr, &[sum_index], "load_index")
|
|
||||||
};
|
|
||||||
|
|
||||||
let inner_list = builder.build_load(inner_list_wrapper_ptr, "inner_list");
|
|
||||||
let inner_list_len = list_len(builder, inner_list.into_struct_value());
|
let inner_list_len = list_len(builder, inner_list.into_struct_value());
|
||||||
|
|
||||||
let next_list_sum = builder.build_int_add(
|
let next_list_sum = builder.build_int_add(
|
||||||
|
@ -259,10 +254,11 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
builder.build_store(list_len_sum_alloca, next_list_sum);
|
builder.build_store(list_len_sum_alloca, next_list_sum);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_index_loop(
|
incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
outer_list_ptr,
|
||||||
outer_list_len,
|
outer_list_len,
|
||||||
"#sum_index",
|
"#sum_index",
|
||||||
None,
|
None,
|
||||||
|
@ -280,16 +276,8 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
builder.build_store(dest_elem_ptr_alloca, final_list_ptr);
|
builder.build_store(dest_elem_ptr_alloca, final_list_ptr);
|
||||||
|
|
||||||
// Inner List Loop
|
// Inner List Loop
|
||||||
let inner_list_loop = |index| {
|
let inner_list_loop = |_, inner_list: BasicValueEnum<'ctx>| {
|
||||||
let inner_list_wrapper = {
|
let inner_list_wrapper = inner_list.into_struct_value();
|
||||||
let wrapper_ptr = unsafe {
|
|
||||||
builder.build_in_bounds_gep(outer_list_ptr, &[index], "load_index")
|
|
||||||
};
|
|
||||||
|
|
||||||
builder
|
|
||||||
.build_load(wrapper_ptr, "inner_list_wrapper")
|
|
||||||
.into_struct_value()
|
|
||||||
};
|
|
||||||
|
|
||||||
let inner_list_len = list_len(builder, inner_list_wrapper);
|
let inner_list_len = list_len(builder, inner_list_wrapper);
|
||||||
|
|
||||||
|
@ -307,20 +295,10 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
builder.position_at_end(inner_list_non_empty_block);
|
builder.position_at_end(inner_list_non_empty_block);
|
||||||
|
|
||||||
|
let inner_list_ptr = load_list_ptr(builder, inner_list_wrapper, elem_ptr_type);
|
||||||
|
|
||||||
// Element Inserting Loop
|
// Element Inserting Loop
|
||||||
let inner_elem_loop = |inner_index| {
|
let inner_elem_loop = |_, src_elem| {
|
||||||
let src_elem_ptr = unsafe {
|
|
||||||
let inner_list_ptr =
|
|
||||||
load_list_ptr(builder, inner_list_wrapper, elem_ptr_type);
|
|
||||||
|
|
||||||
builder.build_in_bounds_gep(
|
|
||||||
inner_list_ptr,
|
|
||||||
&[inner_index],
|
|
||||||
"load_index",
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let src_elem = builder.build_load(src_elem_ptr, "get_elem");
|
|
||||||
// TODO clone src_elem
|
// TODO clone src_elem
|
||||||
|
|
||||||
let curr_dest_elem_ptr = builder
|
let curr_dest_elem_ptr = builder
|
||||||
|
@ -340,10 +318,11 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
builder.build_store(dest_elem_ptr_alloca, inc_dest_elem_ptr);
|
builder.build_store(dest_elem_ptr_alloca, inc_dest_elem_ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_index_loop(
|
incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
inner_list_ptr,
|
||||||
inner_list_len,
|
inner_list_len,
|
||||||
"#inner_index",
|
"#inner_index",
|
||||||
None,
|
None,
|
||||||
|
@ -354,10 +333,11 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
builder.position_at_end(after_inner_list_non_empty_block);
|
builder.position_at_end(after_inner_list_non_empty_block);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_index_loop(
|
incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
outer_list_ptr,
|
||||||
outer_list_len,
|
outer_list_len,
|
||||||
"#inner_list_index",
|
"#inner_list_index",
|
||||||
None,
|
None,
|
||||||
|
@ -391,11 +371,9 @@ pub fn list_join<'a, 'ctx, 'env>(
|
||||||
pub fn list_reverse<'a, 'ctx, 'env>(
|
pub fn list_reverse<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
list: BasicValueEnum<'ctx>,
|
||||||
list: &Symbol,
|
list_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let (_, list_layout) = load_symbol_and_layout(env, scope, list);
|
|
||||||
|
|
||||||
let non_empty_fn =
|
let non_empty_fn =
|
||||||
|elem_layout: &Layout<'a>, len: IntValue<'ctx>, wrapper_struct: StructValue<'ctx>| {
|
|elem_layout: &Layout<'a>, len: IntValue<'ctx>, wrapper_struct: StructValue<'ctx>| {
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
@ -475,7 +453,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
|
||||||
store_list(env, reversed_list_ptr, len)
|
store_list(env, reversed_list_ptr, len)
|
||||||
};
|
};
|
||||||
|
|
||||||
if_non_empty(env, parent, scope, non_empty_fn, list, list_layout)
|
if_list_is_not_empty(env, parent, non_empty_fn, list, list_layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_get_unsafe<'a, 'ctx, 'env>(
|
pub fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
|
@ -667,7 +645,9 @@ pub fn list_map<'a, 'ctx, 'env>(
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
match (func, func_layout) {
|
match (func, func_layout) {
|
||||||
(BasicValueEnum::PointerValue(func_ptr), Layout::FunctionPointer(_, ret_elem_layout)) => {
|
(BasicValueEnum::PointerValue(func_ptr), Layout::FunctionPointer(_, ret_elem_layout)) => {
|
||||||
let non_empty_fn = || {
|
let non_empty_fn = |elem_layout: &Layout<'a>,
|
||||||
|
len: IntValue<'ctx>,
|
||||||
|
list_wrapper: StructValue<'ctx>| {
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
|
@ -678,12 +658,8 @@ pub fn list_map<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let list_ptr = load_list_ptr(builder, list_wrapper, ptr_type);
|
let list_ptr = load_list_ptr(builder, list_wrapper, ptr_type);
|
||||||
|
|
||||||
let list_loop = |index| {
|
let list_loop = |index, before_elem| {
|
||||||
// The pointer to the element in the input list
|
// The pointer to the element in the input list
|
||||||
let before_elem_ptr =
|
|
||||||
unsafe { builder.build_in_bounds_gep(list_ptr, &[index], "load_index") };
|
|
||||||
|
|
||||||
let before_elem = builder.build_load(before_elem_ptr, "get_before_elem");
|
|
||||||
|
|
||||||
let call_site_value =
|
let call_site_value =
|
||||||
builder.build_call(func_ptr, env.arena.alloc([before_elem]), "map_func");
|
builder.build_call(func_ptr, env.arena.alloc([before_elem]), "map_func");
|
||||||
|
@ -705,12 +681,14 @@ pub fn list_map<'a, 'ctx, 'env>(
|
||||||
builder.build_store(after_elem_ptr, after_elem);
|
builder.build_store(after_elem_ptr, after_elem);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_index_loop(builder, parent, ctx, len, "#index", None, list_loop);
|
incrementing_elem_loop(
|
||||||
|
builder, parent, ctx, list_ptr, len, "#index", None, list_loop,
|
||||||
|
);
|
||||||
|
|
||||||
store_list(env, ret_list_ptr, len)
|
store_list(env, ret_list_ptr, len)
|
||||||
};
|
};
|
||||||
|
|
||||||
if_non_empty(env, parent, scope, non_empty_fn, list, list_layout)
|
if_list_is_not_empty(env, parent, non_empty_fn, list, list_layout)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
|
@ -815,16 +793,7 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
||||||
let first_list_ptr = load_list_ptr(builder, first_list_wrapper, ptr_type);
|
let first_list_ptr = load_list_ptr(builder, first_list_wrapper, ptr_type);
|
||||||
|
|
||||||
// FIRST LOOP
|
// FIRST LOOP
|
||||||
let first_loop = |first_index| {
|
let first_loop = |first_index, first_list_elem| {
|
||||||
// The pointer to the element in the first list
|
|
||||||
let first_list_elem_ptr = unsafe {
|
|
||||||
builder.build_in_bounds_gep(
|
|
||||||
first_list_ptr,
|
|
||||||
&[first_index],
|
|
||||||
"load_index",
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// The pointer to the element in the combined list
|
// The pointer to the element in the combined list
|
||||||
let combined_list_elem_ptr = unsafe {
|
let combined_list_elem_ptr = unsafe {
|
||||||
builder.build_in_bounds_gep(
|
builder.build_in_bounds_gep(
|
||||||
|
@ -834,18 +803,17 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_list_elem = builder.build_load(first_list_elem_ptr, "get_elem");
|
|
||||||
|
|
||||||
// Mutate the new array in-place to change the element.
|
// Mutate the new array in-place to change the element.
|
||||||
builder.build_store(combined_list_elem_ptr, first_list_elem);
|
builder.build_store(combined_list_elem_ptr, first_list_elem);
|
||||||
};
|
};
|
||||||
|
|
||||||
let index_name = "#index";
|
let index_name = "#index";
|
||||||
|
|
||||||
let index_alloca = incrementing_index_loop(
|
let index_alloca = incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
first_list_ptr,
|
||||||
first_list_len,
|
first_list_len,
|
||||||
index_name,
|
index_name,
|
||||||
None,
|
None,
|
||||||
|
@ -855,19 +823,10 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
||||||
// Reset the index variable to 0
|
// Reset the index variable to 0
|
||||||
builder.build_store(index_alloca, ctx.i64_type().const_int(0, false));
|
builder.build_store(index_alloca, ctx.i64_type().const_int(0, false));
|
||||||
|
|
||||||
|
let second_list_ptr = load_list_ptr(builder, second_list_wrapper, ptr_type);
|
||||||
|
|
||||||
// SECOND LOOP
|
// SECOND LOOP
|
||||||
let second_loop = |second_index| {
|
let second_loop = |second_index, second_list_elem| {
|
||||||
let second_list_ptr = load_list_ptr(builder, second_list_wrapper, ptr_type);
|
|
||||||
|
|
||||||
// The pointer to the element in the second list
|
|
||||||
let second_list_elem_ptr = unsafe {
|
|
||||||
builder.build_in_bounds_gep(
|
|
||||||
second_list_ptr,
|
|
||||||
&[second_index],
|
|
||||||
"load_index",
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// The pointer to the element in the combined list.
|
// The pointer to the element in the combined list.
|
||||||
// Note that the pointer does not start at the index
|
// Note that the pointer does not start at the index
|
||||||
// 0, it starts at the index of first_list_len. In that
|
// 0, it starts at the index of first_list_len. In that
|
||||||
|
@ -890,16 +849,15 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let second_list_elem = builder.build_load(second_list_elem_ptr, "get_elem");
|
|
||||||
|
|
||||||
// Mutate the new array in-place to change the element.
|
// Mutate the new array in-place to change the element.
|
||||||
builder.build_store(combined_list_elem_ptr, second_list_elem);
|
builder.build_store(combined_list_elem_ptr, second_list_elem);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_index_loop(
|
incrementing_elem_loop(
|
||||||
builder,
|
builder,
|
||||||
parent,
|
parent,
|
||||||
ctx,
|
ctx,
|
||||||
|
second_list_ptr,
|
||||||
second_list_len,
|
second_list_len,
|
||||||
index_name,
|
index_name,
|
||||||
Some(index_alloca),
|
Some(index_alloca),
|
||||||
|
@ -939,7 +897,40 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// This helper simulates a basic for loop, where
|
// This helper simulates a basic for loop, where
|
||||||
// and index increments up from 0 to some end value
|
// and index increments up from 0 to some end value
|
||||||
pub fn incrementing_index_loop<'ctx, LoopFn>(
|
pub fn incrementing_elem_loop<'ctx, LoopFn>(
|
||||||
|
builder: &Builder<'ctx>,
|
||||||
|
parent: FunctionValue<'ctx>,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
list_ptr: PointerValue<'ctx>,
|
||||||
|
end: IntValue<'ctx>,
|
||||||
|
index_name: &str,
|
||||||
|
maybe_alloca: Option<PointerValue<'ctx>>,
|
||||||
|
mut loop_fn: LoopFn,
|
||||||
|
) -> PointerValue<'ctx>
|
||||||
|
where
|
||||||
|
LoopFn: FnMut(IntValue<'ctx>, BasicValueEnum<'ctx>),
|
||||||
|
{
|
||||||
|
incrementing_index_loop(
|
||||||
|
builder,
|
||||||
|
parent,
|
||||||
|
ctx,
|
||||||
|
end,
|
||||||
|
index_name,
|
||||||
|
maybe_alloca,
|
||||||
|
|index| {
|
||||||
|
// The pointer to the element in the list
|
||||||
|
let elem_ptr = unsafe { builder.build_in_bounds_gep(list_ptr, &[index], "load_index") };
|
||||||
|
|
||||||
|
let elem = builder.build_load(elem_ptr, "get_elem");
|
||||||
|
|
||||||
|
loop_fn(index, elem);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This helper simulates a basic for loop, where
|
||||||
|
// and index increments up from 0 to some end value
|
||||||
|
fn incrementing_index_loop<'ctx, LoopFn>(
|
||||||
builder: &Builder<'ctx>,
|
builder: &Builder<'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
|
@ -989,13 +980,19 @@ where
|
||||||
index_alloca
|
index_alloca
|
||||||
}
|
}
|
||||||
|
|
||||||
fn if_non_empty<'a, 'ctx, 'env, 'b, NonEmptyFn>(
|
// In many cases we dont want to do anything if the
|
||||||
|
// builtin was given an empty list. This is because
|
||||||
|
// allocating memory for a list is costly, so its
|
||||||
|
// better to skip if it we can. Furthermore, checking
|
||||||
|
// if a list is empty requires both seeing if the list
|
||||||
|
// is a NonEmpty layout and if its a List(elem_layout)
|
||||||
|
// but with a length of 0.
|
||||||
|
fn if_list_is_not_empty<'a, 'ctx, 'env, 'b, NonEmptyFn>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
|
||||||
mut build_non_empty: NonEmptyFn,
|
mut build_non_empty: NonEmptyFn,
|
||||||
list: &Symbol,
|
list: BasicValueEnum<'ctx>,
|
||||||
list_layout: &'b Layout<'a>,
|
list_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx>
|
) -> BasicValueEnum<'ctx>
|
||||||
where
|
where
|
||||||
NonEmptyFn: FnMut(&Layout<'a>, IntValue<'ctx>, StructValue<'ctx>) -> BasicValueEnum<'ctx>,
|
NonEmptyFn: FnMut(&Layout<'a>, IntValue<'ctx>, StructValue<'ctx>) -> BasicValueEnum<'ctx>,
|
||||||
|
@ -1004,16 +1001,14 @@ where
|
||||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||||
|
|
||||||
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
||||||
let wrapper_struct = load_symbol(env, scope, list).into_struct_value();
|
|
||||||
|
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
|
|
||||||
|
let wrapper_struct = list.into_struct_value();
|
||||||
|
|
||||||
let len = list_len(builder, wrapper_struct);
|
let len = list_len(builder, wrapper_struct);
|
||||||
|
|
||||||
// list_len > 0
|
// list_len > 0
|
||||||
// We do this check to avoid allocating memory. If the input
|
|
||||||
// list is empty, then we can just return an empty list.
|
|
||||||
let comparison = builder.build_int_compare(
|
let comparison = builder.build_int_compare(
|
||||||
IntPredicate::UGT,
|
IntPredicate::UGT,
|
||||||
len,
|
len,
|
||||||
|
@ -1264,7 +1259,7 @@ pub fn allocate_list<'a, 'ctx, 'env>(
|
||||||
list_element_ptr
|
list_element_ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_list<'a, 'ctx, 'env>(
|
pub fn store_list<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
list_ptr: PointerValue<'ctx>,
|
list_ptr: PointerValue<'ctx>,
|
||||||
len: IntValue<'ctx>,
|
len: IntValue<'ctx>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue