1 use super::{
2     help::{MipLevelCoordinate, WrappedArrayLength, WrappedConstructor, WrappedImageQuery},
3     storage::StoreValue,
4     BackendResult, Error, Options,
5 };
6 use crate::{
7     back,
8     proc::{self, NameKey},
9     valid, Handle, Module, ShaderStage, TypeInner,
10 };
11 use std::{fmt, mem};
12 
13 const LOCATION_SEMANTIC: &str = "LOC";
14 const SPECIAL_CBUF_TYPE: &str = "NagaConstants";
15 const SPECIAL_CBUF_VAR: &str = "_NagaConstants";
16 const SPECIAL_BASE_VERTEX: &str = "base_vertex";
17 const SPECIAL_BASE_INSTANCE: &str = "base_instance";
18 const SPECIAL_OTHER: &str = "other";
19 
20 struct EpStructMember {
21     name: String,
22     ty: Handle<crate::Type>,
23     // technically, this should always be `Some`
24     binding: Option<crate::Binding>,
25     index: u32,
26 }
27 
28 /// Structure contains information required for generating
29 /// wrapped structure of all entry points arguments
30 struct EntryPointBinding {
31     /// Name of the fake EP argument that contains the struct
32     /// with all the flattened input data.
33     arg_name: String,
34     /// Generated structure name
35     ty_name: String,
36     /// Members of generated structure
37     members: Vec<EpStructMember>,
38 }
39 
40 pub(super) struct EntryPointInterface {
41     /// If `Some`, the input of an entry point is gathered in a special
42     /// struct with members sorted by binding.
43     /// The `EntryPointBinding::members` array is sorted by index,
44     /// so that we can walk it in `write_ep_arguments_initialization`.
45     input: Option<EntryPointBinding>,
46     /// If `Some`, the output of an entry point is flattened.
47     /// The `EntryPointBinding::members` array is sorted by binding,
48     /// So that we can walk it in `Statement::Return` handler.
49     output: Option<EntryPointBinding>,
50 }
51 
52 #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
53 enum InterfaceKey {
54     Location(u32),
55     BuiltIn(crate::BuiltIn),
56     Other,
57 }
58 
59 impl InterfaceKey {
new(binding: Option<&crate::Binding>) -> Self60     fn new(binding: Option<&crate::Binding>) -> Self {
61         match binding {
62             Some(&crate::Binding::Location { location, .. }) => Self::Location(location),
63             Some(&crate::Binding::BuiltIn(bi)) => Self::BuiltIn(bi),
64             None => Self::Other,
65         }
66     }
67 }
68 
69 #[derive(Copy, Clone, PartialEq)]
70 enum Io {
71     Input,
72     Output,
73 }
74 
75 impl<'a, W: fmt::Write> super::Writer<'a, W> {
new(out: W, options: &'a Options) -> Self76     pub fn new(out: W, options: &'a Options) -> Self {
77         Self {
78             out,
79             names: crate::FastHashMap::default(),
80             namer: proc::Namer::default(),
81             options,
82             entry_point_io: Vec::new(),
83             named_expressions: crate::NamedExpressions::default(),
84             wrapped: super::Wrapped::default(),
85             temp_access_chain: Vec::new(),
86         }
87     }
88 
reset(&mut self, module: &Module)89     fn reset(&mut self, module: &Module) {
90         self.names.clear();
91         self.namer
92             .reset(module, super::keywords::RESERVED, &[], &mut self.names);
93         self.entry_point_io.clear();
94         self.named_expressions.clear();
95         self.wrapped.clear();
96     }
97 
write( &mut self, module: &Module, module_info: &valid::ModuleInfo, ) -> Result<super::ReflectionInfo, Error>98     pub fn write(
99         &mut self,
100         module: &Module,
101         module_info: &valid::ModuleInfo,
102     ) -> Result<super::ReflectionInfo, Error> {
103         self.reset(module);
104 
105         // Write special constants, if needed
106         if let Some(ref bt) = self.options.special_constants_binding {
107             writeln!(self.out, "struct {} {{", SPECIAL_CBUF_TYPE)?;
108             writeln!(self.out, "{}int {};", back::INDENT, SPECIAL_BASE_VERTEX)?;
109             writeln!(self.out, "{}int {};", back::INDENT, SPECIAL_BASE_INSTANCE)?;
110             writeln!(self.out, "{}uint {};", back::INDENT, SPECIAL_OTHER)?;
111             writeln!(self.out, "}};")?;
112             write!(
113                 self.out,
114                 "ConstantBuffer<{}> {}: register(b{}",
115                 SPECIAL_CBUF_TYPE, SPECIAL_CBUF_VAR, bt.register
116             )?;
117             if bt.space != 0 {
118                 write!(self.out, ", space{}", bt.space)?;
119             }
120             writeln!(self.out, ");")?;
121         }
122 
123         // Write all constants
124         // For example, input wgsl shader:
125         // ```wgsl
126         // let c_scale: f32 = 1.2;
127         // return VertexOutput(uv, vec4<f32>(c_scale * pos, 0.0, 1.0));
128         // ```
129         //
130         // Output shader:
131         // ```hlsl
132         // static const float c_scale = 1.2;
133         // const VertexOutput vertexoutput1 = { vertexinput.uv3, float4((c_scale * vertexinput.pos1), 0.0, 1.0) };
134         // ```
135         //
136         // If we remove `write_global_constant` `c_scale` will be inlined.
137         for (handle, constant) in module.constants.iter() {
138             if constant.name.is_some() {
139                 self.write_global_constant(module, &constant.inner, handle)?;
140             }
141         }
142 
143         // Extra newline for readability
144         writeln!(self.out)?;
145 
146         // Save all entry point output types
147         let ep_results = module
148             .entry_points
149             .iter()
150             .map(|ep| (ep.stage, ep.function.result.clone()))
151             .collect::<Vec<(ShaderStage, Option<crate::FunctionResult>)>>();
152 
153         // Write all structs
154         for (handle, ty) in module.types.iter() {
155             if let TypeInner::Struct { ref members, .. } = ty.inner {
156                 if let Some(member) = members.last() {
157                     if let TypeInner::Array {
158                         size: crate::ArraySize::Dynamic,
159                         ..
160                     } = module.types[member.ty].inner
161                     {
162                         // unsized arrays can only be in storage buffers, for which we use `ByteAddressBuffer` anyway.
163                         continue;
164                     }
165                 }
166 
167                 let ep_result = ep_results.iter().find(|e| {
168                     if let Some(ref result) = e.1 {
169                         result.ty == handle
170                     } else {
171                         false
172                     }
173                 });
174 
175                 self.write_struct(
176                     module,
177                     handle,
178                     members,
179                     ep_result.map(|r| (r.0, Io::Output)),
180                 )?;
181                 writeln!(self.out)?;
182             }
183         }
184 
185         // Write all globals
186         for (ty, _) in module.global_variables.iter() {
187             self.write_global(module, ty)?;
188         }
189 
190         if !module.global_variables.is_empty() {
191             // Add extra newline for readability
192             writeln!(self.out)?;
193         }
194 
195         // Write all entry points wrapped structs
196         for ep in module.entry_points.iter() {
197             let ep_io = self.write_ep_interface(module, &ep.function, ep.stage, &ep.name)?;
198             self.entry_point_io.push(ep_io);
199         }
200 
201         // Write all regular functions
202         for (handle, function) in module.functions.iter() {
203             let info = &module_info[handle];
204 
205             // Check if all of the globals are accessible
206             if !self.options.fake_missing_bindings {
207                 if let Some((var_handle, _)) =
208                     module
209                         .global_variables
210                         .iter()
211                         .find(|&(var_handle, var)| match var.binding {
212                             Some(ref binding) if !info[var_handle].is_empty() => {
213                                 self.options.resolve_resource_binding(binding).is_err()
214                             }
215                             _ => false,
216                         })
217                 {
218                     log::info!(
219                         "Skipping function {:?} (name {:?}) because global {:?} is inaccessible",
220                         handle,
221                         function.name,
222                         var_handle
223                     );
224                     continue;
225                 }
226             }
227 
228             let ctx = back::FunctionCtx {
229                 ty: back::FunctionType::Function(handle),
230                 info,
231                 expressions: &function.expressions,
232                 named_expressions: &function.named_expressions,
233             };
234             let name = self.names[&NameKey::Function(handle)].clone();
235 
236             // Write wrapped function for `Expression::ImageQuery` and `Expressions::ArrayLength`
237             // before writing all statements and expressions.
238             self.write_wrapped_functions(module, &ctx)?;
239 
240             self.write_function(module, name.as_str(), function, &ctx)?;
241 
242             writeln!(self.out)?;
243         }
244 
245         let mut entry_point_names = Vec::with_capacity(module.entry_points.len());
246 
247         // Write all entry points
248         for (index, ep) in module.entry_points.iter().enumerate() {
249             let info = module_info.get_entry_point(index);
250 
251             if !self.options.fake_missing_bindings {
252                 let mut ep_error = None;
253                 for (var_handle, var) in module.global_variables.iter() {
254                     match var.binding {
255                         Some(ref binding) if !info[var_handle].is_empty() => {
256                             if let Err(err) = self.options.resolve_resource_binding(binding) {
257                                 ep_error = Some(err);
258                                 break;
259                             }
260                         }
261                         _ => {}
262                     }
263                 }
264                 if let Some(err) = ep_error {
265                     entry_point_names.push(Err(err));
266                     continue;
267                 }
268             }
269 
270             let ctx = back::FunctionCtx {
271                 ty: back::FunctionType::EntryPoint(index as u16),
272                 info,
273                 expressions: &ep.function.expressions,
274                 named_expressions: &ep.function.named_expressions,
275             };
276 
277             // Write wrapped function for `Expression::ImageQuery` and `Expressions::ArrayLength`
278             // before writing all statements and expressions.
279             self.write_wrapped_functions(module, &ctx)?;
280 
281             if ep.stage == ShaderStage::Compute {
282                 // HLSL is calling workgroup size "num threads"
283                 let num_threads = ep.workgroup_size;
284                 writeln!(
285                     self.out,
286                     "[numthreads({}, {}, {})]",
287                     num_threads[0], num_threads[1], num_threads[2]
288                 )?;
289             }
290 
291             let name = self.names[&NameKey::EntryPoint(index as u16)].clone();
292             self.write_function(module, &name, &ep.function, &ctx)?;
293 
294             if index < module.entry_points.len() - 1 {
295                 writeln!(self.out)?;
296             }
297 
298             entry_point_names.push(Ok(name));
299         }
300 
301         Ok(super::ReflectionInfo { entry_point_names })
302     }
303 
304     //TODO: we could force fragment outputs to always go through `entry_point_io.output` path
305     // if they are struct, so that the `stage` argument here could be omitted.
write_semantic( &mut self, binding: &crate::Binding, stage: Option<(ShaderStage, Io)>, ) -> BackendResult306     fn write_semantic(
307         &mut self,
308         binding: &crate::Binding,
309         stage: Option<(ShaderStage, Io)>,
310     ) -> BackendResult {
311         match *binding {
312             crate::Binding::BuiltIn(builtin) => {
313                 let builtin_str = builtin.to_hlsl_str()?;
314                 write!(self.out, " : {}", builtin_str)?;
315             }
316             crate::Binding::Location { location, .. } => {
317                 if stage == Some((crate::ShaderStage::Fragment, Io::Output)) {
318                     write!(self.out, " : SV_Target{}", location)?;
319                 } else {
320                     write!(self.out, " : {}{}", LOCATION_SEMANTIC, location)?;
321                 }
322             }
323         }
324 
325         Ok(())
326     }
327 
write_interface_struct( &mut self, module: &Module, shader_stage: (ShaderStage, Io), struct_name: String, mut members: Vec<EpStructMember>, ) -> Result<EntryPointBinding, Error>328     fn write_interface_struct(
329         &mut self,
330         module: &Module,
331         shader_stage: (ShaderStage, Io),
332         struct_name: String,
333         mut members: Vec<EpStructMember>,
334     ) -> Result<EntryPointBinding, Error> {
335         // Sort the members so that first come the user-defined varyings
336         // in ascending locations, and then built-ins. This allows VS and FS
337         // interfaces to match with regards to order.
338         members.sort_by_key(|m| InterfaceKey::new(m.binding.as_ref()));
339 
340         write!(self.out, "struct {}", struct_name)?;
341         writeln!(self.out, " {{")?;
342         for m in members.iter() {
343             write!(self.out, "{}", back::INDENT)?;
344             self.write_type(module, m.ty)?;
345             write!(self.out, " {}", &m.name)?;
346             if let Some(ref binding) = m.binding {
347                 self.write_semantic(binding, Some(shader_stage))?;
348             }
349             writeln!(self.out, ";")?;
350         }
351         writeln!(self.out, "}};")?;
352         writeln!(self.out)?;
353 
354         match shader_stage.1 {
355             Io::Input => {
356                 // bring back the original order
357                 members.sort_by_key(|m| m.index);
358             }
359             Io::Output => {
360                 // keep it sorted by binding
361             }
362         }
363 
364         Ok(EntryPointBinding {
365             arg_name: self.namer.call(struct_name.to_lowercase().as_str()),
366             ty_name: struct_name,
367             members,
368         })
369     }
370 
371     /// Flatten all entry point arguments into a single struct.
372     /// This is needed since we need to re-order them: first placing user locations,
373     /// then built-ins.
write_ep_input_struct( &mut self, module: &Module, func: &crate::Function, stage: ShaderStage, entry_point_name: &str, ) -> Result<EntryPointBinding, Error>374     fn write_ep_input_struct(
375         &mut self,
376         module: &Module,
377         func: &crate::Function,
378         stage: ShaderStage,
379         entry_point_name: &str,
380     ) -> Result<EntryPointBinding, Error> {
381         let struct_name = format!("{:?}Input_{}", stage, entry_point_name);
382 
383         let mut fake_members = Vec::new();
384         for arg in func.arguments.iter() {
385             match module.types[arg.ty].inner {
386                 TypeInner::Struct { ref members, .. } => {
387                     for member in members.iter() {
388                         let name = self.namer.call_or(&member.name, "member");
389                         let index = fake_members.len() as u32;
390                         fake_members.push(EpStructMember {
391                             name,
392                             ty: member.ty,
393                             binding: member.binding.clone(),
394                             index,
395                         });
396                     }
397                 }
398                 _ => {
399                     let member_name = self.namer.call_or(&arg.name, "member");
400                     let index = fake_members.len() as u32;
401                     fake_members.push(EpStructMember {
402                         name: member_name,
403                         ty: arg.ty,
404                         binding: arg.binding.clone(),
405                         index,
406                     });
407                 }
408             }
409         }
410 
411         self.write_interface_struct(module, (stage, Io::Input), struct_name, fake_members)
412     }
413 
414     /// Flatten all entry point results into a single struct.
415     /// This is needed since we need to re-order them: first placing user locations,
416     /// then built-ins.
write_ep_output_struct( &mut self, module: &Module, result: &crate::FunctionResult, stage: ShaderStage, entry_point_name: &str, ) -> Result<EntryPointBinding, Error>417     fn write_ep_output_struct(
418         &mut self,
419         module: &Module,
420         result: &crate::FunctionResult,
421         stage: ShaderStage,
422         entry_point_name: &str,
423     ) -> Result<EntryPointBinding, Error> {
424         let struct_name = format!("{:?}Output_{}", stage, entry_point_name);
425 
426         let mut fake_members = Vec::new();
427         let empty = [];
428         let members = match module.types[result.ty].inner {
429             TypeInner::Struct { ref members, .. } => members,
430             ref other => {
431                 log::error!("Unexpected {:?} output type without a binding", other);
432                 &empty[..]
433             }
434         };
435 
436         for member in members.iter() {
437             let member_name = self.namer.call_or(&member.name, "member");
438             let index = fake_members.len() as u32;
439             fake_members.push(EpStructMember {
440                 name: member_name,
441                 ty: member.ty,
442                 binding: member.binding.clone(),
443                 index,
444             });
445         }
446 
447         self.write_interface_struct(module, (stage, Io::Output), struct_name, fake_members)
448     }
449 
450     /// Writes special interface structures for an entry point. The special structures have
451     /// all the fields flattened into them and sorted by binding. They are only needed for
452     /// VS outputs and FS inputs, so that these interfaces match.
write_ep_interface( &mut self, module: &Module, func: &crate::Function, stage: ShaderStage, ep_name: &str, ) -> Result<EntryPointInterface, Error>453     fn write_ep_interface(
454         &mut self,
455         module: &Module,
456         func: &crate::Function,
457         stage: ShaderStage,
458         ep_name: &str,
459     ) -> Result<EntryPointInterface, Error> {
460         Ok(EntryPointInterface {
461             input: if !func.arguments.is_empty() && stage == ShaderStage::Fragment {
462                 Some(self.write_ep_input_struct(module, func, stage, ep_name)?)
463             } else {
464                 None
465             },
466             output: match func.result {
467                 Some(ref fr) if fr.binding.is_none() && stage == ShaderStage::Vertex => {
468                     Some(self.write_ep_output_struct(module, fr, stage, ep_name)?)
469                 }
470                 _ => None,
471             },
472         })
473     }
474 
475     /// Write an entry point preface that initializes the arguments as specified in IR.
write_ep_arguments_initialization( &mut self, module: &Module, func: &crate::Function, ep_index: u16, ) -> BackendResult476     fn write_ep_arguments_initialization(
477         &mut self,
478         module: &Module,
479         func: &crate::Function,
480         ep_index: u16,
481     ) -> BackendResult {
482         let ep_input = match self.entry_point_io[ep_index as usize].input.take() {
483             Some(ep_input) => ep_input,
484             None => return Ok(()),
485         };
486         let mut fake_iter = ep_input.members.iter();
487         for (arg_index, arg) in func.arguments.iter().enumerate() {
488             write!(self.out, "{}", back::INDENT)?;
489             self.write_type(module, arg.ty)?;
490             let arg_name = &self.names[&NameKey::EntryPointArgument(ep_index, arg_index as u32)];
491             write!(self.out, " {}", arg_name)?;
492             match module.types[arg.ty].inner {
493                 TypeInner::Array { size, .. } => {
494                     self.write_array_size(module, size)?;
495                     let fake_member = fake_iter.next().unwrap();
496                     writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?;
497                 }
498                 TypeInner::Struct { ref members, .. } => {
499                     write!(self.out, " = {{ ")?;
500                     for index in 0..members.len() {
501                         if index != 0 {
502                             write!(self.out, ", ")?;
503                         }
504                         let fake_member = fake_iter.next().unwrap();
505                         write!(self.out, "{}.{}", ep_input.arg_name, fake_member.name)?;
506                     }
507                     writeln!(self.out, " }};")?;
508                 }
509                 _ => {
510                     let fake_member = fake_iter.next().unwrap();
511                     writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?;
512                 }
513             }
514         }
515         assert!(fake_iter.next().is_none());
516         Ok(())
517     }
518 
519     /// Helper method used to write global variables
520     /// # Notes
521     /// Always adds a newline
write_global( &mut self, module: &Module, handle: Handle<crate::GlobalVariable>, ) -> BackendResult522     fn write_global(
523         &mut self,
524         module: &Module,
525         handle: Handle<crate::GlobalVariable>,
526     ) -> BackendResult {
527         let global = &module.global_variables[handle];
528         let inner = &module.types[global.ty].inner;
529 
530         if let Some(ref binding) = global.binding {
531             if let Err(err) = self.options.resolve_resource_binding(binding) {
532                 log::info!(
533                     "Skipping global {:?} (name {:?}) for being inaccessible: {}",
534                     handle,
535                     global.name,
536                     err,
537                 );
538                 return Ok(());
539             }
540         }
541 
542         // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-register
543         let register_ty = match global.class {
544             crate::StorageClass::Function => unreachable!("Function storage class"),
545             crate::StorageClass::Private => {
546                 write!(self.out, "static ")?;
547                 self.write_type(module, global.ty)?;
548                 ""
549             }
550             crate::StorageClass::WorkGroup => {
551                 write!(self.out, "groupshared ")?;
552                 self.write_type(module, global.ty)?;
553                 ""
554             }
555             crate::StorageClass::Uniform => {
556                 // constant buffer declarations are expected to be inlined, e.g.
557                 // `cbuffer foo: register(b0) { field1: type1; }`
558                 write!(self.out, "cbuffer")?;
559                 "b"
560             }
561             crate::StorageClass::Storage { access } => {
562                 let (prefix, register) = if access.contains(crate::StorageAccess::STORE) {
563                     ("RW", "u")
564                 } else {
565                     ("", "t")
566                 };
567                 write!(self.out, "{}ByteAddressBuffer", prefix)?;
568                 register
569             }
570             crate::StorageClass::Handle => {
571                 let register = match *inner {
572                     TypeInner::Sampler { .. } => "s",
573                     // all storage textures are UAV, unconditionally
574                     TypeInner::Image {
575                         class: crate::ImageClass::Storage { .. },
576                         ..
577                     } => "u",
578                     _ => "t",
579                 };
580                 self.write_type(module, global.ty)?;
581                 register
582             }
583             crate::StorageClass::PushConstant => unimplemented!("Push constants"),
584         };
585 
586         let name = &self.names[&NameKey::GlobalVariable(handle)];
587         write!(self.out, " {}", name)?;
588         if let TypeInner::Array { size, .. } = module.types[global.ty].inner {
589             self.write_array_size(module, size)?;
590         }
591 
592         if let Some(ref binding) = global.binding {
593             // this was already resolved earlier when we started evaluating an entry point.
594             let bt = self.options.resolve_resource_binding(binding).unwrap();
595             write!(self.out, " : register({}{}", register_ty, bt.register)?;
596             if bt.space != 0 {
597                 write!(self.out, ", space{}", bt.space)?;
598             }
599             write!(self.out, ")")?;
600         } else if global.class == crate::StorageClass::Private {
601             write!(self.out, " = ")?;
602             if let Some(init) = global.init {
603                 self.write_constant(module, init)?;
604             } else {
605                 self.write_default_init(module, global.ty)?;
606             }
607         }
608 
609         if global.class == crate::StorageClass::Uniform {
610             write!(self.out, " {{ ")?;
611             self.write_type(module, global.ty)?;
612             let name = &self.names[&NameKey::GlobalVariable(handle)];
613             writeln!(self.out, " {}; }}", name)?;
614         } else {
615             writeln!(self.out, ";")?;
616         }
617 
618         Ok(())
619     }
620 
621     /// Helper method used to write global constants
622     ///
623     /// # Notes
624     /// Ends in a newline
write_global_constant( &mut self, module: &Module, inner: &crate::ConstantInner, handle: Handle<crate::Constant>, ) -> BackendResult625     fn write_global_constant(
626         &mut self,
627         module: &Module,
628         inner: &crate::ConstantInner,
629         handle: Handle<crate::Constant>,
630     ) -> BackendResult {
631         write!(self.out, "static const ")?;
632         match *inner {
633             crate::ConstantInner::Scalar {
634                 width: _,
635                 ref value,
636             } => {
637                 // Write type
638                 let ty_str = match *value {
639                     crate::ScalarValue::Sint(_) => "int",
640                     crate::ScalarValue::Uint(_) => "uint",
641                     crate::ScalarValue::Float(_) => "float",
642                     crate::ScalarValue::Bool(_) => "bool",
643                 };
644                 let name = &self.names[&NameKey::Constant(handle)];
645                 write!(self.out, "{} {} = ", ty_str, name)?;
646 
647                 // Second match required to avoid heap allocation by `format!()`
648                 match *value {
649                     crate::ScalarValue::Sint(value) => write!(self.out, "{}", value)?,
650                     crate::ScalarValue::Uint(value) => write!(self.out, "{}", value)?,
651                     crate::ScalarValue::Float(value) => {
652                         // Floats are written using `Debug` instead of `Display` because it always appends the
653                         // decimal part even it's zero
654                         write!(self.out, "{:?}", value)?
655                     }
656                     crate::ScalarValue::Bool(value) => write!(self.out, "{}", value)?,
657                 };
658             }
659             crate::ConstantInner::Composite { ty, ref components } => {
660                 self.write_type(module, ty)?;
661                 let name = &self.names[&NameKey::Constant(handle)];
662                 write!(self.out, " {} = ", name)?;
663                 self.write_composite_constant(module, ty, components)?;
664             }
665         }
666         writeln!(self.out, ";")?;
667         Ok(())
668     }
669 
write_array_size( &mut self, module: &Module, size: crate::ArraySize, ) -> BackendResult670     pub(super) fn write_array_size(
671         &mut self,
672         module: &Module,
673         size: crate::ArraySize,
674     ) -> BackendResult {
675         write!(self.out, "[")?;
676 
677         // Write the array size
678         // Writes nothing if `ArraySize::Dynamic`
679         // Panics if `ArraySize::Constant` has a constant that isn't an sint or uint
680         match size {
681             crate::ArraySize::Constant(const_handle) => {
682                 let size = module.constants[const_handle].to_array_length().unwrap();
683                 write!(self.out, "{}", size)?;
684             }
685             crate::ArraySize::Dynamic => unreachable!(),
686         }
687 
688         write!(self.out, "]")?;
689         Ok(())
690     }
691 
692     /// Helper method used to write structs
693     ///
694     /// # Notes
695     /// Ends in a newline
write_struct( &mut self, module: &Module, handle: Handle<crate::Type>, members: &[crate::StructMember], shader_stage: Option<(ShaderStage, Io)>, ) -> BackendResult696     fn write_struct(
697         &mut self,
698         module: &Module,
699         handle: Handle<crate::Type>,
700         members: &[crate::StructMember],
701         shader_stage: Option<(ShaderStage, Io)>,
702     ) -> BackendResult {
703         // Write struct name
704         let struct_name = &self.names[&NameKey::Type(handle)];
705         writeln!(self.out, "struct {} {{", struct_name)?;
706 
707         for (index, member) in members.iter().enumerate() {
708             // The indentation is only for readability
709             write!(self.out, "{}", back::INDENT)?;
710 
711             match module.types[member.ty].inner {
712                 TypeInner::Array {
713                     base,
714                     size,
715                     stride: _,
716                 } => {
717                     // HLSL arrays are written as `type name[size]`
718                     if let TypeInner::Matrix { .. } = module.types[base].inner {
719                         write!(self.out, "row_major ")?;
720                     }
721                     self.write_type(module, base)?;
722                     // Write `name`
723                     write!(
724                         self.out,
725                         " {}",
726                         &self.names[&NameKey::StructMember(handle, index as u32)]
727                     )?;
728                     // Write [size]
729                     self.write_array_size(module, size)?;
730                 }
731                 _ => {
732                     // Write interpolation modifier before type
733                     if let Some(crate::Binding::Location {
734                         interpolation,
735                         sampling,
736                         ..
737                     }) = member.binding
738                     {
739                         if let Some(interpolation) = interpolation {
740                             write!(self.out, "{} ", interpolation.to_hlsl_str())?
741                         }
742 
743                         if let Some(sampling) = sampling {
744                             if let Some(string) = sampling.to_hlsl_str() {
745                                 write!(self.out, "{} ", string)?
746                             }
747                         }
748                     }
749 
750                     if let TypeInner::Matrix { .. } = module.types[member.ty].inner {
751                         write!(self.out, "row_major ")?;
752                     }
753 
754                     // Write the member type and name
755                     self.write_type(module, member.ty)?;
756                     write!(
757                         self.out,
758                         " {}",
759                         &self.names[&NameKey::StructMember(handle, index as u32)]
760                     )?;
761                 }
762             }
763 
764             if let Some(ref binding) = member.binding {
765                 self.write_semantic(binding, shader_stage)?;
766             };
767             writeln!(self.out, ";")?;
768         }
769 
770         writeln!(self.out, "}};")?;
771         Ok(())
772     }
773 
774     /// Helper method used to write non image/sampler types
775     ///
776     /// # Notes
777     /// Adds no trailing or leading whitespace
write_type(&mut self, module: &Module, ty: Handle<crate::Type>) -> BackendResult778     pub(super) fn write_type(&mut self, module: &Module, ty: Handle<crate::Type>) -> BackendResult {
779         let inner = &module.types[ty].inner;
780         match *inner {
781             TypeInner::Struct { .. } => write!(self.out, "{}", self.names[&NameKey::Type(ty)])?,
782             // hlsl array has the size separated from the base type
783             TypeInner::Array { base, .. } => self.write_type(module, base)?,
784             ref other => self.write_value_type(module, other)?,
785         }
786 
787         Ok(())
788     }
789 
790     /// Helper method used to write value types
791     ///
792     /// # Notes
793     /// Adds no trailing or leading whitespace
write_value_type(&mut self, module: &Module, inner: &TypeInner) -> BackendResult794     pub(super) fn write_value_type(&mut self, module: &Module, inner: &TypeInner) -> BackendResult {
795         match *inner {
796             TypeInner::Scalar { kind, width } | TypeInner::Atomic { kind, width } => {
797                 write!(self.out, "{}", kind.to_hlsl_str(width)?)?;
798             }
799             TypeInner::Vector { size, kind, width } => {
800                 write!(
801                     self.out,
802                     "{}{}",
803                     kind.to_hlsl_str(width)?,
804                     back::vector_size_str(size)
805                 )?;
806             }
807             TypeInner::Matrix {
808                 columns,
809                 rows,
810                 width,
811             } => {
812                 // The IR supports only float matrix
813                 // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-matrix
814 
815                 // Because of the implicit transpose all matrices have in HLSL, we need to tranpose the size as well.
816                 write!(
817                     self.out,
818                     "{}{}x{}",
819                     crate::ScalarKind::Float.to_hlsl_str(width)?,
820                     back::vector_size_str(rows),
821                     back::vector_size_str(columns),
822                 )?;
823             }
824             TypeInner::Image {
825                 dim,
826                 arrayed,
827                 class,
828             } => {
829                 self.write_image_type(dim, arrayed, class)?;
830             }
831             TypeInner::Sampler { comparison } => {
832                 let sampler = if comparison {
833                     "SamplerComparisonState"
834                 } else {
835                     "SamplerState"
836                 };
837                 write!(self.out, "{}", sampler)?;
838             }
839             // HLSL arrays are written as `type name[size]`
840             // Current code is written arrays only as `[size]`
841             // Base `type` and `name` should be written outside
842             TypeInner::Array { size, .. } => {
843                 self.write_array_size(module, size)?;
844             }
845             _ => {
846                 return Err(Error::Unimplemented(format!(
847                     "write_value_type {:?}",
848                     inner
849                 )))
850             }
851         }
852 
853         Ok(())
854     }
855 
856     /// Helper method used to write functions
857     /// # Notes
858     /// Ends in a newline
write_function( &mut self, module: &Module, name: &str, func: &crate::Function, func_ctx: &back::FunctionCtx<'_>, ) -> BackendResult859     fn write_function(
860         &mut self,
861         module: &Module,
862         name: &str,
863         func: &crate::Function,
864         func_ctx: &back::FunctionCtx<'_>,
865     ) -> BackendResult {
866         // Function Declaration Syntax - https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-function-syntax
867         if let Some(ref result) = func.result {
868             match func_ctx.ty {
869                 back::FunctionType::Function(_) => {
870                     self.write_type(module, result.ty)?;
871                 }
872                 back::FunctionType::EntryPoint(index) => {
873                     if let Some(ref ep_output) = self.entry_point_io[index as usize].output {
874                         write!(self.out, "{}", ep_output.ty_name)?;
875                     } else {
876                         self.write_type(module, result.ty)?;
877                     }
878                 }
879             }
880         } else {
881             write!(self.out, "void")?;
882         }
883 
884         // Write function name
885         write!(self.out, " {}(", name)?;
886 
887         // Write function arguments for non entry point functions
888         match func_ctx.ty {
889             back::FunctionType::Function(handle) => {
890                 for (index, arg) in func.arguments.iter().enumerate() {
891                     if index != 0 {
892                         write!(self.out, ", ")?;
893                     }
894                     // Write argument type
895                     let arg_ty = match module.types[arg.ty].inner {
896                         // pointers in function arguments are expected and resolve to `inout`
897                         TypeInner::Pointer { base, .. } => {
898                             //TODO: can we narrow this down to just `in` when possible?
899                             write!(self.out, "inout ")?;
900                             base
901                         }
902                         _ => arg.ty,
903                     };
904                     self.write_type(module, arg_ty)?;
905 
906                     let argument_name =
907                         &self.names[&NameKey::FunctionArgument(handle, index as u32)];
908 
909                     // Write argument name. Space is important.
910                     write!(self.out, " {}", argument_name)?;
911                     if let TypeInner::Array { size, .. } = module.types[arg.ty].inner {
912                         self.write_array_size(module, size)?;
913                     }
914                 }
915             }
916             back::FunctionType::EntryPoint(ep_index) => {
917                 if let Some(ref ep_input) = self.entry_point_io[ep_index as usize].input {
918                     write!(self.out, "{} {}", ep_input.ty_name, ep_input.arg_name,)?;
919                 } else {
920                     let stage = module.entry_points[ep_index as usize].stage;
921                     for (index, arg) in func.arguments.iter().enumerate() {
922                         if index != 0 {
923                             write!(self.out, ", ")?;
924                         }
925                         self.write_type(module, arg.ty)?;
926 
927                         let argument_name =
928                             &self.names[&NameKey::EntryPointArgument(ep_index, index as u32)];
929 
930                         write!(self.out, " {}", argument_name)?;
931                         if let TypeInner::Array { size, .. } = module.types[arg.ty].inner {
932                             self.write_array_size(module, size)?;
933                         }
934 
935                         if let Some(ref binding) = arg.binding {
936                             self.write_semantic(binding, Some((stage, Io::Input)))?;
937                         }
938                     }
939                 }
940             }
941         }
942         // Ends of arguments
943         write!(self.out, ")")?;
944 
945         // Write semantic if it present
946         if let back::FunctionType::EntryPoint(index) = func_ctx.ty {
947             let stage = module.entry_points[index as usize].stage;
948             if let Some(crate::FunctionResult {
949                 binding: Some(ref binding),
950                 ..
951             }) = func.result
952             {
953                 self.write_semantic(binding, Some((stage, Io::Output)))?;
954             }
955         }
956 
957         // Function body start
958         writeln!(self.out)?;
959         writeln!(self.out, "{{")?;
960 
961         if let back::FunctionType::EntryPoint(index) = func_ctx.ty {
962             self.write_ep_arguments_initialization(module, func, index)?;
963         }
964 
965         // Write function local variables
966         for (handle, local) in func.local_variables.iter() {
967             // Write indentation (only for readability)
968             write!(self.out, "{}", back::INDENT)?;
969 
970             // Write the local name
971             // The leading space is important
972             self.write_type(module, local.ty)?;
973             write!(self.out, " {}", self.names[&func_ctx.name_key(handle)])?;
974             // Write size for array type
975             if let TypeInner::Array { size, .. } = module.types[local.ty].inner {
976                 self.write_array_size(module, size)?;
977             }
978 
979             write!(self.out, " = ")?;
980             // Write the local initializer if needed
981             if let Some(init) = local.init {
982                 // Put the equal signal only if there's a initializer
983                 // The leading and trailing spaces aren't needed but help with readability
984 
985                 // Write the constant
986                 // `write_constant` adds no trailing or leading space/newline
987                 self.write_constant(module, init)?;
988             } else {
989                 // Zero initialize local variables
990                 self.write_default_init(module, local.ty)?;
991             }
992 
993             // Finish the local with `;` and add a newline (only for readability)
994             writeln!(self.out, ";")?
995         }
996 
997         if !func.local_variables.is_empty() {
998             writeln!(self.out)?;
999         }
1000 
1001         // Write the function body (statement list)
1002         for sta in func.body.iter() {
1003             // The indentation should always be 1 when writing the function body
1004             self.write_stmt(module, sta, func_ctx, back::Level(1))?;
1005         }
1006 
1007         writeln!(self.out, "}}")?;
1008 
1009         self.named_expressions.clear();
1010 
1011         Ok(())
1012     }
1013 
1014     /// Helper method used to write statements
1015     ///
1016     /// # Notes
1017     /// Always adds a newline
write_stmt( &mut self, module: &Module, stmt: &crate::Statement, func_ctx: &back::FunctionCtx<'_>, level: back::Level, ) -> BackendResult1018     fn write_stmt(
1019         &mut self,
1020         module: &Module,
1021         stmt: &crate::Statement,
1022         func_ctx: &back::FunctionCtx<'_>,
1023         level: back::Level,
1024     ) -> BackendResult {
1025         use crate::Statement;
1026 
1027         match *stmt {
1028             Statement::Emit(ref range) => {
1029                 for handle in range.clone() {
1030                     let info = &func_ctx.info[handle];
1031                     let ptr_class = info.ty.inner_with(&module.types).pointer_class();
1032                     let expr_name = if ptr_class.is_some() {
1033                         // HLSL can't save a pointer-valued expression in a variable,
1034                         // but we shouldn't ever need to: they should never be named expressions,
1035                         // and none of the expression types flagged by bake_ref_count can be pointer-valued.
1036                         None
1037                     } else if let Some(name) = func_ctx.named_expressions.get(&handle) {
1038                         // Front end provides names for all variables at the start of writing.
1039                         // But we write them to step by step. We need to recache them
1040                         // Otherwise, we could accidentally write variable name instead of full expression.
1041                         // Also, we use sanitized names! It defense backend from generating variable with name from reserved keywords.
1042                         Some(self.namer.call(name))
1043                     } else {
1044                         let min_ref_count = func_ctx.expressions[handle].bake_ref_count();
1045                         if min_ref_count <= info.ref_count {
1046                             Some(format!("_expr{}", handle.index()))
1047                         } else {
1048                             None
1049                         }
1050                     };
1051 
1052                     if let Some(name) = expr_name {
1053                         write!(self.out, "{}", level)?;
1054                         self.write_named_expr(module, handle, name, func_ctx)?;
1055                     }
1056                 }
1057             }
1058             // TODO: copy-paste from glsl-out
1059             Statement::Block(ref block) => {
1060                 write!(self.out, "{}", level)?;
1061                 writeln!(self.out, "{{")?;
1062                 for sta in block.iter() {
1063                     // Increase the indentation to help with readability
1064                     self.write_stmt(module, sta, func_ctx, level.next())?
1065                 }
1066                 writeln!(self.out, "{}}}", level)?
1067             }
1068             // TODO: copy-paste from glsl-out
1069             Statement::If {
1070                 condition,
1071                 ref accept,
1072                 ref reject,
1073             } => {
1074                 write!(self.out, "{}", level)?;
1075                 write!(self.out, "if (")?;
1076                 self.write_expr(module, condition, func_ctx)?;
1077                 writeln!(self.out, ") {{")?;
1078 
1079                 let l2 = level.next();
1080                 for sta in accept {
1081                     // Increase indentation to help with readability
1082                     self.write_stmt(module, sta, func_ctx, l2)?;
1083                 }
1084 
1085                 // If there are no statements in the reject block we skip writing it
1086                 // This is only for readability
1087                 if !reject.is_empty() {
1088                     writeln!(self.out, "{}}} else {{", level)?;
1089 
1090                     for sta in reject {
1091                         // Increase indentation to help with readability
1092                         self.write_stmt(module, sta, func_ctx, l2)?;
1093                     }
1094                 }
1095 
1096                 writeln!(self.out, "{}}}", level)?
1097             }
1098             // TODO: copy-paste from glsl-out
1099             Statement::Kill => writeln!(self.out, "{}discard;", level)?,
1100             Statement::Return { value: None } => {
1101                 writeln!(self.out, "{}return;", level)?;
1102             }
1103             Statement::Return { value: Some(expr) } => {
1104                 let base_ty_res = &func_ctx.info[expr].ty;
1105                 let mut resolved = base_ty_res.inner_with(&module.types);
1106                 if let TypeInner::Pointer { base, class: _ } = *resolved {
1107                     resolved = &module.types[base].inner;
1108                 }
1109 
1110                 if let TypeInner::Struct { .. } = *resolved {
1111                     // We can safery unwrap here, since we now we working with struct
1112                     let ty = base_ty_res.handle().unwrap();
1113                     let struct_name = &self.names[&NameKey::Type(ty)];
1114                     let variable_name = self.namer.call(&struct_name.to_lowercase());
1115                     write!(
1116                         self.out,
1117                         "{}const {} {} = ",
1118                         level, struct_name, variable_name,
1119                     )?;
1120                     self.write_expr(module, expr, func_ctx)?;
1121                     writeln!(self.out, ";")?;
1122 
1123                     // for entry point returns, we may need to reshuffle the outputs into a different struct
1124                     let ep_output = match func_ctx.ty {
1125                         back::FunctionType::Function(_) => None,
1126                         back::FunctionType::EntryPoint(index) => {
1127                             self.entry_point_io[index as usize].output.as_ref()
1128                         }
1129                     };
1130                     let final_name = match ep_output {
1131                         Some(ep_output) => {
1132                             let final_name = self.namer.call(&variable_name);
1133                             write!(
1134                                 self.out,
1135                                 "{}const {} {} = {{ ",
1136                                 level, ep_output.ty_name, final_name,
1137                             )?;
1138                             for (index, m) in ep_output.members.iter().enumerate() {
1139                                 if index != 0 {
1140                                     write!(self.out, ", ")?;
1141                                 }
1142                                 let member_name = &self.names[&NameKey::StructMember(ty, m.index)];
1143                                 write!(self.out, "{}.{}", variable_name, member_name)?;
1144                             }
1145                             writeln!(self.out, " }};")?;
1146                             final_name
1147                         }
1148                         None => variable_name,
1149                     };
1150                     writeln!(self.out, "{}return {};", level, final_name)?;
1151                 } else {
1152                     write!(self.out, "{}return ", level)?;
1153                     self.write_expr(module, expr, func_ctx)?;
1154                     writeln!(self.out, ";")?
1155                 }
1156             }
1157             Statement::Store { pointer, value } => {
1158                 let ty_inner = func_ctx.info[pointer].ty.inner_with(&module.types);
1159                 let array_info = match *ty_inner {
1160                     TypeInner::Pointer { base, .. } => match module.types[base].inner {
1161                         crate::TypeInner::Array {
1162                             size: crate::ArraySize::Constant(ch),
1163                             ..
1164                         } => Some((ch, base)),
1165                         _ => None,
1166                     },
1167                     _ => None,
1168                 };
1169 
1170                 if let Some(crate::StorageClass::Storage { .. }) = ty_inner.pointer_class() {
1171                     let var_handle = self.fill_access_chain(module, pointer, func_ctx)?;
1172                     self.write_storage_store(
1173                         module,
1174                         var_handle,
1175                         StoreValue::Expression(value),
1176                         func_ctx,
1177                         level,
1178                     )?;
1179                 } else if let Some((const_handle, base_ty)) = array_info {
1180                     let size = module.constants[const_handle].to_array_length().unwrap();
1181                     writeln!(self.out, "{}{{", level)?;
1182                     write!(self.out, "{}", level.next())?;
1183                     self.write_type(module, base_ty)?;
1184                     write!(self.out, " _result[{}]=", size)?;
1185                     self.write_expr(module, value, func_ctx)?;
1186                     writeln!(self.out, ";")?;
1187                     write!(
1188                         self.out,
1189                         "{}for(int _i=0; _i<{}; ++_i) ",
1190                         level.next(),
1191                         size
1192                     )?;
1193                     self.write_expr(module, pointer, func_ctx)?;
1194                     writeln!(self.out, "[_i] = _result[_i];")?;
1195                     writeln!(self.out, "{}}}", level)?;
1196                 } else {
1197                     write!(self.out, "{}", level)?;
1198                     self.write_expr(module, pointer, func_ctx)?;
1199                     write!(self.out, " = ")?;
1200                     self.write_expr(module, value, func_ctx)?;
1201                     writeln!(self.out, ";")?
1202                 }
1203             }
1204             Statement::Loop {
1205                 ref body,
1206                 ref continuing,
1207             } => {
1208                 let l2 = level.next();
1209                 if !continuing.is_empty() {
1210                     let gate_name = self.namer.call("loop_init");
1211                     writeln!(self.out, "{}bool {} = true;", level, gate_name)?;
1212                     writeln!(self.out, "{}while(true) {{", level)?;
1213                     writeln!(self.out, "{}if (!{}) {{", l2, gate_name)?;
1214                     for sta in continuing.iter() {
1215                         self.write_stmt(module, sta, func_ctx, l2)?;
1216                     }
1217                     writeln!(self.out, "{}}}", level.next())?;
1218                     writeln!(self.out, "{}{} = false;", level.next(), gate_name)?;
1219                 } else {
1220                     writeln!(self.out, "{}while(true) {{", level)?;
1221                 }
1222 
1223                 for sta in body.iter() {
1224                     self.write_stmt(module, sta, func_ctx, l2)?;
1225                 }
1226                 writeln!(self.out, "{}}}", level)?
1227             }
1228             Statement::Break => writeln!(self.out, "{}break;", level)?,
1229             Statement::Continue => writeln!(self.out, "{}continue;", level)?,
1230             Statement::Barrier(barrier) => {
1231                 if barrier.contains(crate::Barrier::STORAGE) {
1232                     writeln!(self.out, "{}DeviceMemoryBarrierWithGroupSync();", level)?;
1233                 }
1234 
1235                 if barrier.contains(crate::Barrier::WORK_GROUP) {
1236                     writeln!(self.out, "{}GroupMemoryBarrierWithGroupSync();", level)?;
1237                 }
1238             }
1239             Statement::ImageStore {
1240                 image,
1241                 coordinate,
1242                 array_index,
1243                 value,
1244             } => {
1245                 write!(self.out, "{}", level)?;
1246                 self.write_expr(module, image, func_ctx)?;
1247 
1248                 write!(self.out, "[")?;
1249                 if let Some(index) = array_index {
1250                     // Array index accepted only for texture_storage_2d_array, so we can safety use int3(coordinate, array_index) here
1251                     write!(self.out, "int3(")?;
1252                     self.write_expr(module, coordinate, func_ctx)?;
1253                     write!(self.out, ", ")?;
1254                     self.write_expr(module, index, func_ctx)?;
1255                     write!(self.out, ")")?;
1256                 } else {
1257                     self.write_expr(module, coordinate, func_ctx)?;
1258                 }
1259                 write!(self.out, "]")?;
1260 
1261                 write!(self.out, " = ")?;
1262                 self.write_expr(module, value, func_ctx)?;
1263                 writeln!(self.out, ";")?;
1264             }
1265             Statement::Call {
1266                 function,
1267                 ref arguments,
1268                 result,
1269             } => {
1270                 write!(self.out, "{}", level)?;
1271                 if let Some(expr) = result {
1272                     write!(self.out, "const ")?;
1273                     let name = format!("{}{}", back::BAKE_PREFIX, expr.index());
1274                     let expr_ty = &func_ctx.info[expr].ty;
1275                     match *expr_ty {
1276                         proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
1277                         proc::TypeResolution::Value(ref value) => {
1278                             self.write_value_type(module, value)?
1279                         }
1280                     };
1281                     write!(self.out, " {} = ", name)?;
1282                     self.named_expressions.insert(expr, name);
1283                 }
1284                 let func_name = &self.names[&NameKey::Function(function)];
1285                 write!(self.out, "{}(", func_name)?;
1286                 for (index, argument) in arguments.iter().enumerate() {
1287                     self.write_expr(module, *argument, func_ctx)?;
1288                     // Only write a comma if isn't the last element
1289                     if index != arguments.len().saturating_sub(1) {
1290                         // The leading space is for readability only
1291                         write!(self.out, ", ")?;
1292                     }
1293                 }
1294                 writeln!(self.out, ");")?
1295             }
1296             Statement::Atomic {
1297                 pointer,
1298                 ref fun,
1299                 value,
1300                 result,
1301             } => {
1302                 write!(self.out, "{}", level)?;
1303                 let res_name = format!("{}{}", back::BAKE_PREFIX, result.index());
1304                 match func_ctx.info[result].ty {
1305                     proc::TypeResolution::Handle(handle) => self.write_type(module, handle)?,
1306                     proc::TypeResolution::Value(ref value) => {
1307                         self.write_value_type(module, value)?
1308                     }
1309                 };
1310 
1311                 let var_handle = self.fill_access_chain(module, pointer, func_ctx)?;
1312                 // working around the borrow checker in `self.write_expr`
1313                 let chain = mem::take(&mut self.temp_access_chain);
1314                 let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
1315 
1316                 let fun_str = fun.to_hlsl_suffix();
1317                 write!(
1318                     self.out,
1319                     " {}; {}.Interlocked{}(",
1320                     res_name, var_name, fun_str
1321                 )?;
1322                 self.write_storage_address(module, &chain, func_ctx)?;
1323                 write!(self.out, ", ")?;
1324                 // handle the special cases
1325                 match *fun {
1326                     crate::AtomicFunction::Subtract => {
1327                         // we just wrote `InterlockedAdd`, so negate the argument
1328                         write!(self.out, "-")?;
1329                     }
1330                     crate::AtomicFunction::Exchange { compare: Some(_) } => {
1331                         return Err(Error::Unimplemented("atomic CompareExchange".to_string()));
1332                     }
1333                     _ => {}
1334                 }
1335                 self.write_expr(module, value, func_ctx)?;
1336                 writeln!(self.out, ", {});", res_name)?;
1337                 self.temp_access_chain = chain;
1338                 self.named_expressions.insert(result, res_name);
1339             }
1340             Statement::Switch {
1341                 selector,
1342                 ref cases,
1343             } => {
1344                 // Start the switch
1345                 write!(self.out, "{}", level)?;
1346                 write!(self.out, "switch(")?;
1347                 self.write_expr(module, selector, func_ctx)?;
1348                 writeln!(self.out, ") {{")?;
1349                 let type_postfix = match *func_ctx.info[selector].ty.inner_with(&module.types) {
1350                     crate::TypeInner::Scalar {
1351                         kind: crate::ScalarKind::Uint,
1352                         ..
1353                     } => "u",
1354                     _ => "",
1355                 };
1356 
1357                 // Write all cases
1358                 let indent_level_1 = level.next();
1359                 let indent_level_2 = indent_level_1.next();
1360 
1361                 for case in cases {
1362                     match case.value {
1363                         crate::SwitchValue::Integer(value) => writeln!(
1364                             self.out,
1365                             "{}case {}{}: {{",
1366                             indent_level_1, value, type_postfix
1367                         )?,
1368                         crate::SwitchValue::Default => {
1369                             writeln!(self.out, "{}default: {{", indent_level_1)?
1370                         }
1371                     }
1372 
1373                     if case.fall_through {
1374                         // Generate each fallthrough case statement in a new block. This is done to
1375                         // prevent symbol collision of variables declared in these cases statements.
1376                         writeln!(self.out, "{}/* fallthrough */", indent_level_2)?;
1377                         writeln!(self.out, "{}{{", indent_level_2)?;
1378                     }
1379                     for sta in case.body.iter() {
1380                         self.write_stmt(
1381                             module,
1382                             sta,
1383                             func_ctx,
1384                             back::Level(indent_level_2.0 + usize::from(case.fall_through)),
1385                         )?;
1386                     }
1387 
1388                     if case.fall_through {
1389                         writeln!(self.out, "{}}}", indent_level_2)?;
1390                     } else if case.body.last().map_or(true, |s| !s.is_terminator()) {
1391                         writeln!(self.out, "{}break;", indent_level_2)?;
1392                     }
1393 
1394                     writeln!(self.out, "{}}}", indent_level_1)?;
1395                 }
1396 
1397                 writeln!(self.out, "{}}}", level)?
1398             }
1399         }
1400 
1401         Ok(())
1402     }
1403 
1404     /// Helper method to write expressions
1405     ///
1406     /// # Notes
1407     /// Doesn't add any newlines or leading/trailing spaces
write_expr( &mut self, module: &Module, expr: Handle<crate::Expression>, func_ctx: &back::FunctionCtx<'_>, ) -> BackendResult1408     pub(super) fn write_expr(
1409         &mut self,
1410         module: &Module,
1411         expr: Handle<crate::Expression>,
1412         func_ctx: &back::FunctionCtx<'_>,
1413     ) -> BackendResult {
1414         use crate::Expression;
1415 
1416         // Handle the special semantics for base vertex/instance
1417         let ff_input = if self.options.special_constants_binding.is_some() {
1418             func_ctx.is_fixed_function_input(expr, module)
1419         } else {
1420             None
1421         };
1422         let closing_bracket = match ff_input {
1423             Some(crate::BuiltIn::VertexIndex) => {
1424                 write!(self.out, "({}.{} + ", SPECIAL_CBUF_VAR, SPECIAL_BASE_VERTEX)?;
1425                 ")"
1426             }
1427             Some(crate::BuiltIn::InstanceIndex) => {
1428                 write!(
1429                     self.out,
1430                     "({}.{} + ",
1431                     SPECIAL_CBUF_VAR, SPECIAL_BASE_INSTANCE,
1432                 )?;
1433                 ")"
1434             }
1435             Some(crate::BuiltIn::NumWorkGroups) => {
1436                 //Note: despite their names (`BASE_VERTEX` and `BASE_INSTANCE`),
1437                 // in compute shaders the special constants contain the number
1438                 // of workgroups, which we are using here.
1439                 write!(
1440                     self.out,
1441                     "uint3({}.{}, {}.{}, {}.{})",
1442                     SPECIAL_CBUF_VAR,
1443                     SPECIAL_BASE_VERTEX,
1444                     SPECIAL_CBUF_VAR,
1445                     SPECIAL_BASE_INSTANCE,
1446                     SPECIAL_CBUF_VAR,
1447                     SPECIAL_OTHER,
1448                 )?;
1449                 return Ok(());
1450             }
1451             _ => "",
1452         };
1453 
1454         if let Some(name) = self.named_expressions.get(&expr) {
1455             write!(self.out, "{}{}", name, closing_bracket)?;
1456             return Ok(());
1457         }
1458 
1459         let expression = &func_ctx.expressions[expr];
1460 
1461         match *expression {
1462             Expression::Constant(constant) => self.write_constant(module, constant)?,
1463             Expression::Compose { ty, ref components } => {
1464                 let (brace_open, brace_close) = match module.types[ty].inner {
1465                     TypeInner::Struct { .. } => {
1466                         self.write_wrapped_constructor_function_name(WrappedConstructor { ty })?;
1467                         ("(", ")")
1468                     }
1469                     TypeInner::Array { .. } => ("{ ", " }"),
1470                     _ => {
1471                         self.write_type(module, ty)?;
1472                         ("(", ")")
1473                     }
1474                 };
1475 
1476                 write!(self.out, "{}", brace_open)?;
1477 
1478                 for (index, &component) in components.iter().enumerate() {
1479                     if index != 0 {
1480                         // The leading space is for readability only
1481                         write!(self.out, ", ")?;
1482                     }
1483                     self.write_expr(module, component, func_ctx)?;
1484                 }
1485 
1486                 write!(self.out, "{}", brace_close)?;
1487             }
1488             // All of the multiplication can be expressed as `mul`,
1489             // except vector * vector, which needs to use the "*" operator.
1490             Expression::Binary {
1491                 op: crate::BinaryOperator::Multiply,
1492                 left,
1493                 right,
1494             } if func_ctx.info[left].ty.inner_with(&module.types).is_matrix()
1495                 || func_ctx.info[right]
1496                     .ty
1497                     .inner_with(&module.types)
1498                     .is_matrix() =>
1499             {
1500                 // We intentionally flip the order of multiplication as our matrices are implicitly transposed.
1501                 write!(self.out, "mul(")?;
1502                 self.write_expr(module, right, func_ctx)?;
1503                 write!(self.out, ", ")?;
1504                 self.write_expr(module, left, func_ctx)?;
1505                 write!(self.out, ")")?;
1506             }
1507             Expression::Binary { op, left, right } => {
1508                 write!(self.out, "(")?;
1509                 self.write_expr(module, left, func_ctx)?;
1510                 write!(self.out, " {} ", crate::back::binary_operation_str(op))?;
1511                 self.write_expr(module, right, func_ctx)?;
1512                 write!(self.out, ")")?;
1513             }
1514             Expression::Access { base, index } => {
1515                 if let Some(crate::StorageClass::Storage { .. }) = func_ctx.info[expr]
1516                     .ty
1517                     .inner_with(&module.types)
1518                     .pointer_class()
1519                 {
1520                     // do nothing, the chain is written on `Load`/`Store`
1521                 } else {
1522                     self.write_expr(module, base, func_ctx)?;
1523                     write!(self.out, "[")?;
1524                     self.write_expr(module, index, func_ctx)?;
1525                     write!(self.out, "]")?;
1526                 }
1527             }
1528             Expression::AccessIndex { base, index } => {
1529                 if let Some(crate::StorageClass::Storage { .. }) = func_ctx.info[expr]
1530                     .ty
1531                     .inner_with(&module.types)
1532                     .pointer_class()
1533                 {
1534                     // do nothing, the chain is written on `Load`/`Store`
1535                 } else {
1536                     self.write_expr(module, base, func_ctx)?;
1537 
1538                     let base_ty_res = &func_ctx.info[base].ty;
1539                     let mut resolved = base_ty_res.inner_with(&module.types);
1540                     let base_ty_handle = match *resolved {
1541                         TypeInner::Pointer { base, class: _ } => {
1542                             resolved = &module.types[base].inner;
1543                             Some(base)
1544                         }
1545                         _ => base_ty_res.handle(),
1546                     };
1547 
1548                     match *resolved {
1549                         TypeInner::Vector { .. } => {
1550                             // Write vector access as a swizzle
1551                             write!(self.out, ".{}", back::COMPONENTS[index as usize])?
1552                         }
1553                         TypeInner::Matrix { .. }
1554                         | TypeInner::Array { .. }
1555                         | TypeInner::ValuePointer { .. } => write!(self.out, "[{}]", index)?,
1556                         TypeInner::Struct { .. } => {
1557                             // This will never panic in case the type is a `Struct`, this is not true
1558                             // for other types so we can only check while inside this match arm
1559                             let ty = base_ty_handle.unwrap();
1560 
1561                             write!(
1562                                 self.out,
1563                                 ".{}",
1564                                 &self.names[&NameKey::StructMember(ty, index)]
1565                             )?
1566                         }
1567                         ref other => {
1568                             return Err(Error::Custom(format!("Cannot index {:?}", other)))
1569                         }
1570                     }
1571                 }
1572             }
1573             Expression::FunctionArgument(pos) => {
1574                 let key = match func_ctx.ty {
1575                     back::FunctionType::Function(handle) => NameKey::FunctionArgument(handle, pos),
1576                     back::FunctionType::EntryPoint(index) => {
1577                         NameKey::EntryPointArgument(index, pos)
1578                     }
1579                 };
1580                 let name = &self.names[&key];
1581                 write!(self.out, "{}", name)?;
1582             }
1583             Expression::ImageSample {
1584                 image,
1585                 sampler,
1586                 gather,
1587                 coordinate,
1588                 array_index,
1589                 offset,
1590                 level,
1591                 depth_ref,
1592             } => {
1593                 use crate::SampleLevel as Sl;
1594                 const COMPONENTS: [&str; 4] = ["", "Green", "Blue", "Alpha"];
1595 
1596                 let (base_str, component_str) = match gather {
1597                     Some(component) => ("Gather", COMPONENTS[component as usize]),
1598                     None => ("Sample", ""),
1599                 };
1600                 let cmp_str = match depth_ref {
1601                     Some(_) => "Cmp",
1602                     None => "",
1603                 };
1604                 let level_str = match level {
1605                     Sl::Zero if gather.is_none() => "LevelZero",
1606                     Sl::Auto | Sl::Zero => "",
1607                     Sl::Exact(_) => "Level",
1608                     Sl::Bias(_) => "Bias",
1609                     Sl::Gradient { .. } => "Grad",
1610                 };
1611 
1612                 self.write_expr(module, image, func_ctx)?;
1613                 write!(
1614                     self.out,
1615                     ".{}{}{}{}(",
1616                     base_str, cmp_str, component_str, level_str
1617                 )?;
1618                 self.write_expr(module, sampler, func_ctx)?;
1619                 write!(self.out, ", ")?;
1620                 self.write_texture_coordinates(
1621                     "float",
1622                     coordinate,
1623                     array_index,
1624                     MipLevelCoordinate::NotApplicable,
1625                     module,
1626                     func_ctx,
1627                 )?;
1628 
1629                 if let Some(depth_ref) = depth_ref {
1630                     write!(self.out, ", ")?;
1631                     self.write_expr(module, depth_ref, func_ctx)?;
1632                 }
1633 
1634                 match level {
1635                     Sl::Auto | Sl::Zero => {}
1636                     Sl::Exact(expr) => {
1637                         write!(self.out, ", ")?;
1638                         self.write_expr(module, expr, func_ctx)?;
1639                     }
1640                     Sl::Bias(expr) => {
1641                         write!(self.out, ", ")?;
1642                         self.write_expr(module, expr, func_ctx)?;
1643                     }
1644                     Sl::Gradient { x, y } => {
1645                         write!(self.out, ", ")?;
1646                         self.write_expr(module, x, func_ctx)?;
1647                         write!(self.out, ", ")?;
1648                         self.write_expr(module, y, func_ctx)?;
1649                     }
1650                 }
1651 
1652                 if let Some(offset) = offset {
1653                     write!(self.out, ", ")?;
1654                     self.write_constant(module, offset)?;
1655                 }
1656 
1657                 write!(self.out, ")")?;
1658             }
1659             Expression::ImageQuery { image, query } => {
1660                 // use wrapped image query function
1661                 if let TypeInner::Image {
1662                     dim,
1663                     arrayed,
1664                     class,
1665                 } = *func_ctx.info[image].ty.inner_with(&module.types)
1666                 {
1667                     let wrapped_image_query = WrappedImageQuery {
1668                         dim,
1669                         arrayed,
1670                         class,
1671                         query: query.into(),
1672                     };
1673 
1674                     self.write_wrapped_image_query_function_name(wrapped_image_query)?;
1675                     write!(self.out, "(")?;
1676                     // Image always first param
1677                     self.write_expr(module, image, func_ctx)?;
1678                     if let crate::ImageQuery::Size { level: Some(level) } = query {
1679                         write!(self.out, ", ")?;
1680                         self.write_expr(module, level, func_ctx)?;
1681                     }
1682                     write!(self.out, ")")?;
1683                 }
1684             }
1685             Expression::ImageLoad {
1686                 image,
1687                 coordinate,
1688                 array_index,
1689                 index,
1690             } => {
1691                 // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-to-load
1692                 let (ms, storage) = match *func_ctx.info[image].ty.inner_with(&module.types) {
1693                     TypeInner::Image { class, .. } => match class {
1694                         crate::ImageClass::Sampled { multi, .. }
1695                         | crate::ImageClass::Depth { multi } => (multi, false),
1696                         crate::ImageClass::Storage { .. } => (false, true),
1697                     },
1698                     _ => (false, false),
1699                 };
1700 
1701                 self.write_expr(module, image, func_ctx)?;
1702                 write!(self.out, ".Load(")?;
1703 
1704                 let mip_level = if ms || storage {
1705                     MipLevelCoordinate::NotApplicable
1706                 } else {
1707                     match index {
1708                         Some(expr) => MipLevelCoordinate::Expression(expr),
1709                         None => MipLevelCoordinate::Zero,
1710                     }
1711                 };
1712 
1713                 self.write_texture_coordinates(
1714                     "int",
1715                     coordinate,
1716                     array_index,
1717                     mip_level,
1718                     module,
1719                     func_ctx,
1720                 )?;
1721 
1722                 if ms {
1723                     write!(self.out, ", ")?;
1724                     self.write_expr(module, index.unwrap(), func_ctx)?;
1725                 }
1726 
1727                 // close bracket for Load function
1728                 write!(self.out, ")")?;
1729 
1730                 // return x component if return type is scalar
1731                 if let TypeInner::Scalar { .. } = *func_ctx.info[expr].ty.inner_with(&module.types)
1732                 {
1733                     write!(self.out, ".x")?;
1734                 }
1735             }
1736             Expression::GlobalVariable(handle) => match module.global_variables[handle].class {
1737                 crate::StorageClass::Storage { .. } => {}
1738                 _ => {
1739                     let name = &self.names[&NameKey::GlobalVariable(handle)];
1740                     write!(self.out, "{}", name)?;
1741                 }
1742             },
1743             Expression::LocalVariable(handle) => {
1744                 write!(self.out, "{}", self.names[&func_ctx.name_key(handle)])?
1745             }
1746             Expression::Load { pointer } => {
1747                 match func_ctx.info[pointer]
1748                     .ty
1749                     .inner_with(&module.types)
1750                     .pointer_class()
1751                 {
1752                     Some(crate::StorageClass::Storage { .. }) => {
1753                         let var_handle = self.fill_access_chain(module, pointer, func_ctx)?;
1754                         let result_ty = func_ctx.info[expr].ty.clone();
1755                         self.write_storage_load(module, var_handle, result_ty, func_ctx)?;
1756                     }
1757                     _ => {
1758                         self.write_expr(module, pointer, func_ctx)?;
1759                     }
1760                 }
1761             }
1762             Expression::Unary { op, expr } => {
1763                 // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-operators#unary-operators
1764                 let op_str = match op {
1765                     crate::UnaryOperator::Negate => "-",
1766                     crate::UnaryOperator::Not => "!",
1767                 };
1768                 write!(self.out, "{}", op_str)?;
1769                 self.write_expr(module, expr, func_ctx)?;
1770             }
1771             Expression::As {
1772                 expr,
1773                 kind,
1774                 convert,
1775             } => {
1776                 let inner = func_ctx.info[expr].ty.inner_with(&module.types);
1777                 let (size_str, src_width) = match *inner {
1778                     TypeInner::Vector { size, width, .. } => (back::vector_size_str(size), width),
1779                     TypeInner::Scalar { width, .. } => ("", width),
1780                     _ => {
1781                         return Err(Error::Unimplemented(format!(
1782                             "write_expr expression::as {:?}",
1783                             inner
1784                         )));
1785                     }
1786                 };
1787                 let kind_str = kind.to_hlsl_str(convert.unwrap_or(src_width))?;
1788                 write!(self.out, "{}{}(", kind_str, size_str,)?;
1789                 self.write_expr(module, expr, func_ctx)?;
1790                 write!(self.out, ")")?;
1791             }
1792             Expression::Math {
1793                 fun,
1794                 arg,
1795                 arg1,
1796                 arg2,
1797                 arg3,
1798             } => {
1799                 use crate::MathFunction as Mf;
1800 
1801                 enum Function {
1802                     Asincosh { is_sin: bool },
1803                     Atanh,
1804                     Regular(&'static str),
1805                 }
1806 
1807                 let fun = match fun {
1808                     // comparison
1809                     Mf::Abs => Function::Regular("abs"),
1810                     Mf::Min => Function::Regular("min"),
1811                     Mf::Max => Function::Regular("max"),
1812                     Mf::Clamp => Function::Regular("clamp"),
1813                     // trigonometry
1814                     Mf::Cos => Function::Regular("cos"),
1815                     Mf::Cosh => Function::Regular("cosh"),
1816                     Mf::Sin => Function::Regular("sin"),
1817                     Mf::Sinh => Function::Regular("sinh"),
1818                     Mf::Tan => Function::Regular("tan"),
1819                     Mf::Tanh => Function::Regular("tanh"),
1820                     Mf::Acos => Function::Regular("acos"),
1821                     Mf::Asin => Function::Regular("asin"),
1822                     Mf::Atan => Function::Regular("atan"),
1823                     Mf::Atan2 => Function::Regular("atan2"),
1824                     Mf::Asinh => Function::Asincosh { is_sin: true },
1825                     Mf::Acosh => Function::Asincosh { is_sin: false },
1826                     Mf::Atanh => Function::Atanh,
1827                     Mf::Radians => Function::Regular("radians"),
1828                     Mf::Degrees => Function::Regular("degrees"),
1829                     // decomposition
1830                     Mf::Ceil => Function::Regular("ceil"),
1831                     Mf::Floor => Function::Regular("floor"),
1832                     Mf::Round => Function::Regular("round"),
1833                     Mf::Fract => Function::Regular("frac"),
1834                     Mf::Trunc => Function::Regular("trunc"),
1835                     Mf::Modf => Function::Regular("modf"),
1836                     Mf::Frexp => Function::Regular("frexp"),
1837                     Mf::Ldexp => Function::Regular("ldexp"),
1838                     // exponent
1839                     Mf::Exp => Function::Regular("exp"),
1840                     Mf::Exp2 => Function::Regular("exp2"),
1841                     Mf::Log => Function::Regular("log"),
1842                     Mf::Log2 => Function::Regular("log2"),
1843                     Mf::Pow => Function::Regular("pow"),
1844                     // geometry
1845                     Mf::Dot => Function::Regular("dot"),
1846                     //Mf::Outer => ,
1847                     Mf::Cross => Function::Regular("cross"),
1848                     Mf::Distance => Function::Regular("distance"),
1849                     Mf::Length => Function::Regular("length"),
1850                     Mf::Normalize => Function::Regular("normalize"),
1851                     Mf::FaceForward => Function::Regular("faceforward"),
1852                     Mf::Reflect => Function::Regular("reflect"),
1853                     Mf::Refract => Function::Regular("refract"),
1854                     // computational
1855                     Mf::Sign => Function::Regular("sign"),
1856                     Mf::Fma => Function::Regular("mad"),
1857                     Mf::Mix => Function::Regular("lerp"),
1858                     Mf::Step => Function::Regular("step"),
1859                     Mf::SmoothStep => Function::Regular("smoothstep"),
1860                     Mf::Sqrt => Function::Regular("sqrt"),
1861                     Mf::InverseSqrt => Function::Regular("rsqrt"),
1862                     //Mf::Inverse =>,
1863                     Mf::Transpose => Function::Regular("transpose"),
1864                     Mf::Determinant => Function::Regular("determinant"),
1865                     // bits
1866                     Mf::CountOneBits => Function::Regular("countbits"),
1867                     Mf::ReverseBits => Function::Regular("reversebits"),
1868                     Mf::FindLsb => Function::Regular("firstbitlow"),
1869                     Mf::FindMsb => Function::Regular("firstbithigh"),
1870                     _ => return Err(Error::Unimplemented(format!("write_expr_math {:?}", fun))),
1871                 };
1872 
1873                 match fun {
1874                     Function::Asincosh { is_sin } => {
1875                         write!(self.out, "log(")?;
1876                         self.write_expr(module, arg, func_ctx)?;
1877                         write!(self.out, " + sqrt(")?;
1878                         self.write_expr(module, arg, func_ctx)?;
1879                         write!(self.out, " * ")?;
1880                         self.write_expr(module, arg, func_ctx)?;
1881                         match is_sin {
1882                             true => write!(self.out, " + 1.0))")?,
1883                             false => write!(self.out, " - 1.0))")?,
1884                         }
1885                     }
1886                     Function::Atanh => {
1887                         write!(self.out, "0.5 * log((1.0 + ")?;
1888                         self.write_expr(module, arg, func_ctx)?;
1889                         write!(self.out, ") / (1.0 - ")?;
1890                         self.write_expr(module, arg, func_ctx)?;
1891                         write!(self.out, "))")?;
1892                     }
1893                     Function::Regular(fun_name) => {
1894                         write!(self.out, "{}(", fun_name)?;
1895                         self.write_expr(module, arg, func_ctx)?;
1896                         if let Some(arg) = arg1 {
1897                             write!(self.out, ", ")?;
1898                             self.write_expr(module, arg, func_ctx)?;
1899                         }
1900                         if let Some(arg) = arg2 {
1901                             write!(self.out, ", ")?;
1902                             self.write_expr(module, arg, func_ctx)?;
1903                         }
1904                         if let Some(arg) = arg3 {
1905                             write!(self.out, ", ")?;
1906                             self.write_expr(module, arg, func_ctx)?;
1907                         }
1908                         write!(self.out, ")")?
1909                     }
1910                 }
1911             }
1912             Expression::Swizzle {
1913                 size,
1914                 vector,
1915                 pattern,
1916             } => {
1917                 self.write_expr(module, vector, func_ctx)?;
1918                 write!(self.out, ".")?;
1919                 for &sc in pattern[..size as usize].iter() {
1920                     self.out.write_char(back::COMPONENTS[sc as usize])?;
1921                 }
1922             }
1923             Expression::ArrayLength(expr) => {
1924                 let var_handle = match func_ctx.expressions[expr] {
1925                     Expression::AccessIndex { base, index: _ } => {
1926                         match func_ctx.expressions[base] {
1927                             Expression::GlobalVariable(handle) => handle,
1928                             _ => unreachable!(),
1929                         }
1930                     }
1931                     Expression::GlobalVariable(handle) => handle,
1932                     _ => unreachable!(),
1933                 };
1934 
1935                 let var = &module.global_variables[var_handle];
1936                 let (offset, stride) = match module.types[var.ty].inner {
1937                     TypeInner::Array { stride, .. } => (0, stride),
1938                     TypeInner::Struct { ref members, .. } => {
1939                         let last = members.last().unwrap();
1940                         let stride = match module.types[last.ty].inner {
1941                             TypeInner::Array { stride, .. } => stride,
1942                             _ => unreachable!(),
1943                         };
1944                         (last.offset, stride)
1945                     }
1946                     _ => unreachable!(),
1947                 };
1948 
1949                 let storage_access = match var.class {
1950                     crate::StorageClass::Storage { access } => access,
1951                     _ => crate::StorageAccess::default(),
1952                 };
1953                 let wrapped_array_length = WrappedArrayLength {
1954                     writable: storage_access.contains(crate::StorageAccess::STORE),
1955                 };
1956 
1957                 write!(self.out, "((")?;
1958                 self.write_wrapped_array_length_function_name(wrapped_array_length)?;
1959                 let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
1960                 write!(self.out, "({}) - {}) / {})", var_name, offset, stride)?
1961             }
1962             Expression::Derivative { axis, expr } => {
1963                 use crate::DerivativeAxis as Da;
1964 
1965                 let fun_str = match axis {
1966                     Da::X => "ddx",
1967                     Da::Y => "ddy",
1968                     Da::Width => "fwidth",
1969                 };
1970                 write!(self.out, "{}(", fun_str)?;
1971                 self.write_expr(module, expr, func_ctx)?;
1972                 write!(self.out, ")")?
1973             }
1974             Expression::Relational { fun, argument } => {
1975                 use crate::RelationalFunction as Rf;
1976 
1977                 let fun_str = match fun {
1978                     Rf::All => "all",
1979                     Rf::Any => "any",
1980                     Rf::IsNan => "isnan",
1981                     Rf::IsInf => "isinf",
1982                     Rf::IsFinite => "isfinite",
1983                     Rf::IsNormal => "isnormal",
1984                 };
1985                 write!(self.out, "{}(", fun_str)?;
1986                 self.write_expr(module, argument, func_ctx)?;
1987                 write!(self.out, ")")?
1988             }
1989             Expression::Splat { size, value } => {
1990                 // hlsl is not supported one value constructor
1991                 // if we write, for example, int4(0), dxc returns error:
1992                 // error: too few elements in vector initialization (expected 4 elements, have 1)
1993                 let number_of_components = match size {
1994                     crate::VectorSize::Bi => "xx",
1995                     crate::VectorSize::Tri => "xxx",
1996                     crate::VectorSize::Quad => "xxxx",
1997                 };
1998                 let resolved = func_ctx.info[expr].ty.inner_with(&module.types);
1999                 self.write_value_type(module, resolved)?;
2000                 write!(self.out, "(")?;
2001                 self.write_expr(module, value, func_ctx)?;
2002                 write!(self.out, ".{})", number_of_components)?
2003             }
2004             Expression::Select {
2005                 condition,
2006                 accept,
2007                 reject,
2008             } => {
2009                 write!(self.out, "(")?;
2010                 self.write_expr(module, condition, func_ctx)?;
2011                 write!(self.out, " ? ")?;
2012                 self.write_expr(module, accept, func_ctx)?;
2013                 write!(self.out, " : ")?;
2014                 self.write_expr(module, reject, func_ctx)?;
2015                 write!(self.out, ")")?
2016             }
2017             // Nothing to do here, since call expression already cached
2018             Expression::CallResult(_) | Expression::AtomicResult { .. } => {}
2019         }
2020 
2021         if !closing_bracket.is_empty() {
2022             write!(self.out, "{}", closing_bracket)?;
2023         }
2024         Ok(())
2025     }
2026 
2027     /// Helper method used to write constants
2028     ///
2029     /// # Notes
2030     /// Doesn't add any newlines or leading/trailing spaces
write_constant( &mut self, module: &Module, handle: Handle<crate::Constant>, ) -> BackendResult2031     fn write_constant(
2032         &mut self,
2033         module: &Module,
2034         handle: Handle<crate::Constant>,
2035     ) -> BackendResult {
2036         let constant = &module.constants[handle];
2037         match constant.inner {
2038             crate::ConstantInner::Scalar {
2039                 width: _,
2040                 ref value,
2041             } => {
2042                 if constant.name.is_some() {
2043                     write!(self.out, "{}", &self.names[&NameKey::Constant(handle)])?;
2044                 } else {
2045                     self.write_scalar_value(*value)?;
2046                 }
2047             }
2048             crate::ConstantInner::Composite { ty, ref components } => {
2049                 self.write_composite_constant(module, ty, components)?;
2050             }
2051         }
2052 
2053         Ok(())
2054     }
2055 
write_composite_constant( &mut self, module: &Module, ty: Handle<crate::Type>, components: &[Handle<crate::Constant>], ) -> BackendResult2056     fn write_composite_constant(
2057         &mut self,
2058         module: &Module,
2059         ty: Handle<crate::Type>,
2060         components: &[Handle<crate::Constant>],
2061     ) -> BackendResult {
2062         let (open_b, close_b) = match module.types[ty].inner {
2063             TypeInner::Array { .. } | TypeInner::Struct { .. } => ("{ ", " }"),
2064             _ => {
2065                 // We should write type only for non struct/array constants
2066                 self.write_type(module, ty)?;
2067                 ("(", ")")
2068             }
2069         };
2070         write!(self.out, "{}", open_b)?;
2071         for (index, constant) in components.iter().enumerate() {
2072             self.write_constant(module, *constant)?;
2073             // Only write a comma if isn't the last element
2074             if index != components.len().saturating_sub(1) {
2075                 // The leading space is for readability only
2076                 write!(self.out, ", ")?;
2077             }
2078         }
2079         write!(self.out, "{}", close_b)?;
2080 
2081         Ok(())
2082     }
2083 
2084     /// Helper method used to write [`ScalarValue`](crate::ScalarValue)
2085     ///
2086     /// # Notes
2087     /// Adds no trailing or leading whitespace
write_scalar_value(&mut self, value: crate::ScalarValue) -> BackendResult2088     fn write_scalar_value(&mut self, value: crate::ScalarValue) -> BackendResult {
2089         use crate::ScalarValue as Sv;
2090 
2091         match value {
2092             Sv::Sint(value) => write!(self.out, "{}", value)?,
2093             Sv::Uint(value) => write!(self.out, "{}u", value)?,
2094             // Floats are written using `Debug` instead of `Display` because it always appends the
2095             // decimal part even it's zero
2096             Sv::Float(value) => write!(self.out, "{:?}", value)?,
2097             Sv::Bool(value) => write!(self.out, "{}", value)?,
2098         }
2099 
2100         Ok(())
2101     }
2102 
write_named_expr( &mut self, module: &Module, handle: Handle<crate::Expression>, name: String, ctx: &back::FunctionCtx, ) -> BackendResult2103     fn write_named_expr(
2104         &mut self,
2105         module: &Module,
2106         handle: Handle<crate::Expression>,
2107         name: String,
2108         ctx: &back::FunctionCtx,
2109     ) -> BackendResult {
2110         match ctx.info[handle].ty {
2111             proc::TypeResolution::Handle(ty_handle) => match module.types[ty_handle].inner {
2112                 TypeInner::Struct { .. } => {
2113                     let ty_name = &self.names[&NameKey::Type(ty_handle)];
2114                     write!(self.out, "{}", ty_name)?;
2115                 }
2116                 _ => {
2117                     self.write_type(module, ty_handle)?;
2118                 }
2119             },
2120             proc::TypeResolution::Value(ref inner) => {
2121                 self.write_value_type(module, inner)?;
2122             }
2123         }
2124 
2125         let base_ty_res = &ctx.info[handle].ty;
2126         let resolved = base_ty_res.inner_with(&module.types);
2127 
2128         write!(self.out, " {}", name)?;
2129         // If rhs is a array type, we should write array size
2130         if let TypeInner::Array { size, .. } = *resolved {
2131             self.write_array_size(module, size)?;
2132         }
2133         write!(self.out, " = ")?;
2134         self.write_expr(module, handle, ctx)?;
2135         writeln!(self.out, ";")?;
2136         self.named_expressions.insert(handle, name);
2137 
2138         Ok(())
2139     }
2140 
2141     /// Helper function that write default zero initialization
write_default_init(&mut self, module: &Module, ty: Handle<crate::Type>) -> BackendResult2142     fn write_default_init(&mut self, module: &Module, ty: Handle<crate::Type>) -> BackendResult {
2143         match module.types[ty].inner {
2144             TypeInner::Array {
2145                 size: crate::ArraySize::Constant(const_handle),
2146                 base,
2147                 ..
2148             } => {
2149                 write!(self.out, "{{")?;
2150                 let count = module.constants[const_handle].to_array_length().unwrap();
2151                 for i in 0..count {
2152                     if i != 0 {
2153                         write!(self.out, ",")?;
2154                     }
2155                     self.write_default_init(module, base)?;
2156                 }
2157                 write!(self.out, "}}")?;
2158             }
2159             _ => {
2160                 write!(self.out, "(")?;
2161                 self.write_type(module, ty)?;
2162                 write!(self.out, ")0")?;
2163             }
2164         }
2165         Ok(())
2166     }
2167 }
2168