mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Fix Cranelift gen of nonempty lists
This commit is contained in:
parent
5beb65880c
commit
5bf82fa42c
3 changed files with 35 additions and 49 deletions
|
@ -288,39 +288,18 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
Array { elem_layout, elems } => {
|
Array { elem_layout, elems } => {
|
||||||
let cfg = env.cfg;
|
let cfg = env.cfg;
|
||||||
let ptr_bytes = cfg.pointer_bytes() as u32;
|
let ptr_bytes = cfg.pointer_bytes() as u32;
|
||||||
|
let slot = builder.create_stack_slot(StackSlotData::new(
|
||||||
|
StackSlotKind::ExplicitSlot,
|
||||||
|
ptr_bytes * Builtin::LIST_WORDS,
|
||||||
|
));
|
||||||
|
|
||||||
if elems.is_empty() {
|
let elems_ptr = if elems.is_empty() {
|
||||||
let slot = builder.create_stack_slot(StackSlotData::new(
|
// Empty lists get a null pointer so they don't allocate on the heap
|
||||||
StackSlotKind::ExplicitSlot,
|
builder.ins().iconst(cfg.pointer_type(), 0)
|
||||||
// 1 pointer-sized slot for the array pointer, and
|
|
||||||
// 1 pointer-sized slot for the length
|
|
||||||
ptr_bytes * 2,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Set list pointer to null
|
|
||||||
{
|
|
||||||
// let null_ptr = builder.ins().null(ptr_type);
|
|
||||||
let zero = builder.ins().iconst(cfg.pointer_type(), 0);
|
|
||||||
|
|
||||||
builder.ins().stack_store(zero, slot, Offset32::new(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set length to 0
|
|
||||||
{
|
|
||||||
let zero = builder.ins().iconst(cfg.pointer_type(), 0);
|
|
||||||
|
|
||||||
builder
|
|
||||||
.ins()
|
|
||||||
.stack_store(zero, slot, Offset32::new(ptr_bytes as i32));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the pointer
|
|
||||||
builder.ins().stack_addr(cfg.pointer_type(), slot, Offset32::new(0))
|
|
||||||
} else {
|
} else {
|
||||||
panic!("TODO make this work like the empty List, then verify that they both actually work");
|
let elem_bytes = elem_layout.stack_size(ptr_bytes as u32);
|
||||||
let elem_bytes = elem_layout.stack_size(env.cfg.pointer_bytes() as u32) as usize;
|
let bytes_len = elem_bytes as usize * elems.len();
|
||||||
let bytes_len = (elem_bytes * elems.len()) + 1/* TODO drop the +1 when we have structs and this is no longer NUL-terminated. */;
|
let elems_ptr = call_malloc(env, module, builder, bytes_len);
|
||||||
let ptr = call_malloc(env, module, builder, bytes_len);
|
|
||||||
let mem_flags = MemFlags::new();
|
let mem_flags = MemFlags::new();
|
||||||
|
|
||||||
// Copy the elements from the literal into the array
|
// Copy the elements from the literal into the array
|
||||||
|
@ -328,20 +307,28 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
let offset = Offset32::new(elem_bytes as i32 * index as i32);
|
let offset = Offset32::new(elem_bytes as i32 * index as i32);
|
||||||
let val = build_expr(env, scope, module, builder, elem, procs);
|
let val = build_expr(env, scope, module, builder, elem, procs);
|
||||||
|
|
||||||
builder.ins().store(mem_flags, val, ptr, offset);
|
builder.ins().store(mem_flags, val, elems_ptr, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a NUL terminator at the end.
|
elems_ptr
|
||||||
// TODO: Instead of NUL-terminating, return a struct
|
};
|
||||||
// with the pointer and also the length and capacity.
|
|
||||||
let nul_terminator = builder.ins().iconst(types::I8, 0);
|
|
||||||
let index = bytes_len as i32 - 1;
|
|
||||||
let offset = Offset32::new(index);
|
|
||||||
|
|
||||||
builder.ins().store(mem_flags, nul_terminator, ptr, offset);
|
// Store the pointer in slot 0
|
||||||
|
builder
|
||||||
|
.ins()
|
||||||
|
.stack_store(elems_ptr, slot, Offset32::new(0));
|
||||||
|
|
||||||
ptr
|
// Store the length in slot 1
|
||||||
|
{
|
||||||
|
let length = builder.ins().iconst(env.ptr_sized_int(), elems.len() as i64);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ins()
|
||||||
|
.stack_store(length, slot, Offset32::new(ptr_bytes as i32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the pointer to the wrapper
|
||||||
|
builder.ins().stack_addr(cfg.pointer_type(), slot, Offset32::new(0))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("I don't yet know how to crane build {:?}", expr);
|
panic!("I don't yet know how to crane build {:?}", expr);
|
||||||
|
@ -680,7 +667,7 @@ fn call_by_name<'a, B: Backend>(
|
||||||
env.ptr_sized_int(),
|
env.ptr_sized_int(),
|
||||||
MemFlags::new(),
|
MemFlags::new(),
|
||||||
list_ptr,
|
list_ptr,
|
||||||
Offset32::new(0),
|
Offset32::new(env.cfg.pointer_bytes() as i32),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Symbol::LIST_GET_UNSAFE => {
|
Symbol::LIST_GET_UNSAFE => {
|
||||||
|
|
|
@ -507,7 +507,7 @@ mod test_gen {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
3,
|
3,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,6 @@ mod test_gen {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
# TODO remove this annotation once monomorphization works!
|
# TODO remove this annotation once monomorphization works!
|
||||||
getLen : List Int -> Int
|
|
||||||
getLen = \list -> List.len list
|
getLen = \list -> List.len list
|
||||||
|
|
||||||
nums = [ 2, 4, 6 ]
|
nums = [ 2, 4, 6 ]
|
||||||
|
@ -526,13 +525,13 @@ mod test_gen {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
3,
|
3,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn int_list_is_empty() {
|
// fn int_list_is_empty() {
|
||||||
// assert_evals_to!("List.is_empty [ 12, 9, 6, 3 ]", 0, u8, |x| x);
|
// assert_evals_to!("List.isEmpty [ 12, 9, 6, 3 ]", 0, u8, |x| x);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -104,10 +104,10 @@ impl<'a> Builtin<'a> {
|
||||||
const BYTE_SIZE: u32 = std::mem::size_of::<u8>() as u32;
|
const BYTE_SIZE: u32 = std::mem::size_of::<u8>() as u32;
|
||||||
|
|
||||||
/// Number of machine words in an empty one of these
|
/// Number of machine words in an empty one of these
|
||||||
const STR_WORDS: u32 = 3;
|
pub const STR_WORDS: u32 = 2;
|
||||||
const MAP_WORDS: u32 = 6;
|
pub const MAP_WORDS: u32 = 6;
|
||||||
const SET_WORDS: u32 = Builtin::MAP_WORDS; // Set is an alias for Map with {} for value
|
pub const SET_WORDS: u32 = Builtin::MAP_WORDS; // Set is an alias for Map with {} for value
|
||||||
const LIST_WORDS: u32 = 3;
|
pub const LIST_WORDS: u32 = 2;
|
||||||
|
|
||||||
/// Layout of collection wrapper - a struct of (pointer, length, capacity)
|
/// Layout of collection wrapper - a struct of (pointer, length, capacity)
|
||||||
pub const WRAPPER_PTR: u32 = 0;
|
pub const WRAPPER_PTR: u32 = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue