WIP.
This commit is contained in:
parent
15d45e1443
commit
9e5d2fae26
|
@ -43,6 +43,14 @@ impl Module {
|
|||
Ok(slice.to_vec())
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Module> {
|
||||
let ptr = unsafe { BinaryenModuleCreate() };
|
||||
if ptr.is_null() {
|
||||
bail!("Failed to allocate module");
|
||||
}
|
||||
Ok(Module(ptr))
|
||||
}
|
||||
|
||||
pub fn num_funcs(&self) -> usize {
|
||||
unsafe { BinaryenGetNumFunctions(self.0) as usize }
|
||||
}
|
||||
|
@ -88,6 +96,178 @@ impl Module {
|
|||
pub fn module(&self) -> BinaryenModule {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn add_global(&self, ty: ir::Type, mutable: bool, value: Option<u64>) -> ir::Global {
|
||||
let b_ty = Type::from(ty).to_binaryen();
|
||||
let value = value.unwrap_or(0);
|
||||
let init = match ty {
|
||||
ir::Type::I32 => Expression::const_i32(self, value as i32),
|
||||
ir::Type::I64 => Expression::const_i64(self, value as i64),
|
||||
ir::Type::F32 => Expression::const_f32(self, Ieee32::from_bits(value as u32)),
|
||||
ir::Type::F64 => Expression::const_f64(self, Ieee64::from_bits(value)),
|
||||
_ => panic!("Unsupported type"),
|
||||
};
|
||||
|
||||
let num = unsafe { BinaryenGetNumGlobals(self.0) };
|
||||
let global = unsafe { BinaryenAddGlobal(self.0, std::ptr::null(), b_ty, mutable, init.1) };
|
||||
assert!(!global.is_null());
|
||||
ir::Global::from(num)
|
||||
}
|
||||
|
||||
pub fn add_table(&self, ty: ir::Type, init: usize, max: Option<u32>) -> ir::Table {
|
||||
let ty = Type::from(ty).to_binaryen();
|
||||
let num = unsafe { BinaryenGetNumTables(self.0) };
|
||||
let max = max.unwrap_or(0);
|
||||
let table = unsafe {
|
||||
BinaryenAddTable(
|
||||
self.0,
|
||||
std::ptr::null(),
|
||||
init as BinaryenIndex,
|
||||
max as BinaryenIndex,
|
||||
ty,
|
||||
)
|
||||
};
|
||||
assert!(!table.is_null());
|
||||
ir::Table::from(num)
|
||||
}
|
||||
|
||||
pub fn add_table_elem(&self, table: ir::Table, index: usize, elt: ir::Func) {
|
||||
let table_name = unsafe {
|
||||
BinaryenTableGetName(BinaryenGetTableByIndex(
|
||||
self.0,
|
||||
table.index() as BinaryenIndex,
|
||||
))
|
||||
};
|
||||
let func_name = unsafe {
|
||||
BinaryenFunctionGetName(BinaryenGetFunctionByIndex(
|
||||
self.0,
|
||||
elt.index() as BinaryenIndex,
|
||||
))
|
||||
};
|
||||
let offset = Expression::const_i32(self, index as i32);
|
||||
let seg = unsafe {
|
||||
BinaryenAddActiveElementSegment(
|
||||
self.0,
|
||||
table_name,
|
||||
std::ptr::null(),
|
||||
&func_name as *const *const c_char,
|
||||
1,
|
||||
offset.1,
|
||||
)
|
||||
};
|
||||
assert!(!seg.is_null());
|
||||
}
|
||||
|
||||
pub fn add_mem(
|
||||
&self,
|
||||
init_pages: usize,
|
||||
max_pages: Option<usize>,
|
||||
segments: &[ir::MemorySegment],
|
||||
) -> ir::Memory {
|
||||
let seg_passive = vec![false; segments.len()];
|
||||
let seg_offset = segments
|
||||
.iter()
|
||||
.map(|seg| Expression::const_i32(self, seg.offset as i32).1)
|
||||
.collect::<Vec<_>>();
|
||||
let seg_data = segments
|
||||
.iter()
|
||||
.map(|seg| seg.data.as_ptr() as *const c_char)
|
||||
.collect::<Vec<_>>();
|
||||
let seg_size = segments
|
||||
.iter()
|
||||
.map(|seg| seg.data.len() as BinaryenIndex)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Binaryen does not support multi-memory.
|
||||
unsafe {
|
||||
BinaryenSetMemory(
|
||||
self.0,
|
||||
init_pages as BinaryenIndex,
|
||||
max_pages.unwrap_or(0) as BinaryenIndex,
|
||||
std::ptr::null(),
|
||||
seg_data.as_ptr(),
|
||||
seg_passive.as_ptr(),
|
||||
seg_offset.as_ptr(),
|
||||
seg_size.as_ptr(),
|
||||
segments.len() as BinaryenIndex,
|
||||
false,
|
||||
);
|
||||
}
|
||||
ir::Memory::from(0)
|
||||
}
|
||||
|
||||
pub fn add_table_import(&self, table: ir::Table, module: &str, name: &str) {
|
||||
let table_name = unsafe {
|
||||
BinaryenTableGetName(BinaryenGetTableByIndex(
|
||||
self.0,
|
||||
table.index() as BinaryenIndex,
|
||||
))
|
||||
};
|
||||
let c_module = std::ffi::CString::new(module).unwrap();
|
||||
let c_name = std::ffi::CString::new(name).unwrap();
|
||||
unsafe {
|
||||
BinaryenAddTableImport(self.0, table_name, c_module.as_ptr(), c_name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_func_import(
|
||||
&self,
|
||||
func: ir::Func,
|
||||
module: &str,
|
||||
name: &str,
|
||||
params: &[ir::Type],
|
||||
results: &[ir::Type],
|
||||
) {
|
||||
let func_name = unsafe {
|
||||
BinaryenFunctionGetName(BinaryenGetFunctionByIndex(
|
||||
self.0,
|
||||
func.index() as BinaryenIndex,
|
||||
))
|
||||
};
|
||||
let c_module = std::ffi::CString::new(module).unwrap();
|
||||
let c_name = std::ffi::CString::new(name).unwrap();
|
||||
let params = tys_to_binaryen(params.iter().copied());
|
||||
let results = tys_to_binaryen(results.iter().copied());
|
||||
unsafe {
|
||||
BinaryenAddFunctionImport(
|
||||
self.0,
|
||||
func_name,
|
||||
c_module.as_ptr(),
|
||||
c_name.as_ptr(),
|
||||
params,
|
||||
results,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_global_import(
|
||||
&self,
|
||||
global: ir::Global,
|
||||
module: &str,
|
||||
name: &str,
|
||||
ty: ir::Type,
|
||||
mutable: bool,
|
||||
) {
|
||||
let global_name = unsafe {
|
||||
BinaryenGlobalGetName(BinaryenGetGlobalByIndex(
|
||||
self.0,
|
||||
global.index() as BinaryenIndex,
|
||||
))
|
||||
};
|
||||
let c_module = std::ffi::CString::new(module).unwrap();
|
||||
let c_name = std::ffi::CString::new(name).unwrap();
|
||||
let ty = Type::from(ty).to_binaryen();
|
||||
unsafe {
|
||||
BinaryenAddGlobalImport(
|
||||
self.0,
|
||||
global_name,
|
||||
c_module.as_ptr(),
|
||||
c_name.as_ptr(),
|
||||
ty,
|
||||
mutable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Module {
|
||||
|
@ -708,6 +888,8 @@ type BinaryenExport = *const c_void;
|
|||
type BinaryenRelooper = *const c_void;
|
||||
type BinaryenRelooperBlock = *const c_void;
|
||||
type BinaryenTable = *const c_void;
|
||||
type BinaryenGlobal = *const c_void;
|
||||
type BinaryenElementSegment = *const c_void;
|
||||
|
||||
#[repr(C)]
|
||||
struct BinaryenModuleAllocateAndWriteResult {
|
||||
|
@ -787,6 +969,7 @@ impl Drop for Relooper {
|
|||
#[link(name = "binaryen")]
|
||||
extern "C" {
|
||||
fn BinaryenModuleRead(data: *const u8, len: usize) -> BinaryenModule;
|
||||
fn BinaryenModuleCreate() -> BinaryenModule;
|
||||
fn BinaryenModuleDispose(ptr: BinaryenModule);
|
||||
fn BinaryenModuleAllocateAndWrite(
|
||||
ptr: BinaryenModule,
|
||||
|
@ -1373,6 +1556,77 @@ extern "C" {
|
|||
fn BinaryenRefAsData() -> BinaryenOp;
|
||||
fn BinaryenRefAsI31() -> BinaryenOp;
|
||||
|
||||
fn BinaryenAddGlobal(
|
||||
module: BinaryenModule,
|
||||
name: *const c_char,
|
||||
ty: BinaryenType,
|
||||
mutable: bool,
|
||||
init: BinaryenExpression,
|
||||
) -> BinaryenGlobal;
|
||||
fn BinaryenGetNumGlobals(module: BinaryenModule) -> BinaryenIndex;
|
||||
|
||||
fn BinaryenAddTable(
|
||||
module: BinaryenModule,
|
||||
name: *const c_char,
|
||||
initial: BinaryenIndex,
|
||||
max: BinaryenIndex,
|
||||
ty: BinaryenType,
|
||||
) -> BinaryenTable;
|
||||
fn BinaryenGetNumTables(module: BinaryenModule) -> BinaryenIndex;
|
||||
|
||||
fn BinaryenAddActiveElementSegment(
|
||||
module: BinaryenModule,
|
||||
table: *const c_char,
|
||||
name: *const c_char,
|
||||
func_names: *const *const c_char,
|
||||
num_funcs: BinaryenIndex,
|
||||
offset: BinaryenExpression,
|
||||
) -> BinaryenElementSegment;
|
||||
|
||||
fn BinaryenSetMemory(
|
||||
module: BinaryenModule,
|
||||
init: BinaryenIndex,
|
||||
max: BinaryenIndex,
|
||||
export_name: *const c_char,
|
||||
segments: *const *const c_char,
|
||||
seg_passive: *const bool,
|
||||
seg_offsets: *const BinaryenExpression,
|
||||
sizes: *const BinaryenIndex,
|
||||
n_segments: BinaryenIndex,
|
||||
shared: bool,
|
||||
);
|
||||
|
||||
fn BinaryenAddTableImport(
|
||||
module: BinaryenModule,
|
||||
name: *const c_char,
|
||||
extern_module: *const c_char,
|
||||
extern_name: *const c_char,
|
||||
);
|
||||
fn BinaryenAddMemoryImport(
|
||||
module: BinaryenModule,
|
||||
name: *const c_char,
|
||||
extern_module: *const c_char,
|
||||
extern_name: *const c_char,
|
||||
);
|
||||
fn BinaryenAddGlobalImport(
|
||||
module: BinaryenModule,
|
||||
name: *const c_char,
|
||||
extern_module: *const c_char,
|
||||
extern_name: *const c_char,
|
||||
ty: BinaryenType,
|
||||
mutable: bool,
|
||||
);
|
||||
fn BinaryenAddFunctionImport(
|
||||
module: BinaryenModule,
|
||||
name: *const c_char,
|
||||
extern_module: *const c_char,
|
||||
extern_name: *const c_char,
|
||||
params: BinaryenType,
|
||||
results: BinaryenType,
|
||||
);
|
||||
|
||||
fn BinaryenGlobalGetName(global: BinaryenGlobal) -> *const c_char;
|
||||
fn BinaryenGetGlobalByIndex(module: BinaryenModule, index: BinaryenIndex) -> BinaryenGlobal;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
|
@ -1,10 +1,84 @@
|
|||
use crate::backend::binaryen;
|
||||
use crate::entity::EntityRef;
|
||||
use crate::ir::ImportKind;
|
||||
use crate::ir::*;
|
||||
use crate::Operator;
|
||||
use anyhow::Result;
|
||||
use fxhash::FxHashMap;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub(crate) fn lower(module: &Module) -> Result<binaryen::Module> {
|
||||
let into_mod = binaryen::Module::new()?;
|
||||
|
||||
// Create globals.
|
||||
for (global, data) in module.globals() {
|
||||
let new_global = into_mod.add_global(data.ty, data.mutable, data.value);
|
||||
assert_eq!(new_global, global);
|
||||
}
|
||||
|
||||
// Create tables.
|
||||
for (table, data) in module.tables() {
|
||||
let new_table = into_mod.add_table(
|
||||
data.ty,
|
||||
data.func_elements
|
||||
.as_ref()
|
||||
.map(|elems| elems.len())
|
||||
.unwrap_or(0),
|
||||
data.max,
|
||||
);
|
||||
assert_eq!(new_table, table);
|
||||
if let Some(elts) = data.func_elements.as_ref() {
|
||||
for (i, &elt) in elts.iter().enumerate() {
|
||||
if elt.is_valid() {
|
||||
into_mod.add_table_elem(new_table, i, elt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create memories.
|
||||
for (mem, data) in module.memories() {
|
||||
let new_mem = into_mod.add_mem(data.initial_pages, data.maximum_pages, &data.segments[..]);
|
||||
assert_eq!(new_mem, mem);
|
||||
}
|
||||
|
||||
// Create function bodies.
|
||||
|
||||
// Create imports.
|
||||
for import in module.imports() {
|
||||
match &import.kind {
|
||||
&ImportKind::Table(table) => {
|
||||
into_mod.add_table_import(table, &import.module[..], &import.name[..]);
|
||||
}
|
||||
&ImportKind::Func(func) => {
|
||||
let sig = module.func(func).sig();
|
||||
let sigdata = module.signature(sig);
|
||||
into_mod.add_func_import(
|
||||
func,
|
||||
&import.module[..],
|
||||
&import.name[..],
|
||||
&sigdata.params[..],
|
||||
&sigdata.returns[..],
|
||||
);
|
||||
}
|
||||
&ImportKind::Global(global) => {
|
||||
let globdata = module.global(global);
|
||||
into_mod.add_global_import(
|
||||
global,
|
||||
&import.module[..],
|
||||
&import.name[..],
|
||||
globdata.ty,
|
||||
globdata.mutable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create exports.
|
||||
|
||||
Ok(into_mod)
|
||||
}
|
||||
|
||||
/// Creates a body expression for a function. Returns that expression,
|
||||
/// and new locals (as their types) that were created as temporaries
|
||||
/// and need to be appended to `body.locals`.
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
pub mod binaryen;
|
||||
pub mod lower;
|
||||
|
||||
|
|
|
@ -78,12 +78,17 @@ fn handle_payload<'a>(
|
|||
Some(ImportKind::Func(func))
|
||||
}
|
||||
ImportSectionEntryType::Global(ty) => {
|
||||
let mutable = ty.mutable;
|
||||
let ty = ty.content_type.into();
|
||||
let global = module.frontend_add_global(GlobalData { ty, value: None });
|
||||
let global = module.frontend_add_global(GlobalData {
|
||||
ty,
|
||||
value: None,
|
||||
mutable,
|
||||
});
|
||||
Some(ImportKind::Global(global))
|
||||
}
|
||||
ImportSectionEntryType::Table(ty) => {
|
||||
let table = module.frontend_add_table(ty.element_type.into());
|
||||
let table = module.frontend_add_table(ty.element_type.into(), None);
|
||||
Some(ImportKind::Table(table))
|
||||
}
|
||||
_ => None,
|
||||
|
@ -100,18 +105,20 @@ fn handle_payload<'a>(
|
|||
Payload::GlobalSection(reader) => {
|
||||
for global in reader {
|
||||
let global = global?;
|
||||
let mutable = global.ty.mutable;
|
||||
let ty = global.ty.content_type.into();
|
||||
let init_expr = parse_init_expr(&global.init_expr)?;
|
||||
module.frontend_add_global(GlobalData {
|
||||
ty,
|
||||
value: init_expr,
|
||||
mutable,
|
||||
});
|
||||
}
|
||||
}
|
||||
Payload::TableSection(reader) => {
|
||||
for table in reader {
|
||||
let table = table?;
|
||||
module.frontend_add_table(table.element_type.into());
|
||||
module.frontend_add_table(table.element_type.into(), table.maximum);
|
||||
}
|
||||
}
|
||||
Payload::FunctionSection(reader) => {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use super::{Func, FuncDecl, Global, Memory, ModuleDisplay, Signature, Table, Type};
|
||||
use crate::entity::EntityVec;
|
||||
use crate::frontend;
|
||||
use crate::ir::FunctionBody;
|
||||
use crate::{backend, frontend};
|
||||
use anyhow::Result;
|
||||
use fxhash::FxHashSet;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Module<'a> {
|
||||
|
@ -15,8 +14,6 @@ pub struct Module<'a> {
|
|||
imports: Vec<Import>,
|
||||
exports: Vec<Export>,
|
||||
memories: EntityVec<Memory, MemoryData>,
|
||||
|
||||
dirty_funcs: FxHashSet<Func>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
@ -41,6 +38,7 @@ pub struct MemorySegment {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct TableData {
|
||||
pub ty: Type,
|
||||
pub max: Option<u32>,
|
||||
pub func_elements: Option<Vec<Func>>,
|
||||
}
|
||||
|
||||
|
@ -48,6 +46,7 @@ pub struct TableData {
|
|||
pub struct GlobalData {
|
||||
pub ty: Type,
|
||||
pub value: Option<u64>,
|
||||
pub mutable: bool,
|
||||
}
|
||||
|
||||
impl From<&wasmparser::FuncType> for SignatureData {
|
||||
|
@ -134,7 +133,6 @@ impl<'a> Module<'a> {
|
|||
imports: vec![],
|
||||
exports: vec![],
|
||||
memories: EntityVec::default(),
|
||||
dirty_funcs: FxHashSet::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +142,6 @@ impl<'a> Module<'a> {
|
|||
&self.funcs[id]
|
||||
}
|
||||
pub fn func_mut<'b>(&'b mut self, id: Func) -> &'b mut FuncDecl {
|
||||
self.dirty_funcs.insert(id);
|
||||
&mut self.funcs[id]
|
||||
}
|
||||
pub fn funcs<'b>(&'b self) -> impl Iterator<Item = (Func, &'b FuncDecl)> {
|
||||
|
@ -190,13 +187,17 @@ impl<'a> Module<'a> {
|
|||
pub(crate) fn frontend_add_func(&mut self, body: FuncDecl) -> Func {
|
||||
self.funcs.push(body)
|
||||
}
|
||||
pub(crate) fn frontend_add_table(&mut self, ty: Type) -> Table {
|
||||
pub(crate) fn frontend_add_table(&mut self, ty: Type, max: Option<u32>) -> Table {
|
||||
let func_elements = if ty == Type::FuncRef {
|
||||
Some(vec![])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.tables.push(TableData { ty, func_elements })
|
||||
self.tables.push(TableData {
|
||||
ty,
|
||||
func_elements,
|
||||
max,
|
||||
})
|
||||
}
|
||||
pub(crate) fn frontend_add_global(&mut self, global: GlobalData) -> Global {
|
||||
self.globals.push(global)
|
||||
|
@ -225,7 +226,8 @@ impl<'a> Module<'a> {
|
|||
}
|
||||
|
||||
pub fn to_wasm_bytes(&self) -> Result<Vec<u8>> {
|
||||
todo!()
|
||||
let module = backend::lower::lower(self)?;
|
||||
module.write()
|
||||
}
|
||||
|
||||
pub fn display<'b>(&'b self) -> ModuleDisplay<'b>
|
||||
|
|
Loading…
Reference in a new issue