mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Create a high-level structure for Wasm backend
This commit is contained in:
parent
863f449048
commit
a1102222dd
2 changed files with 121 additions and 5 deletions
|
@ -6,3 +6,23 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
roc_collections = { path = "../collections" }
|
||||||
|
# roc_region = { path = "../region" }
|
||||||
|
# roc_load = { path = "../load" }
|
||||||
|
roc_module = { path = "../module" }
|
||||||
|
# roc_problem = { path = "../problem" }
|
||||||
|
# roc_types = { path = "../types" }
|
||||||
|
# roc_builtins = { path = "../builtins" }
|
||||||
|
# roc_constrain = { path = "../constrain" }
|
||||||
|
# roc_unify = { path = "../unify" }
|
||||||
|
# roc_solve = { path = "../solve" }
|
||||||
|
roc_mono = { path = "../mono" }
|
||||||
|
# im = "14" # im and im-rc should always have the same version!
|
||||||
|
# im-rc = "14" # im and im-rc should always have the same version!
|
||||||
|
bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||||
|
# target-lexicon = "0.12.2"
|
||||||
|
# libloading = "0.6"
|
||||||
|
parity-wasm = "0.42"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
wasmer = "2.0.0"
|
||||||
|
|
|
@ -1,7 +1,103 @@
|
||||||
#[cfg(test)]
|
use bumpalo::{collections::Vec, Bump};
|
||||||
mod tests {
|
use parity_wasm::{elements, builder};
|
||||||
#[test]
|
use parity_wasm::elements::{ValueType, Internal};
|
||||||
fn it_works() {
|
use parity_wasm::builder::{ModuleBuilder, FunctionDefinition, FunctionBuilder, CodeLocation};
|
||||||
assert_eq!(2 + 2, 4);
|
|
||||||
|
// use roc_builtins::bitcode;
|
||||||
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
// use roc_module::ident::{ModuleName, TagName};
|
||||||
|
// use roc_module::low_level::LowLevel;
|
||||||
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
|
use roc_mono::ir::{BranchInfo, CallType, Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt};
|
||||||
|
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Env<'a> {
|
||||||
|
pub arena: &'a Bump,
|
||||||
|
pub interns: Interns,
|
||||||
|
pub exposed_to_host: MutSet<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SymbolStorage {
|
||||||
|
Local(ValueType, u32),
|
||||||
|
LocalAndBase(ValueType, u32, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LabelId(u32);
|
||||||
|
|
||||||
|
// Don't allocate any constant data at the address zero or anywhere near it.
|
||||||
|
// These addresses are not special in Wasm, but putting something there seems bug-prone.
|
||||||
|
// Emscripten leaves 1kB free so let's do the same for now, although 4 bytes would probably do.
|
||||||
|
const UNUSED_DATA_SECTION_BYTES: u32 = 1024;
|
||||||
|
|
||||||
|
pub struct BackendWasm<'a> {
|
||||||
|
// module-level state
|
||||||
|
env: &'a Env<'a>,
|
||||||
|
module_builder: ModuleBuilder,
|
||||||
|
data_offset_map: MutMap<Literal<'a>, u32>,
|
||||||
|
data_offset_next: u32,
|
||||||
|
|
||||||
|
// procedure-level state
|
||||||
|
symbol_storage_map: MutMap<Symbol, SymbolStorage>,
|
||||||
|
joinpoint_label_map: MutMap<JoinPointId, LabelId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_module<'a>(env: &'a Env, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>) -> Result<elements::Module, String> {
|
||||||
|
let mut backend = BackendWasm::new(env);
|
||||||
|
let mut layout_ids = LayoutIds::default();
|
||||||
|
|
||||||
|
for ((sym, layout), proc) in procedures {
|
||||||
|
let location = backend.build_proc(proc)?;
|
||||||
|
|
||||||
|
if env.exposed_to_host.contains(&sym) {
|
||||||
|
let fn_name = layout_ids
|
||||||
|
.get_toplevel(sym, &layout)
|
||||||
|
.to_symbol_string(sym, &env.interns);
|
||||||
|
|
||||||
|
let export = builder::export()
|
||||||
|
.field(fn_name.as_str())
|
||||||
|
.with_internal(Internal::Function(location.body))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
backend.module_builder.push_export(export);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(backend.module_builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>BackendWasm<'a> {
|
||||||
|
pub fn new(env: &'a Env) -> Self {
|
||||||
|
BackendWasm {
|
||||||
|
env,
|
||||||
|
module_builder: builder::module(),
|
||||||
|
data_offset_map: MutMap::default(),
|
||||||
|
data_offset_next: UNUSED_DATA_SECTION_BYTES,
|
||||||
|
symbol_storage_map: MutMap::default(),
|
||||||
|
joinpoint_label_map: MutMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_proc(&mut self, proc: Proc<'a>) -> Result<CodeLocation, String> {
|
||||||
|
let mut function_builder = builder::function();
|
||||||
|
//
|
||||||
|
// ... generate stuff ...
|
||||||
|
//
|
||||||
|
let def = function_builder.build();
|
||||||
|
let location = self.module_builder.push_function(def);
|
||||||
|
Ok(location)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> {
|
||||||
|
Err("todo: everything".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_expr(
|
||||||
|
&mut self,
|
||||||
|
sym: &Symbol,
|
||||||
|
expr: &Expr<'a>,
|
||||||
|
layout: &Layout<'a>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
Err("todo: everything".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue