From 5e3edc1de4e5ec4a8bf56b8fb9ee45ebe3a9117e Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Fri, 24 Dec 2021 23:02:20 -0800 Subject: [PATCH] working roundtrip of hello world? --- src/backend/final.rs | 97 ++++------------ src/backend/mod.rs | 4 - src/backend/serialize.rs | 204 ++++++++------------------------- src/backend/structured.rs | 51 ++------- src/frontend.rs | 18 +-- src/ir.rs | 111 +++++------------- src/lib.rs | 1 + src/{backend => }/use_count.rs | 3 +- 8 files changed, 112 insertions(+), 377 deletions(-) rename src/{backend => }/use_count.rs (99%) diff --git a/src/backend/final.rs b/src/backend/final.rs index d3eeb60..0ed80f8 100644 --- a/src/backend/final.rs +++ b/src/backend/final.rs @@ -4,7 +4,6 @@ use super::{Locations, SerializedBlockTarget, SerializedBody, SerializedOperator use crate::{ops::ty_to_valty, FunctionBody}; use std::borrow::Cow; use wasm_encoder::BlockType; -use wasmparser::Type; #[derive(Clone, Debug)] pub struct Wasm { @@ -12,59 +11,23 @@ pub struct Wasm { pub locals: Vec, } -struct WasmContext<'a, FT: FuncTypeSink> { +struct WasmContext<'a> { wasm: &'a mut Wasm, - func_type_sink: &'a mut FT, } -pub trait FuncTypeSink { - fn add_signature(&mut self, params: Vec, results: Vec) -> u32; -} - -impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> { - fn create_type(&mut self, params: Vec, results: Vec) -> u32 { - self.func_type_sink.add_signature(params, results) - } - - fn find_fallthrough_ty<'b>( - &mut self, - params: &[Type], - mut targets: impl Iterator, - ) -> u32 { - let fallthrough_rets = targets - .find_map(|target| match target { - SerializedBlockTarget::Fallthrough(tys, ..) => Some(&tys[..]), - _ => None, - }) - .unwrap_or(&[]); - - self.create_type(params.to_vec(), fallthrough_rets.to_vec()) - } - +impl<'a> WasmContext<'a> { fn translate(&mut self, op: &SerializedOperator, locations: &Locations) { log::trace!("translate: {:?}", op); match op { - SerializedOperator::StartBlock { - ref params, - ref results, - .. - } => { - let ty = - self.create_type(params.iter().map(|&(ty, _)| ty).collect(), results.clone()); - self.wasm.operators.push(wasm_encoder::Instruction::Block( - BlockType::FunctionType(ty), - )); - } - SerializedOperator::StartLoop { - ref params, - ref results, - .. - } => { - let ty = - self.create_type(params.iter().map(|&(ty, _)| ty).collect(), results.clone()); + SerializedOperator::StartBlock { .. } => { self.wasm .operators - .push(wasm_encoder::Instruction::Loop(BlockType::FunctionType(ty))); + .push(wasm_encoder::Instruction::Block(BlockType::Empty)); + } + SerializedOperator::StartLoop { .. } => { + self.wasm + .operators + .push(wasm_encoder::Instruction::Loop(BlockType::Empty)); } SerializedOperator::End => { self.wasm.operators.push(wasm_encoder::Instruction::End); @@ -84,37 +47,29 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> { ref if_true, ref if_false, } => { - let fallthrough_ty = - self.find_fallthrough_ty(&[], [if_true, if_false].iter().map(|&targ| targ)); self.wasm .operators - .push(wasm_encoder::Instruction::If(BlockType::FunctionType( - fallthrough_ty, - ))); + .push(wasm_encoder::Instruction::If(BlockType::Empty)); self.translate_target(1, if_true, locations); self.wasm.operators.push(wasm_encoder::Instruction::Else); self.translate_target(1, if_false, locations); self.wasm.operators.push(wasm_encoder::Instruction::End); } SerializedOperator::BrTable { + ref index_ops, ref targets, ref default, } => { - let fallthrough_ty = self.find_fallthrough_ty( - &[Type::I32], - targets.iter().chain(std::iter::once(default)), - ); - self.wasm.operators.push(wasm_encoder::Instruction::Block( - wasm_encoder::BlockType::FunctionType(fallthrough_ty), - )); - let index_ty = self.create_type(vec![Type::I32], vec![]); - for _ in 0..(targets.len() + 1) { + for _ in 0..(targets.len() + 2) { self.wasm.operators.push(wasm_encoder::Instruction::Block( - wasm_encoder::BlockType::FunctionType(index_ty), + wasm_encoder::BlockType::Empty, )); } let br_table_targets = (1..=targets.len()).map(|i| i as u32).collect::>(); + for op in index_ops { + self.translate(op, locations); + } self.wasm.operators.push(wasm_encoder::Instruction::BrTable( Cow::Owned(br_table_targets), 0, @@ -158,7 +113,7 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> { ) { log::trace!("translate_target: {:?}", target); match target { - &SerializedBlockTarget::Fallthrough(_, ref ops) => { + &SerializedBlockTarget::Fallthrough(ref ops) => { for op in ops { self.translate(op, locations); } @@ -168,7 +123,7 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> { .push(wasm_encoder::Instruction::Br((extra_blocks - 1) as u32)); } } - &SerializedBlockTarget::Branch(branch, _, ref ops) => { + &SerializedBlockTarget::Branch(branch, ref ops) => { for op in ops { self.translate(op, locations); } @@ -180,12 +135,7 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> { } } -pub fn produce_func_wasm( - f: &FunctionBody, - body: &SerializedBody, - locations: &Locations, - ft: &mut FT, -) -> Wasm { +pub fn produce_func_wasm(f: &FunctionBody, body: &SerializedBody, locations: &Locations) -> Wasm { let mut wasm = Wasm { operators: vec![], locals: vec![], @@ -195,13 +145,14 @@ pub fn produce_func_wasm( wasm.locals .extend(locations.new_locals.iter().map(|ty| ty_to_valty(*ty))); - let mut ctx = WasmContext { - wasm: &mut wasm, - func_type_sink: ft, - }; + let mut ctx = WasmContext { wasm: &mut wasm }; for operator in &body.operators { ctx.translate(operator, locations); } + // There is always an explicit Return before this point. This + // allows us to avoid matching the return types in our stack + // discipline / outer block type. + wasm.operators.push(wasm_encoder::Instruction::Unreachable); wasm.operators.push(wasm_encoder::Instruction::End); wasm diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 35482fa..85c66ad 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -2,10 +2,6 @@ mod structured; pub use structured::*; -mod use_count; -pub use use_count::*; -mod schedule; -pub use schedule::*; mod serialize; pub use serialize::*; mod locations; diff --git a/src/backend/serialize.rs b/src/backend/serialize.rs index c940cab..bab2e16 100644 --- a/src/backend/serialize.rs +++ b/src/backend/serialize.rs @@ -3,16 +3,11 @@ //! in Wasm function body. Contains everything needed to emit Wasm //! except for value locations (and corresponding local spill/reloads). -use super::{ - structured::{BlockOrder, BlockOrderEntry}, - Schedule, UseCountAnalysis, -}; +use super::structured::{BlockOrder, BlockOrderEntry}; use crate::{ cfg::CFGInfo, op_traits::op_rematerialize, BlockId, FunctionBody, Operator, Terminator, Value, ValueDef, }; -use fxhash::FxHashSet; -use wasmparser::Type; /// A Wasm function body with a serialized sequence of operators that /// mirror Wasm opcodes in every way *except* for locals corresponding @@ -25,21 +20,17 @@ pub struct SerializedBody { #[derive(Clone, Debug, PartialEq, Eq)] pub enum SerializedBlockTarget { - Fallthrough(Vec, Vec), - Branch(usize, Vec, Vec), + Fallthrough(Vec), + Branch(usize, Vec), } #[derive(Clone, Debug, PartialEq, Eq)] pub enum SerializedOperator { StartBlock { header: BlockId, - params: Vec<(Type, Value)>, - results: Vec, }, StartLoop { header: BlockId, - params: Vec<(Type, Value)>, - results: Vec, }, Br(SerializedBlockTarget), BrIf { @@ -47,6 +38,7 @@ pub enum SerializedOperator { if_false: SerializedBlockTarget, }, BrTable { + index_ops: Vec, targets: Vec, default: SerializedBlockTarget, }, @@ -86,9 +78,13 @@ impl SerializedOperator { if_false.visit_value_locals(r, w); } &SerializedOperator::BrTable { + ref index_ops, ref default, ref targets, } => { + for index_op in index_ops { + index_op.visit_value_locals(r, w); + } default.visit_value_locals(r, w); for target in targets { target.visit_value_locals(r, w); @@ -100,12 +96,7 @@ impl SerializedOperator { &SerializedOperator::Set(v, i) | &SerializedOperator::Tee(v, i) => { w(v, i); } - &SerializedOperator::StartBlock { ref params, .. } - | &SerializedOperator::StartLoop { ref params, .. } => { - for &(_, value) in params { - w(value, 0); - } - } + &SerializedOperator::StartBlock { .. } | &SerializedOperator::StartLoop { .. } => {} &SerializedOperator::GetArg(..) | &SerializedOperator::Operator(..) | &SerializedOperator::End => {} @@ -120,8 +111,8 @@ impl SerializedBlockTarget { w: &mut W, ) { match self { - &SerializedBlockTarget::Branch(_, _, ref ops) - | &SerializedBlockTarget::Fallthrough(_, ref ops) => { + &SerializedBlockTarget::Branch(_, ref ops) + | &SerializedBlockTarget::Fallthrough(ref ops) => { for op in ops { op.visit_value_locals(r, w); } @@ -133,38 +124,21 @@ impl SerializedBlockTarget { struct SerializedBodyContext<'a> { f: &'a FunctionBody, cfg: &'a CFGInfo, - uses: &'a UseCountAnalysis, - schedule: &'a Schedule, operators: Vec, } impl SerializedBody { pub fn compute(f: &FunctionBody, cfg: &CFGInfo, order: &BlockOrder) -> SerializedBody { - let uses = UseCountAnalysis::compute(f); - let schedule = Schedule::compute(f, cfg, &uses); - if log::log_enabled!(log::Level::Trace) { log::trace!("values:"); for value in 0..f.values.len() { log::trace!(" * v{}: {:?}", value, f.values[value]); } - log::trace!("schedule:"); - for value in 0..schedule.location.len() { - log::trace!(" * v{}: {:?}", value, schedule.location[value]); - } for block in 0..f.blocks.len() { log::trace!("block{}:", block); - log::trace!( - " -> at top: {:?}", - schedule.compute_at_top_of_block.get(&block) - ); for &inst in &f.blocks[block].insts { - log::trace!(" -> toplevel: v{}", inst.index()); - log::trace!( - " -> after: {:?}", - schedule.compute_after_value.get(&inst) - ); + log::trace!(" -> v{}", inst.index()); } log::trace!(" -> terminator: {:?}", f.blocks[block].terminator); } @@ -173,8 +147,6 @@ impl SerializedBody { let mut ctx = SerializedBodyContext { f, cfg, - uses: &uses, - schedule: &schedule, operators: vec![], }; for entry in &order.entries { @@ -189,25 +161,18 @@ impl SerializedBody { impl<'a> SerializedBodyContext<'a> { fn compute_entry(&mut self, entry: &BlockOrderEntry) { match entry { - &BlockOrderEntry::StartBlock(header, ref params, ref results) - | &BlockOrderEntry::StartLoop(header, ref params, ref results) => { + &BlockOrderEntry::StartBlock(header) | &BlockOrderEntry::StartLoop(header) => { let is_loop = match entry { &BlockOrderEntry::StartLoop(..) => true, _ => false, }; if is_loop { - self.operators.push(SerializedOperator::StartLoop { - header, - params: params.clone(), - results: results.clone(), - }); + self.operators + .push(SerializedOperator::StartLoop { header }); } else { - self.operators.push(SerializedOperator::StartBlock { - header, - params: params.clone(), - results: results.clone(), - }); + self.operators + .push(SerializedOperator::StartBlock { header }); } } &BlockOrderEntry::End => { @@ -216,24 +181,12 @@ impl<'a> SerializedBodyContext<'a> { &BlockOrderEntry::BasicBlock(block, ref targets) => { log::trace!("BlockOrderEntry: block{}", block); - // Capture BlockParams. - for &(_, param) in self.f.blocks[block].params.iter().rev() { - self.operators.push(SerializedOperator::Set(param, 0)); - } - - // Schedule ops. First handle the compute-at-top ones. - if let Some(compute_at_top) = self.schedule.compute_at_top_of_block.get(&block) { - self.schedule_ops(None, &compute_at_top[..]); - } - - // Next schedule all toplevels, and values ready to - // schedule after each one. + // Compute insts' values in sequence. for &inst in &self.f.blocks[block].insts { - if let Some(after) = self.schedule.compute_after_value.get(&inst) { - self.schedule_ops(Some(inst), &after[..]); - } else { - self.schedule_ops(Some(inst), &[]); - } + let mut rev_ops = vec![]; + self.emit_inst(inst, &mut rev_ops); + rev_ops.reverse(); + self.operators.extend(rev_ops); } // For each BlockOrderTarget, compute a SerializedBlockTarget. @@ -241,21 +194,26 @@ impl<'a> SerializedBodyContext<'a> { .iter() .map(|target| { log::trace!("target: {:?}", target); + let mut rev_ops = vec![]; + + // Store into block param values. + for &(_, value) in &self.f.blocks[target.target].params { + rev_ops.push(SerializedOperator::Set(value, 0)); + } + + // Load from branch operator's args. for &value in target.args.iter().rev() { let value = self.f.resolve_alias(value); self.push_value(value, &mut rev_ops); } + rev_ops.reverse(); - let tys: Vec = self.f.blocks[target.target] - .params - .iter() - .map(|&(ty, _)| ty) - .collect(); log::trace!(" -> ops: {:?}", rev_ops); + match target.relative_branch { - Some(branch) => SerializedBlockTarget::Branch(branch, tys, rev_ops), - None => SerializedBlockTarget::Fallthrough(tys, rev_ops), + Some(branch) => SerializedBlockTarget::Branch(branch, rev_ops), + None => SerializedBlockTarget::Fallthrough(rev_ops), } }) .collect::>(); @@ -286,9 +244,11 @@ impl<'a> SerializedBodyContext<'a> { let value = self.f.resolve_alias(value); self.push_value(value, &mut rev_ops); rev_ops.reverse(); - self.operators.extend(rev_ops); - self.operators - .push(SerializedOperator::BrTable { targets, default }); + self.operators.push(SerializedOperator::BrTable { + index_ops: rev_ops, + targets, + default, + }); } &Terminator::Return { ref values, .. } => { let mut rev_ops = vec![]; @@ -308,44 +268,8 @@ impl<'a> SerializedBodyContext<'a> { } } } - - fn schedule_ops(&mut self, toplevel: Option, values: &[Value]) { - log::trace!("schedule_ops: toplevel {:?} values {:?}", toplevel, values); - // Work backward, generating values in the appropriate order - // on the stack if single-use. - let mut rev_ops = vec![]; - let mut to_compute = values - .iter() - .chain(toplevel.iter()) - .cloned() - .collect::>(); - for &value in values.iter().rev() { - self.schedule_op( - value, - &mut rev_ops, - /* leave_value_on_stack = */ false, - &mut to_compute, - ); - } - if let Some(toplevel) = toplevel { - self.schedule_op( - toplevel, - &mut rev_ops, - /* leave_value_on_stack = */ false, - &mut to_compute, - ); - } - rev_ops.reverse(); - log::trace!( - "schedule_ops: toplevel {:?} values {:?} -> ops {:?}", - toplevel, - values, - rev_ops - ); - self.operators.extend(rev_ops.into_iter()); - } - fn push_value(&mut self, v: Value, rev_ops: &mut Vec) { + let v = self.f.resolve_alias(v); match &self.f.values[v.index()] { &ValueDef::PickOutput(v, i) => { rev_ops.push(SerializedOperator::Get(v, i)); @@ -362,22 +286,8 @@ impl<'a> SerializedBodyContext<'a> { } } - fn schedule_op( - &mut self, - op: Value, - rev_ops: &mut Vec, - leave_value_on_stack: bool, - to_compute: &mut FxHashSet, - ) { - let op = self.f.resolve_alias(op); - if !to_compute.remove(&op) { - if leave_value_on_stack { - self.push_value(op, rev_ops); - } - return; - } - - let (operator, operands) = match &self.f.values[op.index()] { + fn emit_inst(&mut self, inst: Value, rev_ops: &mut Vec) { + let (operator, operands) = match &self.f.values[inst.index()] { &ValueDef::Operator(op, ref operands) => (op, operands), _ => { return; @@ -386,15 +296,8 @@ impl<'a> SerializedBodyContext<'a> { // We're generating ops in reverse order. So we must first // store value. - for i in 0..self.f.types[op.index()].len() { - if !leave_value_on_stack { - rev_ops.push(SerializedOperator::Set(op, i)); - } else { - assert_eq!(i, 0); - if self.uses.use_count[op.index()] > 1 { - rev_ops.push(SerializedOperator::Tee(op, i)); - } - } + for i in 0..self.f.types[inst.index()].len() { + rev_ops.push(SerializedOperator::Set(inst, i)); } rev_ops.push(SerializedOperator::Operator(operator)); @@ -402,24 +305,7 @@ impl<'a> SerializedBodyContext<'a> { // Now push the args in reverse order. for &arg in operands.iter().rev() { let arg = self.f.resolve_alias(arg); - match &self.f.values[arg.index()] { - &ValueDef::Operator(op, ..) => { - if op_rematerialize(&op) { - rev_ops.push(SerializedOperator::Operator(op)); - } else if self.uses.use_count[arg.index()] == 1 - && self.f.types[arg.index()].len() == 1 - { - self.schedule_op( - arg, rev_ops, /* leave_on_stack = */ true, to_compute, - ); - } else { - self.push_value(arg, rev_ops); - } - } - _ => { - self.push_value(arg, rev_ops); - } - } + self.push_value(arg, rev_ops); } } } diff --git a/src/backend/structured.rs b/src/backend/structured.rs index d252c41..ebbd4d6 100644 --- a/src/backend/structured.rs +++ b/src/backend/structured.rs @@ -284,16 +284,8 @@ pub struct BlockOrder { #[derive(Clone, Debug)] pub enum BlockOrderEntry { - StartBlock( - BlockId, - Vec<(wasmparser::Type, Value)>, - Vec, - ), - StartLoop( - BlockId, - Vec<(wasmparser::Type, Value)>, - Vec, - ), + StartBlock(BlockId), + StartLoop(BlockId), End, BasicBlock(BlockId, Vec), } @@ -310,15 +302,7 @@ impl BlockOrder { pub fn compute(f: &FunctionBody, cfg: &CFGInfo, wasm_region: &WasmRegion) -> BlockOrder { let mut target_stack = vec![]; let mut entries = vec![]; - Self::generate_region( - f, - cfg, - &mut target_stack, - &mut entries, - wasm_region, - None, - true, - ); + Self::generate_region(f, cfg, &mut target_stack, &mut entries, wasm_region, None); log::trace!("entries: {:?}", entries); BlockOrder { entries } } @@ -330,7 +314,6 @@ impl BlockOrder { entries: &mut Vec, region: &WasmRegion, fallthrough: Option, - toplevel: bool, ) { log::trace!( "BlockOrder::generate_region: stack {:?} region {:?} fallthrough {:?}", @@ -353,23 +336,11 @@ impl BlockOrder { if let Some(target) = target { target_stack.push(target); } - let params = f.blocks[header].params.clone(); - let results = if toplevel { - f.rets.clone() - } else { - match fallthrough { - Some(fallthrough) => f.blocks[fallthrough] - .params - .iter() - .map(|(ty, _)| *ty) - .collect(), - None => vec![], - } - }; + if is_loop { - entries.push(BlockOrderEntry::StartLoop(header, params, results)); + entries.push(BlockOrderEntry::StartLoop(header)); } else { - entries.push(BlockOrderEntry::StartBlock(header, params, results)); + entries.push(BlockOrderEntry::StartBlock(header)); } for i in 0..subregions.len() { @@ -379,15 +350,7 @@ impl BlockOrder { } else { Some(subregions[i + 1].header()) }; - Self::generate_region( - f, - cfg, - target_stack, - entries, - subregion, - fallthrough, - false, - ); + Self::generate_region(f, cfg, target_stack, entries, subregion, fallthrough); } entries.push(BlockOrderEntry::End); diff --git a/src/frontend.rs b/src/frontend.rs index 574eff9..1d23678 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -5,7 +5,7 @@ use std::convert::TryFrom; use crate::ir::*; -use crate::op_traits::{op_effects, op_inputs, op_outputs}; +use crate::op_traits::{op_inputs, op_outputs}; use crate::ops::Operator; use anyhow::{bail, Result}; use fxhash::{FxHashMap, FxHashSet}; @@ -1181,21 +1181,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { log::trace!(" -> operands: {:?}", input_operands); log::trace!(" -> ty {:?}", outputs); - let side_effects = !op_effects(&op).unwrap().is_empty(); - - let value = if side_effects { - self.body - .add_mutable_inst(outputs.clone(), ValueDef::Operator(op, input_operands)) - } else { - self.body - .add_value(ValueDef::Operator(op, input_operands), outputs.clone()) - }; + let value = self + .body + .add_value(ValueDef::Operator(op, input_operands), outputs.clone()); log::trace!(" -> value: {:?}", value); if let Some(block) = self.cur_block { - if side_effects { - self.body.blocks[block].insts.push(value); - } + self.body.blocks[block].insts.push(value); } if n_outputs == 1 { diff --git a/src/ir.rs b/src/ir.rs index af68d1b..2fabbe7 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -1,19 +1,14 @@ //! Intermediate representation for Wasm. use crate::{ - backend::{ - produce_func_wasm, BlockOrder, FuncTypeSink, Locations, LoopNest, SerializedBody, - WasmRegion, - }, + backend::{produce_func_wasm, BlockOrder, Locations, LoopNest, SerializedBody, WasmRegion}, cfg::CFGInfo, frontend, ops::ty_to_valty, Operator, }; use anyhow::Result; -use fxhash::FxHashMap; use rayon::prelude::*; -use std::collections::hash_map::Entry; use wasmparser::{FuncType, SectionReader, Type}; pub type SignatureId = usize; @@ -57,9 +52,7 @@ pub struct FunctionBody { pub rets: Vec, pub locals: Vec, pub blocks: Vec, - /// Sea-of-nodes representation. pub values: Vec, - value_dedup: FxHashMap, /// A single value can have multiple types if multi-value (e.g. a /// call). pub types: Vec>, @@ -86,17 +79,10 @@ impl FunctionBody { pub fn add_value(&mut self, value: ValueDef, tys: Vec) -> Value { log::trace!("add_value: def {:?} ty {:?}", value, tys); - let id = match self.value_dedup.entry(value.clone()) { - Entry::Occupied(o) => *o.get(), - Entry::Vacant(v) => { - let id = Value(self.values.len() as u32); - self.values.push(value.clone()); - self.types.push(tys); - v.insert(id); - id - } - }; + let id = Value(self.values.len() as u32); log::trace!(" -> value {:?}", id); + self.values.push(value.clone()); + self.types.push(tys); id } @@ -480,10 +466,10 @@ impl<'a> Module<'a> { pub fn to_wasm_bytes(&self) -> Vec { // Do most of the compilation in parallel: up to the - // serialized (pre-regalloc) body and the regalloc - // results. Only the "final parts assembly" needs to be - // serialized because it can add function signatures. - let compiled: Vec<(u32, &FunctionBody, SerializedBody, Locations)> = self + // generation of the function that we emit into the final code + // seciton in order. Only the "final parts assembly" needs to + // be serialized. + let compiled: Vec<(u32, wasm_encoder::Function)> = self .funcs .par_iter() .filter_map(|func| match func { @@ -496,41 +482,40 @@ impl<'a> Module<'a> { log::trace!("serialized: {:?}", serialized); let locations = Locations::compute(body, &serialized); log::trace!("locations: {:?}", locations); - Some((sig as u32, body, serialized, locations)) + let func_body = produce_func_wasm(body, &serialized, &locations); + log::trace!("body: {:?}", func_body); + + let mut locals: Vec<(u32, wasm_encoder::ValType)> = vec![]; + for local_ty in func_body.locals { + if locals.len() > 0 && locals.last().unwrap().1 == local_ty { + locals.last_mut().unwrap().0 += 1; + } else { + locals.push((1, local_ty)); + } + } + let mut func = wasm_encoder::Function::new(locals); + + for inst in func_body.operators { + func.instruction(&inst); + } + + Some((sig as u32, func)) } _ => None, }) .collect(); // Build the final code section and function-type section. - let mut signatures = SignatureAdder::new(&self); let mut code_section = wasm_encoder::CodeSection::new(); let mut func_section = wasm_encoder::FunctionSection::new(); - for (sig, body, serialized, locations) in compiled { - let func_body = produce_func_wasm(body, &serialized, &locations, &mut signatures); - log::trace!("body: {:?}", func_body); - - let mut locals: Vec<(u32, wasm_encoder::ValType)> = vec![]; - for local_ty in func_body.locals { - if locals.len() > 0 && locals.last().unwrap().1 == local_ty { - locals.last_mut().unwrap().0 += 1; - } else { - locals.push((1, local_ty)); - } - } - let mut func = wasm_encoder::Function::new(locals); - - for inst in func_body.operators { - func.instruction(&inst); - } - - func_section.function(sig); + for (sig, func) in compiled { + func_section.function(sig as u32); code_section.function(&func); } // Build the final function-signature (type) section. let mut type_section = wasm_encoder::TypeSection::new(); - for sig in &signatures.signatures { + for sig in &self.signatures { let params: Vec = sig.params.iter().map(|&ty| ty_to_valty(ty)).collect(); let returns: Vec = @@ -612,41 +597,3 @@ impl<'a> Module<'a> { module.finish() } } - -struct SignatureAdder { - signatures: Vec, - signature_dedup: FxHashMap, -} - -impl SignatureAdder { - fn new(module: &Module<'_>) -> Self { - let signature_dedup: FxHashMap = module - .signatures - .iter() - .enumerate() - .map(|(idx, sig)| (sig.clone(), idx as u32)) - .collect(); - - Self { - signatures: module.signatures.clone(), - signature_dedup, - } - } -} - -impl FuncTypeSink for SignatureAdder { - fn add_signature(&mut self, params: Vec, results: Vec) -> u32 { - let ft = wasmparser::FuncType { - params: params.into_boxed_slice(), - returns: results.into_boxed_slice(), - }; - match self.signature_dedup.entry(ft.clone()) { - Entry::Occupied(o) => *o.get(), - Entry::Vacant(v) => { - let idx = self.signatures.len() as u32; - self.signatures.push(ft); - *v.insert(idx) - } - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 986e5a6..0791c12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ mod frontend; mod ir; mod op_traits; mod ops; +mod use_count; pub use ir::*; pub use ops::Operator; diff --git a/src/backend/use_count.rs b/src/use_count.rs similarity index 99% rename from src/backend/use_count.rs rename to src/use_count.rs index 710acc5..c6e04a7 100644 --- a/src/backend/use_count.rs +++ b/src/use_count.rs @@ -1,9 +1,8 @@ //! Use-count analysis. -use std::collections::VecDeque; - use crate::{FunctionBody, Value, ValueDef}; use fxhash::FxHashSet; +use std::collections::VecDeque; #[derive(Clone, Debug)] pub struct UseCountAnalysis {