1
1
use std:: { cell:: Cell , collections:: HashMap } ;
2
2
3
- use itertools:: Itertools ;
4
3
use wasmparser:: Operator ;
5
4
6
5
use crate :: loader:: {
@@ -12,23 +11,25 @@ use crate::loader::{
12
11
/// This is an optional optimization pass that collapses constants into
13
12
/// the node that uses them, if the ISA supports it.
14
13
///
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 .
18
17
///
19
18
/// This pass only happens if `Settings::get_const_collapse_processor()` is
20
19
/// implemented by the user.
21
20
///
22
21
/// Returns the number of constants collapsed.
23
22
pub fn constant_collapse < ' a , S : Settings < ' a > > ( settings : & S , dag : & mut Dag ) -> usize {
24
23
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 ( ) )
26
26
} else {
27
27
0
28
28
}
29
29
}
30
30
31
31
fn recursive_constant_collapse (
32
+ finder : & mut ConstantInputFinder ,
32
33
processor : & impl Fn ( & Operator , & [ MaybeConstant ] ) ,
33
34
nodes : & mut [ dag:: Node ] ,
34
35
const_block_inputs : HashMap < u32 , WasmValue > ,
@@ -43,23 +44,24 @@ fn recursive_constant_collapse(
43
44
44
45
match & mut node. operation {
45
46
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
+ ) ;
48
52
if has_constant {
49
53
// Call the user-provided processor to potentially modify the input constants.
50
- processor ( operator, & input_constants) ;
54
+ processor ( operator, input_constants) ;
51
55
52
56
// 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) {
56
58
if let MaybeConstant :: ReferenceConstant {
57
59
value,
58
60
must_collapse,
59
61
} = maybe_const
60
62
&& must_collapse. get ( )
61
63
{
62
- * input = NodeInput :: Constant ( value) ;
64
+ * input = NodeInput :: Constant ( value. clone ( ) ) ;
63
65
num_collapsed += 1 ;
64
66
}
65
67
}
@@ -72,27 +74,34 @@ fn recursive_constant_collapse(
72
74
// In order to collapse constants that come from the block inputs,
73
75
// we need to know which block inputs are constants.
74
76
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 ( ) )
76
79
. 1
77
- . into_iter ( )
80
+ . iter ( )
78
81
. enumerate ( )
79
82
. filter_map ( |( idx, maybe_const) | match maybe_const {
80
83
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 ( ) ) )
82
88
}
83
- MaybeConstant :: CollapsedConstant ( value) => Some ( ( idx as u32 , value) ) ,
84
89
MaybeConstant :: NonConstant => None ,
85
90
} )
86
91
. collect ( )
87
92
} else {
88
93
// 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.
91
96
HashMap :: new ( )
92
97
} ;
93
98
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
+ ) ;
96
105
}
97
106
_ => {
98
107
// Constant collapse is not supported for other node types.
@@ -103,17 +112,28 @@ fn recursive_constant_collapse(
103
112
num_collapsed
104
113
}
105
114
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
+ }
112
119
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| {
117
137
let origin = match input {
118
138
NodeInput :: Reference ( value_origin) => value_origin,
119
139
NodeInput :: Constant ( wasm_value) => {
@@ -138,8 +158,8 @@ fn find_constant_inputs(
138
158
must_collapse : Cell :: new ( false ) ,
139
159
}
140
160
} )
141
- } )
142
- . collect_vec ( ) ;
161
+ } ) ) ;
143
162
144
- ( has_constant, input_constants)
163
+ ( has_constant, & mut self . buffer )
164
+ }
145
165
}
0 commit comments