mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
get wasm dev backend working
This commit is contained in:
parent
82764dc697
commit
b8fb83af86
4 changed files with 126 additions and 7 deletions
|
@ -1981,12 +1981,33 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
|
||||||
self.register_helper_proc(spec_sym, spec_layout, ProcSource::Helper);
|
self.register_helper_proc(spec_sym, spec_layout, ProcSource::Helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get_existing_refcount_fn_index(proc_symbol, layout, op)
|
self.get_existing_helper_fn_index(proc_symbol, layout, op)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a copy helper procedure and return a pointer (table index) to it
|
||||||
|
/// This allows it to be indirectly called from Zig code
|
||||||
|
pub fn get_copy_fn_index(&mut self, layout: InLayout<'a>) -> u32 {
|
||||||
|
let ident_ids = self
|
||||||
|
.interns
|
||||||
|
.all_ident_ids
|
||||||
|
.get_mut(&self.env.module_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (proc_symbol, new_specializations) =
|
||||||
|
self.helper_proc_gen
|
||||||
|
.gen_copy_proc(ident_ids, self.layout_interner, layout);
|
||||||
|
|
||||||
|
// If any new specializations were created, register their symbol data
|
||||||
|
for (spec_sym, spec_layout) in new_specializations.into_iter() {
|
||||||
|
self.register_helper_proc(spec_sym, spec_layout, ProcSource::Helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.get_existing_helper_fn_index(proc_symbol, layout, HelperOp::IndirectCopy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return a pointer (table index) to a refcount helper procedure.
|
/// return a pointer (table index) to a refcount helper procedure.
|
||||||
/// This allows it to be indirectly called from Zig code
|
/// This allows it to be indirectly called from Zig code
|
||||||
pub fn get_existing_refcount_fn_index(
|
pub fn get_existing_helper_fn_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
proc_symbol: Symbol,
|
proc_symbol: Symbol,
|
||||||
layout: InLayout<'a>,
|
layout: InLayout<'a>,
|
||||||
|
|
|
@ -352,7 +352,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
elem_layout.stack_size_and_alignment(backend.layout_interner);
|
elem_layout.stack_size_and_alignment(backend.layout_interner);
|
||||||
|
|
||||||
let elem_refcounted = backend.layout_interner.contains_refcounted(elem_in_layout);
|
let elem_refcounted = backend.layout_interner.contains_refcounted(elem_in_layout);
|
||||||
let dec_fn = backend.get_existing_refcount_fn_index(
|
let dec_fn = backend.get_existing_helper_fn_index(
|
||||||
dec_fn_sym,
|
dec_fn_sym,
|
||||||
elem_in_layout,
|
elem_in_layout,
|
||||||
HelperOp::IndirectDec,
|
HelperOp::IndirectDec,
|
||||||
|
@ -476,6 +476,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
||||||
let dec_fn_ptr =
|
let dec_fn_ptr =
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec);
|
||||||
|
let copy_fn_ptr = build_copy_element_fn(backend, elem_in_layout);
|
||||||
|
|
||||||
// Load all the arguments for Zig
|
// Load all the arguments for Zig
|
||||||
// (List return pointer) i32
|
// (List return pointer) i32
|
||||||
|
@ -488,6 +489,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
// inc: Inc i32
|
// inc: Inc i32
|
||||||
// dec: Dec i32
|
// dec: Dec i32
|
||||||
// out_element: ?[*]u8, i32
|
// out_element: ?[*]u8, i32
|
||||||
|
// copy: CopyFn, i32
|
||||||
|
|
||||||
let code_builder = &mut backend.code_builder;
|
let code_builder = &mut backend.code_builder;
|
||||||
|
|
||||||
|
@ -517,6 +519,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
code_builder.i32_const((ret_offset + ret_elem_offset) as i32);
|
code_builder.i32_const((ret_offset + ret_elem_offset) as i32);
|
||||||
code_builder.i32_add();
|
code_builder.i32_add();
|
||||||
}
|
}
|
||||||
|
code_builder.i32_const(copy_fn_ptr);
|
||||||
|
|
||||||
// There is an in-place version of this but we don't use it for dev backends. No morphic_lib analysis.
|
// There is an in-place version of this but we don't use it for dev backends. No morphic_lib analysis.
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_REPLACE);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_REPLACE);
|
||||||
|
@ -689,16 +692,18 @@ impl<'a> LowLevelCall<'a> {
|
||||||
let list: Symbol = self.arguments[0];
|
let list: Symbol = self.arguments[0];
|
||||||
let elem: Symbol = self.arguments[1];
|
let elem: Symbol = self.arguments[1];
|
||||||
|
|
||||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout_raw);
|
let elem_in_layout = unwrap_list_elem_layout(self.ret_layout_raw);
|
||||||
let elem_width = backend.layout_interner.stack_size(elem_layout);
|
let elem_width = backend.layout_interner.stack_size(elem_in_layout);
|
||||||
let (elem_local, elem_offset, _) =
|
let (elem_local, elem_offset, _) =
|
||||||
ensure_symbol_is_in_memory(backend, elem, elem_layout, backend.env.arena);
|
ensure_symbol_is_in_memory(backend, elem, elem_in_layout, backend.env.arena);
|
||||||
|
let copy_fn_ptr = build_copy_element_fn(backend, elem_in_layout);
|
||||||
|
|
||||||
// Zig arguments Wasm types
|
// Zig arguments Wasm types
|
||||||
// (return pointer) i32
|
// (return pointer) i32
|
||||||
// list: RocList i32
|
// list: RocList i32
|
||||||
// element: Opaque i32
|
// element: Opaque i32
|
||||||
// element_width: usize i32
|
// element_width: usize i32
|
||||||
|
// copy: CopyFn, i32
|
||||||
|
|
||||||
// return pointer and list
|
// return pointer and list
|
||||||
backend.storage.load_symbols_for_call(
|
backend.storage.load_symbols_for_call(
|
||||||
|
@ -715,6 +720,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
backend.code_builder.i32_const(elem_width as i32);
|
backend.code_builder.i32_const(elem_width as i32);
|
||||||
|
backend.code_builder.i32_const(copy_fn_ptr);
|
||||||
|
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND_UNSAFE);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND_UNSAFE);
|
||||||
}
|
}
|
||||||
|
@ -734,6 +740,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
let elem_refcounted = backend.layout_interner.contains_refcounted(elem_in_layout);
|
let elem_refcounted = backend.layout_interner.contains_refcounted(elem_in_layout);
|
||||||
let inc_fn_ptr =
|
let inc_fn_ptr =
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
||||||
|
let copy_fn_ptr = build_copy_element_fn(backend, elem_in_layout);
|
||||||
|
|
||||||
// Zig arguments Wasm types
|
// Zig arguments Wasm types
|
||||||
// (return pointer) i32
|
// (return pointer) i32
|
||||||
|
@ -743,6 +750,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
// element_width: usize i32
|
// element_width: usize i32
|
||||||
// element_refcounted: bool i32
|
// element_refcounted: bool i32
|
||||||
// inc: Inc i32
|
// inc: Inc i32
|
||||||
|
// copy: CopyFn, i32
|
||||||
|
|
||||||
// return pointer and list
|
// return pointer and list
|
||||||
backend.storage.load_symbols_for_call(
|
backend.storage.load_symbols_for_call(
|
||||||
|
@ -762,6 +770,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
backend.code_builder.i32_const(elem_width as i32);
|
backend.code_builder.i32_const(elem_width as i32);
|
||||||
backend.code_builder.i32_const(elem_refcounted as i32);
|
backend.code_builder.i32_const(elem_refcounted as i32);
|
||||||
backend.code_builder.i32_const(inc_fn_ptr);
|
backend.code_builder.i32_const(inc_fn_ptr);
|
||||||
|
backend.code_builder.i32_const(copy_fn_ptr);
|
||||||
|
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_PREPEND);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_PREPEND);
|
||||||
}
|
}
|
||||||
|
@ -870,6 +879,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
||||||
let dec_fn_ptr =
|
let dec_fn_ptr =
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec);
|
||||||
|
let copy_fn_ptr = build_copy_element_fn(backend, elem_in_layout);
|
||||||
|
|
||||||
// Zig arguments Wasm types
|
// Zig arguments Wasm types
|
||||||
// (return pointer) i32
|
// (return pointer) i32
|
||||||
|
@ -882,6 +892,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
// inc: Inc i32
|
// inc: Inc i32
|
||||||
// dec: Dec i32
|
// dec: Dec i32
|
||||||
// update_mode: UpdateMode, i32
|
// update_mode: UpdateMode, i32
|
||||||
|
// copy: CopyFn, i32
|
||||||
|
|
||||||
// Load the return pointer and the list
|
// Load the return pointer and the list
|
||||||
backend.storage.load_symbols_for_call(
|
backend.storage.load_symbols_for_call(
|
||||||
|
@ -900,6 +911,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
backend.code_builder.i32_const(inc_fn_ptr);
|
backend.code_builder.i32_const(inc_fn_ptr);
|
||||||
backend.code_builder.i32_const(dec_fn_ptr);
|
backend.code_builder.i32_const(dec_fn_ptr);
|
||||||
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
||||||
|
backend.code_builder.i32_const(copy_fn_ptr);
|
||||||
|
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_SWAP);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_SWAP);
|
||||||
}
|
}
|
||||||
|
@ -2784,6 +2796,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectInc);
|
||||||
let dec_fn_ptr =
|
let dec_fn_ptr =
|
||||||
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec);
|
build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec);
|
||||||
|
let copy_fn_ptr = build_copy_element_fn(backend, elem_in_layout);
|
||||||
|
|
||||||
let cb = &mut backend.code_builder;
|
let cb = &mut backend.code_builder;
|
||||||
|
|
||||||
|
@ -2798,6 +2811,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
// element_refcounted: bool i32
|
// element_refcounted: bool i32
|
||||||
// inc: Inc i32
|
// inc: Inc i32
|
||||||
// dec: Dec i32
|
// dec: Dec i32
|
||||||
|
// copy: CopyFn i32
|
||||||
|
|
||||||
backend.storage.load_symbols(cb, &[return_sym, *xs]);
|
backend.storage.load_symbols(cb, &[return_sym, *xs]);
|
||||||
cb.i32_const(wrapper_fn_ptr);
|
cb.i32_const(wrapper_fn_ptr);
|
||||||
|
@ -2817,6 +2831,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
cb.i32_const(elem_refcounted as i32);
|
cb.i32_const(elem_refcounted as i32);
|
||||||
cb.i32_const(inc_fn_ptr);
|
cb.i32_const(inc_fn_ptr);
|
||||||
cb.i32_const(dec_fn_ptr);
|
cb.i32_const(dec_fn_ptr);
|
||||||
|
cb.i32_const(copy_fn_ptr);
|
||||||
|
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_SORT_WITH);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_SORT_WITH);
|
||||||
}
|
}
|
||||||
|
@ -2869,3 +2884,8 @@ fn build_refcount_element_fn<'a>(
|
||||||
let rc_fn = backend.get_refcount_fn_index(elem_layout, rc_op);
|
let rc_fn = backend.get_refcount_fn_index(elem_layout, rc_op);
|
||||||
backend.get_fn_ptr(rc_fn)
|
backend.get_fn_ptr(rc_fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_copy_element_fn<'a>(backend: &mut WasmBackend<'a, '_>, elem_layout: InLayout<'a>) -> i32 {
|
||||||
|
let copy_fn = backend.get_copy_fn_index(elem_layout);
|
||||||
|
backend.get_fn_ptr(copy_fn)
|
||||||
|
}
|
||||||
|
|
38
crates/compiler/mono/src/code_gen_help/copy.rs
Normal file
38
crates/compiler/mono/src/code_gen_help/copy.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use roc_module::symbol::{IdentIds, Symbol};
|
||||||
|
|
||||||
|
use crate::ir::{Expr, Stmt};
|
||||||
|
use crate::layout::{InLayout, Layout, STLayoutInterner};
|
||||||
|
|
||||||
|
use super::{CodeGenHelp, Context};
|
||||||
|
|
||||||
|
const ARG_1: Symbol = Symbol::ARG_1;
|
||||||
|
const ARG_2: Symbol = Symbol::ARG_2;
|
||||||
|
|
||||||
|
pub fn copy_indirect<'a>(
|
||||||
|
root: &mut CodeGenHelp<'a>,
|
||||||
|
ident_ids: &mut IdentIds,
|
||||||
|
_ctx: &mut Context<'a>,
|
||||||
|
_layout_interner: &mut STLayoutInterner<'a>,
|
||||||
|
layout: InLayout<'a>,
|
||||||
|
) -> Stmt<'a> {
|
||||||
|
let arena = root.arena;
|
||||||
|
let unit = root.create_symbol(ident_ids, "unit");
|
||||||
|
let loaded = root.create_symbol(ident_ids, "loaded");
|
||||||
|
Stmt::Let(
|
||||||
|
loaded,
|
||||||
|
Expr::ptr_load(arena.alloc(ARG_2)),
|
||||||
|
layout,
|
||||||
|
arena.alloc(
|
||||||
|
//
|
||||||
|
Stmt::Let(
|
||||||
|
unit,
|
||||||
|
Expr::ptr_store(arena.alloc([ARG_1, loaded])),
|
||||||
|
Layout::UNIT,
|
||||||
|
arena.alloc(
|
||||||
|
//
|
||||||
|
Stmt::Ret(unit),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use crate::layout::{
|
||||||
STLayoutInterner, UnionLayout,
|
STLayoutInterner, UnionLayout,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod copy;
|
||||||
mod equality;
|
mod equality;
|
||||||
mod refcount;
|
mod refcount;
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ pub enum HelperOp {
|
||||||
Reset,
|
Reset,
|
||||||
ResetRef,
|
ResetRef,
|
||||||
Eq,
|
Eq,
|
||||||
|
IndirectCopy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HelperOp {
|
impl HelperOp {
|
||||||
|
@ -57,7 +59,7 @@ impl HelperOp {
|
||||||
pub fn is_indirect(&self) -> bool {
|
pub fn is_indirect(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Self::IndirectInc | Self::IndirectIncN | Self::IndirectDec
|
Self::IndirectInc | Self::IndirectIncN | Self::IndirectDec | Self::IndirectCopy
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,6 +277,25 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
(expr, ctx.new_linker_data)
|
(expr, ctx.new_linker_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a copy procedure, *without* a Call expression.
|
||||||
|
/// *This method should be rarely used* - only when the proc is to be called from Zig.
|
||||||
|
pub fn gen_copy_proc(
|
||||||
|
&mut self,
|
||||||
|
ident_ids: &mut IdentIds,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
|
layout: InLayout<'a>,
|
||||||
|
) -> (Symbol, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||||
|
let mut ctx = Context {
|
||||||
|
new_linker_data: Vec::new_in(self.arena),
|
||||||
|
recursive_union: None,
|
||||||
|
op: HelperOp::IndirectCopy,
|
||||||
|
};
|
||||||
|
|
||||||
|
let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout_interner, layout);
|
||||||
|
|
||||||
|
(proc_name, ctx.new_linker_data)
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
//
|
//
|
||||||
// CALL SPECIALIZED OP
|
// CALL SPECIALIZED OP
|
||||||
|
@ -321,6 +342,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
IndirectIncN => (LAYOUT_UNIT, arena.alloc([ptr_arg, self.layout_isize])),
|
IndirectIncN => (LAYOUT_UNIT, arena.alloc([ptr_arg, self.layout_isize])),
|
||||||
IndirectInc => (LAYOUT_UNIT, arena.alloc([ptr_arg])),
|
IndirectInc => (LAYOUT_UNIT, arena.alloc([ptr_arg])),
|
||||||
Eq => (LAYOUT_BOOL, self.arena.alloc([arg, arg])),
|
Eq => (LAYOUT_BOOL, self.arena.alloc([arg, arg])),
|
||||||
|
IndirectCopy => (LAYOUT_UNIT, self.arena.alloc([ptr_arg, ptr_arg])),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -430,6 +452,10 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
LAYOUT_BOOL,
|
LAYOUT_BOOL,
|
||||||
equality::eq_generic(self, ident_ids, ctx, layout_interner, layout),
|
equality::eq_generic(self, ident_ids, ctx, layout_interner, layout),
|
||||||
),
|
),
|
||||||
|
IndirectCopy => (
|
||||||
|
LAYOUT_UNIT,
|
||||||
|
copy::copy_indirect(self, ident_ids, ctx, layout_interner, layout),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let args: &'a [(InLayout<'a>, Symbol)] = {
|
let args: &'a [(InLayout<'a>, Symbol)] = {
|
||||||
|
@ -452,6 +478,11 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
self.arena.alloc([(ptr_layout, ARG_1)])
|
self.arena.alloc([(ptr_layout, ARG_1)])
|
||||||
}
|
}
|
||||||
Eq => self.arena.alloc([roc_value, (layout, ARG_2)]),
|
Eq => self.arena.alloc([roc_value, (layout, ARG_2)]),
|
||||||
|
IndirectCopy => {
|
||||||
|
let ptr_layout =
|
||||||
|
layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(layout));
|
||||||
|
self.arena.alloc([(ptr_layout, ARG_1), (ptr_layout, ARG_2)])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -524,6 +555,15 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
result: LAYOUT_BOOL,
|
result: LAYOUT_BOOL,
|
||||||
niche: Niche::NONE,
|
niche: Niche::NONE,
|
||||||
},
|
},
|
||||||
|
HelperOp::IndirectCopy => {
|
||||||
|
let ptr_layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(layout));
|
||||||
|
|
||||||
|
ProcLayout {
|
||||||
|
arguments: self.arena.alloc([ptr_layout, ptr_layout]),
|
||||||
|
result: LAYOUT_UNIT,
|
||||||
|
niche: Niche::NONE,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(proc_symbol, proc_layout)
|
(proc_symbol, proc_layout)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue