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