add cli test configuration

This commit is contained in:
Folkert 2022-07-13 19:16:36 +02:00
parent 8c77899d8f
commit b229c70eec
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
4 changed files with 212 additions and 180 deletions

View file

@ -167,6 +167,41 @@ pub enum LlvmBackendMode {
/// Provides a testing implementation of primitives (roc_alloc, roc_panic, etc)
GenTest,
WasmGenTest,
CliTest,
}
impl LlvmBackendMode {
pub(crate) fn has_host(self) -> bool {
match self {
LlvmBackendMode::Binary => true,
LlvmBackendMode::GenTest => false,
LlvmBackendMode::WasmGenTest => false,
LlvmBackendMode::CliTest => false,
}
}
/// In other words, catches exceptions and returns a result
fn returns_roc_result(self) -> bool {
match self {
LlvmBackendMode::Binary => false,
LlvmBackendMode::GenTest => true,
LlvmBackendMode::WasmGenTest => true,
LlvmBackendMode::CliTest => true,
}
}
fn runs_expects(self) -> bool {
match self {
LlvmBackendMode::Binary => false,
LlvmBackendMode::GenTest => false,
LlvmBackendMode::WasmGenTest => false,
LlvmBackendMode::CliTest => true,
}
}
fn runs_expects_in_separate_process(self) -> bool {
false
}
}
pub struct Env<'a, 'ctx, 'env> {
@ -2870,8 +2905,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
bd.build_conditional_branch(condition, then_block, throw_block);
// if let OptLevel::Development = env.opt_level {
if false {
if env.mode.runs_expects() {
bd.position_at_end(throw_block);
match env.target_info.ptr_width() {
@ -2976,12 +3010,15 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
};
}
let func = env
.module
.get_function(bitcode::UTILS_EXPECT_FAILED_FINALIZE)
.unwrap();
// NOTE: signals to the parent process that an expect failed
if env.mode.runs_expects_in_separate_process() {
let func = env
.module
.get_function(bitcode::UTILS_EXPECT_FAILED_FINALIZE)
.unwrap();
bd.build_call(func, &[], "call_expect_finalize_failed");
bd.build_call(func, &[], "call_expect_finalize_failed");
}
bd.build_unconditional_branch(then_block);
}
@ -3617,24 +3654,21 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
let arguments_for_call = &arguments_for_call.into_bump_slice();
let call_result = match env.mode {
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest => {
debug_assert_eq!(args.len(), roc_function.get_params().len());
let call_result = if env.mode.returns_roc_result() {
debug_assert_eq!(args.len(), roc_function.get_params().len());
let roc_wrapper_function = make_exception_catcher(env, roc_function, return_layout);
debug_assert_eq!(
arguments_for_call.len(),
roc_wrapper_function.get_params().len()
);
let roc_wrapper_function = make_exception_catcher(env, roc_function, return_layout);
debug_assert_eq!(
arguments_for_call.len(),
roc_wrapper_function.get_params().len()
);
builder.position_at_end(entry);
builder.position_at_end(entry);
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.target_info);
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
}
LlvmBackendMode::Binary => {
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
}
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.target_info);
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
} else {
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
};
let output_arg_index = 0;
@ -3903,7 +3937,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
c_function_name: &str,
) -> FunctionValue<'ctx> {
match env.mode {
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest => {
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest | LlvmBackendMode::CliTest => {
return expose_function_to_host_help_c_abi_gen_test(
env,
ident_string,
@ -3961,7 +3995,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
debug_info_init!(env, size_function);
let return_type = match env.mode {
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest => {
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest | LlvmBackendMode::CliTest => {
roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
}
@ -4709,44 +4743,39 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
}
}
match env.mode {
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest => {
let call_result = set_jump_and_catch_long_jump(
env,
function_value,
evaluator,
&evaluator_arguments,
*return_layout,
);
if env.mode.returns_roc_result() {
let call_result = set_jump_and_catch_long_jump(
env,
function_value,
evaluator,
&evaluator_arguments,
*return_layout,
);
builder.build_store(output, call_result);
}
builder.build_store(output, call_result);
} else {
let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments);
LlvmBackendMode::Binary => {
let call_result =
call_roc_function(env, evaluator, return_layout, &evaluator_arguments);
if return_layout.is_passed_by_reference(env.target_info) {
let align_bytes = return_layout.alignment_bytes(env.target_info);
if return_layout.is_passed_by_reference(env.target_info) {
let align_bytes = return_layout.alignment_bytes(env.target_info);
if align_bytes > 0 {
let size = env
.ptr_int()
.const_int(return_layout.stack_size(env.target_info) as u64, false);
if align_bytes > 0 {
let size = env
.ptr_int()
.const_int(return_layout.stack_size(env.target_info) as u64, false);
env.builder
.build_memcpy(
output,
align_bytes,
call_result.into_pointer_value(),
align_bytes,
size,
)
.unwrap();
}
} else {
builder.build_store(output, call_result);
env.builder
.build_memcpy(
output,
align_bytes,
call_result.into_pointer_value(),
align_bytes,
size,
)
.unwrap();
}
} else {
builder.build_store(output, call_result);
}
};

View file

@ -7,7 +7,7 @@ use inkwell::values::BasicValue;
use inkwell::AddressSpace;
use roc_builtins::bitcode;
use super::build::{get_sjlj_buffer, LlvmBackendMode, LLVM_LONGJMP};
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)
@ -19,133 +19,128 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
let usize_type = env.ptr_int();
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
match env.mode {
LlvmBackendMode::Binary => { /* externs are provided by the platform */ }
LlvmBackendMode::WasmGenTest => { /* externs are provided by the wasm test platform */ }
LlvmBackendMode::GenTest => {
// 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();
if !env.mode.has_host() {
// 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());
debug_assert!(params.next().is_none());
// Add a basic block for the entry point
let entry = ctx.append_basic_block(fn_val, "entry");
// Add a basic block for the entry point
let entry = ctx.append_basic_block(fn_val, "entry");
builder.position_at_end(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();
// 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));
builder.build_return(Some(&retval));
if cfg!(debug_assertions) {
crate::llvm::build::verify_fn(fn_val);
}
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);
}
}
add_sjlj_roc_panic(env)
}
// 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);
}
}
add_sjlj_roc_panic(env)
}
}