mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Merge branch 'trunk' into store-dec-as-str
This commit is contained in:
commit
4c72aba4a7
64 changed files with 2437 additions and 2132 deletions
|
@ -271,33 +271,11 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
match closure_data_layout {
|
||||
Layout::Closure(_, lambda_set, _) => {
|
||||
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
||||
// do nothing
|
||||
} else {
|
||||
let closure_type =
|
||||
basic_type_from_layout(env, &lambda_set.runtime_representation())
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
|
||||
let closure_data = env.builder.build_load(closure_cast, "load_opaque");
|
||||
|
||||
arguments_cast.push(closure_data);
|
||||
}
|
||||
Layout::Struct(&[]) => {
|
||||
// nothing to add
|
||||
}
|
||||
Layout::Struct([Layout::Closure(_, lambda_set, _)]) => {
|
||||
// a case required for Set.walk; may be able to remove when we can define builtins in
|
||||
// terms of other builtins in the right way (using their function symbols instead of
|
||||
// hacking with lowlevel ops).
|
||||
let closure_type = basic_type_from_layout(
|
||||
env,
|
||||
&Layout::Struct(&[lambda_set.runtime_representation()]),
|
||||
)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
other => {
|
||||
let closure_type = basic_type_from_layout(env, &other).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
|
@ -308,13 +286,6 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
|
||||
arguments_cast.push(closure_data);
|
||||
}
|
||||
Layout::Struct([]) => {
|
||||
// do nothing, should try to remove this case later
|
||||
}
|
||||
Layout::Struct(_) => {
|
||||
// do nothing, should try to remove this case later
|
||||
}
|
||||
other => unreachable!("layout is not valid for a closure: {:?}", other),
|
||||
}
|
||||
|
||||
let call = {
|
||||
|
@ -625,26 +596,23 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
let default = [value1, value2];
|
||||
|
||||
let arguments_cast = match closure_data_layout {
|
||||
Layout::Closure(_, lambda_set, _) => {
|
||||
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
||||
&default
|
||||
} else {
|
||||
let closure_type =
|
||||
basic_type_from_layout(env, &lambda_set.runtime_representation())
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
|
||||
let closure_data = env.builder.build_load(closure_cast, "load_opaque");
|
||||
|
||||
env.arena.alloc([value1, value2, closure_data]) as &[_]
|
||||
}
|
||||
Layout::Struct(&[]) => {
|
||||
// nothing to add
|
||||
&default
|
||||
}
|
||||
other => {
|
||||
let closure_type =
|
||||
basic_type_from_layout(env, &other).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
|
||||
let closure_data = env.builder.build_load(closure_cast, "load_opaque");
|
||||
|
||||
env.arena.alloc([value1, value2, closure_data]) as &[_]
|
||||
}
|
||||
Layout::Struct([]) => &default,
|
||||
other => unreachable!("layout is not valid for a closure: {:?}", other),
|
||||
};
|
||||
|
||||
let call = env.builder.build_call(
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -88,10 +88,6 @@ fn build_hash_layout<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
},
|
||||
|
||||
Layout::Closure(_, _, _) => {
|
||||
unreachable!("the type system will guarantee these are never hashed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,69 +121,6 @@ pub fn list_repeat<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.prepend : List elem, elem -> List elem
|
||||
pub fn list_prepend<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
elem: BasicValueEnum<'ctx>,
|
||||
elem_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
// Load the usize length from the wrapper.
|
||||
let len = list_len(builder, original_wrapper);
|
||||
let elem_type = basic_type_from_layout(env, elem_layout);
|
||||
let ptr_type = elem_type.ptr_type(AddressSpace::Generic);
|
||||
let list_ptr = load_list_ptr(builder, original_wrapper, ptr_type);
|
||||
|
||||
// The output list length, which is the old list length + 1
|
||||
let new_list_len = env.builder.build_int_add(
|
||||
env.ptr_int().const_int(1_u64, false),
|
||||
len,
|
||||
"new_list_length",
|
||||
);
|
||||
|
||||
// Allocate space for the new array that we'll copy into.
|
||||
let clone_ptr = allocate_list(env, elem_layout, new_list_len);
|
||||
|
||||
builder.build_store(clone_ptr, elem);
|
||||
|
||||
let index_1_ptr = unsafe {
|
||||
builder.build_in_bounds_gep(
|
||||
clone_ptr,
|
||||
&[env.ptr_int().const_int(1_u64, false)],
|
||||
"load_index",
|
||||
)
|
||||
};
|
||||
|
||||
// Calculate the number of bytes we'll need to allocate.
|
||||
let elem_bytes = env
|
||||
.ptr_int()
|
||||
.const_int(elem_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
|
||||
// This is the size of the list coming in, before we have added an element
|
||||
// to the beginning.
|
||||
let list_size = env
|
||||
.builder
|
||||
.build_int_mul(elem_bytes, len, "mul_old_len_by_elem_bytes");
|
||||
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
|
||||
if elem_layout.safe_to_memcpy() {
|
||||
// Copy the bytes from the original array into the new
|
||||
// one we just allocated
|
||||
//
|
||||
// TODO how do we decide when to do the small memcpy vs the normal one?
|
||||
builder
|
||||
.build_memcpy(index_1_ptr, ptr_bytes, list_ptr, ptr_bytes, list_size)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("TODO Cranelift currently only knows how to clone list elements that are Copy.");
|
||||
}
|
||||
|
||||
store_list(env, clone_ptr, new_list_len)
|
||||
}
|
||||
|
||||
/// List.join : List (List elem) -> List elem
|
||||
pub fn list_join<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
@ -299,6 +236,25 @@ pub fn list_append<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.prepend : List elem, elem -> List elem
|
||||
pub fn list_prepend<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
element: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
call_bitcode_fn_returns_list(
|
||||
env,
|
||||
&[
|
||||
pass_list_as_i128(env, original_wrapper.into()),
|
||||
env.alignment_intvalue(element_layout),
|
||||
pass_element_as_opaque(env, element),
|
||||
layout_width(env, element_layout),
|
||||
],
|
||||
bitcode::LIST_PREPEND,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.swap : List elem, Nat, Nat -> List elem
|
||||
pub fn list_swap<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
|
|
@ -198,10 +198,6 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
},
|
||||
|
||||
Layout::Closure(_, _, _) => {
|
||||
unreachable!("the type system will guarantee these are never compared")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,10 +336,6 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
Layout::RecursivePointer => {
|
||||
unreachable!("recursion pointers should never be compared directly")
|
||||
}
|
||||
|
||||
Layout::Closure(_, _, _) => {
|
||||
unreachable!("the type system will guarantee these are never compared")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,6 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
use Layout::*;
|
||||
|
||||
match layout {
|
||||
Closure(_args, closure_layout, _ret_layout) => {
|
||||
let closure_data_layout = closure_layout.runtime_representation();
|
||||
basic_type_from_layout(env, &closure_data_layout)
|
||||
}
|
||||
Struct(sorted_fields) => basic_type_from_record(env, sorted_fields),
|
||||
Union(union_layout) => {
|
||||
use UnionLayout::*;
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
use crate::llvm::build::Env;
|
||||
use crate::llvm::build::{add_func, C_CALL_CONV};
|
||||
use crate::llvm::convert::ptr_int;
|
||||
use inkwell::builder::Builder;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::module::{Linkage, Module};
|
||||
use inkwell::module::Linkage;
|
||||
use inkwell::values::BasicValue;
|
||||
use inkwell::AddressSpace;
|
||||
|
||||
/// Define functions for roc_alloc, roc_realloc, and roc_dealloc
|
||||
/// which use libc implementations (malloc, realloc, and free)
|
||||
pub fn add_default_roc_externs<'ctx>(
|
||||
ctx: &'ctx Context,
|
||||
module: &Module<'ctx>,
|
||||
builder: &Builder<'ctx>,
|
||||
ptr_bytes: u32,
|
||||
) {
|
||||
pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
||||
let ctx = env.context;
|
||||
let module = env.module;
|
||||
let builder = env.builder;
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
|
||||
let usize_type = ptr_int(ctx, ptr_bytes);
|
||||
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
|
@ -139,4 +138,69 @@ pub fn add_default_roc_externs<'ctx>(
|
|||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
|
||||
add_sjlj_roc_panic(env)
|
||||
}
|
||||
|
||||
pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
||||
let ctx = env.context;
|
||||
let module = env.module;
|
||||
let builder = env.builder;
|
||||
|
||||
// roc_panic
|
||||
{
|
||||
use crate::llvm::build::LLVM_LONGJMP;
|
||||
|
||||
// The type of this function (but not the implementation) should have
|
||||
// already been defined by the builtins, which rely on it.
|
||||
let fn_val = module.get_function("roc_panic").unwrap();
|
||||
let mut params = fn_val.get_param_iter();
|
||||
let ptr_arg = params.next().unwrap();
|
||||
|
||||
// in debug mode, this is assumed to be NullTerminatedString
|
||||
let _tag_id_arg = params.next().unwrap();
|
||||
|
||||
debug_assert!(params.next().is_none());
|
||||
|
||||
let subprogram = env.new_subprogram("roc_panic");
|
||||
fn_val.set_subprogram(subprogram);
|
||||
|
||||
env.dibuilder.finalize();
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = ctx.append_basic_block(fn_val, "entry");
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
let buffer = crate::llvm::build::get_sjlj_buffer(env);
|
||||
|
||||
// write our error message pointer
|
||||
let index = env.ptr_int().const_int(3 * env.ptr_bytes as u64, false);
|
||||
let message_buffer_raw =
|
||||
unsafe { builder.build_gep(buffer, &[index], "raw_msg_buffer_ptr") };
|
||||
let message_buffer = builder.build_bitcast(
|
||||
message_buffer_raw,
|
||||
env.context
|
||||
.i8_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.ptr_type(AddressSpace::Generic),
|
||||
"to **u8",
|
||||
);
|
||||
|
||||
env.builder
|
||||
.build_store(message_buffer.into_pointer_value(), ptr_arg);
|
||||
|
||||
let tag = env.context.i32_type().const_int(1, false);
|
||||
if true {
|
||||
let _call = env.build_intrinsic_call(LLVM_LONGJMP, &[buffer.into()]);
|
||||
} else {
|
||||
let _call = env.build_intrinsic_call(LLVM_LONGJMP, &[buffer.into(), tag.into()]);
|
||||
}
|
||||
|
||||
builder.build_unreachable();
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -278,7 +278,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
// build then block
|
||||
{
|
||||
builder.position_at_end(then_block);
|
||||
if !env.leak {
|
||||
if !env.is_gen_test {
|
||||
let ptr = builder.build_pointer_cast(
|
||||
refcount_ptr.value,
|
||||
ctx.i8_type().ptr_type(AddressSpace::Generic),
|
||||
|
@ -659,23 +659,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
Some(function)
|
||||
}
|
||||
|
||||
Closure(_, lambda_set, _) => {
|
||||
if lambda_set.contains_refcounted() {
|
||||
let function = modify_refcount_layout_build_function(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
&lambda_set.runtime_representation(),
|
||||
)?;
|
||||
|
||||
Some(function)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Struct(layouts) => {
|
||||
let function = modify_refcount_struct(env, layout_ids, layouts, mode, when_recursive);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue