spirv_tools/opt/
tool.rs

1use crate::error;
2
3#[derive(Default)]
4pub struct ToolOptimizer {
5    target_env: crate::TargetEnv,
6    passes: Vec<super::Passes>,
7    use_perf_passes: bool,
8    use_size_passes: bool,
9    legalize_hlsl: bool,
10}
11
12use super::Optimizer;
13
14impl Optimizer for ToolOptimizer {
15    fn with_env(target_env: crate::TargetEnv) -> Self {
16        Self {
17            target_env,
18            ..Default::default()
19        }
20    }
21
22    fn optimize<MC: error::MessageCallback>(
23        &self,
24        input: impl AsRef<[u32]>,
25        msg_callback: &mut MC,
26        options: Option<super::Options>,
27    ) -> Result<crate::binary::Binary, crate::Error> {
28        let mut cmd = std::process::Command::new("spirv-opt");
29
30        // Note here that we don't do cmd.arg("--target-env").arg(self.target_env.to_string());
31        // like with the other tools, because opt is "special" and will fail to parse
32        // command line options correctly if we don't give join them with the =
33        cmd.arg(format!("--target-env={}", self.target_env));
34
35        cmd.args(
36            self.passes
37                .iter()
38                .filter_map(|p| pass_to_string(*p).map(|s| format!("--{s}"))),
39        );
40
41        if self.use_perf_passes {
42            cmd.arg("-O");
43        }
44
45        if self.use_size_passes {
46            cmd.arg("-Os");
47        }
48
49        if self.legalize_hlsl {
50            cmd.arg("--legalize-hlsl");
51        }
52
53        if let Some(opts) = options {
54            if let Some(max_id_bound) = opts.max_id_bound {
55                cmd.arg(format!("--max-id-bound={max_id_bound}"));
56            }
57
58            if opts.preserve_bindings {
59                cmd.arg("--preserve-bindings");
60            }
61
62            if opts.preserve_spec_constants {
63                cmd.arg("--preserve-spec-constants");
64            }
65
66            if let Some(vopts) = opts.validator_options {
67                crate::val::tool::add_options(&mut cmd, vopts);
68            }
69        }
70
71        let input = crate::binary::from_binary(input.as_ref());
72
73        let cmd_output = crate::cmd::exec(cmd, Some(input), crate::cmd::Output::Retrieve)?;
74
75        for msg in cmd_output.messages {
76            msg_callback.on_message(msg);
77        }
78
79        crate::binary::Binary::try_from(cmd_output.binary)
80    }
81
82    /// Register a single pass with the the optimizer.
83    #[inline]
84    fn register_pass(&mut self, pass: super::Passes) -> &mut Self {
85        self.passes.push(pass);
86        self
87    }
88
89    /// Registers passes that attempt to improve performance of generated code.
90    /// This sequence of passes is subject to constant review and will change
91    /// from time to time.
92    #[inline]
93    fn register_performance_passes(&mut self) -> &mut Self {
94        self.use_perf_passes = true;
95        self
96    }
97
98    /// Registers passes that attempt to improve the size of generated code.
99    /// This sequence of passes is subject to constant review and will change
100    /// from time to time.
101    #[inline]
102    fn register_size_passes(&mut self) -> &mut Self {
103        self.use_size_passes = true;
104        self
105    }
106
107    /// Registers passes that attempt to legalize the generated code.
108    ///
109    /// Note: this recipe is specially designed for legalizing SPIR-V. It should be
110    /// used by compilers after translating HLSL source code literally. It should
111    /// *not* be used by general workloads for performance or size improvement.
112    ///
113    /// This sequence of passes is subject to constant review and will change
114    /// from time to time.
115    #[inline]
116    fn register_hlsl_legalization_passes(&mut self) -> &mut Self {
117        self.legalize_hlsl = true;
118        self
119    }
120}
121
122fn pass_to_string(pass: super::Passes) -> Option<&'static str> {
123    #[allow(clippy::enum_glob_use)]
124    use super::Passes::*;
125
126    Some(match pass {
127        AggressiveDCE => "eliminate-dead-code-aggressive",
128        AmdExtToKhr => "amd-ext-to-khr",
129        BlockMerge => "merge-blocks",
130        CFGCleanup => "cfg-cleanup",
131        CodeSinking => "code-sink",
132        CombineAccessChains => "combine-access-chains",
133        CompactIds => "compact-ids",
134        ConditionalConstantPropagation => "ccp",
135        ConvertRelaxedToHalf => "convert-relaxed-to-half",
136        CopyPropagateArrays => "copy-propagate-arrays",
137        DeadBranchElim => "eliminate-dead-branches",
138        DeadInsertElim => "eliminate-dead-inserts",
139        DeadVariableElimination => "eliminate-dead-variables",
140        DescriptorScalarReplacement => "descriptor-scalar-replacement",
141        EliminateDeadConstant => "eliminate-dead-const",
142        EliminateDeadFunctions => "eliminate-dead-functions",
143        EliminateDeadMembers => "eliminate-dead-members",
144        FixStorageClass => "fix-storage-class",
145        FlattenDecoration => "flatten-decorations",
146        FoldSpecConstantOpAndComposite => "fold-spec-const-op-composite",
147        FreezeSpecConstantValue => "freeze-spec-const",
148        GraphicsRobustAccess => "graphics-robust-access",
149        IfConversion => "if-conversion",
150        InlineExhaustive => "inline-entry-points-exhaustive",
151        InlineOpaque => "inline-entry-points-opaque",
152        InsertExtractElim => "eliminate-insert-extract",
153        // This is only part of the --legalize-hlsl meta pass
154        InterpolateFixup | Null => return None,
155        LocalAccessChainConvert => "convert-local-access-chains",
156        LocalMultiStoreElim => "eliminate-local-multi-store",
157        LocalRedundancyElimination => "local-redundancy-elimination",
158        LocalSingleBlockLoadStoreElim => "eliminate-local-single-block",
159        LocalSingleStoreElim => "eliminate-local-single-store",
160        LoopInvariantCodeMotion => "loop-invariant-code-motion",
161        LoopPeeling => "loop-peeling",
162        LoopUnswitch => "loop-unswitch",
163        MergeReturn => "merge-return",
164        PrivateToLocal => "private-to-local",
165        PropagateLineInfo => "propagate-line-info",
166        ReduceLoadSize => "reduce-load-size",
167        RedundancyElimination => "redundancy-elimination",
168        RedundantLineInfoElim => "eliminate-redundant-line-info",
169        RemoveUnusedInterfaceVariables => "remove-unused-interface-variables",
170        RelaxFloatOps => "relax-float-ops",
171        RemoveDuplicates => "remove-duplicates",
172        ReplaceInvalidOpcode => "replace-invalid-opcode",
173        Simplification => "simplify-instructions",
174        SSARewrite => "ssa-rewrite",
175        StrengthReduction => "strength-reduction",
176        StripDebugInfo => "strip-debug",
177        StripNonSemanticInfo => "strip-nonsemantic",
178        UnifyConstant => "unify-const",
179        UpgradeMemoryModel => "upgrade-memory-model",
180        VectorDCE => "vector-dce",
181        Workaround1209 => "workaround-1209",
182        WrapOpKill => "wrap-opkill",
183    })
184}