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 #[allow(clippy::large_stack_frames)] pub(in crate::front::spv) fn next_block(
23 &mut self,
24 block_id: spirv::Word,
25 ctx: &mut BlockContext,
26 ) -> Result<(), Error> {
27 fn merger(body: &mut Body, target: &MergeBlockInformation) {
29 body.data.push(match *target {
30 MergeBlockInformation::LoopContinue => BodyFragment::Continue,
31 MergeBlockInformation::LoopMerge | MergeBlockInformation::SwitchMerge => {
32 BodyFragment::Break
33 }
34
35 MergeBlockInformation::SelectionMerge => return,
38 })
39 }
40
41 let mut emitter = crate::proc::Emitter::default();
42 emitter.start(ctx.expressions);
43
44 let mut body_idx = *ctx.body_for_label.entry(block_id).or_default();
58
59 let mut block = crate::Block::new();
63
64 let mut selection_merge_block = None;
70
71 macro_rules! get_expr_handle {
72 ($id:expr, $lexp:expr) => {
73 self.get_expr_handle($id, $lexp, ctx, &mut emitter, &mut block, body_idx)
74 };
75 }
76 macro_rules! parse_expr_op {
77 ($op:expr, BINARY) => {
78 self.parse_expr_binary_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
79 };
80
81 ($op:expr, SHIFT) => {
82 self.parse_expr_shift_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
83 };
84 ($op:expr, UNARY) => {
85 self.parse_expr_unary_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
86 };
87 ($axis:expr, $ctrl:expr, DERIVATIVE) => {
88 self.parse_expr_derivative(
89 ctx,
90 &mut emitter,
91 &mut block,
92 block_id,
93 body_idx,
94 ($axis, $ctrl),
95 )
96 };
97 }
98
99 let terminator = loop {
100 use spirv::Op;
101 let start = self.data_offset;
102 let inst = self.next_inst()?;
103 let span = crate::Span::from(start..(start + 4 * (inst.wc as usize)));
104 log::debug!("\t\t{:?} [{}]", inst.op, inst.wc);
105
106 match inst.op {
107 Op::Line => {
108 inst.expect(4)?;
109 let _file_id = self.next()?;
110 let _row_id = self.next()?;
111 let _col_id = self.next()?;
112 }
113 Op::NoLine => inst.expect(1)?,
114 Op::Undef => {
115 inst.expect(3)?;
116 let type_id = self.next()?;
117 let id = self.next()?;
118 let type_lookup = self.lookup_type.lookup(type_id)?;
119 let ty = type_lookup.handle;
120
121 self.lookup_expression.insert(
122 id,
123 LookupExpression {
124 handle: ctx
125 .expressions
126 .append(crate::Expression::ZeroValue(ty), span),
127 type_id,
128 block_id,
129 },
130 );
131 }
132 Op::Variable => {
133 inst.expect_at_least(4)?;
134 block.extend(emitter.finish(ctx.expressions));
135
136 let result_type_id = self.next()?;
137 let result_id = self.next()?;
138 let _storage_class = self.next()?;
139 let init = if inst.wc > 4 {
140 inst.expect(5)?;
141 let init_id = self.next()?;
142 let lconst = self.lookup_constant.lookup(init_id)?;
143 Some(ctx.expressions.append(lconst.inner.to_expr(), span))
144 } else {
145 None
146 };
147
148 let name = self
149 .future_decor
150 .remove(&result_id)
151 .and_then(|decor| decor.name);
152 if let Some(ref name) = name {
153 log::debug!("\t\t\tid={result_id} name={name}");
154 }
155 let lookup_ty = self.lookup_type.lookup(result_type_id)?;
156 let var_handle = ctx.local_arena.append(
157 crate::LocalVariable {
158 name,
159 ty: match ctx.module.types[lookup_ty.handle].inner {
160 crate::TypeInner::Pointer { base, .. } => base,
161 _ => lookup_ty.handle,
162 },
163 init,
164 },
165 span,
166 );
167
168 self.lookup_expression.insert(
169 result_id,
170 LookupExpression {
171 handle: ctx
172 .expressions
173 .append(crate::Expression::LocalVariable(var_handle), span),
174 type_id: result_type_id,
175 block_id,
176 },
177 );
178 emitter.start(ctx.expressions);
179 }
180 Op::Phi => {
181 inst.expect_at_least(3)?;
182 block.extend(emitter.finish(ctx.expressions));
183
184 let result_type_id = self.next()?;
185 let result_id = self.next()?;
186
187 let name = format!("phi_{result_id}");
188 let local = ctx.local_arena.append(
189 crate::LocalVariable {
190 name: Some(name),
191 ty: self.lookup_type.lookup(result_type_id)?.handle,
192 init: None,
193 },
194 self.span_from(start),
195 );
196 let pointer = ctx
197 .expressions
198 .append(crate::Expression::LocalVariable(local), span);
199
200 let in_count = (inst.wc - 3) / 2;
201 let mut phi = PhiExpression {
202 local,
203 expressions: Vec::with_capacity(in_count as usize),
204 };
205 for _ in 0..in_count {
206 let expr = self.next()?;
207 let block = self.next()?;
208 phi.expressions.push((expr, block));
209 }
210
211 ctx.phis.push(phi);
212 emitter.start(ctx.expressions);
213
214 self.lookup_expression.insert(
217 result_id,
218 LookupExpression {
219 handle: ctx
220 .expressions
221 .append(crate::Expression::Load { pointer }, span),
222 type_id: result_type_id,
223 block_id,
224 },
225 );
226 }
227 Op::AccessChain | Op::InBoundsAccessChain => {
228 struct AccessExpression {
229 base_handle: Handle<crate::Expression>,
230 type_id: spirv::Word,
231 load_override: Option<LookupLoadOverride>,
232 }
233
234 inst.expect_at_least(4)?;
235
236 let result_type_id = self.next()?;
237 let result_id = self.next()?;
238 let base_id = self.next()?;
239 log::trace!("\t\t\tlooking up expr {base_id:?}");
240
241 let mut acex = {
242 let lexp = self.lookup_expression.lookup(base_id)?;
243 let lty = self.lookup_type.lookup(lexp.type_id)?;
244
245 let dereference = match ctx.module.types[lty.handle].inner {
255 crate::TypeInner::BindingArray { .. } => false,
256 _ => true,
257 };
258
259 let type_id = if dereference {
260 lty.base_id.ok_or(Error::InvalidAccessType(lexp.type_id))?
261 } else {
262 lexp.type_id
263 };
264
265 AccessExpression {
266 base_handle: get_expr_handle!(base_id, lexp),
267 type_id,
268 load_override: self.lookup_load_override.get(&base_id).cloned(),
269 }
270 };
271
272 for _ in 4..inst.wc {
273 let access_id = self.next()?;
274 log::trace!("\t\t\tlooking up index expr {access_id:?}");
275 let index_expr = self.lookup_expression.lookup(access_id)?.clone();
276 let index_expr_handle = get_expr_handle!(access_id, &index_expr);
277 let index_expr_data = &ctx.expressions[index_expr.handle];
278 let index_maybe = match *index_expr_data {
279 crate::Expression::Constant(const_handle) => Some(
280 ctx.gctx()
281 .get_const_val(ctx.module.constants[const_handle].init)
282 .map_err(|_| {
283 Error::InvalidAccess(crate::Expression::Constant(
284 const_handle,
285 ))
286 })?,
287 ),
288 _ => None,
289 };
290
291 log::trace!("\t\t\tlooking up type {:?}", acex.type_id);
292 let type_lookup = self.lookup_type.lookup(acex.type_id)?;
293 let ty = &ctx.module.types[type_lookup.handle];
294 acex = match ty.inner {
295 crate::TypeInner::Struct { ref members, .. } => {
297 let index = index_maybe
298 .ok_or_else(|| Error::InvalidAccess(index_expr_data.clone()))?;
299
300 let lookup_member = self
301 .lookup_member
302 .get(&(type_lookup.handle, index))
303 .ok_or(Error::InvalidAccessType(acex.type_id))?;
304 let base_handle = ctx.expressions.append(
305 crate::Expression::AccessIndex {
306 base: acex.base_handle,
307 index,
308 },
309 span,
310 );
311
312 if let Some(crate::Binding::BuiltIn(built_in)) =
313 members[index as usize].binding
314 {
315 self.gl_per_vertex_builtin_access.insert(built_in);
316 }
317
318 AccessExpression {
319 base_handle,
320 type_id: lookup_member.type_id,
321 load_override: if lookup_member.row_major {
322 debug_assert!(acex.load_override.is_none());
323 let sub_type_lookup =
324 self.lookup_type.lookup(lookup_member.type_id)?;
325 Some(match ctx.module.types[sub_type_lookup.handle].inner {
326 crate::TypeInner::Matrix { .. } => {
328 let loaded = ctx.expressions.append(
329 crate::Expression::Load {
330 pointer: base_handle,
331 },
332 span,
333 );
334 let transposed = ctx.expressions.append(
335 crate::Expression::Math {
336 fun: crate::MathFunction::Transpose,
337 arg: loaded,
338 arg1: None,
339 arg2: None,
340 arg3: None,
341 },
342 span,
343 );
344 LookupLoadOverride::Loaded(transposed)
345 }
346 _ => LookupLoadOverride::Pending,
347 })
348 } else {
349 None
350 },
351 }
352 }
353 crate::TypeInner::Matrix { .. } => {
354 let load_override = match acex.load_override {
355 Some(LookupLoadOverride::Loaded(load_expr)) => {
357 let index = index_maybe.ok_or_else(|| {
358 Error::InvalidAccess(index_expr_data.clone())
359 })?;
360 let sub_handle = ctx.expressions.append(
361 crate::Expression::AccessIndex {
362 base: load_expr,
363 index,
364 },
365 span,
366 );
367 Some(LookupLoadOverride::Loaded(sub_handle))
368 }
369 _ => None,
370 };
371 let sub_expr = match index_maybe {
372 Some(index) => crate::Expression::AccessIndex {
373 base: acex.base_handle,
374 index,
375 },
376 None => crate::Expression::Access {
377 base: acex.base_handle,
378 index: index_expr_handle,
379 },
380 };
381 AccessExpression {
382 base_handle: ctx.expressions.append(sub_expr, span),
383 type_id: type_lookup
384 .base_id
385 .ok_or(Error::InvalidAccessType(acex.type_id))?,
386 load_override,
387 }
388 }
389 _ => {
391 let base_handle = ctx.expressions.append(
392 crate::Expression::Access {
393 base: acex.base_handle,
394 index: index_expr_handle,
395 },
396 span,
397 );
398 let load_override = match acex.load_override {
399 Some(lookup_load_override) => {
402 let sub_expr = match lookup_load_override {
403 LookupLoadOverride::Pending => {
406 let loaded = ctx.expressions.append(
407 crate::Expression::Load {
408 pointer: base_handle,
409 },
410 span,
411 );
412 ctx.expressions.append(
413 crate::Expression::Math {
414 fun: crate::MathFunction::Transpose,
415 arg: loaded,
416 arg1: None,
417 arg2: None,
418 arg3: None,
419 },
420 span,
421 )
422 }
423 LookupLoadOverride::Loaded(load_expr) => {
425 ctx.expressions.append(
426 crate::Expression::Access {
427 base: load_expr,
428 index: index_expr_handle,
429 },
430 span,
431 )
432 }
433 };
434 Some(LookupLoadOverride::Loaded(sub_expr))
435 }
436 None => None,
437 };
438 AccessExpression {
439 base_handle,
440 type_id: type_lookup
441 .base_id
442 .ok_or(Error::InvalidAccessType(acex.type_id))?,
443 load_override,
444 }
445 }
446 };
447 }
448
449 if let Some(load_expr) = acex.load_override {
450 self.lookup_load_override.insert(result_id, load_expr);
451 }
452 let lookup_expression = LookupExpression {
453 handle: acex.base_handle,
454 type_id: result_type_id,
455 block_id,
456 };
457 self.lookup_expression.insert(result_id, lookup_expression);
458 }
459 Op::VectorExtractDynamic => {
460 inst.expect(5)?;
461
462 let result_type_id = self.next()?;
463 let id = self.next()?;
464 let composite_id = self.next()?;
465 let index_id = self.next()?;
466
467 let root_lexp = self.lookup_expression.lookup(composite_id)?;
468 let root_handle = get_expr_handle!(composite_id, root_lexp);
469 let root_type_lookup = self.lookup_type.lookup(root_lexp.type_id)?;
470 let index_lexp = self.lookup_expression.lookup(index_id)?;
471 let index_handle = get_expr_handle!(index_id, index_lexp);
472 let index_type = self.lookup_type.lookup(index_lexp.type_id)?.handle;
473
474 let num_components = match ctx.module.types[root_type_lookup.handle].inner {
475 crate::TypeInner::Vector { size, .. } => size as u32,
476 _ => return Err(Error::InvalidVectorType(root_type_lookup.handle)),
477 };
478
479 let mut make_index = |ctx: &mut BlockContext, index: u32| {
480 make_index_literal(
481 ctx,
482 index,
483 &mut block,
484 &mut emitter,
485 index_type,
486 index_lexp.type_id,
487 span,
488 )
489 };
490
491 let index_expr = make_index(ctx, 0)?;
492 let mut handle = ctx.expressions.append(
493 crate::Expression::Access {
494 base: root_handle,
495 index: index_expr,
496 },
497 span,
498 );
499 for index in 1..num_components {
500 let index_expr = make_index(ctx, index)?;
501 let access_expr = ctx.expressions.append(
502 crate::Expression::Access {
503 base: root_handle,
504 index: index_expr,
505 },
506 span,
507 );
508 let cond = ctx.expressions.append(
509 crate::Expression::Binary {
510 op: crate::BinaryOperator::Equal,
511 left: index_expr,
512 right: index_handle,
513 },
514 span,
515 );
516 handle = ctx.expressions.append(
517 crate::Expression::Select {
518 condition: cond,
519 accept: access_expr,
520 reject: handle,
521 },
522 span,
523 );
524 }
525
526 self.lookup_expression.insert(
527 id,
528 LookupExpression {
529 handle,
530 type_id: result_type_id,
531 block_id,
532 },
533 );
534 }
535 Op::VectorInsertDynamic => {
536 inst.expect(6)?;
537
538 let result_type_id = self.next()?;
539 let id = self.next()?;
540 let composite_id = self.next()?;
541 let object_id = self.next()?;
542 let index_id = self.next()?;
543
544 let object_lexp = self.lookup_expression.lookup(object_id)?;
545 let object_handle = get_expr_handle!(object_id, object_lexp);
546 let root_lexp = self.lookup_expression.lookup(composite_id)?;
547 let root_handle = get_expr_handle!(composite_id, root_lexp);
548 let root_type_lookup = self.lookup_type.lookup(root_lexp.type_id)?;
549 let index_lexp = self.lookup_expression.lookup(index_id)?;
550 let index_handle = get_expr_handle!(index_id, index_lexp);
551 let index_type = self.lookup_type.lookup(index_lexp.type_id)?.handle;
552
553 let num_components = match ctx.module.types[root_type_lookup.handle].inner {
554 crate::TypeInner::Vector { size, .. } => size as u32,
555 _ => return Err(Error::InvalidVectorType(root_type_lookup.handle)),
556 };
557
558 let mut components = Vec::with_capacity(num_components as usize);
559 for index in 0..num_components {
560 let index_expr = make_index_literal(
561 ctx,
562 index,
563 &mut block,
564 &mut emitter,
565 index_type,
566 index_lexp.type_id,
567 span,
568 )?;
569 let access_expr = ctx.expressions.append(
570 crate::Expression::Access {
571 base: root_handle,
572 index: index_expr,
573 },
574 span,
575 );
576 let cond = ctx.expressions.append(
577 crate::Expression::Binary {
578 op: crate::BinaryOperator::Equal,
579 left: index_expr,
580 right: index_handle,
581 },
582 span,
583 );
584 let handle = ctx.expressions.append(
585 crate::Expression::Select {
586 condition: cond,
587 accept: object_handle,
588 reject: access_expr,
589 },
590 span,
591 );
592 components.push(handle);
593 }
594 let handle = ctx.expressions.append(
595 crate::Expression::Compose {
596 ty: root_type_lookup.handle,
597 components,
598 },
599 span,
600 );
601
602 self.lookup_expression.insert(
603 id,
604 LookupExpression {
605 handle,
606 type_id: result_type_id,
607 block_id,
608 },
609 );
610 }
611 Op::CompositeExtract => {
612 inst.expect_at_least(4)?;
613
614 let result_type_id = self.next()?;
615 let result_id = self.next()?;
616 let base_id = self.next()?;
617 log::trace!("\t\t\tlooking up expr {base_id:?}");
618 let mut lexp = self.lookup_expression.lookup(base_id)?.clone();
619 lexp.handle = get_expr_handle!(base_id, &lexp);
620 for _ in 4..inst.wc {
621 let index = self.next()?;
622 log::trace!("\t\t\tlooking up type {:?}", lexp.type_id);
623 let type_lookup = self.lookup_type.lookup(lexp.type_id)?;
624 let type_id = match ctx.module.types[type_lookup.handle].inner {
625 crate::TypeInner::Struct { .. } => {
626 self.lookup_member
627 .get(&(type_lookup.handle, index))
628 .ok_or(Error::InvalidAccessType(lexp.type_id))?
629 .type_id
630 }
631 crate::TypeInner::Array { .. }
632 | crate::TypeInner::Vector { .. }
633 | crate::TypeInner::Matrix { .. } => type_lookup
634 .base_id
635 .ok_or(Error::InvalidAccessType(lexp.type_id))?,
636 ref other => {
637 log::warn!("composite type {other:?}");
638 return Err(Error::UnsupportedType(type_lookup.handle));
639 }
640 };
641 lexp = LookupExpression {
642 handle: ctx.expressions.append(
643 crate::Expression::AccessIndex {
644 base: lexp.handle,
645 index,
646 },
647 span,
648 ),
649 type_id,
650 block_id,
651 };
652 }
653
654 self.lookup_expression.insert(
655 result_id,
656 LookupExpression {
657 handle: lexp.handle,
658 type_id: result_type_id,
659 block_id,
660 },
661 );
662 }
663 Op::CompositeInsert => {
664 inst.expect_at_least(5)?;
665
666 let result_type_id = self.next()?;
667 let id = self.next()?;
668 let object_id = self.next()?;
669 let composite_id = self.next()?;
670 let mut selections = Vec::with_capacity(inst.wc as usize - 5);
671 for _ in 5..inst.wc {
672 selections.push(self.next()?);
673 }
674
675 let object_lexp = self.lookup_expression.lookup(object_id)?.clone();
676 let object_handle = get_expr_handle!(object_id, &object_lexp);
677 let root_lexp = self.lookup_expression.lookup(composite_id)?.clone();
678 let root_handle = get_expr_handle!(composite_id, &root_lexp);
679 let handle = self.insert_composite(
680 root_handle,
681 result_type_id,
682 object_handle,
683 &selections,
684 &ctx.module.types,
685 ctx.expressions,
686 span,
687 )?;
688
689 self.lookup_expression.insert(
690 id,
691 LookupExpression {
692 handle,
693 type_id: result_type_id,
694 block_id,
695 },
696 );
697 }
698 Op::CompositeConstruct => {
699 inst.expect_at_least(3)?;
700
701 let result_type_id = self.next()?;
702 let id = self.next()?;
703 let mut components = Vec::with_capacity(inst.wc as usize - 2);
704 for _ in 3..inst.wc {
705 let comp_id = self.next()?;
706 log::trace!("\t\t\tlooking up expr {comp_id:?}");
707 let lexp = self.lookup_expression.lookup(comp_id)?;
708 let handle = get_expr_handle!(comp_id, lexp);
709 components.push(handle);
710 }
711 let ty = self.lookup_type.lookup(result_type_id)?.handle;
712 let first = components[0];
713 let expr = match ctx.module.types[ty].inner {
714 crate::TypeInner::Vector { size, .. }
716 if components.len() == size as usize
717 && components[1..].iter().all(|&c| c == first) =>
718 {
719 crate::Expression::Splat { size, value: first }
720 }
721 _ => crate::Expression::Compose { ty, components },
722 };
723 self.lookup_expression.insert(
724 id,
725 LookupExpression {
726 handle: ctx.expressions.append(expr, span),
727 type_id: result_type_id,
728 block_id,
729 },
730 );
731 }
732 Op::Load => {
733 inst.expect_at_least(4)?;
734
735 let result_type_id = self.next()?;
736 let result_id = self.next()?;
737 let pointer_id = self.next()?;
738 if inst.wc != 4 {
739 inst.expect(5)?;
740 let _memory_access = self.next()?;
741 }
742
743 let base_lexp = self.lookup_expression.lookup(pointer_id)?;
744 let base_handle = get_expr_handle!(pointer_id, base_lexp);
745 let type_lookup = self.lookup_type.lookup(base_lexp.type_id)?;
746 let handle = match ctx.module.types[type_lookup.handle].inner {
747 crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => {
748 base_handle
749 }
750 _ => match self.lookup_load_override.get(&pointer_id) {
751 Some(&LookupLoadOverride::Loaded(handle)) => handle,
752 _ => ctx.expressions.append(
754 crate::Expression::Load {
755 pointer: base_handle,
756 },
757 span,
758 ),
759 },
760 };
761
762 self.lookup_expression.insert(
763 result_id,
764 LookupExpression {
765 handle,
766 type_id: result_type_id,
767 block_id,
768 },
769 );
770 }
771 Op::Store => {
772 inst.expect_at_least(3)?;
773
774 let pointer_id = self.next()?;
775 let value_id = self.next()?;
776 if inst.wc != 3 {
777 inst.expect(4)?;
778 let _memory_access = self.next()?;
779 }
780 let base_expr = self.lookup_expression.lookup(pointer_id)?;
781 let base_handle = get_expr_handle!(pointer_id, base_expr);
782 let value_expr = self.lookup_expression.lookup(value_id)?;
783 let value_handle = get_expr_handle!(value_id, value_expr);
784
785 block.extend(emitter.finish(ctx.expressions));
786 block.push(
787 crate::Statement::Store {
788 pointer: base_handle,
789 value: value_handle,
790 },
791 span,
792 );
793 emitter.start(ctx.expressions);
794 }
795 Op::SNegate | Op::FNegate => {
797 inst.expect(4)?;
798 self.parse_expr_unary_op_sign_adjusted(
799 ctx,
800 &mut emitter,
801 &mut block,
802 block_id,
803 body_idx,
804 crate::UnaryOperator::Negate,
805 )?;
806 }
807 Op::IAdd
808 | Op::ISub
809 | Op::IMul
810 | Op::BitwiseOr
811 | Op::BitwiseXor
812 | Op::BitwiseAnd
813 | Op::SDiv
814 | Op::SRem => {
815 inst.expect(5)?;
816 let operator = map_binary_operator(inst.op)?;
817 self.parse_expr_binary_op_sign_adjusted(
818 ctx,
819 &mut emitter,
820 &mut block,
821 block_id,
822 body_idx,
823 operator,
824 SignAnchor::Result,
825 )?;
826 }
827 Op::IEqual | Op::INotEqual => {
828 inst.expect(5)?;
829 let operator = map_binary_operator(inst.op)?;
830 self.parse_expr_binary_op_sign_adjusted(
831 ctx,
832 &mut emitter,
833 &mut block,
834 block_id,
835 body_idx,
836 operator,
837 SignAnchor::Operand,
838 )?;
839 }
840 Op::FAdd => {
841 inst.expect(5)?;
842 parse_expr_op!(crate::BinaryOperator::Add, BINARY)?;
843 }
844 Op::FSub => {
845 inst.expect(5)?;
846 parse_expr_op!(crate::BinaryOperator::Subtract, BINARY)?;
847 }
848 Op::FMul => {
849 inst.expect(5)?;
850 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
851 }
852 Op::UDiv | Op::FDiv => {
853 inst.expect(5)?;
854 parse_expr_op!(crate::BinaryOperator::Divide, BINARY)?;
855 }
856 Op::UMod | Op::FRem => {
857 inst.expect(5)?;
858 parse_expr_op!(crate::BinaryOperator::Modulo, BINARY)?;
859 }
860 Op::SMod => {
861 inst.expect(5)?;
862
863 let start = self.data_offset;
866 let result_type_id = self.next()?;
867 let result_id = self.next()?;
868 let p1_id = self.next()?;
869 let p2_id = self.next()?;
870 let span = self.span_from_with_op(start);
871
872 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
873 let left = self.get_expr_handle(
874 p1_id,
875 p1_lexp,
876 ctx,
877 &mut emitter,
878 &mut block,
879 body_idx,
880 );
881 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
882 let right = self.get_expr_handle(
883 p2_id,
884 p2_lexp,
885 ctx,
886 &mut emitter,
887 &mut block,
888 body_idx,
889 );
890
891 let result_ty = self.lookup_type.lookup(result_type_id)?;
892 let inner = &ctx.module.types[result_ty.handle].inner;
893 let kind = inner.scalar_kind().unwrap();
894 let size = inner.size(ctx.gctx()) as u8;
895
896 let left_cast = ctx.expressions.append(
897 crate::Expression::As {
898 expr: left,
899 target: crate::Scalar {
900 kind: crate::ScalarKind::Float,
901 width: size,
902 },
903 },
904 span,
905 );
906 let right_cast = ctx.expressions.append(
907 crate::Expression::As {
908 expr: right,
909 target: crate::Scalar {
910 kind: crate::ScalarKind::Float,
911 width: size,
912 },
913 },
914 span,
915 );
916 let div = ctx.expressions.append(
917 crate::Expression::Binary {
918 op: crate::BinaryOperator::Divide,
919 left: left_cast,
920 right: right_cast,
921 },
922 span,
923 );
924 let floor = ctx.expressions.append(
925 crate::Expression::Math {
926 fun: crate::MathFunction::Floor,
927 arg: div,
928 arg1: None,
929 arg2: None,
930 arg3: None,
931 },
932 span,
933 );
934 let cast = ctx.expressions.append(
935 crate::Expression::As {
936 expr: floor,
937 target: crate::Scalar { kind, width: size },
938 },
939 span,
940 );
941 let mult = ctx.expressions.append(
942 crate::Expression::Binary {
943 op: crate::BinaryOperator::Multiply,
944 left: cast,
945 right,
946 },
947 span,
948 );
949 let sub = ctx.expressions.append(
950 crate::Expression::Binary {
951 op: crate::BinaryOperator::Subtract,
952 left,
953 right: mult,
954 },
955 span,
956 );
957 self.lookup_expression.insert(
958 result_id,
959 LookupExpression {
960 handle: sub,
961 type_id: result_type_id,
962 block_id,
963 },
964 );
965 }
966 Op::FMod => {
967 inst.expect(5)?;
968
969 let start = self.data_offset;
972 let span = self.span_from_with_op(start);
973
974 let result_type_id = self.next()?;
975 let result_id = self.next()?;
976 let p1_id = self.next()?;
977 let p2_id = self.next()?;
978
979 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
980 let left = self.get_expr_handle(
981 p1_id,
982 p1_lexp,
983 ctx,
984 &mut emitter,
985 &mut block,
986 body_idx,
987 );
988 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
989 let right = self.get_expr_handle(
990 p2_id,
991 p2_lexp,
992 ctx,
993 &mut emitter,
994 &mut block,
995 body_idx,
996 );
997
998 let div = ctx.expressions.append(
999 crate::Expression::Binary {
1000 op: crate::BinaryOperator::Divide,
1001 left,
1002 right,
1003 },
1004 span,
1005 );
1006 let floor = ctx.expressions.append(
1007 crate::Expression::Math {
1008 fun: crate::MathFunction::Floor,
1009 arg: div,
1010 arg1: None,
1011 arg2: None,
1012 arg3: None,
1013 },
1014 span,
1015 );
1016 let mult = ctx.expressions.append(
1017 crate::Expression::Binary {
1018 op: crate::BinaryOperator::Multiply,
1019 left: floor,
1020 right,
1021 },
1022 span,
1023 );
1024 let sub = ctx.expressions.append(
1025 crate::Expression::Binary {
1026 op: crate::BinaryOperator::Subtract,
1027 left,
1028 right: mult,
1029 },
1030 span,
1031 );
1032 self.lookup_expression.insert(
1033 result_id,
1034 LookupExpression {
1035 handle: sub,
1036 type_id: result_type_id,
1037 block_id,
1038 },
1039 );
1040 }
1041 Op::VectorTimesScalar
1042 | Op::VectorTimesMatrix
1043 | Op::MatrixTimesScalar
1044 | Op::MatrixTimesVector
1045 | Op::MatrixTimesMatrix => {
1046 inst.expect(5)?;
1047 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
1048 }
1049 Op::Transpose => {
1050 inst.expect(4)?;
1051
1052 let result_type_id = self.next()?;
1053 let result_id = self.next()?;
1054 let matrix_id = self.next()?;
1055 let matrix_lexp = self.lookup_expression.lookup(matrix_id)?;
1056 let matrix_handle = get_expr_handle!(matrix_id, matrix_lexp);
1057 let expr = crate::Expression::Math {
1058 fun: crate::MathFunction::Transpose,
1059 arg: matrix_handle,
1060 arg1: None,
1061 arg2: None,
1062 arg3: None,
1063 };
1064 self.lookup_expression.insert(
1065 result_id,
1066 LookupExpression {
1067 handle: ctx.expressions.append(expr, span),
1068 type_id: result_type_id,
1069 block_id,
1070 },
1071 );
1072 }
1073 Op::Dot => {
1074 inst.expect(5)?;
1075
1076 let result_type_id = self.next()?;
1077 let result_id = self.next()?;
1078 let left_id = self.next()?;
1079 let right_id = self.next()?;
1080 let left_lexp = self.lookup_expression.lookup(left_id)?;
1081 let left_handle = get_expr_handle!(left_id, left_lexp);
1082 let right_lexp = self.lookup_expression.lookup(right_id)?;
1083 let right_handle = get_expr_handle!(right_id, right_lexp);
1084 let expr = crate::Expression::Math {
1085 fun: crate::MathFunction::Dot,
1086 arg: left_handle,
1087 arg1: Some(right_handle),
1088 arg2: None,
1089 arg3: None,
1090 };
1091 self.lookup_expression.insert(
1092 result_id,
1093 LookupExpression {
1094 handle: ctx.expressions.append(expr, span),
1095 type_id: result_type_id,
1096 block_id,
1097 },
1098 );
1099 }
1100 Op::BitFieldInsert => {
1101 inst.expect(7)?;
1102
1103 let start = self.data_offset;
1104 let span = self.span_from_with_op(start);
1105
1106 let result_type_id = self.next()?;
1107 let result_id = self.next()?;
1108 let base_id = self.next()?;
1109 let insert_id = self.next()?;
1110 let offset_id = self.next()?;
1111 let count_id = self.next()?;
1112 let base_lexp = self.lookup_expression.lookup(base_id)?;
1113 let base_handle = get_expr_handle!(base_id, base_lexp);
1114 let insert_lexp = self.lookup_expression.lookup(insert_id)?;
1115 let insert_handle = get_expr_handle!(insert_id, insert_lexp);
1116 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
1117 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
1118 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
1119 let count_lexp = self.lookup_expression.lookup(count_id)?;
1120 let count_handle = get_expr_handle!(count_id, count_lexp);
1121 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
1122
1123 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
1124 .inner
1125 .scalar_kind()
1126 .unwrap();
1127 let count_kind = ctx.module.types[count_lookup_ty.handle]
1128 .inner
1129 .scalar_kind()
1130 .unwrap();
1131
1132 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
1133 ctx.expressions.append(
1134 crate::Expression::As {
1135 expr: offset_handle,
1136 target: crate::Scalar::U32,
1137 },
1138 span,
1139 )
1140 } else {
1141 offset_handle
1142 };
1143
1144 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
1145 ctx.expressions.append(
1146 crate::Expression::As {
1147 expr: count_handle,
1148 target: crate::Scalar::U32,
1149 },
1150 span,
1151 )
1152 } else {
1153 count_handle
1154 };
1155
1156 let expr = crate::Expression::Math {
1157 fun: crate::MathFunction::InsertBits,
1158 arg: base_handle,
1159 arg1: Some(insert_handle),
1160 arg2: Some(offset_cast_handle),
1161 arg3: Some(count_cast_handle),
1162 };
1163 self.lookup_expression.insert(
1164 result_id,
1165 LookupExpression {
1166 handle: ctx.expressions.append(expr, span),
1167 type_id: result_type_id,
1168 block_id,
1169 },
1170 );
1171 }
1172 Op::BitFieldSExtract | Op::BitFieldUExtract => {
1173 inst.expect(6)?;
1174
1175 let result_type_id = self.next()?;
1176 let result_id = self.next()?;
1177 let base_id = self.next()?;
1178 let offset_id = self.next()?;
1179 let count_id = self.next()?;
1180 let base_lexp = self.lookup_expression.lookup(base_id)?;
1181 let base_handle = get_expr_handle!(base_id, base_lexp);
1182 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
1183 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
1184 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
1185 let count_lexp = self.lookup_expression.lookup(count_id)?;
1186 let count_handle = get_expr_handle!(count_id, count_lexp);
1187 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
1188
1189 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
1190 .inner
1191 .scalar_kind()
1192 .unwrap();
1193 let count_kind = ctx.module.types[count_lookup_ty.handle]
1194 .inner
1195 .scalar_kind()
1196 .unwrap();
1197
1198 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
1199 ctx.expressions.append(
1200 crate::Expression::As {
1201 expr: offset_handle,
1202 target: crate::Scalar::U32,
1203 },
1204 span,
1205 )
1206 } else {
1207 offset_handle
1208 };
1209
1210 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
1211 ctx.expressions.append(
1212 crate::Expression::As {
1213 expr: count_handle,
1214 target: crate::Scalar::U32,
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 = if inst.op == Op::Bitcast {
1622 crate::Expression::Bitcast {
1623 expr: get_expr_handle!(value_id, value_lexp),
1624 ty: ty_lookup.handle,
1625 }
1626 } else {
1627 crate::Expression::As {
1628 expr: get_expr_handle!(value_id, value_lexp),
1629 target: scalar,
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::GlslStd450Op 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 expr: selector_handle,
2155 target: crate::Scalar::I32,
2156 },
2157 span,
2158 )
2159 }
2160 crate::TypeInner::Scalar(crate::Scalar {
2161 kind: crate::ScalarKind::Sint,
2162 width: _,
2163 }) => selector_handle,
2164 ref other => unimplemented!("Unexpected selector {:?}", other),
2165 };
2166
2167 self.switch_cases.clear();
2169
2170 for _ in 0..(inst.wc - 3) / 2 {
2171 let literal = self.next()?;
2172 let target = self.next()?;
2173
2174 let case_body_idx = ctx.bodies.len();
2175
2176 if let Some(&mut (_, ref mut literals)) = self.switch_cases.get_mut(&target)
2180 {
2181 literals.push(literal as i32);
2182 continue;
2183 }
2184
2185 let mut body = Body::with_parent(body_idx);
2186
2187 if let Some(info) = ctx.mergers.get(&target) {
2188 merger(&mut body, info);
2189 }
2190
2191 ctx.bodies.push(body);
2192 ctx.body_for_label.entry(target).or_insert(case_body_idx);
2193
2194 self.switch_cases
2197 .insert(target, (case_body_idx, vec![literal as i32]));
2198 }
2199
2200 let mut cases = Vec::with_capacity((inst.wc as usize - 3) / 2);
2209 for &(case_body_idx, ref literals) in self.switch_cases.values() {
2210 let value = literals[0];
2211
2212 for &literal in literals.iter().skip(1) {
2213 let empty_body_idx = ctx.bodies.len();
2214 let body = Body::with_parent(body_idx);
2215
2216 ctx.bodies.push(body);
2217
2218 cases.push((literal, empty_body_idx));
2219 }
2220
2221 cases.push((value, case_body_idx));
2222 }
2223
2224 block.extend(emitter.finish(ctx.expressions));
2225
2226 let body = &mut ctx.bodies[body_idx];
2227 ctx.blocks.insert(block_id, block);
2228 body.data.reserve(2);
2230 body.data.push(BodyFragment::BlockId(block_id));
2231 body.data.push(BodyFragment::Switch {
2232 selector,
2233 cases,
2234 default,
2235 });
2236
2237 return Ok(());
2238 }
2239 Op::SelectionMerge => {
2240 inst.expect(3)?;
2241 let merge_block_id = self.next()?;
2242 let _selection_control = self.next()?;
2244
2245 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
2248
2249 ctx.mergers
2252 .insert(merge_block_id, MergeBlockInformation::SelectionMerge);
2253
2254 selection_merge_block = Some(merge_block_id);
2255 }
2256 Op::LoopMerge => {
2257 inst.expect_at_least(4)?;
2258 let merge_block_id = self.next()?;
2259 let continuing = self.next()?;
2260
2261 for _ in 0..inst.wc - 3 {
2263 self.next()?;
2264 }
2265
2266 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
2269 ctx.mergers
2272 .insert(merge_block_id, MergeBlockInformation::LoopMerge);
2273
2274 let loop_body_idx = ctx.bodies.len();
2275 ctx.bodies.push(Body::with_parent(body_idx));
2276
2277 let continue_idx = ctx.bodies.len();
2278 ctx.bodies.push(Body::with_parent(loop_body_idx));
2280 ctx.body_for_label.entry(continuing).or_insert(continue_idx);
2281 ctx.mergers
2284 .insert(continuing, MergeBlockInformation::LoopContinue);
2285
2286 ctx.body_for_label.insert(block_id, loop_body_idx);
2288
2289 let parent_body = &mut ctx.bodies[body_idx];
2290 parent_body.data.push(BodyFragment::Loop {
2291 body: loop_body_idx,
2292 continuing: continue_idx,
2293 break_if: None,
2294 });
2295 body_idx = loop_body_idx;
2296 }
2297 Op::DPdxCoarse => {
2298 parse_expr_op!(
2299 crate::DerivativeAxis::X,
2300 crate::DerivativeControl::Coarse,
2301 DERIVATIVE
2302 )?;
2303 }
2304 Op::DPdyCoarse => {
2305 parse_expr_op!(
2306 crate::DerivativeAxis::Y,
2307 crate::DerivativeControl::Coarse,
2308 DERIVATIVE
2309 )?;
2310 }
2311 Op::FwidthCoarse => {
2312 parse_expr_op!(
2313 crate::DerivativeAxis::Width,
2314 crate::DerivativeControl::Coarse,
2315 DERIVATIVE
2316 )?;
2317 }
2318 Op::DPdxFine => {
2319 parse_expr_op!(
2320 crate::DerivativeAxis::X,
2321 crate::DerivativeControl::Fine,
2322 DERIVATIVE
2323 )?;
2324 }
2325 Op::DPdyFine => {
2326 parse_expr_op!(
2327 crate::DerivativeAxis::Y,
2328 crate::DerivativeControl::Fine,
2329 DERIVATIVE
2330 )?;
2331 }
2332 Op::FwidthFine => {
2333 parse_expr_op!(
2334 crate::DerivativeAxis::Width,
2335 crate::DerivativeControl::Fine,
2336 DERIVATIVE
2337 )?;
2338 }
2339 Op::DPdx => {
2340 parse_expr_op!(
2341 crate::DerivativeAxis::X,
2342 crate::DerivativeControl::None,
2343 DERIVATIVE
2344 )?;
2345 }
2346 Op::DPdy => {
2347 parse_expr_op!(
2348 crate::DerivativeAxis::Y,
2349 crate::DerivativeControl::None,
2350 DERIVATIVE
2351 )?;
2352 }
2353 Op::Fwidth => {
2354 parse_expr_op!(
2355 crate::DerivativeAxis::Width,
2356 crate::DerivativeControl::None,
2357 DERIVATIVE
2358 )?;
2359 }
2360 Op::ArrayLength => {
2361 inst.expect(5)?;
2362 let result_type_id = self.next()?;
2363 let result_id = self.next()?;
2364 let structure_id = self.next()?;
2365 let member_index = self.next()?;
2366
2367 let structure_ptr = self.lookup_expression.lookup(structure_id)?;
2371 let structure_handle = get_expr_handle!(structure_id, structure_ptr);
2372
2373 let member_ptr = ctx.expressions.append(
2374 crate::Expression::AccessIndex {
2375 base: structure_handle,
2376 index: member_index,
2377 },
2378 span,
2379 );
2380
2381 let length = ctx
2382 .expressions
2383 .append(crate::Expression::ArrayLength(member_ptr), span);
2384
2385 self.lookup_expression.insert(
2386 result_id,
2387 LookupExpression {
2388 handle: length,
2389 type_id: result_type_id,
2390 block_id,
2391 },
2392 );
2393 }
2394 Op::CopyMemory => {
2395 inst.expect_at_least(3)?;
2396 let target_id = self.next()?;
2397 let source_id = self.next()?;
2398 let _memory_access = if inst.wc != 3 {
2399 inst.expect(4)?;
2400 spirv::MemoryAccess::from_bits(self.next()?)
2401 .ok_or(Error::InvalidParameter(Op::CopyMemory))?
2402 } else {
2403 spirv::MemoryAccess::NONE
2404 };
2405
2406 let target = self.lookup_expression.lookup(target_id)?;
2408 let target_handle = get_expr_handle!(target_id, target);
2409 let source = self.lookup_expression.lookup(source_id)?;
2410 let source_handle = get_expr_handle!(source_id, source);
2411
2412 let value_expr = ctx.expressions.append(
2414 crate::Expression::Load {
2415 pointer: source_handle,
2416 },
2417 span,
2418 );
2419
2420 block.extend(emitter.finish(ctx.expressions));
2421 block.push(
2422 crate::Statement::Store {
2423 pointer: target_handle,
2424 value: value_expr,
2425 },
2426 span,
2427 );
2428
2429 emitter.start(ctx.expressions);
2430 }
2431 Op::ControlBarrier => {
2432 inst.expect(4)?;
2433 let exec_scope_id = self.next()?;
2434 let _mem_scope_raw = self.next()?;
2435 let semantics_id = self.next()?;
2436 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2437 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
2438
2439 let exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2440 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2441 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
2442 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
2443
2444 if exec_scope == spirv::Scope::Workgroup as u32
2445 || exec_scope == spirv::Scope::Subgroup as u32
2446 {
2447 let mut flags = crate::Barrier::empty();
2448 flags.set(
2449 crate::Barrier::STORAGE,
2450 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
2451 );
2452 flags.set(
2453 crate::Barrier::WORK_GROUP,
2454 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
2455 );
2456 flags.set(
2457 crate::Barrier::SUB_GROUP,
2458 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
2459 );
2460 flags.set(
2461 crate::Barrier::TEXTURE,
2462 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
2463 );
2464
2465 block.extend(emitter.finish(ctx.expressions));
2466 block.push(crate::Statement::ControlBarrier(flags), span);
2467 emitter.start(ctx.expressions);
2468 } else {
2469 log::warn!("Unsupported barrier execution scope: {exec_scope}");
2470 }
2471 }
2472 Op::MemoryBarrier => {
2473 inst.expect(3)?;
2474 let mem_scope_id = self.next()?;
2475 let semantics_id = self.next()?;
2476 let mem_scope_const = self.lookup_constant.lookup(mem_scope_id)?;
2477 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
2478
2479 let mem_scope = resolve_constant(ctx.gctx(), &mem_scope_const.inner)
2480 .ok_or(Error::InvalidBarrierScope(mem_scope_id))?;
2481 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
2482 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
2483
2484 let mut flags = if mem_scope == spirv::Scope::Device as u32 {
2485 crate::Barrier::STORAGE
2486 } else if mem_scope == spirv::Scope::Workgroup as u32 {
2487 crate::Barrier::WORK_GROUP
2488 } else if mem_scope == spirv::Scope::Subgroup as u32 {
2489 crate::Barrier::SUB_GROUP
2490 } else {
2491 crate::Barrier::empty()
2492 };
2493 flags.set(
2494 crate::Barrier::STORAGE,
2495 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
2496 );
2497 flags.set(
2498 crate::Barrier::WORK_GROUP,
2499 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
2500 );
2501 flags.set(
2502 crate::Barrier::SUB_GROUP,
2503 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
2504 );
2505 flags.set(
2506 crate::Barrier::TEXTURE,
2507 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
2508 );
2509
2510 block.extend(emitter.finish(ctx.expressions));
2511 block.push(crate::Statement::MemoryBarrier(flags), span);
2512 emitter.start(ctx.expressions);
2513 }
2514 Op::CopyObject => {
2515 inst.expect(4)?;
2516 let result_type_id = self.next()?;
2517 let result_id = self.next()?;
2518 let operand_id = self.next()?;
2519
2520 let lookup = self.lookup_expression.lookup(operand_id)?;
2521 let handle = get_expr_handle!(operand_id, lookup);
2522
2523 self.lookup_expression.insert(
2524 result_id,
2525 LookupExpression {
2526 handle,
2527 type_id: result_type_id,
2528 block_id,
2529 },
2530 );
2531 }
2532 Op::GroupNonUniformBallot => {
2533 inst.expect(5)?;
2534 let result_type_id = self.next()?;
2535 let result_id = self.next()?;
2536 let exec_scope_id = self.next()?;
2537 let predicate_id = self.next()?;
2538
2539 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2540 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2541 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2542 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2543
2544 let predicate = if self
2545 .lookup_constant
2546 .lookup(predicate_id)
2547 .ok()
2548 .filter(|predicate_const| match predicate_const.inner {
2549 Constant::Constant(constant) => matches!(
2550 ctx.gctx().global_expressions[ctx.gctx().constants[constant].init],
2551 crate::Expression::Literal(crate::Literal::Bool(true)),
2552 ),
2553 Constant::Override(_) => false,
2554 })
2555 .is_some()
2556 {
2557 None
2558 } else {
2559 let predicate_lookup = self.lookup_expression.lookup(predicate_id)?;
2560 let predicate_handle = get_expr_handle!(predicate_id, predicate_lookup);
2561 Some(predicate_handle)
2562 };
2563
2564 block.extend(emitter.finish(ctx.expressions));
2565 let result_handle = ctx
2566 .expressions
2567 .append(crate::Expression::SubgroupBallotResult, span);
2568 self.lookup_expression.insert(
2569 result_id,
2570 LookupExpression {
2571 handle: result_handle,
2572 type_id: result_type_id,
2573 block_id,
2574 },
2575 );
2576
2577 block.push(
2578 crate::Statement::SubgroupBallot {
2579 result: result_handle,
2580 predicate,
2581 },
2582 span,
2583 );
2584 emitter.start(ctx.expressions);
2585 }
2586 Op::GroupNonUniformAll
2587 | Op::GroupNonUniformAny
2588 | Op::GroupNonUniformIAdd
2589 | Op::GroupNonUniformFAdd
2590 | Op::GroupNonUniformIMul
2591 | Op::GroupNonUniformFMul
2592 | Op::GroupNonUniformSMax
2593 | Op::GroupNonUniformUMax
2594 | Op::GroupNonUniformFMax
2595 | Op::GroupNonUniformSMin
2596 | Op::GroupNonUniformUMin
2597 | Op::GroupNonUniformFMin
2598 | Op::GroupNonUniformBitwiseAnd
2599 | Op::GroupNonUniformBitwiseOr
2600 | Op::GroupNonUniformBitwiseXor
2601 | Op::GroupNonUniformLogicalAnd
2602 | Op::GroupNonUniformLogicalOr
2603 | Op::GroupNonUniformLogicalXor => {
2604 inst.expect(
2605 if matches!(inst.op, Op::GroupNonUniformAll | Op::GroupNonUniformAny) {
2606 5
2607 } else {
2608 6
2609 },
2610 )?;
2611 let result_type_id = self.next()?;
2612 let result_id = self.next()?;
2613 let exec_scope_id = self.next()?;
2614 let collective_op_id = match inst.op {
2615 Op::GroupNonUniformAll | Op::GroupNonUniformAny => {
2616 crate::CollectiveOperation::Reduce
2617 }
2618 _ => {
2619 let group_op_id = self.next()?;
2620 match spirv::GroupOperation::from_u32(group_op_id) {
2621 Some(spirv::GroupOperation::Reduce) => {
2622 crate::CollectiveOperation::Reduce
2623 }
2624 Some(spirv::GroupOperation::InclusiveScan) => {
2625 crate::CollectiveOperation::InclusiveScan
2626 }
2627 Some(spirv::GroupOperation::ExclusiveScan) => {
2628 crate::CollectiveOperation::ExclusiveScan
2629 }
2630 _ => return Err(Error::UnsupportedGroupOperation(group_op_id)),
2631 }
2632 }
2633 };
2634 let argument_id = self.next()?;
2635
2636 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2637 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2638
2639 block.extend(emitter.finish(ctx.expressions));
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 let result_type_id = self.next()?;
2714 let result_id = self.next()?;
2715 let exec_scope_id = self.next()?;
2716 let argument_id = self.next()?;
2717
2718 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2719 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2720
2721 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2722 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2723 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2724 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2725
2726 let mode = if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
2727 crate::GatherMode::BroadcastFirst
2728 } else {
2729 let index_id = self.next()?;
2730 let index_lookup = self.lookup_expression.lookup(index_id)?;
2731 let index_handle = get_expr_handle!(index_id, index_lookup);
2732 match inst.op {
2733 Op::GroupNonUniformBroadcast => {
2734 crate::GatherMode::Broadcast(index_handle)
2735 }
2736 Op::GroupNonUniformShuffle => crate::GatherMode::Shuffle(index_handle),
2737 Op::GroupNonUniformShuffleDown => {
2738 crate::GatherMode::ShuffleDown(index_handle)
2739 }
2740 Op::GroupNonUniformShuffleUp => {
2741 crate::GatherMode::ShuffleUp(index_handle)
2742 }
2743 Op::GroupNonUniformShuffleXor => {
2744 crate::GatherMode::ShuffleXor(index_handle)
2745 }
2746 Op::GroupNonUniformQuadBroadcast => {
2747 crate::GatherMode::QuadBroadcast(index_handle)
2748 }
2749 _ => unreachable!(),
2750 }
2751 };
2752
2753 block.extend(emitter.finish(ctx.expressions));
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 let result_type_id = self.next()?;
2784 let result_id = self.next()?;
2785 let exec_scope_id = self.next()?;
2786 let argument_id = self.next()?;
2787 let direction_id = self.next()?;
2788
2789 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2790 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2791
2792 block.extend(emitter.finish(ctx.expressions));
2793
2794 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2795 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2796 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2797 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2798
2799 let direction_const = self.lookup_constant.lookup(direction_id)?;
2800 let direction_const = resolve_constant(ctx.gctx(), &direction_const.inner)
2801 .ok_or(Error::InvalidOperand)?;
2802 let direction = match direction_const {
2803 0 => crate::Direction::X,
2804 1 => crate::Direction::Y,
2805 2 => crate::Direction::Diagonal,
2806 _ => unreachable!(),
2807 };
2808
2809 let result_type = self.lookup_type.lookup(result_type_id)?;
2810
2811 let result_handle = ctx.expressions.append(
2812 crate::Expression::SubgroupOperationResult {
2813 ty: result_type.handle,
2814 },
2815 span,
2816 );
2817 self.lookup_expression.insert(
2818 result_id,
2819 LookupExpression {
2820 handle: result_handle,
2821 type_id: result_type_id,
2822 block_id,
2823 },
2824 );
2825
2826 block.push(
2827 crate::Statement::SubgroupGather {
2828 mode: crate::GatherMode::QuadSwap(direction),
2829 result: result_handle,
2830 argument: argument_handle,
2831 },
2832 span,
2833 );
2834 emitter.start(ctx.expressions);
2835 }
2836 Op::AtomicLoad => {
2837 inst.expect(6)?;
2838 let start = self.data_offset;
2839 let result_type_id = self.next()?;
2840 let result_id = self.next()?;
2841 let pointer_id = self.next()?;
2842 let _scope_id = self.next()?;
2843 let _memory_semantics_id = self.next()?;
2844 let span = self.span_from_with_op(start);
2845
2846 log::trace!("\t\t\tlooking up expr {pointer_id:?}");
2847 let p_lexp_handle =
2848 get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?);
2849
2850 let expr = crate::Expression::Load {
2852 pointer: p_lexp_handle,
2853 };
2854 let handle = ctx.expressions.append(expr, span);
2855 self.lookup_expression.insert(
2856 result_id,
2857 LookupExpression {
2858 handle,
2859 type_id: result_type_id,
2860 block_id,
2861 },
2862 );
2863
2864 self.record_atomic_access(ctx, p_lexp_handle)?;
2866 }
2867 Op::AtomicStore => {
2868 inst.expect(5)?;
2869 let start = self.data_offset;
2870 let pointer_id = self.next()?;
2871 let _scope_id = self.next()?;
2872 let _memory_semantics_id = self.next()?;
2873 let value_id = self.next()?;
2874 let span = self.span_from_with_op(start);
2875
2876 log::trace!("\t\t\tlooking up pointer expr {pointer_id:?}");
2877 let p_lexp_handle =
2878 get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?);
2879
2880 log::trace!("\t\t\tlooking up value expr {pointer_id:?}");
2881 let v_lexp_handle =
2882 get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?);
2883
2884 block.extend(emitter.finish(ctx.expressions));
2885 let stmt = crate::Statement::Store {
2887 pointer: p_lexp_handle,
2888 value: v_lexp_handle,
2889 };
2890 block.push(stmt, span);
2891 emitter.start(ctx.expressions);
2892
2893 self.record_atomic_access(ctx, p_lexp_handle)?;
2895 }
2896 Op::AtomicIIncrement | Op::AtomicIDecrement => {
2897 inst.expect(6)?;
2898 let start = self.data_offset;
2899 let result_type_id = self.next()?;
2900 let result_id = self.next()?;
2901 let pointer_id = self.next()?;
2902 let _scope_id = self.next()?;
2903 let _memory_semantics_id = self.next()?;
2904 let span = self.span_from_with_op(start);
2905
2906 let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles(
2907 pointer_id,
2908 ctx,
2909 &mut emitter,
2910 &mut block,
2911 body_idx,
2912 )?;
2913
2914 block.extend(emitter.finish(ctx.expressions));
2915 let r_lexp_handle = {
2917 let expr = crate::Expression::AtomicResult {
2918 ty: p_base_ty_h,
2919 comparison: false,
2920 };
2921 let handle = ctx.expressions.append(expr, span);
2922 self.lookup_expression.insert(
2923 result_id,
2924 LookupExpression {
2925 handle,
2926 type_id: result_type_id,
2927 block_id,
2928 },
2929 );
2930 handle
2931 };
2932 emitter.start(ctx.expressions);
2933
2934 let one_lexp_handle = make_index_literal(
2936 ctx,
2937 1,
2938 &mut block,
2939 &mut emitter,
2940 p_base_ty_h,
2941 result_type_id,
2942 span,
2943 )?;
2944
2945 let stmt = crate::Statement::Atomic {
2947 pointer: p_exp_h,
2948 fun: match inst.op {
2949 Op::AtomicIIncrement => crate::AtomicFunction::Add,
2950 _ => crate::AtomicFunction::Subtract,
2951 },
2952 value: one_lexp_handle,
2953 result: Some(r_lexp_handle),
2954 };
2955 block.push(stmt, span);
2956
2957 self.record_atomic_access(ctx, p_exp_h)?;
2959 }
2960 Op::AtomicCompareExchange => {
2961 inst.expect(9)?;
2962
2963 let start = self.data_offset;
2964 let span = self.span_from_with_op(start);
2965 let result_type_id = self.next()?;
2966 let result_id = self.next()?;
2967 let pointer_id = self.next()?;
2968 let _memory_scope_id = self.next()?;
2969 let _equal_memory_semantics_id = self.next()?;
2970 let _unequal_memory_semantics_id = self.next()?;
2971 let value_id = self.next()?;
2972 let comparator_id = self.next()?;
2973
2974 let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles(
2975 pointer_id,
2976 ctx,
2977 &mut emitter,
2978 &mut block,
2979 body_idx,
2980 )?;
2981
2982 log::trace!("\t\t\tlooking up value expr {value_id:?}");
2983 let v_lexp_handle =
2984 get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?);
2985
2986 log::trace!("\t\t\tlooking up comparator expr {value_id:?}");
2987 let c_lexp_handle = get_expr_handle!(
2988 comparator_id,
2989 self.lookup_expression.lookup(comparator_id)?
2990 );
2991
2992 let crate::TypeInner::Scalar(scalar) = ctx.module.types[p_base_ty_h].inner
2996 else {
2997 return Err(
2998 crate::front::atomic_upgrade::Error::CompareExchangeNonScalarBaseType
2999 .into(),
3000 );
3001 };
3002
3003 let atomic_result_struct_ty_h = ctx.module.generate_predeclared_type(
3005 crate::PredeclaredType::AtomicCompareExchangeWeakResult(scalar),
3006 );
3007
3008 block.extend(emitter.finish(ctx.expressions));
3009
3010 let atomic_lexp_handle = {
3012 let expr = crate::Expression::AtomicResult {
3013 ty: atomic_result_struct_ty_h,
3014 comparison: true,
3015 };
3016 ctx.expressions.append(expr, span)
3017 };
3018
3019 emitter.start(ctx.expressions);
3020
3021 {
3025 let expr = crate::Expression::AccessIndex {
3026 base: atomic_lexp_handle,
3027 index: 0,
3028 };
3029 let handle = ctx.expressions.append(expr, span);
3030 let _ = self.lookup_expression.insert(
3032 result_id,
3033 LookupExpression {
3034 handle,
3035 type_id: result_type_id,
3036 block_id,
3037 },
3038 );
3039 }
3040
3041 let stmt = crate::Statement::Atomic {
3043 pointer: p_exp_h,
3044 fun: crate::AtomicFunction::Exchange {
3045 compare: Some(c_lexp_handle),
3046 },
3047 value: v_lexp_handle,
3048 result: Some(atomic_lexp_handle),
3049 };
3050 block.push(stmt, span);
3051
3052 self.record_atomic_access(ctx, p_exp_h)?;
3054 }
3055 Op::AtomicExchange
3056 | Op::AtomicIAdd
3057 | Op::AtomicISub
3058 | Op::AtomicSMin
3059 | Op::AtomicUMin
3060 | Op::AtomicSMax
3061 | Op::AtomicUMax
3062 | Op::AtomicAnd
3063 | Op::AtomicOr
3064 | Op::AtomicXor
3065 | Op::AtomicFAddEXT => self.parse_atomic_expr_with_value(
3066 inst,
3067 &mut emitter,
3068 ctx,
3069 &mut block,
3070 block_id,
3071 body_idx,
3072 match inst.op {
3073 Op::AtomicExchange => crate::AtomicFunction::Exchange { compare: None },
3074 Op::AtomicIAdd | Op::AtomicFAddEXT => crate::AtomicFunction::Add,
3075 Op::AtomicISub => crate::AtomicFunction::Subtract,
3076 Op::AtomicSMin => crate::AtomicFunction::Min,
3077 Op::AtomicUMin => crate::AtomicFunction::Min,
3078 Op::AtomicSMax => crate::AtomicFunction::Max,
3079 Op::AtomicUMax => crate::AtomicFunction::Max,
3080 Op::AtomicAnd => crate::AtomicFunction::And,
3081 Op::AtomicOr => crate::AtomicFunction::InclusiveOr,
3082 Op::AtomicXor => crate::AtomicFunction::ExclusiveOr,
3083 _ => unreachable!(),
3084 },
3085 )?,
3086
3087 _ => {
3088 return Err(Error::UnsupportedInstruction(self.state, inst.op));
3089 }
3090 }
3091 };
3092
3093 block.extend(emitter.finish(ctx.expressions));
3094 if let Some(stmt) = terminator {
3095 block.push(stmt, crate::Span::default());
3096 }
3097
3098 ctx.blocks.insert(block_id, block);
3101 let body = &mut ctx.bodies[body_idx];
3102 body.data.push(BodyFragment::BlockId(block_id));
3103 Ok(())
3104 }
3105}
3106
3107fn make_index_literal(
3108 ctx: &mut BlockContext,
3109 index: u32,
3110 block: &mut crate::Block,
3111 emitter: &mut crate::proc::Emitter,
3112 index_type: Handle<crate::Type>,
3113 index_type_id: spirv::Word,
3114 span: crate::Span,
3115) -> Result<Handle<crate::Expression>, Error> {
3116 block.extend(emitter.finish(ctx.expressions));
3117
3118 let literal = match ctx.module.types[index_type].inner.scalar_kind() {
3119 Some(crate::ScalarKind::Uint) => crate::Literal::U32(index),
3120 Some(crate::ScalarKind::Sint) => crate::Literal::I32(index as i32),
3121 _ => return Err(Error::InvalidIndexType(index_type_id)),
3122 };
3123 let expr = ctx
3124 .expressions
3125 .append(crate::Expression::Literal(literal), span);
3126
3127 emitter.start(ctx.expressions);
3128 Ok(expr)
3129}