mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
commit
099d9e35f6
6 changed files with 333 additions and 88 deletions
|
@ -1,7 +1,6 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::execution_engine::ExecutionEngine;
|
use inkwell::execution_engine::ExecutionEngine;
|
||||||
use inkwell::types::BasicType;
|
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use roc_builtins::unique::uniq_stdlib;
|
use roc_builtins::unique::uniq_stdlib;
|
||||||
use roc_can::constraint::Constraint;
|
use roc_can::constraint::Constraint;
|
||||||
|
@ -15,7 +14,6 @@ use roc_constrain::module::{constrain_imported_values, load_builtin_aliases, Imp
|
||||||
use roc_fmt::annotation::{Formattable, Newlines, Parens};
|
use roc_fmt::annotation::{Formattable, Newlines, Parens};
|
||||||
use roc_gen::layout_id::LayoutIds;
|
use roc_gen::layout_id::LayoutIds;
|
||||||
use roc_gen::llvm::build::{build_proc, build_proc_header, OptLevel};
|
use roc_gen::llvm::build::{build_proc, build_proc_header, OptLevel};
|
||||||
use roc_gen::llvm::convert::basic_type_from_layout;
|
|
||||||
use roc_module::ident::Ident;
|
use roc_module::ident::Ident;
|
||||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_mono::ir::Procs;
|
use roc_mono::ir::Procs;
|
||||||
|
@ -223,10 +221,6 @@ fn gen(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<ReplOutput, Fa
|
||||||
// in --release mode and then trying to eval anything in the repl.
|
// in --release mode and then trying to eval anything in the repl.
|
||||||
ExecutionEngine::link_in_mc_jit();
|
ExecutionEngine::link_in_mc_jit();
|
||||||
|
|
||||||
let main_fn_type = basic_type_from_layout(&arena, &context, &main_ret_layout, ptr_bytes)
|
|
||||||
.fn_type(&[], false);
|
|
||||||
let main_fn_name = "$Test.main";
|
|
||||||
|
|
||||||
// Compile and add all the Procs before adding main
|
// Compile and add all the Procs before adding main
|
||||||
let mut env = roc_gen::llvm::build::Env {
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
|
@ -322,23 +316,10 @@ fn gen(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<ReplOutput, Fa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add main to the module.
|
let (main_fn_name, main_fn) = roc_gen::llvm::build::make_main_function(
|
||||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
|
||||||
let cc = roc_gen::llvm::build::FAST_CALL_CONV;
|
|
||||||
|
|
||||||
main_fn.set_call_conventions(cc);
|
|
||||||
|
|
||||||
// Add main's body
|
|
||||||
let basic_block = context.append_basic_block(main_fn, "entry");
|
|
||||||
|
|
||||||
builder.position_at_end(basic_block);
|
|
||||||
|
|
||||||
// builds the function body (return statement included)
|
|
||||||
roc_gen::llvm::build::build_exp_stmt(
|
|
||||||
&env,
|
&env,
|
||||||
&mut layout_ids,
|
&mut layout_ids,
|
||||||
&mut roc_gen::llvm::build::Scope::default(),
|
&main_ret_layout,
|
||||||
main_fn,
|
|
||||||
&main_body,
|
&main_body,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -118,20 +118,67 @@ fn jit_to_ast_help<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Functions can return structs of either 8 or 16 bytes, depending
|
|
||||||
// on whether we're compiling for a 64-bit or 32-bit target.
|
|
||||||
match env.ptr_bytes {
|
match env.ptr_bytes {
|
||||||
// 64-bit target (8-byte pointers, 16-byte structs)
|
// 64-bit target (8-byte pointers, 16-byte structs)
|
||||||
8 => jit_map!(
|
8 => match layout.stack_size(env.ptr_bytes) {
|
||||||
execution_engine,
|
8 => {
|
||||||
main_fn_name,
|
// just one eightbyte, returned as-is
|
||||||
[u8; 16],
|
jit_map!(execution_engine, main_fn_name, [u8; 8], |bytes: [u8; 8]| {
|
||||||
|bytes: [u8; 16]| { ptr_to_ast((&bytes).as_ptr() as *const libc::c_void) }
|
ptr_to_ast((&bytes).as_ptr() as *const libc::c_void)
|
||||||
),
|
})
|
||||||
|
}
|
||||||
|
16 => {
|
||||||
|
// two eightbytes, returned as-is
|
||||||
|
jit_map!(
|
||||||
|
execution_engine,
|
||||||
|
main_fn_name,
|
||||||
|
[u8; 16],
|
||||||
|
|bytes: [u8; 16]| {
|
||||||
|
ptr_to_ast((&bytes).as_ptr() as *const libc::c_void)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// anything more than 2 eightbytes
|
||||||
|
// the return "value" is a pointer to the result
|
||||||
|
jit_map!(
|
||||||
|
execution_engine,
|
||||||
|
main_fn_name,
|
||||||
|
*const u8,
|
||||||
|
|bytes: *const u8| { ptr_to_ast(bytes as *const libc::c_void) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
// 32-bit target (4-byte pointers, 8-byte structs)
|
// 32-bit target (4-byte pointers, 8-byte structs)
|
||||||
4 => jit_map!(execution_engine, main_fn_name, [u8; 8], |bytes: [u8; 8]| {
|
4 => {
|
||||||
ptr_to_ast((&bytes).as_ptr() as *const libc::c_void)
|
// TODO what are valid return sizes here?
|
||||||
}),
|
// this is just extrapolated from the 64-bit case above
|
||||||
|
// and not (yet) actually tested on a 32-bit system
|
||||||
|
match layout.stack_size(env.ptr_bytes) {
|
||||||
|
4 => {
|
||||||
|
// just one fourbyte, returned as-is
|
||||||
|
jit_map!(execution_engine, main_fn_name, [u8; 4], |bytes: [u8; 4]| {
|
||||||
|
ptr_to_ast((&bytes).as_ptr() as *const libc::c_void)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
8 => {
|
||||||
|
// just one fourbyte, returned as-is
|
||||||
|
jit_map!(execution_engine, main_fn_name, [u8; 8], |bytes: [u8; 8]| {
|
||||||
|
ptr_to_ast((&bytes).as_ptr() as *const libc::c_void)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// anything more than 2 fourbytes
|
||||||
|
// the return "value" is a pointer to the result
|
||||||
|
jit_map!(
|
||||||
|
execution_engine,
|
||||||
|
main_fn_name,
|
||||||
|
*const u8,
|
||||||
|
|bytes: *const u8| { ptr_to_ast(bytes as *const libc::c_void) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
other => {
|
other => {
|
||||||
panic!("Unsupported target: Roc cannot currently compile to systems where pointers are {} bytes in length.", other);
|
panic!("Unsupported target: Roc cannot currently compile to systems where pointers are {} bytes in length.", other);
|
||||||
}
|
}
|
||||||
|
@ -280,7 +327,7 @@ fn struct_to_ast<'a>(
|
||||||
output.push(loc_field);
|
output.push(loc_field);
|
||||||
|
|
||||||
// Advance the field pointer to the next field.
|
// Advance the field pointer to the next field.
|
||||||
field_ptr = unsafe { ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
|
field_ptr = unsafe { field_ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Record {
|
Expr::Record {
|
||||||
|
|
|
@ -232,6 +232,15 @@ mod repl_eval {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_element_record() {
|
||||||
|
// if this tests turns out to fail on 32-bit platforms, look at jit_to_ast_help
|
||||||
|
expect_success(
|
||||||
|
"{ a: 1, b: 2, c: 3 }",
|
||||||
|
"{ a: 1, b: 2, c: 3 } : { a : Num *, b : Num *, c : Num * }",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn multiline_string() {
|
// fn multiline_string() {
|
||||||
// // If a string contains newlines, format it as a multiline string in the output
|
// // If a string contains newlines, format it as a multiline string in the output
|
||||||
|
|
|
@ -219,6 +219,120 @@ pub fn construct_optimization_passes<'a>(
|
||||||
(mpm, fpm)
|
(mpm, fpm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For communication with C (tests and platforms) we need to abide by the C calling convention
|
||||||
|
///
|
||||||
|
/// While small values are just returned like with the fast CC, larger structures need to
|
||||||
|
/// be written into a pointer (into the callers stack)
|
||||||
|
enum PassVia {
|
||||||
|
Register,
|
||||||
|
Memory,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PassVia {
|
||||||
|
fn from_layout(ptr_bytes: u32, layout: &Layout<'_>) -> Self {
|
||||||
|
if layout.stack_size(ptr_bytes) > 16 {
|
||||||
|
PassVia::Memory
|
||||||
|
} else {
|
||||||
|
PassVia::Register
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_main_function<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
layout: &Layout<'a>,
|
||||||
|
main_body: &roc_mono::ir::Stmt<'a>,
|
||||||
|
) -> (&'static str, &'a FunctionValue<'ctx>) {
|
||||||
|
use inkwell::types::BasicType;
|
||||||
|
use PassVia::*;
|
||||||
|
|
||||||
|
let context = env.context;
|
||||||
|
let builder = env.builder;
|
||||||
|
let arena = env.arena;
|
||||||
|
let ptr_bytes = env.ptr_bytes;
|
||||||
|
|
||||||
|
let return_type = basic_type_from_layout(&arena, context, &layout, ptr_bytes);
|
||||||
|
let roc_main_fn_name = "$Test.roc_main";
|
||||||
|
|
||||||
|
// make the roc main function
|
||||||
|
let roc_main_fn_type = return_type.fn_type(&[], false);
|
||||||
|
|
||||||
|
// Add main to the module.
|
||||||
|
let roc_main_fn = env
|
||||||
|
.module
|
||||||
|
.add_function(roc_main_fn_name, roc_main_fn_type, None);
|
||||||
|
|
||||||
|
// our exposed main function adheres to the C calling convention
|
||||||
|
roc_main_fn.set_call_conventions(FAST_CALL_CONV);
|
||||||
|
|
||||||
|
// Add main's body
|
||||||
|
let basic_block = context.append_basic_block(roc_main_fn, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(basic_block);
|
||||||
|
|
||||||
|
// builds the function body (return statement included)
|
||||||
|
build_exp_stmt(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
&mut Scope::default(),
|
||||||
|
roc_main_fn,
|
||||||
|
main_body,
|
||||||
|
);
|
||||||
|
|
||||||
|
// build the C calling convention wrapper
|
||||||
|
|
||||||
|
let main_fn_name = "$Test.main";
|
||||||
|
let register_or_memory = PassVia::from_layout(env.ptr_bytes, layout);
|
||||||
|
|
||||||
|
let main_fn_type = match register_or_memory {
|
||||||
|
Memory => {
|
||||||
|
let return_value_ptr = context.i64_type().ptr_type(AddressSpace::Generic).into();
|
||||||
|
context.void_type().fn_type(&[return_value_ptr], false)
|
||||||
|
}
|
||||||
|
Register => return_type.fn_type(&[], false),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add main to the module.
|
||||||
|
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||||
|
|
||||||
|
// our exposed main function adheres to the C calling convention
|
||||||
|
main_fn.set_call_conventions(C_CALL_CONV);
|
||||||
|
|
||||||
|
// Add main's body
|
||||||
|
let basic_block = context.append_basic_block(main_fn, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(basic_block);
|
||||||
|
|
||||||
|
let call = builder.build_call(roc_main_fn, &[], "call_roc_main");
|
||||||
|
call.set_call_convention(FAST_CALL_CONV);
|
||||||
|
|
||||||
|
let call_result = call.try_as_basic_value().left().unwrap();
|
||||||
|
|
||||||
|
match register_or_memory {
|
||||||
|
Memory => {
|
||||||
|
// write the result into the supplied pointer
|
||||||
|
// this is a void function, therefore return None
|
||||||
|
let ptr_return_type = return_type.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
|
let ptr_as_int = main_fn.get_first_param().unwrap();
|
||||||
|
|
||||||
|
let ptr = builder.build_bitcast(ptr_as_int, ptr_return_type, "caller_ptr");
|
||||||
|
|
||||||
|
builder.build_store(ptr.into_pointer_value(), call_result);
|
||||||
|
|
||||||
|
builder.build_return(None);
|
||||||
|
}
|
||||||
|
Register => {
|
||||||
|
// construct a normal return
|
||||||
|
// values are passed to the caller via registers
|
||||||
|
builder.build_return(Some(&call_result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(main_fn_name, env.arena.alloc(main_fn))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_inplace_from_layout(layout: &Layout<'_>) -> InPlace {
|
fn get_inplace_from_layout(layout: &Layout<'_>) -> InPlace {
|
||||||
match layout {
|
match layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => InPlace::InPlace,
|
Layout::Builtin(Builtin::EmptyList) => InPlace::InPlace,
|
||||||
|
|
|
@ -533,4 +533,147 @@ mod gen_records {
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_2() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ x: 3, y: 5 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
[3, 5],
|
||||||
|
[i64; 2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_3() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ x: 3, y: 5, z: 4 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(3, 5, 4),
|
||||||
|
(i64, i64, i64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_4() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 3, b: 5, c: 4, d: 2 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
[3, 5, 4, 2],
|
||||||
|
[i64; 4]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_5() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 3, b: 5, c: 4, d: 2, e: 1 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
[3, 5, 4, 2, 1],
|
||||||
|
[i64; 5]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_6() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
[3, 5, 4, 2, 1, 7],
|
||||||
|
[i64; 6]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_7() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
[3, 5, 4, 2, 1, 7, 8],
|
||||||
|
[i64; 7]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_float_int() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 3.14, b: 0x1 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(3.14, 0x1),
|
||||||
|
(f64, i64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_int_float() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 0x1, b: 3.14 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(0x1, 3.14),
|
||||||
|
(i64, f64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_float_float() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 6.28, b: 3.14 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(6.28, 3.14),
|
||||||
|
(f64, f64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_record_float_float_float() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 6.28, b: 3.14, c: 0.1 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(6.28, 3.14, 0.1),
|
||||||
|
(f64, f64, f64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn just_to_be_sure() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ a: 1, b : 2, c : 3 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
[1, 2, 3],
|
||||||
|
[i64; 3]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,8 @@ pub fn helper_without_uniqueness<'a>(
|
||||||
context: &'a inkwell::context::Context,
|
context: &'a inkwell::context::Context,
|
||||||
) -> (&'static str, inkwell::execution_engine::ExecutionEngine<'a>) {
|
) -> (&'static str, inkwell::execution_engine::ExecutionEngine<'a>) {
|
||||||
use crate::helpers::{can_expr, infer_expr, CanExprOut};
|
use crate::helpers::{can_expr, infer_expr, CanExprOut};
|
||||||
use inkwell::types::BasicType;
|
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use roc_gen::llvm::build::Scope;
|
|
||||||
use roc_gen::llvm::build::{build_proc, build_proc_header};
|
use roc_gen::llvm::build::{build_proc, build_proc_header};
|
||||||
use roc_gen::llvm::convert::basic_type_from_layout;
|
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
|
|
||||||
let target = target_lexicon::Triple::host();
|
let target = target_lexicon::Triple::host();
|
||||||
|
@ -66,7 +63,7 @@ pub fn helper_without_uniqueness<'a>(
|
||||||
roc_gen::llvm::build::construct_optimization_passes(module, opt_level);
|
roc_gen::llvm::build::construct_optimization_passes(module, opt_level);
|
||||||
|
|
||||||
// Compute main_fn_type before moving subs to Env
|
// Compute main_fn_type before moving subs to Env
|
||||||
let layout = Layout::new(&arena, content, &subs).unwrap_or_else(|err| {
|
let return_layout = Layout::new(&arena, content, &subs).unwrap_or_else(|err| {
|
||||||
panic!(
|
panic!(
|
||||||
"Code gen error in NON-OPTIMIZED test: could not convert to layout. Err was {:?}",
|
"Code gen error in NON-OPTIMIZED test: could not convert to layout. Err was {:?}",
|
||||||
err
|
err
|
||||||
|
@ -76,10 +73,6 @@ pub fn helper_without_uniqueness<'a>(
|
||||||
.create_jit_execution_engine(OptimizationLevel::None)
|
.create_jit_execution_engine(OptimizationLevel::None)
|
||||||
.expect("Error creating JIT execution engine for test");
|
.expect("Error creating JIT execution engine for test");
|
||||||
|
|
||||||
let main_fn_type =
|
|
||||||
basic_type_from_layout(&arena, context, &layout, ptr_bytes).fn_type(&[], false);
|
|
||||||
let main_fn_name = "$Test.main";
|
|
||||||
|
|
||||||
// Compile and add all the Procs before adding main
|
// Compile and add all the Procs before adding main
|
||||||
let mut env = roc_gen::llvm::build::Env {
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
|
@ -163,25 +156,8 @@ pub fn helper_without_uniqueness<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add main to the module.
|
let (main_fn_name, main_fn) =
|
||||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
roc_gen::llvm::build::make_main_function(&env, &mut layout_ids, &return_layout, &main_body);
|
||||||
let cc = roc_gen::llvm::build::FAST_CALL_CONV;
|
|
||||||
|
|
||||||
main_fn.set_call_conventions(cc);
|
|
||||||
|
|
||||||
// Add main's body
|
|
||||||
let basic_block = context.append_basic_block(main_fn, "entry");
|
|
||||||
|
|
||||||
builder.position_at_end(basic_block);
|
|
||||||
|
|
||||||
// builds the function body (return statement included)
|
|
||||||
roc_gen::llvm::build::build_exp_stmt(
|
|
||||||
&env,
|
|
||||||
&mut layout_ids,
|
|
||||||
&mut Scope::default(),
|
|
||||||
main_fn,
|
|
||||||
&main_body,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
||||||
// env.module.print_to_stderr();
|
// env.module.print_to_stderr();
|
||||||
|
@ -212,11 +188,8 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
context: &'a inkwell::context::Context,
|
context: &'a inkwell::context::Context,
|
||||||
) -> (&'static str, inkwell::execution_engine::ExecutionEngine<'a>) {
|
) -> (&'static str, inkwell::execution_engine::ExecutionEngine<'a>) {
|
||||||
use crate::helpers::{infer_expr, uniq_expr};
|
use crate::helpers::{infer_expr, uniq_expr};
|
||||||
use inkwell::types::BasicType;
|
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use roc_gen::llvm::build::Scope;
|
|
||||||
use roc_gen::llvm::build::{build_proc, build_proc_header};
|
use roc_gen::llvm::build::{build_proc, build_proc_header};
|
||||||
use roc_gen::llvm::convert::basic_type_from_layout;
|
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
|
|
||||||
let target = target_lexicon::Triple::host();
|
let target = target_lexicon::Triple::host();
|
||||||
|
@ -258,7 +231,7 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
let (mpm, fpm) = roc_gen::llvm::build::construct_optimization_passes(module, opt_level);
|
let (mpm, fpm) = roc_gen::llvm::build::construct_optimization_passes(module, opt_level);
|
||||||
|
|
||||||
// Compute main_fn_type before moving subs to Env
|
// Compute main_fn_type before moving subs to Env
|
||||||
let layout = Layout::new(&arena, content, &subs).unwrap_or_else(|err| {
|
let return_layout = Layout::new(&arena, content, &subs).unwrap_or_else(|err| {
|
||||||
panic!(
|
panic!(
|
||||||
"Code gen error in OPTIMIZED test: could not convert to layout. Err was {:?}",
|
"Code gen error in OPTIMIZED test: could not convert to layout. Err was {:?}",
|
||||||
err
|
err
|
||||||
|
@ -269,11 +242,6 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
.create_jit_execution_engine(OptimizationLevel::None)
|
.create_jit_execution_engine(OptimizationLevel::None)
|
||||||
.expect("Error creating JIT execution engine for test");
|
.expect("Error creating JIT execution engine for test");
|
||||||
|
|
||||||
let main_fn_type = basic_type_from_layout(&arena, context, &layout, ptr_bytes)
|
|
||||||
.fn_type(&[], false)
|
|
||||||
.clone();
|
|
||||||
let main_fn_name = "$Test.main";
|
|
||||||
|
|
||||||
// Compile and add all the Procs before adding main
|
// Compile and add all the Procs before adding main
|
||||||
let mut env = roc_gen::llvm::build::Env {
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
|
@ -357,25 +325,8 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add main to the module.
|
let (main_fn_name, main_fn) =
|
||||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
roc_gen::llvm::build::make_main_function(&env, &mut layout_ids, &return_layout, &main_body);
|
||||||
let cc = roc_gen::llvm::build::FAST_CALL_CONV;
|
|
||||||
|
|
||||||
main_fn.set_call_conventions(cc);
|
|
||||||
|
|
||||||
// Add main's body
|
|
||||||
let basic_block = context.append_basic_block(main_fn, "entry");
|
|
||||||
|
|
||||||
builder.position_at_end(basic_block);
|
|
||||||
|
|
||||||
// builds the function body (return statement included)
|
|
||||||
roc_gen::llvm::build::build_exp_stmt(
|
|
||||||
&env,
|
|
||||||
&mut layout_ids,
|
|
||||||
&mut Scope::default(),
|
|
||||||
main_fn,
|
|
||||||
&main_body,
|
|
||||||
);
|
|
||||||
|
|
||||||
// you're in the version with uniqueness!
|
// you're in the version with uniqueness!
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue