mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-19 01:59:48 +00:00
Merge remote-tracking branch 'origin/trunk' into remove-old-expect-logic
This commit is contained in:
commit
f05274faef
1139 changed files with 23491 additions and 21403 deletions
204
crates/compiler/gen_llvm/src/llvm/externs.rs
Normal file
204
crates/compiler/gen_llvm/src/llvm/externs.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||
use crate::llvm::build::{add_func, get_panic_msg_ptr, C_CALL_CONV};
|
||||
use crate::llvm::build::{CCReturn, Env, FunctionSpec};
|
||||
use inkwell::module::Linkage;
|
||||
use inkwell::types::BasicType;
|
||||
use inkwell::values::BasicValue;
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
|
||||
use super::build::{get_sjlj_buffer, LLVM_LONGJMP};
|
||||
|
||||
/// Define functions for roc_alloc, roc_realloc, and roc_dealloc
|
||||
/// which use libc implementations (malloc, realloc, and free)
|
||||
pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
||||
let ctx = env.context;
|
||||
let module = env.module;
|
||||
let builder = env.builder;
|
||||
|
||||
let usize_type = env.ptr_int();
|
||||
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
// roc_alloc
|
||||
{
|
||||
// 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_alloc").unwrap();
|
||||
let mut params = fn_val.get_param_iter();
|
||||
let size_arg = params.next().unwrap();
|
||||
let _alignment_arg = params.next().unwrap();
|
||||
|
||||
debug_assert!(params.next().is_none());
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = ctx.append_basic_block(fn_val, "entry");
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
// Call libc malloc()
|
||||
let retval = builder
|
||||
.build_array_malloc(ctx.i8_type(), size_arg.into_int_value(), "call_malloc")
|
||||
.unwrap();
|
||||
|
||||
builder.build_return(Some(&retval));
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
|
||||
// roc_realloc
|
||||
{
|
||||
let libc_realloc_val = {
|
||||
let fn_spec = FunctionSpec::cconv(
|
||||
env,
|
||||
CCReturn::Return,
|
||||
Some(i8_ptr_type.as_basic_type_enum()),
|
||||
&[
|
||||
// ptr: *void
|
||||
i8_ptr_type.into(),
|
||||
// size: usize
|
||||
usize_type.into(),
|
||||
],
|
||||
);
|
||||
let fn_val = add_func(env.context, module, "realloc", fn_spec, Linkage::External);
|
||||
|
||||
let mut params = fn_val.get_param_iter();
|
||||
let ptr_arg = params.next().unwrap();
|
||||
let size_arg = params.next().unwrap();
|
||||
|
||||
debug_assert!(params.next().is_none());
|
||||
|
||||
ptr_arg.set_name("ptr");
|
||||
size_arg.set_name("size");
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
|
||||
fn_val
|
||||
};
|
||||
|
||||
// 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_realloc").unwrap();
|
||||
let mut params = fn_val.get_param_iter();
|
||||
let ptr_arg = params.next().unwrap();
|
||||
let new_size_arg = params.next().unwrap();
|
||||
let _old_size_arg = params.next().unwrap();
|
||||
let _alignment_arg = params.next().unwrap();
|
||||
|
||||
debug_assert!(params.next().is_none());
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = ctx.append_basic_block(fn_val, "entry");
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
// Call libc realloc()
|
||||
let call = builder.build_call(
|
||||
libc_realloc_val,
|
||||
&[ptr_arg.into(), new_size_arg.into()],
|
||||
"call_libc_realloc",
|
||||
);
|
||||
|
||||
call.set_call_convention(C_CALL_CONV);
|
||||
|
||||
let retval = call.try_as_basic_value().left().unwrap();
|
||||
|
||||
builder.build_return(Some(&retval));
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
|
||||
// roc_dealloc
|
||||
{
|
||||
// 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_dealloc").unwrap();
|
||||
let mut params = fn_val.get_param_iter();
|
||||
let ptr_arg = params.next().unwrap();
|
||||
let _alignment_arg = params.next().unwrap();
|
||||
|
||||
debug_assert!(params.next().is_none());
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = ctx.append_basic_block(fn_val, "entry");
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
// Call libc free()
|
||||
builder.build_free(ptr_arg.into_pointer_value());
|
||||
|
||||
builder.build_return(None);
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
|
||||
if env.is_gen_test {
|
||||
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
|
||||
{
|
||||
// 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);
|
||||
|
||||
// write our error message pointer
|
||||
env.builder.build_store(get_panic_msg_ptr(env), ptr_arg);
|
||||
|
||||
build_longjmp_call(env);
|
||||
|
||||
builder.build_unreachable();
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_longjmp_call(env: &Env) {
|
||||
let jmp_buf = get_sjlj_buffer(env);
|
||||
if cfg!(target_arch = "aarch64") {
|
||||
// Call the Zig-linked longjmp: `void longjmp(i32*, i32)`
|
||||
let tag = env.context.i32_type().const_int(1, false);
|
||||
let _call =
|
||||
call_void_bitcode_fn(env, &[jmp_buf.into(), tag.into()], bitcode::UTILS_LONGJMP);
|
||||
} else {
|
||||
// Call the LLVM-intrinsic longjmp: `void @llvm.eh.sjlj.longjmp(i8* %setjmp_buf)`
|
||||
let jmp_buf_i8p = env.builder.build_bitcast(
|
||||
jmp_buf,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf i8*",
|
||||
);
|
||||
let _call = env.build_intrinsic_call(LLVM_LONGJMP, &[jmp_buf_i8p]);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue