Fix constant generation

This commit is contained in:
Rerumu 2022-05-19 17:09:44 -04:00
parent f9cf75c98a
commit 0e92163cb3
7 changed files with 115 additions and 112 deletions

View File

@ -8,8 +8,7 @@ use wasm_ast::node::{
use crate::analyzer::operator::bin_symbol_of; use crate::analyzer::operator::bin_symbol_of;
use super::manager::{ use super::manager::{
write_cmp_op, write_condition, write_f32, write_f64, write_separated, write_variable, Driver, write_cmp_op, write_condition, write_separated, write_variable, Driver, Manager,
Manager,
}; };
impl Driver for Recall { impl Driver for Recall {
@ -69,6 +68,30 @@ impl Driver for MemoryGrow {
} }
} }
pub fn write_f32(number: f32, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
pub fn write_f64(number: f64, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
impl Driver for Value { impl Driver for Value {
fn write(&self, _: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, _: &mut Manager, w: &mut dyn Write) -> Result<()> {
match self { match self {

View File

@ -55,30 +55,6 @@ pub fn write_ascending(prefix: &str, range: Range<usize>, w: &mut dyn Write) ->
write_separated(range, |i, w| write!(w, "{prefix}_{i}"), w) write_separated(range, |i, w| write!(w, "{prefix}_{i}"), w)
} }
pub fn write_f32(number: f32, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
pub fn write_f64(number: f64, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
pub fn write_variable(var: usize, mng: &Manager, w: &mut dyn Write) -> Result<()> { pub fn write_variable(var: usize, mng: &Manager, w: &mut dyn Write) -> Result<()> {
if let Some(rem) = var.checked_sub(mng.num_param) { if let Some(rem) = var.checked_sub(mng.num_param) {
write!(w, "loc_{rem} ") write!(w, "loc_{rem} ")

View File

@ -14,7 +14,7 @@ use wasm_ast::{
use crate::{ use crate::{
analyzer::{localize, memory}, analyzer::{localize, memory},
backend::manager::{write_f32, write_f64, Driver, Manager}, backend::manager::{Driver, Manager},
}; };
fn aux_internal_index(internal: Internal) -> u32 { fn aux_internal_index(internal: Internal) -> u32 {
@ -48,24 +48,12 @@ fn write_named_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
write!(w, "local {name} = table_new({len}, {hash})") write!(w, "local {name} = table_new({len}, {hash})")
} }
fn write_constant(code: &[Instruction], w: &mut dyn Write) -> Result<()> { fn write_constant(code: &[Instruction], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
// FIXME: Badly generated WASM will produce the wrong constant. let func = Builder::new(type_info).with_anon(code);
for inst in code {
let result = match *inst {
Instruction::I32Const(v) => write!(w, "{v} "),
Instruction::I64Const(v) => write!(w, "{v}LL "),
Instruction::F32Const(v) => write_f32(f32::from_bits(v), w),
Instruction::F64Const(v) => write_f64(f64::from_bits(v), w),
Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{i}].value "),
_ => {
continue;
}
};
return result; write!(w, "(")?;
} func.write(&mut Manager::default(), w)?;
write!(w, ")()")
write!(w, "error(\"mundane expression\")")
} }
fn write_import_of<T>(wasm: &Module, lower: &str, cond: T, w: &mut dyn Write) -> Result<()> fn write_import_of<T>(wasm: &Module, lower: &str, cond: T, w: &mut dyn Write) -> Result<()>
@ -154,7 +142,7 @@ fn write_memory_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
Ok(()) Ok(())
} }
fn write_global_list(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_global_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
let global = match wasm.global_section() { let global = match wasm.global_section() {
Some(v) => v, Some(v) => v,
None => return Ok(()), None => return Ok(()),
@ -163,25 +151,27 @@ fn write_global_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
for (i, v) in global.entries().iter().enumerate() { for (i, v) in global.entries().iter().enumerate() {
write!(w, "GLOBAL_LIST[{}] = {{ value =", i + offset)?; write!(w, "GLOBAL_LIST[{}] = {{ value =", i + offset)?;
write_constant(v.init_expr().code(), w)?; write_constant(v.init_expr().code(), type_info, w)?;
write!(w, "}}")?; write!(w, "}}")?;
} }
Ok(()) Ok(())
} }
fn write_element_list(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_element_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
let element = match wasm.elements_section() { let element = match wasm.elements_section() {
Some(v) => v.entries(), Some(v) => v.entries(),
None => return Ok(()), None => return Ok(()),
}; };
for v in element { for v in element {
let code = v.offset().as_ref().unwrap().code();
write!(w, "do ")?; write!(w, "do ")?;
write!(w, "local target = TABLE_LIST[{}].data ", v.index())?; write!(w, "local target = TABLE_LIST[{}].data ", v.index())?;
write!(w, "local offset =")?; write!(w, "local offset =")?;
write_constant(v.offset().as_ref().unwrap().code(), w)?; write_constant(code, type_info, w)?;
write!(w, "local data = {{")?; write!(w, "local data = {{")?;
@ -199,18 +189,20 @@ fn write_element_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
Ok(()) Ok(())
} }
fn write_data_list(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_data_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
let data = match wasm.data_section() { let data = match wasm.data_section() {
Some(v) => v.entries(), Some(v) => v.entries(),
None => return Ok(()), None => return Ok(()),
}; };
for v in data { for v in data {
let code = v.offset().as_ref().unwrap().code();
write!(w, "do ")?; write!(w, "do ")?;
write!(w, "local target = MEMORY_LIST[{}]", v.index())?; write!(w, "local target = MEMORY_LIST[{}]", v.index())?;
write!(w, "local offset =")?; write!(w, "local offset =")?;
write_constant(v.offset().as_ref().unwrap().code(), w)?; write_constant(code, type_info, w)?;
write!(w, "local data = \"")?; write!(w, "local data = \"")?;
@ -234,7 +226,7 @@ fn build_func_list(wasm: &Module, type_info: &TypeInfo) -> Vec<Intermediate> {
let iter = list.iter().enumerate(); let iter = list.iter().enumerate();
iter.map(|f| Builder::new(type_info).consume(f.0, f.1)) iter.map(|f| Builder::new(type_info).with_index(f.0, f.1))
.collect() .collect()
} }
@ -287,13 +279,18 @@ fn write_func_list(
}) })
} }
fn write_module_start(wasm: &Module, mem_list: &[usize], w: &mut dyn Write) -> Result<()> { fn write_module_start(
wasm: &Module,
type_info: &TypeInfo,
mem_list: &[usize],
w: &mut dyn Write,
) -> Result<()> {
write!(w, "local function run_init_code()")?; write!(w, "local function run_init_code()")?;
write_table_list(wasm, w)?; write_table_list(wasm, w)?;
write_memory_list(wasm, w)?; write_memory_list(wasm, w)?;
write_global_list(wasm, w)?; write_global_list(wasm, type_info, w)?;
write_element_list(wasm, w)?; write_element_list(wasm, type_info, w)?;
write_data_list(wasm, w)?; write_data_list(wasm, type_info, w)?;
write!(w, "end ")?; write!(w, "end ")?;
write!(w, "return function(wasm)")?; write!(w, "return function(wasm)")?;
@ -329,5 +326,5 @@ pub fn translate(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Resu
write_named_array("GLOBAL_LIST", wasm.globals_space(), w)?; write_named_array("GLOBAL_LIST", wasm.globals_space(), w)?;
write_func_list(wasm, type_info, &func_list, w)?; write_func_list(wasm, type_info, &func_list, w)?;
write_module_start(wasm, &mem_list, w) write_module_start(wasm, type_info, &mem_list, w)
} }

View File

@ -7,7 +7,7 @@ use wasm_ast::node::{
use crate::analyzer::operator::bin_symbol_of; use crate::analyzer::operator::bin_symbol_of;
use super::manager::{write_f32, write_f64, write_separated, write_variable, Driver, Manager}; use super::manager::{write_separated, write_variable, Driver, Manager};
impl Driver for Recall { impl Driver for Recall {
fn write(&self, _: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, _: &mut Manager, w: &mut dyn Write) -> Result<()> {
@ -66,6 +66,30 @@ impl Driver for MemoryGrow {
} }
} }
pub fn write_f32(number: f32, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
pub fn write_f64(number: f64, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
impl Driver for Value { impl Driver for Value {
fn write(&self, _: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, _: &mut Manager, w: &mut dyn Write) -> Result<()> {
match self { match self {

View File

@ -56,30 +56,6 @@ pub fn write_ascending(prefix: &str, range: Range<usize>, w: &mut dyn Write) ->
write_separated(range, |i, w| write!(w, "{prefix}_{i}"), w) write_separated(range, |i, w| write!(w, "{prefix}_{i}"), w)
} }
pub fn write_f32(number: f32, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
pub fn write_f64(number: f64, w: &mut dyn Write) -> Result<()> {
let sign = if number.is_sign_negative() { "-" } else { "" };
if number.is_infinite() {
write!(w, "{sign}math.huge ")
} else if number.is_nan() {
write!(w, "{sign}0/0 ")
} else {
write!(w, "{number:e} ")
}
}
pub fn write_variable(var: usize, mng: &Manager, w: &mut dyn Write) -> Result<()> { pub fn write_variable(var: usize, mng: &Manager, w: &mut dyn Write) -> Result<()> {
if let Some(rem) = var.checked_sub(mng.num_param) { if let Some(rem) = var.checked_sub(mng.num_param) {
write!(w, "loc_{rem} ") write!(w, "loc_{rem} ")

View File

@ -14,7 +14,7 @@ use wasm_ast::{
use crate::{ use crate::{
analyzer::localize, analyzer::localize,
backend::manager::{write_f32, write_f64, Driver, Manager}, backend::manager::{Driver, Manager},
}; };
fn aux_internal_index(internal: Internal) -> u32 { fn aux_internal_index(internal: Internal) -> u32 {
@ -47,24 +47,12 @@ fn write_named_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
write!(w, "local {name} = table.create({len})") write!(w, "local {name} = table.create({len})")
} }
fn write_constant(code: &[Instruction], w: &mut dyn Write) -> Result<()> { fn write_constant(code: &[Instruction], type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
// FIXME: Badly generated WASM will produce the wrong constant. let func = Builder::new(type_info).with_anon(code);
for inst in code {
let result = match *inst {
Instruction::I32Const(v) => write!(w, "{v} "),
Instruction::I64Const(v) => write!(w, "{v} "),
Instruction::F32Const(v) => write_f32(f32::from_bits(v), w),
Instruction::F64Const(v) => write_f64(f64::from_bits(v), w),
Instruction::GetGlobal(i) => write!(w, "GLOBAL_LIST[{i}].value "),
_ => {
continue;
}
};
return result; write!(w, "(")?;
} func.write(&mut Manager::default(), w)?;
write!(w, ")()")
write!(w, "error(\"mundane expression\")")
} }
fn write_import_of<T>(wasm: &Module, lower: &str, cond: T, w: &mut dyn Write) -> Result<()> fn write_import_of<T>(wasm: &Module, lower: &str, cond: T, w: &mut dyn Write) -> Result<()>
@ -153,7 +141,7 @@ fn write_memory_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
Ok(()) Ok(())
} }
fn write_global_list(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_global_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
let global = match wasm.global_section() { let global = match wasm.global_section() {
Some(v) => v, Some(v) => v,
None => return Ok(()), None => return Ok(()),
@ -162,25 +150,27 @@ fn write_global_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
for (i, v) in global.entries().iter().enumerate() { for (i, v) in global.entries().iter().enumerate() {
write!(w, "GLOBAL_LIST[{}] = {{ value =", i + offset)?; write!(w, "GLOBAL_LIST[{}] = {{ value =", i + offset)?;
write_constant(v.init_expr().code(), w)?; write_constant(v.init_expr().code(), type_info, w)?;
write!(w, "}}")?; write!(w, "}}")?;
} }
Ok(()) Ok(())
} }
fn write_element_list(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_element_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
let element = match wasm.elements_section() { let element = match wasm.elements_section() {
Some(v) => v.entries(), Some(v) => v.entries(),
None => return Ok(()), None => return Ok(()),
}; };
for v in element { for v in element {
let code = v.offset().as_ref().unwrap().code();
write!(w, "do ")?; write!(w, "do ")?;
write!(w, "local target = TABLE_LIST[{}].data ", v.index())?; write!(w, "local target = TABLE_LIST[{}].data ", v.index())?;
write!(w, "local offset =")?; write!(w, "local offset =")?;
write_constant(v.offset().as_ref().unwrap().code(), w)?; write_constant(code, type_info, w)?;
write!(w, "local data = {{")?; write!(w, "local data = {{")?;
@ -198,18 +188,20 @@ fn write_element_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
Ok(()) Ok(())
} }
fn write_data_list(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_data_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
let data = match wasm.data_section() { let data = match wasm.data_section() {
Some(v) => v.entries(), Some(v) => v.entries(),
None => return Ok(()), None => return Ok(()),
}; };
for v in data { for v in data {
let code = v.offset().as_ref().unwrap().code();
write!(w, "do ")?; write!(w, "do ")?;
write!(w, "local target = MEMORY_LIST[{}]", v.index())?; write!(w, "local target = MEMORY_LIST[{}]", v.index())?;
write!(w, "local offset =")?; write!(w, "local offset =")?;
write_constant(v.offset().as_ref().unwrap().code(), w)?; write_constant(code, type_info, w)?;
write!(w, "local data = \"")?; write!(w, "local data = \"")?;
@ -233,7 +225,7 @@ fn build_func_list(wasm: &Module, type_info: &TypeInfo) -> Vec<Intermediate> {
let iter = list.iter().enumerate(); let iter = list.iter().enumerate();
iter.map(|f| Builder::new(type_info).consume(f.0, f.1)) iter.map(|f| Builder::new(type_info).with_index(f.0, f.1))
.collect() .collect()
} }
@ -279,13 +271,13 @@ fn write_func_list(
}) })
} }
fn write_module_start(wasm: &Module, w: &mut dyn Write) -> Result<()> { fn write_module_start(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
write!(w, "local function run_init_code()")?; write!(w, "local function run_init_code()")?;
write_table_list(wasm, w)?; write_table_list(wasm, w)?;
write_memory_list(wasm, w)?; write_memory_list(wasm, w)?;
write_global_list(wasm, w)?; write_global_list(wasm, type_info, w)?;
write_element_list(wasm, w)?; write_element_list(wasm, type_info, w)?;
write_data_list(wasm, w)?; write_data_list(wasm, type_info, w)?;
write!(w, "end ")?; write!(w, "end ")?;
write!(w, "return function(wasm)")?; write!(w, "return function(wasm)")?;
@ -314,5 +306,5 @@ pub fn translate(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) -> Resu
write_named_array("GLOBAL_LIST", wasm.globals_space(), w)?; write_named_array("GLOBAL_LIST", wasm.globals_space(), w)?;
write_func_list(wasm, type_info, &func_list, w)?; write_func_list(wasm, type_info, &func_list, w)?;
write_module_start(wasm, w) write_module_start(wasm, type_info, w)
} }

View File

@ -289,7 +289,22 @@ impl<'a> Builder<'a> {
} }
#[must_use] #[must_use]
pub fn consume(mut self, index: usize, func: &'a FuncBody) -> Intermediate { pub fn with_anon(mut self, mut inst: &[Instruction]) -> Intermediate {
self.num_result = 1;
let code = self.new_forward(&mut inst);
let num_stack = self.data.last_stack;
Intermediate {
local_data: Vec::new(),
num_param: 0,
num_stack,
code,
}
}
#[must_use]
pub fn with_index(mut self, index: usize, func: &'a FuncBody) -> Intermediate {
let arity = &self.type_info.arity_of(self.type_info.len_ex() + index); let arity = &self.type_info.arity_of(self.type_info.len_ex() + index);
self.num_result = arity.num_result; self.num_result = arity.num_result;