mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
First pass at some List implementation stuff
This commit is contained in:
parent
80722b872a
commit
4c19dd86ff
4 changed files with 75 additions and 22 deletions
|
@ -233,9 +233,34 @@ pub fn build_expr<'a, B: Backend>(
|
|||
}
|
||||
}
|
||||
Array { elem_layout, elems } => {
|
||||
let cfg = env.cfg;
|
||||
let ptr_bytes = cfg.pointer_bytes() as u32;
|
||||
|
||||
if elems.is_empty() {
|
||||
panic!("TODO build an empty Array in Crane");
|
||||
let slot = builder.create_stack_slot(StackSlotData::new(
|
||||
StackSlotKind::ExplicitSlot,
|
||||
ptr_bytes + 64,
|
||||
));
|
||||
let ptr_type = cfg.pointer_type();
|
||||
let null_ptr = builder.ins().null(ptr_type);
|
||||
let zero = builder.ins().iconst(Type::int(32).unwrap(), 0);
|
||||
|
||||
// Initialize a null pointer for the pointer
|
||||
builder.ins().stack_store(null_ptr, slot, Offset32::new(0));
|
||||
|
||||
// Set both length and capacity to 0
|
||||
let ptr_bytes = ptr_bytes as i32;
|
||||
|
||||
builder
|
||||
.ins()
|
||||
.stack_store(zero, slot, Offset32::new(ptr_bytes));
|
||||
builder
|
||||
.ins()
|
||||
.stack_store(zero, slot, Offset32::new(ptr_bytes + 32));
|
||||
|
||||
builder.ins().stack_addr(ptr_type, slot, Offset32::new(0))
|
||||
} else {
|
||||
panic!("TODO make this work like the empty List, then verify that they both actually work");
|
||||
let elem_bytes = elem_layout.stack_size(env.cfg.pointer_bytes() as u32) as usize;
|
||||
let bytes_len = (elem_bytes * elems.len()) + 1/* TODO drop the +1 when we have structs and this is no longer NUL-terminated. */;
|
||||
let ptr = call_malloc(env, module, builder, bytes_len);
|
||||
|
@ -574,6 +599,22 @@ fn call_by_name<'a, B: Backend>(
|
|||
|
||||
builder.ins().ineg(num)
|
||||
}
|
||||
Symbol::LIST_LEN => {
|
||||
debug_assert!(args.len() == 1);
|
||||
|
||||
let list = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
|
||||
// Get the 32-bit int length
|
||||
let i32_val = builder.ins().load_complex(
|
||||
Type::int(32).unwrap(),
|
||||
MemFlags::new(),
|
||||
&[list],
|
||||
Offset32::new(0),
|
||||
);
|
||||
|
||||
// Cast the 32-bit int length to a 64-bit integer
|
||||
builder.ins().bitcast(Type::int(64).unwrap(), i32_val)
|
||||
}
|
||||
Symbol::LIST_GET_UNSAFE => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
|
@ -667,7 +708,7 @@ fn call_by_name<'a, B: Backend>(
|
|||
let fn_id = match scope.get(&symbol) {
|
||||
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
|
||||
other => panic!(
|
||||
"CallByName could not find function named {:?} in scope; instead, found {:?} in scope {:?}",
|
||||
"CallByName could not find function named {:?} declared in scope (and it was not special-cased in crane::build as a builtin); instead, found {:?} in scope {:?}",
|
||||
symbol, other, scope
|
||||
),
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::llvm::convert::{
|
|||
use roc_collections::all::ImMap;
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_mono::expr::{Expr, Proc, Procs};
|
||||
use roc_mono::layout::Layout;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
|
||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
||||
|
@ -222,7 +222,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
|||
.build_insert_value(
|
||||
struct_type.const_zero(),
|
||||
BasicValueEnum::PointerValue(ptr_type.const_null()),
|
||||
0,
|
||||
Builtin::WRAPPER_PTR,
|
||||
"insert_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -258,17 +258,27 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
|||
|
||||
// Field 0: pointer
|
||||
struct_val = builder
|
||||
.build_insert_value(struct_type.const_zero(), ptr_val, 0, "insert_ptr")
|
||||
.build_insert_value(
|
||||
struct_type.const_zero(),
|
||||
ptr_val,
|
||||
Builtin::WRAPPER_PTR,
|
||||
"insert_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Field 1: length
|
||||
struct_val = builder
|
||||
.build_insert_value(struct_val, len, 1, "insert_len")
|
||||
.build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len")
|
||||
.unwrap();
|
||||
|
||||
// Field 2: capacity (initially set to length)
|
||||
struct_val = builder
|
||||
.build_insert_value(struct_val, len, 2, "insert_capacity")
|
||||
.build_insert_value(
|
||||
struct_val,
|
||||
len,
|
||||
Builtin::WRAPPER_CAPACITY,
|
||||
"insert_capacity",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
BasicValueEnum::StructValue(struct_val.into_struct_value())
|
||||
|
@ -615,7 +625,7 @@ fn call_with_args<'a, 'ctx, 'env>(
|
|||
let builder = env.builder;
|
||||
|
||||
// Get the 32-bit int length
|
||||
let i32_val = builder.build_extract_value(wrapper_struct, 1, "unwrapped_list_len").unwrap().into_int_value();
|
||||
let i32_val = builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_LEN, "unwrapped_list_len").unwrap().into_int_value();
|
||||
|
||||
// cast the 32-bit length to a 64-bit int
|
||||
BasicValueEnum::IntValue(builder.build_int_cast(i32_val, env.context.i64_type(), "i32_to_i64"))
|
||||
|
@ -641,12 +651,12 @@ fn call_with_args<'a, 'ctx, 'env>(
|
|||
let elem_index = args[1].into_int_value();
|
||||
|
||||
// Slot 1 in the wrapper struct is the length
|
||||
let _list_len = builder.build_extract_value(wrapper_struct, 1, "unwrapped_list_len").unwrap().into_int_value();
|
||||
let _list_len = builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_LEN, "unwrapped_list_len").unwrap().into_int_value();
|
||||
|
||||
// TODO here, check to see if the requested index exceeds the length of the array.
|
||||
|
||||
// Slot 0 in the wrapper struct is the pointer to the array data
|
||||
let array_data_ptr = builder.build_extract_value(wrapper_struct, 0, "unwrapped_list_ptr").unwrap().into_pointer_value();
|
||||
let array_data_ptr = builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_PTR, "unwrapped_list_ptr").unwrap().into_pointer_value();
|
||||
|
||||
let elem_bytes = 8; // TODO Look this size up instead of hardcoding it!
|
||||
let elem_size = env.context.i64_type().const_int(elem_bytes, false);
|
||||
|
@ -669,13 +679,13 @@ fn call_with_args<'a, 'ctx, 'env>(
|
|||
let elem = args[2];
|
||||
|
||||
// Slot 1 in the wrapper struct is the length
|
||||
let _list_len = builder.build_extract_value(wrapper_struct, 1, "unwrapped_list_len").unwrap().into_int_value();
|
||||
let _list_len = builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_LEN, "unwrapped_list_len").unwrap().into_int_value();
|
||||
|
||||
// TODO here, check to see if the requested index exceeds the length of the array.
|
||||
// If so, bail out and return the list unaltered.
|
||||
|
||||
// Slot 0 in the wrapper struct is the pointer to the array data
|
||||
let array_data_ptr = builder.build_extract_value(wrapper_struct, 0, "unwrapped_list_ptr").unwrap().into_pointer_value();
|
||||
let array_data_ptr = builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_PTR, "unwrapped_list_ptr").unwrap().into_pointer_value();
|
||||
|
||||
let elem_bytes = 8; // TODO Look this size up instead of hardcoding it!
|
||||
let elem_size = env.context.i64_type().const_int(elem_bytes, false);
|
||||
|
|
|
@ -488,14 +488,13 @@ mod test_gen {
|
|||
// }
|
||||
|
||||
#[test]
|
||||
fn int_list_len() {
|
||||
// assert_evals_to!("List.len [ 12, 9, 6, 3 ]", 4, i64);
|
||||
assert_llvm_evals_to!("List.len [ 12, 9, 6, 3 ]", 4, i64, |x| x);
|
||||
fn basic_int_list_len() {
|
||||
assert_evals_to!("List.len [ 12, 9, 6, 3 ]", 4, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loaded_int_list_len() {
|
||||
assert_llvm_evals_to!(
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
nums = [ 2, 4, 6 ]
|
||||
|
@ -504,14 +503,13 @@ mod test_gen {
|
|||
"#
|
||||
),
|
||||
3,
|
||||
i64,
|
||||
|x| x
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_int_list_len() {
|
||||
assert_llvm_evals_to!(
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
# TODO remove this annotation once monomorphization works!
|
||||
|
@ -524,14 +522,13 @@ mod test_gen {
|
|||
"#
|
||||
),
|
||||
3,
|
||||
i64,
|
||||
|x| x
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn int_list_is_empty() {
|
||||
// assert_evals_to!("List.is_empty [ 12, 9, 6, 3 ]", 0, i32, |x| x);
|
||||
// assert_evals_to!("List.is_empty [ 12, 9, 6, 3 ]", 0, u8, |x| x);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -92,6 +92,11 @@ impl<'a> Builtin<'a> {
|
|||
const SET_WORDS: u32 = Builtin::MAP_WORDS; // Set is an alias for Map with {} for value
|
||||
const LIST_WORDS: u32 = 3;
|
||||
|
||||
/// Layout of collection wrapper - a struct of (pointer, length, capacity)
|
||||
pub const WRAPPER_PTR: u32 = 0;
|
||||
pub const WRAPPER_LEN: u32 = 1;
|
||||
pub const WRAPPER_CAPACITY: u32 = 2;
|
||||
|
||||
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||
use Builtin::*;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue