Refactor to store args and types in common list pool.
This commit is contained in:
parent
4fd635ef7f
commit
dab18103ce
|
@ -38,7 +38,7 @@ fuzz_target!(
|
|||
log::trace!("Rejecting due to timeout in orig");
|
||||
return;
|
||||
}
|
||||
InterpResult::Trap => {
|
||||
InterpResult::Trap(..) => {
|
||||
// Silently reject.
|
||||
log::trace!("Rejecting due to trap in orig");
|
||||
return;
|
||||
|
|
|
@ -90,13 +90,13 @@ impl<'a, V: Visitor> BlockVisitor<'a, V> {
|
|||
}
|
||||
fn visit_inst(&mut self, value: Value, root: bool) {
|
||||
// If this is an instruction...
|
||||
if let ValueDef::Operator(_, ref args, _) = &self.body.values[value] {
|
||||
if let ValueDef::Operator(_, args, _) = &self.body.values[value] {
|
||||
// If root, we need to process the def.
|
||||
if root {
|
||||
self.visitor.visit_def(value);
|
||||
}
|
||||
// Handle uses.
|
||||
for &arg in args {
|
||||
for &arg in &self.body.arg_pool[*args] {
|
||||
self.visit_use(arg);
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ impl<'a> Context<'a> {
|
|||
// allocate a new one.
|
||||
let mut allocs = smallvec![];
|
||||
let expiring = expiring.entry(range.end).or_insert_with(|| smallvec![]);
|
||||
for &ty in self.body.values[value].tys() {
|
||||
for &ty in self.body.values[value].tys(&self.body.type_pool) {
|
||||
let local = freelist
|
||||
.get_mut(&ty)
|
||||
.and_then(|v| v.pop())
|
||||
|
|
|
@ -185,7 +185,9 @@ impl<'a> WasmFuncBackend<'a> {
|
|||
} else {
|
||||
let local = match &self.body.values[value] {
|
||||
&ValueDef::BlockParam(..) | &ValueDef::Operator(..) => self.locals.values[value][0],
|
||||
&ValueDef::PickOutput(orig_value, idx, _) => self.locals.values[orig_value][idx],
|
||||
&ValueDef::PickOutput(orig_value, idx, _) => {
|
||||
self.locals.values[orig_value][idx as usize]
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
func.instruction(&wasm_encoder::Instruction::LocalGet(local.index() as u32));
|
||||
|
@ -206,8 +208,8 @@ impl<'a> WasmFuncBackend<'a> {
|
|||
fn lower_inst(&self, value: Value, root: bool, func: &mut wasm_encoder::Function) {
|
||||
log::trace!("lower_inst: value {} root {}", value, root);
|
||||
match &self.body.values[value] {
|
||||
&ValueDef::Operator(ref op, ref args, ref tys) => {
|
||||
for &arg in &args[..] {
|
||||
&ValueDef::Operator(ref op, args, tys) => {
|
||||
for &arg in &self.body.arg_pool[args] {
|
||||
let arg = self.body.resolve_alias(arg);
|
||||
if self.trees.owner.contains_key(&arg) || self.trees.remat.contains(&arg) {
|
||||
log::trace!(" -> arg {} is owned", arg);
|
||||
|
|
|
@ -43,10 +43,10 @@ impl Trees {
|
|||
|
||||
for (value, def) in body.values.entries() {
|
||||
match def {
|
||||
&ValueDef::Operator(op, ref args, _) => {
|
||||
&ValueDef::Operator(op, args, _) => {
|
||||
// Ignore operators with invalid args: these must
|
||||
// always be unreachable.
|
||||
if args.iter().any(|arg| arg.is_invalid()) {
|
||||
if body.arg_pool[args].iter().any(|arg| arg.is_invalid()) {
|
||||
continue;
|
||||
}
|
||||
// If this is an always-rematerialized operator,
|
||||
|
@ -62,7 +62,7 @@ impl Trees {
|
|||
// in the arg slot. Otherwise if owned already
|
||||
// somewhere else, undo that and put in
|
||||
// `multi_use`.
|
||||
for (i, &arg) in args.iter().enumerate() {
|
||||
for (i, &arg) in body.arg_pool[args].iter().enumerate() {
|
||||
let arg = body.resolve_alias(arg);
|
||||
if multi_use.contains(&arg) {
|
||||
continue;
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::errors::FrontendError;
|
|||
use crate::ir::*;
|
||||
use crate::op_traits::{op_inputs, op_outputs};
|
||||
use crate::ops::Operator;
|
||||
use crate::pool::ListRef;
|
||||
use addr2line::gimli;
|
||||
use anyhow::{bail, Result};
|
||||
use fxhash::{FxHashMap, FxHashSet};
|
||||
|
@ -656,26 +657,27 @@ impl LocalTracker {
|
|||
ty: Type,
|
||||
at_block: Block,
|
||||
) -> Value {
|
||||
let types = body.single_type_list(ty);
|
||||
let val = match ty {
|
||||
Type::I32 => body.add_value(ValueDef::Operator(
|
||||
Operator::I32Const { value: 0 },
|
||||
vec![],
|
||||
vec![ty],
|
||||
ListRef::default(),
|
||||
types,
|
||||
)),
|
||||
Type::I64 => body.add_value(ValueDef::Operator(
|
||||
Operator::I64Const { value: 0 },
|
||||
vec![],
|
||||
vec![ty],
|
||||
ListRef::default(),
|
||||
types,
|
||||
)),
|
||||
Type::F32 => body.add_value(ValueDef::Operator(
|
||||
Operator::F32Const { value: 0 },
|
||||
vec![],
|
||||
vec![ty],
|
||||
ListRef::default(),
|
||||
types,
|
||||
)),
|
||||
Type::F64 => body.add_value(ValueDef::Operator(
|
||||
Operator::F64Const { value: 0 },
|
||||
vec![],
|
||||
vec![ty],
|
||||
ListRef::default(),
|
||||
types,
|
||||
)),
|
||||
_ => todo!("unsupported type: {:?}", ty),
|
||||
};
|
||||
|
@ -1684,19 +1686,25 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
|
||||
let n_outputs = outputs.len();
|
||||
|
||||
let mut input_operands = vec![];
|
||||
for &input in inputs.into_iter().rev() {
|
||||
let input_operands = self.body.arg_pool.allocate(inputs.len(), Value::invalid());
|
||||
let args = &mut self.body.arg_pool[input_operands];
|
||||
for (i, &input) in inputs.into_iter().enumerate().rev() {
|
||||
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
|
||||
assert_eq!(stack_top_ty, input);
|
||||
input_operands.push(stack_top);
|
||||
args[i] = stack_top;
|
||||
}
|
||||
input_operands.reverse();
|
||||
log::trace!(" -> operands: {:?}", input_operands);
|
||||
log::trace!(" -> ty {:?}", outputs);
|
||||
|
||||
let outputs_list = if n_outputs == 1 {
|
||||
self.body.single_type_list(outputs[0])
|
||||
} else {
|
||||
self.body.type_pool.from_iter(outputs.iter().cloned())
|
||||
};
|
||||
|
||||
let value = self
|
||||
.body
|
||||
.add_value(ValueDef::Operator(op, input_operands, outputs.to_vec()));
|
||||
.add_value(ValueDef::Operator(op, input_operands, outputs_list));
|
||||
log::trace!(" -> value: {:?}", value);
|
||||
|
||||
if self.reachable {
|
||||
|
@ -1711,7 +1719,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
|||
for (i, &output_ty) in outputs.into_iter().enumerate() {
|
||||
let pick = self
|
||||
.body
|
||||
.add_value(ValueDef::PickOutput(value, i, output_ty));
|
||||
.add_value(ValueDef::PickOutput(value, i as u32, output_ty));
|
||||
if self.reachable {
|
||||
self.body.append_to_block(self.cur_block, pick);
|
||||
}
|
||||
|
|
|
@ -133,10 +133,10 @@ impl InterpContext {
|
|||
&ValueDef::Alias(_) => smallvec![],
|
||||
&ValueDef::PickOutput(val, idx, _) => {
|
||||
let val = body.resolve_alias(val);
|
||||
smallvec![frame.values.get(&val).unwrap()[idx]]
|
||||
smallvec![frame.values.get(&val).unwrap()[idx as usize]]
|
||||
}
|
||||
&ValueDef::Operator(Operator::Call { function_index }, ref args, _) => {
|
||||
let args = args
|
||||
&ValueDef::Operator(Operator::Call { function_index }, args, _) => {
|
||||
let args = body.arg_pool[args]
|
||||
.iter()
|
||||
.map(|&arg| {
|
||||
let arg = body.resolve_alias(arg);
|
||||
|
@ -151,12 +151,8 @@ impl InterpContext {
|
|||
_ => return result,
|
||||
}
|
||||
}
|
||||
&ValueDef::Operator(
|
||||
Operator::CallIndirect { table_index, .. },
|
||||
ref args,
|
||||
_,
|
||||
) => {
|
||||
let args = args
|
||||
&ValueDef::Operator(Operator::CallIndirect { table_index, .. }, args, _) => {
|
||||
let args = body.arg_pool[args]
|
||||
.iter()
|
||||
.map(|&arg| {
|
||||
let arg = body.resolve_alias(arg);
|
||||
|
@ -173,8 +169,8 @@ impl InterpContext {
|
|||
_ => return result,
|
||||
}
|
||||
}
|
||||
&ValueDef::Operator(ref op, ref args, _) => {
|
||||
let args = args
|
||||
&ValueDef::Operator(ref op, args, _) => {
|
||||
let args = body.arg_pool[args]
|
||||
.iter()
|
||||
.map(|&arg| {
|
||||
let arg = body.resolve_alias(arg);
|
||||
|
@ -200,9 +196,9 @@ impl InterpContext {
|
|||
};
|
||||
smallvec![result]
|
||||
}
|
||||
&ValueDef::Trace(id, ref args) => {
|
||||
&ValueDef::Trace(id, args) => {
|
||||
if let Some(handler) = self.trace_handler.as_ref() {
|
||||
let args = args
|
||||
let args = body.arg_pool[args]
|
||||
.iter()
|
||||
.map(|&arg| {
|
||||
let arg = body.resolve_alias(arg);
|
||||
|
|
|
@ -5,24 +5,24 @@ use crate::entity::EntityRef;
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
pub struct FunctionBodyDisplay<'a>(
|
||||
pub(crate) &'a FunctionBody,
|
||||
pub(crate) &'a str,
|
||||
pub(crate) bool,
|
||||
pub(crate) Option<&'a Module<'a>>,
|
||||
);
|
||||
pub struct FunctionBodyDisplay<'a> {
|
||||
pub(crate) body: &'a FunctionBody,
|
||||
pub(crate) indent: &'a str,
|
||||
pub(crate) verbose: bool,
|
||||
pub(crate) module: Option<&'a Module<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Display for FunctionBodyDisplay<'a> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
let arg_tys = self
|
||||
.0
|
||||
.body
|
||||
.locals
|
||||
.values()
|
||||
.take(self.0.n_params)
|
||||
.take(self.body.n_params)
|
||||
.map(|&ty| format!("{}", ty))
|
||||
.collect::<Vec<_>>();
|
||||
let ret_tys = self
|
||||
.0
|
||||
.body
|
||||
.rets
|
||||
.iter()
|
||||
.map(|&ty| format!("{}", ty))
|
||||
|
@ -30,51 +30,63 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
|
|||
writeln!(
|
||||
f,
|
||||
"{}function({}) -> {} {{",
|
||||
self.1,
|
||||
self.indent,
|
||||
arg_tys.join(", "),
|
||||
ret_tys.join(", ")
|
||||
)?;
|
||||
|
||||
let verbose = self.2;
|
||||
for (value, value_def) in self.0.values.entries() {
|
||||
for (value, value_def) in self.body.values.entries() {
|
||||
match value_def {
|
||||
ValueDef::Operator(op, args, tys) if verbose => writeln!(
|
||||
ValueDef::Operator(op, args, tys) if self.verbose => writeln!(
|
||||
f,
|
||||
"{} {} = {} {} # {}",
|
||||
self.1,
|
||||
self.indent,
|
||||
value,
|
||||
op,
|
||||
args.iter()
|
||||
self.body.arg_pool[*args]
|
||||
.iter()
|
||||
.map(|arg| format!("{}", arg))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
tys.iter()
|
||||
self.body.type_pool[*tys]
|
||||
.iter()
|
||||
.map(|arg| format!("{}", arg))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)?,
|
||||
ValueDef::BlockParam(block, idx, ty) if verbose => writeln!(
|
||||
ValueDef::BlockParam(block, idx, ty) if self.verbose => writeln!(
|
||||
f,
|
||||
"{} {} = blockparam {}, {} # {}",
|
||||
self.1, value, block, idx, ty
|
||||
self.indent, value, block, idx, ty
|
||||
)?,
|
||||
ValueDef::Alias(alias_target) => {
|
||||
if verbose {
|
||||
writeln!(f, "{} {} = {}", self.1, value, alias_target)?
|
||||
if self.verbose {
|
||||
writeln!(f, "{} {} = {}", self.indent, value, alias_target)?
|
||||
}
|
||||
}
|
||||
ValueDef::PickOutput(val, idx, ty) => {
|
||||
writeln!(f, "{} {} = {}.{} # {}", self.1, value, val, idx, ty)?
|
||||
writeln!(f, "{} {} = {}.{} # {}", self.indent, value, val, idx, ty)?
|
||||
}
|
||||
ValueDef::Placeholder(ty) => {
|
||||
writeln!(f, "{} {} = placeholder # {}", self.1, value, ty)?
|
||||
writeln!(f, "{} {} = placeholder # {}", self.indent, value, ty)?
|
||||
}
|
||||
ValueDef::Trace(id, args) => writeln!(
|
||||
f,
|
||||
"{} trace {}, {}",
|
||||
self.indent,
|
||||
id,
|
||||
self.body.arg_pool[*args]
|
||||
.iter()
|
||||
.map(|arg| format!("{}", arg))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)?,
|
||||
ValueDef::None => panic!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
for (block_id, block) in self.0.blocks.entries() {
|
||||
for (block_id, block) in self.body.blocks.entries() {
|
||||
let block_params = block
|
||||
.params
|
||||
.iter()
|
||||
|
@ -83,7 +95,7 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
|
|||
writeln!(
|
||||
f,
|
||||
"{} {}({}): # {}",
|
||||
self.1,
|
||||
self.indent,
|
||||
block_id,
|
||||
block_params.join(", "),
|
||||
block.desc
|
||||
|
@ -91,43 +103,49 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
|
|||
writeln!(
|
||||
f,
|
||||
"{} # preds: {}",
|
||||
self.1,
|
||||
self.indent,
|
||||
block
|
||||
.preds
|
||||
.iter()
|
||||
.map(|pred| format!("{} ({})", pred, self.0.blocks[*pred].desc))
|
||||
.map(|pred| format!("{} ({})", pred, self.body.blocks[*pred].desc))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"{} # succs: {}",
|
||||
self.1,
|
||||
self.indent,
|
||||
block
|
||||
.succs
|
||||
.iter()
|
||||
.map(|succ| format!("{} ({})", succ, self.0.blocks[*succ].desc))
|
||||
.map(|succ| format!("{} ({})", succ, self.body.blocks[*succ].desc))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)?;
|
||||
for (_, param) in &block.params {
|
||||
if let Some(local) = self.0.value_locals[*param] {
|
||||
writeln!(f, "{} # {}: {}", self.1, param, local)?;
|
||||
if let Some(local) = self.body.value_locals[*param] {
|
||||
writeln!(f, "{} # {}: {}", self.indent, param, local)?;
|
||||
}
|
||||
}
|
||||
for &inst in &block.insts {
|
||||
if let Some(local) = self.0.value_locals[inst] {
|
||||
writeln!(f, "{} # {}: {}", self.1, inst, local)?;
|
||||
if let Some(local) = self.body.value_locals[inst] {
|
||||
writeln!(f, "{} # {}: {}", self.indent, inst, local)?;
|
||||
}
|
||||
match &self.0.values[inst] {
|
||||
match &self.body.values[inst] {
|
||||
ValueDef::Operator(op, args, tys) => {
|
||||
let args = args.iter().map(|&v| format!("{}", v)).collect::<Vec<_>>();
|
||||
let tys = tys.iter().map(|&ty| format!("{}", ty)).collect::<Vec<_>>();
|
||||
let loc = if self.0.source_locs[inst] != SourceLoc::invalid()
|
||||
&& self.3.is_some()
|
||||
let args = self.body.arg_pool[*args]
|
||||
.iter()
|
||||
.map(|&v| format!("{}", v))
|
||||
.collect::<Vec<_>>();
|
||||
let tys = self.body.type_pool[*tys]
|
||||
.iter()
|
||||
.map(|&ty| format!("{}", ty))
|
||||
.collect::<Vec<_>>();
|
||||
let loc = if self.body.source_locs[inst] != SourceLoc::invalid()
|
||||
&& self.module.is_some()
|
||||
{
|
||||
let module = self.3.as_ref().unwrap();
|
||||
let loc = self.0.source_locs[inst];
|
||||
let module = self.module.as_ref().unwrap();
|
||||
let loc = self.body.source_locs[inst];
|
||||
let data = &module.debug.source_locs[loc];
|
||||
let filename = &module.debug.source_files[data.file];
|
||||
format!("@{} {}:{}:{}", loc, filename, data.line, data.col)
|
||||
|
@ -137,7 +155,7 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
|
|||
writeln!(
|
||||
f,
|
||||
"{} {} = {} {} # {} {}",
|
||||
self.1,
|
||||
self.indent,
|
||||
inst,
|
||||
op,
|
||||
args.join(", "),
|
||||
|
@ -146,37 +164,42 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
|
|||
)?;
|
||||
}
|
||||
ValueDef::PickOutput(val, idx, ty) => {
|
||||
writeln!(f, "{} {} = {}.{} # {}", self.1, inst, val, idx, ty)?;
|
||||
writeln!(f, "{} {} = {}.{} # {}", self.indent, inst, val, idx, ty)?;
|
||||
}
|
||||
ValueDef::Alias(val) => {
|
||||
writeln!(f, "{} {} = {}", self.1, inst, val)?;
|
||||
writeln!(f, "{} {} = {}", self.indent, inst, val)?;
|
||||
}
|
||||
ValueDef::Trace(id, args) => {
|
||||
let args = args.iter().map(|&v| format!("{}", v)).collect::<Vec<_>>();
|
||||
writeln!(f, "{} trace {}, {}", self.1, id, args.join(", "))?;
|
||||
let args = self.body.arg_pool[*args]
|
||||
.iter()
|
||||
.map(|&v| format!("{}", v))
|
||||
.collect::<Vec<_>>();
|
||||
writeln!(f, "{} trace {}, {}", self.indent, id, args.join(", "))?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
writeln!(f, "{} {}", self.1, block.terminator)?;
|
||||
writeln!(f, "{} {}", self.indent, block.terminator)?;
|
||||
}
|
||||
|
||||
writeln!(f, "{}}}", self.1)?;
|
||||
writeln!(f, "{}}}", self.indent)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModuleDisplay<'a>(pub(crate) &'a Module<'a>);
|
||||
pub struct ModuleDisplay<'a> {
|
||||
pub(crate) module: &'a Module<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Display for ModuleDisplay<'a> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
writeln!(f, "module {{")?;
|
||||
if let Some(func) = self.0.start_func {
|
||||
if let Some(func) = self.module.start_func {
|
||||
writeln!(f, " start = {}", func)?;
|
||||
}
|
||||
let mut sig_strs = HashMap::new();
|
||||
for (sig, sig_data) in self.0.signatures.entries() {
|
||||
for (sig, sig_data) in self.module.signatures.entries() {
|
||||
let arg_tys = sig_data
|
||||
.params
|
||||
.iter()
|
||||
|
@ -191,14 +214,14 @@ impl<'a> Display for ModuleDisplay<'a> {
|
|||
sig_strs.insert(sig, sig_str.clone());
|
||||
writeln!(f, " {}: {}", sig, sig_str)?;
|
||||
}
|
||||
for (global, global_data) in self.0.globals.entries() {
|
||||
for (global, global_data) in self.module.globals.entries() {
|
||||
writeln!(
|
||||
f,
|
||||
" {}: {:?} # {}",
|
||||
global, global_data.value, global_data.ty
|
||||
)?;
|
||||
}
|
||||
for (table, table_data) in self.0.tables.entries() {
|
||||
for (table, table_data) in self.module.tables.entries() {
|
||||
writeln!(f, " {}: {}", table, table_data.ty)?;
|
||||
if let Some(funcs) = &table_data.func_elements {
|
||||
for (i, &func) in funcs.iter().enumerate() {
|
||||
|
@ -206,7 +229,7 @@ impl<'a> Display for ModuleDisplay<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (memory, memory_data) in self.0.memories.entries() {
|
||||
for (memory, memory_data) in self.module.memories.entries() {
|
||||
writeln!(
|
||||
f,
|
||||
" {}: initial {} max {:?}",
|
||||
|
@ -222,17 +245,17 @@ impl<'a> Display for ModuleDisplay<'a> {
|
|||
)?;
|
||||
}
|
||||
}
|
||||
for import in &self.0.imports {
|
||||
for import in &self.module.imports {
|
||||
writeln!(
|
||||
f,
|
||||
" import \"{}\".\"{}\": {}",
|
||||
import.module, import.name, import.kind
|
||||
)?;
|
||||
}
|
||||
for export in &self.0.exports {
|
||||
for export in &self.module.exports {
|
||||
writeln!(f, " export \"{}\": {}", export.name, export.kind)?;
|
||||
}
|
||||
for (func, func_decl) in self.0.funcs.entries() {
|
||||
for (func, func_decl) in self.module.funcs.entries() {
|
||||
match func_decl {
|
||||
FuncDecl::Body(sig, name, body) => {
|
||||
writeln!(
|
||||
|
@ -243,7 +266,7 @@ impl<'a> Display for ModuleDisplay<'a> {
|
|||
sig,
|
||||
sig_strs.get(&sig).unwrap()
|
||||
)?;
|
||||
writeln!(f, "{}", body.display(" ", Some(self.0)))?;
|
||||
writeln!(f, "{}", body.display(" ", Some(self.module)))?;
|
||||
}
|
||||
FuncDecl::Lazy(sig, name, reader) => {
|
||||
writeln!(
|
||||
|
@ -282,14 +305,14 @@ impl<'a> Display for ModuleDisplay<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (loc, loc_data) in self.0.debug.source_locs.entries() {
|
||||
for (loc, loc_data) in self.module.debug.source_locs.entries() {
|
||||
writeln!(
|
||||
f,
|
||||
" {} = {} line {} column {}",
|
||||
loc, loc_data.file, loc_data.line, loc_data.col
|
||||
)?;
|
||||
}
|
||||
for (file, file_name) in self.0.debug.source_files.entries() {
|
||||
for (file, file_name) in self.module.debug.source_files.entries() {
|
||||
writeln!(f, " {} = \"{}\"", file, file_name)?;
|
||||
}
|
||||
writeln!(f, "}}")?;
|
||||
|
|
|
@ -4,7 +4,9 @@ use crate::cfg::CFGInfo;
|
|||
use crate::entity::{EntityRef, EntityVec, PerEntity};
|
||||
use crate::frontend::parse_body;
|
||||
use crate::ir::SourceLoc;
|
||||
use crate::pool::{ListPool, ListRef};
|
||||
use anyhow::Result;
|
||||
use fxhash::FxHashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// A declaration of a function: there is one `FuncDecl` per `Func`
|
||||
|
@ -124,6 +126,12 @@ pub struct FunctionBody {
|
|||
pub blocks: EntityVec<Block, BlockDef>,
|
||||
/// Value definitions, indexed by `Value`.
|
||||
pub values: EntityVec<Value, ValueDef>,
|
||||
/// Pool of types for ValueDefs' result type lists.
|
||||
pub type_pool: ListPool<Type>,
|
||||
/// Deduplication for type-lists of single types.
|
||||
pub single_type_dedup: FxHashMap<Type, ListRef<Type>>,
|
||||
/// Pool of values for ValueDefs' arg lists.
|
||||
pub arg_pool: ListPool<Value>,
|
||||
/// Blocks in which values are computed. Each may be `Block::invalid()` if not placed.
|
||||
pub value_blocks: PerEntity<Value, Block>,
|
||||
/// Wasm locals that values correspond to, if any.
|
||||
|
@ -142,7 +150,7 @@ impl FunctionBody {
|
|||
let mut values = EntityVec::default();
|
||||
let mut value_blocks = PerEntity::default();
|
||||
for (i, &arg_ty) in locals.values().enumerate() {
|
||||
let value = values.push(ValueDef::BlockParam(entry, i, arg_ty));
|
||||
let value = values.push(ValueDef::BlockParam(entry, i as u32, arg_ty));
|
||||
blocks[entry].params.push((arg_ty, value));
|
||||
value_blocks[value] = entry;
|
||||
}
|
||||
|
@ -153,6 +161,9 @@ impl FunctionBody {
|
|||
entry,
|
||||
blocks,
|
||||
values,
|
||||
type_pool: ListPool::default(),
|
||||
arg_pool: ListPool::default(),
|
||||
single_type_dedup: FxHashMap::default(),
|
||||
value_blocks,
|
||||
value_locals: PerEntity::default(),
|
||||
source_locs: PerEntity::default(),
|
||||
|
@ -178,6 +189,14 @@ impl FunctionBody {
|
|||
id
|
||||
}
|
||||
|
||||
pub fn single_type_list(&mut self, ty: Type) -> ListRef<Type> {
|
||||
let type_pool = &mut self.type_pool;
|
||||
*self
|
||||
.single_type_dedup
|
||||
.entry(ty)
|
||||
.or_insert_with(|| type_pool.single(ty))
|
||||
}
|
||||
|
||||
pub fn add_edge(&mut self, from: Block, to: Block) {
|
||||
let succ_pos = self.blocks[from].succs.len();
|
||||
let pred_pos = self.blocks[to].preds.len();
|
||||
|
@ -284,7 +303,7 @@ impl FunctionBody {
|
|||
|
||||
pub fn add_blockparam(&mut self, block: Block, ty: Type) -> Value {
|
||||
let index = self.blocks[block].params.len();
|
||||
let value = self.add_value(ValueDef::BlockParam(block, index, ty));
|
||||
let value = self.add_value(ValueDef::BlockParam(block, index as u32, ty));
|
||||
self.blocks[block].params.push((ty, value));
|
||||
self.value_blocks[value] = block;
|
||||
value
|
||||
|
@ -301,7 +320,7 @@ impl FunctionBody {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
self.blocks[block].params.push((ty, value));
|
||||
self.values[value] = ValueDef::BlockParam(block, index, ty);
|
||||
self.values[value] = ValueDef::BlockParam(block, index as u32, ty);
|
||||
}
|
||||
|
||||
pub fn mark_value_as_local(&mut self, value: Value, local: Local) {
|
||||
|
@ -342,7 +361,12 @@ impl FunctionBody {
|
|||
indent: &'a str,
|
||||
module: Option<&'a Module>,
|
||||
) -> FunctionBodyDisplay<'a> {
|
||||
FunctionBodyDisplay(self, indent, /* verbose = */ false, module)
|
||||
FunctionBodyDisplay {
|
||||
body: self,
|
||||
indent,
|
||||
verbose: false,
|
||||
module,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_verbose<'a>(
|
||||
|
@ -350,7 +374,12 @@ impl FunctionBody {
|
|||
indent: &'a str,
|
||||
module: Option<&'a Module>,
|
||||
) -> FunctionBodyDisplay<'a> {
|
||||
FunctionBodyDisplay(self, indent, /* verbose = */ true, module)
|
||||
FunctionBodyDisplay {
|
||||
body: self,
|
||||
indent,
|
||||
verbose: true,
|
||||
module,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> anyhow::Result<()> {
|
||||
|
@ -419,8 +448,8 @@ impl FunctionBody {
|
|||
|
||||
for (i, &inst) in block_def.insts.iter().enumerate() {
|
||||
match &self.values[inst] {
|
||||
&ValueDef::Operator(_, ref args, _) => {
|
||||
for &arg in args {
|
||||
&ValueDef::Operator(_, args, _) => {
|
||||
for &arg in &self.arg_pool[args] {
|
||||
visit_use(arg, Some(i), Some(inst));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,6 +236,6 @@ impl<'a> Module<'a> {
|
|||
where
|
||||
'b: 'a,
|
||||
{
|
||||
ModuleDisplay(self)
|
||||
ModuleDisplay { module: self }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
use super::{Block, Type, Value};
|
||||
use crate::pool::{ListPool, ListRef};
|
||||
use crate::Operator;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub enum ValueDef {
|
||||
BlockParam(Block, usize, Type),
|
||||
Operator(Operator, Vec<Value>, Vec<Type>),
|
||||
PickOutput(Value, usize, Type),
|
||||
BlockParam(Block, u32, Type),
|
||||
Operator(Operator, ListRef<Value>, ListRef<Type>),
|
||||
PickOutput(Value, u32, Type),
|
||||
Alias(Value),
|
||||
Placeholder(Type),
|
||||
Trace(usize, Vec<Value>),
|
||||
Trace(usize, ListRef<Value>),
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
impl ValueDef {
|
||||
pub fn ty(&self) -> Option<Type> {
|
||||
pub fn ty(&self, types: &ListPool<Type>) -> Option<Type> {
|
||||
match self {
|
||||
&ValueDef::BlockParam(_, _, ty) => Some(ty),
|
||||
&ValueDef::Operator(_, _, ref tys) if tys.len() == 0 => None,
|
||||
&ValueDef::Operator(_, _, ref tys) if tys.len() == 1 => Some(tys[0]),
|
||||
&ValueDef::Operator(_, _, tys) if tys.len() == 0 => None,
|
||||
&ValueDef::Operator(_, _, tys) if tys.len() == 1 => Some(types[tys][0]),
|
||||
&ValueDef::PickOutput(_, _, ty) => Some(ty),
|
||||
&ValueDef::Placeholder(ty) => Some(ty),
|
||||
&ValueDef::Trace(_, _) => None,
|
||||
|
@ -26,9 +27,9 @@ impl ValueDef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tys(&self) -> &[Type] {
|
||||
pub fn tys<'a>(&'a self, types: &'a ListPool<Type>) -> &'a [Type] {
|
||||
match self {
|
||||
&ValueDef::Operator(_, _, ref tys) => &tys[..],
|
||||
&ValueDef::Operator(_, _, tys) => &types[tys],
|
||||
&ValueDef::BlockParam(_, _, ref ty)
|
||||
| &ValueDef::PickOutput(_, _, ref ty)
|
||||
| &ValueDef::Placeholder(ref ty) => std::slice::from_ref(ty),
|
||||
|
@ -36,19 +37,19 @@ impl ValueDef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn visit_uses<F: FnMut(Value)>(&self, mut f: F) {
|
||||
pub fn visit_uses<F: FnMut(Value)>(&self, arg_pool: &ListPool<Value>, mut f: F) {
|
||||
match self {
|
||||
&ValueDef::BlockParam { .. } => {}
|
||||
&ValueDef::Operator(_, ref args, _) => {
|
||||
for &arg in args {
|
||||
&ValueDef::Operator(_, args, _) => {
|
||||
for &arg in &arg_pool[args] {
|
||||
f(arg);
|
||||
}
|
||||
}
|
||||
&ValueDef::PickOutput(from, ..) => f(from),
|
||||
&ValueDef::Alias(value) => f(value),
|
||||
&ValueDef::Placeholder(_) => {}
|
||||
&ValueDef::Trace(_, ref args) => {
|
||||
for &arg in args {
|
||||
&ValueDef::Trace(_, args) => {
|
||||
for &arg in &arg_pool[args] {
|
||||
f(arg);
|
||||
}
|
||||
}
|
||||
|
@ -56,19 +57,19 @@ impl ValueDef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_uses<F: FnMut(&mut Value)>(&mut self, mut f: F) {
|
||||
pub fn update_uses<F: FnMut(&mut Value)>(&mut self, arg_pool: &mut ListPool<Value>, mut f: F) {
|
||||
match self {
|
||||
&mut ValueDef::BlockParam { .. } => {}
|
||||
&mut ValueDef::Operator(_, ref mut args, _) => {
|
||||
for arg in args {
|
||||
&mut ValueDef::Operator(_, args, _) => {
|
||||
for arg in &mut arg_pool[args] {
|
||||
f(arg);
|
||||
}
|
||||
}
|
||||
&mut ValueDef::PickOutput(ref mut from, ..) => f(from),
|
||||
&mut ValueDef::Alias(ref mut value) => f(value),
|
||||
&mut ValueDef::Placeholder(_) => {}
|
||||
&mut ValueDef::Trace(_, ref mut args) => {
|
||||
for arg in args {
|
||||
&mut ValueDef::Trace(_, args) => {
|
||||
for arg in &mut arg_pool[args] {
|
||||
f(arg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ mod ir;
|
|||
mod op_traits;
|
||||
mod ops;
|
||||
pub mod passes;
|
||||
pub mod pool;
|
||||
mod scoped_map;
|
||||
|
||||
pub use errors::*;
|
||||
|
|
|
@ -297,6 +297,11 @@ pub enum Operator {
|
|||
},
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn op_size() {
|
||||
assert_eq!(std::mem::size_of::<Operator>(), 16);
|
||||
}
|
||||
|
||||
impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||
type Error = ();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::cfg::CFGInfo;
|
|||
use crate::interp::{const_eval, ConstVal};
|
||||
use crate::ir::*;
|
||||
use crate::passes::dom_pass::{dom_pass, DomtreePass};
|
||||
use crate::pool::ListRef;
|
||||
use crate::scoped_map::ScopedMap;
|
||||
use crate::Operator;
|
||||
|
||||
|
@ -48,10 +49,24 @@ impl GVNPass {
|
|||
i += 1;
|
||||
if value_is_pure(inst, body) {
|
||||
let mut value = body.values[inst].clone();
|
||||
value.update_uses(|val| *val = body.resolve_and_update_alias(*val));
|
||||
|
||||
match &mut value {
|
||||
&mut ValueDef::Operator(_, args, _) | &mut ValueDef::Trace(_, args) => {
|
||||
for i in 0..args.len() {
|
||||
let val = body.arg_pool[args][i];
|
||||
let val = body.resolve_and_update_alias(val);
|
||||
body.arg_pool[args][i] = val;
|
||||
}
|
||||
}
|
||||
&mut ValueDef::PickOutput(ref mut val, ..) => {
|
||||
let updated = body.resolve_and_update_alias(*val);
|
||||
*val = updated;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let ValueDef::Operator(op, args, ..) = &value {
|
||||
let arg_values = args
|
||||
let arg_values = body.arg_pool[*args]
|
||||
.iter()
|
||||
.map(|&arg| match body.values[arg] {
|
||||
ValueDef::Operator(Operator::I32Const { value }, _, _) => {
|
||||
|
@ -74,32 +89,32 @@ impl GVNPass {
|
|||
Some(ConstVal::I32(val)) => {
|
||||
value = ValueDef::Operator(
|
||||
Operator::I32Const { value: val },
|
||||
vec![],
|
||||
vec![Type::I32],
|
||||
ListRef::default(),
|
||||
body.single_type_list(Type::I32),
|
||||
);
|
||||
body.values[inst] = value.clone();
|
||||
}
|
||||
Some(ConstVal::I64(val)) => {
|
||||
value = ValueDef::Operator(
|
||||
Operator::I64Const { value: val },
|
||||
vec![],
|
||||
vec![Type::I64],
|
||||
ListRef::default(),
|
||||
body.single_type_list(Type::I64),
|
||||
);
|
||||
body.values[inst] = value.clone();
|
||||
}
|
||||
Some(ConstVal::F32(val)) => {
|
||||
value = ValueDef::Operator(
|
||||
Operator::F32Const { value: val },
|
||||
vec![],
|
||||
vec![Type::F32],
|
||||
ListRef::default(),
|
||||
body.single_type_list(Type::F32),
|
||||
);
|
||||
body.values[inst] = value.clone();
|
||||
}
|
||||
Some(ConstVal::F64(val)) => {
|
||||
value = ValueDef::Operator(
|
||||
Operator::F64Const { value: val },
|
||||
vec![],
|
||||
vec![Type::F64],
|
||||
ListRef::default(),
|
||||
body.single_type_list(Type::F64),
|
||||
);
|
||||
body.values[inst] = value.clone();
|
||||
}
|
||||
|
|
|
@ -48,8 +48,8 @@ impl MaxSSAPass {
|
|||
let mut uses = BTreeSet::default();
|
||||
for &inst in &body.blocks[block].insts {
|
||||
match &body.values[inst] {
|
||||
&ValueDef::Operator(_, ref args, _) => {
|
||||
for &arg in args {
|
||||
&ValueDef::Operator(_, args, _) | &ValueDef::Trace(_, args) => {
|
||||
for &arg in &body.arg_pool[args] {
|
||||
let arg = body.resolve_alias(arg);
|
||||
uses.insert(arg);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ impl MaxSSAPass {
|
|||
self.new_args[block].push(value);
|
||||
|
||||
// Create a placeholder value.
|
||||
let ty = body.values[value].ty().unwrap();
|
||||
let ty = body.values[value].ty(&body.type_pool).unwrap();
|
||||
let blockparam = body.add_blockparam(block, ty);
|
||||
self.value_map.insert((block, value), blockparam);
|
||||
|
||||
|
@ -147,9 +147,11 @@ impl MaxSSAPass {
|
|||
let inst = body.blocks[block].insts[i];
|
||||
let mut def = std::mem::take(&mut body.values[inst]);
|
||||
match &mut def {
|
||||
ValueDef::Operator(_, args, _) => {
|
||||
for arg in args {
|
||||
*arg = resolve(body, *arg);
|
||||
ValueDef::Operator(_, args, _) | ValueDef::Trace(_, args) => {
|
||||
for i in 0..args.len() {
|
||||
let val = body.arg_pool[*args][i];
|
||||
let val = resolve(body, val);
|
||||
body.arg_pool[*args][i] = val;
|
||||
}
|
||||
}
|
||||
ValueDef::PickOutput(value, ..) => {
|
||||
|
|
|
@ -99,8 +99,8 @@ pub fn run(func: &mut FunctionBody, cfg: &CFGInfo) {
|
|||
|
||||
// Renumber blockparam values.
|
||||
for (i, &(_, param)) in func.blocks[block].params.iter().enumerate() {
|
||||
let ty = func.values[param].ty().unwrap();
|
||||
func.values[param] = ValueDef::BlockParam(block, i, ty);
|
||||
let ty = func.values[param].ty(&func.type_pool).unwrap();
|
||||
func.values[param] = ValueDef::BlockParam(block, i as u32, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ pub fn run(body: &mut FunctionBody) {
|
|||
for value in body.values.iter() {
|
||||
let mut value_def = std::mem::take(&mut body.values[value]);
|
||||
match &mut value_def {
|
||||
ValueDef::Operator(_op, args, _tys) => {
|
||||
for arg in args {
|
||||
*arg = body.resolve_alias(*arg);
|
||||
ValueDef::Operator(_, args, _) | ValueDef::Trace(_, args) => {
|
||||
for i in 0..args.len() {
|
||||
let val = body.arg_pool[*args][i];
|
||||
let val = body.resolve_and_update_alias(val);
|
||||
body.arg_pool[*args][i] = val;
|
||||
}
|
||||
}
|
||||
ValueDef::PickOutput(val, _idx, _ty) => {
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn run(body: &FunctionBody, cfg: &CFGInfo) {
|
|||
match &body.values[param] {
|
||||
&ValueDef::BlockParam(param_block, param_idx, _) => {
|
||||
assert_eq!(param_block, block);
|
||||
assert_eq!(param_idx, i);
|
||||
assert_eq!(param_idx, i as u32);
|
||||
}
|
||||
_ => panic!(
|
||||
"Bad blockparam value for param {} of {} ({}): {:?}",
|
||||
|
@ -55,19 +55,14 @@ pub fn run(body: &FunctionBody, cfg: &CFGInfo) {
|
|||
|
||||
for &inst in &data.insts {
|
||||
match &body.values[inst] {
|
||||
&ValueDef::Operator(_, ref args, _) => {
|
||||
for &arg in args {
|
||||
&ValueDef::Operator(_, args, _) | &ValueDef::Trace(_, args) => {
|
||||
for &arg in &body.arg_pool[args] {
|
||||
validate(arg);
|
||||
}
|
||||
}
|
||||
&ValueDef::PickOutput(val, _, _) => {
|
||||
validate(val);
|
||||
}
|
||||
&ValueDef::Trace(_, ref args) => {
|
||||
for &arg in args {
|
||||
validate(arg);
|
||||
}
|
||||
}
|
||||
&ValueDef::Alias(..) => {}
|
||||
&ValueDef::None | &ValueDef::Placeholder(_) | &ValueDef::BlockParam(..) => {}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,8 @@ pub fn run(body: &mut FunctionBody) {
|
|||
for (block, data) in body.blocks.entries_mut() {
|
||||
let value = ValueDef::Trace(
|
||||
block.index(),
|
||||
data.params
|
||||
.iter()
|
||||
.map(|&(_, param)| param)
|
||||
.collect::<Vec<_>>(),
|
||||
body.arg_pool
|
||||
.from_iter(data.params.iter().map(|&(_, param)| param)),
|
||||
);
|
||||
let value = body.values.push(value);
|
||||
data.insts.insert(0, value);
|
||||
|
|
64
src/pool.rs
Normal file
64
src/pool.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
//! Pooled list data structure.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::default::Default;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ListPool<T: Clone + Debug> {
|
||||
storage: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug> Default for ListPool<T> {
|
||||
fn default() -> Self {
|
||||
ListPool { storage: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ListRef<T>(u32, u32, PhantomData<T>);
|
||||
|
||||
impl<T> Default for ListRef<T> {
|
||||
fn default() -> Self {
|
||||
ListRef(0, 0, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug> ListPool<T> {
|
||||
pub fn from_iter<I: Iterator<Item = T>>(&mut self, iter: I) -> ListRef<T> {
|
||||
let start = u32::try_from(self.storage.len()).unwrap();
|
||||
self.storage.extend(iter);
|
||||
let end = u32::try_from(self.storage.len()).unwrap();
|
||||
ListRef(start, end, PhantomData)
|
||||
}
|
||||
pub fn single(&mut self, value: T) -> ListRef<T> {
|
||||
self.from_iter(std::iter::once(value))
|
||||
}
|
||||
pub fn allocate(&mut self, size: usize, initial: T) -> ListRef<T> {
|
||||
self.from_iter(std::iter::repeat(initial).take(size))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug> Index<ListRef<T>> for ListPool<T> {
|
||||
type Output = [T];
|
||||
fn index(&self, index: ListRef<T>) -> &[T] {
|
||||
&self.storage[index.0 as usize..index.1 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug> IndexMut<ListRef<T>> for ListPool<T> {
|
||||
fn index_mut(&mut self, index: ListRef<T>) -> &mut [T] {
|
||||
&mut self.storage[index.0 as usize..index.1 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ListRef<T> {
|
||||
pub fn len(&self) -> usize {
|
||||
(self.1 - self.0) as usize
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue