1use alloc::{
2 format,
3 string::{String, ToString},
4 vec,
5 vec::Vec,
6};
7use core::iter;
8
9use super::{
10 ast::*,
11 builtins::{inject_builtin, sampled_to_depth},
12 context::{Context, ExprPos, StmtContext},
13 error::{Error, ErrorKind},
14 types::scalar_components,
15 Frontend, Result,
16};
17use crate::{
18 front::glsl::types::type_power, proc::ensure_block_returns, AddressSpace, Block, EntryPoint,
19 Expression, Function, FunctionArgument, FunctionResult, Handle, Literal, LocalVariable, Scalar,
20 ScalarKind, Span, Statement, StructMember, Type, TypeInner,
21};
22
23struct ProxyWrite {
25 target: Handle<Expression>,
27 value: Handle<Expression>,
29 convert: Option<Scalar>,
31}
32
33impl Frontend {
34 pub(crate) fn function_or_constructor_call(
35 &mut self,
36 ctx: &mut Context,
37 stmt: &StmtContext,
38 fc: FunctionCallKind,
39 raw_args: &[Handle<HirExpr>],
40 meta: Span,
41 ) -> Result<Option<Handle<Expression>>> {
42 let args: Vec<_> = raw_args
43 .iter()
44 .map(|e| ctx.lower_expect_inner(stmt, self, *e, ExprPos::Rhs))
45 .collect::<Result<_>>()?;
46
47 match fc {
48 FunctionCallKind::TypeConstructor(ty) => {
49 if args.len() == 1 {
50 self.constructor_single(ctx, ty, args[0], meta).map(Some)
51 } else {
52 self.constructor_many(ctx, ty, args, meta).map(Some)
53 }
54 }
55 FunctionCallKind::Function(name) => {
56 self.function_call(ctx, stmt, name, args, raw_args, meta)
57 }
58 }
59 }
60
61 fn constructor_single(
62 &mut self,
63 ctx: &mut Context,
64 ty: Handle<Type>,
65 (mut value, expr_meta): (Handle<Expression>, Span),
66 meta: Span,
67 ) -> Result<Handle<Expression>> {
68 let expr_type = ctx.resolve_type(value, expr_meta)?;
69
70 let vector_size = match *expr_type {
71 TypeInner::Vector { size, .. } => Some(size),
72 _ => None,
73 };
74
75 let expr_is_bool = expr_type.scalar_kind() == Some(ScalarKind::Bool);
76
77 match ctx.module.types[ty].inner.scalar() {
79 Some(result_scalar) if expr_is_bool && result_scalar.kind != ScalarKind::Bool => {
80 let result_scalar = Scalar {
81 width: 4,
82 ..result_scalar
83 };
84 let l0 = Literal::zero(result_scalar).unwrap();
85 let l1 = Literal::one(result_scalar).unwrap();
86 let mut reject = ctx.add_expression(Expression::Literal(l0), expr_meta)?;
87 let mut accept = ctx.add_expression(Expression::Literal(l1), expr_meta)?;
88
89 ctx.implicit_splat(&mut reject, meta, vector_size)?;
90 ctx.implicit_splat(&mut accept, meta, vector_size)?;
91
92 let h = ctx.add_expression(
93 Expression::Select {
94 accept,
95 reject,
96 condition: value,
97 },
98 expr_meta,
99 )?;
100
101 return Ok(h);
102 }
103 _ => {}
104 }
105
106 Ok(match ctx.module.types[ty].inner {
107 TypeInner::Vector { size, scalar } if vector_size.is_none() => {
108 ctx.forced_conversion(&mut value, expr_meta, scalar)?;
109
110 if let TypeInner::Scalar { .. } = *ctx.resolve_type(value, expr_meta)? {
111 ctx.add_expression(Expression::Splat { size, value }, meta)?
112 } else {
113 self.vector_constructor(ctx, ty, size, scalar, &[(value, expr_meta)], meta)?
114 }
115 }
116 TypeInner::Scalar(scalar) => {
117 let mut expr = value;
118 if let TypeInner::Vector { .. } | TypeInner::Matrix { .. } =
119 *ctx.resolve_type(value, expr_meta)?
120 {
121 expr = ctx.add_expression(
122 Expression::AccessIndex {
123 base: expr,
124 index: 0,
125 },
126 meta,
127 )?;
128 }
129
130 if let TypeInner::Matrix { .. } = *ctx.resolve_type(value, expr_meta)? {
131 expr = ctx.add_expression(
132 Expression::AccessIndex {
133 base: expr,
134 index: 0,
135 },
136 meta,
137 )?;
138 }
139
140 ctx.add_expression(
141 Expression::As {
142 target: scalar,
143 expr,
144 },
145 meta,
146 )?
147 }
148 TypeInner::Vector { size, scalar } => {
149 if vector_size != Some(size) {
150 value = ctx.vector_resize(size, value, expr_meta)?;
151 }
152
153 ctx.add_expression(
154 Expression::As {
155 target: scalar,
156 expr: value,
157 },
158 meta,
159 )?
160 }
161 TypeInner::Matrix {
162 columns,
163 rows,
164 scalar,
165 } => self.matrix_one_arg(ctx, ty, columns, rows, scalar, (value, expr_meta), meta)?,
166 TypeInner::Struct { ref members, .. } => {
167 let scalar_components = members
168 .first()
169 .and_then(|member| scalar_components(&ctx.module.types[member.ty].inner));
170 if let Some(scalar) = scalar_components {
171 ctx.implicit_conversion(&mut value, expr_meta, scalar)?;
172 }
173
174 ctx.add_expression(
175 Expression::Compose {
176 ty,
177 components: vec![value],
178 },
179 meta,
180 )?
181 }
182
183 TypeInner::Array { base, .. } => {
184 let scalar_components = scalar_components(&ctx.module.types[base].inner);
185 if let Some(scalar) = scalar_components {
186 ctx.implicit_conversion(&mut value, expr_meta, scalar)?;
187 }
188
189 ctx.add_expression(
190 Expression::Compose {
191 ty,
192 components: vec![value],
193 },
194 meta,
195 )?
196 }
197 _ => {
198 self.errors.push(Error {
199 kind: ErrorKind::SemanticError("Bad type constructor".into()),
200 meta,
201 });
202
203 value
204 }
205 })
206 }
207
208 #[allow(clippy::too_many_arguments)]
209 fn matrix_one_arg(
210 &mut self,
211 ctx: &mut Context,
212 ty: Handle<Type>,
213 columns: crate::VectorSize,
214 rows: crate::VectorSize,
215 element_scalar: Scalar,
216 (mut value, expr_meta): (Handle<Expression>, Span),
217 meta: Span,
218 ) -> Result<Handle<Expression>> {
219 let mut components = Vec::with_capacity(columns as usize);
220 ctx.forced_conversion(&mut value, expr_meta, element_scalar)?;
225 match *ctx.resolve_type(value, expr_meta)? {
226 TypeInner::Scalar(_) => {
227 let vector_ty = ctx.module.types.insert(
231 Type {
232 name: None,
233 inner: TypeInner::Vector {
234 size: rows,
235 scalar: element_scalar,
236 },
237 },
238 meta,
239 );
240
241 let zero_literal = Literal::zero(element_scalar).unwrap();
242 let zero = ctx.add_expression(Expression::Literal(zero_literal), meta)?;
243
244 for i in 0..columns as u32 {
245 components.push(
246 ctx.add_expression(
247 Expression::Compose {
248 ty: vector_ty,
249 components: (0..rows as u32)
250 .map(|r| match r == i {
251 true => value,
252 false => zero,
253 })
254 .collect(),
255 },
256 meta,
257 )?,
258 )
259 }
260 }
261 TypeInner::Matrix {
262 rows: ori_rows,
263 columns: ori_cols,
264 ..
265 } => {
266 let zero_literal = Literal::zero(element_scalar).unwrap();
272 let one_literal = Literal::one(element_scalar).unwrap();
273
274 let zero = ctx.add_expression(Expression::Literal(zero_literal), meta)?;
275 let one = ctx.add_expression(Expression::Literal(one_literal), meta)?;
276
277 let vector_ty = ctx.module.types.insert(
278 Type {
279 name: None,
280 inner: TypeInner::Vector {
281 size: rows,
282 scalar: element_scalar,
283 },
284 },
285 meta,
286 );
287
288 for i in 0..columns as u32 {
289 if i < ori_cols as u32 {
290 use core::cmp::Ordering;
291
292 let vector = ctx.add_expression(
293 Expression::AccessIndex {
294 base: value,
295 index: i,
296 },
297 meta,
298 )?;
299
300 components.push(match ori_rows.cmp(&rows) {
301 Ordering::Less => {
302 let components = (0..rows as u32)
303 .map(|r| {
304 if r < ori_rows as u32 {
305 ctx.add_expression(
306 Expression::AccessIndex {
307 base: vector,
308 index: r,
309 },
310 meta,
311 )
312 } else if r == i {
313 Ok(one)
314 } else {
315 Ok(zero)
316 }
317 })
318 .collect::<Result<_>>()?;
319
320 ctx.add_expression(
321 Expression::Compose {
322 ty: vector_ty,
323 components,
324 },
325 meta,
326 )?
327 }
328 Ordering::Equal => vector,
329 Ordering::Greater => ctx.vector_resize(rows, vector, meta)?,
330 })
331 } else {
332 let compose_expr = Expression::Compose {
333 ty: vector_ty,
334 components: (0..rows as u32)
335 .map(|r| match r == i {
336 true => one,
337 false => zero,
338 })
339 .collect(),
340 };
341
342 let vec = ctx.add_expression(compose_expr, meta)?;
343
344 components.push(vec)
345 }
346 }
347 }
348 _ => {
349 components = iter::repeat_n(value, columns as usize).collect();
350 }
351 }
352
353 ctx.add_expression(Expression::Compose { ty, components }, meta)
354 }
355
356 fn vector_constructor(
357 &mut self,
358 ctx: &mut Context,
359 ty: Handle<Type>,
360 size: crate::VectorSize,
361 scalar: Scalar,
362 args: &[(Handle<Expression>, Span)],
363 meta: Span,
364 ) -> Result<Handle<Expression>> {
365 let mut components = Vec::with_capacity(size as usize);
366
367 for (mut arg, expr_meta) in args.iter().copied() {
368 ctx.forced_conversion(&mut arg, expr_meta, scalar)?;
369
370 if components.len() >= size as usize {
371 break;
372 }
373
374 match *ctx.resolve_type(arg, expr_meta)? {
375 TypeInner::Scalar { .. } => components.push(arg),
376 TypeInner::Matrix { rows, columns, .. } => {
377 components.reserve(rows as usize * columns as usize);
378 for c in 0..(columns as u32) {
379 let base = ctx.add_expression(
380 Expression::AccessIndex {
381 base: arg,
382 index: c,
383 },
384 expr_meta,
385 )?;
386 for r in 0..(rows as u32) {
387 components.push(ctx.add_expression(
388 Expression::AccessIndex { base, index: r },
389 expr_meta,
390 )?)
391 }
392 }
393 }
394 TypeInner::Vector { size: ori_size, .. } => {
395 components.reserve(ori_size as usize);
396 for index in 0..(ori_size as u32) {
397 components.push(ctx.add_expression(
398 Expression::AccessIndex { base: arg, index },
399 expr_meta,
400 )?)
401 }
402 }
403 _ => components.push(arg),
404 }
405 }
406
407 components.truncate(size as usize);
408
409 ctx.add_expression(Expression::Compose { ty, components }, meta)
410 }
411
412 fn constructor_many(
413 &mut self,
414 ctx: &mut Context,
415 ty: Handle<Type>,
416 args: Vec<(Handle<Expression>, Span)>,
417 meta: Span,
418 ) -> Result<Handle<Expression>> {
419 let mut components = Vec::with_capacity(args.len());
420
421 let struct_member_data = match ctx.module.types[ty].inner {
422 TypeInner::Matrix {
423 columns,
424 rows,
425 scalar: element_scalar,
426 } => {
427 let mut flattened = Vec::with_capacity(columns as usize * rows as usize);
428
429 for (mut arg, meta) in args.iter().copied() {
430 ctx.forced_conversion(&mut arg, meta, element_scalar)?;
431
432 match *ctx.resolve_type(arg, meta)? {
433 TypeInner::Vector { size, .. } => {
434 for i in 0..(size as u32) {
435 flattened.push(ctx.add_expression(
436 Expression::AccessIndex {
437 base: arg,
438 index: i,
439 },
440 meta,
441 )?)
442 }
443 }
444 _ => flattened.push(arg),
445 }
446 }
447
448 let ty = ctx.module.types.insert(
449 Type {
450 name: None,
451 inner: TypeInner::Vector {
452 size: rows,
453 scalar: element_scalar,
454 },
455 },
456 meta,
457 );
458
459 for chunk in flattened.chunks(rows as usize) {
460 components.push(ctx.add_expression(
461 Expression::Compose {
462 ty,
463 components: Vec::from(chunk),
464 },
465 meta,
466 )?)
467 }
468 None
469 }
470 TypeInner::Vector { size, scalar } => {
471 return self.vector_constructor(ctx, ty, size, scalar, &args, meta)
472 }
473 TypeInner::Array { base, .. } => {
474 for (mut arg, meta) in args.iter().copied() {
475 let scalar_components = scalar_components(&ctx.module.types[base].inner);
476 if let Some(scalar) = scalar_components {
477 ctx.implicit_conversion(&mut arg, meta, scalar)?;
478 }
479
480 components.push(arg)
481 }
482 None
483 }
484 TypeInner::Struct { ref members, .. } => Some(
485 members
486 .iter()
487 .map(|member| scalar_components(&ctx.module.types[member.ty].inner))
488 .collect::<Vec<_>>(),
489 ),
490 _ => {
491 return Err(Error {
492 kind: ErrorKind::SemanticError("Constructor: Too many arguments".into()),
493 meta,
494 })
495 }
496 };
497
498 if let Some(struct_member_data) = struct_member_data {
499 for ((mut arg, meta), scalar_components) in
500 args.iter().copied().zip(struct_member_data.iter().copied())
501 {
502 if let Some(scalar) = scalar_components {
503 ctx.implicit_conversion(&mut arg, meta, scalar)?;
504 }
505
506 components.push(arg)
507 }
508 }
509
510 ctx.add_expression(Expression::Compose { ty, components }, meta)
511 }
512
513 fn function_call(
514 &mut self,
515 ctx: &mut Context,
516 stmt: &StmtContext,
517 name: String,
518 args: Vec<(Handle<Expression>, Span)>,
519 raw_args: &[Handle<HirExpr>],
520 meta: Span,
521 ) -> Result<Option<Handle<Expression>>> {
522 for &(expr, span) in args.iter() {
525 ctx.typifier_grow(expr, span)?;
526 }
527
528 let mut variations =
530 builtin_required_variations(args.iter().map(|&(expr, _)| ctx.get_type(expr)));
531
532 let declaration = self.lookup_function.entry(name.clone()).or_insert_with(|| {
534 variations |= BuiltinVariations::STANDARD;
535 Default::default()
536 });
537 inject_builtin(declaration, ctx.module, &name, variations);
538
539 let declaration = self.lookup_function.get(&name).unwrap();
541
542 let mut maybe_overload = None;
544 let mut old_conversions = vec![Conversion::None; args.len()];
547 let mut ambiguous = false;
549
550 'outer: for (overload_idx, overload) in declaration.overloads.iter().enumerate() {
553 if args.len() != overload.parameters.len() {
556 continue;
557 }
558
559 log::trace!("Testing overload {overload_idx}");
560
561 let mut exact = true;
563 let mut superior = None;
568 let mut new_conversions = vec![Conversion::None; args.len()];
571
572 for (i, overload_parameter) in overload.parameters.iter().enumerate() {
575 let call_argument = &args[i];
576 let parameter_info = &overload.parameters_info[i];
577
578 if parameter_info.depth {
581 sampled_to_depth(ctx, call_argument.0, call_argument.1, &mut self.errors);
582 ctx.invalidate_expression(call_argument.0, call_argument.1)?
583 }
584
585 ctx.typifier_grow(call_argument.0, call_argument.1)?;
586
587 let overload_param_ty = &ctx.module.types[*overload_parameter].inner;
588 let call_arg_ty = ctx.get_type(call_argument.0);
589
590 log::trace!(
591 "Testing parameter {i}\n\tOverload = {overload_param_ty:?}\n\tCall = {call_arg_ty:?}"
592 );
593
594 if let (
598 &TypeInner::Image {
599 class:
600 crate::ImageClass::Storage {
601 format: overload_format,
602 access: overload_access,
603 },
604 dim: overload_dim,
605 arrayed: overload_arrayed,
606 },
607 &TypeInner::Image {
608 class:
609 crate::ImageClass::Storage {
610 format: call_format,
611 access: call_access,
612 },
613 dim: call_dim,
614 arrayed: call_arrayed,
615 },
616 ) = (overload_param_ty, call_arg_ty)
617 {
618 let good_size = call_dim == overload_dim && call_arrayed == overload_arrayed;
620 let good_format = overload_format == call_format
624 || (overload.internal
625 && Scalar::from(overload_format) == Scalar::from(call_format));
626 if !(good_size && good_format) {
627 continue 'outer;
628 }
629
630 if !call_access.contains(overload_access) {
634 self.errors.push(Error {
635 kind: ErrorKind::SemanticError(
636 format!(
637 "'{name}': image needs {overload_access:?} access but only {call_access:?} was provided"
638 )
639 .into(),
640 ),
641 meta,
642 });
643 }
644
645 new_conversions[i] = Conversion::Exact;
647 continue;
648 } else if overload_param_ty == call_arg_ty {
649 new_conversions[i] = Conversion::Exact;
651 continue;
652 }
653
654 if let ParameterQualifier::InOut = parameter_info.qualifier {
660 continue 'outer;
661 }
662
663 let maybe_conversion = if parameter_info.qualifier.is_lhs() {
674 conversion(call_arg_ty, overload_param_ty)
675 } else {
676 conversion(overload_param_ty, call_arg_ty)
677 };
678
679 let conversion = match maybe_conversion {
680 Some(info) => info,
681 None => continue 'outer,
682 };
683
684 exact = false;
687
688 let best_arg = match (conversion, old_conversions[i]) {
693 (_, Conversion::Exact) => false,
696 (_, Conversion::None) => true,
698 (Conversion::FloatToDouble, _) => true,
700 (_, Conversion::FloatToDouble) => false,
701 (Conversion::IntToFloat, Conversion::IntToDouble) => true,
704 (Conversion::IntToDouble, Conversion::IntToFloat) => false,
705 _ => continue,
708 };
709
710 match best_arg {
713 true => match superior {
714 Some(false) => ambiguous = true,
715 _ => {
716 superior = Some(true);
717 new_conversions[i] = conversion
718 }
719 },
720 false => match superior {
721 Some(true) => ambiguous = true,
722 _ => superior = Some(false),
723 },
724 }
725 }
726
727 if exact {
731 maybe_overload = Some(overload);
732 ambiguous = false;
733 break;
734 }
735
736 match superior {
737 Some(true) => {
739 maybe_overload = Some(overload);
740 old_conversions = new_conversions;
742 }
743 Some(false) => {}
745 None => {
749 ambiguous = true;
750 maybe_overload = Some(overload);
754 }
755 }
756 }
757
758 if ambiguous {
759 self.errors.push(Error {
760 kind: ErrorKind::SemanticError(
761 format!("Ambiguous best function for '{name}'").into(),
762 ),
763 meta,
764 })
765 }
766
767 let overload = maybe_overload.ok_or_else(|| Error {
768 kind: ErrorKind::SemanticError(format!("Unknown function '{name}'").into()),
769 meta,
770 })?;
771
772 let parameters_info = overload.parameters_info.clone();
773 let parameters = overload.parameters.clone();
774 let is_void = overload.void;
775 let kind = overload.kind;
776
777 let mut arguments = Vec::with_capacity(args.len());
778 let mut proxy_writes = Vec::new();
779
780 for (((parameter_info, call_argument), expr), parameter) in parameters_info
782 .iter()
783 .zip(&args)
784 .zip(raw_args)
785 .zip(¶meters)
786 {
787 if parameter_info.qualifier.is_lhs() {
788 let (handle, meta) = ctx.lower_expect_inner(stmt, self, *expr, ExprPos::Lhs)?;
790
791 self.process_lhs_argument(
792 ctx,
793 meta,
794 *parameter,
795 parameter_info,
796 handle,
797 call_argument,
798 &mut proxy_writes,
799 &mut arguments,
800 )?;
801
802 continue;
803 }
804
805 let (mut handle, meta) = *call_argument;
806
807 let scalar_comps = scalar_components(&ctx.module.types[*parameter].inner);
808
809 if let Some(scalar) = scalar_comps {
811 ctx.implicit_conversion(&mut handle, meta, scalar)?;
812 }
813
814 arguments.push(handle)
815 }
816
817 match kind {
818 FunctionKind::Call(function) => {
819 ctx.emit_end();
820
821 let result = if !is_void {
822 Some(ctx.add_expression(Expression::CallResult(function), meta)?)
823 } else {
824 None
825 };
826
827 ctx.body.push(
828 Statement::Call {
829 function,
830 arguments,
831 result,
832 },
833 meta,
834 );
835
836 ctx.emit_start();
837
838 for proxy_write in proxy_writes {
840 let mut value = ctx.add_expression(
841 Expression::Load {
842 pointer: proxy_write.value,
843 },
844 meta,
845 )?;
846
847 if let Some(scalar) = proxy_write.convert {
848 ctx.conversion(&mut value, meta, scalar)?;
849 }
850
851 ctx.emit_restart();
852
853 ctx.body.push(
854 Statement::Store {
855 pointer: proxy_write.target,
856 value,
857 },
858 meta,
859 );
860 }
861
862 Ok(result)
863 }
864 FunctionKind::Macro(builtin) => builtin.call(self, ctx, arguments.as_mut_slice(), meta),
865 }
866 }
867
868 #[allow(clippy::too_many_arguments)]
871 fn process_lhs_argument(
872 &mut self,
873 ctx: &mut Context,
874 meta: Span,
875 parameter_ty: Handle<Type>,
876 parameter_info: &ParameterInfo,
877 original: Handle<Expression>,
878 call_argument: &(Handle<Expression>, Span),
879 proxy_writes: &mut Vec<ProxyWrite>,
880 arguments: &mut Vec<Handle<Expression>>,
881 ) -> Result<()> {
882 let original_ty = ctx.resolve_type(original, meta)?;
883 let original_pointer_space = original_ty.pointer_space();
884
885 let mut maybe_ty = match *original_ty {
887 TypeInner::Vector { size, scalar } => Some(ctx.module.types.insert(
891 Type {
892 name: None,
893 inner: TypeInner::Vector { size, scalar },
894 },
895 Span::default(),
896 )),
897 TypeInner::Pointer { base, space } if space != AddressSpace::Function => Some(base),
901 TypeInner::ValuePointer {
902 size,
903 scalar,
904 space,
905 } if space != AddressSpace::Function => {
906 let inner = match size {
907 Some(size) => TypeInner::Vector { size, scalar },
908 None => TypeInner::Scalar(scalar),
909 };
910
911 Some(
912 ctx.module
913 .types
914 .insert(Type { name: None, inner }, Span::default()),
915 )
916 }
917 _ => None,
918 };
919
920 let value = if original_pointer_space.is_some() {
923 ctx.add_expression(Expression::Load { pointer: original }, Span::default())?
924 } else {
925 original
926 };
927
928 ctx.typifier_grow(call_argument.0, call_argument.1)?;
929
930 let overload_param_ty = &ctx.module.types[parameter_ty].inner;
931 let call_arg_ty = ctx.get_type(call_argument.0);
932 let needs_conversion = call_arg_ty != overload_param_ty;
933
934 let arg_scalar_comps = scalar_components(call_arg_ty);
935
936 if needs_conversion {
940 maybe_ty = Some(parameter_ty);
941 }
942
943 if let Some(ty) = maybe_ty {
944 let spill_var = ctx.locals.append(
946 LocalVariable {
947 name: None,
948 ty,
949 init: None,
950 },
951 Span::default(),
952 );
953 let spill_expr =
954 ctx.add_expression(Expression::LocalVariable(spill_var), Span::default())?;
955
956 if let ParameterQualifier::InOut = parameter_info.qualifier {
959 ctx.body.push(
960 Statement::Store {
961 pointer: spill_expr,
962 value,
963 },
964 Span::default(),
965 );
966 }
967
968 arguments.push(spill_expr);
970
971 let convert = if needs_conversion {
972 arg_scalar_comps
973 } else {
974 None
975 };
976
977 if let Expression::Swizzle {
980 size,
981 mut vector,
982 pattern,
983 } = ctx.expressions[original]
984 {
985 if let Expression::Load { pointer } = ctx.expressions[vector] {
986 vector = pointer;
987 }
988
989 for (i, component) in pattern.iter().take(size as usize).enumerate() {
990 let original = ctx.add_expression(
991 Expression::AccessIndex {
992 base: vector,
993 index: *component as u32,
994 },
995 Span::default(),
996 )?;
997
998 let spill_component = ctx.add_expression(
999 Expression::AccessIndex {
1000 base: spill_expr,
1001 index: i as u32,
1002 },
1003 Span::default(),
1004 )?;
1005
1006 proxy_writes.push(ProxyWrite {
1007 target: original,
1008 value: spill_component,
1009 convert,
1010 });
1011 }
1012 } else {
1013 proxy_writes.push(ProxyWrite {
1014 target: original,
1015 value: spill_expr,
1016 convert,
1017 });
1018 }
1019 } else {
1020 arguments.push(original);
1021 }
1022
1023 Ok(())
1024 }
1025
1026 pub(crate) fn add_function(
1027 &mut self,
1028 mut ctx: Context,
1029 name: String,
1030 result: Option<FunctionResult>,
1031 meta: Span,
1032 ) {
1033 ensure_block_returns(&mut ctx.body);
1034
1035 let void = result.is_none();
1036
1037 let mut variations = builtin_required_variations(
1039 ctx.parameters
1040 .iter()
1041 .map(|&arg| &ctx.module.types[arg].inner),
1042 );
1043
1044 let declaration = self.lookup_function.entry(name.clone()).or_insert_with(|| {
1046 variations |= BuiltinVariations::STANDARD;
1047 Default::default()
1048 });
1049 inject_builtin(declaration, ctx.module, &name, variations);
1050
1051 let Context {
1052 expressions,
1053 locals,
1054 arguments,
1055 parameters,
1056 parameters_info,
1057 body,
1058 module,
1059 ..
1060 } = ctx;
1061
1062 let function = Function {
1063 name: Some(name),
1064 arguments,
1065 result,
1066 local_variables: locals,
1067 expressions,
1068 named_expressions: crate::NamedExpressions::default(),
1069 body,
1070 diagnostic_filter_leaf: None,
1071 };
1072
1073 'outer: for decl in declaration.overloads.iter_mut() {
1074 if parameters.len() != decl.parameters.len() {
1075 continue;
1076 }
1077
1078 for (new_parameter, old_parameter) in parameters.iter().zip(decl.parameters.iter()) {
1079 let new_inner = &module.types[*new_parameter].inner;
1080 let old_inner = &module.types[*old_parameter].inner;
1081
1082 if new_inner != old_inner {
1083 continue 'outer;
1084 }
1085 }
1086
1087 if decl.defined {
1088 return self.errors.push(Error {
1089 kind: ErrorKind::SemanticError("Function already defined".into()),
1090 meta,
1091 });
1092 }
1093
1094 decl.defined = true;
1095 decl.parameters_info = parameters_info;
1096 match decl.kind {
1097 FunctionKind::Call(handle) => *module.functions.get_mut(handle) = function,
1098 FunctionKind::Macro(_) => {
1099 let handle = module.functions.append(function, meta);
1100 decl.kind = FunctionKind::Call(handle)
1101 }
1102 }
1103 return;
1104 }
1105
1106 let handle = module.functions.append(function, meta);
1107 declaration.overloads.push(Overload {
1108 parameters,
1109 parameters_info,
1110 kind: FunctionKind::Call(handle),
1111 defined: true,
1112 internal: false,
1113 void,
1114 });
1115 }
1116
1117 pub(crate) fn add_prototype(
1118 &mut self,
1119 ctx: Context,
1120 name: String,
1121 result: Option<FunctionResult>,
1122 meta: Span,
1123 ) {
1124 let void = result.is_none();
1125
1126 let mut variations = builtin_required_variations(
1128 ctx.parameters
1129 .iter()
1130 .map(|&arg| &ctx.module.types[arg].inner),
1131 );
1132
1133 let declaration = self.lookup_function.entry(name.clone()).or_insert_with(|| {
1135 variations |= BuiltinVariations::STANDARD;
1136 Default::default()
1137 });
1138 inject_builtin(declaration, ctx.module, &name, variations);
1139
1140 let Context {
1141 arguments,
1142 parameters,
1143 parameters_info,
1144 module,
1145 ..
1146 } = ctx;
1147
1148 let function = Function {
1149 name: Some(name),
1150 arguments,
1151 result,
1152 ..Default::default()
1153 };
1154
1155 'outer: for decl in declaration.overloads.iter() {
1156 if parameters.len() != decl.parameters.len() {
1157 continue;
1158 }
1159
1160 for (new_parameter, old_parameter) in parameters.iter().zip(decl.parameters.iter()) {
1161 let new_inner = &module.types[*new_parameter].inner;
1162 let old_inner = &module.types[*old_parameter].inner;
1163
1164 if new_inner != old_inner {
1165 continue 'outer;
1166 }
1167 }
1168
1169 return self.errors.push(Error {
1170 kind: ErrorKind::SemanticError("Prototype already defined".into()),
1171 meta,
1172 });
1173 }
1174
1175 let handle = module.functions.append(function, meta);
1176 declaration.overloads.push(Overload {
1177 parameters,
1178 parameters_info,
1179 kind: FunctionKind::Call(handle),
1180 defined: false,
1181 internal: false,
1182 void,
1183 });
1184 }
1185
1186 pub(crate) fn add_entry_point(
1217 &mut self,
1218 function: Handle<Function>,
1219 mut ctx: Context,
1220 ) -> Result<()> {
1221 let mut arguments = Vec::new();
1222
1223 let body = Block::with_capacity(
1224 ctx.body.len() +
1226 self.entry_args.len() * 2
1228 + 3,
1230 );
1231
1232 let global_init_body = core::mem::replace(&mut ctx.body, body);
1233
1234 for arg in self.entry_args.iter() {
1235 if arg.storage != StorageQualifier::Input {
1236 continue;
1237 }
1238
1239 let pointer = ctx
1240 .expressions
1241 .append(Expression::GlobalVariable(arg.handle), Default::default());
1242 ctx.local_expression_kind_tracker
1243 .insert(pointer, crate::proc::ExpressionKind::Runtime);
1244
1245 let ty = ctx.module.global_variables[arg.handle].ty;
1246
1247 ctx.arg_type_walker(
1248 arg.name.clone(),
1249 arg.binding.clone(),
1250 pointer,
1251 ty,
1252 &mut |ctx, name, pointer, ty, binding| {
1253 let idx = arguments.len() as u32;
1254
1255 arguments.push(FunctionArgument {
1256 name,
1257 ty,
1258 binding: Some(binding),
1259 });
1260
1261 let value = ctx
1262 .expressions
1263 .append(Expression::FunctionArgument(idx), Default::default());
1264 ctx.local_expression_kind_tracker
1265 .insert(value, crate::proc::ExpressionKind::Runtime);
1266 ctx.body
1267 .push(Statement::Store { pointer, value }, Default::default());
1268 },
1269 )?
1270 }
1271
1272 ctx.body.extend_block(global_init_body);
1273
1274 ctx.body.push(
1275 Statement::Call {
1276 function,
1277 arguments: Vec::new(),
1278 result: None,
1279 },
1280 Default::default(),
1281 );
1282
1283 let mut span = 0;
1284 let mut members = Vec::new();
1285 let mut components = Vec::new();
1286
1287 for arg in self.entry_args.iter() {
1288 if arg.storage != StorageQualifier::Output {
1289 continue;
1290 }
1291
1292 let pointer = ctx
1293 .expressions
1294 .append(Expression::GlobalVariable(arg.handle), Default::default());
1295 ctx.local_expression_kind_tracker
1296 .insert(pointer, crate::proc::ExpressionKind::Runtime);
1297
1298 let ty = ctx.module.global_variables[arg.handle].ty;
1299
1300 ctx.arg_type_walker(
1301 arg.name.clone(),
1302 arg.binding.clone(),
1303 pointer,
1304 ty,
1305 &mut |ctx, name, pointer, ty, binding| {
1306 members.push(StructMember {
1307 name,
1308 ty,
1309 binding: Some(binding),
1310 offset: span,
1311 });
1312
1313 span += ctx.module.types[ty].inner.size(ctx.module.to_ctx());
1314
1315 let len = ctx.expressions.len();
1316 let load = ctx
1317 .expressions
1318 .append(Expression::Load { pointer }, Default::default());
1319 ctx.local_expression_kind_tracker
1320 .insert(load, crate::proc::ExpressionKind::Runtime);
1321 ctx.body.push(
1322 Statement::Emit(ctx.expressions.range_from(len)),
1323 Default::default(),
1324 );
1325 components.push(load)
1326 },
1327 )?
1328 }
1329
1330 let (ty, value) = if !components.is_empty() {
1331 let ty = ctx.module.types.insert(
1332 Type {
1333 name: None,
1334 inner: TypeInner::Struct { members, span },
1335 },
1336 Default::default(),
1337 );
1338
1339 let len = ctx.expressions.len();
1340 let res = ctx
1341 .expressions
1342 .append(Expression::Compose { ty, components }, Default::default());
1343 ctx.local_expression_kind_tracker
1344 .insert(res, crate::proc::ExpressionKind::Runtime);
1345 ctx.body.push(
1346 Statement::Emit(ctx.expressions.range_from(len)),
1347 Default::default(),
1348 );
1349
1350 (Some(ty), Some(res))
1351 } else {
1352 (None, None)
1353 };
1354
1355 ctx.body
1356 .push(Statement::Return { value }, Default::default());
1357
1358 let Context {
1359 body, expressions, ..
1360 } = ctx;
1361
1362 ctx.module.entry_points.push(EntryPoint {
1363 name: "main".to_string(),
1364 stage: self.meta.stage,
1365 early_depth_test: self
1366 .meta
1367 .early_fragment_tests
1368 .then_some(crate::EarlyDepthTest::Force),
1369 workgroup_size: self.meta.workgroup_size,
1370 workgroup_size_overrides: None,
1371 function: Function {
1372 arguments,
1373 expressions,
1374 body,
1375 result: ty.map(|ty| FunctionResult { ty, binding: None }),
1376 ..Default::default()
1377 },
1378 mesh_info: None,
1379 task_payload: None,
1380 incoming_ray_payload: None,
1381 });
1382
1383 Ok(())
1384 }
1385}
1386
1387impl Context<'_> {
1388 fn arg_type_walker(
1400 &mut self,
1401 name: Option<String>,
1402 binding: crate::Binding,
1403 pointer: Handle<Expression>,
1404 ty: Handle<Type>,
1405 f: &mut impl FnMut(
1406 &mut Context,
1407 Option<String>,
1408 Handle<Expression>,
1409 Handle<Type>,
1410 crate::Binding,
1411 ),
1412 ) -> Result<()> {
1413 match self.module.types[ty].inner {
1414 TypeInner::Array {
1418 base,
1419 size: crate::ArraySize::Constant(size),
1420 ..
1421 } => {
1422 let location = match binding {
1423 crate::Binding::Location { location, .. } => location,
1424 crate::Binding::BuiltIn(_) => return Ok(()),
1425 };
1426
1427 let interpolation =
1428 self.module.types[base]
1429 .inner
1430 .scalar_kind()
1431 .map(|kind| match kind {
1432 ScalarKind::Float => crate::Interpolation::Perspective,
1433 _ => crate::Interpolation::Flat,
1434 });
1435
1436 for index in 0..size.get() {
1437 let member_pointer = self.add_expression(
1438 Expression::AccessIndex {
1439 base: pointer,
1440 index,
1441 },
1442 Span::default(),
1443 )?;
1444
1445 let binding = crate::Binding::Location {
1446 location: location + index,
1447 interpolation,
1448 sampling: None,
1449 blend_src: None,
1450 per_primitive: false,
1451 };
1452
1453 self.arg_type_walker(name.clone(), binding, member_pointer, base, f)?
1454 }
1455 }
1456 TypeInner::Struct { ref members, .. } => {
1457 let mut location = match binding {
1458 crate::Binding::Location { location, .. } => location,
1459 crate::Binding::BuiltIn(_) => return Ok(()),
1460 };
1461
1462 for (i, member) in members.clone().into_iter().enumerate() {
1463 let member_pointer = self.add_expression(
1464 Expression::AccessIndex {
1465 base: pointer,
1466 index: i as u32,
1467 },
1468 Span::default(),
1469 )?;
1470
1471 let binding = match member.binding {
1472 Some(binding) => binding,
1473 None => {
1474 let interpolation = self.module.types[member.ty]
1475 .inner
1476 .scalar_kind()
1477 .map(|kind| match kind {
1478 ScalarKind::Float => crate::Interpolation::Perspective,
1479 _ => crate::Interpolation::Flat,
1480 });
1481 let binding = crate::Binding::Location {
1482 location,
1483 interpolation,
1484 sampling: None,
1485 blend_src: None,
1486 per_primitive: false,
1487 };
1488 location += 1;
1489 binding
1490 }
1491 };
1492
1493 self.arg_type_walker(member.name, binding, member_pointer, member.ty, f)?
1494 }
1495 }
1496 _ => f(self, name, pointer, ty, binding),
1497 }
1498
1499 Ok(())
1500 }
1501}
1502
1503#[derive(PartialEq, Eq, Clone, Copy, Debug)]
1505enum Conversion {
1506 Exact,
1508 FloatToDouble,
1510 IntToFloat,
1512 IntToDouble,
1514 Other,
1516 None,
1518}
1519
1520fn conversion(target: &TypeInner, source: &TypeInner) -> Option<Conversion> {
1523 use ScalarKind::*;
1524
1525 let (target_scalar, source_scalar) = match (target, source) {
1527 (&TypeInner::Scalar(tgt_scalar), &TypeInner::Scalar(src_scalar)) => {
1529 (tgt_scalar, src_scalar)
1530 }
1531 (
1533 &TypeInner::Vector {
1534 size: tgt_size,
1535 scalar: tgt_scalar,
1536 },
1537 &TypeInner::Vector {
1538 size: src_size,
1539 scalar: src_scalar,
1540 },
1541 ) if tgt_size == src_size => (tgt_scalar, src_scalar),
1542 (
1544 &TypeInner::Matrix {
1545 rows: tgt_rows,
1546 columns: tgt_cols,
1547 scalar: tgt_scalar,
1548 },
1549 &TypeInner::Matrix {
1550 rows: src_rows,
1551 columns: src_cols,
1552 scalar: src_scalar,
1553 },
1554 ) if tgt_cols == src_cols && tgt_rows == src_rows => (tgt_scalar, src_scalar),
1555 _ => return None,
1556 };
1557
1558 let target_power = type_power(target_scalar);
1561 let source_power = type_power(source_scalar);
1562 if target_power < source_power {
1563 return None;
1564 }
1565
1566 Some(match (target_scalar, source_scalar) {
1567 (Scalar::F64, Scalar::F32) => Conversion::FloatToDouble,
1569 (
1571 Scalar::F32,
1572 Scalar {
1573 kind: Sint | Uint,
1574 width: _,
1575 },
1576 ) => Conversion::IntToFloat,
1577 (
1579 Scalar::F64,
1580 Scalar {
1581 kind: Sint | Uint,
1582 width: _,
1583 },
1584 ) => Conversion::IntToDouble,
1585 _ => Conversion::Other,
1586 })
1587}
1588
1589fn builtin_required_variations<'a>(args: impl Iterator<Item = &'a TypeInner>) -> BuiltinVariations {
1592 let mut variations = BuiltinVariations::empty();
1593
1594 for ty in args {
1595 match *ty {
1596 TypeInner::ValuePointer { scalar, .. }
1597 | TypeInner::Scalar(scalar)
1598 | TypeInner::Vector { scalar, .. }
1599 | TypeInner::Matrix { scalar, .. }
1600 if scalar == Scalar::F64 =>
1601 {
1602 variations |= BuiltinVariations::DOUBLE
1603 }
1604 TypeInner::Image {
1605 dim,
1606 arrayed,
1607 class,
1608 } => {
1609 if dim == crate::ImageDimension::Cube && arrayed {
1610 variations |= BuiltinVariations::CUBE_TEXTURES_ARRAY
1611 }
1612
1613 if dim == crate::ImageDimension::D2 && arrayed && class.is_multisampled() {
1614 variations |= BuiltinVariations::D2_MULTI_TEXTURES_ARRAY
1615 }
1616 }
1617 _ => {}
1618 }
1619 }
1620
1621 variations
1622}