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 kind: crate::ScalarKind::Float,
900 convert: Some(size),
901 },
902 span,
903 );
904 let right_cast = ctx.expressions.append(
905 crate::Expression::As {
906 expr: right,
907 kind: crate::ScalarKind::Float,
908 convert: Some(size),
909 },
910 span,
911 );
912 let div = ctx.expressions.append(
913 crate::Expression::Binary {
914 op: crate::BinaryOperator::Divide,
915 left: left_cast,
916 right: right_cast,
917 },
918 span,
919 );
920 let floor = ctx.expressions.append(
921 crate::Expression::Math {
922 fun: crate::MathFunction::Floor,
923 arg: div,
924 arg1: None,
925 arg2: None,
926 arg3: None,
927 },
928 span,
929 );
930 let cast = ctx.expressions.append(
931 crate::Expression::As {
932 expr: floor,
933 kind,
934 convert: Some(size),
935 },
936 span,
937 );
938 let mult = ctx.expressions.append(
939 crate::Expression::Binary {
940 op: crate::BinaryOperator::Multiply,
941 left: cast,
942 right,
943 },
944 span,
945 );
946 let sub = ctx.expressions.append(
947 crate::Expression::Binary {
948 op: crate::BinaryOperator::Subtract,
949 left,
950 right: mult,
951 },
952 span,
953 );
954 self.lookup_expression.insert(
955 result_id,
956 LookupExpression {
957 handle: sub,
958 type_id: result_type_id,
959 block_id,
960 },
961 );
962 }
963 Op::FMod => {
964 inst.expect(5)?;
965
966 let start = self.data_offset;
969 let span = self.span_from_with_op(start);
970
971 let result_type_id = self.next()?;
972 let result_id = self.next()?;
973 let p1_id = self.next()?;
974 let p2_id = self.next()?;
975
976 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
977 let left = self.get_expr_handle(
978 p1_id,
979 p1_lexp,
980 ctx,
981 &mut emitter,
982 &mut block,
983 body_idx,
984 );
985 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
986 let right = self.get_expr_handle(
987 p2_id,
988 p2_lexp,
989 ctx,
990 &mut emitter,
991 &mut block,
992 body_idx,
993 );
994
995 let div = ctx.expressions.append(
996 crate::Expression::Binary {
997 op: crate::BinaryOperator::Divide,
998 left,
999 right,
1000 },
1001 span,
1002 );
1003 let floor = ctx.expressions.append(
1004 crate::Expression::Math {
1005 fun: crate::MathFunction::Floor,
1006 arg: div,
1007 arg1: None,
1008 arg2: None,
1009 arg3: None,
1010 },
1011 span,
1012 );
1013 let mult = ctx.expressions.append(
1014 crate::Expression::Binary {
1015 op: crate::BinaryOperator::Multiply,
1016 left: floor,
1017 right,
1018 },
1019 span,
1020 );
1021 let sub = ctx.expressions.append(
1022 crate::Expression::Binary {
1023 op: crate::BinaryOperator::Subtract,
1024 left,
1025 right: mult,
1026 },
1027 span,
1028 );
1029 self.lookup_expression.insert(
1030 result_id,
1031 LookupExpression {
1032 handle: sub,
1033 type_id: result_type_id,
1034 block_id,
1035 },
1036 );
1037 }
1038 Op::VectorTimesScalar
1039 | Op::VectorTimesMatrix
1040 | Op::MatrixTimesScalar
1041 | Op::MatrixTimesVector
1042 | Op::MatrixTimesMatrix => {
1043 inst.expect(5)?;
1044 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
1045 }
1046 Op::Transpose => {
1047 inst.expect(4)?;
1048
1049 let result_type_id = self.next()?;
1050 let result_id = self.next()?;
1051 let matrix_id = self.next()?;
1052 let matrix_lexp = self.lookup_expression.lookup(matrix_id)?;
1053 let matrix_handle = get_expr_handle!(matrix_id, matrix_lexp);
1054 let expr = crate::Expression::Math {
1055 fun: crate::MathFunction::Transpose,
1056 arg: matrix_handle,
1057 arg1: None,
1058 arg2: None,
1059 arg3: None,
1060 };
1061 self.lookup_expression.insert(
1062 result_id,
1063 LookupExpression {
1064 handle: ctx.expressions.append(expr, span),
1065 type_id: result_type_id,
1066 block_id,
1067 },
1068 );
1069 }
1070 Op::Dot => {
1071 inst.expect(5)?;
1072
1073 let result_type_id = self.next()?;
1074 let result_id = self.next()?;
1075 let left_id = self.next()?;
1076 let right_id = self.next()?;
1077 let left_lexp = self.lookup_expression.lookup(left_id)?;
1078 let left_handle = get_expr_handle!(left_id, left_lexp);
1079 let right_lexp = self.lookup_expression.lookup(right_id)?;
1080 let right_handle = get_expr_handle!(right_id, right_lexp);
1081 let expr = crate::Expression::Math {
1082 fun: crate::MathFunction::Dot,
1083 arg: left_handle,
1084 arg1: Some(right_handle),
1085 arg2: None,
1086 arg3: None,
1087 };
1088 self.lookup_expression.insert(
1089 result_id,
1090 LookupExpression {
1091 handle: ctx.expressions.append(expr, span),
1092 type_id: result_type_id,
1093 block_id,
1094 },
1095 );
1096 }
1097 Op::BitFieldInsert => {
1098 inst.expect(7)?;
1099
1100 let start = self.data_offset;
1101 let span = self.span_from_with_op(start);
1102
1103 let result_type_id = self.next()?;
1104 let result_id = self.next()?;
1105 let base_id = self.next()?;
1106 let insert_id = self.next()?;
1107 let offset_id = self.next()?;
1108 let count_id = self.next()?;
1109 let base_lexp = self.lookup_expression.lookup(base_id)?;
1110 let base_handle = get_expr_handle!(base_id, base_lexp);
1111 let insert_lexp = self.lookup_expression.lookup(insert_id)?;
1112 let insert_handle = get_expr_handle!(insert_id, insert_lexp);
1113 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
1114 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
1115 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
1116 let count_lexp = self.lookup_expression.lookup(count_id)?;
1117 let count_handle = get_expr_handle!(count_id, count_lexp);
1118 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
1119
1120 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
1121 .inner
1122 .scalar_kind()
1123 .unwrap();
1124 let count_kind = ctx.module.types[count_lookup_ty.handle]
1125 .inner
1126 .scalar_kind()
1127 .unwrap();
1128
1129 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
1130 ctx.expressions.append(
1131 crate::Expression::As {
1132 expr: offset_handle,
1133 kind: crate::ScalarKind::Uint,
1134 convert: None,
1135 },
1136 span,
1137 )
1138 } else {
1139 offset_handle
1140 };
1141
1142 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
1143 ctx.expressions.append(
1144 crate::Expression::As {
1145 expr: count_handle,
1146 kind: crate::ScalarKind::Uint,
1147 convert: None,
1148 },
1149 span,
1150 )
1151 } else {
1152 count_handle
1153 };
1154
1155 let expr = crate::Expression::Math {
1156 fun: crate::MathFunction::InsertBits,
1157 arg: base_handle,
1158 arg1: Some(insert_handle),
1159 arg2: Some(offset_cast_handle),
1160 arg3: Some(count_cast_handle),
1161 };
1162 self.lookup_expression.insert(
1163 result_id,
1164 LookupExpression {
1165 handle: ctx.expressions.append(expr, span),
1166 type_id: result_type_id,
1167 block_id,
1168 },
1169 );
1170 }
1171 Op::BitFieldSExtract | Op::BitFieldUExtract => {
1172 inst.expect(6)?;
1173
1174 let result_type_id = self.next()?;
1175 let result_id = self.next()?;
1176 let base_id = self.next()?;
1177 let offset_id = self.next()?;
1178 let count_id = self.next()?;
1179 let base_lexp = self.lookup_expression.lookup(base_id)?;
1180 let base_handle = get_expr_handle!(base_id, base_lexp);
1181 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
1182 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
1183 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
1184 let count_lexp = self.lookup_expression.lookup(count_id)?;
1185 let count_handle = get_expr_handle!(count_id, count_lexp);
1186 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
1187
1188 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
1189 .inner
1190 .scalar_kind()
1191 .unwrap();
1192 let count_kind = ctx.module.types[count_lookup_ty.handle]
1193 .inner
1194 .scalar_kind()
1195 .unwrap();
1196
1197 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
1198 ctx.expressions.append(
1199 crate::Expression::As {
1200 expr: offset_handle,
1201 kind: crate::ScalarKind::Uint,
1202 convert: None,
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 kind: crate::ScalarKind::Uint,
1215 convert: None,
1216 },
1217 span,
1218 )
1219 } else {
1220 count_handle
1221 };
1222
1223 let expr = crate::Expression::Math {
1224 fun: crate::MathFunction::ExtractBits,
1225 arg: base_handle,
1226 arg1: Some(offset_cast_handle),
1227 arg2: Some(count_cast_handle),
1228 arg3: None,
1229 };
1230 self.lookup_expression.insert(
1231 result_id,
1232 LookupExpression {
1233 handle: ctx.expressions.append(expr, span),
1234 type_id: result_type_id,
1235 block_id,
1236 },
1237 );
1238 }
1239 Op::BitReverse | Op::BitCount => {
1240 inst.expect(4)?;
1241
1242 let result_type_id = self.next()?;
1243 let result_id = self.next()?;
1244 let base_id = self.next()?;
1245 let base_lexp = self.lookup_expression.lookup(base_id)?;
1246 let base_handle = get_expr_handle!(base_id, base_lexp);
1247 let expr = crate::Expression::Math {
1248 fun: match inst.op {
1249 Op::BitReverse => crate::MathFunction::ReverseBits,
1250 Op::BitCount => crate::MathFunction::CountOneBits,
1251 _ => unreachable!(),
1252 },
1253 arg: base_handle,
1254 arg1: None,
1255 arg2: None,
1256 arg3: None,
1257 };
1258 self.lookup_expression.insert(
1259 result_id,
1260 LookupExpression {
1261 handle: ctx.expressions.append(expr, span),
1262 type_id: result_type_id,
1263 block_id,
1264 },
1265 );
1266 }
1267 Op::OuterProduct => {
1268 inst.expect(5)?;
1269
1270 let result_type_id = self.next()?;
1271 let result_id = self.next()?;
1272 let left_id = self.next()?;
1273 let right_id = self.next()?;
1274 let left_lexp = self.lookup_expression.lookup(left_id)?;
1275 let left_handle = get_expr_handle!(left_id, left_lexp);
1276 let right_lexp = self.lookup_expression.lookup(right_id)?;
1277 let right_handle = get_expr_handle!(right_id, right_lexp);
1278 let expr = crate::Expression::Math {
1279 fun: crate::MathFunction::Outer,
1280 arg: left_handle,
1281 arg1: Some(right_handle),
1282 arg2: None,
1283 arg3: None,
1284 };
1285 self.lookup_expression.insert(
1286 result_id,
1287 LookupExpression {
1288 handle: ctx.expressions.append(expr, span),
1289 type_id: result_type_id,
1290 block_id,
1291 },
1292 );
1293 }
1294 Op::Not => {
1296 inst.expect(4)?;
1297 self.parse_expr_unary_op_sign_adjusted(
1298 ctx,
1299 &mut emitter,
1300 &mut block,
1301 block_id,
1302 body_idx,
1303 crate::UnaryOperator::BitwiseNot,
1304 )?;
1305 }
1306 Op::ShiftRightLogical => {
1307 inst.expect(5)?;
1308 parse_expr_op!(crate::BinaryOperator::ShiftRight, SHIFT)?;
1310 }
1311 Op::ShiftRightArithmetic => {
1312 inst.expect(5)?;
1313 parse_expr_op!(crate::BinaryOperator::ShiftRight, SHIFT)?;
1315 }
1316 Op::ShiftLeftLogical => {
1317 inst.expect(5)?;
1318 parse_expr_op!(crate::BinaryOperator::ShiftLeft, SHIFT)?;
1319 }
1320 Op::Image => {
1322 inst.expect(4)?;
1323 self.parse_image_uncouple(block_id)?;
1324 }
1325 Op::SampledImage => {
1326 inst.expect(5)?;
1327 self.parse_image_couple()?;
1328 }
1329 Op::ImageWrite => {
1330 let extra = inst.expect_at_least(4)?;
1331 let stmt =
1332 self.parse_image_write(extra, ctx, &mut emitter, &mut block, body_idx)?;
1333 block.extend(emitter.finish(ctx.expressions));
1334 block.push(stmt, span);
1335 emitter.start(ctx.expressions);
1336 }
1337 Op::ImageFetch | Op::ImageRead => {
1338 let extra = inst.expect_at_least(5)?;
1339 self.parse_image_load(
1340 extra,
1341 ctx,
1342 &mut emitter,
1343 &mut block,
1344 block_id,
1345 body_idx,
1346 )?;
1347 }
1348 Op::ImageSampleImplicitLod | Op::ImageSampleExplicitLod => {
1349 let extra = inst.expect_at_least(5)?;
1350 let options = image::SamplingOptions {
1351 compare: false,
1352 project: false,
1353 gather: false,
1354 };
1355 self.parse_image_sample(
1356 extra,
1357 options,
1358 ctx,
1359 &mut emitter,
1360 &mut block,
1361 block_id,
1362 body_idx,
1363 )?;
1364 }
1365 Op::ImageSampleProjImplicitLod | Op::ImageSampleProjExplicitLod => {
1366 let extra = inst.expect_at_least(5)?;
1367 let options = image::SamplingOptions {
1368 compare: false,
1369 project: true,
1370 gather: false,
1371 };
1372 self.parse_image_sample(
1373 extra,
1374 options,
1375 ctx,
1376 &mut emitter,
1377 &mut block,
1378 block_id,
1379 body_idx,
1380 )?;
1381 }
1382 Op::ImageSampleDrefImplicitLod | Op::ImageSampleDrefExplicitLod => {
1383 let extra = inst.expect_at_least(6)?;
1384 let options = image::SamplingOptions {
1385 compare: true,
1386 project: false,
1387 gather: false,
1388 };
1389 self.parse_image_sample(
1390 extra,
1391 options,
1392 ctx,
1393 &mut emitter,
1394 &mut block,
1395 block_id,
1396 body_idx,
1397 )?;
1398 }
1399 Op::ImageSampleProjDrefImplicitLod | Op::ImageSampleProjDrefExplicitLod => {
1400 let extra = inst.expect_at_least(6)?;
1401 let options = image::SamplingOptions {
1402 compare: true,
1403 project: true,
1404 gather: false,
1405 };
1406 self.parse_image_sample(
1407 extra,
1408 options,
1409 ctx,
1410 &mut emitter,
1411 &mut block,
1412 block_id,
1413 body_idx,
1414 )?;
1415 }
1416 Op::ImageGather => {
1417 let extra = inst.expect_at_least(6)?;
1418 let options = image::SamplingOptions {
1419 compare: false,
1420 project: false,
1421 gather: true,
1422 };
1423 self.parse_image_sample(
1424 extra,
1425 options,
1426 ctx,
1427 &mut emitter,
1428 &mut block,
1429 block_id,
1430 body_idx,
1431 )?;
1432 }
1433 Op::ImageDrefGather => {
1434 let extra = inst.expect_at_least(6)?;
1435 let options = image::SamplingOptions {
1436 compare: true,
1437 project: false,
1438 gather: true,
1439 };
1440 self.parse_image_sample(
1441 extra,
1442 options,
1443 ctx,
1444 &mut emitter,
1445 &mut block,
1446 block_id,
1447 body_idx,
1448 )?;
1449 }
1450 Op::ImageQuerySize => {
1451 inst.expect(4)?;
1452 self.parse_image_query_size(
1453 false,
1454 ctx,
1455 &mut emitter,
1456 &mut block,
1457 block_id,
1458 body_idx,
1459 )?;
1460 }
1461 Op::ImageQuerySizeLod => {
1462 inst.expect(5)?;
1463 self.parse_image_query_size(
1464 true,
1465 ctx,
1466 &mut emitter,
1467 &mut block,
1468 block_id,
1469 body_idx,
1470 )?;
1471 }
1472 Op::ImageQueryLevels => {
1473 inst.expect(4)?;
1474 self.parse_image_query_other(crate::ImageQuery::NumLevels, ctx, block_id)?;
1475 }
1476 Op::ImageQuerySamples => {
1477 inst.expect(4)?;
1478 self.parse_image_query_other(crate::ImageQuery::NumSamples, ctx, block_id)?;
1479 }
1480 Op::Select => {
1482 inst.expect(6)?;
1483 let result_type_id = self.next()?;
1484 let result_id = self.next()?;
1485 let condition = self.next()?;
1486 let o1_id = self.next()?;
1487 let o2_id = self.next()?;
1488
1489 let cond_lexp = self.lookup_expression.lookup(condition)?;
1490 let cond_handle = get_expr_handle!(condition, cond_lexp);
1491 let o1_lexp = self.lookup_expression.lookup(o1_id)?;
1492 let o1_handle = get_expr_handle!(o1_id, o1_lexp);
1493 let o2_lexp = self.lookup_expression.lookup(o2_id)?;
1494 let o2_handle = get_expr_handle!(o2_id, o2_lexp);
1495
1496 let expr = crate::Expression::Select {
1497 condition: cond_handle,
1498 accept: o1_handle,
1499 reject: o2_handle,
1500 };
1501 self.lookup_expression.insert(
1502 result_id,
1503 LookupExpression {
1504 handle: ctx.expressions.append(expr, span),
1505 type_id: result_type_id,
1506 block_id,
1507 },
1508 );
1509 }
1510 Op::VectorShuffle => {
1511 inst.expect_at_least(5)?;
1512 let result_type_id = self.next()?;
1513 let result_id = self.next()?;
1514 let v1_id = self.next()?;
1515 let v2_id = self.next()?;
1516
1517 let v1_lexp = self.lookup_expression.lookup(v1_id)?;
1518 let v1_lty = self.lookup_type.lookup(v1_lexp.type_id)?;
1519 let v1_handle = get_expr_handle!(v1_id, v1_lexp);
1520 let n1 = match ctx.module.types[v1_lty.handle].inner {
1521 crate::TypeInner::Vector { size, .. } => size as u32,
1522 _ => return Err(Error::InvalidInnerType(v1_lexp.type_id)),
1523 };
1524 let v2_lexp = self.lookup_expression.lookup(v2_id)?;
1525 let v2_lty = self.lookup_type.lookup(v2_lexp.type_id)?;
1526 let v2_handle = get_expr_handle!(v2_id, v2_lexp);
1527 let n2 = match ctx.module.types[v2_lty.handle].inner {
1528 crate::TypeInner::Vector { size, .. } => size as u32,
1529 _ => return Err(Error::InvalidInnerType(v2_lexp.type_id)),
1530 };
1531
1532 self.temp_bytes.clear();
1533 let mut max_component = 0;
1534 for _ in 5..inst.wc as usize {
1535 let mut index = self.next()?;
1536 if index == u32::MAX {
1537 index = 0;
1539 }
1540 max_component = max_component.max(index);
1541 self.temp_bytes.push(index as u8);
1542 }
1543
1544 let expr = if max_component < n1 {
1546 use crate::SwizzleComponent as Sc;
1547 let size = match self.temp_bytes.len() {
1548 2 => crate::VectorSize::Bi,
1549 3 => crate::VectorSize::Tri,
1550 _ => crate::VectorSize::Quad,
1551 };
1552 let mut pattern = [Sc::X; 4];
1553 for (pat, index) in pattern.iter_mut().zip(self.temp_bytes.drain(..)) {
1554 *pat = match index {
1555 0 => Sc::X,
1556 1 => Sc::Y,
1557 2 => Sc::Z,
1558 _ => Sc::W,
1559 };
1560 }
1561 crate::Expression::Swizzle {
1562 size,
1563 vector: v1_handle,
1564 pattern,
1565 }
1566 } else {
1567 let mut components = Vec::with_capacity(self.temp_bytes.len());
1569 for index in self.temp_bytes.drain(..).map(|i| i as u32) {
1570 let expr = if index < n1 {
1571 crate::Expression::AccessIndex {
1572 base: v1_handle,
1573 index,
1574 }
1575 } else if index < n1 + n2 {
1576 crate::Expression::AccessIndex {
1577 base: v2_handle,
1578 index: index - n1,
1579 }
1580 } else {
1581 return Err(Error::InvalidAccessIndex(index));
1582 };
1583 components.push(ctx.expressions.append(expr, span));
1584 }
1585 crate::Expression::Compose {
1586 ty: self.lookup_type.lookup(result_type_id)?.handle,
1587 components,
1588 }
1589 };
1590
1591 self.lookup_expression.insert(
1592 result_id,
1593 LookupExpression {
1594 handle: ctx.expressions.append(expr, span),
1595 type_id: result_type_id,
1596 block_id,
1597 },
1598 );
1599 }
1600 Op::Bitcast
1601 | Op::ConvertSToF
1602 | Op::ConvertUToF
1603 | Op::ConvertFToU
1604 | Op::ConvertFToS
1605 | Op::FConvert
1606 | Op::UConvert
1607 | Op::SConvert => {
1608 inst.expect(4)?;
1609 let result_type_id = self.next()?;
1610 let result_id = self.next()?;
1611 let value_id = self.next()?;
1612
1613 let value_lexp = self.lookup_expression.lookup(value_id)?;
1614 let ty_lookup = self.lookup_type.lookup(result_type_id)?;
1615 let scalar = match ctx.module.types[ty_lookup.handle].inner {
1616 crate::TypeInner::Scalar(scalar)
1617 | crate::TypeInner::Vector { scalar, .. }
1618 | crate::TypeInner::Matrix { scalar, .. } => scalar,
1619 _ => return Err(Error::InvalidAsType(ty_lookup.handle)),
1620 };
1621
1622 let expr = crate::Expression::As {
1623 expr: get_expr_handle!(value_id, value_lexp),
1624 kind: scalar.kind,
1625 convert: if scalar.kind == crate::ScalarKind::Bool {
1626 Some(crate::BOOL_WIDTH)
1627 } else if inst.op == Op::Bitcast {
1628 None
1629 } else {
1630 Some(scalar.width)
1631 },
1632 };
1633 self.lookup_expression.insert(
1634 result_id,
1635 LookupExpression {
1636 handle: ctx.expressions.append(expr, span),
1637 type_id: result_type_id,
1638 block_id,
1639 },
1640 );
1641 }
1642 Op::FunctionCall => {
1643 inst.expect_at_least(4)?;
1644
1645 let result_type_id = self.next()?;
1646 let result_id = self.next()?;
1647 let func_id = self.next()?;
1648
1649 let mut arguments = Vec::with_capacity(inst.wc as usize - 4);
1650 for _ in 0..arguments.capacity() {
1651 let arg_id = self.next()?;
1652 let lexp = self.lookup_expression.lookup(arg_id)?;
1653 arguments.push(get_expr_handle!(arg_id, lexp));
1654 }
1655
1656 block.extend(emitter.finish(ctx.expressions));
1657
1658 let function = self.add_call(ctx.function_id, func_id);
1660
1661 let result = if self.lookup_void_type == Some(result_type_id) {
1662 None
1663 } else {
1664 let expr_handle = ctx
1665 .expressions
1666 .append(crate::Expression::CallResult(function), span);
1667 self.lookup_expression.insert(
1668 result_id,
1669 LookupExpression {
1670 handle: expr_handle,
1671 type_id: result_type_id,
1672 block_id,
1673 },
1674 );
1675 Some(expr_handle)
1676 };
1677 block.push(
1678 crate::Statement::Call {
1679 function,
1680 arguments,
1681 result,
1682 },
1683 span,
1684 );
1685 emitter.start(ctx.expressions);
1686 }
1687 Op::ExtInst => {
1688 use crate::MathFunction as Mf;
1689 use spirv::GlslStd450Op as Glo;
1690
1691 let base_wc = 5;
1692 inst.expect_at_least(base_wc)?;
1693
1694 let result_type_id = self.next()?;
1695 let result_id = self.next()?;
1696 let set_id = self.next()?;
1697 if Some(set_id) == self.ext_non_semantic_id {
1698 for _ in 0..inst.wc - 4 {
1699 self.next()?;
1700 }
1701 continue;
1702 } else if Some(set_id) != self.ext_glsl_id {
1703 return Err(Error::UnsupportedExtInstSet(set_id));
1704 }
1705 let inst_id = self.next()?;
1706 let gl_op = Glo::from_u32(inst_id).ok_or(Error::UnsupportedExtInst(inst_id))?;
1707
1708 let fun = match gl_op {
1709 Glo::Round => Mf::Round,
1710 Glo::RoundEven => Mf::Round,
1711 Glo::Trunc => Mf::Trunc,
1712 Glo::FAbs | Glo::SAbs => Mf::Abs,
1713 Glo::FSign | Glo::SSign => Mf::Sign,
1714 Glo::Floor => Mf::Floor,
1715 Glo::Ceil => Mf::Ceil,
1716 Glo::Fract => Mf::Fract,
1717 Glo::Sin => Mf::Sin,
1718 Glo::Cos => Mf::Cos,
1719 Glo::Tan => Mf::Tan,
1720 Glo::Asin => Mf::Asin,
1721 Glo::Acos => Mf::Acos,
1722 Glo::Atan => Mf::Atan,
1723 Glo::Sinh => Mf::Sinh,
1724 Glo::Cosh => Mf::Cosh,
1725 Glo::Tanh => Mf::Tanh,
1726 Glo::Atan2 => Mf::Atan2,
1727 Glo::Asinh => Mf::Asinh,
1728 Glo::Acosh => Mf::Acosh,
1729 Glo::Atanh => Mf::Atanh,
1730 Glo::Radians => Mf::Radians,
1731 Glo::Degrees => Mf::Degrees,
1732 Glo::Pow => Mf::Pow,
1733 Glo::Exp => Mf::Exp,
1734 Glo::Log => Mf::Log,
1735 Glo::Exp2 => Mf::Exp2,
1736 Glo::Log2 => Mf::Log2,
1737 Glo::Sqrt => Mf::Sqrt,
1738 Glo::InverseSqrt => Mf::InverseSqrt,
1739 Glo::MatrixInverse => Mf::Inverse,
1740 Glo::Determinant => Mf::Determinant,
1741 Glo::ModfStruct => Mf::Modf,
1742 Glo::FMin | Glo::UMin | Glo::SMin | Glo::NMin => Mf::Min,
1743 Glo::FMax | Glo::UMax | Glo::SMax | Glo::NMax => Mf::Max,
1744 Glo::FClamp | Glo::UClamp | Glo::SClamp | Glo::NClamp => Mf::Clamp,
1745 Glo::FMix => Mf::Mix,
1746 Glo::Step => Mf::Step,
1747 Glo::SmoothStep => Mf::SmoothStep,
1748 Glo::Fma => Mf::Fma,
1749 Glo::FrexpStruct => Mf::Frexp,
1750 Glo::Ldexp => Mf::Ldexp,
1751 Glo::Length => Mf::Length,
1752 Glo::Distance => Mf::Distance,
1753 Glo::Cross => Mf::Cross,
1754 Glo::Normalize => Mf::Normalize,
1755 Glo::FaceForward => Mf::FaceForward,
1756 Glo::Reflect => Mf::Reflect,
1757 Glo::Refract => Mf::Refract,
1758 Glo::PackUnorm4x8 => Mf::Pack4x8unorm,
1759 Glo::PackSnorm4x8 => Mf::Pack4x8snorm,
1760 Glo::PackHalf2x16 => Mf::Pack2x16float,
1761 Glo::PackUnorm2x16 => Mf::Pack2x16unorm,
1762 Glo::PackSnorm2x16 => Mf::Pack2x16snorm,
1763 Glo::UnpackUnorm4x8 => Mf::Unpack4x8unorm,
1764 Glo::UnpackSnorm4x8 => Mf::Unpack4x8snorm,
1765 Glo::UnpackHalf2x16 => Mf::Unpack2x16float,
1766 Glo::UnpackUnorm2x16 => Mf::Unpack2x16unorm,
1767 Glo::UnpackSnorm2x16 => Mf::Unpack2x16snorm,
1768 Glo::FindILsb => Mf::FirstTrailingBit,
1769 Glo::FindUMsb | Glo::FindSMsb => Mf::FirstLeadingBit,
1770 Glo::Modf | Glo::Frexp => return Err(Error::UnsupportedExtInst(inst_id)),
1772 Glo::IMix
1773 | Glo::PackDouble2x32
1774 | Glo::UnpackDouble2x32
1775 | Glo::InterpolateAtCentroid
1776 | Glo::InterpolateAtSample
1777 | Glo::InterpolateAtOffset => {
1778 return Err(Error::UnsupportedExtInst(inst_id))
1779 }
1780 };
1781
1782 let arg_count = fun.argument_count();
1783 inst.expect(base_wc + arg_count as u16)?;
1784 let arg = {
1785 let arg_id = self.next()?;
1786 let lexp = self.lookup_expression.lookup(arg_id)?;
1787 get_expr_handle!(arg_id, lexp)
1788 };
1789 let arg1 = if arg_count > 1 {
1790 let arg_id = self.next()?;
1791 let lexp = self.lookup_expression.lookup(arg_id)?;
1792 Some(get_expr_handle!(arg_id, lexp))
1793 } else {
1794 None
1795 };
1796 let arg2 = if arg_count > 2 {
1797 let arg_id = self.next()?;
1798 let lexp = self.lookup_expression.lookup(arg_id)?;
1799 Some(get_expr_handle!(arg_id, lexp))
1800 } else {
1801 None
1802 };
1803 let arg3 = if arg_count > 3 {
1804 let arg_id = self.next()?;
1805 let lexp = self.lookup_expression.lookup(arg_id)?;
1806 Some(get_expr_handle!(arg_id, lexp))
1807 } else {
1808 None
1809 };
1810
1811 let expr = crate::Expression::Math {
1812 fun,
1813 arg,
1814 arg1,
1815 arg2,
1816 arg3,
1817 };
1818 self.lookup_expression.insert(
1819 result_id,
1820 LookupExpression {
1821 handle: ctx.expressions.append(expr, span),
1822 type_id: result_type_id,
1823 block_id,
1824 },
1825 );
1826 }
1827 Op::LogicalNot => {
1829 inst.expect(4)?;
1830 parse_expr_op!(crate::UnaryOperator::LogicalNot, UNARY)?;
1831 }
1832 Op::LogicalOr => {
1833 inst.expect(5)?;
1834 parse_expr_op!(crate::BinaryOperator::LogicalOr, BINARY)?;
1835 }
1836 Op::LogicalAnd => {
1837 inst.expect(5)?;
1838 parse_expr_op!(crate::BinaryOperator::LogicalAnd, BINARY)?;
1839 }
1840 Op::SGreaterThan | Op::SGreaterThanEqual | Op::SLessThan | Op::SLessThanEqual => {
1841 inst.expect(5)?;
1842 self.parse_expr_int_comparison(
1843 ctx,
1844 &mut emitter,
1845 &mut block,
1846 block_id,
1847 body_idx,
1848 map_binary_operator(inst.op)?,
1849 crate::ScalarKind::Sint,
1850 )?;
1851 }
1852 Op::UGreaterThan | Op::UGreaterThanEqual | Op::ULessThan | Op::ULessThanEqual => {
1853 inst.expect(5)?;
1854 self.parse_expr_int_comparison(
1855 ctx,
1856 &mut emitter,
1857 &mut block,
1858 block_id,
1859 body_idx,
1860 map_binary_operator(inst.op)?,
1861 crate::ScalarKind::Uint,
1862 )?;
1863 }
1864 Op::FOrdEqual
1865 | Op::FUnordEqual
1866 | Op::FOrdNotEqual
1867 | Op::FUnordNotEqual
1868 | Op::FOrdLessThan
1869 | Op::FUnordLessThan
1870 | Op::FOrdGreaterThan
1871 | Op::FUnordGreaterThan
1872 | Op::FOrdLessThanEqual
1873 | Op::FUnordLessThanEqual
1874 | Op::FOrdGreaterThanEqual
1875 | Op::FUnordGreaterThanEqual
1876 | Op::LogicalEqual
1877 | Op::LogicalNotEqual => {
1878 inst.expect(5)?;
1879 let operator = map_binary_operator(inst.op)?;
1880 parse_expr_op!(operator, BINARY)?;
1881 }
1882 Op::Any | Op::All | Op::IsNan | Op::IsInf | Op::IsFinite | Op::IsNormal => {
1883 inst.expect(4)?;
1884 let result_type_id = self.next()?;
1885 let result_id = self.next()?;
1886 let arg_id = self.next()?;
1887
1888 let arg_lexp = self.lookup_expression.lookup(arg_id)?;
1889 let arg_handle = get_expr_handle!(arg_id, arg_lexp);
1890
1891 let expr = crate::Expression::Relational {
1892 fun: map_relational_fun(inst.op)?,
1893 argument: arg_handle,
1894 };
1895 self.lookup_expression.insert(
1896 result_id,
1897 LookupExpression {
1898 handle: ctx.expressions.append(expr, span),
1899 type_id: result_type_id,
1900 block_id,
1901 },
1902 );
1903 }
1904 Op::Kill => {
1905 inst.expect(1)?;
1906 break Some(crate::Statement::Kill);
1907 }
1908 Op::Unreachable => {
1909 inst.expect(1)?;
1910 break None;
1911 }
1912 Op::Return => {
1913 inst.expect(1)?;
1914 break Some(crate::Statement::Return { value: None });
1915 }
1916 Op::ReturnValue => {
1917 inst.expect(2)?;
1918 let value_id = self.next()?;
1919 let value_lexp = self.lookup_expression.lookup(value_id)?;
1920 let value_handle = get_expr_handle!(value_id, value_lexp);
1921 break Some(crate::Statement::Return {
1922 value: Some(value_handle),
1923 });
1924 }
1925 Op::Branch => {
1926 inst.expect(2)?;
1927 let target_id = self.next()?;
1928
1929 if let Some(info) = ctx.mergers.get(&target_id) {
1938 block.extend(emitter.finish(ctx.expressions));
1939 ctx.blocks.insert(block_id, block);
1940 let body = &mut ctx.bodies[body_idx];
1941 body.data.push(BodyFragment::BlockId(block_id));
1942
1943 merger(body, info);
1944
1945 return Ok(());
1946 }
1947
1948 ctx.body_for_label.entry(target_id).or_insert(body_idx);
1965
1966 break None;
1967 }
1968 Op::BranchConditional => {
1969 inst.expect_at_least(4)?;
1970
1971 let condition = {
1972 let condition_id = self.next()?;
1973 let lexp = self.lookup_expression.lookup(condition_id)?;
1974 get_expr_handle!(condition_id, lexp)
1975 };
1976
1977 #[derive(Copy, Clone)]
1980 struct BranchTarget {
1981 label_id: spirv::Word,
1982 merge_info: Option<MergeBlockInformation>,
1983 }
1984 let branch_target = |label_id| BranchTarget {
1985 label_id,
1986 merge_info: ctx.mergers.get(&label_id).copied(),
1987 };
1988
1989 let true_target = branch_target(self.next()?);
1990 let false_target = branch_target(self.next()?);
1991
1992 for _ in 4..inst.wc {
1994 let _ = self.next()?;
1995 }
1996
1997 let parent_body_idx = ctx.bodies[body_idx].parent;
2005 let parent_parent_body_idx = ctx.bodies[parent_body_idx].parent;
2006 match ctx.bodies[parent_parent_body_idx].data[..] {
2007 [.., BodyFragment::Loop {
2011 body: loop_body_idx,
2012 continuing: loop_continuing_idx,
2013 break_if: ref mut break_if_slot @ None,
2014 }] if body_idx == loop_continuing_idx => {
2015 let break_if_cond = [true, false].into_iter().find_map(|true_breaks| {
2018 let (break_candidate, backedge_candidate) = if true_breaks {
2019 (true_target, false_target)
2020 } else {
2021 (false_target, true_target)
2022 };
2023
2024 if break_candidate.merge_info
2025 != Some(MergeBlockInformation::LoopMerge)
2026 {
2027 return None;
2028 }
2029
2030 let backedge_candidate_is_backedge =
2034 backedge_candidate.merge_info.is_none()
2035 && ctx.body_for_label.get(&backedge_candidate.label_id)
2036 == Some(&loop_body_idx);
2037 if !backedge_candidate_is_backedge {
2038 return None;
2039 }
2040
2041 Some(if true_breaks {
2042 condition
2043 } else {
2044 ctx.expressions.append(
2045 crate::Expression::Unary {
2046 op: crate::UnaryOperator::LogicalNot,
2047 expr: condition,
2048 },
2049 span,
2050 )
2051 })
2052 });
2053
2054 if let Some(break_if_cond) = break_if_cond {
2055 *break_if_slot = Some(break_if_cond);
2056
2057 break None;
2061 }
2062 }
2063 _ => {}
2064 }
2065
2066 block.extend(emitter.finish(ctx.expressions));
2067 ctx.blocks.insert(block_id, block);
2068 let body = &mut ctx.bodies[body_idx];
2069 body.data.push(BodyFragment::BlockId(block_id));
2070
2071 let same_target = true_target.label_id == false_target.label_id;
2072
2073 let accept = ctx.bodies.len();
2075 let mut accept_block = Body::with_parent(body_idx);
2076
2077 if let Some(info) = true_target.merge_info {
2081 merger(
2082 match same_target {
2083 true => &mut ctx.bodies[body_idx],
2084 false => &mut accept_block,
2085 },
2086 &info,
2087 )
2088 } else {
2089 let prev = ctx.body_for_label.insert(
2091 true_target.label_id,
2092 match same_target {
2093 true => body_idx,
2094 false => accept,
2095 },
2096 );
2097 debug_assert!(prev.is_none());
2098 }
2099
2100 if same_target {
2101 return Ok(());
2102 }
2103
2104 ctx.bodies.push(accept_block);
2105
2106 let reject = ctx.bodies.len();
2108 let mut reject_block = Body::with_parent(body_idx);
2109
2110 if let Some(info) = false_target.merge_info {
2111 merger(&mut reject_block, &info)
2112 } else {
2113 let prev = ctx.body_for_label.insert(false_target.label_id, reject);
2114 debug_assert!(prev.is_none());
2115 }
2116
2117 ctx.bodies.push(reject_block);
2118
2119 let body = &mut ctx.bodies[body_idx];
2120 body.data.push(BodyFragment::If {
2121 condition,
2122 accept,
2123 reject,
2124 });
2125
2126 return Ok(());
2127 }
2128 Op::Switch => {
2129 inst.expect_at_least(3)?;
2130 let selector = self.next()?;
2131 let default_id = self.next()?;
2132
2133 if let Some(merge) = selection_merge_block {
2136 ctx.mergers
2137 .insert(merge, MergeBlockInformation::SwitchMerge);
2138 }
2139
2140 let default = ctx.bodies.len();
2141 ctx.bodies.push(Body::with_parent(body_idx));
2142 ctx.body_for_label.entry(default_id).or_insert(default);
2143
2144 let selector_lexp = &self.lookup_expression[&selector];
2145 let selector_lty = self.lookup_type.lookup(selector_lexp.type_id)?;
2146 let selector_handle = get_expr_handle!(selector, selector_lexp);
2147 let selector = match ctx.module.types[selector_lty.handle].inner {
2148 crate::TypeInner::Scalar(crate::Scalar {
2149 kind: crate::ScalarKind::Uint,
2150 width: _,
2151 }) => {
2152 ctx.expressions.append(
2154 crate::Expression::As {
2155 kind: crate::ScalarKind::Sint,
2156 expr: selector_handle,
2157 convert: None,
2158 },
2159 span,
2160 )
2161 }
2162 crate::TypeInner::Scalar(crate::Scalar {
2163 kind: crate::ScalarKind::Sint,
2164 width: _,
2165 }) => selector_handle,
2166 ref other => unimplemented!("Unexpected selector {:?}", other),
2167 };
2168
2169 self.switch_cases.clear();
2171
2172 for _ in 0..(inst.wc - 3) / 2 {
2173 let literal = self.next()?;
2174 let target = self.next()?;
2175
2176 let case_body_idx = ctx.bodies.len();
2177
2178 if let Some(&mut (_, ref mut literals)) = self.switch_cases.get_mut(&target)
2182 {
2183 literals.push(literal as i32);
2184 continue;
2185 }
2186
2187 let mut body = Body::with_parent(body_idx);
2188
2189 if let Some(info) = ctx.mergers.get(&target) {
2190 merger(&mut body, info);
2191 }
2192
2193 ctx.bodies.push(body);
2194 ctx.body_for_label.entry(target).or_insert(case_body_idx);
2195
2196 self.switch_cases
2199 .insert(target, (case_body_idx, vec![literal as i32]));
2200 }
2201
2202 let mut cases = Vec::with_capacity((inst.wc as usize - 3) / 2);
2211 for &(case_body_idx, ref literals) in self.switch_cases.values() {
2212 let value = literals[0];
2213
2214 for &literal in literals.iter().skip(1) {
2215 let empty_body_idx = ctx.bodies.len();
2216 let body = Body::with_parent(body_idx);
2217
2218 ctx.bodies.push(body);
2219
2220 cases.push((literal, empty_body_idx));
2221 }
2222
2223 cases.push((value, case_body_idx));
2224 }
2225
2226 block.extend(emitter.finish(ctx.expressions));
2227
2228 let body = &mut ctx.bodies[body_idx];
2229 ctx.blocks.insert(block_id, block);
2230 body.data.reserve(2);
2232 body.data.push(BodyFragment::BlockId(block_id));
2233 body.data.push(BodyFragment::Switch {
2234 selector,
2235 cases,
2236 default,
2237 });
2238
2239 return Ok(());
2240 }
2241 Op::SelectionMerge => {
2242 inst.expect(3)?;
2243 let merge_block_id = self.next()?;
2244 let _selection_control = self.next()?;
2246
2247 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
2250
2251 ctx.mergers
2254 .insert(merge_block_id, MergeBlockInformation::SelectionMerge);
2255
2256 selection_merge_block = Some(merge_block_id);
2257 }
2258 Op::LoopMerge => {
2259 inst.expect_at_least(4)?;
2260 let merge_block_id = self.next()?;
2261 let continuing = self.next()?;
2262
2263 for _ in 0..inst.wc - 3 {
2265 self.next()?;
2266 }
2267
2268 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
2271 ctx.mergers
2274 .insert(merge_block_id, MergeBlockInformation::LoopMerge);
2275
2276 let loop_body_idx = ctx.bodies.len();
2277 ctx.bodies.push(Body::with_parent(body_idx));
2278
2279 let continue_idx = ctx.bodies.len();
2280 ctx.bodies.push(Body::with_parent(loop_body_idx));
2282 ctx.body_for_label.entry(continuing).or_insert(continue_idx);
2283 ctx.mergers
2286 .insert(continuing, MergeBlockInformation::LoopContinue);
2287
2288 ctx.body_for_label.insert(block_id, loop_body_idx);
2290
2291 let parent_body = &mut ctx.bodies[body_idx];
2292 parent_body.data.push(BodyFragment::Loop {
2293 body: loop_body_idx,
2294 continuing: continue_idx,
2295 break_if: None,
2296 });
2297 body_idx = loop_body_idx;
2298 }
2299 Op::DPdxCoarse => {
2300 parse_expr_op!(
2301 crate::DerivativeAxis::X,
2302 crate::DerivativeControl::Coarse,
2303 DERIVATIVE
2304 )?;
2305 }
2306 Op::DPdyCoarse => {
2307 parse_expr_op!(
2308 crate::DerivativeAxis::Y,
2309 crate::DerivativeControl::Coarse,
2310 DERIVATIVE
2311 )?;
2312 }
2313 Op::FwidthCoarse => {
2314 parse_expr_op!(
2315 crate::DerivativeAxis::Width,
2316 crate::DerivativeControl::Coarse,
2317 DERIVATIVE
2318 )?;
2319 }
2320 Op::DPdxFine => {
2321 parse_expr_op!(
2322 crate::DerivativeAxis::X,
2323 crate::DerivativeControl::Fine,
2324 DERIVATIVE
2325 )?;
2326 }
2327 Op::DPdyFine => {
2328 parse_expr_op!(
2329 crate::DerivativeAxis::Y,
2330 crate::DerivativeControl::Fine,
2331 DERIVATIVE
2332 )?;
2333 }
2334 Op::FwidthFine => {
2335 parse_expr_op!(
2336 crate::DerivativeAxis::Width,
2337 crate::DerivativeControl::Fine,
2338 DERIVATIVE
2339 )?;
2340 }
2341 Op::DPdx => {
2342 parse_expr_op!(
2343 crate::DerivativeAxis::X,
2344 crate::DerivativeControl::None,
2345 DERIVATIVE
2346 )?;
2347 }
2348 Op::DPdy => {
2349 parse_expr_op!(
2350 crate::DerivativeAxis::Y,
2351 crate::DerivativeControl::None,
2352 DERIVATIVE
2353 )?;
2354 }
2355 Op::Fwidth => {
2356 parse_expr_op!(
2357 crate::DerivativeAxis::Width,
2358 crate::DerivativeControl::None,
2359 DERIVATIVE
2360 )?;
2361 }
2362 Op::ArrayLength => {
2363 inst.expect(5)?;
2364 let result_type_id = self.next()?;
2365 let result_id = self.next()?;
2366 let structure_id = self.next()?;
2367 let member_index = self.next()?;
2368
2369 let structure_ptr = self.lookup_expression.lookup(structure_id)?;
2373 let structure_handle = get_expr_handle!(structure_id, structure_ptr);
2374
2375 let member_ptr = ctx.expressions.append(
2376 crate::Expression::AccessIndex {
2377 base: structure_handle,
2378 index: member_index,
2379 },
2380 span,
2381 );
2382
2383 let length = ctx
2384 .expressions
2385 .append(crate::Expression::ArrayLength(member_ptr), span);
2386
2387 self.lookup_expression.insert(
2388 result_id,
2389 LookupExpression {
2390 handle: length,
2391 type_id: result_type_id,
2392 block_id,
2393 },
2394 );
2395 }
2396 Op::CopyMemory => {
2397 inst.expect_at_least(3)?;
2398 let target_id = self.next()?;
2399 let source_id = self.next()?;
2400 let _memory_access = if inst.wc != 3 {
2401 inst.expect(4)?;
2402 spirv::MemoryAccess::from_bits(self.next()?)
2403 .ok_or(Error::InvalidParameter(Op::CopyMemory))?
2404 } else {
2405 spirv::MemoryAccess::NONE
2406 };
2407
2408 let target = self.lookup_expression.lookup(target_id)?;
2410 let target_handle = get_expr_handle!(target_id, target);
2411 let source = self.lookup_expression.lookup(source_id)?;
2412 let source_handle = get_expr_handle!(source_id, source);
2413
2414 let value_expr = ctx.expressions.append(
2416 crate::Expression::Load {
2417 pointer: source_handle,
2418 },
2419 span,
2420 );
2421
2422 block.extend(emitter.finish(ctx.expressions));
2423 block.push(
2424 crate::Statement::Store {
2425 pointer: target_handle,
2426 value: value_expr,
2427 },
2428 span,
2429 );
2430
2431 emitter.start(ctx.expressions);
2432 }
2433 Op::ControlBarrier => {
2434 inst.expect(4)?;
2435 let exec_scope_id = self.next()?;
2436 let _mem_scope_raw = self.next()?;
2437 let semantics_id = self.next()?;
2438 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2439 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
2440
2441 let exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2442 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2443 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
2444 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
2445
2446 if exec_scope == spirv::Scope::Workgroup as u32
2447 || exec_scope == spirv::Scope::Subgroup as u32
2448 {
2449 let mut flags = crate::Barrier::empty();
2450 flags.set(
2451 crate::Barrier::STORAGE,
2452 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
2453 );
2454 flags.set(
2455 crate::Barrier::WORK_GROUP,
2456 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
2457 );
2458 flags.set(
2459 crate::Barrier::SUB_GROUP,
2460 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
2461 );
2462 flags.set(
2463 crate::Barrier::TEXTURE,
2464 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
2465 );
2466
2467 block.extend(emitter.finish(ctx.expressions));
2468 block.push(crate::Statement::ControlBarrier(flags), span);
2469 emitter.start(ctx.expressions);
2470 } else {
2471 log::warn!("Unsupported barrier execution scope: {exec_scope}");
2472 }
2473 }
2474 Op::MemoryBarrier => {
2475 inst.expect(3)?;
2476 let mem_scope_id = self.next()?;
2477 let semantics_id = self.next()?;
2478 let mem_scope_const = self.lookup_constant.lookup(mem_scope_id)?;
2479 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
2480
2481 let mem_scope = resolve_constant(ctx.gctx(), &mem_scope_const.inner)
2482 .ok_or(Error::InvalidBarrierScope(mem_scope_id))?;
2483 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
2484 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
2485
2486 let mut flags = if mem_scope == spirv::Scope::Device as u32 {
2487 crate::Barrier::STORAGE
2488 } else if mem_scope == spirv::Scope::Workgroup as u32 {
2489 crate::Barrier::WORK_GROUP
2490 } else if mem_scope == spirv::Scope::Subgroup as u32 {
2491 crate::Barrier::SUB_GROUP
2492 } else {
2493 crate::Barrier::empty()
2494 };
2495 flags.set(
2496 crate::Barrier::STORAGE,
2497 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
2498 );
2499 flags.set(
2500 crate::Barrier::WORK_GROUP,
2501 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
2502 );
2503 flags.set(
2504 crate::Barrier::SUB_GROUP,
2505 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
2506 );
2507 flags.set(
2508 crate::Barrier::TEXTURE,
2509 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
2510 );
2511
2512 block.extend(emitter.finish(ctx.expressions));
2513 block.push(crate::Statement::MemoryBarrier(flags), span);
2514 emitter.start(ctx.expressions);
2515 }
2516 Op::CopyObject => {
2517 inst.expect(4)?;
2518 let result_type_id = self.next()?;
2519 let result_id = self.next()?;
2520 let operand_id = self.next()?;
2521
2522 let lookup = self.lookup_expression.lookup(operand_id)?;
2523 let handle = get_expr_handle!(operand_id, lookup);
2524
2525 self.lookup_expression.insert(
2526 result_id,
2527 LookupExpression {
2528 handle,
2529 type_id: result_type_id,
2530 block_id,
2531 },
2532 );
2533 }
2534 Op::GroupNonUniformBallot => {
2535 inst.expect(5)?;
2536 block.extend(emitter.finish(ctx.expressions));
2537 let result_type_id = self.next()?;
2538 let result_id = self.next()?;
2539 let exec_scope_id = self.next()?;
2540 let predicate_id = self.next()?;
2541
2542 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2543 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2544 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2545 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2546
2547 let predicate = if self
2548 .lookup_constant
2549 .lookup(predicate_id)
2550 .ok()
2551 .filter(|predicate_const| match predicate_const.inner {
2552 Constant::Constant(constant) => matches!(
2553 ctx.gctx().global_expressions[ctx.gctx().constants[constant].init],
2554 crate::Expression::Literal(crate::Literal::Bool(true)),
2555 ),
2556 Constant::Override(_) => false,
2557 })
2558 .is_some()
2559 {
2560 None
2561 } else {
2562 let predicate_lookup = self.lookup_expression.lookup(predicate_id)?;
2563 let predicate_handle = get_expr_handle!(predicate_id, predicate_lookup);
2564 Some(predicate_handle)
2565 };
2566
2567 let result_handle = ctx
2568 .expressions
2569 .append(crate::Expression::SubgroupBallotResult, span);
2570 self.lookup_expression.insert(
2571 result_id,
2572 LookupExpression {
2573 handle: result_handle,
2574 type_id: result_type_id,
2575 block_id,
2576 },
2577 );
2578
2579 block.push(
2580 crate::Statement::SubgroupBallot {
2581 result: result_handle,
2582 predicate,
2583 },
2584 span,
2585 );
2586 emitter.start(ctx.expressions);
2587 }
2588 Op::GroupNonUniformAll
2589 | Op::GroupNonUniformAny
2590 | Op::GroupNonUniformIAdd
2591 | Op::GroupNonUniformFAdd
2592 | Op::GroupNonUniformIMul
2593 | Op::GroupNonUniformFMul
2594 | Op::GroupNonUniformSMax
2595 | Op::GroupNonUniformUMax
2596 | Op::GroupNonUniformFMax
2597 | Op::GroupNonUniformSMin
2598 | Op::GroupNonUniformUMin
2599 | Op::GroupNonUniformFMin
2600 | Op::GroupNonUniformBitwiseAnd
2601 | Op::GroupNonUniformBitwiseOr
2602 | Op::GroupNonUniformBitwiseXor
2603 | Op::GroupNonUniformLogicalAnd
2604 | Op::GroupNonUniformLogicalOr
2605 | Op::GroupNonUniformLogicalXor => {
2606 block.extend(emitter.finish(ctx.expressions));
2607 inst.expect(
2608 if matches!(inst.op, Op::GroupNonUniformAll | Op::GroupNonUniformAny) {
2609 5
2610 } else {
2611 6
2612 },
2613 )?;
2614 let result_type_id = self.next()?;
2615 let result_id = self.next()?;
2616 let exec_scope_id = self.next()?;
2617 let collective_op_id = match inst.op {
2618 Op::GroupNonUniformAll | Op::GroupNonUniformAny => {
2619 crate::CollectiveOperation::Reduce
2620 }
2621 _ => {
2622 let group_op_id = self.next()?;
2623 match spirv::GroupOperation::from_u32(group_op_id) {
2624 Some(spirv::GroupOperation::Reduce) => {
2625 crate::CollectiveOperation::Reduce
2626 }
2627 Some(spirv::GroupOperation::InclusiveScan) => {
2628 crate::CollectiveOperation::InclusiveScan
2629 }
2630 Some(spirv::GroupOperation::ExclusiveScan) => {
2631 crate::CollectiveOperation::ExclusiveScan
2632 }
2633 _ => return Err(Error::UnsupportedGroupOperation(group_op_id)),
2634 }
2635 }
2636 };
2637 let argument_id = self.next()?;
2638
2639 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2640 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2641
2642 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2643 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2644 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2645 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2646
2647 let op_id = match inst.op {
2648 Op::GroupNonUniformAll => crate::SubgroupOperation::All,
2649 Op::GroupNonUniformAny => crate::SubgroupOperation::Any,
2650 Op::GroupNonUniformIAdd | Op::GroupNonUniformFAdd => {
2651 crate::SubgroupOperation::Add
2652 }
2653 Op::GroupNonUniformIMul | Op::GroupNonUniformFMul => {
2654 crate::SubgroupOperation::Mul
2655 }
2656 Op::GroupNonUniformSMax
2657 | Op::GroupNonUniformUMax
2658 | Op::GroupNonUniformFMax => crate::SubgroupOperation::Max,
2659 Op::GroupNonUniformSMin
2660 | Op::GroupNonUniformUMin
2661 | Op::GroupNonUniformFMin => crate::SubgroupOperation::Min,
2662 Op::GroupNonUniformBitwiseAnd | Op::GroupNonUniformLogicalAnd => {
2663 crate::SubgroupOperation::And
2664 }
2665 Op::GroupNonUniformBitwiseOr | Op::GroupNonUniformLogicalOr => {
2666 crate::SubgroupOperation::Or
2667 }
2668 Op::GroupNonUniformBitwiseXor | Op::GroupNonUniformLogicalXor => {
2669 crate::SubgroupOperation::Xor
2670 }
2671 _ => unreachable!(),
2672 };
2673
2674 let result_type = self.lookup_type.lookup(result_type_id)?;
2675
2676 let result_handle = ctx.expressions.append(
2677 crate::Expression::SubgroupOperationResult {
2678 ty: result_type.handle,
2679 },
2680 span,
2681 );
2682 self.lookup_expression.insert(
2683 result_id,
2684 LookupExpression {
2685 handle: result_handle,
2686 type_id: result_type_id,
2687 block_id,
2688 },
2689 );
2690
2691 block.push(
2692 crate::Statement::SubgroupCollectiveOperation {
2693 result: result_handle,
2694 op: op_id,
2695 collective_op: collective_op_id,
2696 argument: argument_handle,
2697 },
2698 span,
2699 );
2700 emitter.start(ctx.expressions);
2701 }
2702 Op::GroupNonUniformBroadcastFirst
2703 | Op::GroupNonUniformBroadcast
2704 | Op::GroupNonUniformShuffle
2705 | Op::GroupNonUniformShuffleDown
2706 | Op::GroupNonUniformShuffleUp
2707 | Op::GroupNonUniformShuffleXor
2708 | Op::GroupNonUniformQuadBroadcast => {
2709 inst.expect(if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
2710 5
2711 } else {
2712 6
2713 })?;
2714 block.extend(emitter.finish(ctx.expressions));
2715 let result_type_id = self.next()?;
2716 let result_id = self.next()?;
2717 let exec_scope_id = self.next()?;
2718 let argument_id = self.next()?;
2719
2720 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2721 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
2722
2723 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
2724 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
2725 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
2726 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
2727
2728 let mode = if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
2729 crate::GatherMode::BroadcastFirst
2730 } else {
2731 let index_id = self.next()?;
2732 let index_lookup = self.lookup_expression.lookup(index_id)?;
2733 let index_handle = get_expr_handle!(index_id, index_lookup);
2734 match inst.op {
2735 Op::GroupNonUniformBroadcast => {
2736 crate::GatherMode::Broadcast(index_handle)
2737 }
2738 Op::GroupNonUniformShuffle => crate::GatherMode::Shuffle(index_handle),
2739 Op::GroupNonUniformShuffleDown => {
2740 crate::GatherMode::ShuffleDown(index_handle)
2741 }
2742 Op::GroupNonUniformShuffleUp => {
2743 crate::GatherMode::ShuffleUp(index_handle)
2744 }
2745 Op::GroupNonUniformShuffleXor => {
2746 crate::GatherMode::ShuffleXor(index_handle)
2747 }
2748 Op::GroupNonUniformQuadBroadcast => {
2749 crate::GatherMode::QuadBroadcast(index_handle)
2750 }
2751 _ => unreachable!(),
2752 }
2753 };
2754
2755 let result_type = self.lookup_type.lookup(result_type_id)?;
2756
2757 let result_handle = ctx.expressions.append(
2758 crate::Expression::SubgroupOperationResult {
2759 ty: result_type.handle,
2760 },
2761 span,
2762 );
2763 self.lookup_expression.insert(
2764 result_id,
2765 LookupExpression {
2766 handle: result_handle,
2767 type_id: result_type_id,
2768 block_id,
2769 },
2770 );
2771
2772 block.push(
2773 crate::Statement::SubgroupGather {
2774 result: result_handle,
2775 mode,
2776 argument: argument_handle,
2777 },
2778 span,
2779 );
2780 emitter.start(ctx.expressions);
2781 }
2782 Op::GroupNonUniformQuadSwap => {
2783 inst.expect(6)?;
2784 block.extend(emitter.finish(ctx.expressions));
2785 let result_type_id = self.next()?;
2786 let result_id = self.next()?;
2787 let exec_scope_id = self.next()?;
2788 let argument_id = self.next()?;
2789 let direction_id = self.next()?;
2790
2791 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
2792 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
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}