wasm_opt/api.rs
1pub use crate::features::Feature;
2pub use crate::passes::Pass;
3use crate::profiles::Profile;
4use std::collections::{HashMap, HashSet};
5
6/// Optimization options and optimization builder.
7///
8/// This type declares all supported Binaryen options.
9/// It can be modified directly or by its [builder-pattern] methods.
10///
11/// Call [`OptimizationOptions::run`] to perform the optimizations.
12///
13/// [builder-pattern]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html
14#[derive(Clone, Debug)]
15pub struct OptimizationOptions {
16 /// Options for reading the unoptimized wasm module.
17 pub reader: ReaderOptions,
18 /// Options for writing the optimized wasm module.
19 pub writer: WriterOptions,
20 /// Options related to inlining.
21 pub inlining: InliningOptions,
22 /// Options that affect how optimization passes behave.
23 pub passopts: PassOptions,
24 /// The set of optimization passes to apply.
25 pub passes: Passes,
26 /// The set of wasm-features.
27 pub features: Features,
28 /// Run passes to convergence, continuing while binary size decreases.
29 pub converge: bool,
30}
31
32/// Options for reading the unoptimized wasm module.
33#[derive(Copy, Clone, Debug)]
34pub struct ReaderOptions {
35 /// The module format: wasm, wat, or either.
36 ///
37 /// The default value is [`FileType::Any`].
38 ///
39 /// When this is `FileType::Any` the first bytes
40 /// of the module will be inspected to determine whether
41 /// the module is in binary or text format,
42 /// then read as appropriate.
43 pub file_type: FileType,
44}
45
46/// Options for writing the optimized wasm module.
47#[derive(Clone, Debug)]
48pub struct WriterOptions {
49 /// The module format: wasm, wat, or either.
50 ///
51 /// The default value is [`FileType::Wasm`].
52 ///
53 /// Note that when this is [`FileType::Any`] the following logic applies:
54 ///
55 /// If [`ReaderOptions::file_type`] is [`FileType::Wat`],
56 /// write a wat file, otherwise write a wasm file.
57 pub file_type: FileType,
58}
59
60/// Module format used by [`ReaderOptions`] and [`WriterOptions`].
61#[derive(Copy, Clone, Debug)]
62pub enum FileType {
63 /// A binary wasm module.
64 Wasm,
65 /// A text wasm module in wat format.
66 Wat,
67 /// Either a binary or text module.
68 ///
69 /// See the documentation for [`ReaderOptions`] and [`WriterOptions`]
70 /// for an explanation of how this is interpreted.
71 Any,
72}
73
74/// Options related to inlining.
75#[derive(Copy, Clone, Debug)]
76pub struct InliningOptions {
77 /// Function size at which we always inline.
78 ///
79 /// Default: `2`.
80 pub always_inline_max_size: u32,
81 /// Function size which we inline when there is only one caller.
82 ///
83 /// Default: `u32::MAX`.
84 pub one_caller_inline_max_size: u32,
85 /// Function size above which we generally never inline.
86 ///
87 /// Default: `20`.
88 pub flexible_inline_max_size: u32,
89 /// Functions with loops are usually not inlined.
90 ///
91 /// Default: `false`.
92 pub allow_functions_with_loops: bool,
93 /// The number of `if`s to allow partial inlining of their conditions.
94 ///
95 /// Default: `0`.
96 pub partial_inlining_ifs: u32,
97}
98
99/// Options that affect how optimization passes behave.
100///
101/// The Binaryen source code has more extensive documentation of these options
102/// than is reproduced here.
103#[derive(Clone, Debug)]
104pub struct PassOptions {
105 /// Validate both the unoptimized module and the optimized module.
106 ///
107 /// Default: `true`.
108 pub validate: bool,
109 /// Validate globally, not just locally.
110 ///
111 /// Default: `true`.
112 pub validate_globally: bool,
113 /// The amount of optimization to apply.
114 ///
115 /// The default depends on how [`OptimizationOptions`] is constructed.
116 pub optimize_level: OptimizeLevel,
117 /// The amount of effort to put into reducing module size.
118 ///
119 /// The default depends on how [`OptimizationOptions`] is constructed.
120 pub shrink_level: ShrinkLevel,
121 /// Assume traps never happen at runtime.
122 ///
123 /// Default: `false`.
124 pub traps_never_happen: bool,
125 /// Assume that the low 1K of memory is not valid for application use.
126 ///
127 /// Default: `false`.
128 pub low_memory_unused: bool,
129 /// Do faster floating point math by breaking official IEEE semantics.
130 ///
131 /// Default: `false`.
132 pub fast_math: bool,
133 /// Assume imported memory is zeroed.
134 ///
135 /// Default: `false`.
136 pub zero_filled_memory: bool,
137 /// Preserve debug info.
138 ///
139 /// Default: `false`.
140 pub debug_info: bool,
141 /// Additional pass-specific arguments.
142 pub arguments: HashMap<String, String>,
143}
144
145/// The amount of optimization to apply.
146///
147/// This is interpreted differently by different passes.
148///
149/// See the documentation of various [`OptimizationOptions`]
150/// constructors for a general description of how these behave.
151#[derive(Copy, Clone, Debug, Eq, PartialEq)]
152pub enum OptimizeLevel {
153 Level0 = 0,
154 Level1 = 1,
155 Level2 = 2,
156 Level3 = 3,
157 Level4 = 4,
158}
159
160/// The amount of effort to put into reducing module size.
161///
162/// This is interpreted differently by different passes.
163///
164/// See the documentation of various [`OptimizationOptions`]
165/// constructors for a general description of how these behave.
166#[derive(Copy, Clone, Debug, Eq, PartialEq)]
167pub enum ShrinkLevel {
168 Level0 = 0,
169 Level1 = 1,
170 Level2 = 2,
171}
172
173/// The set of optimization passes to apply.
174#[derive(Clone, Debug)]
175pub struct Passes {
176 /// Apply the default set of optimization passes.
177 pub add_default_passes: bool,
178 /// Additional passes to apply.
179 pub more_passes: Vec<Pass>,
180}
181
182/// Which wasm [`Feature`]s to enable and disable.
183///
184/// The baseline features are applied first, then
185/// enabled and disabled features are applied.
186#[derive(Clone, Debug, Default)]
187pub struct Features {
188 pub baseline: FeatureBaseline,
189 pub enabled: HashSet<Feature>,
190 pub disabled: HashSet<Feature>,
191}
192
193/// The set of features to apply before applying custom features.
194#[derive(Clone, Debug)]
195pub enum FeatureBaseline {
196 /// The default Binaryen feature set.
197 ///
198 /// Enables [`Feature::Default`].
199 /// Disables [`Feature::None`].
200 Default,
201 /// Only allow WebAssembly MVP features.
202 ///
203 /// Enables [`Feature::Mvp`].
204 /// Disables [`Feature::All`].
205 MvpOnly,
206 /// Allow all features.
207 ///
208 /// Enables [`Feature::All`].
209 /// Disables [Feature::Mvp`].
210 All,
211}
212
213/// Constructors.
214impl OptimizationOptions {
215 pub(crate) fn new_empty() -> Self {
216 OptimizationOptions {
217 reader: ReaderOptions::default(),
218 writer: WriterOptions::default(),
219 inlining: InliningOptions::default(),
220 passopts: PassOptions::default(),
221 passes: Passes::default(),
222 features: Features::default(),
223 converge: false,
224 }
225 }
226
227 /// Optimize for size.
228 ///
229 /// This corresponds to the `-Os` argument to `wasm-opt`,
230 /// and also the `-O` argument to `wasm-opt`.
231 ///
232 /// It applies
233 /// - [`Passes::add_default_passes`],
234 /// - [`OptimizeLevel::Level2`],
235 /// - [`ShrinkLevel::Level1`].
236 pub fn new_optimize_for_size() -> Self {
237 Profile::optimize_for_size().into_opts()
238 }
239
240 /// Optimize for size, but even more.
241 ///
242 /// It applies
243 /// - [`Passes::add_default_passes`],
244 /// - [`OptimizeLevel::Level2`],
245 /// - [`ShrinkLevel::Level2`].
246 ///
247 /// This corresponds to the `-Oz` argument to `wasm-opt`.
248 pub fn new_optimize_for_size_aggressively() -> Self {
249 Profile::optimize_for_size_aggressively().into_opts()
250 }
251
252 /// Do not optimize.
253 ///
254 /// It applies
255 /// - [`OptimizeLevel::Level0`],
256 /// - [`ShrinkLevel::Level0`].
257 ///
258 /// It adds no default passes.
259 ///
260 /// This corresponds to the `-O0` argument to `wasm-opt`,
261 /// and also to calling `wasm-opt` with no `-O*` optional at all.
262 pub fn new_opt_level_0() -> Self {
263 Profile::opt_level_0().into_opts()
264 }
265
266 /// Apply basic optimizations.
267 ///
268 /// Useful for fast iteration.
269 ///
270 /// It applies
271 /// - [`Passes::add_default_passes`],
272 /// - [`OptimizeLevel::Level1`],
273 /// - [`ShrinkLevel::Level0`].
274 ///
275 /// This corresponds to the `-O1` argument to `wasm-opt`.
276 pub fn new_opt_level_1() -> Self {
277 Profile::opt_level_1().into_opts()
278 }
279
280 /// Apply most optimizations.
281 ///
282 /// This level of optimization is appropriate for most applications.
283 /// Higher optimization levels will not necessarily yield better performance,
284 /// but will take longer to optimize.
285 ///
286 /// It applies
287 /// - [`Passes::add_default_passes`],
288 /// - [`OptimizeLevel::Level2`],
289 /// - [`ShrinkLevel::Level0`].
290 ///
291 /// This corresponds to the `-O2` argument to `wasm-opt`.
292 pub fn new_opt_level_2() -> Self {
293 Profile::opt_level_2().into_opts()
294 }
295
296 /// Apply slower optimizations.
297 ///
298 /// Spends potentially a lot of time on optimizations.
299 ///
300 /// It applies
301 /// - [`Passes::add_default_passes`],
302 /// - [`OptimizeLevel::Level3`],
303 /// - [`ShrinkLevel::Level0`].
304 ///
305 /// This corresponds to the `-O3` argument to `wasm-opt`.
306 pub fn new_opt_level_3() -> Self {
307 Profile::opt_level_3().into_opts()
308 }
309
310 /// Apply the most aggressive optimizations.
311 ///
312 /// Flattens the IR, which can take a lot of time and memory,
313 /// but may be useful on nested / complex / less-optimized input.
314 ///
315 /// It applies
316 /// - [`Passes::add_default_passes`],
317 /// - [`OptimizeLevel::Level4`],
318 /// - [`ShrinkLevel::Level0`].
319 ///
320 /// This corresponds to the `-O4` argument to `wasm-opt`.
321 pub fn new_opt_level_4() -> Self {
322 Profile::opt_level_4().into_opts()
323 }
324}
325
326impl Default for ReaderOptions {
327 fn default() -> ReaderOptions {
328 ReaderOptions {
329 file_type: FileType::Any,
330 }
331 }
332}
333
334impl Default for WriterOptions {
335 fn default() -> WriterOptions {
336 WriterOptions {
337 file_type: FileType::Wasm,
338 }
339 }
340}
341
342impl Default for InliningOptions {
343 fn default() -> InliningOptions {
344 InliningOptions {
345 always_inline_max_size: 2,
346 one_caller_inline_max_size: u32::MAX,
347 flexible_inline_max_size: 20,
348 allow_functions_with_loops: false,
349 partial_inlining_ifs: 0,
350 }
351 }
352}
353
354impl Default for PassOptions {
355 fn default() -> PassOptions {
356 PassOptions {
357 validate: true,
358 validate_globally: true,
359 optimize_level: OptimizeLevel::default(),
360 shrink_level: ShrinkLevel::default(),
361 traps_never_happen: false,
362 low_memory_unused: false,
363 fast_math: false,
364 zero_filled_memory: false,
365 debug_info: false,
366 arguments: HashMap::<String, String>::new(),
367 }
368 }
369}
370
371impl Default for OptimizeLevel {
372 fn default() -> OptimizeLevel {
373 OptimizeLevel::Level0
374 }
375}
376
377impl Default for ShrinkLevel {
378 fn default() -> ShrinkLevel {
379 ShrinkLevel::Level0
380 }
381}
382
383impl Default for Passes {
384 fn default() -> Passes {
385 Passes {
386 add_default_passes: true,
387 more_passes: vec![],
388 }
389 }
390}
391
392impl Default for FeatureBaseline {
393 fn default() -> FeatureBaseline {
394 FeatureBaseline::Default
395 }
396}