Skip to content

Commit db86da5

Browse files
committed
Reusing the same vector for all the nodes.
1 parent dded0ad commit db86da5

File tree

1 file changed

+53
-33
lines changed

1 file changed

+53
-33
lines changed

src/loader/dag/const_collapse.rs

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{cell::Cell, collections::HashMap};
22

3-
use itertools::Itertools;
43
use wasmparser::Operator;
54

65
use crate::loader::{
@@ -12,23 +11,25 @@ use crate::loader::{
1211
/// This is an optional optimization pass that collapses constants into
1312
/// the node that uses them, if the ISA supports it.
1413
///
15-
/// For example, an `i32.add` instruction that takes a constant
16-
/// `5` as input could be collapsed into an `i32.add_imm` instruction
17-
/// that takes `5` as an immediate operand.
14+
/// For example, if the output ISA is RISC-V, in an `i32.add` instruction that
15+
/// has a constant node `5` as input, the value `5` could be collapsed into an
16+
/// immediate for `addi` instruction.
1817
///
1918
/// This pass only happens if `Settings::get_const_collapse_processor()` is
2019
/// implemented by the user.
2120
///
2221
/// Returns the number of constants collapsed.
2322
pub fn constant_collapse<'a, S: Settings<'a>>(settings: &S, dag: &mut Dag) -> usize {
2423
if let Some(processor) = settings.get_const_collapse_processor() {
25-
recursive_constant_collapse(&processor, &mut dag.nodes, HashMap::new())
24+
let mut finder = ConstantInputFinder::new();
25+
recursive_constant_collapse(&mut finder, &processor, &mut dag.nodes, HashMap::new())
2626
} else {
2727
0
2828
}
2929
}
3030

3131
fn recursive_constant_collapse(
32+
finder: &mut ConstantInputFinder,
3233
processor: &impl Fn(&Operator, &[MaybeConstant]),
3334
nodes: &mut [dag::Node],
3435
const_block_inputs: HashMap<u32, WasmValue>,
@@ -43,23 +44,24 @@ fn recursive_constant_collapse(
4344

4445
match &mut node.operation {
4546
dag::Operation::WASMOp(operator) => {
46-
let (has_constant, input_constants) =
47-
find_constant_inputs(&node.inputs, prev_nodes, const_block_inputs.clone());
47+
let (has_constant, input_constants) = finder.find_constant_inputs(
48+
&node.inputs,
49+
prev_nodes,
50+
const_block_inputs.clone(),
51+
);
4852
if has_constant {
4953
// Call the user-provided processor to potentially modify the input constants.
50-
processor(operator, &input_constants);
54+
processor(operator, input_constants);
5155

5256
// Collapse any inputs that were marked for collapsing.
53-
for (input, maybe_const) in
54-
node.inputs.iter_mut().zip(input_constants.into_iter())
55-
{
57+
for (input, maybe_const) in node.inputs.iter_mut().zip(input_constants) {
5658
if let MaybeConstant::ReferenceConstant {
5759
value,
5860
must_collapse,
5961
} = maybe_const
6062
&& must_collapse.get()
6163
{
62-
*input = NodeInput::Constant(value);
64+
*input = NodeInput::Constant(value.clone());
6365
num_collapsed += 1;
6466
}
6567
}
@@ -72,27 +74,34 @@ fn recursive_constant_collapse(
7274
// In order to collapse constants that come from the block inputs,
7375
// we need to know which block inputs are constants.
7476
let const_inputs = if matches!(kind, BlockKind::Block) {
75-
find_constant_inputs(&node.inputs, prev_nodes, const_block_inputs.clone())
77+
finder
78+
.find_constant_inputs(&node.inputs, prev_nodes, const_block_inputs.clone())
7679
.1
77-
.into_iter()
80+
.iter()
7881
.enumerate()
7982
.filter_map(|(idx, maybe_const)| match maybe_const {
8083
MaybeConstant::ReferenceConstant { value, .. } => {
81-
Some((idx as u32, value))
84+
Some((idx as u32, value.clone()))
85+
}
86+
MaybeConstant::CollapsedConstant(value) => {
87+
Some((idx as u32, value.clone()))
8288
}
83-
MaybeConstant::CollapsedConstant(value) => Some((idx as u32, value)),
8489
MaybeConstant::NonConstant => None,
8590
})
8691
.collect()
8792
} else {
8893
// Loops have multiple entry points, so we can't be sure a constant input
89-
// is always constant. Besides, an optimized WASM wouldn't have constant
90-
// inputs to loops anyway.
94+
// at entry will be always constant. Besides, an optimized WASM wouldn't
95+
// have constant inputs to loops anyway.
9196
HashMap::new()
9297
};
9398

94-
num_collapsed +=
95-
recursive_constant_collapse(processor, &mut sub_dag.nodes, const_inputs);
99+
num_collapsed += recursive_constant_collapse(
100+
finder,
101+
processor,
102+
&mut sub_dag.nodes,
103+
const_inputs,
104+
);
96105
}
97106
_ => {
98107
// Constant collapse is not supported for other node types.
@@ -103,17 +112,28 @@ fn recursive_constant_collapse(
103112
num_collapsed
104113
}
105114

106-
fn find_constant_inputs(
107-
inputs: &[NodeInput],
108-
nodes: &mut [dag::Node],
109-
const_block_inputs: HashMap<u32, WasmValue>,
110-
) -> (bool, Vec<MaybeConstant>) {
111-
let mut has_constant = false;
115+
struct ConstantInputFinder {
116+
/// This buffer will be reused to avoid allocations on each node.
117+
buffer: Vec<MaybeConstant>,
118+
}
112119

113-
// Check if any of the inputs are constants.
114-
let input_constants = inputs
115-
.iter()
116-
.map(|input| {
120+
impl ConstantInputFinder {
121+
fn new() -> Self {
122+
Self { buffer: Vec::new() }
123+
}
124+
125+
/// Finds which of the given inputs are constants.
126+
fn find_constant_inputs<'a>(
127+
&'a mut self,
128+
inputs: &[NodeInput],
129+
nodes: &mut [dag::Node],
130+
const_block_inputs: HashMap<u32, WasmValue>,
131+
) -> (bool, &'a mut [MaybeConstant]) {
132+
let mut has_constant = false;
133+
134+
// Check if any of the inputs are constants.
135+
self.buffer.clear();
136+
self.buffer.extend(inputs.iter().map(|input| {
117137
let origin = match input {
118138
NodeInput::Reference(value_origin) => value_origin,
119139
NodeInput::Constant(wasm_value) => {
@@ -138,8 +158,8 @@ fn find_constant_inputs(
138158
must_collapse: Cell::new(false),
139159
}
140160
})
141-
})
142-
.collect_vec();
161+
}));
143162

144-
(has_constant, input_constants)
163+
(has_constant, &mut self.buffer)
164+
}
145165
}

0 commit comments

Comments
 (0)