mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
working codegen
This commit is contained in:
parent
e7f9ff8b51
commit
8c99cdf817
5 changed files with 103 additions and 68 deletions
|
@ -704,6 +704,7 @@ impl<
|
|||
}
|
||||
} else {
|
||||
// This is a single element struct. Just copy the single field to the stack.
|
||||
dbg!(sym, layout);
|
||||
debug_assert_eq!(fields.len(), 1);
|
||||
self.copy_symbol_to_stack_offset(
|
||||
layout_interner,
|
||||
|
|
|
@ -266,6 +266,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
args: &'a [(InLayout<'a>, Symbol)],
|
||||
ret_layout: &InLayout<'a>,
|
||||
) {
|
||||
dbg!(layout_interner.dbg(*ret_layout));
|
||||
let returns_via_pointer =
|
||||
X86_64SystemV::returns_via_arg_pointer(layout_interner, ret_layout);
|
||||
|
||||
|
@ -276,7 +277,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
argument_offset: X86_64SystemV::SHADOW_SPACE_SIZE as i32 + 16,
|
||||
};
|
||||
|
||||
if returns_via_pointer {
|
||||
if dbg!(returns_via_pointer) {
|
||||
storage_manager.ret_pointer_arg(X86_64SystemV::GENERAL_PARAM_REGS[0]);
|
||||
}
|
||||
|
||||
|
@ -379,6 +380,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
}
|
||||
_ => {
|
||||
// This is a large type returned via the arg pointer.
|
||||
dbg!(sym);
|
||||
storage_manager.copy_symbol_to_arg_pointer(buf, sym, layout);
|
||||
// Also set the return reg to the arg pointer.
|
||||
storage_manager.load_to_specified_general_reg(
|
||||
|
|
|
@ -13,7 +13,7 @@ use roc_module::symbol;
|
|||
use roc_module::symbol::Interns;
|
||||
use roc_mono::ir::{Call, CallSpecId, Expr, UpdateModeId};
|
||||
use roc_mono::ir::{Proc, ProcLayout, Stmt};
|
||||
use roc_mono::layout::{LambdaName, Layout, LayoutIds, LayoutInterner, STLayoutInterner};
|
||||
use roc_mono::layout::{LambdaName, Layout, LayoutIds, LayoutInterner, Niche, STLayoutInterner};
|
||||
use roc_target::TargetInfo;
|
||||
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
|
||||
|
||||
|
@ -30,8 +30,6 @@ pub fn build_module<'a, 'r>(
|
|||
target: &Triple,
|
||||
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) -> Object<'a> {
|
||||
dbg!(&target);
|
||||
|
||||
match target {
|
||||
Triple {
|
||||
architecture: TargetArch::X86_64,
|
||||
|
@ -330,6 +328,24 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
let exposed_proc = build_exposed_proc(&mut backend, &proc);
|
||||
let exposed_generic_proc = build_exposed_generic_proc(&mut backend, &proc);
|
||||
|
||||
// ModuleId,
|
||||
// &mut STLayoutInterner<'a>,
|
||||
// &mut Interns,
|
||||
// &mut CodeGenHelp<'a>,
|
||||
// &mut Vec<'a, CallerProc<'a>>,
|
||||
|
||||
let (module_id, layout_interner, interns, code_gen_help, _) =
|
||||
backend.module_interns_helpers_mut();
|
||||
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
let test_helper = roc_mono::code_gen_help::test_helper(
|
||||
code_gen_help,
|
||||
ident_ids,
|
||||
layout_interner,
|
||||
&proc,
|
||||
);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let module_id = exposed_generic_proc.name.name().module_id();
|
||||
|
@ -341,6 +357,18 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
module_id.register_debug_idents(ident_ids);
|
||||
}
|
||||
|
||||
println!("{}", test_helper.to_pretty(backend.interner(), 200, true));
|
||||
|
||||
build_proc_symbol(
|
||||
&mut output,
|
||||
&mut layout_ids,
|
||||
&mut procs,
|
||||
&mut backend,
|
||||
layout,
|
||||
test_helper,
|
||||
Exposed::TestMain,
|
||||
);
|
||||
|
||||
build_proc_symbol(
|
||||
&mut output,
|
||||
&mut layout_ids,
|
||||
|
@ -615,44 +643,12 @@ fn build_exposed_generic_proc<'a, B: Backend<'a>>(backend: &mut B, proc: &Proc<'
|
|||
}
|
||||
}
|
||||
|
||||
fn build_test_main<'a, B: Backend<'a>>(
|
||||
output: &mut Object<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
procs: &mut Vec<'a, (String, SectionId, SymbolId, Proc<'a>)>,
|
||||
backend: &mut B,
|
||||
layout: ProcLayout<'a>,
|
||||
proc: Proc<'a>,
|
||||
exposed: Exposed,
|
||||
) {
|
||||
let sym = proc.name.name();
|
||||
|
||||
let section_id = output.add_section(
|
||||
output.segment_name(StandardSegment::Text).to_vec(),
|
||||
&b".text.test_main",
|
||||
SectionKind::Text,
|
||||
);
|
||||
|
||||
let fn_name = "test_main";
|
||||
|
||||
let proc_symbol = Symbol {
|
||||
name: fn_name.as_bytes().to_vec(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Text,
|
||||
scope: SymbolScope::Linkage,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(section_id),
|
||||
flags: SymbolFlags::None,
|
||||
};
|
||||
let proc_id = output.add_symbol(proc_symbol);
|
||||
procs.push((fn_name, section_id, proc_id, proc));
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum Exposed {
|
||||
ExposedGeneric,
|
||||
Exposed,
|
||||
NotExposed,
|
||||
TestMain,
|
||||
}
|
||||
|
||||
fn build_proc_symbol<'a, B: Backend<'a>>(
|
||||
|
@ -685,6 +681,7 @@ fn build_proc_symbol<'a, B: Backend<'a>>(
|
|||
None,
|
||||
layout.result,
|
||||
),
|
||||
Exposed::TestMain => String::from("test_main"),
|
||||
};
|
||||
|
||||
let proc_symbol = Symbol {
|
||||
|
@ -695,7 +692,7 @@ fn build_proc_symbol<'a, B: Backend<'a>>(
|
|||
// TODO: Depending on whether we are building a static or dynamic lib, this should change.
|
||||
// We should use Dynamic -> anyone, Linkage -> static link, Compilation -> this module only.
|
||||
scope: match exposed {
|
||||
Exposed::ExposedGeneric | Exposed::Exposed => SymbolScope::Dynamic,
|
||||
Exposed::ExposedGeneric | Exposed::Exposed | Exposed::TestMain => SymbolScope::Dynamic,
|
||||
Exposed::NotExposed => SymbolScope::Linkage,
|
||||
},
|
||||
weak: false,
|
||||
|
|
|
@ -850,7 +850,7 @@ fn layout_needs_helper_proc<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn test_helper<'a>(
|
||||
pub fn test_helper<'a>(
|
||||
env: &CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
|
@ -865,7 +865,21 @@ fn test_helper<'a>(
|
|||
.map(|(s, (l, _))| (*l, *s));
|
||||
let args = Vec::from_iter_in(it, env.arena).into_bump_slice();
|
||||
|
||||
let body = test_helper_body(env, ident_ids, layout_interner, main_proc, arguments);
|
||||
// tag: u64,
|
||||
// error_msg: *mut RocStr,
|
||||
// value: MaybeUninit<T>,
|
||||
let fields = [Layout::U64, Layout::U64, main_proc.ret_layout];
|
||||
let repr = LayoutRepr::Struct(env.arena.alloc(fields));
|
||||
let output_layout = layout_interner.insert_direct_no_semantic(repr);
|
||||
|
||||
let body = test_helper_body(
|
||||
env,
|
||||
ident_ids,
|
||||
layout_interner,
|
||||
main_proc,
|
||||
arguments,
|
||||
output_layout,
|
||||
);
|
||||
|
||||
let name = LambdaName::no_niche(env.create_symbol(ident_ids, "test_main"));
|
||||
|
||||
|
@ -874,7 +888,7 @@ fn test_helper<'a>(
|
|||
args,
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: main_proc.ret_layout,
|
||||
ret_layout: output_layout,
|
||||
is_self_recursive: main_proc.is_self_recursive,
|
||||
host_exposed_layouts: HostExposedLayouts::HostExposed {
|
||||
rigids: Default::default(),
|
||||
|
@ -890,6 +904,7 @@ fn test_helper_body<'a>(
|
|||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
main_proc: &Proc<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
output_layout: InLayout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
// let buffer = SetLongJmpBuffer
|
||||
let buffer_symbol = env.create_symbol(ident_ids, "buffer");
|
||||
|
@ -908,17 +923,10 @@ fn test_helper_body<'a>(
|
|||
op: LowLevel::SetJmp,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: &[buffer_symbol],
|
||||
arguments: env.arena.alloc([buffer_symbol]),
|
||||
});
|
||||
let is_longjmp_stmt = |next| Stmt::Let(is_longjmp_symbol, is_longjmp_expr, Layout::U64, next);
|
||||
|
||||
// tag: u64,
|
||||
// error_msg: *mut RocStr,
|
||||
// value: MaybeUninit<T>,
|
||||
let fields = [Layout::U64, Layout::U64, main_proc.ret_layout];
|
||||
let repr = LayoutRepr::Struct(env.arena.alloc(fields));
|
||||
let return_layout = layout_interner.insert_direct_no_semantic(repr);
|
||||
|
||||
// normal path, no panics
|
||||
let if_zero_stmt = {
|
||||
let it = main_proc.args.iter().map(|(a, _)| *a);
|
||||
|
@ -945,10 +953,10 @@ fn test_helper_body<'a>(
|
|||
let msg_ptr = |next| Stmt::Let(msg_ptr_symbol, msg_ptr_expr, Layout::U64, next);
|
||||
|
||||
// construct the record
|
||||
let output_symbol = env.create_symbol(ident_ids, "output");
|
||||
let output_symbol = env.create_symbol(ident_ids, "output_ok");
|
||||
let fields = [ok_tag_symbol, msg_ptr_symbol, result_symbol];
|
||||
let output_expr = Expr::Struct(env.arena.alloc(fields));
|
||||
let output = |next| Stmt::Let(output_symbol, output_expr, Layout::U64, next);
|
||||
let output = |next| Stmt::Let(output_symbol, output_expr, output_layout, next);
|
||||
|
||||
let arena = env.arena;
|
||||
result(arena.alloc(
|
||||
|
@ -981,31 +989,31 @@ fn test_helper_body<'a>(
|
|||
op: LowLevel::PtrLoad,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: &[alloca_symbol],
|
||||
arguments: env.arena.alloc([alloca_symbol]),
|
||||
});
|
||||
let load = |next| Stmt::Let(load_symbol, load_expr, Layout::U64, next);
|
||||
|
||||
// is_longjmp_symbol will the pointer to the error message
|
||||
let ok_tag_symbol = env.create_symbol(ident_ids, "ok_tag");
|
||||
let ok_tag_expr = Expr::Literal(Literal::Int((0 as i128).to_be_bytes()));
|
||||
let ok_tag = |next| Stmt::Let(ok_tag_symbol, ok_tag_expr, Layout::U64, next);
|
||||
let err_tag_symbol = env.create_symbol(ident_ids, "err_tag");
|
||||
let err_tag_expr = Expr::Literal(Literal::Int((1 as i128).to_be_bytes()));
|
||||
let err_tag = |next| Stmt::Let(err_tag_symbol, err_tag_expr, Layout::U64, next);
|
||||
|
||||
let msg_ptr_symbol = env.create_symbol(ident_ids, "msg_ptr");
|
||||
let msg_ptr_expr = Expr::Literal(Literal::Int((0 as i128).to_be_bytes()));
|
||||
let msg_ptr = |next| Stmt::Let(msg_ptr_symbol, msg_ptr_expr, Layout::U64, next);
|
||||
|
||||
// construct the record
|
||||
let output_symbol = env.create_symbol(ident_ids, "output");
|
||||
let fields = [ok_tag_symbol, msg_ptr_symbol, load_symbol];
|
||||
let output_symbol = env.create_symbol(ident_ids, "output_err");
|
||||
let fields = [err_tag_symbol, msg_ptr_symbol, load_symbol];
|
||||
let output_expr = Expr::Struct(env.arena.alloc(fields));
|
||||
let output = |next| Stmt::Let(output_symbol, output_expr, Layout::U64, next);
|
||||
let output = |next| Stmt::Let(output_symbol, output_expr, output_layout, next);
|
||||
|
||||
let arena = env.arena;
|
||||
arena.alloc(alloca(arena.alloc(
|
||||
//
|
||||
load(arena.alloc(
|
||||
//
|
||||
ok_tag(arena.alloc(
|
||||
err_tag(arena.alloc(
|
||||
//
|
||||
msg_ptr(arena.alloc(
|
||||
//
|
||||
|
@ -1019,13 +1027,19 @@ fn test_helper_body<'a>(
|
|||
)))
|
||||
};
|
||||
|
||||
switch_if_zero_else(
|
||||
env.arena,
|
||||
is_longjmp_symbol,
|
||||
return_layout,
|
||||
if_zero_stmt,
|
||||
if_nonzero_stmt,
|
||||
)
|
||||
buffer_stmt(env.arena.alloc(
|
||||
//
|
||||
is_longjmp_stmt(env.arena.alloc(
|
||||
//
|
||||
switch_if_zero_else(
|
||||
env.arena,
|
||||
is_longjmp_symbol,
|
||||
output_layout,
|
||||
if_zero_stmt,
|
||||
if_nonzero_stmt,
|
||||
),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
fn switch_if_zero_else<'a>(
|
||||
|
|
|
@ -267,7 +267,6 @@ macro_rules! assert_evals_to {
|
|||
};
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr, $leak:expr, $lazy_literals:expr) => {
|
||||
use bumpalo::Bump;
|
||||
use roc_gen_dev::run_jit_function_raw;
|
||||
|
||||
let arena = Bump::new();
|
||||
let (main_fn_name, errors, lib) =
|
||||
|
@ -279,7 +278,29 @@ macro_rules! assert_evals_to {
|
|||
let given = $transform(success);
|
||||
assert_eq!(&given, &expected);
|
||||
};
|
||||
run_jit_function_raw!(lib, main_fn_name, $ty, transform, errors)
|
||||
|
||||
unsafe {
|
||||
let main: libloading::Symbol<unsafe extern "C" fn() -> $ty> = lib
|
||||
.get(main_fn_name.as_bytes())
|
||||
.ok()
|
||||
.ok_or(format!("Unable to JIT compile `{}`", main_fn_name))
|
||||
.expect("errored");
|
||||
|
||||
let result = main();
|
||||
|
||||
if !errors.is_empty() {
|
||||
dbg!(&errors);
|
||||
|
||||
assert_eq!(
|
||||
errors,
|
||||
std::vec::Vec::new(),
|
||||
"Encountered errors: {:?}",
|
||||
errors
|
||||
);
|
||||
}
|
||||
|
||||
transform(result)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue