1#![allow(non_snake_case)]
18
19use itertools::{Itertools, chain, izip};
20use num_traits::{One, ToBytes, ToPrimitive, Zero, real::Real};
21
22use crate::{
23 Error, Instance, ShaderStage,
24 conv::{Convert, convert, convert_all_ty},
25 f16,
26 inst::{
27 AtomicInstance, LiteralInstance, MatInstance, RefInstance, StructInstance, VecInstance,
28 },
29 ty::{Ty, Type},
30};
31
32use super::{Compwise, atomic_compare_exchange_struct_type, frexp_struct_type};
33
34type E = Error;
35
36pub fn bitcast_t(tplt_ty: &Type, e: &Instance) -> Result<Instance, E> {
47 fn lit_bytes(l: &LiteralInstance) -> Result<Vec<u8>, E> {
48 match l {
49 LiteralInstance::Bool(_) => Err(E::Builtin("bitcast argument cannot be bool")),
50 LiteralInstance::AbstractInt(_) => Err(E::Unreachable), LiteralInstance::AbstractFloat(_) => Err(E::Unreachable),
52 LiteralInstance::I32(n) => Ok(n.to_le_bytes().to_vec()),
53 LiteralInstance::U32(n) => Ok(n.to_le_bytes().to_vec()),
54 LiteralInstance::F32(n) => Ok(n.to_le_bytes().to_vec()),
55 LiteralInstance::F16(n) => Ok(n.to_le_bytes().to_vec()),
56 #[cfg(feature = "naga-ext")]
57 LiteralInstance::I64(n) => Ok(n.to_le_bytes().to_vec()),
58 #[cfg(feature = "naga-ext")]
59 LiteralInstance::U64(n) => Ok(n.to_le_bytes().to_vec()),
60 #[cfg(feature = "naga-ext")]
61 LiteralInstance::F64(n) => Ok(n.to_le_bytes().to_vec()),
62 }
63 }
64
65 fn vec_bytes(v: &VecInstance) -> Result<Vec<u8>, E> {
66 v.iter()
67 .map(|n| lit_bytes(n.unwrap_literal_ref()))
68 .reduce(|n1, n2| Ok(chain(n1?, n2?).collect_vec()))
69 .unwrap()
70 }
71
72 let inner_ty = tplt_ty.inner_ty();
73
74 let e = match inner_ty {
75 Type::U32 if e.inner_ty().is_abstract_int() => e.convert_inner_to(&Type::U32),
78 _ => e.concretize(),
79 };
80
81 let bytes = match e {
82 Some(Instance::Literal(l)) => lit_bytes(&l),
83 Some(Instance::Vec(v)) => vec_bytes(&v),
84 _ => Err(E::Builtin(
85 "`bitcast` expects a numeric scalar or vector argument",
86 )),
87 }?;
88
89 let size_err = E::Builtin("`bitcast` input and output types must have the same size");
90
91 match tplt_ty {
92 Type::I32 => {
93 let n = i32::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
94 Ok(LiteralInstance::I32(n).into())
95 }
96 Type::U32 => {
97 let n = u32::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
98 Ok(LiteralInstance::U32(n).into())
99 }
100 Type::F32 => {
101 let n = f32::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
102 Ok(LiteralInstance::F32(n).into())
103 }
104 Type::F16 => {
105 let n = f16::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
106 Ok(LiteralInstance::F16(n).into())
107 }
108 Type::Vec(n, ty) => {
109 if **ty == Type::I32 && bytes.len() == 4 * (*n as usize) {
110 let v = bytes
111 .chunks(4)
112 .map(|b| i32::from_le_bytes(b.try_into().unwrap()))
113 .map(|n| LiteralInstance::from(n).into())
114 .collect_vec();
115 Ok(VecInstance::new(v).into())
116 } else if **ty == Type::U32 && bytes.len() == 4 * (*n as usize) {
117 let v = bytes
118 .chunks(4)
119 .map(|b| u32::from_le_bytes(b.try_into().unwrap()))
120 .map(|n| LiteralInstance::from(n).into())
121 .collect_vec();
122 Ok(VecInstance::new(v).into())
123 } else if **ty == Type::F32 && bytes.len() == 4 * (*n as usize) {
124 let v = bytes
125 .chunks(4)
126 .map(|b| f32::from_le_bytes(b.try_into().unwrap()))
127 .map(|n| LiteralInstance::from(n).into())
128 .collect_vec();
129 Ok(VecInstance::new(v).into())
130 } else if **ty == Type::F16 && bytes.len() == 2 * (*n as usize) {
131 let v = bytes
132 .chunks(2)
133 .map(|b| f16::from_le_bytes(b.try_into().unwrap()))
134 .map(|n| LiteralInstance::from(n).into())
135 .collect_vec();
136 Ok(VecInstance::new(v).into())
137 } else {
138 #[cfg(feature = "naga-ext")]
139 if matches!(**ty, Type::I64 | Type::U64 | Type::F64) {
140 return Err(E::Todo("`bitcast` with 64-bit type".to_string()));
141 }
142 Err(size_err)
143 }
144 }
145 #[cfg(feature = "naga-ext")]
146 Type::I64 | Type::U64 | Type::F64 => Err(E::Todo("`bitcast` with 64-bit type".to_string())),
147 _ => Err(E::Builtin("invalid `bitcast` template")),
148 }
149}
150
151pub fn all(e: &Instance) -> Result<Instance, E> {
160 match e {
161 Instance::Literal(LiteralInstance::Bool(_)) => Ok(e.clone()),
162 Instance::Vec(v) if v.inner_ty() == Type::Bool => {
163 let b = v.iter().all(|b| b.unwrap_literal_ref().unwrap_bool());
164 Ok(LiteralInstance::Bool(b).into())
165 }
166 _ => Err(E::Builtin(
167 "`all` expects a boolean or vector of boolean argument",
168 )),
169 }
170}
171
172pub fn any(e: &Instance) -> Result<Instance, E> {
176 match e {
177 Instance::Literal(LiteralInstance::Bool(_)) => Ok(e.clone()),
178 Instance::Vec(v) if v.inner_ty() == Type::Bool => {
179 let b = v.iter().any(|b| b.unwrap_literal_ref().unwrap_bool());
180 Ok(LiteralInstance::Bool(b).into())
181 }
182 _ => Err(E::Builtin(
183 "`any` expects a boolean or vector of boolean argument",
184 )),
185 }
186}
187
188pub fn select(f: &Instance, t: &Instance, cond: &Instance) -> Result<Instance, E> {
192 let (f, t) = convert(f, t).ok_or(E::Builtin(
193 "`select` 1st and 2nd arguments are incompatible",
194 ))?;
195
196 match cond {
197 Instance::Literal(LiteralInstance::Bool(b)) => Ok(b.then_some(t).unwrap_or(f)),
198 Instance::Vec(v) if v.inner_ty() == Type::Bool => match (f, t) {
199 (Instance::Vec(v1), Instance::Vec(v2)) => {
200 if v1.n() != v.n() {
201 Err(E::Builtin(
202 "`select` vector arguments must have the same number of components",
203 ))
204 } else {
205 let v = izip!(v1, v2, v.iter())
206 .map(|(f, t, b)| {
207 if b.unwrap_literal_ref().unwrap_bool() {
208 t.to_owned() } else {
210 f.to_owned()
211 }
212 })
213 .collect_vec();
214 Ok(VecInstance::new(v).into())
215 }
216 }
217 _ => Err(E::Builtin(
218 "`select` arguments must be vectors when the condition is a vector",
219 )),
220 },
221 _ => Err(E::Builtin(
222 "`select` 3rd argument must be a boolean or vector of boolean",
223 )),
224 }
225}
226
227pub fn arrayLength(p: &Instance) -> Result<Instance, E> {
236 let err = E::Builtin("`arrayLength` expects a pointer to array argument");
237 let r = match p {
238 Instance::Ptr(p) => RefInstance::from(p.clone()),
239 _ => return Err(err),
240 };
241 let r = r.read()?;
242 match &*r {
243 Instance::Array(a) => Ok(LiteralInstance::U32(a.n() as u32).into()),
244 _ => Err(err),
245 }
246}
247
248macro_rules! impl_call_float_unary {
254 ($name:literal, $e:ident, $n:ident => $expr:expr) => {{
255 const ERR: E = E::Builtin(concat!(
256 "`",
257 $name,
258 "` expects a float or vector of float argument"
259 ));
260 fn lit_fn(l: &LiteralInstance) -> Result<LiteralInstance, E> {
261 match l {
262 LiteralInstance::Bool(_) => Err(ERR),
263 LiteralInstance::AbstractInt(_) => {
264 let $n = l
265 .convert_to(&Type::AbstractFloat)
266 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
267 .unwrap_abstract_float();
268 Ok(LiteralInstance::from($expr))
269 }
270 LiteralInstance::AbstractFloat($n) => Ok(LiteralInstance::from($expr)),
271 LiteralInstance::I32(_) => Err(ERR),
272 LiteralInstance::U32(_) => Err(ERR),
273 LiteralInstance::F32($n) => Ok(LiteralInstance::from($expr)),
274 LiteralInstance::F16($n) => Ok(LiteralInstance::from($expr)),
275 #[cfg(feature = "naga-ext")]
276 LiteralInstance::I64(_) => Err(ERR),
277 #[cfg(feature = "naga-ext")]
278 LiteralInstance::U64(_) => Err(ERR),
279 #[cfg(feature = "naga-ext")]
280 LiteralInstance::F64($n) => Ok(LiteralInstance::F64($expr)),
281 }
282 }
283 match $e {
284 Instance::Literal(l) => lit_fn(l).map(Into::into),
285 Instance::Vec(v) => v.compwise_unary(lit_fn).map(Into::into),
286 _ => Err(ERR),
287 }
288 }};
289}
290
291pub fn abs(e: &Instance) -> Result<Instance, E> {
296 const ERR: E = E::Builtin("`abs` expects a scalar or vector of scalar argument");
297 fn lit_abs(l: &LiteralInstance) -> Result<LiteralInstance, E> {
298 match l {
299 LiteralInstance::Bool(_) => Err(ERR),
300 LiteralInstance::AbstractInt(n) => Ok(LiteralInstance::from(n.wrapping_abs())),
301 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(n.abs())),
302 LiteralInstance::I32(n) => Ok(LiteralInstance::from(n.wrapping_abs())),
303 LiteralInstance::U32(_) => Ok(*l),
304 LiteralInstance::F32(n) => Ok(LiteralInstance::from(n.abs())),
305 LiteralInstance::F16(n) => Ok(LiteralInstance::from(n.abs())),
306 #[cfg(feature = "naga-ext")]
307 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.wrapping_abs())),
308 #[cfg(feature = "naga-ext")]
309 LiteralInstance::U64(_) => Ok(*l),
310 #[cfg(feature = "naga-ext")]
311 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(n.abs())),
312 }
313 }
314 match e {
315 Instance::Literal(l) => lit_abs(l).map(Into::into),
316 Instance::Vec(v) => v.compwise_unary(lit_abs).map(Into::into),
317 _ => Err(ERR),
318 }
319}
320
321pub fn acos(e: &Instance) -> Result<Instance, E> {
327 impl_call_float_unary!("acos", e, n => n.acos())
328}
329
330pub fn acosh(e: &Instance) -> Result<Instance, E> {
336 impl_call_float_unary!("acosh", e, n => n.acosh())
339}
340
341pub fn asin(e: &Instance) -> Result<Instance, E> {
347 impl_call_float_unary!("asin", e, n => n.asin())
348}
349
350pub fn asinh(e: &Instance) -> Result<Instance, E> {
354 impl_call_float_unary!("asinh", e, n => n.asinh())
357}
358
359pub fn atan(e: &Instance) -> Result<Instance, E> {
363 impl_call_float_unary!("atan", e, n => n.atan())
364}
365
366pub fn atanh(e: &Instance) -> Result<Instance, E> {
372 impl_call_float_unary!("atanh", e, n => n.atanh())
373}
374
375pub fn atan2(y: &Instance, x: &Instance) -> Result<Instance, E> {
379 const ERR: E = E::Builtin("`atan2` expects a float or vector of float argument");
380 fn lit_atan2(y: &LiteralInstance, x: &LiteralInstance) -> Result<LiteralInstance, E> {
381 match y {
382 LiteralInstance::Bool(_) => Err(ERR),
383 LiteralInstance::AbstractInt(_) => {
384 let y = y
385 .convert_to(&Type::AbstractFloat)
386 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?;
387 let x = x
388 .convert_to(&Type::AbstractFloat)
389 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?;
390 Ok(LiteralInstance::from(
391 y.unwrap_abstract_float().atan2(x.unwrap_abstract_float()),
392 ))
393 }
394 LiteralInstance::AbstractFloat(y) => {
395 Ok(LiteralInstance::from(y.atan2(x.unwrap_abstract_float())))
396 }
397 LiteralInstance::I32(_) => Err(ERR),
398 LiteralInstance::U32(_) => Err(ERR),
399 LiteralInstance::F32(y) => Ok(LiteralInstance::from(y.atan2(x.unwrap_f32()))),
400 LiteralInstance::F16(y) => Ok(LiteralInstance::from(y.atan2(x.unwrap_f16()))),
401 #[cfg(feature = "naga-ext")]
402 LiteralInstance::I64(_) => Err(ERR),
403 #[cfg(feature = "naga-ext")]
404 LiteralInstance::U64(_) => Err(ERR),
405 #[cfg(feature = "naga-ext")]
406 LiteralInstance::F64(y) => Ok(LiteralInstance::F64(y.atan2(x.unwrap_f64()))),
407 }
408 }
409 let (y, x) = convert(y, x).ok_or(E::Builtin("`atan2` arguments are incompatible"))?;
410 match (y, x) {
411 (Instance::Literal(y), Instance::Literal(x)) => lit_atan2(&y, &x).map(Into::into),
412 (Instance::Vec(y), Instance::Vec(x)) => y.compwise_binary(&x, lit_atan2).map(Into::into),
413 _ => Err(ERR),
414 }
415}
416
417pub fn ceil(e: &Instance) -> Result<Instance, E> {
421 impl_call_float_unary!("ceil", e, n => n.ceil())
422}
423
424pub fn clamp(e: &Instance, low: &Instance, high: &Instance) -> Result<Instance, E> {
428 const ERR: E = E::Builtin("`clamp` arguments are incompatible");
429 let tys = [e.ty(), low.ty(), high.ty()];
430 let ty = convert_all_ty(&tys).ok_or(ERR)?;
431 let e = e.convert_to(ty).ok_or(ERR)?;
432 let low = low.convert_to(ty).ok_or(ERR)?;
433 let high = high.convert_to(ty).ok_or(ERR)?;
434 min(&max(&e, &low)?, &high)
435}
436
437pub fn cos(e: &Instance) -> Result<Instance, E> {
443 impl_call_float_unary!("cos", e, n => n.cos())
444}
445
446pub fn cosh(e: &Instance) -> Result<Instance, E> {
450 impl_call_float_unary!("cosh", e, n => n.cosh())
451}
452
453pub fn countLeadingZeros(e: &Instance) -> Result<Instance, E> {
457 const ERR: E = E::Builtin("`countLeadingZeros` expects an integer scalar or vector argument");
458 fn lit_leading_zeros(l: &LiteralInstance) -> Result<LiteralInstance, E> {
459 match l {
460 LiteralInstance::Bool(_) => Err(ERR),
461 LiteralInstance::AbstractInt(_) => Err(E::Unreachable), LiteralInstance::AbstractFloat(_) => Err(E::Unreachable),
463 LiteralInstance::I32(n) => Ok(LiteralInstance::I32(n.leading_zeros() as i32)),
464 LiteralInstance::U32(n) => Ok(LiteralInstance::U32(n.leading_zeros())),
465 LiteralInstance::F32(_) => Err(ERR),
466 LiteralInstance::F16(_) => Err(ERR),
467 #[cfg(feature = "naga-ext")]
468 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.leading_zeros() as i64)),
469 #[cfg(feature = "naga-ext")]
470 LiteralInstance::U64(n) => Ok(LiteralInstance::U64(n.leading_zeros() as u64)),
471 #[cfg(feature = "naga-ext")]
472 LiteralInstance::F64(_) => Err(ERR),
473 }
474 }
475 match e.concretize() {
476 Some(Instance::Literal(l)) => lit_leading_zeros(&l).map(Into::into),
477 Some(Instance::Vec(v)) => v.compwise_unary(lit_leading_zeros).map(Into::into),
478 _ => Err(ERR),
479 }
480}
481
482pub fn countOneBits(e: &Instance) -> Result<Instance, E> {
486 const ERR: E = E::Builtin("`countOneBits` expects an integer scalar or vector argument");
487 fn lit_count_ones(l: &LiteralInstance) -> Result<LiteralInstance, E> {
488 match l {
489 LiteralInstance::Bool(_) => Err(ERR),
490 LiteralInstance::AbstractInt(_) => Err(E::Unreachable), LiteralInstance::AbstractFloat(_) => Err(E::Unreachable),
492 LiteralInstance::I32(n) => Ok(LiteralInstance::I32(n.count_ones() as i32)),
493 LiteralInstance::U32(n) => Ok(LiteralInstance::U32(n.count_ones())),
494 LiteralInstance::F32(_) => Err(ERR),
495 LiteralInstance::F16(_) => Err(ERR),
496 #[cfg(feature = "naga-ext")]
497 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.count_ones() as i64)),
498 #[cfg(feature = "naga-ext")]
499 LiteralInstance::U64(n) => Ok(LiteralInstance::U64(n.count_ones() as u64)),
500 #[cfg(feature = "naga-ext")]
501 LiteralInstance::F64(_) => Err(ERR),
502 }
503 }
504 match e.concretize() {
505 Some(Instance::Literal(l)) => lit_count_ones(&l).map(Into::into),
506 Some(Instance::Vec(v)) => v.compwise_unary(lit_count_ones).map(Into::into),
507 _ => Err(ERR),
508 }
509}
510
511pub fn countTrailingZeros(e: &Instance) -> Result<Instance, E> {
515 const ERR: E = E::Builtin("`countTrailingZeros` expects an integer scalar or vector argument");
516 fn lit_trailing_zeros(l: &LiteralInstance) -> Result<LiteralInstance, E> {
517 match l {
518 LiteralInstance::Bool(_) => Err(ERR),
519 LiteralInstance::AbstractInt(_) => Err(E::Unreachable), LiteralInstance::AbstractFloat(_) => Err(E::Unreachable),
521 LiteralInstance::I32(n) => Ok(LiteralInstance::I32(n.trailing_zeros() as i32)),
522 LiteralInstance::U32(n) => Ok(LiteralInstance::U32(n.trailing_zeros())),
523 LiteralInstance::F32(_) => Err(ERR),
524 LiteralInstance::F16(_) => Err(ERR),
525 #[cfg(feature = "naga-ext")]
526 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.trailing_zeros() as i64)),
527 #[cfg(feature = "naga-ext")]
528 LiteralInstance::U64(n) => Ok(LiteralInstance::U64(n.trailing_zeros() as u64)),
529 #[cfg(feature = "naga-ext")]
530 LiteralInstance::F64(_) => Err(ERR),
531 }
532 }
533 match e.concretize() {
534 Some(Instance::Literal(l)) => lit_trailing_zeros(&l).map(Into::into),
535 Some(Instance::Vec(v)) => v.compwise_unary(lit_trailing_zeros).map(Into::into),
536 _ => Err(ERR),
537 }
538}
539
540pub fn cross(a: &Instance, b: &Instance, stage: ShaderStage) -> Result<Instance, E> {
544 let (a, b) = convert(a, b).ok_or(E::Builtin("`cross` arguments are incompatible"))?;
545 match (a, b) {
546 (Instance::Vec(a), Instance::Vec(b)) if a.n() == 3 => {
547 let s1 = a[1]
548 .op_mul(&b[2], stage)?
549 .op_sub(&a[2].op_mul(&b[1], stage)?, stage)?;
550 let s2 = a[2]
551 .op_mul(&b[0], stage)?
552 .op_sub(&a[0].op_mul(&b[2], stage)?, stage)?;
553 let s3 = a[0]
554 .op_mul(&b[1], stage)?
555 .op_sub(&a[1].op_mul(&b[0], stage)?, stage)?;
556 Ok(VecInstance::new(vec![s1, s2, s3]).into())
557 }
558 _ => Err(E::Builtin(
559 "`cross` expects a 3-component vector of float arguments",
560 )),
561 }
562}
563
564pub fn degrees(e: &Instance) -> Result<Instance, E> {
568 impl_call_float_unary!("degrees", e, n => n.to_degrees())
569}
570
571pub fn determinant(_a1: &Instance) -> Result<Instance, E> {
573 Err(E::Todo("determinant".to_string()))
574}
575
576pub fn distance(e1: &Instance, e2: &Instance, stage: ShaderStage) -> Result<Instance, E> {
582 length(&e1.op_sub(e2, stage)?)
583}
584
585pub fn dot(e1: &Instance, e2: &Instance, stage: ShaderStage) -> Result<Instance, E> {
589 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`dot` arguments are incompatible"))?;
590 match (e1, e2) {
591 (Instance::Vec(e1), Instance::Vec(e2)) => e1.dot(&e2, stage).map(Into::into),
592 _ => Err(E::Builtin("`dot` expects vector arguments")),
593 }
594}
595
596pub fn dot4U8Packed(_a1: &Instance, _a2: &Instance) -> Result<Instance, E> {
598 Err(E::Todo("dot4U8Packed".to_string()))
599}
600
601pub fn dot4I8Packed(_a1: &Instance, _a2: &Instance) -> Result<Instance, E> {
603 Err(E::Todo("dot4I8Packed".to_string()))
604}
605
606pub fn exp(e: &Instance) -> Result<Instance, E> {
610 impl_call_float_unary!("exp", e, n => n.exp())
611}
612
613pub fn exp2(e: &Instance) -> Result<Instance, E> {
617 impl_call_float_unary!("exp2", e, n => n.exp2())
618}
619
620pub fn extractBits(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
622 Err(E::Todo("extractBits".to_string()))
623}
624
625pub fn faceForward(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
627 Err(E::Todo("faceForward".to_string()))
628}
629
630pub fn firstLeadingBit(_a1: &Instance) -> Result<Instance, E> {
632 Err(E::Todo("firstLeadingBit".to_string()))
633}
634
635pub fn firstTrailingBit(_a1: &Instance) -> Result<Instance, E> {
637 Err(E::Todo("firstTrailingBit".to_string()))
638}
639
640pub fn floor(e: &Instance) -> Result<Instance, E> {
644 impl_call_float_unary!("floor", e, n => n.floor())
645}
646
647pub fn fma(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
649 Err(E::Todo("fma".to_string()))
650}
651
652pub fn fract(e: &Instance, stage: ShaderStage) -> Result<Instance, E> {
656 e.op_sub(&floor(e)?, stage)
657 }
659
660pub fn frexp(e: &Instance) -> Result<Instance, E> {
666 const ERR: E = E::Builtin("`frexp` expects a float or vector of float argument");
667 fn make_frexp_inst(fract: Instance, exp: Instance) -> Instance {
668 Instance::Struct(StructInstance::new(
669 frexp_struct_type(&fract.ty()).unwrap(),
670 vec![fract, exp],
671 ))
672 }
673 fn frexp(x: f64) -> (f64, i32) {
675 let mut y = x.to_bits();
676 let ee = ((y >> 52) & 0x7ff) as i32;
677
678 if ee == 0 {
679 if x != 0.0 {
680 let x1p64 = f64::from_bits(0x43f0000000000000);
681 let (x, e) = frexp(x * x1p64);
682 return (x, e - 64);
683 }
684 return (x, 0);
685 } else if ee == 0x7ff {
686 return (x, 0);
687 }
688
689 let e = ee - 0x3fe;
690 y &= 0x800fffffffffffff;
691 y |= 0x3fe0000000000000;
692 (f64::from_bits(y), e)
693 }
694 match e {
695 Instance::Literal(l) => match l {
696 LiteralInstance::Bool(_) => Err(E::Todo("frexp with bool input".to_string())),
697 LiteralInstance::AbstractInt(_) => {
698 Err(E::Todo("frexp with AbstractInt input".to_string()))
699 }
700 LiteralInstance::AbstractFloat(n) => {
701 let (fract, exp) = frexp(*n);
702 Ok(make_frexp_inst(
703 LiteralInstance::AbstractFloat(fract).into(),
704 LiteralInstance::AbstractInt(exp as i64).into(),
705 ))
706 }
707 LiteralInstance::I32(_) => Err(E::Todo("frexp with i32 input".to_string())),
708 LiteralInstance::U32(_) => Err(E::Todo("frexp with u32 input".to_string())),
709 LiteralInstance::F32(n) => {
710 let (fract, exp) = frexp(*n as f64);
711 Ok(make_frexp_inst(
712 LiteralInstance::F32(fract as f32).into(),
713 LiteralInstance::I32(exp).into(),
714 ))
715 }
716 LiteralInstance::F16(n) => {
717 let (fract, exp) = frexp(n.to_f64().unwrap());
718 Ok(make_frexp_inst(
719 LiteralInstance::F16(f16::from_f64(fract)).into(),
720 LiteralInstance::I32(exp).into(),
721 ))
722 }
723 #[cfg(feature = "naga-ext")]
724 LiteralInstance::I64(_) => Err(E::Todo("frexp with i64 input".to_string())),
725 #[cfg(feature = "naga-ext")]
726 LiteralInstance::U64(_) => Err(E::Todo("frexp with u64 input".to_string())),
727 #[cfg(feature = "naga-ext")]
728 LiteralInstance::F64(n) => {
729 let (fract, exp) = frexp(*n);
730 Ok(make_frexp_inst(
731 LiteralInstance::F64(fract).into(),
732 LiteralInstance::I64(exp as i64).into(),
733 ))
734 }
735 },
736 Instance::Vec(v) => {
737 let ty = v.inner_ty();
738 let (fracts, exps): (Vec<_>, Vec<_>) = v
739 .iter()
740 .map(|l| match l.unwrap_literal_ref() {
741 LiteralInstance::AbstractFloat(n) => Ok(*n),
742 LiteralInstance::F32(n) => Ok(*n as f64),
743 LiteralInstance::F16(n) => {
744 Ok(n.to_f64().unwrap())
745 }
746 _ => Err(ERR),
747 })
748 .collect::<Result<Vec<_>, _>>()?
749 .into_iter()
750 .map(frexp)
751 .unzip();
752 let fracts = fracts
753 .into_iter()
754 .map(|n| match ty {
755 Type::AbstractFloat => LiteralInstance::AbstractFloat(n).into(),
756 Type::F32 => LiteralInstance::F32(n as f32).into(),
757 Type::F16 => LiteralInstance::F16(f16::from_f64(n)).into(),
758 _ => unreachable!("case handled above"),
759 })
760 .collect_vec();
761 let exps = exps
762 .into_iter()
763 .map(|n| match ty {
764 Type::AbstractFloat => LiteralInstance::AbstractInt(n as i64).into(),
765 Type::F32 => LiteralInstance::I32(n).into(),
766 Type::F16 => LiteralInstance::I32(n).into(),
767 _ => unreachable!("case handled above"),
768 })
769 .collect_vec();
770 let fract = VecInstance::new(fracts).into();
771 let exp = VecInstance::new(exps).into();
772 Ok(make_frexp_inst(fract, exp))
773 }
774 _ => Err(ERR),
775 }
776}
777
778pub fn insertBits(
780 _a1: &Instance,
781 _a2: &Instance,
782 _a3: &Instance,
783 _a4: &Instance,
784) -> Result<Instance, E> {
785 Err(E::Todo("insertBits".to_string()))
786}
787
788pub fn inverseSqrt(e: &Instance) -> Result<Instance, E> {
794 const ERR: E = E::Builtin("`inverseSqrt` expects a float or vector of float argument");
795 fn lit_isqrt(l: &LiteralInstance) -> Result<LiteralInstance, E> {
796 match l {
797 LiteralInstance::Bool(_) => Err(ERR),
798 LiteralInstance::AbstractInt(_) => l
799 .convert_to(&Type::AbstractFloat)
800 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))
801 .map(|n| LiteralInstance::from(1.0 / n.unwrap_abstract_float().sqrt())),
802 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(1.0 / n.sqrt())),
803 LiteralInstance::I32(_) => Err(ERR),
804 LiteralInstance::U32(_) => Err(ERR),
805 LiteralInstance::F32(n) => Ok(LiteralInstance::from(1.0 / n.sqrt())),
806 LiteralInstance::F16(n) => Ok(LiteralInstance::from(f16::one() / n.sqrt())),
807 #[cfg(feature = "naga-ext")]
808 LiteralInstance::I64(_) => Err(ERR),
809 #[cfg(feature = "naga-ext")]
810 LiteralInstance::U64(_) => Err(ERR),
811 #[cfg(feature = "naga-ext")]
812 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(1.0 / n.sqrt())),
813 }
814 }
815 match e {
816 Instance::Literal(l) => lit_isqrt(l).map(Into::into),
817 Instance::Vec(v) => v.compwise_unary(lit_isqrt).map(Into::into),
818 _ => Err(ERR),
819 }
820}
821
822pub fn ldexp(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
827 fn scalbn(x: f64, mut n: i32) -> f64 {
829 let x1p1023 = f64::from_bits(0x7fe0000000000000); let x1p53 = f64::from_bits(0x4340000000000000); let x1p_1022 = f64::from_bits(0x0010000000000000); let mut y = x;
834
835 if n > 1023 {
836 y *= x1p1023;
837 n -= 1023;
838 if n > 1023 {
839 y *= x1p1023;
840 n -= 1023;
841 if n > 1023 {
842 n = 1023;
843 }
844 }
845 } else if n < -1022 {
846 y *= x1p_1022 * x1p53;
849 n += 1022 - 53;
850 if n < -1022 {
851 y *= x1p_1022 * x1p53;
852 n += 1022 - 53;
853 if n < -1022 {
854 n = -1022;
855 }
856 }
857 }
858 y * f64::from_bits(((0x3ff + n) as u64) << 52)
859 }
860 fn ldexp_lit(l1: &LiteralInstance, l2: &LiteralInstance) -> Result<LiteralInstance, E> {
861 match (l1, l2) {
862 (LiteralInstance::AbstractInt(n1), LiteralInstance::AbstractInt(n2)) => Ok(
863 LiteralInstance::AbstractFloat(scalbn(n1.to_f64().unwrap(), n2.to_i32().unwrap())),
864 ),
865 (LiteralInstance::AbstractFloat(n1), LiteralInstance::AbstractInt(n2)) => Ok(
866 LiteralInstance::AbstractFloat(scalbn(*n1, n2.to_i32().unwrap())),
867 ),
868 (LiteralInstance::AbstractInt(n1), LiteralInstance::I32(n2)) => Ok(
869 LiteralInstance::F32(scalbn(n1.to_f64().unwrap(), *n2) as f32),
870 ),
871 (LiteralInstance::AbstractFloat(n1), LiteralInstance::I32(n2)) => Ok(
872 LiteralInstance::F32(scalbn(*n1, n2.to_i32().unwrap()) as f32),
873 ),
874 (LiteralInstance::F32(n1), LiteralInstance::AbstractInt(n2)) => Ok(
875 LiteralInstance::F32(scalbn(n1.to_f64().unwrap(), n2.to_i32().unwrap()) as f32),
876 ),
877 (LiteralInstance::F32(n1), LiteralInstance::I32(n2)) => Ok(LiteralInstance::F32(
878 scalbn(n1.to_f64().unwrap(), n2.to_i32().unwrap()) as f32,
879 )),
880 (LiteralInstance::F16(n1), LiteralInstance::AbstractInt(n2)) => {
881 Ok(LiteralInstance::F16(f16::from_f64(scalbn(
882 n1.to_f64().unwrap(),
883 n2.to_i32().unwrap(),
884 ))))
885 }
886 (LiteralInstance::F16(n1), LiteralInstance::I32(n2)) => Ok(LiteralInstance::F16(
887 f16::from_f64(scalbn(n1.to_f64().unwrap(), *n2)),
888 )),
889 _ => Err(E::Builtin(
890 "`ldexp` with scalar arguments expects a float and a i32 arguments",
891 )),
892 }
893 }
894
895 match (e1, e2) {
897 (Instance::Literal(l1), Instance::Literal(l2)) => ldexp_lit(l1, l2).map(Into::into),
898 (Instance::Vec(v1), Instance::Vec(v2)) => v1.compwise_binary(v2, ldexp_lit).map(Into::into),
899 _ => Err(E::Builtin(
900 "`ldexp` expects two scalar or two vector arguments",
901 )),
902 }
903}
904
905pub fn length(e: &Instance) -> Result<Instance, E> {
909 const ERR: E = E::Builtin("`length` expects a float or vector of float argument");
910 match e {
911 Instance::Literal(LiteralInstance::AbstractInt(_)) => {
912 abs(&e.convert_to(&Type::AbstractFloat).unwrap())
913 }
914 Instance::Literal(l) if l.ty().is_float() => abs(e),
915 Instance::Vec(v) => sqrt(
916 &v.op_mul(v, ShaderStage::Exec)?
917 .into_iter()
918 .map(Ok)
919 .reduce(|a, b| a?.op_add(&b?, ShaderStage::Exec))
920 .unwrap()?,
921 ),
922 _ => Err(ERR),
923 }
924}
925
926pub fn log(e: &Instance) -> Result<Instance, E> {
930 impl_call_float_unary!("log", e, n => n.ln())
931}
932
933pub fn log2(e: &Instance) -> Result<Instance, E> {
937 impl_call_float_unary!("log2", e, n => n.log2())
938}
939
940pub fn max(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
944 const ERR: E = E::Builtin("`max` expects a scalar or vector of scalar argument");
945 fn lit_max(e1: &LiteralInstance, e2: &LiteralInstance) -> Result<LiteralInstance, E> {
946 match e1 {
947 LiteralInstance::Bool(_) => Err(ERR),
948 LiteralInstance::AbstractInt(e1) => {
949 Ok(LiteralInstance::from(*e1.max(&e2.unwrap_abstract_int())))
950 }
951 LiteralInstance::AbstractFloat(e1) => {
952 Ok(LiteralInstance::from(e1.max(e2.unwrap_abstract_float())))
953 }
954 LiteralInstance::I32(e1) => Ok(LiteralInstance::from(*e1.max(&e2.unwrap_i32()))),
955 LiteralInstance::U32(e1) => Ok(LiteralInstance::from(*e1.max(&e2.unwrap_u32()))),
956 LiteralInstance::F32(e1) => Ok(LiteralInstance::from(e1.max(e2.unwrap_f32()))),
957 LiteralInstance::F16(e1) => Ok(LiteralInstance::from(e1.max(e2.unwrap_f16()))),
958 #[cfg(feature = "naga-ext")]
959 LiteralInstance::I64(e1) => Ok(LiteralInstance::I64(*e1.max(&e2.unwrap_i64()))),
960 #[cfg(feature = "naga-ext")]
961 LiteralInstance::U64(e1) => Ok(LiteralInstance::U64(*e1.max(&e2.unwrap_u64()))),
962 #[cfg(feature = "naga-ext")]
963 LiteralInstance::F64(e1) => Ok(LiteralInstance::F64(e1.max(e2.unwrap_f64()))),
964 }
965 }
966 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`max` arguments are incompatible"))?;
967 match (e1, e2) {
968 (Instance::Literal(e1), Instance::Literal(e2)) => lit_max(&e1, &e2).map(Into::into),
969 (Instance::Vec(e1), Instance::Vec(e2)) => e1.compwise_binary(&e2, lit_max).map(Into::into),
970 _ => Err(ERR),
971 }
972}
973
974pub fn min(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
978 const ERR: E = E::Builtin("`min` expects a scalar or vector of scalar argument");
979 fn lit_min(e1: &LiteralInstance, e2: &LiteralInstance) -> Result<LiteralInstance, E> {
980 match e1 {
981 LiteralInstance::Bool(_) => Err(ERR),
982 LiteralInstance::AbstractInt(e1) => {
983 Ok(LiteralInstance::from(*e1.min(&e2.unwrap_abstract_int())))
984 }
985 LiteralInstance::AbstractFloat(e1) => {
986 Ok(LiteralInstance::from(e1.min(e2.unwrap_abstract_float())))
987 }
988 LiteralInstance::I32(e1) => Ok(LiteralInstance::from(*e1.min(&e2.unwrap_i32()))),
989 LiteralInstance::U32(e1) => Ok(LiteralInstance::from(*e1.min(&e2.unwrap_u32()))),
990 LiteralInstance::F32(e1) => Ok(LiteralInstance::from(e1.min(e2.unwrap_f32()))),
991 LiteralInstance::F16(e1) => Ok(LiteralInstance::from(e1.min(e2.unwrap_f16()))),
992 #[cfg(feature = "naga-ext")]
993 LiteralInstance::I64(e1) => Ok(LiteralInstance::I64(*e1.min(&e2.unwrap_i64()))),
994 #[cfg(feature = "naga-ext")]
995 LiteralInstance::U64(e1) => Ok(LiteralInstance::U64(*e1.min(&e2.unwrap_u64()))),
996 #[cfg(feature = "naga-ext")]
997 LiteralInstance::F64(e1) => Ok(LiteralInstance::F64(e1.min(e2.unwrap_f64()))),
998 }
999 }
1000 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`min` arguments are incompatible"))?;
1001 match (e1, e2) {
1002 (Instance::Literal(e1), Instance::Literal(e2)) => lit_min(&e1, &e2).map(Into::into),
1003 (Instance::Vec(e1), Instance::Vec(e2)) => e1.compwise_binary(&e2, lit_min).map(Into::into),
1004 _ => Err(ERR),
1005 }
1006}
1007
1008pub fn mix(e1: &Instance, e2: &Instance, e3: &Instance, stage: ShaderStage) -> Result<Instance, E> {
1012 let tys = [e1.inner_ty(), e2.inner_ty(), e3.inner_ty()];
1013 let inner_ty = convert_all_ty(&tys).ok_or(E::Builtin("`mix` arguments are incompatible"))?;
1014 let e1 = e1.convert_inner_to(inner_ty).unwrap();
1015 let e2 = e2.convert_inner_to(inner_ty).unwrap();
1016 let e3 = e3.convert_inner_to(inner_ty).unwrap();
1017 let (e1, e2) = convert(&e1, &e2).ok_or(E::Builtin("`mix` arguments are incompatible"))?;
1018
1019 let one = Instance::Literal(LiteralInstance::AbstractInt(1));
1021
1022 e1.op_mul(&one.op_sub(&e3, stage)?, stage)?
1023 .op_add(&e2.op_mul(&e3, stage)?, stage)
1024}
1025
1026pub fn modf(_a1: &Instance) -> Result<Instance, E> {
1028 Err(E::Todo("modf".to_string()))
1029}
1030
1031pub fn normalize(e: &Instance, stage: ShaderStage) -> Result<Instance, E> {
1035 e.op_div(&length(e)?, stage)
1036}
1037
1038pub fn pow(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1042 const ERR: E = E::Builtin("`pow` expects a scalar or vector of scalar argument");
1043 fn lit_powf(e1: &LiteralInstance, e2: &LiteralInstance) -> Result<LiteralInstance, E> {
1044 match e1 {
1045 LiteralInstance::Bool(_) => Err(ERR),
1046 LiteralInstance::AbstractInt(_) => {
1047 let e1 = e1
1048 .convert_to(&Type::AbstractFloat)
1049 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1050 .unwrap_abstract_float();
1051 let e2 = e2
1052 .convert_to(&Type::AbstractFloat)
1053 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1054 .unwrap_abstract_float();
1055 Ok(LiteralInstance::from(e1.powf(e2)))
1056 }
1057 LiteralInstance::AbstractFloat(e1) => {
1058 Ok(LiteralInstance::from(e1.powf(e2.unwrap_abstract_float())))
1059 }
1060 LiteralInstance::I32(_) => Err(ERR),
1061 LiteralInstance::U32(_) => Err(ERR),
1062 LiteralInstance::F32(e1) => Ok(LiteralInstance::from(e1.powf(e2.unwrap_f32()))),
1063 LiteralInstance::F16(e1) => Ok(LiteralInstance::from(e1.powf(e2.unwrap_f16()))),
1064 #[cfg(feature = "naga-ext")]
1065 LiteralInstance::I64(_) => Err(ERR),
1066 #[cfg(feature = "naga-ext")]
1067 LiteralInstance::U64(_) => Err(ERR),
1068 #[cfg(feature = "naga-ext")]
1069 LiteralInstance::F64(e1) => Ok(LiteralInstance::F64(e1.powf(e2.unwrap_f64()))),
1070 }
1071 }
1072 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`pow` arguments are incompatible"))?;
1073 match (e1, e2) {
1074 (Instance::Literal(e1), Instance::Literal(e2)) => lit_powf(&e1, &e2).map(Into::into),
1075 (Instance::Vec(e1), Instance::Vec(e2)) => e1.compwise_binary(&e2, lit_powf).map(Into::into),
1076 _ => Err(ERR),
1077 }
1078}
1079
1080pub fn quantizeToF16(_a1: &Instance) -> Result<Instance, E> {
1082 Err(E::Todo("quantizeToF16".to_string()))
1083}
1084
1085pub fn radians(e: &Instance) -> Result<Instance, E> {
1089 impl_call_float_unary!("radians", e, n => n.to_radians())
1090}
1091
1092pub fn reflect(_a1: &Instance, _a2: &Instance) -> Result<Instance, E> {
1094 Err(E::Todo("reflect".to_string()))
1095}
1096
1097pub fn refract(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
1099 Err(E::Todo("refract".to_string()))
1100}
1101
1102pub fn reverseBits(_a1: &Instance) -> Result<Instance, E> {
1104 Err(E::Todo("reverseBits".to_string()))
1105}
1106
1107pub fn round(e: &Instance) -> Result<Instance, E> {
1111 const ERR: E = E::Builtin("`round` expects a float or vector of float argument");
1112 fn lit_fn(l: &LiteralInstance) -> Result<LiteralInstance, E> {
1113 match l {
1114 LiteralInstance::Bool(_) => Err(ERR),
1115 LiteralInstance::AbstractInt(_) => {
1116 let n = l
1117 .convert_to(&Type::AbstractFloat)
1118 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1119 .unwrap_abstract_float();
1120 Ok(LiteralInstance::from(n.round_ties_even()))
1121 }
1122 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(n.round_ties_even())),
1123 LiteralInstance::I32(_) => Err(ERR),
1124 LiteralInstance::U32(_) => Err(ERR),
1125 LiteralInstance::F32(n) => Ok(LiteralInstance::from(n.round_ties_even())),
1126 LiteralInstance::F16(n) => Ok(LiteralInstance::from(f16::from_f32(
1127 f16::to_f32(*n).round_ties_even(),
1128 ))),
1129 #[cfg(feature = "naga-ext")]
1130 LiteralInstance::I64(_) => Err(ERR),
1131 #[cfg(feature = "naga-ext")]
1132 LiteralInstance::U64(_) => Err(ERR),
1133 #[cfg(feature = "naga-ext")]
1134 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(n.round_ties_even())),
1135 }
1136 }
1137 match e {
1138 Instance::Literal(l) => lit_fn(l).map(Into::into),
1139 Instance::Vec(v) => v.compwise_unary(lit_fn).map(Into::into),
1140 _ => Err(ERR),
1141 }
1142}
1143
1144pub fn saturate(e: &Instance) -> Result<Instance, E> {
1148 match e {
1149 Instance::Literal(_) => {
1150 let zero = LiteralInstance::AbstractFloat(0.0);
1151 let one = LiteralInstance::AbstractFloat(1.0);
1152 clamp(e, &zero.into(), &one.into())
1153 }
1154 Instance::Vec(v) => {
1155 let n = v.n();
1156 let zero = Instance::from(LiteralInstance::AbstractFloat(0.0));
1157 let one = Instance::from(LiteralInstance::AbstractFloat(1.0));
1158 let zero = VecInstance::new((0..n).map(|_| zero.clone()).collect_vec());
1159 let one = VecInstance::new((0..n).map(|_| one.clone()).collect_vec());
1160 clamp(e, &zero.into(), &one.into())
1161 }
1162 _ => Err(E::Builtin(
1163 "`saturate` expects a float or vector of float argument",
1164 )),
1165 }
1166}
1167
1168pub fn sign(e: &Instance) -> Result<Instance, E> {
1172 const ERR: E = E::Builtin("`sign` expects a signed scalar or vector argument");
1173 fn lit_fn(l: &LiteralInstance) -> Result<LiteralInstance, E> {
1174 match l {
1175 LiteralInstance::Bool(_) => Err(ERR),
1176 LiteralInstance::AbstractInt(n) => Ok(LiteralInstance::from(n.signum())),
1177 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(if n.is_zero() {
1178 *n
1179 } else {
1180 n.signum()
1181 })),
1182 LiteralInstance::I32(n) => Ok(LiteralInstance::from(n.signum())),
1183 LiteralInstance::U32(_) => Err(ERR),
1184 LiteralInstance::F32(n) => Ok(LiteralInstance::from(if n.is_zero() {
1185 *n
1186 } else {
1187 n.signum()
1188 })),
1189 LiteralInstance::F16(n) => Ok(LiteralInstance::from(if n.is_zero() {
1190 *n
1191 } else {
1192 n.signum()
1193 })),
1194 #[cfg(feature = "naga-ext")]
1195 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.signum())),
1196 #[cfg(feature = "naga-ext")]
1197 LiteralInstance::U64(_) => Err(ERR),
1198 #[cfg(feature = "naga-ext")]
1199 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(if n.is_zero() {
1200 *n
1201 } else {
1202 n.signum()
1203 })),
1204 }
1205 }
1206 match e {
1207 Instance::Literal(l) => lit_fn(l).map(Into::into),
1208 Instance::Vec(v) => v.compwise_unary(lit_fn).map(Into::into),
1209 _ => Err(ERR),
1210 }
1211}
1212
1213pub fn sin(e: &Instance) -> Result<Instance, E> {
1217 impl_call_float_unary!("sin", e, n => n.sin())
1218}
1219
1220pub fn sinh(e: &Instance) -> Result<Instance, E> {
1224 impl_call_float_unary!("sinh", e, n => n.sinh())
1225}
1226
1227pub fn smoothstep(_low: &Instance, _high: &Instance, _x: &Instance) -> Result<Instance, E> {
1229 Err(E::Todo("smoothstep".to_string()))
1230}
1231
1232pub fn sqrt(e: &Instance) -> Result<Instance, E> {
1236 impl_call_float_unary!("sqrt", e, n => n.sqrt())
1237}
1238
1239pub fn step(edge: &Instance, x: &Instance) -> Result<Instance, E> {
1243 const ERR: E = E::Builtin("`step` expects a float or vector of float argument");
1244 fn lit_step(edge: &LiteralInstance, x: &LiteralInstance) -> Result<LiteralInstance, E> {
1245 match edge {
1246 LiteralInstance::Bool(_) => Err(ERR),
1247 LiteralInstance::AbstractInt(_) => {
1248 let edge = edge
1249 .convert_to(&Type::AbstractFloat)
1250 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1251 .unwrap_abstract_float();
1252 let x = x
1253 .convert_to(&Type::AbstractFloat)
1254 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1255 .unwrap_abstract_float();
1256 Ok(LiteralInstance::from(if edge <= x {
1257 1.0
1258 } else {
1259 0.0
1260 }))
1261 }
1262 LiteralInstance::AbstractFloat(edge) => Ok(LiteralInstance::from(
1263 if *edge <= x.unwrap_abstract_float() {
1264 1.0
1265 } else {
1266 0.0
1267 },
1268 )),
1269 LiteralInstance::I32(_) => Err(ERR),
1270 LiteralInstance::U32(_) => Err(ERR),
1271 LiteralInstance::F32(edge) => Ok(LiteralInstance::from(if *edge <= x.unwrap_f32() {
1272 1.0
1273 } else {
1274 0.0
1275 })),
1276 LiteralInstance::F16(edge) => Ok(LiteralInstance::from(if *edge <= x.unwrap_f16() {
1277 1.0
1278 } else {
1279 0.0
1280 })),
1281 #[cfg(feature = "naga-ext")]
1282 LiteralInstance::I64(_) => Err(ERR),
1283 #[cfg(feature = "naga-ext")]
1284 LiteralInstance::U64(_) => Err(ERR),
1285 #[cfg(feature = "naga-ext")]
1286 LiteralInstance::F64(edge) => Ok(LiteralInstance::F64(if *edge <= x.unwrap_f64() {
1287 1.0
1288 } else {
1289 0.0
1290 })),
1291 }
1292 }
1293 let (edge, x) = convert(edge, x).ok_or(E::Builtin("`step` arguments are incompatible"))?;
1294 match (edge, x) {
1295 (Instance::Literal(edge), Instance::Literal(x)) => lit_step(&edge, &x).map(Into::into),
1296 (Instance::Vec(edge), Instance::Vec(x)) => {
1297 edge.compwise_binary(&x, lit_step).map(Into::into)
1298 }
1299 _ => Err(ERR),
1300 }
1301}
1302
1303pub fn tan(e: &Instance) -> Result<Instance, E> {
1307 impl_call_float_unary!("tan", e, n => n.tan())
1308}
1309
1310pub fn tanh(e: &Instance) -> Result<Instance, E> {
1314 impl_call_float_unary!("tanh", e, n => n.tanh())
1315}
1316
1317pub fn transpose(e: &Instance) -> Result<Instance, E> {
1321 match e {
1322 Instance::Mat(e) => Ok(e.transpose().into()),
1323 _ => Err(E::Builtin("`transpose` expects a matrix argument")),
1324 }
1325}
1326
1327pub fn trunc(e: &Instance) -> Result<Instance, E> {
1331 impl_call_float_unary!("trunc", e, n => n.trunc())
1332}
1333
1334pub fn atomicLoad(e: &Instance) -> Result<Instance, E> {
1343 let err = E::Builtin("`atomicLoad` expects a pointer to atomic argument");
1344 if let Instance::Ptr(ptr) = e {
1345 let inst = ptr.ptr.read()?;
1347 if let Instance::Atomic(inst) = &*inst {
1348 Ok(inst.inner().clone())
1349 } else {
1350 Err(err)
1351 }
1352 } else {
1353 Err(err)
1354 }
1355}
1356
1357pub fn atomicStore(e1: &Instance, e2: &Instance) -> Result<(), E> {
1361 let err = E::Builtin("`atomicStore` expects a pointer to atomic argument");
1362 if let Instance::Ptr(ptr) = e1 {
1363 let mut inst = ptr.ptr.read_write()?;
1364 if let Instance::Atomic(inst) = &mut *inst {
1365 let ty = inst.inner().ty();
1366 let e2 = e2
1367 .convert_to(&ty)
1368 .ok_or_else(|| E::ParamType(ty, e2.ty()))?;
1369 *inst = AtomicInstance::new(e2);
1370 Ok(())
1371 } else {
1372 Err(err)
1373 }
1374 } else {
1375 Err(err)
1376 }
1377}
1378
1379pub fn atomicAdd(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1383 let initial = atomicLoad(e1)?;
1384 atomicStore(e1, &initial.op_add(e2, ShaderStage::Exec)?)?;
1385 Ok(initial)
1386}
1387
1388pub fn atomicSub(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1392 let initial = atomicLoad(e1)?;
1393 atomicStore(e1, &initial.op_sub(e2, ShaderStage::Exec)?)?;
1394 Ok(initial)
1395}
1396
1397pub fn atomicMax(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1401 let initial = atomicLoad(e1)?;
1402 atomicStore(e1, &max(&initial, e2)?)?;
1403 Ok(initial)
1404}
1405
1406pub fn atomicMin(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1410 let initial = atomicLoad(e1)?;
1411 atomicStore(e1, &min(&initial, e2)?)?;
1412 Ok(initial)
1413}
1414
1415pub fn atomicAnd(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1419 let initial = atomicLoad(e1)?;
1420 atomicStore(e1, &initial.op_bitand(e2)?)?;
1421 Ok(initial)
1422}
1423
1424pub fn atomicOr(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1428 let initial = atomicLoad(e1)?;
1429 atomicStore(e1, &initial.op_bitor(e2)?)?;
1430 Ok(initial)
1431}
1432
1433pub fn atomicXor(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1437 let initial = atomicLoad(e1)?;
1438 atomicStore(e1, &initial.op_bitxor(e2)?)?;
1439 Ok(initial)
1440}
1441
1442pub fn atomicExchange(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1446 let initial = atomicLoad(e1)?;
1447 atomicStore(e1, e2)?;
1448 Ok(initial)
1449}
1450
1451pub fn atomicCompareExchangeWeak(
1455 atomic_ptr: &Instance,
1456 cmp: &Instance,
1457 v: &Instance,
1458) -> Result<Instance, E> {
1459 let old_value = atomicLoad(atomic_ptr)?;
1460
1461 let ty = old_value.ty();
1462
1463 let Some(cmp) = cmp.convert_to(&ty) else {
1464 return Err(E::ParamType(ty, cmp.ty()));
1465 };
1466
1467 let Some(v) = v.convert_to(&ty) else {
1468 return Err(E::ParamType(ty, v.ty()));
1469 };
1470
1471 let exchanged = old_value == cmp;
1472 if exchanged {
1473 atomicStore(atomic_ptr, &v)?;
1474 }
1475 Ok(Instance::Struct(StructInstance::new(
1476 atomic_compare_exchange_struct_type(&old_value.ty()),
1477 vec![old_value, LiteralInstance::Bool(exchanged).into()],
1478 )))
1479}
1480
1481pub fn pack4x8snorm(e: &Instance) -> Result<Instance, E> {
1490 const ERR: E = E::Builtin("`pack4x8snorm` expects a `vec4<f32>` argument");
1491
1492 let v = e
1493 .convert_to(&Type::Vec(4, Type::F32.into()))
1494 .ok_or(ERR)?
1495 .unwrap_vec();
1496
1497 let mut result = 0u32;
1498 for i in 0..4 {
1499 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1500 let bits = (0.5 + 127.0 * val.clamp(-1.0, 1.0)).floor() as i8 as u8;
1501 result |= (bits as u32) << (8 * i);
1502 }
1503 Ok(LiteralInstance::U32(result).into())
1504}
1505
1506pub fn pack4x8unorm(e: &Instance) -> Result<Instance, E> {
1510 const ERR: E = E::Builtin("`pack4x8unorm` expects a `vec4<f32>` argument");
1511
1512 let v = e
1513 .convert_to(&Type::Vec(4, Type::F32.into()))
1514 .ok_or(ERR)?
1515 .unwrap_vec();
1516
1517 let mut result = 0u32;
1518 for i in 0..4 {
1519 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1520 let bits = (0.5 + 255.0 * val.clamp(0.0, 1.0)).floor() as u8;
1521 result |= (bits as u32) << (8 * i);
1522 }
1523 Ok(LiteralInstance::U32(result).into())
1524}
1525
1526pub fn pack4xI8(e: &Instance) -> Result<Instance, E> {
1530 const ERR: E = E::Builtin("`pack4xI8` expects a `vec4<i32>` argument");
1531
1532 let v = e
1533 .convert_to(&Type::Vec(4, Type::I32.into()))
1534 .ok_or(ERR)?
1535 .unwrap_vec();
1536
1537 let mut result = 0u32;
1538 for i in 0..4 {
1539 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_i32();
1540 result |= (val as u8 as u32) << (8 * i);
1541 }
1542 Ok(LiteralInstance::U32(result).into())
1543}
1544
1545pub fn pack4xU8(e: &Instance) -> Result<Instance, E> {
1549 const ERR: E = E::Builtin("`pack4xU8` expects a `vec4<u32>` argument");
1550
1551 let v = e
1552 .convert_to(&Type::Vec(4, Type::U32.into()))
1553 .ok_or(ERR)?
1554 .unwrap_vec();
1555
1556 let mut result = 0u32;
1557 for i in 0..4 {
1558 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_u32();
1559 result |= (val as u8 as u32) << (8 * i);
1560 }
1561 Ok(LiteralInstance::U32(result).into())
1562}
1563
1564pub fn pack4xI8Clamp(e: &Instance) -> Result<Instance, E> {
1568 const ERR: E = E::Builtin("`pack4xI8Clamp` expects a `vec4<i32>` argument");
1569
1570 let v = e
1571 .convert_to(&Type::Vec(4, Type::I32.into()))
1572 .ok_or(ERR)?
1573 .unwrap_vec();
1574
1575 let mut result = 0u32;
1576 for i in 0..4 {
1577 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_i32();
1578 result |= (val.clamp(-128, 127) as u8 as u32) << (8 * i);
1579 }
1580 Ok(LiteralInstance::U32(result).into())
1581}
1582
1583pub fn pack4xU8Clamp(e: &Instance) -> Result<Instance, E> {
1587 const ERR: E = E::Builtin("`pack4xU8Clamp` expects a `vec4<u32>` argument");
1588
1589 let v = e
1590 .convert_to(&Type::Vec(4, Type::U32.into()))
1591 .ok_or(ERR)?
1592 .unwrap_vec();
1593
1594 let mut result = 0u32;
1595 for i in 0..4 {
1596 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_u32();
1597 result |= (val.min(255) as u8 as u32) << (8 * i);
1598 }
1599 Ok(LiteralInstance::U32(result).into())
1600}
1601
1602pub fn pack2x16snorm(e: &Instance) -> Result<Instance, E> {
1606 const ERR: E = E::Builtin("`pack2x16snorm` expects a `vec2<f32>` argument");
1607
1608 let v = e
1609 .convert_to(&Type::Vec(2, Type::F32.into()))
1610 .ok_or(ERR)?
1611 .unwrap_vec();
1612
1613 let mut result = 0u32;
1614 for i in 0..2 {
1615 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1616 let bits = (0.5 + 32767.0 * val.clamp(-1.0, 1.0)).floor() as i16 as u16;
1617 result |= (bits as u32) << (16 * i);
1618 }
1619 Ok(LiteralInstance::U32(result).into())
1620}
1621
1622pub fn pack2x16unorm(e: &Instance) -> Result<Instance, E> {
1626 const ERR: E = E::Builtin("`pack2x16unorm` expects a `vec2<f32>` argument");
1627
1628 let v = e
1629 .convert_to(&Type::Vec(2, Type::F32.into()))
1630 .ok_or(ERR)?
1631 .unwrap_vec();
1632
1633 let mut result = 0u32;
1634 for i in 0..2 {
1635 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1636 let bits = (0.5 + 65535.0 * val.clamp(0.0, 1.0)).floor() as u16;
1637 result |= (bits as u32) << (16 * i);
1638 }
1639 Ok(LiteralInstance::U32(result).into())
1640}
1641
1642pub fn pack2x16float(e: &Instance) -> Result<Instance, E> {
1646 const ERR: E = E::Builtin("`pack2x16float` expects a `vec2<f32>` argument");
1647
1648 let v = e
1649 .convert_to(&Type::Vec(2, Type::F32.into()))
1650 .ok_or(ERR)?
1651 .unwrap_vec();
1652
1653 let mut result = 0u32;
1654 for i in 0..2 {
1655 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1656 let bits = f16::from_f32(val).to_bits();
1657 result |= (bits as u32) << (16 * i);
1658 }
1659 Ok(LiteralInstance::U32(result).into())
1660}
1661
1662pub fn unpack4x8snorm(e: &Instance) -> Result<Instance, E> {
1666 const ERR: E = E::Builtin("`unpack4x8snorm` expects a `u32` argument");
1667
1668 let e = e
1669 .convert_to(&Type::U32)
1670 .ok_or(ERR)?
1671 .unwrap_literal()
1672 .unwrap_u32();
1673
1674 let comps = e
1675 .to_le_bytes()
1676 .map(|c| ((c as i8 as f32) / 127.0).max(-1.0))
1677 .map(Instance::from)
1678 .to_vec();
1679
1680 Ok(VecInstance::new(comps).into())
1681}
1682
1683pub fn unpack4x8unorm(e: &Instance) -> Result<Instance, E> {
1687 const ERR: E = E::Builtin("`unpack4x8unorm` expects a `u32` argument");
1688
1689 let e = e
1690 .convert_to(&Type::U32)
1691 .ok_or(ERR)?
1692 .unwrap_literal()
1693 .unwrap_u32();
1694
1695 let comps = e
1696 .to_le_bytes()
1697 .map(|c| (c as f32) / 255.0)
1698 .map(Instance::from)
1699 .to_vec();
1700
1701 Ok(VecInstance::new(comps).into())
1702}
1703
1704pub fn unpack4xI8(e: &Instance) -> Result<Instance, E> {
1708 const ERR: E = E::Builtin("`unpack4xI8` expects a `u32` argument");
1709
1710 let e = e
1711 .convert_to(&Type::U32)
1712 .ok_or(ERR)?
1713 .unwrap_literal()
1714 .unwrap_u32();
1715
1716 let comps = e
1717 .to_le_bytes()
1718 .map(|c| c as i8 as i32)
1719 .map(Instance::from)
1720 .to_vec();
1721
1722 Ok(VecInstance::new(comps).into())
1723}
1724
1725pub fn unpack4xU8(e: &Instance) -> Result<Instance, E> {
1729 const ERR: E = E::Builtin("`unpack4xU8` expects a `u32` argument");
1730
1731 let e = e
1732 .convert_to(&Type::U32)
1733 .ok_or(ERR)?
1734 .unwrap_literal()
1735 .unwrap_u32();
1736
1737 let comps = e
1738 .to_le_bytes()
1739 .map(|c| c as u32)
1740 .map(Instance::from)
1741 .to_vec();
1742
1743 Ok(VecInstance::new(comps).into())
1744}
1745
1746pub fn unpack2x16snorm(e: &Instance) -> Result<Instance, E> {
1750 const ERR: E = E::Builtin("`unpack2x16snorm` expects a `u32` argument");
1751
1752 let e = e
1753 .convert_to(&Type::U32)
1754 .ok_or(ERR)?
1755 .unwrap_literal()
1756 .unwrap_u32();
1757
1758 let lsb = e as u16 as i16;
1759 let msb = (e >> 16) as u16 as i16;
1760
1761 let comps = [lsb, msb]
1762 .map(|c| ((c as f32) / 32767.0).max(-1.0))
1763 .map(Instance::from)
1764 .to_vec();
1765
1766 Ok(VecInstance::new(comps).into())
1767}
1768
1769pub fn unpack2x16unorm(e: &Instance) -> Result<Instance, E> {
1773 const ERR: E = E::Builtin("`unpack2x16unorm` expects a `u32` argument");
1774
1775 let e = e
1776 .convert_to(&Type::U32)
1777 .ok_or(ERR)?
1778 .unwrap_literal()
1779 .unwrap_u32();
1780
1781 let lsb = e as u16;
1782 let msb = (e >> 16) as u16;
1783
1784 let comps = [lsb, msb]
1785 .map(|c| (c as f32) / 65535.0)
1786 .map(Instance::from)
1787 .to_vec();
1788
1789 Ok(VecInstance::new(comps).into())
1790}
1791
1792pub fn unpack2x16float(e: &Instance) -> Result<Instance, E> {
1796 const ERR: E = E::Builtin("`unpack2x16float` expects a `u32` argument");
1797
1798 let e = e
1799 .convert_to(&Type::U32)
1800 .ok_or(ERR)?
1801 .unwrap_literal()
1802 .unwrap_u32();
1803
1804 let lsb = e as u16;
1805 let msb = (e >> 16) as u16;
1806
1807 let comps = [lsb, msb]
1808 .map(|c| f16::from_bits(c).to_f32())
1809 .map(Instance::from)
1810 .to_vec();
1811
1812 Ok(VecInstance::new(comps).into())
1813}
1814
1815impl VecInstance {
1816 pub fn dot(&self, rhs: &VecInstance, stage: ShaderStage) -> Result<LiteralInstance, E> {
1818 self.compwise_binary(rhs, |a, b| a.op_mul(b, stage))?
1819 .into_iter()
1820 .map(|c| Ok(c.unwrap_literal()))
1821 .reduce(|a, b| a?.op_add(&b?, stage))
1822 .unwrap()
1823 }
1824}
1825
1826impl MatInstance {
1827 pub fn transpose(&self) -> MatInstance {
1829 let components = (0..self.r())
1830 .map(|j| {
1831 VecInstance::new(
1832 (0..self.c())
1833 .map(|i| self.get(i, j).unwrap().clone())
1834 .collect_vec(),
1835 )
1836 .into()
1837 })
1838 .collect_vec();
1839 MatInstance::from_cols(components)
1840 }
1841}