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