1use alloc::{format, vec, vec::Vec};
6
7use crate::front::spv::{
8 convert::{map_binary_operator, map_relational_fun},
9 image, resolve_constant, BlockContext, Body, BodyFragment, Constant, Error, Frontend,
10 LookupExpression, LookupHelper as _, LookupLoadOverride, MergeBlockInformation, PhiExpression,
11 SignAnchor,
12};
13use crate::Handle;
14
15impl<I: Iterator<Item = u32>> Frontend<I> {
16 pub(in crate::front::spv) fn next_block(
22 &mut self,
23 block_id: spirv::Word,
24 ctx: &mut BlockContext,
25 ) -> Result<(), Error> {
26 fn merger(body: &mut Body, target: &MergeBlockInformation) {
28 body.data.push(match *target {
29 MergeBlockInformation::LoopContinue => BodyFragment::Continue,
30 MergeBlockInformation::LoopMerge | MergeBlockInformation::SwitchMerge => {
31 BodyFragment::Break
32 }
33
34 MergeBlockInformation::SelectionMerge => return,
37 })
38 }
39
40 let mut emitter = crate::proc::Emitter::default();
41 emitter.start(ctx.expressions);
42
43 let mut body_idx = *ctx.body_for_label.entry(block_id).or_default();
57
58 let mut block = crate::Block::new();
62
63 let mut selection_merge_block = None;
69
70 macro_rules! get_expr_handle {
71 ($id:expr, $lexp:expr) => {
72 self.get_expr_handle($id, $lexp, ctx, &mut emitter, &mut block, body_idx)
73 };
74 }
75 macro_rules! parse_expr_op {
76 ($op:expr, BINARY) => {
77 self.parse_expr_binary_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
78 };
79
80 ($op:expr, SHIFT) => {
81 self.parse_expr_shift_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
82 };
83 ($op:expr, UNARY) => {
84 self.parse_expr_unary_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
85 };
86 ($axis:expr, $ctrl:expr, DERIVATIVE) => {
87 self.parse_expr_derivative(
88 ctx,
89 &mut emitter,
90 &mut block,
91 block_id,
92 body_idx,
93 ($axis, $ctrl),
94 )
95 };
96 }
97
98 let terminator = loop {
99 use spirv::Op;
100 let start = self.data_offset;
101 let inst = self.next_inst()?;
102 let span = crate::Span::from(start..(start + 4 * (inst.wc as usize)));
103 log::debug!("\t\t{:?} [{}]", inst.op, inst.wc);
104
105 match inst.op {
106 Op::Line => {
107 inst.expect(4)?;
108 let _file_id = self.next()?;
109 let _row_id = self.next()?;
110 let _col_id = self.next()?;
111 }
112 Op::NoLine => inst.expect(1)?,
113 Op::Undef => {
114 inst.expect(3)?;
115 let type_id = self.next()?;
116 let id = self.next()?;
117 let type_lookup = self.lookup_type.lookup(type_id)?;
118 let ty = type_lookup.handle;
119
120 self.lookup_expression.insert(
121 id,
122 LookupExpression {
123 handle: ctx
124 .expressions
125 .append(crate::Expression::ZeroValue(ty), span),
126 type_id,
127 block_id,
128 },
129 );
130 }
131 Op::Variable => {
132 inst.expect_at_least(4)?;
133 block.extend(emitter.finish(ctx.expressions));
134
135 let result_type_id = self.next()?;
136 let result_id = self.next()?;
137 let _storage_class = self.next()?;
138 let init = if inst.wc > 4 {
139 inst.expect(5)?;
140 let init_id = self.next()?;
141 let lconst = self.lookup_constant.lookup(init_id)?;
142 Some(ctx.expressions.append(lconst.inner.to_expr(), span))
143 } else {
144 None
145 };
146
147 let name = self
148 .future_decor
149 .remove(&result_id)
150 .and_then(|decor| decor.name);
151 if let Some(ref name) = name {
152 log::debug!("\t\t\tid={result_id} name={name}");
153 }
154 let lookup_ty = self.lookup_type.lookup(result_type_id)?;
155 let var_handle = ctx.local_arena.append(
156 crate::LocalVariable {
157 name,
158 ty: match ctx.module.types[lookup_ty.handle].inner {
159 crate::TypeInner::Pointer { base, .. } => base,
160 _ => lookup_ty.handle,
161 },
162 init,
163 },
164 span,
165 );
166
167 self.lookup_expression.insert(
168 result_id,
169 LookupExpression {
170 handle: ctx
171 .expressions
172 .append(crate::Expression::LocalVariable(var_handle), span),
173 type_id: result_type_id,
174 block_id,
175 },
176 );
177 emitter.start(ctx.expressions);
178 }
179 Op::Phi => {
180 inst.expect_at_least(3)?;
181 block.extend(emitter.finish(ctx.expressions));
182
183 let result_type_id = self.next()?;
184 let result_id = self.next()?;
185
186 let name = format!("phi_{result_id}");
187 let local = ctx.local_arena.append(
188 crate::LocalVariable {
189 name: Some(name),
190 ty: self.lookup_type.lookup(result_type_id)?.handle,
191 init: None,
192 },
193 self.span_from(start),
194 );
195 let pointer = ctx
196 .expressions
197 .append(crate::Expression::LocalVariable(local), span);
198
199 let in_count = (inst.wc - 3) / 2;
200 let mut phi = PhiExpression {
201 local,
202 expressions: Vec::with_capacity(in_count as usize),
203 };
204 for _ in 0..in_count {
205 let expr = self.next()?;
206 let block = self.next()?;
207 phi.expressions.push((expr, block));
208 }
209
210 ctx.phis.push(phi);
211 emitter.start(ctx.expressions);
212
213 self.lookup_expression.insert(
216 result_id,
217 LookupExpression {
218 handle: ctx
219 .expressions
220 .append(crate::Expression::Load { pointer }, span),
221 type_id: result_type_id,
222 block_id,
223 },
224 );
225 }
226 Op::AccessChain | Op::InBoundsAccessChain => {
227 struct AccessExpression {
228 base_handle: Handle<crate::Expression>,
229 type_id: spirv::Word,
230 load_override: Option<LookupLoadOverride>,
231 }
232
233 inst.expect_at_least(4)?;
234
235 let result_type_id = self.next()?;
236 let result_id = self.next()?;
237 let base_id = self.next()?;
238 log::trace!("\t\t\tlooking up expr {base_id:?}");
239
240 let mut acex = {
241 let lexp = self.lookup_expression.lookup(base_id)?;
242 let lty = self.lookup_type.lookup(lexp.type_id)?;
243
244 let dereference = match ctx.module.types[lty.handle].inner {
254 crate::TypeInner::BindingArray { .. } => false,
255 _ => true,
256 };
257
258 let type_id = if dereference {
259 lty.base_id.ok_or(Error::InvalidAccessType(lexp.type_id))?
260 } else {
261 lexp.type_id
262 };
263
264 AccessExpression {
265 base_handle: get_expr_handle!(base_id, lexp),
266 type_id,
267 load_override: self.lookup_load_override.get(&base_id).cloned(),
268 }
269 };
270
271 for _ in 4..inst.wc {
272 let access_id = self.next()?;
273 log::trace!("\t\t\tlooking up index expr {access_id:?}");
274 let index_expr = self.lookup_expression.lookup(access_id)?.clone();
275 let index_expr_handle = get_expr_handle!(access_id, &index_expr);
276 let index_expr_data = &ctx.expressions[index_expr.handle];
277 let index_maybe = match *index_expr_data {
278 crate::Expression::Constant(const_handle) => Some(
279 ctx.gctx()
280 .get_const_val(ctx.module.constants[const_handle].init)
281 .map_err(|_| {
282 Error::InvalidAccess(crate::Expression::Constant(
283 const_handle,
284 ))
285 })?,
286 ),
287 _ => None,
288 };
289
290 log::trace!("\t\t\tlooking up type {:?}", acex.type_id);
291 let type_lookup = self.lookup_type.lookup(acex.type_id)?;
292 let ty = &ctx.module.types[type_lookup.handle];
293 acex = match ty.inner {
294 crate::TypeInner::Struct { ref members, .. } => {
296 let index = index_maybe
297 .ok_or_else(|| Error::InvalidAccess(index_expr_data.clone()))?;
298
299 let lookup_member = self
300 .lookup_member
301 .get(&(type_lookup.handle, index))
302 .ok_or(Error::InvalidAccessType(acex.type_id))?;
303 let base_handle = ctx.expressions.append(
304 crate::Expression::AccessIndex {
305 base: acex.base_handle,
306 index,
307 },
308 span,
309 );
310
311 if let Some(crate::Binding::BuiltIn(built_in)) =
312 members[index as usize].binding
313 {
314 self.gl_per_vertex_builtin_access.insert(built_in);
315 }
316
317 AccessExpression {
318 base_handle,
319 type_id: lookup_member.type_id,
320 load_override: if lookup_member.row_major {
321 debug_assert!(acex.load_override.is_none());
322 let sub_type_lookup =
323 self.lookup_type.lookup(lookup_member.type_id)?;
324 Some(match ctx.module.types[sub_type_lookup.handle].inner {
325 crate::TypeInner::Matrix { .. } => {
327 let loaded = ctx.expressions.append(
328 crate::Expression::Load {
329 pointer: base_handle,
330 },
331 span,
332 );
333 let transposed = ctx.expressions.append(
334 crate::Expression::Math {
335 fun: crate::MathFunction::Transpose,
336 arg: loaded,
337 arg1: None,
338 arg2: None,
339 arg3: None,
340 },
341 span,
342 );
343 LookupLoadOverride::Loaded(transposed)
344 }
345 _ => LookupLoadOverride::Pending,
346 })
347 } else {
348 None
349 },
350 }
351 }
352 crate::TypeInner::Matrix { .. } => {
353 let load_override = match acex.load_override {
354 Some(LookupLoadOverride::Loaded(load_expr)) => {
356 let index = index_maybe.ok_or_else(|| {
357 Error::InvalidAccess(index_expr_data.clone())
358 })?;
359 let sub_handle = ctx.expressions.append(
360 crate::Expression::AccessIndex {
361 base: load_expr,
362 index,
363 },
364 span,
365 );
366 Some(LookupLoadOverride::Loaded(sub_handle))
367 }
368 _ => None,
369 };
370 let sub_expr = match index_maybe {
371 Some(index) => crate::Expression::AccessIndex {
372 base: acex.base_handle,
373 index,
374 },
375 None => crate::Expression::Access {
376 base: acex.base_handle,
377 index: index_expr_handle,
378 },
379 };
380 AccessExpression {
381 base_handle: ctx.expressions.append(sub_expr, span),
382 type_id: type_lookup
383 .base_id
384 .ok_or(Error::InvalidAccessType(acex.type_id))?,
385 load_override,
386 }
387 }
388 _ => {
390 let base_handle = ctx.expressions.append(
391 crate::Expression::Access {
392 base: acex.base_handle,
393 index: index_expr_handle,
394 },
395 span,
396 );
397 let load_override = match acex.load_override {
398 Some(lookup_load_override) => {
401 let sub_expr = match lookup_load_override {
402 LookupLoadOverride::Pending => {
405 let loaded = ctx.expressions.append(
406 crate::Expression::Load {
407 pointer: base_handle,
408 },
409 span,
410 );
411 ctx.expressions.append(
412 crate::Expression::Math {
413 fun: crate::MathFunction::Transpose,
414 arg: loaded,
415 arg1: None,
416 arg2: None,
417 arg3: None,
418 },
419 span,
420 )
421 }
422 LookupLoadOverride::Loaded(load_expr) => {
424 ctx.expressions.append(
425 crate::Expression::Access {
426 base: load_expr,
427 index: index_expr_handle,
428 },
429 span,
430 )
431 }
432 };
433 Some(LookupLoadOverride::Loaded(sub_expr))
434 }
435 None => None,
436 };
437 AccessExpression {
438 base_handle,
439 type_id: type_lookup
440 .base_id
441 .ok_or(Error::InvalidAccessType(acex.type_id))?,
442 load_override,
443 }
444 }
445 };
446 }
447
448 if let Some(load_expr) = acex.load_override {
449 self.lookup_load_override.insert(result_id, load_expr);
450 }
451 let lookup_expression = LookupExpression {
452 handle: acex.base_handle,
453 type_id: result_type_id,
454 block_id,
455 };
456 self.lookup_expression.insert(result_id, lookup_expression);
457 }
458 Op::VectorExtractDynamic => {
459 inst.expect(5)?;
460
461 let result_type_id = self.next()?;
462 let id = self.next()?;
463 let composite_id = self.next()?;
464 let index_id = self.next()?;
465
466 let root_lexp = self.lookup_expression.lookup(composite_id)?;
467 let root_handle = get_expr_handle!(composite_id, root_lexp);
468 let root_type_lookup = self.lookup_type.lookup(root_lexp.type_id)?;
469 let index_lexp = self.lookup_expression.lookup(index_id)?;
470 let index_handle = get_expr_handle!(index_id, index_lexp);
471 let index_type = self.lookup_type.lookup(index_lexp.type_id)?.handle;
472
473 let num_components = match ctx.module.types[root_type_lookup.handle].inner {
474 crate::TypeInner::Vector { size, .. } => size as u32,
475 _ => return Err(Error::InvalidVectorType(root_type_lookup.handle)),
476 };
477
478 let mut make_index = |ctx: &mut BlockContext, index: u32| {
479 make_index_literal(
480 ctx,
481 index,
482 &mut block,
483 &mut emitter,
484 index_type,
485 index_lexp.type_id,
486 span,
487 )
488 };
489
490 let index_expr = make_index(ctx, 0)?;
491 let mut handle = ctx.expressions.append(
492 crate::Expression::Access {
493 base: root_handle,
494 index: index_expr,
495 },
496 span,
497 );
498 for index in 1..num_components {
499 let index_expr = make_index(ctx, index)?;
500 let access_expr = ctx.expressions.append(
501 crate::Expression::Access {
502 base: root_handle,
503 index: index_expr,
504 },
505 span,
506 );
507 let cond = ctx.expressions.append(
508 crate::Expression::Binary {
509 op: crate::BinaryOperator::Equal,
510 left: index_expr,
511 right: index_handle,
512 },
513 span,
514 );
515 handle = ctx.expressions.append(
516 crate::Expression::Select {
517 condition: cond,
518 accept: access_expr,
519 reject: handle,
520 },
521 span,
522 );
523 }
524
525 self.lookup_expression.insert(
526 id,
527 LookupExpression {
528 handle,
529 type_id: result_type_id,
530 block_id,
531 },
532 );
533 }
534 Op::VectorInsertDynamic => {
535 inst.expect(6)?;
536
537 let result_type_id = self.next()?;
538 let id = self.next()?;
539 let composite_id = self.next()?;
540 let object_id = self.next()?;
541 let index_id = self.next()?;
542
543 let object_lexp = self.lookup_expression.lookup(object_id)?;
544 let object_handle = get_expr_handle!(object_id, object_lexp);
545 let root_lexp = self.lookup_expression.lookup(composite_id)?;
546 let root_handle = get_expr_handle!(composite_id, root_lexp);
547 let root_type_lookup = self.lookup_type.lookup(root_lexp.type_id)?;
548 let index_lexp = self.lookup_expression.lookup(index_id)?;
549 let index_handle = get_expr_handle!(index_id, index_lexp);
550 let index_type = self.lookup_type.lookup(index_lexp.type_id)?.handle;
551
552 let num_components = match ctx.module.types[root_type_lookup.handle].inner {
553 crate::TypeInner::Vector { size, .. } => size as u32,
554 _ => return Err(Error::InvalidVectorType(root_type_lookup.handle)),
555 };
556
557 let mut components = Vec::with_capacity(num_components as usize);
558 for index in 0..num_components {
559 let index_expr = make_index_literal(
560 ctx,
561 index,
562 &mut block,
563 &mut emitter,
564 index_type,
565 index_lexp.type_id,
566 span,
567 )?;
568 let access_expr = ctx.expressions.append(
569 crate::Expression::Access {
570 base: root_handle,
571 index: index_expr,
572 },
573 span,
574 );
575 let cond = ctx.expressions.append(
576 crate::Expression::Binary {
577 op: crate::BinaryOperator::Equal,
578 left: index_expr,
579 right: index_handle,
580 },
581 span,
582 );
583 let handle = ctx.expressions.append(
584 crate::Expression::Select {
585 condition: cond,
586 accept: object_handle,
587 reject: access_expr,
588 },
589 span,
590 );
591 components.push(handle);
592 }
593 let handle = ctx.expressions.append(
594 crate::Expression::Compose {
595 ty: root_type_lookup.handle,
596 components,
597 },
598 span,
599 );
600
601 self.lookup_expression.insert(
602 id,
603 LookupExpression {
604 handle,
605 type_id: result_type_id,
606 block_id,
607 },
608 );
609 }
610 Op::CompositeExtract => {
611 inst.expect_at_least(4)?;
612
613 let result_type_id = self.next()?;
614 let result_id = self.next()?;
615 let base_id = self.next()?;
616 log::trace!("\t\t\tlooking up expr {base_id:?}");
617 let mut lexp = self.lookup_expression.lookup(base_id)?.clone();
618 lexp.handle = get_expr_handle!(base_id, &lexp);
619 for _ in 4..inst.wc {
620 let index = self.next()?;
621 log::trace!("\t\t\tlooking up type {:?}", lexp.type_id);
622 let type_lookup = self.lookup_type.lookup(lexp.type_id)?;
623 let type_id = match ctx.module.types[type_lookup.handle].inner {
624 crate::TypeInner::Struct { .. } => {
625 self.lookup_member
626 .get(&(type_lookup.handle, index))
627 .ok_or(Error::InvalidAccessType(lexp.type_id))?
628 .type_id
629 }
630 crate::TypeInner::Array { .. }
631 | crate::TypeInner::Vector { .. }
632 | crate::TypeInner::Matrix { .. } => type_lookup
633 .base_id
634 .ok_or(Error::InvalidAccessType(lexp.type_id))?,
635 ref other => {
636 log::warn!("composite type {other:?}");
637 return Err(Error::UnsupportedType(type_lookup.handle));
638 }
639 };
640 lexp = LookupExpression {
641 handle: ctx.expressions.append(
642 crate::Expression::AccessIndex {
643 base: lexp.handle,
644 index,
645 },
646 span,
647 ),
648 type_id,
649 block_id,
650 };
651 }
652
653 self.lookup_expression.insert(
654 result_id,
655 LookupExpression {
656 handle: lexp.handle,
657 type_id: result_type_id,
658 block_id,
659 },
660 );
661 }
662 Op::CompositeInsert => {
663 inst.expect_at_least(5)?;
664
665 let result_type_id = self.next()?;
666 let id = self.next()?;
667 let object_id = self.next()?;
668 let composite_id = self.next()?;
669 let mut selections = Vec::with_capacity(inst.wc as usize - 5);
670 for _ in 5..inst.wc {
671 selections.push(self.next()?);
672 }
673
674 let object_lexp = self.lookup_expression.lookup(object_id)?.clone();
675 let object_handle = get_expr_handle!(object_id, &object_lexp);
676 let root_lexp = self.lookup_expression.lookup(composite_id)?.clone();
677 let root_handle = get_expr_handle!(composite_id, &root_lexp);
678 let handle = self.insert_composite(
679 root_handle,
680 result_type_id,
681 object_handle,
682 &selections,
683 &ctx.module.types,
684 ctx.expressions,
685 span,
686 )?;
687
688 self.lookup_expression.insert(
689 id,
690 LookupExpression {
691 handle,
692 type_id: result_type_id,
693 block_id,
694 },
695 );
696 }
697 Op::CompositeConstruct => {
698 inst.expect_at_least(3)?;
699
700 let result_type_id = self.next()?;
701 let id = self.next()?;
702 let mut components = Vec::with_capacity(inst.wc as usize - 2);
703 for _ in 3..inst.wc {
704 let comp_id = self.next()?;
705 log::trace!("\t\t\tlooking up expr {comp_id:?}");
706 let lexp = self.lookup_expression.lookup(comp_id)?;
707 let handle = get_expr_handle!(comp_id, lexp);
708 components.push(handle);
709 }
710 let ty = self.lookup_type.lookup(result_type_id)?.handle;
711 let first = components[0];
712 let expr = match ctx.module.types[ty].inner {
713 crate::TypeInner::Vector { size, .. }
715 if components.len() == size as usize
716 && components[1..].iter().all(|&c| c == first) =>
717 {
718 crate::Expression::Splat { size, value: first }
719 }
720 _ => crate::Expression::Compose { ty, components },
721 };
722 self.lookup_expression.insert(
723 id,
724 LookupExpression {
725 handle: ctx.expressions.append(expr, span),
726 type_id: result_type_id,
727 block_id,
728 },
729 );
730 }
731 Op::Load => {
732 inst.expect_at_least(4)?;
733
734 let result_type_id = self.next()?;
735 let result_id = self.next()?;
736 let pointer_id = self.next()?;
737 if inst.wc != 4 {
738 inst.expect(5)?;
739 let _memory_access = self.next()?;
740 }
741
742 let base_lexp = self.lookup_expression.lookup(pointer_id)?;
743 let base_handle = get_expr_handle!(pointer_id, base_lexp);
744 let type_lookup = self.lookup_type.lookup(base_lexp.type_id)?;
745 let handle = match ctx.module.types[type_lookup.handle].inner {
746 crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => {
747 base_handle
748 }
749 _ => match self.lookup_load_override.get(&pointer_id) {
750 Some(&LookupLoadOverride::Loaded(handle)) => handle,
751 _ => ctx.expressions.append(
753 crate::Expression::Load {
754 pointer: base_handle,
755 },
756 span,
757 ),
758 },
759 };
760
761 self.lookup_expression.insert(
762 result_id,
763 LookupExpression {
764 handle,
765 type_id: result_type_id,
766 block_id,
767 },
768 );
769 }
770 Op::Store => {
771 inst.expect_at_least(3)?;
772
773 let pointer_id = self.next()?;
774 let value_id = self.next()?;
775 if inst.wc != 3 {
776 inst.expect(4)?;
777 let _memory_access = self.next()?;
778 }
779 let base_expr = self.lookup_expression.lookup(pointer_id)?;
780 let base_handle = get_expr_handle!(pointer_id, base_expr);
781 let value_expr = self.lookup_expression.lookup(value_id)?;
782 let value_handle = get_expr_handle!(value_id, value_expr);
783
784 block.extend(emitter.finish(ctx.expressions));
785 block.push(
786 crate::Statement::Store {
787 pointer: base_handle,
788 value: value_handle,
789 },
790 span,
791 );
792 emitter.start(ctx.expressions);
793 }
794 Op::SNegate | Op::FNegate => {
796 inst.expect(4)?;
797 self.parse_expr_unary_op_sign_adjusted(
798 ctx,
799 &mut emitter,
800 &mut block,
801 block_id,
802 body_idx,
803 crate::UnaryOperator::Negate,
804 )?;
805 }
806 Op::IAdd
807 | Op::ISub
808 | Op::IMul
809 | Op::BitwiseOr
810 | Op::BitwiseXor
811 | Op::BitwiseAnd
812 | Op::SDiv
813 | Op::SRem => {
814 inst.expect(5)?;
815 let operator = map_binary_operator(inst.op)?;
816 self.parse_expr_binary_op_sign_adjusted(
817 ctx,
818 &mut emitter,
819 &mut block,
820 block_id,
821 body_idx,
822 operator,
823 SignAnchor::Result,
824 )?;
825 }
826 Op::IEqual | Op::INotEqual => {
827 inst.expect(5)?;
828 let operator = map_binary_operator(inst.op)?;
829 self.parse_expr_binary_op_sign_adjusted(
830 ctx,
831 &mut emitter,
832 &mut block,
833 block_id,
834 body_idx,
835 operator,
836 SignAnchor::Operand,
837 )?;
838 }
839 Op::FAdd => {
840 inst.expect(5)?;
841 parse_expr_op!(crate::BinaryOperator::Add, BINARY)?;
842 }
843 Op::FSub => {
844 inst.expect(5)?;
845 parse_expr_op!(crate::BinaryOperator::Subtract, BINARY)?;
846 }
847 Op::FMul => {
848 inst.expect(5)?;
849 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
850 }
851 Op::UDiv | Op::FDiv => {
852 inst.expect(5)?;
853 parse_expr_op!(crate::BinaryOperator::Divide, BINARY)?;
854 }
855 Op::UMod | Op::FRem => {
856 inst.expect(5)?;
857 parse_expr_op!(crate::BinaryOperator::Modulo, BINARY)?;
858 }
859 Op::SMod => {
860 inst.expect(5)?;
861
862 let start = self.data_offset;
865 let result_type_id = self.next()?;
866 let result_id = self.next()?;
867 let p1_id = self.next()?;
868 let p2_id = self.next()?;
869 let span = self.span_from_with_op(start);
870
871 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
872 let left = self.get_expr_handle(
873 p1_id,
874 p1_lexp,
875 ctx,
876 &mut emitter,
877 &mut block,
878 body_idx,
879 );
880 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
881 let right = self.get_expr_handle(
882 p2_id,
883 p2_lexp,
884 ctx,
885 &mut emitter,
886 &mut block,
887 body_idx,
888 );
889
890 let result_ty = self.lookup_type.lookup(result_type_id)?;
891 let inner = &ctx.module.types[result_ty.handle].inner;
892 let kind = inner.scalar_kind().unwrap();
893 let size = inner.size(ctx.gctx()) as u8;
894
895 let left_cast = ctx.expressions.append(
896 crate::Expression::As {
897 expr: left,
898 kind: crate::ScalarKind::Float,
899 convert: Some(size),
900 },
901 span,
902 );
903 let right_cast = ctx.expressions.append(
904 crate::Expression::As {
905 expr: right,
906 kind: crate::ScalarKind::Float,
907 convert: Some(size),
908 },
909 span,
910 );
911 let div = ctx.expressions.append(
912 crate::Expression::Binary {
913 op: crate::BinaryOperator::Divide,
914 left: left_cast,
915 right: right_cast,
916 },
917 span,
918 );
919 let floor = ctx.expressions.append(
920 crate::Expression::Math {
921 fun: crate::MathFunction::Floor,
922 arg: div,
923 arg1: None,
924 arg2: None,
925 arg3: None,
926 },
927 span,
928 );
929 let cast = ctx.expressions.append(
930 crate::Expression::As {
931 expr: floor,
932 kind,
933 convert: Some(size),
934 },
935 span,
936 );
937 let mult = ctx.expressions.append(
938 crate::Expression::Binary {
939 op: crate::BinaryOperator::Multiply,
940 left: cast,
941 right,
942 },
943 span,
944 );
945 let sub = ctx.expressions.append(
946 crate::Expression::Binary {
947 op: crate::BinaryOperator::Subtract,
948 left,
949 right: mult,
950 },
951 span,
952 );
953 self.lookup_expression.insert(
954 result_id,
955 LookupExpression {
956 handle: sub,
957 type_id: result_type_id,
958 block_id,
959 },
960 );
961 }
962 Op::FMod => {
963 inst.expect(5)?;
964
965 let start = self.data_offset;
968 let span = self.span_from_with_op(start);
969
970 let result_type_id = self.next()?;
971 let result_id = self.next()?;
972 let p1_id = self.next()?;
973 let p2_id = self.next()?;
974
975 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
976 let left = self.get_expr_handle(
977 p1_id,
978 p1_lexp,
979 ctx,
980 &mut emitter,
981 &mut block,
982 body_idx,
983 );
984 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
985 let right = self.get_expr_handle(
986 p2_id,
987 p2_lexp,
988 ctx,
989 &mut emitter,
990 &mut block,
991 body_idx,
992 );
993
994 let div = ctx.expressions.append(
995 crate::Expression::Binary {
996 op: crate::BinaryOperator::Divide,
997 left,
998 right,
999 },
1000 span,
1001 );
1002 let floor = ctx.expressions.append(
1003 crate::Expression::Math {
1004 fun: crate::MathFunction::Floor,
1005 arg: div,
1006 arg1: None,
1007 arg2: None,
1008 arg3: None,
1009 },
1010 span,
1011 );
1012 let mult = ctx.expressions.append(
1013 crate::Expression::Binary {
1014 op: crate::BinaryOperator::Multiply,
1015 left: floor,
1016 right,
1017 },
1018 span,
1019 );
1020 let sub = ctx.expressions.append(
1021 crate::Expression::Binary {
1022 op: crate::BinaryOperator::Subtract,
1023 left,
1024 right: mult,
1025 },
1026 span,
1027 );
1028 self.lookup_expression.insert(
1029 result_id,
1030 LookupExpression {
1031 handle: sub,
1032 type_id: result_type_id,
1033 block_id,
1034 },
1035 );
1036 }
1037 Op::VectorTimesScalar
1038 | Op::VectorTimesMatrix
1039 | Op::MatrixTimesScalar
1040 | Op::MatrixTimesVector
1041 | Op::MatrixTimesMatrix => {
1042 inst.expect(5)?;
1043 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
1044 }
1045 Op::Transpose => {
1046 inst.expect(4)?;
1047
1048 let result_type_id = self.next()?;
1049 let result_id = self.next()?;
1050 let matrix_id = self.next()?;
1051 let matrix_lexp = self.lookup_expression.lookup(matrix_id)?;
1052 let matrix_handle = get_expr_handle!(matrix_id, matrix_lexp);
1053 let expr = crate::Expression::Math {
1054 fun: crate::MathFunction::Transpose,
1055 arg: matrix_handle,
1056 arg1: None,
1057 arg2: None,
1058 arg3: None,
1059 };
1060 self.lookup_expression.insert(
1061 result_id,
1062 LookupExpression {
1063 handle: ctx.expressions.append(expr, span),
1064 type_id: result_type_id,
1065 block_id,
1066 },
1067 );
1068 }
1069 Op::Dot => {
1070 inst.expect(5)?;
1071
1072 let result_type_id = self.next()?;
1073 let result_id = self.next()?;
1074 let left_id = self.next()?;
1075 let right_id = self.next()?;
1076 let left_lexp = self.lookup_expression.lookup(left_id)?;
1077 let left_handle = get_expr_handle!(left_id, left_lexp);
1078 let right_lexp = self.lookup_expression.lookup(right_id)?;
1079 let right_handle = get_expr_handle!(right_id, right_lexp);
1080 let expr = crate::Expression::Math {
1081 fun: crate::MathFunction::Dot,
1082 arg: left_handle,
1083 arg1: Some(right_handle),
1084 arg2: None,
1085 arg3: None,
1086 };
1087 self.lookup_expression.insert(
1088 result_id,
1089 LookupExpression {
1090 handle: ctx.expressions.append(expr, span),
1091 type_id: result_type_id,
1092 block_id,
1093 },
1094 );
1095 }
1096 Op::BitFieldInsert => {
1097 inst.expect(7)?;
1098
1099 let start = self.data_offset;
1100 let span = self.span_from_with_op(start);
1101
1102 let result_type_id = self.next()?;
1103 let result_id = self.next()?;
1104 let base_id = self.next()?;
1105 let insert_id = self.next()?;
1106 let offset_id = self.next()?;
1107 let count_id = self.next()?;
1108 let base_lexp = self.lookup_expression.lookup(base_id)?;
1109 let base_handle = get_expr_handle!(base_id, base_lexp);
1110 let insert_lexp = self.lookup_expression.lookup(insert_id)?;
1111 let insert_handle = get_expr_handle!(insert_id, insert_lexp);
1112 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
1113 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
1114 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
1115 let count_lexp = self.lookup_expression.lookup(count_id)?;
1116 let count_handle = get_expr_handle!(count_id, count_lexp);
1117 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
1118
1119 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
1120 .inner
1121 .scalar_kind()
1122 .unwrap();
1123 let count_kind = ctx.module.types[count_lookup_ty.handle]
1124 .inner
1125 .scalar_kind()
1126 .unwrap();
1127
1128 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
1129 ctx.expressions.append(
1130 crate::Expression::As {
1131 expr: offset_handle,
1132 kind: crate::ScalarKind::Uint,
1133 convert: None,
1134 },
1135 span,
1136 )
1137 } else {
1138 offset_handle
1139 };
1140
1141 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
1142 ctx.expressions.append(
1143 crate::Expression::As {
1144 expr: count_handle,
1145 kind: crate::ScalarKind::Uint,
1146 convert: None,
1147 },
1148 span,
1149 )
1150 } else {
1151 count_handle
1152 };
1153
1154 let expr = crate::Expression::Math {
1155 fun: crate::MathFunction::InsertBits,
1156 arg: base_handle,
1157 arg1: Some(insert_handle),
1158 arg2: Some(offset_cast_handle),
1159 arg3: Some(count_cast_handle),
1160 };
1161 self.lookup_expression.insert(
1162 result_id,
1163 LookupExpression {
1164 handle: ctx.expressions.append(expr, span),
1165 type_id: result_type_id,
1166 block_id,
1167 },
1168 );
1169 }
1170 Op::BitFieldSExtract | Op::BitFieldUExtract => {
1171 inst.expect(6)?;
1172
1173 let result_type_id = self.next()?;
1174 let result_id = self.next()?;
1175 let base_id = self.next()?;
1176 let offset_id = self.next()?;
1177 let count_id = self.next()?;
1178 let base_lexp = self.lookup_expression.lookup(base_id)?;
1179 let base_handle = get_expr_handle!(base_id, base_lexp);
1180 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
1181 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
1182 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
1183 let count_lexp = self.lookup_expression.lookup(count_id)?;
1184 let count_handle = get_expr_handle!(count_id, count_lexp);
1185 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
1186
1187 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
1188 .inner
1189 .scalar_kind()
1190 .unwrap();
1191 let count_kind = ctx.module.types[count_lookup_ty.handle]
1192 .inner
1193 .scalar_kind()
1194 .unwrap();
1195
1196 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
1197 ctx.expressions.append(
1198 crate::Expression::As {
1199 expr: offset_handle,
1200 kind: crate::ScalarKind::Uint,
1201 convert: None,
1202 },
1203 span,
1204 )
1205 } else {
1206 offset_handle
1207 };
1208
1209 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
1210 ctx.expressions.append(
1211 crate::Expression::As {
1212 expr: count_handle,
1213 kind: crate::ScalarKind::Uint,
1214 convert: None,
1215 },
1216 span,
1217 )
1218 } else {
1219 count_handle
1220 };
1221
1222 let expr = crate::Expression::Math {
1223 fun: crate::MathFunction::ExtractBits,
1224 arg: base_handle,
1225 arg1: Some(offset_cast_handle),
1226 arg2: Some(count_cast_handle),
1227 arg3: None,
1228 };
1229 self.lookup_expression.insert(
1230 result_id,
1231 LookupExpression {
1232 handle: ctx.expressions.append(expr, span),
1233 type_id: result_type_id,
1234 block_id,
1235 },
1236 );
1237 }
1238 Op::BitReverse | Op::BitCount => {
1239 inst.expect(4)?;
1240
1241 let result_type_id = self.next()?;
1242 let result_id = self.next()?;
1243 let base_id = self.next()?;
1244 let base_lexp = self.lookup_expression.lookup(base_id)?;
1245 let base_handle = get_expr_handle!(base_id, base_lexp);
1246 let expr = crate::Expression::Math {
1247 fun: match inst.op {
1248 Op::BitReverse => crate::MathFunction::ReverseBits,
1249 Op::BitCount => crate::MathFunction::CountOneBits,
1250 _ => unreachable!(),
1251 },
1252 arg: base_handle,
1253 arg1: None,
1254 arg2: None,
1255 arg3: None,
1256 };
1257 self.lookup_expression.insert(
1258 result_id,
1259 LookupExpression {
1260 handle: ctx.expressions.append(expr, span),
1261 type_id: result_type_id,
1262 block_id,
1263 },
1264 );
1265 }
1266 Op::OuterProduct => {
1267 inst.expect(5)?;
1268
1269 let result_type_id = self.next()?;
1270 let result_id = self.next()?;
1271 let left_id = self.next()?;
1272 let right_id = self.next()?;
1273 let left_lexp = self.lookup_expression.lookup(left_id)?;
1274 let left_handle = get_expr_handle!(left_id, left_lexp);
1275 let right_lexp = self.lookup_expression.lookup(right_id)?;
1276 let right_handle = get_expr_handle!(right_id, right_lexp);
1277 let expr = crate::Expression::Math {
1278 fun: crate::MathFunction::Outer,
1279 arg: left_handle,
1280 arg1: Some(right_handle),
1281 arg2: None,
1282 arg3: None,
1283 };
1284 self.lookup_expression.insert(
1285 result_id,
1286 LookupExpression {
1287 handle: ctx.expressions.append(expr, span),
1288 type_id: result_type_id,
1289 block_id,
1290 },
1291 );
1292 }
1293 Op::Not => {
1295 inst.expect(4)?;
1296 self.parse_expr_unary_op_sign_adjusted(
1297 ctx,
1298 &mut emitter,
1299 &mut block,
1300 block_id,
1301 body_idx,
1302 crate::UnaryOperator::BitwiseNot,
1303 )?;
1304 }
1305 Op::ShiftRightLogical => {
1306 inst.expect(5)?;
1307 parse_expr_op!(crate::BinaryOperator::ShiftRight, SHIFT)?;
1309 }
1310 Op::ShiftRightArithmetic => {
1311 inst.expect(5)?;
1312 parse_expr_op!(crate::BinaryOperator::ShiftRight, SHIFT)?;
1314 }
1315 Op::ShiftLeftLogical => {
1316 inst.expect(5)?;
1317 parse_expr_op!(crate::BinaryOperator::ShiftLeft, SHIFT)?;
1318 }
1319 Op::Image => {
1321 inst.expect(4)?;
1322 self.parse_image_uncouple(block_id)?;
1323 }
1324 Op::SampledImage => {
1325 inst.expect(5)?;
1326 self.parse_image_couple()?;
1327 }
1328 Op::ImageWrite => {
1329 let extra = inst.expect_at_least(4)?;
1330 let stmt =
1331 self.parse_image_write(extra, ctx, &mut emitter, &mut block, body_idx)?;
1332 block.extend(emitter.finish(ctx.expressions));
1333 block.push(stmt, span);
1334 emitter.start(ctx.expressions);
1335 }
1336 Op::ImageFetch | Op::ImageRead => {
1337 let extra = inst.expect_at_least(5)?;
1338 self.parse_image_load(
1339 extra,
1340 ctx,
1341 &mut emitter,
1342 &mut block,
1343 block_id,
1344 body_idx,
1345 )?;
1346 }
1347 Op::ImageSampleImplicitLod | Op::ImageSampleExplicitLod => {
1348 let extra = inst.expect_at_least(5)?;
1349 let options = image::SamplingOptions {
1350 compare: false,
1351 project: false,
1352 gather: false,
1353 };
1354 self.parse_image_sample(
1355 extra,
1356 options,
1357 ctx,
1358 &mut emitter,
1359 &mut block,
1360 block_id,
1361 body_idx,
1362 )?;
1363 }
1364 Op::ImageSampleProjImplicitLod | Op::ImageSampleProjExplicitLod => {
1365 let extra = inst.expect_at_least(5)?;
1366 let options = image::SamplingOptions {
1367 compare: false,
1368 project: true,
1369 gather: false,
1370 };
1371 self.parse_image_sample(
1372 extra,
1373 options,
1374 ctx,
1375 &mut emitter,
1376 &mut block,
1377 block_id,
1378 body_idx,
1379 )?;
1380 }
1381 Op::ImageSampleDrefImplicitLod | Op::ImageSampleDrefExplicitLod => {
1382 let extra = inst.expect_at_least(6)?;
1383 let options = image::SamplingOptions {
1384 compare: true,
1385 project: false,
1386 gather: false,
1387 };
1388 self.parse_image_sample(
1389 extra,
1390 options,
1391 ctx,
1392 &mut emitter,
1393 &mut block,
1394 block_id,
1395 body_idx,
1396 )?;
1397 }
1398 Op::ImageSampleProjDrefImplicitLod | Op::ImageSampleProjDrefExplicitLod => {
1399 let extra = inst.expect_at_least(6)?;
1400 let options = image::SamplingOptions {
1401 compare: true,
1402 project: true,
1403 gather: false,
1404 };
1405 self.parse_image_sample(
1406 extra,
1407 options,
1408 ctx,
1409 &mut emitter,
1410 &mut block,
1411 block_id,
1412 body_idx,
1413 )?;
1414 }
1415 Op::ImageGather => {
1416 let extra = inst.expect_at_least(6)?;
1417 let options = image::SamplingOptions {
1418 compare: false,
1419 project: false,
1420 gather: true,
1421 };
1422 self.parse_image_sample(
1423 extra,
1424 options,
1425 ctx,
1426 &mut emitter,
1427 &mut block,
1428 block_id,
1429 body_idx,
1430 )?;
1431 }
1432 Op::ImageDrefGather => {
1433 let extra = inst.expect_at_least(6)?;
1434 let options = image::SamplingOptions {
1435 compare: true,
1436 project: false,
1437 gather: true,
1438 };
1439 self.parse_image_sample(
1440 extra,
1441 options,
1442 ctx,
1443 &mut emitter,
1444 &mut block,
1445 block_id,
1446 body_idx,
1447 )?;
1448 }
1449 Op::ImageQuerySize => {
1450 inst.expect(4)?;
1451 self.parse_image_query_size(
1452 false,
1453 ctx,
1454 &mut emitter,
1455 &mut block,
1456 block_id,
1457 body_idx,
1458 )?;
1459 }
1460 Op::ImageQuerySizeLod => {
1461 inst.expect(5)?;
1462 self.parse_image_query_size(
1463 true,
1464 ctx,
1465 &mut emitter,
1466 &mut block,
1467 block_id,
1468 body_idx,
1469 )?;
1470 }
1471 Op::ImageQueryLevels => {
1472 inst.expect(4)?;
1473 self.parse_image_query_other(crate::ImageQuery::NumLevels, ctx, block_id)?;
1474 }
1475 Op::ImageQuerySamples => {
1476 inst.expect(4)?;
1477 self.parse_image_query_other(crate::ImageQuery::NumSamples, ctx, block_id)?;
1478 }
1479 Op::Select => {
1481 inst.expect(6)?;
1482 let result_type_id = self.next()?;
1483 let result_id = self.next()?;
1484 let condition = self.next()?;
1485 let o1_id = self.next()?;
1486 let o2_id = self.next()?;
1487
1488 let cond_lexp = self.lookup_expression.lookup(condition)?;
1489 let cond_handle = get_expr_handle!(condition, cond_lexp);
1490 let o1_lexp = self.lookup_expression.lookup(o1_id)?;
1491 let o1_handle = get_expr_handle!(o1_id, o1_lexp);
1492 let o2_lexp = self.lookup_expression.lookup(o2_id)?;
1493 let o2_handle = get_expr_handle!(o2_id, o2_lexp);
1494
1495 let expr = crate::Expression::Select {
1496 condition: cond_handle,
1497 accept: o1_handle,
1498 reject: o2_handle,
1499 };
1500 self.lookup_expression.insert(
1501 result_id,
1502 LookupExpression {
1503 handle: ctx.expressions.append(expr, span),
1504 type_id: result_type_id,
1505 block_id,
1506 },
1507 );
1508 }
1509 Op::VectorShuffle => {
1510 inst.expect_at_least(5)?;
1511 let result_type_id = self.next()?;
1512 let result_id = self.next()?;
1513 let v1_id = self.next()?;
1514 let v2_id = self.next()?;
1515
1516 let v1_lexp = self.lookup_expression.lookup(v1_id)?;
1517 let v1_lty = self.lookup_type.lookup(v1_lexp.type_id)?;
1518 let v1_handle = get_expr_handle!(v1_id, v1_lexp);
1519 let n1 = match ctx.module.types[v1_lty.handle].inner {
1520 crate::TypeInner::Vector { size, .. } => size as u32,
1521 _ => return Err(Error::InvalidInnerType(v1_lexp.type_id)),
1522 };
1523 let v2_lexp = self.lookup_expression.lookup(v2_id)?;
1524 let v2_lty = self.lookup_type.lookup(v2_lexp.type_id)?;
1525 let v2_handle = get_expr_handle!(v2_id, v2_lexp);
1526 let n2 = match ctx.module.types[v2_lty.handle].inner {
1527 crate::TypeInner::Vector { size, .. } => size as u32,
1528 _ => return Err(Error::InvalidInnerType(v2_lexp.type_id)),
1529 };
1530
1531 self.temp_bytes.clear();
1532 let mut max_component = 0;
1533 for _ in 5..inst.wc as usize {
1534 let mut index = self.next()?;
1535 if index == u32::MAX {
1536 index = 0;
1538 }
1539 max_component = max_component.max(index);
1540 self.temp_bytes.push(index as u8);
1541 }
1542
1543 let expr = if max_component < n1 {
1545 use crate::SwizzleComponent as Sc;
1546 let size = match self.temp_bytes.len() {
1547 2 => crate::VectorSize::Bi,
1548 3 => crate::VectorSize::Tri,
1549 _ => crate::VectorSize::Quad,
1550 };
1551 let mut pattern = [Sc::X; 4];
1552 for (pat, index) in pattern.iter_mut().zip(self.temp_bytes.drain(..)) {
1553 *pat = match index {
1554 0 => Sc::X,
1555 1 => Sc::Y,
1556 2 => Sc::Z,
1557 _ => Sc::W,
1558 };
1559 }
1560 crate::Expression::Swizzle {
1561 size,
1562 vector: v1_handle,
1563 pattern,
1564 }
1565 } else {
1566 let mut components = Vec::with_capacity(self.temp_bytes.len());
1568 for index in self.temp_bytes.drain(..).map(|i| i as u32) {
1569 let expr = if index < n1 {
1570 crate::Expression::AccessIndex {
1571 base: v1_handle,
1572 index,
1573 }
1574 } else if index < n1 + n2 {
1575 crate::Expression::AccessIndex {
1576 base: v2_handle,
1577 index: index - n1,
1578 }
1579 } else {
1580 return Err(Error::InvalidAccessIndex(index));
1581 };
1582 components.push(ctx.expressions.append(expr, span));
1583 }
1584 crate::Expression::Compose {
1585 ty: self.lookup_type.lookup(result_type_id)?.handle,
1586 components,
1587 }
1588 };
1589
1590 self.lookup_expression.insert(
1591 result_id,
1592 LookupExpression {
1593 handle: ctx.expressions.append(expr, span),
1594 type_id: result_type_id,
1595 block_id,
1596 },
1597 );
1598 }
1599 Op::Bitcast
1600 | Op::ConvertSToF
1601 | Op::ConvertUToF
1602 | Op::ConvertFToU
1603 | Op::ConvertFToS
1604 | Op::FConvert
1605 | Op::UConvert
1606 | Op::SConvert => {
1607 inst.expect(4)?;
1608 let result_type_id = self.next()?;
1609 let result_id = self.next()?;
1610 let value_id = self.next()?;
1611
1612 let value_lexp = self.lookup_expression.lookup(value_id)?;
1613 let ty_lookup = self.lookup_type.lookup(result_type_id)?;
1614 let scalar = match ctx.module.types[ty_lookup.handle].inner {
1615 crate::TypeInner::Scalar(scalar)
1616 | crate::TypeInner::Vector { scalar, .. }
1617 | crate::TypeInner::Matrix { scalar, .. } => scalar,
1618 _ => return Err(Error::InvalidAsType(ty_lookup.handle)),
1619 };
1620
1621 let expr = crate::Expression::As {
1622 expr: get_expr_handle!(value_id, value_lexp),
1623 kind: scalar.kind,
1624 convert: if scalar.kind == crate::ScalarKind::Bool {
1625 Some(crate::BOOL_WIDTH)
1626 } else if inst.op == Op::Bitcast {
1627 None
1628 } else {
1629 Some(scalar.width)
1630 },
1631 };
1632 self.lookup_expression.insert(
1633 result_id,
1634 LookupExpression {
1635 handle: ctx.expressions.append(expr, span),
1636 type_id: result_type_id,
1637 block_id,
1638 },
1639 );
1640 }
1641 Op::FunctionCall => {
1642 inst.expect_at_least(4)?;
1643
1644 let result_type_id = self.next()?;
1645 let result_id = self.next()?;
1646 let func_id = self.next()?;
1647
1648 let mut arguments = Vec::with_capacity(inst.wc as usize - 4);
1649 for _ in 0..arguments.capacity() {
1650 let arg_id = self.next()?;
1651 let lexp = self.lookup_expression.lookup(arg_id)?;
1652 arguments.push(get_expr_handle!(arg_id, lexp));
1653 }
1654
1655 block.extend(emitter.finish(ctx.expressions));
1656
1657 let function = self.add_call(ctx.function_id, func_id);
1659
1660 let result = if self.lookup_void_type == Some(result_type_id) {
1661 None
1662 } else {
1663 let expr_handle = ctx
1664 .expressions
1665 .append(crate::Expression::CallResult(function), span);
1666 self.lookup_expression.insert(
1667 result_id,
1668 LookupExpression {
1669 handle: expr_handle,
1670 type_id: result_type_id,
1671 block_id,
1672 },
1673 );
1674 Some(expr_handle)
1675 };
1676 block.push(
1677 crate::Statement::Call {
1678 function,
1679 arguments,
1680 result,
1681 },
1682 span,
1683 );
1684 emitter.start(ctx.expressions);
1685 }
1686 Op::ExtInst => {
1687 use crate::MathFunction as Mf;
1688 use spirv::GLOp as Glo;
1689
1690 let base_wc = 5;
1691 inst.expect_at_least(base_wc)?;
1692
1693 let result_type_id = self.next()?;
1694 let result_id = self.next()?;
1695 let set_id = self.next()?;
1696 if Some(set_id) == self.ext_non_semantic_id {
1697 for _ in 0..inst.wc - 4 {
1698 self.next()?;
1699 }
1700 continue;
1701 } else if Some(set_id) != self.ext_glsl_id {
1702 return Err(Error::UnsupportedExtInstSet(set_id));
1703 }
1704 let inst_id = self.next()?;
1705 let gl_op = Glo::from_u32(inst_id).ok_or(Error::UnsupportedExtInst(inst_id))?;
1706
1707 let fun = match gl_op {
1708 Glo::Round => Mf::Round,
1709 Glo::RoundEven => Mf::Round,
1710 Glo::Trunc => Mf::Trunc,
1711 Glo::FAbs | Glo::SAbs => Mf::Abs,
1712 Glo::FSign | Glo::SSign => Mf::Sign,
1713 Glo::Floor => Mf::Floor,
1714 Glo::Ceil => Mf::Ceil,
1715 Glo::Fract => Mf::Fract,
1716 Glo::Sin => Mf::Sin,
1717 Glo::Cos => Mf::Cos,
1718 Glo::Tan => Mf::Tan,
1719 Glo::Asin => Mf::Asin,
1720 Glo::Acos => Mf::Acos,
1721 Glo::Atan => Mf::Atan,
1722 Glo::Sinh => Mf::Sinh,
1723 Glo::Cosh => Mf::Cosh,
1724 Glo::Tanh => Mf::Tanh,
1725 Glo::Atan2 => Mf::Atan2,
1726 Glo::Asinh => Mf::Asinh,
1727 Glo::Acosh => Mf::Acosh,
1728 Glo::Atanh => Mf::Atanh,
1729 Glo::Radians => Mf::Radians,
1730 Glo::Degrees => Mf::Degrees,
1731 Glo::Pow => Mf::Pow,
1732 Glo::Exp => Mf::Exp,
1733 Glo::Log => Mf::Log,
1734 Glo::Exp2 => Mf::Exp2,
1735 Glo::Log2 => Mf::Log2,
1736 Glo::Sqrt => Mf::Sqrt,
1737 Glo::InverseSqrt => Mf::InverseSqrt,
1738 Glo::MatrixInverse => Mf::Inverse,
1739 Glo::Determinant => Mf::Determinant,
1740 Glo::ModfStruct => Mf::Modf,
1741 Glo::FMin | Glo::UMin | Glo::SMin | Glo::NMin => Mf::Min,
1742 Glo::FMax | Glo::UMax | Glo::SMax | Glo::NMax => Mf::Max,
1743 Glo::FClamp | Glo::UClamp | Glo::SClamp | Glo::NClamp => Mf::Clamp,
1744 Glo::FMix => Mf::Mix,
1745 Glo::Step => Mf::Step,
1746 Glo::SmoothStep => Mf::SmoothStep,
1747 Glo::Fma => Mf::Fma,
1748 Glo::FrexpStruct => Mf::Frexp,
1749 Glo::Ldexp => Mf::Ldexp,
1750 Glo::Length => Mf::Length,
1751 Glo::Distance => Mf::Distance,
1752 Glo::Cross => Mf::Cross,
1753 Glo::Normalize => Mf::Normalize,
1754 Glo::FaceForward => Mf::FaceForward,
1755 Glo::Reflect => Mf::Reflect,
1756 Glo::Refract => Mf::Refract,
1757 Glo::PackUnorm4x8 => Mf::Pack4x8unorm,
1758 Glo::PackSnorm4x8 => Mf::Pack4x8snorm,
1759 Glo::PackHalf2x16 => Mf::Pack2x16float,
1760 Glo::PackUnorm2x16 => Mf::Pack2x16unorm,
1761 Glo::PackSnorm2x16 => Mf::Pack2x16snorm,
1762 Glo::UnpackUnorm4x8 => Mf::Unpack4x8unorm,
1763 Glo::UnpackSnorm4x8 => Mf::Unpack4x8snorm,
1764 Glo::UnpackHalf2x16 => Mf::Unpack2x16float,
1765 Glo::UnpackUnorm2x16 => Mf::Unpack2x16unorm,
1766 Glo::UnpackSnorm2x16 => Mf::Unpack2x16snorm,
1767 Glo::FindILsb => Mf::FirstTrailingBit,
1768 Glo::FindUMsb | Glo::FindSMsb => Mf::FirstLeadingBit,
1769 Glo::Modf | Glo::Frexp => return Err(Error::UnsupportedExtInst(inst_id)),
1771 Glo::IMix
1772 | Glo::PackDouble2x32
1773 | Glo::UnpackDouble2x32
1774 | Glo::InterpolateAtCentroid
1775 | Glo::InterpolateAtSample
1776 | Glo::InterpolateAtOffset => {
1777 return Err(Error::UnsupportedExtInst(inst_id))
1778 }
1779 };
1780
1781 let arg_count = fun.argument_count();
1782 inst.expect(base_wc + arg_count as u16)?;
1783 let arg = {
1784 let arg_id = self.next()?;
1785 let lexp = self.lookup_expression.lookup(arg_id)?;
1786 get_expr_handle!(arg_id, lexp)
1787 };
1788 let arg1 = if arg_count > 1 {
1789 let arg_id = self.next()?;
1790 let lexp = self.lookup_expression.lookup(arg_id)?;
1791 Some(get_expr_handle!(arg_id, lexp))
1792 } else {
1793 None
1794 };
1795 let arg2 = if arg_count > 2 {
1796 let arg_id = self.next()?;
1797 let lexp = self.lookup_expression.lookup(arg_id)?;
1798 Some(get_expr_handle!(arg_id, lexp))
1799 } else {
1800 None
1801 };
1802 let arg3 = if arg_count > 3 {
1803 let arg_id = self.next()?;
1804 let lexp = self.lookup_expression.lookup(arg_id)?;
1805 Some(get_expr_handle!(arg_id, lexp))
1806 } else {
1807 None
1808 };
1809
1810 let expr = crate::Expression::Math {
1811 fun,
1812 arg,
1813 arg1,
1814 arg2,
1815 arg3,
1816 };
1817 self.lookup_expression.insert(
1818 result_id,
1819 LookupExpression {
1820 handle: ctx.expressions.append(expr, span),
1821 type_id: result_type_id,
1822 block_id,
1823 },
1824 );
1825 }
1826 Op::LogicalNot => {
1828 inst.expect(4)?;
1829 parse_expr_op!(crate::UnaryOperator::LogicalNot, UNARY)?;
1830 }
1831 Op::LogicalOr => {
1832 inst.expect(5)?;
1833 parse_expr_op!(crate::BinaryOperator::LogicalOr, BINARY)?;
1834 }
1835 Op::LogicalAnd => {
1836 inst.expect(5)?;
1837 parse_expr_op!(crate::BinaryOperator::LogicalAnd, BINARY)?;
1838 }
1839 Op::SGreaterThan | Op::SGreaterThanEqual | Op::SLessThan | Op::SLessThanEqual => {
1840 inst.expect(5)?;
1841 self.parse_expr_int_comparison(
1842 ctx,
1843 &mut emitter,
1844 &mut block,
1845 block_id,
1846 body_idx,
1847 map_binary_operator(inst.op)?,
1848 crate::ScalarKind::Sint,
1849 )?;
1850 }
1851 Op::UGreaterThan | Op::UGreaterThanEqual | Op::ULessThan | Op::ULessThanEqual => {
1852 inst.expect(5)?;
1853 self.parse_expr_int_comparison(
1854 ctx,
1855 &mut emitter,
1856 &mut block,
1857 block_id,
1858 body_idx,
1859 map_binary_operator(inst.op)?,
1860 crate::ScalarKind::Uint,
1861 )?;
1862 }
1863 Op::FOrdEqual
1864 | Op::FUnordEqual
1865 | Op::FOrdNotEqual
1866 | Op::FUnordNotEqual
1867 | Op::FOrdLessThan
1868 | Op::FUnordLessThan
1869 | Op::FOrdGreaterThan
1870 | Op::FUnordGreaterThan
1871 | Op::FOrdLessThanEqual
1872 | Op::FUnordLessThanEqual
1873 | Op::FOrdGreaterThanEqual
1874 | Op::FUnordGreaterThanEqual
1875 | Op::LogicalEqual
1876 | Op::LogicalNotEqual => {
1877 inst.expect(5)?;
1878 let operator = map_binary_operator(inst.op)?;
1879 parse_expr_op!(operator, BINARY)?;
1880 }
1881 Op::Any | Op::All | Op::IsNan | Op::IsInf | Op::IsFinite | Op::IsNormal => {
1882 inst.expect(4)?;
1883 let result_type_id = self.next()?;
1884 let result_id = self.next()?;
1885 let arg_id = self.next()?;
1886
1887 let arg_lexp = self.lookup_expression.lookup(arg_id)?;
1888 let arg_handle = get_expr_handle!(arg_id, arg_lexp);
1889
1890 let expr = crate::Expression::Relational {
1891 fun: map_relational_fun(inst.op)?,
1892 argument: arg_handle,
1893 };
1894 self.lookup_expression.insert(
1895 result_id,
1896 LookupExpression {
1897 handle: ctx.expressions.append(expr, span),
1898 type_id: result_type_id,
1899 block_id,
1900 },
1901 );
1902 }
1903 Op::Kill => {
1904 inst.expect(1)?;
1905 break Some(crate::Statement::Kill);
1906 }
1907 Op::Unreachable => {
1908 inst.expect(1)?;
1909 break None;
1910 }
1911 Op::Return => {
1912 inst.expect(1)?;
1913 break Some(crate::Statement::Return { value: None });
1914 }
1915 Op::ReturnValue => {
1916 inst.expect(2)?;
1917 let value_id = self.next()?;
1918 let value_lexp = self.lookup_expression.lookup(value_id)?;
1919 let value_handle = get_expr_handle!(value_id, value_lexp);
1920 break Some(crate::Statement::Return {
1921 value: Some(value_handle),
1922 });
1923 }
1924 Op::Branch => {
1925 inst.expect(2)?;
1926 let target_id = self.next()?;
1927
1928 if let Some(info) = ctx.mergers.get(&target_id) {
1937 block.extend(emitter.finish(ctx.expressions));
1938 ctx.blocks.insert(block_id, block);
1939 let body = &mut ctx.bodies[body_idx];
1940 body.data.push(BodyFragment::BlockId(block_id));
1941
1942 merger(body, info);
1943
1944 return Ok(());
1945 }
1946
1947 ctx.body_for_label.entry(target_id).or_insert(body_idx);
1964
1965 break None;
1966 }
1967 Op::BranchConditional => {
1968 inst.expect_at_least(4)?;
1969
1970 let condition = {
1971 let condition_id = self.next()?;
1972 let lexp = self.lookup_expression.lookup(condition_id)?;
1973 get_expr_handle!(condition_id, lexp)
1974 };
1975
1976 #[derive(Copy, Clone)]
1979 struct BranchTarget {
1980 label_id: spirv::Word,
1981 merge_info: Option<MergeBlockInformation>,
1982 }
1983 let branch_target = |label_id| BranchTarget {
1984 label_id,
1985 merge_info: ctx.mergers.get(&label_id).copied(),
1986 };
1987
1988 let true_target = branch_target(self.next()?);
1989 let false_target = branch_target(self.next()?);
1990
1991 for _ in 4..inst.wc {
1993 let _ = self.next()?;
1994 }
1995
1996 let parent_body_idx = ctx.bodies[body_idx].parent;
2004 let parent_parent_body_idx = ctx.bodies[parent_body_idx].parent;
2005 match ctx.bodies[parent_parent_body_idx].data[..] {
2006 [.., BodyFragment::Loop {
2010 body: loop_body_idx,
2011 continuing: loop_continuing_idx,
2012 break_if: ref mut break_if_slot @ None,
2013 }] if body_idx == loop_continuing_idx => {
2014 let break_if_cond = [true, false].into_iter().find_map(|true_breaks| {
2017 let (break_candidate, backedge_candidate) = if true_breaks {
2018 (true_target, false_target)
2019 } else {
2020 (false_target, true_target)
2021 };
2022
2023 if break_candidate.merge_info
2024 != Some(MergeBlockInformation::LoopMerge)
2025 {
2026 return None;
2027 }
2028
2029 let backedge_candidate_is_backedge =
2033 backedge_candidate.merge_info.is_none()
2034 && ctx.body_for_label.get(&backedge_candidate.label_id)
2035 == Some(&loop_body_idx);
2036 if !backedge_candidate_is_backedge {
2037 return None;
2038 }
2039
2040 Some(if true_breaks {
2041 condition
2042 } else {
2043 ctx.expressions.append(
2044 crate::Expression::Unary {
2045 op: crate::UnaryOperator::LogicalNot,
2046 expr: condition,
2047 },
2048 span,
2049 )
2050 })
2051 });
2052
2053 if let Some(break_if_cond) = break_if_cond {
2054 *break_if_slot = Some(break_if_cond);
2055
2056 break None;
2060 }
2061 }
2062 _ => {}
2063 }
2064
2065 block.extend(emitter.finish(ctx.expressions));
2066 ctx.blocks.insert(block_id, block);
2067 let body = &mut ctx.bodies[body_idx];
2068 body.data.push(BodyFragment::BlockId(block_id));
2069
2070 let same_target = true_target.label_id == false_target.label_id;
2071
2072 let accept = ctx.bodies.len();
2074 let mut accept_block = Body::with_parent(body_idx);
2075
2076 if let Some(info) = true_target.merge_info {
2080 merger(
2081 match same_target {
2082 true => &mut ctx.bodies[body_idx],
2083 false => &mut accept_block,
2084 },
2085 &info,
2086 )
2087 } else {
2088 let prev = ctx.body_for_label.insert(
2090 true_target.label_id,
2091 match same_target {
2092 true => body_idx,
2093 false => accept,
2094 },
2095 );
2096 debug_assert!(prev.is_none());
2097 }
2098
2099 if same_target {
2100 return Ok(());
2101 }
2102
2103 ctx.bodies.push(accept_block);
2104
2105 let reject = ctx.bodies.len();
2107 let mut reject_block = Body::with_parent(body_idx);
2108
2109 if let Some(info) = false_target.merge_info {
2110 merger(&mut reject_block, &info)
2111 } else {
2112 let prev = ctx.body_for_label.insert(false_target.label_id, reject);
2113 debug_assert!(prev.is_none());
2114 }
2115
2116 ctx.bodies.push(reject_block);
2117
2118 let body = &mut ctx.bodies[body_idx];
2119 body.data.push(BodyFragment::If {
2120 condition,
2121 accept,
2122 reject,
2123 });
2124
2125 return Ok(());
2126 }
2127 Op::Switch => {
2128 inst.expect_at_least(3)?;
2129 let selector = self.next()?;
2130 let default_id = self.next()?;
2131
2132 if let Some(merge) = selection_merge_block {
2135 ctx.mergers
2136 .insert(merge, MergeBlockInformation::SwitchMerge);
2137 }
2138
2139 let default = ctx.bodies.len();
2140 ctx.bodies.push(Body::with_parent(body_idx));
2141 ctx.body_for_label.entry(default_id).or_insert(default);
2142
2143 let selector_lexp = &self.lookup_expression[&selector];
2144 let selector_lty = self.lookup_type.lookup(selector_lexp.type_id)?;
2145 let selector_handle = get_expr_handle!(selector, selector_lexp);
2146 let selector = match ctx.module.types[selector_lty.handle].inner {
2147 crate::TypeInner::Scalar(crate::Scalar {
2148 kind: crate::ScalarKind::Uint,
2149 width: _,
2150 }) => {
2151 ctx.expressions.append(
2153 crate::Expression::As {
2154 kind: crate::ScalarKind::Sint,
2155 expr: selector_handle,
2156 convert: None,
2157 },
2158 span,
2159 )
2160 }
2161 crate::TypeInner::Scalar(crate::Scalar {
2162 kind: crate::ScalarKind::Sint,
2163 width: _,
2164 }) => selector_handle,
2165 ref other => unimplemented!("Unexpected selector {:?}", other),
2166 };
2167
2168 self.switch_cases.clear();
2170
2171 for _ in 0..(inst.wc - 3) / 2 {
2172 let literal = self.next()?;
2173 let target = self.next()?;
2174
2175 let case_body_idx = ctx.bodies.len();
2176
2177 if let Some(&mut (_, ref mut literals)) = self.switch_cases.get_mut(&target)
2181 {
2182 literals.push(literal as i32);
2183 continue;
2184 }
2185
2186 let mut body = Body::with_parent(body_idx);
2187
2188 if let Some(info) = ctx.mergers.get(&target) {
2189 merger(&mut body, info);
2190 }
2191
2192 ctx.bodies.push(body);
2193 ctx.body_for_label.entry(target).or_insert(case_body_idx);
2194
2195 self.switch_cases
2198 .insert(target, (case_body_idx, vec![literal as i32]));
2199 }
2200
2201 let mut cases = Vec::with_capacity((inst.wc as usize - 3) / 2);
2210 for &(case_body_idx, ref literals) in self.switch_cases.values() {
2211 let value = literals[0];
2212
2213 for &literal in literals.iter().skip(1) {
2214 let empty_body_idx = ctx.bodies.len();
2215 let body = Body::with_parent(body_idx);
2216
2217 ctx.bodies.push(body);
2218
2219 cases.push((literal, empty_body_idx));
2220 }
2221
2222 cases.push((value, case_body_idx));
2223 }
2224
2225 block.extend(emitter.finish(ctx.expressions));
2226
2227 let body = &mut ctx.bodies[body_idx];
2228 ctx.blocks.insert(block_id, block);
2229 body.data.reserve(2);
2231 body.data.push(BodyFragment::BlockId(block_id));
2232 body.data.push(BodyFragment::Switch {
2233 selector,
2234 cases,
2235 default,
2236 });
2237
2238 return Ok(());
2239 }
2240 Op::SelectionMerge => {
2241 inst.expect(3)?;
2242 let merge_block_id = self.next()?;
2243 let _selection_control = self.next()?;
2245
2246 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
2249
2250 ctx.mergers
2253 .insert(merge_block_id, MergeBlockInformation::SelectionMerge);
2254
2255 selection_merge_block = Some(merge_block_id);
2256 }
2257 Op::LoopMerge => {
2258 inst.expect_at_least(4)?;
2259 let merge_block_id = self.next()?;
2260 let continuing = self.next()?;
2261
2262 for _ in 0..inst.wc - 3 {
2264 self.next()?;
2265 }
2266
2267 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
2270 ctx.mergers
2273 .insert(merge_block_id, MergeBlockInformation::LoopMerge);
2274
2275 let loop_body_idx = ctx.bodies.len();
2276 ctx.bodies.push(Body::with_parent(body_idx));
2277
2278 let continue_idx = ctx.bodies.len();
2279 ctx.bodies.push(Body::with_parent(loop_body_idx));
2281 ctx.body_for_label.entry(continuing).or_insert(continue_idx);
2282 ctx.mergers
2285 .insert(continuing, MergeBlockInformation::LoopContinue);
2286
2287 ctx.body_for_label.insert(block_id, loop_body_idx);
2289
2290 let parent_body = &mut ctx.bodies[body_idx];
2291 parent_body.data.push(BodyFragment::Loop {
2292 body: loop_body_idx,
2293 continuing: continue_idx,
2294 break_if: None,
2295 });
2296 body_idx = loop_body_idx;
2297 }
2298 Op::DPdxCoarse => {
2299 parse_expr_op!(
2300 crate::DerivativeAxis::X,
2301 crate::DerivativeControl::Coarse,
2302 DERIVATIVE
2303 )?;
2304 }
2305 Op::DPdyCoarse => {
2306 parse_expr_op!(
2307 crate::DerivativeAxis::Y,
2308 crate::DerivativeControl::Coarse,
2309 DERIVATIVE
2310 )?;
2311 }
2312 Op::FwidthCoarse => {
2313 parse_expr_op!(
2314 crate::DerivativeAxis::Width,
2315 crate::DerivativeControl::Coarse,
2316 DERIVATIVE
2317 )?;
2318 }
2319 Op::DPdxFine => {
2320 parse_expr_op!(
2321 crate::DerivativeAxis::X,
2322 crate::DerivativeControl::Fine,
2323 DERIVATIVE
2324 )?;
2325 }
2326 Op::DPdyFine => {
2327 parse_expr_op!(
2328 crate::DerivativeAxis::Y,
2329 crate::DerivativeControl::Fine,
2330 DERIVATIVE
2331 )?;
2332 }
2333 Op::FwidthFine => {
2334 parse_expr_op!(
2335 crate::DerivativeAxis::Width,
2336 crate::DerivativeControl::Fine,
2337 DERIVATIVE
2338 )?;
2339 }
2340 Op::DPdx => {
2341 parse_expr_op!(
2342 crate::DerivativeAxis::X,
2343 crate::DerivativeControl::None,
2344 DERIVATIVE
2345 )?;
2346 }
2347 Op::DPdy => {
2348 parse_expr_op!(
2349 crate::DerivativeAxis::Y,
2350 crate::DerivativeControl::None,
2351 DERIVATIVE
2352 )?;
2353 }
2354 Op::Fwidth => {
2355 parse_expr_op!(
2356 crate::DerivativeAxis::Width,
2357 crate::DerivativeControl::None,
2358 DERIVATIVE
2359 )?;
2360 }
2361 Op::ArrayLength => {
2362 inst.expect(5)?;
2363 let result_type_id = self.next()?;
2364 let result_id = self.next()?;
2365 let structure_id = self.next()?;
2366 let member_index = self.next()?;
2367
2368 let structure_ptr = self.lookup_expression.lookup(structure_id)?;
2372 let structure_handle = get_expr_handle!(structure_id, structure_ptr);
2373
2374 let member_ptr = ctx.expressions.append(
2375 crate::Expression::AccessIndex {
2376 base: structure_handle,
2377 index: member_index,
2378 },
2379 span,
2380 );
2381
2382 let length = ctx
2383 .expressions
2384 .append(crate::Expression::ArrayLength(member_ptr), span);
2385
2386 self.lookup_expression.insert(
2387 result_id,
2388 LookupExpression {
2389 handle: length,
2390 type_id: result_type_id,
2391 block_id,
2392 },
2393 );
2394 }
2395 Op::CopyMemory => {
2396 inst.expect_at_least(3)?;
2397 let target_id = self.next()?;
2398 let source_id = self.next()?;
2399 let _memory_access = if inst.wc != 3 {
2400 inst.expect(4)?;
2401 spirv::MemoryAccess::from_bits(self.next()?)
2402 .ok_or(Error::InvalidParameter(Op::CopyMemory))?
2403 } else {
2404 spirv::MemoryAccess::NONE
2405 };
2406
2407 let target = self.lookup_expression.lookup(target_id)?;
2409 let target_handle = get_expr_handle!(target_id, target);
2410 let source = self.lookup_expression.lookup(source_id)?;
2411 let source_handle = get_expr_handle!(source_id, source);
2412
2413 let value_expr = ctx.expressions.append(
2415 crate::Expression::Load {
2416 pointer: source_handle,
2417 },
2418 span,
2419 );
2420
2421 block.extend(emitter.finish(ctx.expressions));
2422 block.push(
2423 crate::Statement::Store {
2424 pointer: target_handle,
2425 value: value_expr,
2426 },
2427 span,
2428 );
2429
2430 emitter.start(ctx.expressions);
2431 }
2432 Op::ControlBarrier => {
2433 inst.expect(4)?;
2434 let exec_scope_id = self.next()?;
2435 let _mem_scope_raw = self.next()?;
2436 let semantics_id = self.next()?;
2437 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2438 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
2439
2440 let exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2441 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2442 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
2443 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
2444
2445 if exec_scope == spirv::Scope::Workgroup as u32
2446 || exec_scope == spirv::Scope::Subgroup as u32
2447 {
2448 let mut flags = crate::Barrier::empty();
2449 flags.set(
2450 crate::Barrier::STORAGE,
2451 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
2452 );
2453 flags.set(
2454 crate::Barrier::WORK_GROUP,
2455 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
2456 );
2457 flags.set(
2458 crate::Barrier::SUB_GROUP,
2459 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
2460 );
2461 flags.set(
2462 crate::Barrier::TEXTURE,
2463 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
2464 );
2465
2466 block.extend(emitter.finish(ctx.expressions));
2467 block.push(crate::Statement::ControlBarrier(flags), span);
2468 emitter.start(ctx.expressions);
2469 } else {
2470 log::warn!("Unsupported barrier execution scope: {exec_scope}");
2471 }
2472 }
2473 Op::MemoryBarrier => {
2474 inst.expect(3)?;
2475 let mem_scope_id = self.next()?;
2476 let semantics_id = self.next()?;
2477 let mem_scope_const = self.lookup_constant.lookup(mem_scope_id)?;
2478 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
2479
2480 let mem_scope = resolve_constant(ctx.gctx(), &mem_scope_const.inner)
2481 .ok_or(Error::InvalidBarrierScope(mem_scope_id))?;
2482 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
2483 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
2484
2485 let mut flags = if mem_scope == spirv::Scope::Device as u32 {
2486 crate::Barrier::STORAGE
2487 } else if mem_scope == spirv::Scope::Workgroup as u32 {
2488 crate::Barrier::WORK_GROUP
2489 } else if mem_scope == spirv::Scope::Subgroup as u32 {
2490 crate::Barrier::SUB_GROUP
2491 } else {
2492 crate::Barrier::empty()
2493 };
2494 flags.set(
2495 crate::Barrier::STORAGE,
2496 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
2497 );
2498 flags.set(
2499 crate::Barrier::WORK_GROUP,
2500 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
2501 );
2502 flags.set(
2503 crate::Barrier::SUB_GROUP,
2504 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
2505 );
2506 flags.set(
2507 crate::Barrier::TEXTURE,
2508 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
2509 );
2510
2511 block.extend(emitter.finish(ctx.expressions));
2512 block.push(crate::Statement::MemoryBarrier(flags), span);
2513 emitter.start(ctx.expressions);
2514 }
2515 Op::CopyObject => {
2516 inst.expect(4)?;
2517 let result_type_id = self.next()?;
2518 let result_id = self.next()?;
2519 let operand_id = self.next()?;
2520
2521 let lookup = self.lookup_expression.lookup(operand_id)?;
2522 let handle = get_expr_handle!(operand_id, lookup);
2523
2524 self.lookup_expression.insert(
2525 result_id,
2526 LookupExpression {
2527 handle,
2528 type_id: result_type_id,
2529 block_id,
2530 },
2531 );
2532 }
2533 Op::GroupNonUniformBallot => {
2534 inst.expect(5)?;
2535 block.extend(emitter.finish(ctx.expressions));
2536 let result_type_id = self.next()?;
2537 let result_id = self.next()?;
2538 let exec_scope_id = self.next()?;
2539 let predicate_id = self.next()?;
2540
2541 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2542 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2543 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2544 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2545
2546 let predicate = if self
2547 .lookup_constant
2548 .lookup(predicate_id)
2549 .ok()
2550 .filter(|predicate_const| match predicate_const.inner {
2551 Constant::Constant(constant) => matches!(
2552 ctx.gctx().global_expressions[ctx.gctx().constants[constant].init],
2553 crate::Expression::Literal(crate::Literal::Bool(true)),
2554 ),
2555 Constant::Override(_) => false,
2556 })
2557 .is_some()
2558 {
2559 None
2560 } else {
2561 let predicate_lookup = self.lookup_expression.lookup(predicate_id)?;
2562 let predicate_handle = get_expr_handle!(predicate_id, predicate_lookup);
2563 Some(predicate_handle)
2564 };
2565
2566 let result_handle = ctx
2567 .expressions
2568 .append(crate::Expression::SubgroupBallotResult, span);
2569 self.lookup_expression.insert(
2570 result_id,
2571 LookupExpression {
2572 handle: result_handle,
2573 type_id: result_type_id,
2574 block_id,
2575 },
2576 );
2577
2578 block.push(
2579 crate::Statement::SubgroupBallot {
2580 result: result_handle,
2581 predicate,
2582 },
2583 span,
2584 );
2585 emitter.start(ctx.expressions);
2586 }
2587 Op::GroupNonUniformAll
2588 | Op::GroupNonUniformAny
2589 | Op::GroupNonUniformIAdd
2590 | Op::GroupNonUniformFAdd
2591 | Op::GroupNonUniformIMul
2592 | Op::GroupNonUniformFMul
2593 | Op::GroupNonUniformSMax
2594 | Op::GroupNonUniformUMax
2595 | Op::GroupNonUniformFMax
2596 | Op::GroupNonUniformSMin
2597 | Op::GroupNonUniformUMin
2598 | Op::GroupNonUniformFMin
2599 | Op::GroupNonUniformBitwiseAnd
2600 | Op::GroupNonUniformBitwiseOr
2601 | Op::GroupNonUniformBitwiseXor
2602 | Op::GroupNonUniformLogicalAnd
2603 | Op::GroupNonUniformLogicalOr
2604 | Op::GroupNonUniformLogicalXor => {
2605 block.extend(emitter.finish(ctx.expressions));
2606 inst.expect(
2607 if matches!(inst.op, Op::GroupNonUniformAll | Op::GroupNonUniformAny) {
2608 5
2609 } else {
2610 6
2611 },
2612 )?;
2613 let result_type_id = self.next()?;
2614 let result_id = self.next()?;
2615 let exec_scope_id = self.next()?;
2616 let collective_op_id = match inst.op {
2617 Op::GroupNonUniformAll | Op::GroupNonUniformAny => {
2618 crate::CollectiveOperation::Reduce
2619 }
2620 _ => {
2621 let group_op_id = self.next()?;
2622 match spirv::GroupOperation::from_u32(group_op_id) {
2623 Some(spirv::GroupOperation::Reduce) => {
2624 crate::CollectiveOperation::Reduce
2625 }
2626 Some(spirv::GroupOperation::InclusiveScan) => {
2627 crate::CollectiveOperation::InclusiveScan
2628 }
2629 Some(spirv::GroupOperation::ExclusiveScan) => {
2630 crate::CollectiveOperation::ExclusiveScan
2631 }
2632 _ => return Err(Error::UnsupportedGroupOperation(group_op_id)),
2633 }
2634 }
2635 };
2636 let argument_id = self.next()?;
2637
2638 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2639 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2640
2641 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2642 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2643 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2644 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2645
2646 let op_id = match inst.op {
2647 Op::GroupNonUniformAll => crate::SubgroupOperation::All,
2648 Op::GroupNonUniformAny => crate::SubgroupOperation::Any,
2649 Op::GroupNonUniformIAdd | Op::GroupNonUniformFAdd => {
2650 crate::SubgroupOperation::Add
2651 }
2652 Op::GroupNonUniformIMul | Op::GroupNonUniformFMul => {
2653 crate::SubgroupOperation::Mul
2654 }
2655 Op::GroupNonUniformSMax
2656 | Op::GroupNonUniformUMax
2657 | Op::GroupNonUniformFMax => crate::SubgroupOperation::Max,
2658 Op::GroupNonUniformSMin
2659 | Op::GroupNonUniformUMin
2660 | Op::GroupNonUniformFMin => crate::SubgroupOperation::Min,
2661 Op::GroupNonUniformBitwiseAnd | Op::GroupNonUniformLogicalAnd => {
2662 crate::SubgroupOperation::And
2663 }
2664 Op::GroupNonUniformBitwiseOr | Op::GroupNonUniformLogicalOr => {
2665 crate::SubgroupOperation::Or
2666 }
2667 Op::GroupNonUniformBitwiseXor | Op::GroupNonUniformLogicalXor => {
2668 crate::SubgroupOperation::Xor
2669 }
2670 _ => unreachable!(),
2671 };
2672
2673 let result_type = self.lookup_type.lookup(result_type_id)?;
2674
2675 let result_handle = ctx.expressions.append(
2676 crate::Expression::SubgroupOperationResult {
2677 ty: result_type.handle,
2678 },
2679 span,
2680 );
2681 self.lookup_expression.insert(
2682 result_id,
2683 LookupExpression {
2684 handle: result_handle,
2685 type_id: result_type_id,
2686 block_id,
2687 },
2688 );
2689
2690 block.push(
2691 crate::Statement::SubgroupCollectiveOperation {
2692 result: result_handle,
2693 op: op_id,
2694 collective_op: collective_op_id,
2695 argument: argument_handle,
2696 },
2697 span,
2698 );
2699 emitter.start(ctx.expressions);
2700 }
2701 Op::GroupNonUniformBroadcastFirst
2702 | Op::GroupNonUniformBroadcast
2703 | Op::GroupNonUniformShuffle
2704 | Op::GroupNonUniformShuffleDown
2705 | Op::GroupNonUniformShuffleUp
2706 | Op::GroupNonUniformShuffleXor
2707 | Op::GroupNonUniformQuadBroadcast => {
2708 inst.expect(if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
2709 5
2710 } else {
2711 6
2712 })?;
2713 block.extend(emitter.finish(ctx.expressions));
2714 let result_type_id = self.next()?;
2715 let result_id = self.next()?;
2716 let exec_scope_id = self.next()?;
2717 let argument_id = self.next()?;
2718
2719 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2720 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2721
2722 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2723 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2724 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2725 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2726
2727 let mode = if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
2728 crate::GatherMode::BroadcastFirst
2729 } else {
2730 let index_id = self.next()?;
2731 let index_lookup = self.lookup_expression.lookup(index_id)?;
2732 let index_handle = get_expr_handle!(index_id, index_lookup);
2733 match inst.op {
2734 Op::GroupNonUniformBroadcast => {
2735 crate::GatherMode::Broadcast(index_handle)
2736 }
2737 Op::GroupNonUniformShuffle => crate::GatherMode::Shuffle(index_handle),
2738 Op::GroupNonUniformShuffleDown => {
2739 crate::GatherMode::ShuffleDown(index_handle)
2740 }
2741 Op::GroupNonUniformShuffleUp => {
2742 crate::GatherMode::ShuffleUp(index_handle)
2743 }
2744 Op::GroupNonUniformShuffleXor => {
2745 crate::GatherMode::ShuffleXor(index_handle)
2746 }
2747 Op::GroupNonUniformQuadBroadcast => {
2748 crate::GatherMode::QuadBroadcast(index_handle)
2749 }
2750 _ => unreachable!(),
2751 }
2752 };
2753
2754 let result_type = self.lookup_type.lookup(result_type_id)?;
2755
2756 let result_handle = ctx.expressions.append(
2757 crate::Expression::SubgroupOperationResult {
2758 ty: result_type.handle,
2759 },
2760 span,
2761 );
2762 self.lookup_expression.insert(
2763 result_id,
2764 LookupExpression {
2765 handle: result_handle,
2766 type_id: result_type_id,
2767 block_id,
2768 },
2769 );
2770
2771 block.push(
2772 crate::Statement::SubgroupGather {
2773 result: result_handle,
2774 mode,
2775 argument: argument_handle,
2776 },
2777 span,
2778 );
2779 emitter.start(ctx.expressions);
2780 }
2781 Op::GroupNonUniformQuadSwap => {
2782 inst.expect(6)?;
2783 block.extend(emitter.finish(ctx.expressions));
2784 let result_type_id = self.next()?;
2785 let result_id = self.next()?;
2786 let exec_scope_id = self.next()?;
2787 let argument_id = self.next()?;
2788 let direction_id = self.next()?;
2789
2790 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2791 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2792
2793 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2794 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2795 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2796 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2797
2798 let direction_const = self.lookup_constant.lookup(direction_id)?;
2799 let direction_const = resolve_constant(ctx.gctx(), &direction_const.inner)
2800 .ok_or(Error::InvalidOperand)?;
2801 let direction = match direction_const {
2802 0 => crate::Direction::X,
2803 1 => crate::Direction::Y,
2804 2 => crate::Direction::Diagonal,
2805 _ => unreachable!(),
2806 };
2807
2808 let result_type = self.lookup_type.lookup(result_type_id)?;
2809
2810 let result_handle = ctx.expressions.append(
2811 crate::Expression::SubgroupOperationResult {
2812 ty: result_type.handle,
2813 },
2814 span,
2815 );
2816 self.lookup_expression.insert(
2817 result_id,
2818 LookupExpression {
2819 handle: result_handle,
2820 type_id: result_type_id,
2821 block_id,
2822 },
2823 );
2824
2825 block.push(
2826 crate::Statement::SubgroupGather {
2827 mode: crate::GatherMode::QuadSwap(direction),
2828 result: result_handle,
2829 argument: argument_handle,
2830 },
2831 span,
2832 );
2833 emitter.start(ctx.expressions);
2834 }
2835 Op::AtomicLoad => {
2836 inst.expect(6)?;
2837 let start = self.data_offset;
2838 let result_type_id = self.next()?;
2839 let result_id = self.next()?;
2840 let pointer_id = self.next()?;
2841 let _scope_id = self.next()?;
2842 let _memory_semantics_id = self.next()?;
2843 let span = self.span_from_with_op(start);
2844
2845 log::trace!("\t\t\tlooking up expr {pointer_id:?}");
2846 let p_lexp_handle =
2847 get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?);
2848
2849 let expr = crate::Expression::Load {
2851 pointer: p_lexp_handle,
2852 };
2853 let handle = ctx.expressions.append(expr, span);
2854 self.lookup_expression.insert(
2855 result_id,
2856 LookupExpression {
2857 handle,
2858 type_id: result_type_id,
2859 block_id,
2860 },
2861 );
2862
2863 self.record_atomic_access(ctx, p_lexp_handle)?;
2865 }
2866 Op::AtomicStore => {
2867 inst.expect(5)?;
2868 let start = self.data_offset;
2869 let pointer_id = self.next()?;
2870 let _scope_id = self.next()?;
2871 let _memory_semantics_id = self.next()?;
2872 let value_id = self.next()?;
2873 let span = self.span_from_with_op(start);
2874
2875 log::trace!("\t\t\tlooking up pointer expr {pointer_id:?}");
2876 let p_lexp_handle =
2877 get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?);
2878
2879 log::trace!("\t\t\tlooking up value expr {pointer_id:?}");
2880 let v_lexp_handle =
2881 get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?);
2882
2883 block.extend(emitter.finish(ctx.expressions));
2884 let stmt = crate::Statement::Store {
2886 pointer: p_lexp_handle,
2887 value: v_lexp_handle,
2888 };
2889 block.push(stmt, span);
2890 emitter.start(ctx.expressions);
2891
2892 self.record_atomic_access(ctx, p_lexp_handle)?;
2894 }
2895 Op::AtomicIIncrement | Op::AtomicIDecrement => {
2896 inst.expect(6)?;
2897 let start = self.data_offset;
2898 let result_type_id = self.next()?;
2899 let result_id = self.next()?;
2900 let pointer_id = self.next()?;
2901 let _scope_id = self.next()?;
2902 let _memory_semantics_id = self.next()?;
2903 let span = self.span_from_with_op(start);
2904
2905 let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles(
2906 pointer_id,
2907 ctx,
2908 &mut emitter,
2909 &mut block,
2910 body_idx,
2911 )?;
2912
2913 block.extend(emitter.finish(ctx.expressions));
2914 let r_lexp_handle = {
2916 let expr = crate::Expression::AtomicResult {
2917 ty: p_base_ty_h,
2918 comparison: false,
2919 };
2920 let handle = ctx.expressions.append(expr, span);
2921 self.lookup_expression.insert(
2922 result_id,
2923 LookupExpression {
2924 handle,
2925 type_id: result_type_id,
2926 block_id,
2927 },
2928 );
2929 handle
2930 };
2931 emitter.start(ctx.expressions);
2932
2933 let one_lexp_handle = make_index_literal(
2935 ctx,
2936 1,
2937 &mut block,
2938 &mut emitter,
2939 p_base_ty_h,
2940 result_type_id,
2941 span,
2942 )?;
2943
2944 let stmt = crate::Statement::Atomic {
2946 pointer: p_exp_h,
2947 fun: match inst.op {
2948 Op::AtomicIIncrement => crate::AtomicFunction::Add,
2949 _ => crate::AtomicFunction::Subtract,
2950 },
2951 value: one_lexp_handle,
2952 result: Some(r_lexp_handle),
2953 };
2954 block.push(stmt, span);
2955
2956 self.record_atomic_access(ctx, p_exp_h)?;
2958 }
2959 Op::AtomicCompareExchange => {
2960 inst.expect(9)?;
2961
2962 let start = self.data_offset;
2963 let span = self.span_from_with_op(start);
2964 let result_type_id = self.next()?;
2965 let result_id = self.next()?;
2966 let pointer_id = self.next()?;
2967 let _memory_scope_id = self.next()?;
2968 let _equal_memory_semantics_id = self.next()?;
2969 let _unequal_memory_semantics_id = self.next()?;
2970 let value_id = self.next()?;
2971 let comparator_id = self.next()?;
2972
2973 let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles(
2974 pointer_id,
2975 ctx,
2976 &mut emitter,
2977 &mut block,
2978 body_idx,
2979 )?;
2980
2981 log::trace!("\t\t\tlooking up value expr {value_id:?}");
2982 let v_lexp_handle =
2983 get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?);
2984
2985 log::trace!("\t\t\tlooking up comparator expr {value_id:?}");
2986 let c_lexp_handle = get_expr_handle!(
2987 comparator_id,
2988 self.lookup_expression.lookup(comparator_id)?
2989 );
2990
2991 let crate::TypeInner::Scalar(scalar) = ctx.module.types[p_base_ty_h].inner
2995 else {
2996 return Err(
2997 crate::front::atomic_upgrade::Error::CompareExchangeNonScalarBaseType
2998 .into(),
2999 );
3000 };
3001
3002 let atomic_result_struct_ty_h = ctx.module.generate_predeclared_type(
3004 crate::PredeclaredType::AtomicCompareExchangeWeakResult(scalar),
3005 );
3006
3007 block.extend(emitter.finish(ctx.expressions));
3008
3009 let atomic_lexp_handle = {
3011 let expr = crate::Expression::AtomicResult {
3012 ty: atomic_result_struct_ty_h,
3013 comparison: true,
3014 };
3015 ctx.expressions.append(expr, span)
3016 };
3017
3018 {
3022 let expr = crate::Expression::AccessIndex {
3023 base: atomic_lexp_handle,
3024 index: 0,
3025 };
3026 let handle = ctx.expressions.append(expr, span);
3027 let _ = self.lookup_expression.insert(
3029 result_id,
3030 LookupExpression {
3031 handle,
3032 type_id: result_type_id,
3033 block_id,
3034 },
3035 );
3036 }
3037
3038 emitter.start(ctx.expressions);
3039
3040 let stmt = crate::Statement::Atomic {
3042 pointer: p_exp_h,
3043 fun: crate::AtomicFunction::Exchange {
3044 compare: Some(c_lexp_handle),
3045 },
3046 value: v_lexp_handle,
3047 result: Some(atomic_lexp_handle),
3048 };
3049 block.push(stmt, span);
3050
3051 self.record_atomic_access(ctx, p_exp_h)?;
3053 }
3054 Op::AtomicExchange
3055 | Op::AtomicIAdd
3056 | Op::AtomicISub
3057 | Op::AtomicSMin
3058 | Op::AtomicUMin
3059 | Op::AtomicSMax
3060 | Op::AtomicUMax
3061 | Op::AtomicAnd
3062 | Op::AtomicOr
3063 | Op::AtomicXor
3064 | Op::AtomicFAddEXT => self.parse_atomic_expr_with_value(
3065 inst,
3066 &mut emitter,
3067 ctx,
3068 &mut block,
3069 block_id,
3070 body_idx,
3071 match inst.op {
3072 Op::AtomicExchange => crate::AtomicFunction::Exchange { compare: None },
3073 Op::AtomicIAdd | Op::AtomicFAddEXT => crate::AtomicFunction::Add,
3074 Op::AtomicISub => crate::AtomicFunction::Subtract,
3075 Op::AtomicSMin => crate::AtomicFunction::Min,
3076 Op::AtomicUMin => crate::AtomicFunction::Min,
3077 Op::AtomicSMax => crate::AtomicFunction::Max,
3078 Op::AtomicUMax => crate::AtomicFunction::Max,
3079 Op::AtomicAnd => crate::AtomicFunction::And,
3080 Op::AtomicOr => crate::AtomicFunction::InclusiveOr,
3081 Op::AtomicXor => crate::AtomicFunction::ExclusiveOr,
3082 _ => unreachable!(),
3083 },
3084 )?,
3085
3086 _ => {
3087 return Err(Error::UnsupportedInstruction(self.state, inst.op));
3088 }
3089 }
3090 };
3091
3092 block.extend(emitter.finish(ctx.expressions));
3093 if let Some(stmt) = terminator {
3094 block.push(stmt, crate::Span::default());
3095 }
3096
3097 ctx.blocks.insert(block_id, block);
3100 let body = &mut ctx.bodies[body_idx];
3101 body.data.push(BodyFragment::BlockId(block_id));
3102 Ok(())
3103 }
3104}
3105
3106fn make_index_literal(
3107 ctx: &mut BlockContext,
3108 index: u32,
3109 block: &mut crate::Block,
3110 emitter: &mut crate::proc::Emitter,
3111 index_type: Handle<crate::Type>,
3112 index_type_id: spirv::Word,
3113 span: crate::Span,
3114) -> Result<Handle<crate::Expression>, Error> {
3115 block.extend(emitter.finish(ctx.expressions));
3116
3117 let literal = match ctx.module.types[index_type].inner.scalar_kind() {
3118 Some(crate::ScalarKind::Uint) => crate::Literal::U32(index),
3119 Some(crate::ScalarKind::Sint) => crate::Literal::I32(index as i32),
3120 _ => return Err(Error::InvalidIndexType(index_type_id)),
3121 };
3122 let expr = ctx
3123 .expressions
3124 .append(crate::Expression::Literal(literal), span);
3125
3126 emitter.start(ctx.expressions);
3127 Ok(expr)
3128}