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 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 #[inline]
84 fn register_pass(&mut self, pass: super::Passes) -> &mut Self {
85 self.passes.push(pass);
86 self
87 }
88
89 #[inline]
93 fn register_performance_passes(&mut self) -> &mut Self {
94 self.use_perf_passes = true;
95 self
96 }
97
98 #[inline]
102 fn register_size_passes(&mut self) -> &mut Self {
103 self.use_size_passes = true;
104 self
105 }
106
107 #[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 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}