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