1use std::num::NonZeroU32;
2
3use crate::front::wgsl::error::{Error, ExpectedToken, InvalidAssignmentType};
4use crate::front::wgsl::index::Index;
5use crate::front::wgsl::parse::number::Number;
6use crate::front::wgsl::parse::{ast, conv};
7use crate::front::Typifier;
8use crate::proc::{
9 ensure_block_returns, Alignment, ConstantEvaluator, Emitter, Layouter, ResolveContext,
10};
11use crate::{Arena, FastHashMap, FastIndexMap, Handle, Span};
12
13mod construction;
14mod conversion;
15
16macro_rules! resolve_inner {
30 ($ctx:ident, $expr:expr) => {{
31 $ctx.grow_types($expr)?;
32 $ctx.typifier()[$expr].inner_with(&$ctx.module.types)
33 }};
34}
35pub(super) use resolve_inner;
36
37macro_rules! resolve_inner_binary {
45 ($ctx:ident, $left:expr, $right:expr) => {{
46 $ctx.grow_types($left)?;
47 $ctx.grow_types($right)?;
48 (
49 $ctx.typifier()[$left].inner_with(&$ctx.module.types),
50 $ctx.typifier()[$right].inner_with(&$ctx.module.types),
51 )
52 }};
53}
54
55macro_rules! resolve {
65 ($ctx:ident, $expr:expr) => {{
66 $ctx.grow_types($expr)?;
67 &$ctx.typifier()[$expr]
68 }};
69}
70pub(super) use resolve;
71
72pub struct GlobalContext<'source, 'temp, 'out> {
74 ast_expressions: &'temp Arena<ast::Expression<'source>>,
76
77 types: &'temp Arena<ast::Type<'source>>,
79
80 globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
84
85 module: &'out mut crate::Module,
87
88 const_typifier: &'temp mut Typifier,
89
90 global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
91}
92
93impl<'source> GlobalContext<'source, '_, '_> {
94 fn as_const(&mut self) -> ExpressionContext<'source, '_, '_> {
95 ExpressionContext {
96 ast_expressions: self.ast_expressions,
97 globals: self.globals,
98 types: self.types,
99 module: self.module,
100 const_typifier: self.const_typifier,
101 expr_type: ExpressionContextType::Constant,
102 global_expression_kind_tracker: self.global_expression_kind_tracker,
103 }
104 }
105
106 fn as_override(&mut self) -> ExpressionContext<'source, '_, '_> {
107 ExpressionContext {
108 ast_expressions: self.ast_expressions,
109 globals: self.globals,
110 types: self.types,
111 module: self.module,
112 const_typifier: self.const_typifier,
113 expr_type: ExpressionContextType::Override,
114 global_expression_kind_tracker: self.global_expression_kind_tracker,
115 }
116 }
117
118 fn ensure_type_exists(
119 &mut self,
120 name: Option<String>,
121 inner: crate::TypeInner,
122 ) -> Handle<crate::Type> {
123 self.module
124 .types
125 .insert(crate::Type { inner, name }, Span::UNDEFINED)
126 }
127}
128
129pub struct StatementContext<'source, 'temp, 'out> {
131 ast_expressions: &'temp Arena<ast::Expression<'source>>,
137
138 types: &'temp Arena<ast::Type<'source>>,
143
144 globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
148
149 local_table: &'temp mut FastHashMap<Handle<ast::Local>, Typed<Handle<crate::Expression>>>,
164
165 const_typifier: &'temp mut Typifier,
166 typifier: &'temp mut Typifier,
167 function: &'out mut crate::Function,
168 named_expressions: &'out mut FastIndexMap<Handle<crate::Expression>, (String, Span)>,
171 module: &'out mut crate::Module,
172
173 local_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
183 global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
184}
185
186impl<'a, 'temp> StatementContext<'a, 'temp, '_> {
187 fn as_expression<'t>(
188 &'t mut self,
189 block: &'t mut crate::Block,
190 emitter: &'t mut Emitter,
191 ) -> ExpressionContext<'a, 't, '_>
192 where
193 'temp: 't,
194 {
195 ExpressionContext {
196 globals: self.globals,
197 types: self.types,
198 ast_expressions: self.ast_expressions,
199 const_typifier: self.const_typifier,
200 global_expression_kind_tracker: self.global_expression_kind_tracker,
201 module: self.module,
202 expr_type: ExpressionContextType::Runtime(RuntimeExpressionContext {
203 local_table: self.local_table,
204 function: self.function,
205 block,
206 emitter,
207 typifier: self.typifier,
208 local_expression_kind_tracker: self.local_expression_kind_tracker,
209 }),
210 }
211 }
212
213 fn as_global(&mut self) -> GlobalContext<'a, '_, '_> {
214 GlobalContext {
215 ast_expressions: self.ast_expressions,
216 globals: self.globals,
217 types: self.types,
218 module: self.module,
219 const_typifier: self.const_typifier,
220 global_expression_kind_tracker: self.global_expression_kind_tracker,
221 }
222 }
223
224 fn invalid_assignment_type(&self, expr: Handle<crate::Expression>) -> InvalidAssignmentType {
225 if let Some(&(_, span)) = self.named_expressions.get(&expr) {
226 InvalidAssignmentType::ImmutableBinding(span)
227 } else {
228 match self.function.expressions[expr] {
229 crate::Expression::Swizzle { .. } => InvalidAssignmentType::Swizzle,
230 crate::Expression::Access { base, .. } => self.invalid_assignment_type(base),
231 crate::Expression::AccessIndex { base, .. } => self.invalid_assignment_type(base),
232 _ => InvalidAssignmentType::Other,
233 }
234 }
235 }
236}
237
238pub struct RuntimeExpressionContext<'temp, 'out> {
239 local_table: &'temp FastHashMap<Handle<ast::Local>, Typed<Handle<crate::Expression>>>,
244
245 function: &'out mut crate::Function,
246 block: &'temp mut crate::Block,
247 emitter: &'temp mut Emitter,
248 typifier: &'temp mut Typifier,
249
250 local_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
255}
256
257pub enum ExpressionContextType<'temp, 'out> {
259 Runtime(RuntimeExpressionContext<'temp, 'out>),
266
267 Constant,
274
275 Override,
282}
283
284pub struct ExpressionContext<'source, 'temp, 'out> {
322 ast_expressions: &'temp Arena<ast::Expression<'source>>,
324 types: &'temp Arena<ast::Type<'source>>,
325
326 globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
330
331 module: &'out mut crate::Module,
335
336 const_typifier: &'temp mut Typifier,
340 global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
341
342 expr_type: ExpressionContextType<'temp, 'out>,
345}
346
347impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
348 fn as_const(&mut self) -> ExpressionContext<'source, '_, '_> {
349 ExpressionContext {
350 globals: self.globals,
351 types: self.types,
352 ast_expressions: self.ast_expressions,
353 const_typifier: self.const_typifier,
354 module: self.module,
355 expr_type: ExpressionContextType::Constant,
356 global_expression_kind_tracker: self.global_expression_kind_tracker,
357 }
358 }
359
360 fn as_global(&mut self) -> GlobalContext<'source, '_, '_> {
361 GlobalContext {
362 ast_expressions: self.ast_expressions,
363 globals: self.globals,
364 types: self.types,
365 module: self.module,
366 const_typifier: self.const_typifier,
367 global_expression_kind_tracker: self.global_expression_kind_tracker,
368 }
369 }
370
371 fn as_const_evaluator(&mut self) -> ConstantEvaluator {
372 match self.expr_type {
373 ExpressionContextType::Runtime(ref mut rctx) => ConstantEvaluator::for_wgsl_function(
374 self.module,
375 &mut rctx.function.expressions,
376 rctx.local_expression_kind_tracker,
377 rctx.emitter,
378 rctx.block,
379 ),
380 ExpressionContextType::Constant => ConstantEvaluator::for_wgsl_module(
381 self.module,
382 self.global_expression_kind_tracker,
383 false,
384 ),
385 ExpressionContextType::Override => ConstantEvaluator::for_wgsl_module(
386 self.module,
387 self.global_expression_kind_tracker,
388 true,
389 ),
390 }
391 }
392
393 fn append_expression(
394 &mut self,
395 expr: crate::Expression,
396 span: Span,
397 ) -> Result<Handle<crate::Expression>, Error<'source>> {
398 let mut eval = self.as_const_evaluator();
399 eval.try_eval_and_append(expr, span)
400 .map_err(|e| Error::ConstantEvaluatorError(e, span))
401 }
402
403 fn const_access(&self, handle: Handle<crate::Expression>) -> Option<u32> {
404 match self.expr_type {
405 ExpressionContextType::Runtime(ref ctx) => {
406 if !ctx.local_expression_kind_tracker.is_const(handle) {
407 return None;
408 }
409
410 self.module
411 .to_ctx()
412 .eval_expr_to_u32_from(handle, &ctx.function.expressions)
413 .ok()
414 }
415 ExpressionContextType::Constant => self.module.to_ctx().eval_expr_to_u32(handle).ok(),
416 ExpressionContextType::Override => None,
417 }
418 }
419
420 fn get_expression_span(&self, handle: Handle<crate::Expression>) -> Span {
421 match self.expr_type {
422 ExpressionContextType::Runtime(ref ctx) => ctx.function.expressions.get_span(handle),
423 ExpressionContextType::Constant | ExpressionContextType::Override => {
424 self.module.global_expressions.get_span(handle)
425 }
426 }
427 }
428
429 fn typifier(&self) -> &Typifier {
430 match self.expr_type {
431 ExpressionContextType::Runtime(ref ctx) => ctx.typifier,
432 ExpressionContextType::Constant | ExpressionContextType::Override => {
433 self.const_typifier
434 }
435 }
436 }
437
438 fn runtime_expression_ctx(
439 &mut self,
440 span: Span,
441 ) -> Result<&mut RuntimeExpressionContext<'temp, 'out>, Error<'source>> {
442 match self.expr_type {
443 ExpressionContextType::Runtime(ref mut ctx) => Ok(ctx),
444 ExpressionContextType::Constant | ExpressionContextType::Override => {
445 Err(Error::UnexpectedOperationInConstContext(span))
446 }
447 }
448 }
449
450 fn gather_component(
451 &mut self,
452 expr: Handle<crate::Expression>,
453 component_span: Span,
454 gather_span: Span,
455 ) -> Result<crate::SwizzleComponent, Error<'source>> {
456 match self.expr_type {
457 ExpressionContextType::Runtime(ref rctx) => {
458 if !rctx.local_expression_kind_tracker.is_const(expr) {
459 return Err(Error::ExpectedConstExprConcreteIntegerScalar(
460 component_span,
461 ));
462 }
463
464 let index = self
465 .module
466 .to_ctx()
467 .eval_expr_to_u32_from(expr, &rctx.function.expressions)
468 .map_err(|err| match err {
469 crate::proc::U32EvalError::NonConst => {
470 Error::ExpectedConstExprConcreteIntegerScalar(component_span)
471 }
472 crate::proc::U32EvalError::Negative => {
473 Error::ExpectedNonNegative(component_span)
474 }
475 })?;
476 crate::SwizzleComponent::XYZW
477 .get(index as usize)
478 .copied()
479 .ok_or(Error::InvalidGatherComponent(component_span))
480 }
481 ExpressionContextType::Constant | ExpressionContextType::Override => {
484 Err(Error::UnexpectedOperationInConstContext(gather_span))
485 }
486 }
487 }
488
489 fn register_type(
500 &mut self,
501 handle: Handle<crate::Expression>,
502 ) -> Result<Handle<crate::Type>, Error<'source>> {
503 self.grow_types(handle)?;
504 let typifier = match self.expr_type {
508 ExpressionContextType::Runtime(ref ctx) => ctx.typifier,
509 ExpressionContextType::Constant | ExpressionContextType::Override => {
510 &*self.const_typifier
511 }
512 };
513 Ok(typifier.register_type(handle, &mut self.module.types))
514 }
515
516 fn grow_types(
537 &mut self,
538 handle: Handle<crate::Expression>,
539 ) -> Result<&mut Self, Error<'source>> {
540 let empty_arena = Arena::new();
541 let resolve_ctx;
542 let typifier;
543 let expressions;
544 match self.expr_type {
545 ExpressionContextType::Runtime(ref mut ctx) => {
546 resolve_ctx = ResolveContext::with_locals(
547 self.module,
548 &ctx.function.local_variables,
549 &ctx.function.arguments,
550 );
551 typifier = &mut *ctx.typifier;
552 expressions = &ctx.function.expressions;
553 }
554 ExpressionContextType::Constant | ExpressionContextType::Override => {
555 resolve_ctx = ResolveContext::with_locals(self.module, &empty_arena, &[]);
556 typifier = self.const_typifier;
557 expressions = &self.module.global_expressions;
558 }
559 };
560 typifier
561 .grow(handle, expressions, &resolve_ctx)
562 .map_err(Error::InvalidResolve)?;
563
564 Ok(self)
565 }
566
567 fn image_data(
568 &mut self,
569 image: Handle<crate::Expression>,
570 span: Span,
571 ) -> Result<(crate::ImageClass, bool), Error<'source>> {
572 match *resolve_inner!(self, image) {
573 crate::TypeInner::Image { class, arrayed, .. } => Ok((class, arrayed)),
574 _ => Err(Error::BadTexture(span)),
575 }
576 }
577
578 fn prepare_args<'b>(
579 &mut self,
580 args: &'b [Handle<ast::Expression<'source>>],
581 min_args: u32,
582 span: Span,
583 ) -> ArgumentContext<'b, 'source> {
584 ArgumentContext {
585 args: args.iter(),
586 min_args,
587 args_used: 0,
588 total_args: args.len() as u32,
589 span,
590 }
591 }
592
593 fn binary_op_splat(
601 &mut self,
602 op: crate::BinaryOperator,
603 left: &mut Handle<crate::Expression>,
604 right: &mut Handle<crate::Expression>,
605 ) -> Result<(), Error<'source>> {
606 if matches!(
607 op,
608 crate::BinaryOperator::Add
609 | crate::BinaryOperator::Subtract
610 | crate::BinaryOperator::Divide
611 | crate::BinaryOperator::Modulo
612 ) {
613 match resolve_inner_binary!(self, *left, *right) {
614 (&crate::TypeInner::Vector { size, .. }, &crate::TypeInner::Scalar { .. }) => {
615 *right = self.append_expression(
616 crate::Expression::Splat {
617 size,
618 value: *right,
619 },
620 self.get_expression_span(*right),
621 )?;
622 }
623 (&crate::TypeInner::Scalar { .. }, &crate::TypeInner::Vector { size, .. }) => {
624 *left = self.append_expression(
625 crate::Expression::Splat { size, value: *left },
626 self.get_expression_span(*left),
627 )?;
628 }
629 _ => {}
630 }
631 }
632
633 Ok(())
634 }
635
636 fn interrupt_emitter(
641 &mut self,
642 expression: crate::Expression,
643 span: Span,
644 ) -> Result<Handle<crate::Expression>, Error<'source>> {
645 match self.expr_type {
646 ExpressionContextType::Runtime(ref mut rctx) => {
647 rctx.block
648 .extend(rctx.emitter.finish(&rctx.function.expressions));
649 }
650 ExpressionContextType::Constant | ExpressionContextType::Override => {}
651 }
652 let result = self.append_expression(expression, span);
653 match self.expr_type {
654 ExpressionContextType::Runtime(ref mut rctx) => {
655 rctx.emitter.start(&rctx.function.expressions);
656 }
657 ExpressionContextType::Constant | ExpressionContextType::Override => {}
658 }
659 result
660 }
661
662 fn apply_load_rule(
667 &mut self,
668 expr: Typed<Handle<crate::Expression>>,
669 ) -> Result<Handle<crate::Expression>, Error<'source>> {
670 match expr {
671 Typed::Reference(pointer) => {
672 let load = crate::Expression::Load { pointer };
673 let span = self.get_expression_span(pointer);
674 self.append_expression(load, span)
675 }
676 Typed::Plain(handle) => Ok(handle),
677 }
678 }
679
680 fn ensure_type_exists(&mut self, inner: crate::TypeInner) -> Handle<crate::Type> {
681 self.as_global().ensure_type_exists(None, inner)
682 }
683}
684
685struct ArgumentContext<'ctx, 'source> {
686 args: std::slice::Iter<'ctx, Handle<ast::Expression<'source>>>,
687 min_args: u32,
688 args_used: u32,
689 total_args: u32,
690 span: Span,
691}
692
693impl<'source> ArgumentContext<'_, 'source> {
694 pub fn finish(self) -> Result<(), Error<'source>> {
695 if self.args.len() == 0 {
696 Ok(())
697 } else {
698 Err(Error::WrongArgumentCount {
699 found: self.total_args,
700 expected: self.min_args..self.args_used + 1,
701 span: self.span,
702 })
703 }
704 }
705
706 pub fn next(&mut self) -> Result<Handle<ast::Expression<'source>>, Error<'source>> {
707 match self.args.next().copied() {
708 Some(arg) => {
709 self.args_used += 1;
710 Ok(arg)
711 }
712 None => Err(Error::WrongArgumentCount {
713 found: self.total_args,
714 expected: self.min_args..self.args_used + 1,
715 span: self.span,
716 }),
717 }
718 }
719}
720
721#[derive(Debug, Copy, Clone)]
743enum Typed<T> {
744 Reference(T),
746
747 Plain(T),
749}
750
751impl<T> Typed<T> {
752 fn map<U>(self, mut f: impl FnMut(T) -> U) -> Typed<U> {
753 match self {
754 Self::Reference(v) => Typed::Reference(f(v)),
755 Self::Plain(v) => Typed::Plain(f(v)),
756 }
757 }
758
759 fn try_map<U, E>(self, mut f: impl FnMut(T) -> Result<U, E>) -> Result<Typed<U>, E> {
760 Ok(match self {
761 Self::Reference(expr) => Typed::Reference(f(expr)?),
762 Self::Plain(expr) => Typed::Plain(f(expr)?),
763 })
764 }
765}
766
767enum Components {
773 Single(u32),
774 Swizzle {
775 size: crate::VectorSize,
776 pattern: [crate::SwizzleComponent; 4],
777 },
778}
779
780impl Components {
781 const fn letter_component(letter: char) -> Option<crate::SwizzleComponent> {
782 use crate::SwizzleComponent as Sc;
783 match letter {
784 'x' | 'r' => Some(Sc::X),
785 'y' | 'g' => Some(Sc::Y),
786 'z' | 'b' => Some(Sc::Z),
787 'w' | 'a' => Some(Sc::W),
788 _ => None,
789 }
790 }
791
792 fn single_component(name: &str, name_span: Span) -> Result<u32, Error> {
793 let ch = name.chars().next().ok_or(Error::BadAccessor(name_span))?;
794 match Self::letter_component(ch) {
795 Some(sc) => Ok(sc as u32),
796 None => Err(Error::BadAccessor(name_span)),
797 }
798 }
799
800 fn new(name: &str, name_span: Span) -> Result<Self, Error> {
804 let size = match name.len() {
805 1 => return Ok(Components::Single(Self::single_component(name, name_span)?)),
806 2 => crate::VectorSize::Bi,
807 3 => crate::VectorSize::Tri,
808 4 => crate::VectorSize::Quad,
809 _ => return Err(Error::BadAccessor(name_span)),
810 };
811
812 let mut pattern = [crate::SwizzleComponent::X; 4];
813 for (comp, ch) in pattern.iter_mut().zip(name.chars()) {
814 *comp = Self::letter_component(ch).ok_or(Error::BadAccessor(name_span))?;
815 }
816
817 Ok(Components::Swizzle { size, pattern })
818 }
819}
820
821enum LoweredGlobalDecl {
823 Function(Handle<crate::Function>),
824 Var(Handle<crate::GlobalVariable>),
825 Const(Handle<crate::Constant>),
826 Override(Handle<crate::Override>),
827 Type(Handle<crate::Type>),
828 EntryPoint,
829}
830
831enum Texture {
832 Gather,
833 GatherCompare,
834
835 Sample,
836 SampleBias,
837 SampleCompare,
838 SampleCompareLevel,
839 SampleGrad,
840 SampleLevel,
841 }
843
844impl Texture {
845 pub fn map(word: &str) -> Option<Self> {
846 Some(match word {
847 "textureGather" => Self::Gather,
848 "textureGatherCompare" => Self::GatherCompare,
849
850 "textureSample" => Self::Sample,
851 "textureSampleBias" => Self::SampleBias,
852 "textureSampleCompare" => Self::SampleCompare,
853 "textureSampleCompareLevel" => Self::SampleCompareLevel,
854 "textureSampleGrad" => Self::SampleGrad,
855 "textureSampleLevel" => Self::SampleLevel,
856 _ => return None,
858 })
859 }
860
861 pub const fn min_argument_count(&self) -> u32 {
862 match *self {
863 Self::Gather => 3,
864 Self::GatherCompare => 4,
865
866 Self::Sample => 3,
867 Self::SampleBias => 5,
868 Self::SampleCompare => 5,
869 Self::SampleCompareLevel => 5,
870 Self::SampleGrad => 6,
871 Self::SampleLevel => 5,
872 }
874 }
875}
876
877enum SubgroupGather {
878 BroadcastFirst,
879 Broadcast,
880 Shuffle,
881 ShuffleDown,
882 ShuffleUp,
883 ShuffleXor,
884}
885
886impl SubgroupGather {
887 pub fn map(word: &str) -> Option<Self> {
888 Some(match word {
889 "subgroupBroadcastFirst" => Self::BroadcastFirst,
890 "subgroupBroadcast" => Self::Broadcast,
891 "subgroupShuffle" => Self::Shuffle,
892 "subgroupShuffleDown" => Self::ShuffleDown,
893 "subgroupShuffleUp" => Self::ShuffleUp,
894 "subgroupShuffleXor" => Self::ShuffleXor,
895 _ => return None,
896 })
897 }
898}
899
900pub struct Lowerer<'source, 'temp> {
901 index: &'temp Index<'source>,
902 layouter: Layouter,
903}
904
905impl<'source, 'temp> Lowerer<'source, 'temp> {
906 pub fn new(index: &'temp Index<'source>) -> Self {
907 Self {
908 index,
909 layouter: Layouter::default(),
910 }
911 }
912
913 pub fn lower(
914 &mut self,
915 tu: &'temp ast::TranslationUnit<'source>,
916 ) -> Result<crate::Module, Error<'source>> {
917 let mut module = crate::Module::default();
918
919 let mut ctx = GlobalContext {
920 ast_expressions: &tu.expressions,
921 globals: &mut FastHashMap::default(),
922 types: &tu.types,
923 module: &mut module,
924 const_typifier: &mut Typifier::new(),
925 global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker::new(),
926 };
927
928 for decl_handle in self.index.visit_ordered() {
929 let span = tu.decls.get_span(decl_handle);
930 let decl = &tu.decls[decl_handle];
931
932 match decl.kind {
933 ast::GlobalDeclKind::Fn(ref f) => {
934 let lowered_decl = self.function(f, span, &mut ctx)?;
935 ctx.globals.insert(f.name.name, lowered_decl);
936 }
937 ast::GlobalDeclKind::Var(ref v) => {
938 let ty = self.resolve_ast_type(v.ty, &mut ctx)?;
939
940 let init;
941 if let Some(init_ast) = v.init {
942 let mut ectx = ctx.as_override();
943 let lowered = self.expression_for_abstract(init_ast, &mut ectx)?;
944 let ty_res = crate::proc::TypeResolution::Handle(ty);
945 let converted = ectx
946 .try_automatic_conversions(lowered, &ty_res, v.name.span)
947 .map_err(|error| match error {
948 Error::AutoConversion {
949 dest_span: _,
950 dest_type,
951 source_span: _,
952 source_type,
953 } => Error::InitializationTypeMismatch {
954 name: v.name.span,
955 expected: dest_type,
956 got: source_type,
957 },
958 other => other,
959 })?;
960 init = Some(converted);
961 } else {
962 init = None;
963 }
964
965 let binding = if let Some(ref binding) = v.binding {
966 Some(crate::ResourceBinding {
967 group: self.const_u32(binding.group, &mut ctx.as_const())?.0,
968 binding: self.const_u32(binding.binding, &mut ctx.as_const())?.0,
969 })
970 } else {
971 None
972 };
973
974 let handle = ctx.module.global_variables.append(
975 crate::GlobalVariable {
976 name: Some(v.name.name.to_string()),
977 space: v.space,
978 binding,
979 ty,
980 init,
981 },
982 span,
983 );
984
985 ctx.globals
986 .insert(v.name.name, LoweredGlobalDecl::Var(handle));
987 }
988 ast::GlobalDeclKind::Const(ref c) => {
989 let mut ectx = ctx.as_const();
990 let mut init = self.expression_for_abstract(c.init, &mut ectx)?;
991
992 let ty;
993 if let Some(explicit_ty) = c.ty {
994 let explicit_ty =
995 self.resolve_ast_type(explicit_ty, &mut ectx.as_global())?;
996 let explicit_ty_res = crate::proc::TypeResolution::Handle(explicit_ty);
997 init = ectx
998 .try_automatic_conversions(init, &explicit_ty_res, c.name.span)
999 .map_err(|error| match error {
1000 Error::AutoConversion {
1001 dest_span: _,
1002 dest_type,
1003 source_span: _,
1004 source_type,
1005 } => Error::InitializationTypeMismatch {
1006 name: c.name.span,
1007 expected: dest_type,
1008 got: source_type,
1009 },
1010 other => other,
1011 })?;
1012 ty = explicit_ty;
1013 } else {
1014 init = ectx.concretize(init)?;
1015 ty = ectx.register_type(init)?;
1016 }
1017
1018 let handle = ctx.module.constants.append(
1019 crate::Constant {
1020 name: Some(c.name.name.to_string()),
1021 ty,
1022 init,
1023 },
1024 span,
1025 );
1026
1027 ctx.globals
1028 .insert(c.name.name, LoweredGlobalDecl::Const(handle));
1029 }
1030 ast::GlobalDeclKind::Override(ref o) => {
1031 let init = o
1032 .init
1033 .map(|init| self.expression(init, &mut ctx.as_override()))
1034 .transpose()?;
1035 let inferred_type = init
1036 .map(|init| ctx.as_const().register_type(init))
1037 .transpose()?;
1038
1039 let explicit_ty =
1040 o.ty.map(|ty| self.resolve_ast_type(ty, &mut ctx))
1041 .transpose()?;
1042
1043 let id =
1044 o.id.map(|id| self.const_u32(id, &mut ctx.as_const()))
1045 .transpose()?;
1046
1047 let id = if let Some((id, id_span)) = id {
1048 Some(
1049 u16::try_from(id)
1050 .map_err(|_| Error::PipelineConstantIDValue(id_span))?,
1051 )
1052 } else {
1053 None
1054 };
1055
1056 let ty = match (explicit_ty, inferred_type) {
1057 (Some(explicit_ty), Some(inferred_type)) => {
1058 if explicit_ty == inferred_type {
1059 explicit_ty
1060 } else {
1061 let gctx = ctx.module.to_ctx();
1062 return Err(Error::InitializationTypeMismatch {
1063 name: o.name.span,
1064 expected: explicit_ty.to_wgsl(&gctx),
1065 got: inferred_type.to_wgsl(&gctx),
1066 });
1067 }
1068 }
1069 (Some(explicit_ty), None) => explicit_ty,
1070 (None, Some(inferred_type)) => inferred_type,
1071 (None, None) => {
1072 return Err(Error::DeclMissingTypeAndInit(o.name.span));
1073 }
1074 };
1075
1076 let handle = ctx.module.overrides.append(
1077 crate::Override {
1078 name: Some(o.name.name.to_string()),
1079 id,
1080 ty,
1081 init,
1082 },
1083 span,
1084 );
1085
1086 ctx.globals
1087 .insert(o.name.name, LoweredGlobalDecl::Override(handle));
1088 }
1089 ast::GlobalDeclKind::Struct(ref s) => {
1090 let handle = self.r#struct(s, span, &mut ctx)?;
1091 ctx.globals
1092 .insert(s.name.name, LoweredGlobalDecl::Type(handle));
1093 }
1094 ast::GlobalDeclKind::Type(ref alias) => {
1095 let ty = self.resolve_named_ast_type(
1096 alias.ty,
1097 Some(alias.name.name.to_string()),
1098 &mut ctx,
1099 )?;
1100 ctx.globals
1101 .insert(alias.name.name, LoweredGlobalDecl::Type(ty));
1102 }
1103 }
1104 }
1105
1106 crate::compact::compact(&mut module);
1110
1111 Ok(module)
1112 }
1113
1114 fn function(
1115 &mut self,
1116 f: &ast::Function<'source>,
1117 span: Span,
1118 ctx: &mut GlobalContext<'source, '_, '_>,
1119 ) -> Result<LoweredGlobalDecl, Error<'source>> {
1120 let mut local_table = FastHashMap::default();
1121 let mut expressions = Arena::new();
1122 let mut named_expressions = FastIndexMap::default();
1123 let mut local_expression_kind_tracker = crate::proc::ExpressionKindTracker::new();
1124
1125 let arguments = f
1126 .arguments
1127 .iter()
1128 .enumerate()
1129 .map(|(i, arg)| {
1130 let ty = self.resolve_ast_type(arg.ty, ctx)?;
1131 let expr = expressions
1132 .append(crate::Expression::FunctionArgument(i as u32), arg.name.span);
1133 local_table.insert(arg.handle, Typed::Plain(expr));
1134 named_expressions.insert(expr, (arg.name.name.to_string(), arg.name.span));
1135 local_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Runtime);
1136
1137 Ok(crate::FunctionArgument {
1138 name: Some(arg.name.name.to_string()),
1139 ty,
1140 binding: self.binding(&arg.binding, ty, ctx)?,
1141 })
1142 })
1143 .collect::<Result<Vec<_>, _>>()?;
1144
1145 let result = f
1146 .result
1147 .as_ref()
1148 .map(|res| {
1149 let ty = self.resolve_ast_type(res.ty, ctx)?;
1150 Ok(crate::FunctionResult {
1151 ty,
1152 binding: self.binding(&res.binding, ty, ctx)?,
1153 })
1154 })
1155 .transpose()?;
1156
1157 let mut function = crate::Function {
1158 name: Some(f.name.name.to_string()),
1159 arguments,
1160 result,
1161 local_variables: Arena::new(),
1162 expressions,
1163 named_expressions: crate::NamedExpressions::default(),
1164 body: crate::Block::default(),
1165 };
1166
1167 let mut typifier = Typifier::default();
1168 let mut stmt_ctx = StatementContext {
1169 local_table: &mut local_table,
1170 globals: ctx.globals,
1171 ast_expressions: ctx.ast_expressions,
1172 const_typifier: ctx.const_typifier,
1173 typifier: &mut typifier,
1174 function: &mut function,
1175 named_expressions: &mut named_expressions,
1176 types: ctx.types,
1177 module: ctx.module,
1178 local_expression_kind_tracker: &mut local_expression_kind_tracker,
1179 global_expression_kind_tracker: ctx.global_expression_kind_tracker,
1180 };
1181 let mut body = self.block(&f.body, false, &mut stmt_ctx)?;
1182 ensure_block_returns(&mut body);
1183
1184 function.body = body;
1185 function.named_expressions = named_expressions
1186 .into_iter()
1187 .map(|(key, (name, _))| (key, name))
1188 .collect();
1189
1190 if let Some(ref entry) = f.entry_point {
1191 let workgroup_size = if let Some(workgroup_size) = entry.workgroup_size {
1192 let mut workgroup_size_out = [1; 3];
1194 for (i, size) in workgroup_size.into_iter().enumerate() {
1195 if let Some(size_expr) = size {
1196 workgroup_size_out[i] = self.const_u32(size_expr, &mut ctx.as_const())?.0;
1197 }
1198 }
1199 workgroup_size_out
1200 } else {
1201 [0; 3]
1202 };
1203
1204 ctx.module.entry_points.push(crate::EntryPoint {
1205 name: f.name.name.to_string(),
1206 stage: entry.stage,
1207 early_depth_test: entry.early_depth_test,
1208 workgroup_size,
1209 function,
1210 });
1211 Ok(LoweredGlobalDecl::EntryPoint)
1212 } else {
1213 let handle = ctx.module.functions.append(function, span);
1214 Ok(LoweredGlobalDecl::Function(handle))
1215 }
1216 }
1217
1218 fn block(
1219 &mut self,
1220 b: &ast::Block<'source>,
1221 is_inside_loop: bool,
1222 ctx: &mut StatementContext<'source, '_, '_>,
1223 ) -> Result<crate::Block, Error<'source>> {
1224 let mut block = crate::Block::default();
1225
1226 for stmt in b.stmts.iter() {
1227 self.statement(stmt, &mut block, is_inside_loop, ctx)?;
1228 }
1229
1230 Ok(block)
1231 }
1232
1233 fn statement(
1234 &mut self,
1235 stmt: &ast::Statement<'source>,
1236 block: &mut crate::Block,
1237 is_inside_loop: bool,
1238 ctx: &mut StatementContext<'source, '_, '_>,
1239 ) -> Result<(), Error<'source>> {
1240 let out = match stmt.kind {
1241 ast::StatementKind::Block(ref block) => {
1242 let block = self.block(block, is_inside_loop, ctx)?;
1243 crate::Statement::Block(block)
1244 }
1245 ast::StatementKind::LocalDecl(ref decl) => match *decl {
1246 ast::LocalDecl::Let(ref l) => {
1247 let mut emitter = Emitter::default();
1248 emitter.start(&ctx.function.expressions);
1249
1250 let value =
1251 self.expression(l.init, &mut ctx.as_expression(block, &mut emitter))?;
1252
1253 ctx.local_expression_kind_tracker.force_non_const(value);
1259
1260 let explicit_ty =
1261 l.ty.map(|ty| self.resolve_ast_type(ty, &mut ctx.as_global()))
1262 .transpose()?;
1263
1264 if let Some(ty) = explicit_ty {
1265 let mut ctx = ctx.as_expression(block, &mut emitter);
1266 let init_ty = ctx.register_type(value)?;
1267 if !ctx.module.types[ty]
1268 .inner
1269 .equivalent(&ctx.module.types[init_ty].inner, &ctx.module.types)
1270 {
1271 let gctx = &ctx.module.to_ctx();
1272 return Err(Error::InitializationTypeMismatch {
1273 name: l.name.span,
1274 expected: ty.to_wgsl(gctx),
1275 got: init_ty.to_wgsl(gctx),
1276 });
1277 }
1278 }
1279
1280 block.extend(emitter.finish(&ctx.function.expressions));
1281 ctx.local_table.insert(l.handle, Typed::Plain(value));
1282 ctx.named_expressions
1283 .insert(value, (l.name.name.to_string(), l.name.span));
1284
1285 return Ok(());
1286 }
1287 ast::LocalDecl::Var(ref v) => {
1288 let explicit_ty =
1289 v.ty.map(|ast| self.resolve_ast_type(ast, &mut ctx.as_global()))
1290 .transpose()?;
1291
1292 let mut emitter = Emitter::default();
1293 emitter.start(&ctx.function.expressions);
1294 let mut ectx = ctx.as_expression(block, &mut emitter);
1295
1296 let ty;
1297 let initializer;
1298 match (v.init, explicit_ty) {
1299 (Some(init), Some(explicit_ty)) => {
1300 let init = self.expression_for_abstract(init, &mut ectx)?;
1301 let ty_res = crate::proc::TypeResolution::Handle(explicit_ty);
1302 let init = ectx
1303 .try_automatic_conversions(init, &ty_res, v.name.span)
1304 .map_err(|error| match error {
1305 Error::AutoConversion {
1306 dest_span: _,
1307 dest_type,
1308 source_span: _,
1309 source_type,
1310 } => Error::InitializationTypeMismatch {
1311 name: v.name.span,
1312 expected: dest_type,
1313 got: source_type,
1314 },
1315 other => other,
1316 })?;
1317 ty = explicit_ty;
1318 initializer = Some(init);
1319 }
1320 (Some(init), None) => {
1321 let concretized = self.expression(init, &mut ectx)?;
1322 ty = ectx.register_type(concretized)?;
1323 initializer = Some(concretized);
1324 }
1325 (None, Some(explicit_ty)) => {
1326 ty = explicit_ty;
1327 initializer = None;
1328 }
1329 (None, None) => return Err(Error::DeclMissingTypeAndInit(v.name.span)),
1330 }
1331
1332 let (const_initializer, initializer) = {
1333 match initializer {
1334 Some(init) => {
1335 if is_inside_loop
1343 || !ctx.local_expression_kind_tracker.is_const_or_override(init)
1344 {
1345 (None, Some(init))
1346 } else {
1347 (Some(init), None)
1348 }
1349 }
1350 None => (None, None),
1351 }
1352 };
1353
1354 let var = ctx.function.local_variables.append(
1355 crate::LocalVariable {
1356 name: Some(v.name.name.to_string()),
1357 ty,
1358 init: const_initializer,
1359 },
1360 stmt.span,
1361 );
1362
1363 let handle = ctx.as_expression(block, &mut emitter).interrupt_emitter(
1364 crate::Expression::LocalVariable(var),
1365 Span::UNDEFINED,
1366 )?;
1367 block.extend(emitter.finish(&ctx.function.expressions));
1368 ctx.local_table.insert(v.handle, Typed::Reference(handle));
1369
1370 match initializer {
1371 Some(initializer) => crate::Statement::Store {
1372 pointer: handle,
1373 value: initializer,
1374 },
1375 None => return Ok(()),
1376 }
1377 }
1378 },
1379 ast::StatementKind::If {
1380 condition,
1381 ref accept,
1382 ref reject,
1383 } => {
1384 let mut emitter = Emitter::default();
1385 emitter.start(&ctx.function.expressions);
1386
1387 let condition =
1388 self.expression(condition, &mut ctx.as_expression(block, &mut emitter))?;
1389 block.extend(emitter.finish(&ctx.function.expressions));
1390
1391 let accept = self.block(accept, is_inside_loop, ctx)?;
1392 let reject = self.block(reject, is_inside_loop, ctx)?;
1393
1394 crate::Statement::If {
1395 condition,
1396 accept,
1397 reject,
1398 }
1399 }
1400 ast::StatementKind::Switch {
1401 selector,
1402 ref cases,
1403 } => {
1404 let mut emitter = Emitter::default();
1405 emitter.start(&ctx.function.expressions);
1406
1407 let mut ectx = ctx.as_expression(block, &mut emitter);
1408 let selector = self.expression(selector, &mut ectx)?;
1409
1410 let uint =
1411 resolve_inner!(ectx, selector).scalar_kind() == Some(crate::ScalarKind::Uint);
1412 block.extend(emitter.finish(&ctx.function.expressions));
1413
1414 let cases = cases
1415 .iter()
1416 .map(|case| {
1417 Ok(crate::SwitchCase {
1418 value: match case.value {
1419 ast::SwitchValue::Expr(expr) => {
1420 let span = ctx.ast_expressions.get_span(expr);
1421 let expr =
1422 self.expression(expr, &mut ctx.as_global().as_const())?;
1423 match ctx.module.to_ctx().eval_expr_to_literal(expr) {
1424 Some(crate::Literal::I32(value)) if !uint => {
1425 crate::SwitchValue::I32(value)
1426 }
1427 Some(crate::Literal::U32(value)) if uint => {
1428 crate::SwitchValue::U32(value)
1429 }
1430 _ => {
1431 return Err(Error::InvalidSwitchValue { uint, span });
1432 }
1433 }
1434 }
1435 ast::SwitchValue::Default => crate::SwitchValue::Default,
1436 },
1437 body: self.block(&case.body, is_inside_loop, ctx)?,
1438 fall_through: case.fall_through,
1439 })
1440 })
1441 .collect::<Result<_, _>>()?;
1442
1443 crate::Statement::Switch { selector, cases }
1444 }
1445 ast::StatementKind::Loop {
1446 ref body,
1447 ref continuing,
1448 break_if,
1449 } => {
1450 let body = self.block(body, true, ctx)?;
1451 let mut continuing = self.block(continuing, true, ctx)?;
1452
1453 let mut emitter = Emitter::default();
1454 emitter.start(&ctx.function.expressions);
1455 let break_if = break_if
1456 .map(|expr| {
1457 self.expression(expr, &mut ctx.as_expression(&mut continuing, &mut emitter))
1458 })
1459 .transpose()?;
1460 continuing.extend(emitter.finish(&ctx.function.expressions));
1461
1462 crate::Statement::Loop {
1463 body,
1464 continuing,
1465 break_if,
1466 }
1467 }
1468 ast::StatementKind::Break => crate::Statement::Break,
1469 ast::StatementKind::Continue => crate::Statement::Continue,
1470 ast::StatementKind::Return { value } => {
1471 let mut emitter = Emitter::default();
1472 emitter.start(&ctx.function.expressions);
1473
1474 let value = value
1475 .map(|expr| self.expression(expr, &mut ctx.as_expression(block, &mut emitter)))
1476 .transpose()?;
1477 block.extend(emitter.finish(&ctx.function.expressions));
1478
1479 crate::Statement::Return { value }
1480 }
1481 ast::StatementKind::Kill => crate::Statement::Kill,
1482 ast::StatementKind::Call {
1483 ref function,
1484 ref arguments,
1485 } => {
1486 let mut emitter = Emitter::default();
1487 emitter.start(&ctx.function.expressions);
1488
1489 let _ = self.call(
1490 stmt.span,
1491 function,
1492 arguments,
1493 &mut ctx.as_expression(block, &mut emitter),
1494 )?;
1495 block.extend(emitter.finish(&ctx.function.expressions));
1496 return Ok(());
1497 }
1498 ast::StatementKind::Assign {
1499 target: ast_target,
1500 op,
1501 value,
1502 } => {
1503 let mut emitter = Emitter::default();
1504 emitter.start(&ctx.function.expressions);
1505
1506 let target = self.expression_for_reference(
1507 ast_target,
1508 &mut ctx.as_expression(block, &mut emitter),
1509 )?;
1510 let mut value =
1511 self.expression(value, &mut ctx.as_expression(block, &mut emitter))?;
1512
1513 let target_handle = match target {
1514 Typed::Reference(handle) => handle,
1515 Typed::Plain(handle) => {
1516 let ty = ctx.invalid_assignment_type(handle);
1517 return Err(Error::InvalidAssignment {
1518 span: ctx.ast_expressions.get_span(ast_target),
1519 ty,
1520 });
1521 }
1522 };
1523
1524 let value = match op {
1525 Some(op) => {
1526 let mut ctx = ctx.as_expression(block, &mut emitter);
1527 let mut left = ctx.apply_load_rule(target)?;
1528 ctx.binary_op_splat(op, &mut left, &mut value)?;
1529 ctx.append_expression(
1530 crate::Expression::Binary {
1531 op,
1532 left,
1533 right: value,
1534 },
1535 stmt.span,
1536 )?
1537 }
1538 None => value,
1539 };
1540 block.extend(emitter.finish(&ctx.function.expressions));
1541
1542 crate::Statement::Store {
1543 pointer: target_handle,
1544 value,
1545 }
1546 }
1547 ast::StatementKind::Increment(value) | ast::StatementKind::Decrement(value) => {
1548 let mut emitter = Emitter::default();
1549 emitter.start(&ctx.function.expressions);
1550
1551 let op = match stmt.kind {
1552 ast::StatementKind::Increment(_) => crate::BinaryOperator::Add,
1553 ast::StatementKind::Decrement(_) => crate::BinaryOperator::Subtract,
1554 _ => unreachable!(),
1555 };
1556
1557 let value_span = ctx.ast_expressions.get_span(value);
1558 let target = self
1559 .expression_for_reference(value, &mut ctx.as_expression(block, &mut emitter))?;
1560 let target_handle = match target {
1561 Typed::Reference(handle) => handle,
1562 Typed::Plain(_) => return Err(Error::BadIncrDecrReferenceType(value_span)),
1563 };
1564
1565 let mut ectx = ctx.as_expression(block, &mut emitter);
1566 let scalar = match *resolve_inner!(ectx, target_handle) {
1567 crate::TypeInner::ValuePointer {
1568 size: None, scalar, ..
1569 } => scalar,
1570 crate::TypeInner::Pointer { base, .. } => match ectx.module.types[base].inner {
1571 crate::TypeInner::Scalar(scalar) => scalar,
1572 _ => return Err(Error::BadIncrDecrReferenceType(value_span)),
1573 },
1574 _ => return Err(Error::BadIncrDecrReferenceType(value_span)),
1575 };
1576 let literal = match scalar.kind {
1577 crate::ScalarKind::Sint | crate::ScalarKind::Uint => {
1578 crate::Literal::one(scalar)
1579 .ok_or(Error::BadIncrDecrReferenceType(value_span))?
1580 }
1581 _ => return Err(Error::BadIncrDecrReferenceType(value_span)),
1582 };
1583
1584 let right =
1585 ectx.interrupt_emitter(crate::Expression::Literal(literal), Span::UNDEFINED)?;
1586 let rctx = ectx.runtime_expression_ctx(stmt.span)?;
1587 let left = rctx.function.expressions.append(
1588 crate::Expression::Load {
1589 pointer: target_handle,
1590 },
1591 value_span,
1592 );
1593 let value = rctx
1594 .function
1595 .expressions
1596 .append(crate::Expression::Binary { op, left, right }, stmt.span);
1597 rctx.local_expression_kind_tracker
1598 .insert(left, crate::proc::ExpressionKind::Runtime);
1599 rctx.local_expression_kind_tracker
1600 .insert(value, crate::proc::ExpressionKind::Runtime);
1601
1602 block.extend(emitter.finish(&ctx.function.expressions));
1603 crate::Statement::Store {
1604 pointer: target_handle,
1605 value,
1606 }
1607 }
1608 ast::StatementKind::Ignore(expr) => {
1609 let mut emitter = Emitter::default();
1610 emitter.start(&ctx.function.expressions);
1611
1612 let _ = self.expression(expr, &mut ctx.as_expression(block, &mut emitter))?;
1613 block.extend(emitter.finish(&ctx.function.expressions));
1614 return Ok(());
1615 }
1616 };
1617
1618 block.push(out, stmt.span);
1619
1620 Ok(())
1621 }
1622
1623 fn expression(
1631 &mut self,
1632 expr: Handle<ast::Expression<'source>>,
1633 ctx: &mut ExpressionContext<'source, '_, '_>,
1634 ) -> Result<Handle<crate::Expression>, Error<'source>> {
1635 let expr = self.expression_for_abstract(expr, ctx)?;
1636 ctx.concretize(expr)
1637 }
1638
1639 fn expression_for_abstract(
1640 &mut self,
1641 expr: Handle<ast::Expression<'source>>,
1642 ctx: &mut ExpressionContext<'source, '_, '_>,
1643 ) -> Result<Handle<crate::Expression>, Error<'source>> {
1644 let expr = self.expression_for_reference(expr, ctx)?;
1645 ctx.apply_load_rule(expr)
1646 }
1647
1648 fn expression_for_reference(
1649 &mut self,
1650 expr: Handle<ast::Expression<'source>>,
1651 ctx: &mut ExpressionContext<'source, '_, '_>,
1652 ) -> Result<Typed<Handle<crate::Expression>>, Error<'source>> {
1653 let span = ctx.ast_expressions.get_span(expr);
1654 let expr = &ctx.ast_expressions[expr];
1655
1656 let expr: Typed<crate::Expression> = match *expr {
1657 ast::Expression::Literal(literal) => {
1658 let literal = match literal {
1659 ast::Literal::Number(Number::F32(f)) => crate::Literal::F32(f),
1660 ast::Literal::Number(Number::I32(i)) => crate::Literal::I32(i),
1661 ast::Literal::Number(Number::U32(u)) => crate::Literal::U32(u),
1662 ast::Literal::Number(Number::I64(i)) => crate::Literal::I64(i),
1663 ast::Literal::Number(Number::U64(u)) => crate::Literal::U64(u),
1664 ast::Literal::Number(Number::F64(f)) => crate::Literal::F64(f),
1665 ast::Literal::Number(Number::AbstractInt(i)) => crate::Literal::AbstractInt(i),
1666 ast::Literal::Number(Number::AbstractFloat(f)) => {
1667 crate::Literal::AbstractFloat(f)
1668 }
1669 ast::Literal::Bool(b) => crate::Literal::Bool(b),
1670 };
1671 let handle = ctx.interrupt_emitter(crate::Expression::Literal(literal), span)?;
1672 return Ok(Typed::Plain(handle));
1673 }
1674 ast::Expression::Ident(ast::IdentExpr::Local(local)) => {
1675 let rctx = ctx.runtime_expression_ctx(span)?;
1676 return Ok(rctx.local_table[&local]);
1677 }
1678 ast::Expression::Ident(ast::IdentExpr::Unresolved(name)) => {
1679 let global = ctx
1680 .globals
1681 .get(name)
1682 .ok_or(Error::UnknownIdent(span, name))?;
1683 let expr = match *global {
1684 LoweredGlobalDecl::Var(handle) => {
1685 let expr = crate::Expression::GlobalVariable(handle);
1686 match ctx.module.global_variables[handle].space {
1687 crate::AddressSpace::Handle => Typed::Plain(expr),
1688 _ => Typed::Reference(expr),
1689 }
1690 }
1691 LoweredGlobalDecl::Const(handle) => {
1692 Typed::Plain(crate::Expression::Constant(handle))
1693 }
1694 LoweredGlobalDecl::Override(handle) => {
1695 Typed::Plain(crate::Expression::Override(handle))
1696 }
1697 LoweredGlobalDecl::Function(_)
1698 | LoweredGlobalDecl::Type(_)
1699 | LoweredGlobalDecl::EntryPoint => {
1700 return Err(Error::Unexpected(span, ExpectedToken::Variable));
1701 }
1702 };
1703
1704 return expr.try_map(|handle| ctx.interrupt_emitter(handle, span));
1705 }
1706 ast::Expression::Construct {
1707 ref ty,
1708 ty_span,
1709 ref components,
1710 } => {
1711 let handle = self.construct(span, ty, ty_span, components, ctx)?;
1712 return Ok(Typed::Plain(handle));
1713 }
1714 ast::Expression::Unary { op, expr } => {
1715 let expr = self.expression_for_abstract(expr, ctx)?;
1716 Typed::Plain(crate::Expression::Unary { op, expr })
1717 }
1718 ast::Expression::AddrOf(expr) => {
1719 match self.expression_for_reference(expr, ctx)? {
1722 Typed::Reference(handle) => {
1723 return Ok(Typed::Plain(handle));
1725 }
1726 Typed::Plain(_) => {
1727 return Err(Error::NotReference("the operand of the `&` operator", span));
1728 }
1729 }
1730 }
1731 ast::Expression::Deref(expr) => {
1732 let pointer = self.expression(expr, ctx)?;
1734
1735 if resolve_inner!(ctx, pointer).pointer_space().is_none() {
1736 return Err(Error::NotPointer(span));
1737 }
1738
1739 return Ok(Typed::Reference(pointer));
1741 }
1742 ast::Expression::Binary { op, left, right } => {
1743 self.binary(op, left, right, span, ctx)?
1744 }
1745 ast::Expression::Call {
1746 ref function,
1747 ref arguments,
1748 } => {
1749 let handle = self
1750 .call(span, function, arguments, ctx)?
1751 .ok_or(Error::FunctionReturnsVoid(function.span))?;
1752 return Ok(Typed::Plain(handle));
1753 }
1754 ast::Expression::Index { base, index } => {
1755 let lowered_base = self.expression_for_reference(base, ctx)?;
1756 let index = self.expression(index, ctx)?;
1757
1758 if let Typed::Plain(handle) = lowered_base {
1759 if resolve_inner!(ctx, handle).pointer_space().is_some() {
1760 return Err(Error::Pointer(
1761 "the value indexed by a `[]` subscripting expression",
1762 ctx.ast_expressions.get_span(base),
1763 ));
1764 }
1765 }
1766
1767 lowered_base.map(|base| match ctx.const_access(index) {
1768 Some(index) => crate::Expression::AccessIndex { base, index },
1769 None => crate::Expression::Access { base, index },
1770 })
1771 }
1772 ast::Expression::Member { base, ref field } => {
1773 let lowered_base = self.expression_for_reference(base, ctx)?;
1774
1775 let temp_inner;
1776 let composite_type: &crate::TypeInner = match lowered_base {
1777 Typed::Reference(handle) => {
1778 let inner = resolve_inner!(ctx, handle);
1779 match *inner {
1780 crate::TypeInner::Pointer { base, .. } => &ctx.module.types[base].inner,
1781 crate::TypeInner::ValuePointer {
1782 size: None, scalar, ..
1783 } => {
1784 temp_inner = crate::TypeInner::Scalar(scalar);
1785 &temp_inner
1786 }
1787 crate::TypeInner::ValuePointer {
1788 size: Some(size),
1789 scalar,
1790 ..
1791 } => {
1792 temp_inner = crate::TypeInner::Vector { size, scalar };
1793 &temp_inner
1794 }
1795 _ => unreachable!(
1796 "In Typed::Reference(handle), handle must be a Naga pointer"
1797 ),
1798 }
1799 }
1800
1801 Typed::Plain(handle) => {
1802 let inner = resolve_inner!(ctx, handle);
1803 if let crate::TypeInner::Pointer { .. }
1804 | crate::TypeInner::ValuePointer { .. } = *inner
1805 {
1806 return Err(Error::Pointer(
1807 "the value accessed by a `.member` expression",
1808 ctx.ast_expressions.get_span(base),
1809 ));
1810 }
1811 inner
1812 }
1813 };
1814
1815 let access = match *composite_type {
1816 crate::TypeInner::Struct { ref members, .. } => {
1817 let index = members
1818 .iter()
1819 .position(|m| m.name.as_deref() == Some(field.name))
1820 .ok_or(Error::BadAccessor(field.span))?
1821 as u32;
1822
1823 lowered_base.map(|base| crate::Expression::AccessIndex { base, index })
1824 }
1825 crate::TypeInner::Vector { .. } | crate::TypeInner::Matrix { .. } => {
1826 match Components::new(field.name, field.span)? {
1827 Components::Swizzle { size, pattern } => {
1828 Typed::Plain(crate::Expression::Swizzle {
1831 size,
1832 vector: ctx.apply_load_rule(lowered_base)?,
1833 pattern,
1834 })
1835 }
1836 Components::Single(index) => lowered_base
1837 .map(|base| crate::Expression::AccessIndex { base, index }),
1838 }
1839 }
1840 _ => return Err(Error::BadAccessor(field.span)),
1841 };
1842
1843 access
1844 }
1845 ast::Expression::Bitcast { expr, to, ty_span } => {
1846 let expr = self.expression(expr, ctx)?;
1847 let to_resolved = self.resolve_ast_type(to, &mut ctx.as_global())?;
1848
1849 let element_scalar = match ctx.module.types[to_resolved].inner {
1850 crate::TypeInner::Scalar(scalar) => scalar,
1851 crate::TypeInner::Vector { scalar, .. } => scalar,
1852 _ => {
1853 let ty = resolve!(ctx, expr);
1854 let gctx = &ctx.module.to_ctx();
1855 return Err(Error::BadTypeCast {
1856 from_type: ty.to_wgsl(gctx),
1857 span: ty_span,
1858 to_type: to_resolved.to_wgsl(gctx),
1859 });
1860 }
1861 };
1862
1863 Typed::Plain(crate::Expression::As {
1864 expr,
1865 kind: element_scalar.kind,
1866 convert: None,
1867 })
1868 }
1869 };
1870
1871 expr.try_map(|handle| ctx.append_expression(handle, span))
1872 }
1873
1874 fn binary(
1875 &mut self,
1876 op: crate::BinaryOperator,
1877 left: Handle<ast::Expression<'source>>,
1878 right: Handle<ast::Expression<'source>>,
1879 span: Span,
1880 ctx: &mut ExpressionContext<'source, '_, '_>,
1881 ) -> Result<Typed<crate::Expression>, Error<'source>> {
1882 let mut left = self.expression_for_abstract(left, ctx)?;
1884 let mut right = self.expression_for_abstract(right, ctx)?;
1885
1886 ctx.binary_op_splat(op, &mut left, &mut right)?;
1889
1890 match op {
1892 crate::BinaryOperator::ShiftLeft | crate::BinaryOperator::ShiftRight => {
1897 right =
1898 ctx.try_automatic_conversion_for_leaf_scalar(right, crate::Scalar::U32, span)?;
1899 }
1900
1901 _ => {
1906 ctx.grow_types(left)?;
1907 ctx.grow_types(right)?;
1908 if let Ok(consensus_scalar) =
1909 ctx.automatic_conversion_consensus([left, right].iter())
1910 {
1911 ctx.convert_to_leaf_scalar(&mut left, consensus_scalar)?;
1912 ctx.convert_to_leaf_scalar(&mut right, consensus_scalar)?;
1913 }
1914 }
1915 }
1916
1917 Ok(Typed::Plain(crate::Expression::Binary { op, left, right }))
1918 }
1919
1920 fn call(
1939 &mut self,
1940 span: Span,
1941 function: &ast::Ident<'source>,
1942 arguments: &[Handle<ast::Expression<'source>>],
1943 ctx: &mut ExpressionContext<'source, '_, '_>,
1944 ) -> Result<Option<Handle<crate::Expression>>, Error<'source>> {
1945 match ctx.globals.get(function.name) {
1946 Some(&LoweredGlobalDecl::Type(ty)) => {
1947 let handle = self.construct(
1948 span,
1949 &ast::ConstructorType::Type(ty),
1950 function.span,
1951 arguments,
1952 ctx,
1953 )?;
1954 Ok(Some(handle))
1955 }
1956 Some(
1957 &LoweredGlobalDecl::Const(_)
1958 | &LoweredGlobalDecl::Override(_)
1959 | &LoweredGlobalDecl::Var(_),
1960 ) => Err(Error::Unexpected(function.span, ExpectedToken::Function)),
1961 Some(&LoweredGlobalDecl::EntryPoint) => Err(Error::CalledEntryPoint(function.span)),
1962 Some(&LoweredGlobalDecl::Function(function)) => {
1963 let arguments = arguments
1964 .iter()
1965 .map(|&arg| self.expression(arg, ctx))
1966 .collect::<Result<Vec<_>, _>>()?;
1967
1968 let has_result = ctx.module.functions[function].result.is_some();
1969 let rctx = ctx.runtime_expression_ctx(span)?;
1970 rctx.block
1972 .extend(rctx.emitter.finish(&rctx.function.expressions));
1973 let result = has_result.then(|| {
1974 let result = rctx
1975 .function
1976 .expressions
1977 .append(crate::Expression::CallResult(function), span);
1978 rctx.local_expression_kind_tracker
1979 .insert(result, crate::proc::ExpressionKind::Runtime);
1980 result
1981 });
1982 rctx.emitter.start(&rctx.function.expressions);
1983 rctx.block.push(
1984 crate::Statement::Call {
1985 function,
1986 arguments,
1987 result,
1988 },
1989 span,
1990 );
1991
1992 Ok(result)
1993 }
1994 None => {
1995 let span = function.span;
1996 let expr = if let Some(fun) = conv::map_relational_fun(function.name) {
1997 let mut args = ctx.prepare_args(arguments, 1, span);
1998 let argument = self.expression(args.next()?, ctx)?;
1999 args.finish()?;
2000
2001 let argument_unmodified = matches!(
2003 fun,
2004 crate::RelationalFunction::All | crate::RelationalFunction::Any
2005 ) && {
2006 matches!(
2007 resolve_inner!(ctx, argument),
2008 &crate::TypeInner::Scalar(crate::Scalar {
2009 kind: crate::ScalarKind::Bool,
2010 ..
2011 })
2012 )
2013 };
2014
2015 if argument_unmodified {
2016 return Ok(Some(argument));
2017 } else {
2018 crate::Expression::Relational { fun, argument }
2019 }
2020 } else if let Some((axis, ctrl)) = conv::map_derivative(function.name) {
2021 let mut args = ctx.prepare_args(arguments, 1, span);
2022 let expr = self.expression(args.next()?, ctx)?;
2023 args.finish()?;
2024
2025 crate::Expression::Derivative { axis, ctrl, expr }
2026 } else if let Some(fun) = conv::map_standard_fun(function.name) {
2027 let expected = fun.argument_count() as _;
2028 let mut args = ctx.prepare_args(arguments, expected, span);
2029
2030 let arg = self.expression(args.next()?, ctx)?;
2031 let arg1 = args
2032 .next()
2033 .map(|x| self.expression(x, ctx))
2034 .ok()
2035 .transpose()?;
2036 let arg2 = args
2037 .next()
2038 .map(|x| self.expression(x, ctx))
2039 .ok()
2040 .transpose()?;
2041 let arg3 = args
2042 .next()
2043 .map(|x| self.expression(x, ctx))
2044 .ok()
2045 .transpose()?;
2046
2047 args.finish()?;
2048
2049 if fun == crate::MathFunction::Modf || fun == crate::MathFunction::Frexp {
2050 if let Some((size, width)) = match *resolve_inner!(ctx, arg) {
2051 crate::TypeInner::Scalar(crate::Scalar { width, .. }) => {
2052 Some((None, width))
2053 }
2054 crate::TypeInner::Vector {
2055 size,
2056 scalar: crate::Scalar { width, .. },
2057 ..
2058 } => Some((Some(size), width)),
2059 _ => None,
2060 } {
2061 ctx.module.generate_predeclared_type(
2062 if fun == crate::MathFunction::Modf {
2063 crate::PredeclaredType::ModfResult { size, width }
2064 } else {
2065 crate::PredeclaredType::FrexpResult { size, width }
2066 },
2067 );
2068 }
2069 }
2070
2071 crate::Expression::Math {
2072 fun,
2073 arg,
2074 arg1,
2075 arg2,
2076 arg3,
2077 }
2078 } else if let Some(fun) = Texture::map(function.name) {
2079 self.texture_sample_helper(fun, arguments, span, ctx)?
2080 } else if let Some((op, cop)) = conv::map_subgroup_operation(function.name) {
2081 return Ok(Some(
2082 self.subgroup_operation_helper(span, op, cop, arguments, ctx)?,
2083 ));
2084 } else if let Some(mode) = SubgroupGather::map(function.name) {
2085 return Ok(Some(
2086 self.subgroup_gather_helper(span, mode, arguments, ctx)?,
2087 ));
2088 } else if let Some(fun) = crate::AtomicFunction::map(function.name) {
2089 return Ok(Some(self.atomic_helper(span, fun, arguments, ctx)?));
2090 } else {
2091 match function.name {
2092 "select" => {
2093 let mut args = ctx.prepare_args(arguments, 3, span);
2094
2095 let reject = self.expression(args.next()?, ctx)?;
2096 let accept = self.expression(args.next()?, ctx)?;
2097 let condition = self.expression(args.next()?, ctx)?;
2098
2099 args.finish()?;
2100
2101 crate::Expression::Select {
2102 reject,
2103 accept,
2104 condition,
2105 }
2106 }
2107 "arrayLength" => {
2108 let mut args = ctx.prepare_args(arguments, 1, span);
2109 let expr = self.expression(args.next()?, ctx)?;
2110 args.finish()?;
2111
2112 crate::Expression::ArrayLength(expr)
2113 }
2114 "atomicLoad" => {
2115 let mut args = ctx.prepare_args(arguments, 1, span);
2116 let pointer = self.atomic_pointer(args.next()?, ctx)?;
2117 args.finish()?;
2118
2119 crate::Expression::Load { pointer }
2120 }
2121 "atomicStore" => {
2122 let mut args = ctx.prepare_args(arguments, 2, span);
2123 let pointer = self.atomic_pointer(args.next()?, ctx)?;
2124 let value = self.expression(args.next()?, ctx)?;
2125 args.finish()?;
2126
2127 let rctx = ctx.runtime_expression_ctx(span)?;
2128 rctx.block
2129 .extend(rctx.emitter.finish(&rctx.function.expressions));
2130 rctx.emitter.start(&rctx.function.expressions);
2131 rctx.block
2132 .push(crate::Statement::Store { pointer, value }, span);
2133 return Ok(None);
2134 }
2135 "atomicCompareExchangeWeak" => {
2136 let mut args = ctx.prepare_args(arguments, 3, span);
2137
2138 let pointer = self.atomic_pointer(args.next()?, ctx)?;
2139
2140 let compare = self.expression(args.next()?, ctx)?;
2141
2142 let value = args.next()?;
2143 let value_span = ctx.ast_expressions.get_span(value);
2144 let value = self.expression(value, ctx)?;
2145
2146 args.finish()?;
2147
2148 let expression = match *resolve_inner!(ctx, value) {
2149 crate::TypeInner::Scalar(scalar) => {
2150 crate::Expression::AtomicResult {
2151 ty: ctx.module.generate_predeclared_type(
2152 crate::PredeclaredType::AtomicCompareExchangeWeakResult(
2153 scalar,
2154 ),
2155 ),
2156 comparison: true,
2157 }
2158 }
2159 _ => return Err(Error::InvalidAtomicOperandType(value_span)),
2160 };
2161
2162 let result = ctx.interrupt_emitter(expression, span)?;
2163 let rctx = ctx.runtime_expression_ctx(span)?;
2164 rctx.block.push(
2165 crate::Statement::Atomic {
2166 pointer,
2167 fun: crate::AtomicFunction::Exchange {
2168 compare: Some(compare),
2169 },
2170 value,
2171 result,
2172 },
2173 span,
2174 );
2175 return Ok(Some(result));
2176 }
2177 "storageBarrier" => {
2178 ctx.prepare_args(arguments, 0, span).finish()?;
2179
2180 let rctx = ctx.runtime_expression_ctx(span)?;
2181 rctx.block
2182 .push(crate::Statement::Barrier(crate::Barrier::STORAGE), span);
2183 return Ok(None);
2184 }
2185 "workgroupBarrier" => {
2186 ctx.prepare_args(arguments, 0, span).finish()?;
2187
2188 let rctx = ctx.runtime_expression_ctx(span)?;
2189 rctx.block
2190 .push(crate::Statement::Barrier(crate::Barrier::WORK_GROUP), span);
2191 return Ok(None);
2192 }
2193 "subgroupBarrier" => {
2194 ctx.prepare_args(arguments, 0, span).finish()?;
2195
2196 let rctx = ctx.runtime_expression_ctx(span)?;
2197 rctx.block
2198 .push(crate::Statement::Barrier(crate::Barrier::SUB_GROUP), span);
2199 return Ok(None);
2200 }
2201 "workgroupUniformLoad" => {
2202 let mut args = ctx.prepare_args(arguments, 1, span);
2203 let expr = args.next()?;
2204 args.finish()?;
2205
2206 let pointer = self.expression(expr, ctx)?;
2207 let result_ty = match *resolve_inner!(ctx, pointer) {
2208 crate::TypeInner::Pointer {
2209 base,
2210 space: crate::AddressSpace::WorkGroup,
2211 } => base,
2212 ref other => {
2213 log::error!("Type {other:?} passed to workgroupUniformLoad");
2214 let span = ctx.ast_expressions.get_span(expr);
2215 return Err(Error::InvalidWorkGroupUniformLoad(span));
2216 }
2217 };
2218 let result = ctx.interrupt_emitter(
2219 crate::Expression::WorkGroupUniformLoadResult { ty: result_ty },
2220 span,
2221 )?;
2222 let rctx = ctx.runtime_expression_ctx(span)?;
2223 rctx.block.push(
2224 crate::Statement::WorkGroupUniformLoad { pointer, result },
2225 span,
2226 );
2227
2228 return Ok(Some(result));
2229 }
2230 "textureStore" => {
2231 let mut args = ctx.prepare_args(arguments, 3, span);
2232
2233 let image = args.next()?;
2234 let image_span = ctx.ast_expressions.get_span(image);
2235 let image = self.expression(image, ctx)?;
2236
2237 let coordinate = self.expression(args.next()?, ctx)?;
2238
2239 let (_, arrayed) = ctx.image_data(image, image_span)?;
2240 let array_index = arrayed
2241 .then(|| {
2242 args.min_args += 1;
2243 self.expression(args.next()?, ctx)
2244 })
2245 .transpose()?;
2246
2247 let value = self.expression(args.next()?, ctx)?;
2248
2249 args.finish()?;
2250
2251 let rctx = ctx.runtime_expression_ctx(span)?;
2252 rctx.block
2253 .extend(rctx.emitter.finish(&rctx.function.expressions));
2254 rctx.emitter.start(&rctx.function.expressions);
2255 let stmt = crate::Statement::ImageStore {
2256 image,
2257 coordinate,
2258 array_index,
2259 value,
2260 };
2261 rctx.block.push(stmt, span);
2262 return Ok(None);
2263 }
2264 "textureLoad" => {
2265 let mut args = ctx.prepare_args(arguments, 2, span);
2266
2267 let image = args.next()?;
2268 let image_span = ctx.ast_expressions.get_span(image);
2269 let image = self.expression(image, ctx)?;
2270
2271 let coordinate = self.expression(args.next()?, ctx)?;
2272
2273 let (class, arrayed) = ctx.image_data(image, image_span)?;
2274 let array_index = arrayed
2275 .then(|| {
2276 args.min_args += 1;
2277 self.expression(args.next()?, ctx)
2278 })
2279 .transpose()?;
2280
2281 let level = class
2282 .is_mipmapped()
2283 .then(|| {
2284 args.min_args += 1;
2285 self.expression(args.next()?, ctx)
2286 })
2287 .transpose()?;
2288
2289 let sample = class
2290 .is_multisampled()
2291 .then(|| self.expression(args.next()?, ctx))
2292 .transpose()?;
2293
2294 args.finish()?;
2295
2296 crate::Expression::ImageLoad {
2297 image,
2298 coordinate,
2299 array_index,
2300 level,
2301 sample,
2302 }
2303 }
2304 "textureDimensions" => {
2305 let mut args = ctx.prepare_args(arguments, 1, span);
2306 let image = self.expression(args.next()?, ctx)?;
2307 let level = args
2308 .next()
2309 .map(|arg| self.expression(arg, ctx))
2310 .ok()
2311 .transpose()?;
2312 args.finish()?;
2313
2314 crate::Expression::ImageQuery {
2315 image,
2316 query: crate::ImageQuery::Size { level },
2317 }
2318 }
2319 "textureNumLevels" => {
2320 let mut args = ctx.prepare_args(arguments, 1, span);
2321 let image = self.expression(args.next()?, ctx)?;
2322 args.finish()?;
2323
2324 crate::Expression::ImageQuery {
2325 image,
2326 query: crate::ImageQuery::NumLevels,
2327 }
2328 }
2329 "textureNumLayers" => {
2330 let mut args = ctx.prepare_args(arguments, 1, span);
2331 let image = self.expression(args.next()?, ctx)?;
2332 args.finish()?;
2333
2334 crate::Expression::ImageQuery {
2335 image,
2336 query: crate::ImageQuery::NumLayers,
2337 }
2338 }
2339 "textureNumSamples" => {
2340 let mut args = ctx.prepare_args(arguments, 1, span);
2341 let image = self.expression(args.next()?, ctx)?;
2342 args.finish()?;
2343
2344 crate::Expression::ImageQuery {
2345 image,
2346 query: crate::ImageQuery::NumSamples,
2347 }
2348 }
2349 "rayQueryInitialize" => {
2350 let mut args = ctx.prepare_args(arguments, 3, span);
2351 let query = self.ray_query_pointer(args.next()?, ctx)?;
2352 let acceleration_structure = self.expression(args.next()?, ctx)?;
2353 let descriptor = self.expression(args.next()?, ctx)?;
2354 args.finish()?;
2355
2356 let _ = ctx.module.generate_ray_desc_type();
2357 let fun = crate::RayQueryFunction::Initialize {
2358 acceleration_structure,
2359 descriptor,
2360 };
2361
2362 let rctx = ctx.runtime_expression_ctx(span)?;
2363 rctx.block
2364 .extend(rctx.emitter.finish(&rctx.function.expressions));
2365 rctx.emitter.start(&rctx.function.expressions);
2366 rctx.block
2367 .push(crate::Statement::RayQuery { query, fun }, span);
2368 return Ok(None);
2369 }
2370 "rayQueryProceed" => {
2371 let mut args = ctx.prepare_args(arguments, 1, span);
2372 let query = self.ray_query_pointer(args.next()?, ctx)?;
2373 args.finish()?;
2374
2375 let result = ctx.interrupt_emitter(
2376 crate::Expression::RayQueryProceedResult,
2377 span,
2378 )?;
2379 let fun = crate::RayQueryFunction::Proceed { result };
2380 let rctx = ctx.runtime_expression_ctx(span)?;
2381 rctx.block
2382 .push(crate::Statement::RayQuery { query, fun }, span);
2383 return Ok(Some(result));
2384 }
2385 "rayQueryGetCommittedIntersection" => {
2386 let mut args = ctx.prepare_args(arguments, 1, span);
2387 let query = self.ray_query_pointer(args.next()?, ctx)?;
2388 args.finish()?;
2389
2390 let _ = ctx.module.generate_ray_intersection_type();
2391
2392 crate::Expression::RayQueryGetIntersection {
2393 query,
2394 committed: true,
2395 }
2396 }
2397 "RayDesc" => {
2398 let ty = ctx.module.generate_ray_desc_type();
2399 let handle = self.construct(
2400 span,
2401 &ast::ConstructorType::Type(ty),
2402 function.span,
2403 arguments,
2404 ctx,
2405 )?;
2406 return Ok(Some(handle));
2407 }
2408 "subgroupBallot" => {
2409 let mut args = ctx.prepare_args(arguments, 0, span);
2410 let predicate = if arguments.len() == 1 {
2411 Some(self.expression(args.next()?, ctx)?)
2412 } else {
2413 None
2414 };
2415 args.finish()?;
2416
2417 let result = ctx
2418 .interrupt_emitter(crate::Expression::SubgroupBallotResult, span)?;
2419 let rctx = ctx.runtime_expression_ctx(span)?;
2420 rctx.block
2421 .push(crate::Statement::SubgroupBallot { result, predicate }, span);
2422 return Ok(Some(result));
2423 }
2424 _ => return Err(Error::UnknownIdent(function.span, function.name)),
2425 }
2426 };
2427
2428 let expr = ctx.append_expression(expr, span)?;
2429 Ok(Some(expr))
2430 }
2431 }
2432 }
2433
2434 fn atomic_pointer(
2435 &mut self,
2436 expr: Handle<ast::Expression<'source>>,
2437 ctx: &mut ExpressionContext<'source, '_, '_>,
2438 ) -> Result<Handle<crate::Expression>, Error<'source>> {
2439 let span = ctx.ast_expressions.get_span(expr);
2440 let pointer = self.expression(expr, ctx)?;
2441
2442 match *resolve_inner!(ctx, pointer) {
2443 crate::TypeInner::Pointer { base, .. } => match ctx.module.types[base].inner {
2444 crate::TypeInner::Atomic { .. } => Ok(pointer),
2445 ref other => {
2446 log::error!("Pointer type to {:?} passed to atomic op", other);
2447 Err(Error::InvalidAtomicPointer(span))
2448 }
2449 },
2450 ref other => {
2451 log::error!("Type {:?} passed to atomic op", other);
2452 Err(Error::InvalidAtomicPointer(span))
2453 }
2454 }
2455 }
2456
2457 fn atomic_helper(
2458 &mut self,
2459 span: Span,
2460 fun: crate::AtomicFunction,
2461 args: &[Handle<ast::Expression<'source>>],
2462 ctx: &mut ExpressionContext<'source, '_, '_>,
2463 ) -> Result<Handle<crate::Expression>, Error<'source>> {
2464 let mut args = ctx.prepare_args(args, 2, span);
2465
2466 let pointer = self.atomic_pointer(args.next()?, ctx)?;
2467
2468 let value = args.next()?;
2469 let value = self.expression(value, ctx)?;
2470 let ty = ctx.register_type(value)?;
2471
2472 args.finish()?;
2473
2474 let result = ctx.interrupt_emitter(
2475 crate::Expression::AtomicResult {
2476 ty,
2477 comparison: false,
2478 },
2479 span,
2480 )?;
2481 let rctx = ctx.runtime_expression_ctx(span)?;
2482 rctx.block.push(
2483 crate::Statement::Atomic {
2484 pointer,
2485 fun,
2486 value,
2487 result,
2488 },
2489 span,
2490 );
2491 Ok(result)
2492 }
2493
2494 fn texture_sample_helper(
2495 &mut self,
2496 fun: Texture,
2497 args: &[Handle<ast::Expression<'source>>],
2498 span: Span,
2499 ctx: &mut ExpressionContext<'source, '_, '_>,
2500 ) -> Result<crate::Expression, Error<'source>> {
2501 let mut args = ctx.prepare_args(args, fun.min_argument_count(), span);
2502
2503 fn get_image_and_span<'source>(
2504 lowerer: &mut Lowerer<'source, '_>,
2505 args: &mut ArgumentContext<'_, 'source>,
2506 ctx: &mut ExpressionContext<'source, '_, '_>,
2507 ) -> Result<(Handle<crate::Expression>, Span), Error<'source>> {
2508 let image = args.next()?;
2509 let image_span = ctx.ast_expressions.get_span(image);
2510 let image = lowerer.expression(image, ctx)?;
2511 Ok((image, image_span))
2512 }
2513
2514 let (image, image_span, gather) = match fun {
2515 Texture::Gather => {
2516 let image_or_component = args.next()?;
2517 let image_or_component_span = ctx.ast_expressions.get_span(image_or_component);
2518 let lowered_image_or_component = self.expression(image_or_component, ctx)?;
2520
2521 match *resolve_inner!(ctx, lowered_image_or_component) {
2522 crate::TypeInner::Image {
2523 class: crate::ImageClass::Depth { .. },
2524 ..
2525 } => (
2526 lowered_image_or_component,
2527 image_or_component_span,
2528 Some(crate::SwizzleComponent::X),
2529 ),
2530 _ => {
2531 let (image, image_span) = get_image_and_span(self, &mut args, ctx)?;
2532 (
2533 image,
2534 image_span,
2535 Some(ctx.gather_component(
2536 lowered_image_or_component,
2537 image_or_component_span,
2538 span,
2539 )?),
2540 )
2541 }
2542 }
2543 }
2544 Texture::GatherCompare => {
2545 let (image, image_span) = get_image_and_span(self, &mut args, ctx)?;
2546 (image, image_span, Some(crate::SwizzleComponent::X))
2547 }
2548
2549 _ => {
2550 let (image, image_span) = get_image_and_span(self, &mut args, ctx)?;
2551 (image, image_span, None)
2552 }
2553 };
2554
2555 let sampler = self.expression(args.next()?, ctx)?;
2556
2557 let coordinate = self.expression(args.next()?, ctx)?;
2558
2559 let (_, arrayed) = ctx.image_data(image, image_span)?;
2560 let array_index = arrayed
2561 .then(|| self.expression(args.next()?, ctx))
2562 .transpose()?;
2563
2564 let (level, depth_ref) = match fun {
2565 Texture::Gather => (crate::SampleLevel::Zero, None),
2566 Texture::GatherCompare => {
2567 let reference = self.expression(args.next()?, ctx)?;
2568 (crate::SampleLevel::Zero, Some(reference))
2569 }
2570
2571 Texture::Sample => (crate::SampleLevel::Auto, None),
2572 Texture::SampleBias => {
2573 let bias = self.expression(args.next()?, ctx)?;
2574 (crate::SampleLevel::Bias(bias), None)
2575 }
2576 Texture::SampleCompare => {
2577 let reference = self.expression(args.next()?, ctx)?;
2578 (crate::SampleLevel::Auto, Some(reference))
2579 }
2580 Texture::SampleCompareLevel => {
2581 let reference = self.expression(args.next()?, ctx)?;
2582 (crate::SampleLevel::Zero, Some(reference))
2583 }
2584 Texture::SampleGrad => {
2585 let x = self.expression(args.next()?, ctx)?;
2586 let y = self.expression(args.next()?, ctx)?;
2587 (crate::SampleLevel::Gradient { x, y }, None)
2588 }
2589 Texture::SampleLevel => {
2590 let level = self.expression(args.next()?, ctx)?;
2591 (crate::SampleLevel::Exact(level), None)
2592 }
2593 };
2594
2595 let offset = args
2596 .next()
2597 .map(|arg| self.expression(arg, &mut ctx.as_const()))
2598 .ok()
2599 .transpose()?;
2600
2601 args.finish()?;
2602
2603 Ok(crate::Expression::ImageSample {
2604 image,
2605 sampler,
2606 gather,
2607 coordinate,
2608 array_index,
2609 offset,
2610 level,
2611 depth_ref,
2612 })
2613 }
2614
2615 fn subgroup_operation_helper(
2616 &mut self,
2617 span: Span,
2618 op: crate::SubgroupOperation,
2619 collective_op: crate::CollectiveOperation,
2620 arguments: &[Handle<ast::Expression<'source>>],
2621 ctx: &mut ExpressionContext<'source, '_, '_>,
2622 ) -> Result<Handle<crate::Expression>, Error<'source>> {
2623 let mut args = ctx.prepare_args(arguments, 1, span);
2624
2625 let argument = self.expression(args.next()?, ctx)?;
2626 args.finish()?;
2627
2628 let ty = ctx.register_type(argument)?;
2629
2630 let result =
2631 ctx.interrupt_emitter(crate::Expression::SubgroupOperationResult { ty }, span)?;
2632 let rctx = ctx.runtime_expression_ctx(span)?;
2633 rctx.block.push(
2634 crate::Statement::SubgroupCollectiveOperation {
2635 op,
2636 collective_op,
2637 argument,
2638 result,
2639 },
2640 span,
2641 );
2642 Ok(result)
2643 }
2644
2645 fn subgroup_gather_helper(
2646 &mut self,
2647 span: Span,
2648 mode: SubgroupGather,
2649 arguments: &[Handle<ast::Expression<'source>>],
2650 ctx: &mut ExpressionContext<'source, '_, '_>,
2651 ) -> Result<Handle<crate::Expression>, Error<'source>> {
2652 let mut args = ctx.prepare_args(arguments, 2, span);
2653
2654 let argument = self.expression(args.next()?, ctx)?;
2655
2656 use SubgroupGather as Sg;
2657 let mode = if let Sg::BroadcastFirst = mode {
2658 crate::GatherMode::BroadcastFirst
2659 } else {
2660 let index = self.expression(args.next()?, ctx)?;
2661 match mode {
2662 Sg::Broadcast => crate::GatherMode::Broadcast(index),
2663 Sg::Shuffle => crate::GatherMode::Shuffle(index),
2664 Sg::ShuffleDown => crate::GatherMode::ShuffleDown(index),
2665 Sg::ShuffleUp => crate::GatherMode::ShuffleUp(index),
2666 Sg::ShuffleXor => crate::GatherMode::ShuffleXor(index),
2667 Sg::BroadcastFirst => unreachable!(),
2668 }
2669 };
2670
2671 args.finish()?;
2672
2673 let ty = ctx.register_type(argument)?;
2674
2675 let result =
2676 ctx.interrupt_emitter(crate::Expression::SubgroupOperationResult { ty }, span)?;
2677 let rctx = ctx.runtime_expression_ctx(span)?;
2678 rctx.block.push(
2679 crate::Statement::SubgroupGather {
2680 mode,
2681 argument,
2682 result,
2683 },
2684 span,
2685 );
2686 Ok(result)
2687 }
2688
2689 fn r#struct(
2690 &mut self,
2691 s: &ast::Struct<'source>,
2692 span: Span,
2693 ctx: &mut GlobalContext<'source, '_, '_>,
2694 ) -> Result<Handle<crate::Type>, Error<'source>> {
2695 let mut offset = 0;
2696 let mut struct_alignment = Alignment::ONE;
2697 let mut members = Vec::with_capacity(s.members.len());
2698
2699 for member in s.members.iter() {
2700 let ty = self.resolve_ast_type(member.ty, ctx)?;
2701
2702 self.layouter.update(ctx.module.to_ctx()).unwrap();
2703
2704 let member_min_size = self.layouter[ty].size;
2705 let member_min_alignment = self.layouter[ty].alignment;
2706
2707 let member_size = if let Some(size_expr) = member.size {
2708 let (size, span) = self.const_u32(size_expr, &mut ctx.as_const())?;
2709 if size < member_min_size {
2710 return Err(Error::SizeAttributeTooLow(span, member_min_size));
2711 } else {
2712 size
2713 }
2714 } else {
2715 member_min_size
2716 };
2717
2718 let member_alignment = if let Some(align_expr) = member.align {
2719 let (align, span) = self.const_u32(align_expr, &mut ctx.as_const())?;
2720 if let Some(alignment) = Alignment::new(align) {
2721 if alignment < member_min_alignment {
2722 return Err(Error::AlignAttributeTooLow(span, member_min_alignment));
2723 } else {
2724 alignment
2725 }
2726 } else {
2727 return Err(Error::NonPowerOfTwoAlignAttribute(span));
2728 }
2729 } else {
2730 member_min_alignment
2731 };
2732
2733 let binding = self.binding(&member.binding, ty, ctx)?;
2734
2735 offset = member_alignment.round_up(offset);
2736 struct_alignment = struct_alignment.max(member_alignment);
2737
2738 members.push(crate::StructMember {
2739 name: Some(member.name.name.to_owned()),
2740 ty,
2741 binding,
2742 offset,
2743 });
2744
2745 offset += member_size;
2746 }
2747
2748 let size = struct_alignment.round_up(offset);
2749 let inner = crate::TypeInner::Struct {
2750 members,
2751 span: size,
2752 };
2753
2754 let handle = ctx.module.types.insert(
2755 crate::Type {
2756 name: Some(s.name.name.to_string()),
2757 inner,
2758 },
2759 span,
2760 );
2761 Ok(handle)
2762 }
2763
2764 fn const_u32(
2765 &mut self,
2766 expr: Handle<ast::Expression<'source>>,
2767 ctx: &mut ExpressionContext<'source, '_, '_>,
2768 ) -> Result<(u32, Span), Error<'source>> {
2769 let span = ctx.ast_expressions.get_span(expr);
2770 let expr = self.expression(expr, ctx)?;
2771 let value = ctx
2772 .module
2773 .to_ctx()
2774 .eval_expr_to_u32(expr)
2775 .map_err(|err| match err {
2776 crate::proc::U32EvalError::NonConst => {
2777 Error::ExpectedConstExprConcreteIntegerScalar(span)
2778 }
2779 crate::proc::U32EvalError::Negative => Error::ExpectedNonNegative(span),
2780 })?;
2781 Ok((value, span))
2782 }
2783
2784 fn array_size(
2785 &mut self,
2786 size: ast::ArraySize<'source>,
2787 ctx: &mut GlobalContext<'source, '_, '_>,
2788 ) -> Result<crate::ArraySize, Error<'source>> {
2789 Ok(match size {
2790 ast::ArraySize::Constant(expr) => {
2791 let span = ctx.ast_expressions.get_span(expr);
2792 let const_expr = self.expression(expr, &mut ctx.as_const())?;
2793 let len =
2794 ctx.module
2795 .to_ctx()
2796 .eval_expr_to_u32(const_expr)
2797 .map_err(|err| match err {
2798 crate::proc::U32EvalError::NonConst => {
2799 Error::ExpectedConstExprConcreteIntegerScalar(span)
2800 }
2801 crate::proc::U32EvalError::Negative => {
2802 Error::ExpectedPositiveArrayLength(span)
2803 }
2804 })?;
2805 let size = NonZeroU32::new(len).ok_or(Error::ExpectedPositiveArrayLength(span))?;
2806 crate::ArraySize::Constant(size)
2807 }
2808 ast::ArraySize::Dynamic => crate::ArraySize::Dynamic,
2809 })
2810 }
2811
2812 fn resolve_named_ast_type(
2822 &mut self,
2823 handle: Handle<ast::Type<'source>>,
2824 name: Option<String>,
2825 ctx: &mut GlobalContext<'source, '_, '_>,
2826 ) -> Result<Handle<crate::Type>, Error<'source>> {
2827 let inner = match ctx.types[handle] {
2828 ast::Type::Scalar(scalar) => scalar.to_inner_scalar(),
2829 ast::Type::Vector { size, scalar } => scalar.to_inner_vector(size),
2830 ast::Type::Matrix {
2831 rows,
2832 columns,
2833 width,
2834 } => crate::TypeInner::Matrix {
2835 columns,
2836 rows,
2837 scalar: crate::Scalar::float(width),
2838 },
2839 ast::Type::Atomic(scalar) => scalar.to_inner_atomic(),
2840 ast::Type::Pointer { base, space } => {
2841 let base = self.resolve_ast_type(base, ctx)?;
2842 crate::TypeInner::Pointer { base, space }
2843 }
2844 ast::Type::Array { base, size } => {
2845 let base = self.resolve_ast_type(base, ctx)?;
2846 let size = self.array_size(size, ctx)?;
2847
2848 self.layouter.update(ctx.module.to_ctx()).unwrap();
2849 let stride = self.layouter[base].to_stride();
2850
2851 crate::TypeInner::Array { base, size, stride }
2852 }
2853 ast::Type::Image {
2854 dim,
2855 arrayed,
2856 class,
2857 } => crate::TypeInner::Image {
2858 dim,
2859 arrayed,
2860 class,
2861 },
2862 ast::Type::Sampler { comparison } => crate::TypeInner::Sampler { comparison },
2863 ast::Type::AccelerationStructure => crate::TypeInner::AccelerationStructure,
2864 ast::Type::RayQuery => crate::TypeInner::RayQuery,
2865 ast::Type::BindingArray { base, size } => {
2866 let base = self.resolve_ast_type(base, ctx)?;
2867 let size = self.array_size(size, ctx)?;
2868 crate::TypeInner::BindingArray { base, size }
2869 }
2870 ast::Type::RayDesc => {
2871 return Ok(ctx.module.generate_ray_desc_type());
2872 }
2873 ast::Type::RayIntersection => {
2874 return Ok(ctx.module.generate_ray_intersection_type());
2875 }
2876 ast::Type::User(ref ident) => {
2877 return match ctx.globals.get(ident.name) {
2878 Some(&LoweredGlobalDecl::Type(handle)) => Ok(handle),
2879 Some(_) => Err(Error::Unexpected(ident.span, ExpectedToken::Type)),
2880 None => Err(Error::UnknownType(ident.span)),
2881 }
2882 }
2883 };
2884
2885 Ok(ctx.ensure_type_exists(name, inner))
2886 }
2887
2888 fn resolve_ast_type(
2890 &mut self,
2891 handle: Handle<ast::Type<'source>>,
2892 ctx: &mut GlobalContext<'source, '_, '_>,
2893 ) -> Result<Handle<crate::Type>, Error<'source>> {
2894 self.resolve_named_ast_type(handle, None, ctx)
2895 }
2896
2897 fn binding(
2898 &mut self,
2899 binding: &Option<ast::Binding<'source>>,
2900 ty: Handle<crate::Type>,
2901 ctx: &mut GlobalContext<'source, '_, '_>,
2902 ) -> Result<Option<crate::Binding>, Error<'source>> {
2903 Ok(match *binding {
2904 Some(ast::Binding::BuiltIn(b)) => Some(crate::Binding::BuiltIn(b)),
2905 Some(ast::Binding::Location {
2906 location,
2907 second_blend_source,
2908 interpolation,
2909 sampling,
2910 }) => {
2911 let mut binding = crate::Binding::Location {
2912 location: self.const_u32(location, &mut ctx.as_const())?.0,
2913 second_blend_source,
2914 interpolation,
2915 sampling,
2916 };
2917 binding.apply_default_interpolation(&ctx.module.types[ty].inner);
2918 Some(binding)
2919 }
2920 None => None,
2921 })
2922 }
2923
2924 fn ray_query_pointer(
2925 &mut self,
2926 expr: Handle<ast::Expression<'source>>,
2927 ctx: &mut ExpressionContext<'source, '_, '_>,
2928 ) -> Result<Handle<crate::Expression>, Error<'source>> {
2929 let span = ctx.ast_expressions.get_span(expr);
2930 let pointer = self.expression(expr, ctx)?;
2931
2932 match *resolve_inner!(ctx, pointer) {
2933 crate::TypeInner::Pointer { base, .. } => match ctx.module.types[base].inner {
2934 crate::TypeInner::RayQuery => Ok(pointer),
2935 ref other => {
2936 log::error!("Pointer type to {:?} passed to ray query op", other);
2937 Err(Error::InvalidRayQueryPointer(span))
2938 }
2939 },
2940 ref other => {
2941 log::error!("Type {:?} passed to ray query op", other);
2942 Err(Error::InvalidRayQueryPointer(span))
2943 }
2944 }
2945 }
2946}
2947
2948impl crate::AtomicFunction {
2949 pub fn map(word: &str) -> Option<Self> {
2950 Some(match word {
2951 "atomicAdd" => crate::AtomicFunction::Add,
2952 "atomicSub" => crate::AtomicFunction::Subtract,
2953 "atomicAnd" => crate::AtomicFunction::And,
2954 "atomicOr" => crate::AtomicFunction::InclusiveOr,
2955 "atomicXor" => crate::AtomicFunction::ExclusiveOr,
2956 "atomicMin" => crate::AtomicFunction::Min,
2957 "atomicMax" => crate::AtomicFunction::Max,
2958 "atomicExchange" => crate::AtomicFunction::Exchange { compare: None },
2959 _ => return None,
2960 })
2961 }
2962}