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}