Fix #8, as BrTable
s have better codegen
This commit is contained in:
parent
8169080779
commit
b282bdf490
29
codegen-luajit/src/analyzer/br_table.rs
Normal file
29
codegen-luajit/src/analyzer/br_table.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use wasm_ast::{
|
||||||
|
node::{BrTable, FuncData},
|
||||||
|
visit::{Driver, Visitor},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Visit {
|
||||||
|
id_map: HashMap<usize, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visitor for Visit {
|
||||||
|
fn visit_br_table(&mut self, table: &BrTable) {
|
||||||
|
let id = table as *const _ as usize;
|
||||||
|
let len = self.id_map.len() + 1;
|
||||||
|
|
||||||
|
self.id_map.insert(id, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit(ast: &FuncData) -> HashMap<usize, usize> {
|
||||||
|
let mut visit = Visit {
|
||||||
|
id_map: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
ast.accept(&mut visit);
|
||||||
|
|
||||||
|
visit.id_map
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
|
pub mod br_table;
|
||||||
pub mod localize;
|
pub mod localize;
|
||||||
pub mod operator;
|
pub mod operator;
|
||||||
|
@ -1,20 +1,36 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
io::{Result, Write},
|
io::{Result, Write},
|
||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
use wasm_ast::node::{CmpOp, Expression};
|
use wasm_ast::node::{BrTable, CmpOp, Expression};
|
||||||
|
|
||||||
use crate::analyzer::operator::cmp_symbol_of;
|
use crate::analyzer::operator::cmp_symbol_of;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
|
table_map: HashMap<usize, usize>,
|
||||||
label_list: Vec<usize>,
|
label_list: Vec<usize>,
|
||||||
num_label: usize,
|
num_label: usize,
|
||||||
pub num_param: usize,
|
num_param: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
pub fn get_table_index(&self, table: &BrTable) -> usize {
|
||||||
|
let id = table as *const _ as usize;
|
||||||
|
|
||||||
|
self.table_map[&id]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_table_map(&mut self, map: HashMap<usize, usize>) {
|
||||||
|
self.table_map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_num_param(&mut self, num: usize) {
|
||||||
|
self.num_param = num;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn label_list(&self) -> &[usize] {
|
pub fn label_list(&self) -> &[usize] {
|
||||||
&self.label_list
|
&self.label_list
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ use wasm_ast::node::{
|
|||||||
SetLocal, SetTemporary, Statement, StoreAt, Terminator,
|
SetLocal, SetTemporary, Statement, StoreAt, Terminator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::analyzer::br_table;
|
||||||
|
|
||||||
use super::manager::{
|
use super::manager::{
|
||||||
write_ascending, write_condition, write_separated, write_variable, Driver, Manager,
|
write_ascending, write_condition, write_separated, write_variable, Driver, Manager,
|
||||||
};
|
};
|
||||||
@ -28,26 +30,80 @@ impl Driver for Br {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_ordered_table<'a>(list: &'a [Br], default: &'a Br) -> Vec<&'a Br> {
|
||||||
|
let mut data: Vec<_> = list.iter().chain(std::iter::once(default)).collect();
|
||||||
|
|
||||||
|
data.sort_by_key(|v| v.target);
|
||||||
|
data.dedup_by_key(|v| v.target);
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_search_layer(
|
||||||
|
range: Range<usize>,
|
||||||
|
list: &[&Br],
|
||||||
|
mng: &mut Manager,
|
||||||
|
w: &mut dyn Write,
|
||||||
|
) -> Result<()> {
|
||||||
|
if range.len() == 1 {
|
||||||
|
return list[range.start].write(mng, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
let center = range.start + range.len() / 2;
|
||||||
|
let br = list[center];
|
||||||
|
|
||||||
|
if range.start != center {
|
||||||
|
write!(w, "if temp < {} then ", br.target)?;
|
||||||
|
write_search_layer(range.start..center, list, mng, w)?;
|
||||||
|
write!(w, "else")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if range.end != center + 1 {
|
||||||
|
write!(w, "if temp > {} then ", br.target)?;
|
||||||
|
write_search_layer(center + 1..range.end, list, mng, w)?;
|
||||||
|
write!(w, "else")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, " ")?;
|
||||||
|
br.write(mng, w)?;
|
||||||
|
write!(w, "end ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_table_setup(table: &BrTable, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let id = mng.get_table_index(table);
|
||||||
|
|
||||||
|
write!(w, "if not br_map[{id}] then ")?;
|
||||||
|
write!(w, "br_map[{id}] = (function() return {{[0] =")?;
|
||||||
|
|
||||||
|
table
|
||||||
|
.data
|
||||||
|
.iter()
|
||||||
|
.try_for_each(|v| write!(w, "{},", v.target))?;
|
||||||
|
|
||||||
|
write!(w, "}} end)()")?;
|
||||||
|
write!(w, "end ")?;
|
||||||
|
|
||||||
|
write!(w, "temp = br_map[{id}][")?;
|
||||||
|
table.cond.write(mng, w)?;
|
||||||
|
write!(w, "] or {} ", table.default.target)
|
||||||
|
}
|
||||||
|
|
||||||
impl Driver for BrTable {
|
impl Driver for BrTable {
|
||||||
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "temp = ")?;
|
|
||||||
self.cond.write(mng, w)?;
|
|
||||||
|
|
||||||
// Our condition should be pure so we probably don't need
|
|
||||||
// to emit it in this case.
|
|
||||||
if self.data.is_empty() {
|
if self.data.is_empty() {
|
||||||
|
// Our condition should be pure so we probably don't need
|
||||||
|
// to emit it in this case.
|
||||||
return self.default.write(mng, w);
|
return self.default.write(mng, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (case, dest) in self.data.iter().enumerate() {
|
// `BrTable` is optimized by first mapping all indices to targets through
|
||||||
write!(w, "if temp == {case} then ")?;
|
// a Lua table; this reduces the size of the code generated as duplicate entries
|
||||||
dest.write(mng, w)?;
|
// don't need checking. Then, for speed, a binary search is done for the target
|
||||||
write!(w, "else")?;
|
// and the appropriate jump is performed.
|
||||||
}
|
let list = to_ordered_table(&self.data, &self.default);
|
||||||
|
|
||||||
write!(w, " ")?;
|
write_table_setup(self, mng, w)?;
|
||||||
self.default.write(mng, w)?;
|
write_search_layer(0..list.len(), &list, mng, w)
|
||||||
write!(w, "end ")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,11 +321,17 @@ fn write_variable_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> {
|
|||||||
|
|
||||||
impl Driver for FuncData {
|
impl Driver for FuncData {
|
||||||
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let br_map = br_table::visit(self);
|
||||||
|
|
||||||
write_parameter_list(self, w)?;
|
write_parameter_list(self, w)?;
|
||||||
write_variable_list(self, w)?;
|
write_variable_list(self, w)?;
|
||||||
write!(w, "local temp ")?;
|
|
||||||
|
|
||||||
mng.num_param = self.num_param;
|
if !br_map.is_empty() {
|
||||||
|
write!(w, "local br_map, temp = {{}}, nil ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
mng.set_table_map(br_map);
|
||||||
|
mng.set_num_param(self.num_param);
|
||||||
self.code.write(mng, w)?;
|
self.code.write(mng, w)?;
|
||||||
|
|
||||||
if self.num_result != 0 {
|
if self.num_result != 0 {
|
||||||
|
29
codegen-luau/src/analyzer/br_table.rs
Normal file
29
codegen-luau/src/analyzer/br_table.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use wasm_ast::{
|
||||||
|
node::{BrTable, FuncData},
|
||||||
|
visit::{Driver, Visitor},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Visit {
|
||||||
|
id_map: HashMap<usize, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visitor for Visit {
|
||||||
|
fn visit_br_table(&mut self, table: &BrTable) {
|
||||||
|
let id = table as *const _ as usize;
|
||||||
|
let len = self.id_map.len() + 1;
|
||||||
|
|
||||||
|
self.id_map.insert(id, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit(ast: &FuncData) -> HashMap<usize, usize> {
|
||||||
|
let mut visit = Visit {
|
||||||
|
id_map: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
ast.accept(&mut visit);
|
||||||
|
|
||||||
|
visit.id_map
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
|
pub mod br_table;
|
||||||
pub mod localize;
|
pub mod localize;
|
||||||
pub mod operator;
|
pub mod operator;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
io::{Result, Write},
|
io::{Result, Write},
|
||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
use wasm_ast::node::{CmpOp, Expression};
|
use wasm_ast::node::{BrTable, CmpOp, Expression};
|
||||||
|
|
||||||
use crate::analyzer::operator::cmp_symbol_of;
|
use crate::analyzer::operator::cmp_symbol_of;
|
||||||
|
|
||||||
@ -15,11 +16,26 @@ pub enum Label {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
|
table_map: HashMap<usize, usize>,
|
||||||
label_list: Vec<Label>,
|
label_list: Vec<Label>,
|
||||||
pub num_param: usize,
|
num_param: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
pub fn get_table_index(&self, table: &BrTable) -> usize {
|
||||||
|
let id = table as *const _ as usize;
|
||||||
|
|
||||||
|
self.table_map[&id]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_table_map(&mut self, map: HashMap<usize, usize>) {
|
||||||
|
self.table_map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_num_param(&mut self, num_param: usize) {
|
||||||
|
self.num_param = num_param;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn label_list(&self) -> &[Label] {
|
pub fn label_list(&self) -> &[Label] {
|
||||||
&self.label_list
|
&self.label_list
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ use wasm_ast::node::{
|
|||||||
SetLocal, SetTemporary, Statement, StoreAt, Terminator,
|
SetLocal, SetTemporary, Statement, StoreAt, Terminator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::analyzer::br_table;
|
||||||
|
|
||||||
use super::manager::{
|
use super::manager::{
|
||||||
write_ascending, write_condition, write_separated, write_variable, Driver, Label, Manager,
|
write_ascending, write_condition, write_separated, write_variable, Driver, Label, Manager,
|
||||||
};
|
};
|
||||||
@ -39,26 +41,80 @@ impl Driver for Br {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_ordered_table<'a>(list: &'a [Br], default: &'a Br) -> Vec<&'a Br> {
|
||||||
|
let mut data: Vec<_> = list.iter().chain(std::iter::once(default)).collect();
|
||||||
|
|
||||||
|
data.sort_by_key(|v| v.target);
|
||||||
|
data.dedup_by_key(|v| v.target);
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_search_layer(
|
||||||
|
range: Range<usize>,
|
||||||
|
list: &[&Br],
|
||||||
|
mng: &mut Manager,
|
||||||
|
w: &mut dyn Write,
|
||||||
|
) -> Result<()> {
|
||||||
|
if range.len() == 1 {
|
||||||
|
return list[range.start].write(mng, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
let center = range.start + range.len() / 2;
|
||||||
|
let br = list[center];
|
||||||
|
|
||||||
|
if range.start != center {
|
||||||
|
write!(w, "if temp < {} then ", br.target)?;
|
||||||
|
write_search_layer(range.start..center, list, mng, w)?;
|
||||||
|
write!(w, "else")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if range.end != center + 1 {
|
||||||
|
write!(w, "if temp > {} then ", br.target)?;
|
||||||
|
write_search_layer(center + 1..range.end, list, mng, w)?;
|
||||||
|
write!(w, "else")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(w, " ")?;
|
||||||
|
br.write(mng, w)?;
|
||||||
|
write!(w, "end ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_table_setup(table: &BrTable, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let id = mng.get_table_index(table);
|
||||||
|
|
||||||
|
write!(w, "if not br_map[{id}] then ")?;
|
||||||
|
write!(w, "br_map[{id}] = (function() return {{[0] =")?;
|
||||||
|
|
||||||
|
table
|
||||||
|
.data
|
||||||
|
.iter()
|
||||||
|
.try_for_each(|v| write!(w, "{},", v.target))?;
|
||||||
|
|
||||||
|
write!(w, "}} end)()")?;
|
||||||
|
write!(w, "end ")?;
|
||||||
|
|
||||||
|
write!(w, "local temp = br_map[{id}][")?;
|
||||||
|
table.cond.write(mng, w)?;
|
||||||
|
write!(w, "] or {} ", table.default.target)
|
||||||
|
}
|
||||||
|
|
||||||
impl Driver for BrTable {
|
impl Driver for BrTable {
|
||||||
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
||||||
write!(w, "temp = ")?;
|
|
||||||
self.cond.write(mng, w)?;
|
|
||||||
|
|
||||||
// Our condition should be pure so we probably don't need
|
|
||||||
// to emit it in this case.
|
|
||||||
if self.data.is_empty() {
|
if self.data.is_empty() {
|
||||||
|
// Our condition should be pure so we probably don't need
|
||||||
|
// to emit it in this case.
|
||||||
return self.default.write(mng, w);
|
return self.default.write(mng, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (case, dest) in self.data.iter().enumerate() {
|
// `BrTable` is optimized by first mapping all indices to targets through
|
||||||
write!(w, "if temp == {case} then ")?;
|
// a Lua table; this reduces the size of the code generated as duplicate entries
|
||||||
dest.write(mng, w)?;
|
// don't need checking. Then, for speed, a binary search is done for the target
|
||||||
write!(w, "else")?;
|
// and the appropriate jump is performed.
|
||||||
}
|
let list = to_ordered_table(&self.data, &self.default);
|
||||||
|
|
||||||
write!(w, " ")?;
|
write_table_setup(self, mng, w)?;
|
||||||
self.default.write(mng, w)?;
|
write_search_layer(0..list.len(), &list, mng, w)
|
||||||
write!(w, "end ")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,11 +355,18 @@ fn write_variable_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> {
|
|||||||
|
|
||||||
impl Driver for FuncData {
|
impl Driver for FuncData {
|
||||||
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
|
||||||
|
let br_map = br_table::visit(self);
|
||||||
|
|
||||||
write_parameter_list(self, w)?;
|
write_parameter_list(self, w)?;
|
||||||
write_variable_list(self, w)?;
|
write_variable_list(self, w)?;
|
||||||
write!(w, "local desired, temp ")?;
|
write!(w, "local desired ")?;
|
||||||
|
|
||||||
mng.num_param = self.num_param;
|
if !br_map.is_empty() {
|
||||||
|
write!(w, "local br_map = {{}} ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
mng.set_table_map(br_map);
|
||||||
|
mng.set_num_param(self.num_param);
|
||||||
self.code.write(mng, w)?;
|
self.code.write(mng, w)?;
|
||||||
|
|
||||||
if self.num_result != 0 {
|
if self.num_result != 0 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user