Extract externs helpers into gen

This commit is contained in:
Richard Feldman 2021-05-23 12:12:00 -04:00
parent 3eb75619ea
commit e6ece40f76
4 changed files with 201 additions and 191 deletions

View File

@ -1,17 +1,15 @@
use crate::repl::eval;
use bumpalo::Bump;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::{Linkage, Module};
use inkwell::AddressSpace;
use inkwell::module::Linkage;
use roc_build::link::module_to_dylib;
use roc_build::program::FunctionIterator;
use roc_can::builtins::builtin_defs_map;
use roc_collections::all::{MutMap, MutSet};
use roc_fmt::annotation::Formattable;
use roc_fmt::annotation::{Newlines, Parens};
use roc_gen::llvm::build::{build_proc, build_proc_header, set_name, OptLevel, C_CALL_CONV};
use roc_gen::llvm::convert::ptr_int;
use roc_gen::llvm::build::{build_proc, build_proc_header, OptLevel};
use roc_gen::llvm::externs::add_default_roc_externs;
use roc_load::file::LoadingProblem;
use roc_parse::parser::SyntaxError;
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
@ -319,188 +317,3 @@ fn promote_expr_to_module(src: &str) -> String {
buffer
}
/// Define functions for roc_alloc, roc_realloc, and roc_dealloc
/// which use libc implementations (malloc, realloc, and free)
fn add_default_roc_externs<'ctx>(
ctx: &'ctx Context,
module: &Module<'ctx>,
builder: &Builder<'ctx>,
ptr_bytes: u32,
) {
let usize_type = ptr_int(ctx, ptr_bytes);
let i32_type = ctx.i32_type();
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
// roc_alloc
{
let fn_val = module.add_function(
"roc_alloc",
i8_ptr_type.fn_type(
&[
// alignment: u32
i32_type.into(),
// size: usize
usize_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
let mut params = fn_val.get_param_iter();
let alignment_arg = params.next().unwrap();
let size_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
set_name(alignment_arg, "alignment");
set_name(size_arg, "size");
// 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) {
roc_gen::llvm::build::verify_fn(fn_val);
}
}
// roc_realloc
{
let libc_realloc_val = {
let fn_val = module.add_function(
"realloc",
i8_ptr_type.fn_type(
&[
// ptr: *void
i8_ptr_type.into(),
// size: usize
usize_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
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());
set_name(ptr_arg, "ptr");
set_name(size_arg, "size");
if cfg!(debug_assertions) {
roc_gen::llvm::build::verify_fn(fn_val);
}
fn_val
};
let fn_val = module.add_function(
"roc_realloc",
i8_ptr_type.fn_type(
&[
// alignment: u32
i32_type.into(),
// ptr: *void
i8_ptr_type.into(),
// old_size: usize
usize_type.into(),
// new_size: usize
usize_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
let mut params = fn_val.get_param_iter();
let alignment_arg = params.next().unwrap();
let ptr_arg = params.next().unwrap();
let old_size_arg = params.next().unwrap();
let new_size_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
set_name(alignment_arg, "alignment");
set_name(ptr_arg, "ptr");
set_name(old_size_arg, "old_size");
set_name(new_size_arg, "new_size");
// 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, new_size_arg],
"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) {
roc_gen::llvm::build::verify_fn(fn_val);
}
}
// roc_dealloc
{
let fn_val = module.add_function(
"roc_dealloc",
ctx.void_type().fn_type(
&[
// alignment: u32
i32_type.into(),
// ptr: *void
i8_ptr_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
let mut params = fn_val.get_param_iter();
let alignment_arg = params.next().unwrap();
let ptr_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
set_name(alignment_arg, "alignment");
set_name(ptr_arg, "ptr");
// Call libc free()
builder.build_free(ptr_arg.into_pointer_value());
builder.build_return(None);
if cfg!(debug_assertions) {
roc_gen::llvm::build::verify_fn(fn_val);
}
}
}

View File

@ -0,0 +1,191 @@
use crate::llvm::build::{set_name, C_CALL_CONV};
use crate::llvm::convert::ptr_int;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::{Linkage, Module};
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,
) {
let usize_type = ptr_int(ctx, ptr_bytes);
let i32_type = ctx.i32_type();
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
// roc_alloc
{
let fn_val = module.add_function(
"roc_alloc",
i8_ptr_type.fn_type(
&[
// alignment: u32
i32_type.into(),
// size: usize
usize_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
let mut params = fn_val.get_param_iter();
let alignment_arg = params.next().unwrap();
let size_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
set_name(alignment_arg, "alignment");
set_name(size_arg, "size");
// 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_val = module.add_function(
"realloc",
i8_ptr_type.fn_type(
&[
// ptr: *void
i8_ptr_type.into(),
// size: usize
usize_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
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());
set_name(ptr_arg, "ptr");
set_name(size_arg, "size");
if cfg!(debug_assertions) {
crate::llvm::build::verify_fn(fn_val);
}
fn_val
};
let fn_val = module.add_function(
"roc_realloc",
i8_ptr_type.fn_type(
&[
// alignment: u32
i32_type.into(),
// ptr: *void
i8_ptr_type.into(),
// old_size: usize
usize_type.into(),
// new_size: usize
usize_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
let mut params = fn_val.get_param_iter();
let alignment_arg = params.next().unwrap();
let ptr_arg = params.next().unwrap();
let old_size_arg = params.next().unwrap();
let new_size_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
set_name(alignment_arg, "alignment");
set_name(ptr_arg, "ptr");
set_name(old_size_arg, "old_size");
set_name(new_size_arg, "new_size");
// 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, new_size_arg],
"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
{
let fn_val = module.add_function(
"roc_dealloc",
ctx.void_type().fn_type(
&[
// alignment: u32
i32_type.into(),
// ptr: *void
i8_ptr_type.into(),
],
false,
),
Some(Linkage::External),
);
fn_val.set_call_conventions(C_CALL_CONV);
let mut params = fn_val.get_param_iter();
let alignment_arg = params.next().unwrap();
let ptr_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
set_name(alignment_arg, "alignment");
set_name(ptr_arg, "ptr");
// 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);
}
}
}

View File

@ -6,4 +6,5 @@ pub mod build_list;
pub mod build_str;
pub mod compare;
pub mod convert;
pub mod externs;
pub mod refcounting;

View File

@ -4,6 +4,7 @@ use roc_build::program::FunctionIterator;
use roc_can::builtins::builtin_defs_map;
use roc_can::def::Def;
use roc_collections::all::{MutMap, MutSet};
use roc_gen::llvm::externs::add_default_roc_externs;
use roc_module::symbol::Symbol;
use roc_types::subs::VarStore;
@ -184,7 +185,6 @@ pub fn helper<'a>(
// strip Zig debug stuff
module.strip_debug_info();
let builder = context.create_builder();
let opt_level = if cfg!(debug_assertions) {
roc_gen::llvm::build::OptLevel::Normal
} else {
@ -216,6 +216,11 @@ pub fn helper<'a>(
}
}
// Add roc_alloc, roc_realloc, and roc_dealloc, since the repl has no
// platform to provide them.
let builder = context.create_builder();
add_default_roc_externs(&context, module, &builder, ptr_bytes);
// Compile and add all the Procs before adding main
let env = roc_gen::llvm::build::Env {
arena: &arena,