1#![allow(non_snake_case)]
18
19use half::prelude::*;
20use itertools::{Itertools, chain, izip};
21use num_traits::{One, ToBytes, ToPrimitive, Zero, real::Real};
22
23use crate::{
24 Error, Instance, ShaderStage,
25 conv::{Convert, convert, convert_all_ty},
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> {
45 fn lit_bytes(l: &LiteralInstance, ty: &Type) -> Result<Vec<u8>, E> {
46 match l {
47 LiteralInstance::Bool(_) => Err(E::Builtin("bitcast argument cannot be bool")),
48 LiteralInstance::AbstractInt(n) => {
49 if ty == &Type::U32 {
50 n.to_u32()
51 .map(|n| n.to_le_bytes().to_vec())
52 .ok_or(E::ConvOverflow(*l, Type::U32))
53 } else {
54 n.to_i32()
55 .map(|n| n.to_le_bytes().to_vec())
56 .ok_or(E::ConvOverflow(*l, Type::I32))
57 }
58 }
59 LiteralInstance::AbstractFloat(n) => n
60 .to_f32()
61 .map(|n| n.to_le_bytes().to_vec())
62 .ok_or(E::ConvOverflow(*l, Type::F32)),
63 LiteralInstance::I32(n) => Ok(n.to_le_bytes().to_vec()),
64 LiteralInstance::U32(n) => Ok(n.to_le_bytes().to_vec()),
65 LiteralInstance::F32(n) => Ok(n.to_le_bytes().to_vec()),
66 LiteralInstance::F16(n) => Ok(n.to_le_bytes().to_vec()),
67 #[cfg(feature = "naga-ext")]
68 LiteralInstance::I64(n) => Ok(n.to_le_bytes().to_vec()),
69 #[cfg(feature = "naga-ext")]
70 LiteralInstance::U64(n) => Ok(n.to_le_bytes().to_vec()),
71 #[cfg(feature = "naga-ext")]
72 LiteralInstance::F64(n) => Ok(n.to_le_bytes().to_vec()),
73 }
74 }
75
76 fn vec_bytes(v: &VecInstance, ty: &Type) -> Result<Vec<u8>, E> {
77 v.iter()
78 .map(|n| lit_bytes(n.unwrap_literal_ref(), ty))
79 .reduce(|n1, n2| Ok(chain(n1?, n2?).collect_vec()))
80 .unwrap()
81 }
82
83 let inner_ty = tplt_ty.inner_ty();
84
85 let bytes = match e {
86 Instance::Literal(l) => lit_bytes(l, &inner_ty),
87 Instance::Vec(v) => vec_bytes(v, &inner_ty),
88 _ => Err(E::Builtin(
89 "`bitcast` expects a numeric scalar or vector argument",
90 )),
91 }?;
92
93 let size_err = E::Builtin("`bitcast` input and output types must have the same size");
94
95 match tplt_ty {
96 Type::I32 => {
97 let n = i32::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
98 Ok(LiteralInstance::I32(n).into())
99 }
100 Type::U32 => {
101 let n = u32::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
102 Ok(LiteralInstance::U32(n).into())
103 }
104 Type::F32 => {
105 let n = f32::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
106 Ok(LiteralInstance::F32(n).into())
107 }
108 Type::F16 => {
109 let n = f16::from_le_bytes(bytes.try_into().map_err(|_| size_err)?);
110 Ok(LiteralInstance::F16(n).into())
111 }
112 Type::Vec(n, ty) => {
113 if **ty == Type::I32 && bytes.len() == 4 * (*n as usize) {
114 let v = bytes
115 .chunks(4)
116 .map(|b| i32::from_le_bytes(b.try_into().unwrap()))
117 .map(|n| LiteralInstance::from(n).into())
118 .collect_vec();
119 Ok(VecInstance::new(v).into())
120 } else if **ty == Type::U32 && bytes.len() == 4 * (*n as usize) {
121 let v = bytes
122 .chunks(4)
123 .map(|b| u32::from_le_bytes(b.try_into().unwrap()))
124 .map(|n| LiteralInstance::from(n).into())
125 .collect_vec();
126 Ok(VecInstance::new(v).into())
127 } else if **ty == Type::F32 && bytes.len() == 4 * (*n as usize) {
128 let v = bytes
129 .chunks(4)
130 .map(|b| f32::from_le_bytes(b.try_into().unwrap()))
131 .map(|n| LiteralInstance::from(n).into())
132 .collect_vec();
133 Ok(VecInstance::new(v).into())
134 } else if **ty == Type::F16 && bytes.len() == 2 * (*n as usize) {
135 let v = bytes
136 .chunks(2)
137 .map(|b| f16::from_le_bytes(b.try_into().unwrap()))
138 .map(|n| LiteralInstance::from(n).into())
139 .collect_vec();
140 Ok(VecInstance::new(v).into())
141 } else {
142 Err(size_err)
143 }
144 }
145 _ => unreachable!("invalid `bitcast` template"),
146 }
147}
148
149pub fn all(e: &Instance) -> Result<Instance, E> {
158 match e {
159 Instance::Literal(LiteralInstance::Bool(_)) => Ok(e.clone()),
160 Instance::Vec(v) if v.inner_ty() == Type::Bool => {
161 let b = v.iter().all(|b| b.unwrap_literal_ref().unwrap_bool());
162 Ok(LiteralInstance::Bool(b).into())
163 }
164 _ => Err(E::Builtin(
165 "`all` expects a boolean or vector of boolean argument",
166 )),
167 }
168}
169
170pub fn any(e: &Instance) -> Result<Instance, E> {
174 match e {
175 Instance::Literal(LiteralInstance::Bool(_)) => Ok(e.clone()),
176 Instance::Vec(v) if v.inner_ty() == Type::Bool => {
177 let b = v.iter().any(|b| b.unwrap_literal_ref().unwrap_bool());
178 Ok(LiteralInstance::Bool(b).into())
179 }
180 _ => Err(E::Builtin(
181 "`any` expects a boolean or vector of boolean argument",
182 )),
183 }
184}
185
186pub fn select(f: &Instance, t: &Instance, cond: &Instance) -> Result<Instance, E> {
190 let (f, t) = convert(f, t).ok_or(E::Builtin(
191 "`select` 1st and 2nd arguments are incompatible",
192 ))?;
193
194 match cond {
195 Instance::Literal(LiteralInstance::Bool(b)) => Ok(b.then_some(t).unwrap_or(f)),
196 Instance::Vec(v) if v.inner_ty() == Type::Bool => match (f, t) {
197 (Instance::Vec(v1), Instance::Vec(v2)) => {
198 if v1.n() != v.n() {
199 Err(E::Builtin(
200 "`select` vector arguments must have the same number of components",
201 ))
202 } else {
203 let v = izip!(v1, v2, v.iter())
204 .map(|(f, t, b)| {
205 if b.unwrap_literal_ref().unwrap_bool() {
206 t.to_owned() } else {
208 f.to_owned()
209 }
210 })
211 .collect_vec();
212 Ok(VecInstance::new(v).into())
213 }
214 }
215 _ => Err(E::Builtin(
216 "`select` arguments must be vectors when the condition is a vector",
217 )),
218 },
219 _ => Err(E::Builtin(
220 "`select` 3rd argument must be a boolean or vector of boolean",
221 )),
222 }
223}
224
225pub fn arrayLength(p: &Instance) -> Result<Instance, E> {
234 let err = E::Builtin("`arrayLength` expects a pointer to array argument");
235 let r = match p {
236 Instance::Ptr(p) => RefInstance::from(p.clone()),
237 _ => return Err(err),
238 };
239 let r = r.read()?;
240 match &*r {
241 Instance::Array(a) => Ok(LiteralInstance::U32(a.n() as u32).into()),
242 _ => Err(err),
243 }
244}
245
246macro_rules! impl_call_float_unary {
252 ($name:literal, $e:ident, $n:ident => $expr:expr) => {{
253 const ERR: E = E::Builtin(concat!(
254 "`",
255 $name,
256 "` expects a float or vector of float argument"
257 ));
258 fn lit_fn(l: &LiteralInstance) -> Result<LiteralInstance, E> {
259 match l {
260 LiteralInstance::Bool(_) => Err(ERR),
261 LiteralInstance::AbstractInt(_) => {
262 let $n = l
263 .convert_to(&Type::AbstractFloat)
264 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
265 .unwrap_abstract_float();
266 Ok(LiteralInstance::from($expr))
267 }
268 LiteralInstance::AbstractFloat($n) => Ok(LiteralInstance::from($expr)),
269 LiteralInstance::I32(_) => Err(ERR),
270 LiteralInstance::U32(_) => Err(ERR),
271 LiteralInstance::F32($n) => Ok(LiteralInstance::from($expr)),
272 LiteralInstance::F16($n) => Ok(LiteralInstance::from($expr)),
273 #[cfg(feature = "naga-ext")]
274 LiteralInstance::I64(_) => Err(ERR),
275 #[cfg(feature = "naga-ext")]
276 LiteralInstance::U64(_) => Err(ERR),
277 #[cfg(feature = "naga-ext")]
278 LiteralInstance::F64($n) => Ok(LiteralInstance::F64($expr)),
279 }
280 }
281 match $e {
282 Instance::Literal(l) => lit_fn(l).map(Into::into),
283 Instance::Vec(v) => v.compwise_unary(lit_fn).map(Into::into),
284 _ => Err(ERR),
285 }
286 }};
287}
288
289pub fn abs(e: &Instance) -> Result<Instance, E> {
294 const ERR: E = E::Builtin("`abs` expects a scalar or vector of scalar argument");
295 fn lit_abs(l: &LiteralInstance) -> Result<LiteralInstance, E> {
296 match l {
297 LiteralInstance::Bool(_) => Err(ERR),
298 LiteralInstance::AbstractInt(n) => Ok(LiteralInstance::from(n.wrapping_abs())),
299 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(n.abs())),
300 LiteralInstance::I32(n) => Ok(LiteralInstance::from(n.wrapping_abs())),
301 LiteralInstance::U32(_) => Ok(*l),
302 LiteralInstance::F32(n) => Ok(LiteralInstance::from(n.abs())),
303 LiteralInstance::F16(n) => Ok(LiteralInstance::from(n.abs())),
304 #[cfg(feature = "naga-ext")]
305 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.wrapping_abs())),
306 #[cfg(feature = "naga-ext")]
307 LiteralInstance::U64(_) => Ok(*l),
308 #[cfg(feature = "naga-ext")]
309 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(n.abs())),
310 }
311 }
312 match e {
313 Instance::Literal(l) => lit_abs(l).map(Into::into),
314 Instance::Vec(v) => v.compwise_unary(lit_abs).map(Into::into),
315 _ => Err(ERR),
316 }
317}
318
319pub fn acos(e: &Instance) -> Result<Instance, E> {
325 impl_call_float_unary!("acos", e, n => n.acos())
326}
327
328pub fn acosh(e: &Instance) -> Result<Instance, E> {
334 impl_call_float_unary!("acosh", e, n => n.acosh())
337}
338
339pub fn asin(e: &Instance) -> Result<Instance, E> {
345 impl_call_float_unary!("asin", e, n => n.asin())
346}
347
348pub fn asinh(e: &Instance) -> Result<Instance, E> {
352 impl_call_float_unary!("asinh", e, n => n.asinh())
355}
356
357pub fn atan(e: &Instance) -> Result<Instance, E> {
361 impl_call_float_unary!("atan", e, n => n.atan())
362}
363
364pub fn atanh(e: &Instance) -> Result<Instance, E> {
370 impl_call_float_unary!("atanh", e, n => n.atanh())
371}
372
373pub fn atan2(y: &Instance, x: &Instance) -> Result<Instance, E> {
377 const ERR: E = E::Builtin("`atan2` expects a float or vector of float argument");
378 fn lit_atan2(y: &LiteralInstance, x: &LiteralInstance) -> Result<LiteralInstance, E> {
379 match y {
380 LiteralInstance::Bool(_) => Err(ERR),
381 LiteralInstance::AbstractInt(_) => {
382 let y = y
383 .convert_to(&Type::AbstractFloat)
384 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?;
385 let x = x
386 .convert_to(&Type::AbstractFloat)
387 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?;
388 Ok(LiteralInstance::from(
389 y.unwrap_abstract_float().atan2(x.unwrap_abstract_float()),
390 ))
391 }
392 LiteralInstance::AbstractFloat(y) => {
393 Ok(LiteralInstance::from(y.atan2(x.unwrap_abstract_float())))
394 }
395 LiteralInstance::I32(_) => Err(ERR),
396 LiteralInstance::U32(_) => Err(ERR),
397 LiteralInstance::F32(y) => Ok(LiteralInstance::from(y.atan2(x.unwrap_f32()))),
398 LiteralInstance::F16(y) => Ok(LiteralInstance::from(y.atan2(x.unwrap_f16()))),
399 #[cfg(feature = "naga-ext")]
400 LiteralInstance::I64(_) => Err(ERR),
401 #[cfg(feature = "naga-ext")]
402 LiteralInstance::U64(_) => Err(ERR),
403 #[cfg(feature = "naga-ext")]
404 LiteralInstance::F64(y) => Ok(LiteralInstance::F64(y.atan2(x.unwrap_f64()))),
405 }
406 }
407 let (y, x) = convert(y, x).ok_or(E::Builtin("`atan2` arguments are incompatible"))?;
408 match (y, x) {
409 (Instance::Literal(y), Instance::Literal(x)) => lit_atan2(&y, &x).map(Into::into),
410 (Instance::Vec(y), Instance::Vec(x)) => y.compwise_binary(&x, lit_atan2).map(Into::into),
411 _ => Err(ERR),
412 }
413}
414
415pub fn ceil(e: &Instance) -> Result<Instance, E> {
419 impl_call_float_unary!("ceil", e, n => n.ceil())
420}
421
422pub fn clamp(e: &Instance, low: &Instance, high: &Instance) -> Result<Instance, E> {
426 const ERR: E = E::Builtin("`clamp` arguments are incompatible");
427 let tys = [e.ty(), low.ty(), high.ty()];
428 let ty = convert_all_ty(&tys).ok_or(ERR)?;
429 let e = e.convert_to(ty).ok_or(ERR)?;
430 let low = low.convert_to(ty).ok_or(ERR)?;
431 let high = high.convert_to(ty).ok_or(ERR)?;
432 min(&max(&e, &low)?, &high)
433}
434
435pub fn cos(e: &Instance) -> Result<Instance, E> {
441 impl_call_float_unary!("cos", e, n => n.cos())
442}
443
444pub fn cosh(e: &Instance) -> Result<Instance, E> {
448 impl_call_float_unary!("cosh", e, n => n.cosh())
449}
450
451pub fn countLeadingZeros(e: &Instance) -> Result<Instance, E> {
455 const ERR: E = E::Builtin("`countLeadingZeros` expects a float or vector of float argument");
456 fn lit_leading_zeros(l: &LiteralInstance) -> Result<LiteralInstance, E> {
457 match l {
458 LiteralInstance::Bool(_) => Err(ERR),
459 LiteralInstance::AbstractInt(n) => {
460 Ok(LiteralInstance::AbstractInt(n.leading_zeros() as i64))
461 }
462 LiteralInstance::AbstractFloat(_) => Err(ERR),
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 {
476 Instance::Literal(l) => lit_leading_zeros(l).map(Into::into),
477 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 a float or vector of float argument");
487 fn lit_count_ones(l: &LiteralInstance) -> Result<LiteralInstance, E> {
488 match l {
489 LiteralInstance::Bool(_) => Err(ERR),
490 LiteralInstance::AbstractInt(n) => {
491 Ok(LiteralInstance::AbstractInt(n.count_ones() as i64))
492 }
493 LiteralInstance::AbstractFloat(_) => Err(ERR),
494 LiteralInstance::I32(n) => Ok(LiteralInstance::I32(n.count_ones() as i32)),
495 LiteralInstance::U32(n) => Ok(LiteralInstance::U32(n.count_ones())),
496 LiteralInstance::F32(_) => Err(ERR),
497 LiteralInstance::F16(_) => Err(ERR),
498 #[cfg(feature = "naga-ext")]
499 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.count_ones() as i64)),
500 #[cfg(feature = "naga-ext")]
501 LiteralInstance::U64(n) => Ok(LiteralInstance::U64(n.count_ones() as u64)),
502 #[cfg(feature = "naga-ext")]
503 LiteralInstance::F64(_) => Err(ERR),
504 }
505 }
506 match e {
507 Instance::Literal(l) => lit_count_ones(l).map(Into::into),
508 Instance::Vec(v) => v.compwise_unary(lit_count_ones).map(Into::into),
509 _ => Err(ERR),
510 }
511}
512
513pub fn countTrailingZeros(e: &Instance) -> Result<Instance, E> {
517 const ERR: E = E::Builtin("`countTrailingZeros` expects a float or vector of float argument");
518 fn lit_trailing_zeros(l: &LiteralInstance) -> Result<LiteralInstance, E> {
519 match l {
520 LiteralInstance::Bool(_) => Err(ERR),
521 LiteralInstance::AbstractInt(n) => {
522 Ok(LiteralInstance::AbstractInt(n.trailing_zeros() as i64))
523 }
524 LiteralInstance::AbstractFloat(_) => Err(ERR),
525 LiteralInstance::I32(n) => Ok(LiteralInstance::I32(n.trailing_zeros() as i32)),
526 LiteralInstance::U32(n) => Ok(LiteralInstance::U32(n.trailing_zeros())),
527 LiteralInstance::F32(_) => Err(ERR),
528 LiteralInstance::F16(_) => Err(ERR),
529 #[cfg(feature = "naga-ext")]
530 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.trailing_zeros() as i64)),
531 #[cfg(feature = "naga-ext")]
532 LiteralInstance::U64(n) => Ok(LiteralInstance::U64(n.trailing_zeros() as u64)),
533 #[cfg(feature = "naga-ext")]
534 LiteralInstance::F64(_) => Err(ERR),
535 }
536 }
537 match e {
538 Instance::Literal(l) => lit_trailing_zeros(l).map(Into::into),
539 Instance::Vec(v) => v.compwise_unary(lit_trailing_zeros).map(Into::into),
540 _ => Err(ERR),
541 }
542}
543
544pub fn cross(a: &Instance, b: &Instance, stage: ShaderStage) -> Result<Instance, E> {
548 let (a, b) = convert(a, b).ok_or(E::Builtin("`cross` arguments are incompatible"))?;
549 match (a, b) {
550 (Instance::Vec(a), Instance::Vec(b)) if a.n() == 3 => {
551 let s1 = a[1]
552 .op_mul(&b[2], stage)?
553 .op_sub(&a[2].op_mul(&b[1], stage)?, stage)?;
554 let s2 = a[2]
555 .op_mul(&b[0], stage)?
556 .op_sub(&a[0].op_mul(&b[2], stage)?, stage)?;
557 let s3 = a[0]
558 .op_mul(&b[1], stage)?
559 .op_sub(&a[1].op_mul(&b[0], stage)?, stage)?;
560 Ok(VecInstance::new(vec![s1, s2, s3]).into())
561 }
562 _ => Err(E::Builtin(
563 "`cross` expects a 3-component vector of float arguments",
564 )),
565 }
566}
567
568pub fn degrees(e: &Instance) -> Result<Instance, E> {
572 impl_call_float_unary!("degrees", e, n => n.to_degrees())
573}
574
575pub fn determinant(_a1: &Instance) -> Result<Instance, E> {
577 Err(E::Todo("determinant".to_string()))
578}
579
580pub fn distance(e1: &Instance, e2: &Instance, stage: ShaderStage) -> Result<Instance, E> {
586 length(&e1.op_sub(e2, stage)?)
587}
588
589pub fn dot(e1: &Instance, e2: &Instance, stage: ShaderStage) -> Result<Instance, E> {
593 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`dot` arguments are incompatible"))?;
594 match (e1, e2) {
595 (Instance::Vec(e1), Instance::Vec(e2)) => e1.dot(&e2, stage).map(Into::into),
596 _ => Err(E::Builtin("`dot` expects vector arguments")),
597 }
598}
599
600pub fn dot4U8Packed(_a1: &Instance, _a2: &Instance) -> Result<Instance, E> {
602 Err(E::Todo("dot4U8Packed".to_string()))
603}
604
605pub fn dot4I8Packed(_a1: &Instance, _a2: &Instance) -> Result<Instance, E> {
607 Err(E::Todo("dot4I8Packed".to_string()))
608}
609
610pub fn exp(e: &Instance) -> Result<Instance, E> {
614 impl_call_float_unary!("exp", e, n => n.exp())
615}
616
617pub fn exp2(e: &Instance) -> Result<Instance, E> {
621 impl_call_float_unary!("exp2", e, n => n.exp2())
622}
623
624pub fn extractBits(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
626 Err(E::Todo("extractBits".to_string()))
627}
628
629pub fn faceForward(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
631 Err(E::Todo("faceForward".to_string()))
632}
633
634pub fn firstLeadingBit(_a1: &Instance) -> Result<Instance, E> {
636 Err(E::Todo("firstLeadingBit".to_string()))
637}
638
639pub fn firstTrailingBit(_a1: &Instance) -> Result<Instance, E> {
641 Err(E::Todo("firstTrailingBit".to_string()))
642}
643
644pub fn floor(e: &Instance) -> Result<Instance, E> {
648 impl_call_float_unary!("floor", e, n => n.floor())
649}
650
651pub fn fma(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
653 Err(E::Todo("fma".to_string()))
654}
655
656pub fn fract(e: &Instance, stage: ShaderStage) -> Result<Instance, E> {
660 e.op_sub(&floor(e)?, stage)
661 }
663
664pub fn frexp(e: &Instance) -> Result<Instance, E> {
670 const ERR: E = E::Builtin("`frexp` expects a float or vector of float argument");
671 fn make_frexp_inst(fract: Instance, exp: Instance) -> Instance {
672 Instance::Struct(StructInstance::new(
673 frexp_struct_type(&fract.ty()).unwrap(),
674 vec![fract, exp],
675 ))
676 }
677 fn frexp(x: f64) -> (f64, i32) {
679 let mut y = x.to_bits();
680 let ee = ((y >> 52) & 0x7ff) as i32;
681
682 if ee == 0 {
683 if x != 0.0 {
684 let x1p64 = f64::from_bits(0x43f0000000000000);
685 let (x, e) = frexp(x * x1p64);
686 return (x, e - 64);
687 }
688 return (x, 0);
689 } else if ee == 0x7ff {
690 return (x, 0);
691 }
692
693 let e = ee - 0x3fe;
694 y &= 0x800fffffffffffff;
695 y |= 0x3fe0000000000000;
696 (f64::from_bits(y), e)
697 }
698 match e {
699 Instance::Literal(l) => match l {
700 LiteralInstance::Bool(_) => todo!(),
701 LiteralInstance::AbstractInt(_) => todo!(),
702 LiteralInstance::AbstractFloat(n) => {
703 let (fract, exp) = frexp(*n);
704 Ok(make_frexp_inst(
705 LiteralInstance::AbstractFloat(fract).into(),
706 LiteralInstance::AbstractInt(exp as i64).into(),
707 ))
708 }
709 LiteralInstance::I32(_) => todo!(),
710 LiteralInstance::U32(_) => todo!(),
711 LiteralInstance::F32(n) => {
712 let (fract, exp) = frexp(*n as f64);
713 Ok(make_frexp_inst(
714 LiteralInstance::F32(fract as f32).into(),
715 LiteralInstance::I32(exp).into(),
716 ))
717 }
718 LiteralInstance::F16(n) => {
719 let (fract, exp) = frexp(n.to_f64().unwrap());
720 Ok(make_frexp_inst(
721 LiteralInstance::F16(f16::from_f64(fract)).into(),
722 LiteralInstance::I32(exp).into(),
723 ))
724 }
725 #[cfg(feature = "naga-ext")]
726 LiteralInstance::I64(_) => todo!(),
727 #[cfg(feature = "naga-ext")]
728 LiteralInstance::U64(_) => todo!(),
729 #[cfg(feature = "naga-ext")]
730 LiteralInstance::F64(n) => {
731 let (fract, exp) = frexp(*n);
732 Ok(make_frexp_inst(
733 LiteralInstance::F64(fract).into(),
734 LiteralInstance::I64(exp as i64).into(),
735 ))
736 }
737 },
738 Instance::Vec(v) => {
739 let ty = v.inner_ty();
740 let (fracts, exps): (Vec<_>, Vec<_>) = v
741 .iter()
742 .map(|l| match l.unwrap_literal_ref() {
743 LiteralInstance::AbstractFloat(n) => Ok(*n),
744 LiteralInstance::F32(n) => Ok(*n as f64),
745 LiteralInstance::F16(n) => {
746 Ok(n.to_f64().unwrap())
747 }
748 _ => Err(ERR),
749 })
750 .collect::<Result<Vec<_>, _>>()?
751 .into_iter()
752 .map(frexp)
753 .unzip();
754 let fracts = fracts
755 .into_iter()
756 .map(|n| match ty {
757 Type::AbstractFloat => LiteralInstance::AbstractFloat(n).into(),
758 Type::F32 => LiteralInstance::F32(n as f32).into(),
759 Type::F16 => LiteralInstance::F16(f16::from_f64(n)).into(),
760 _ => unreachable!("case handled above"),
761 })
762 .collect_vec();
763 let exps = exps
764 .into_iter()
765 .map(|n| match ty {
766 Type::AbstractFloat => LiteralInstance::AbstractInt(n as i64).into(),
767 Type::F32 => LiteralInstance::I32(n).into(),
768 Type::F16 => LiteralInstance::I32(n).into(),
769 _ => unreachable!("case handled above"),
770 })
771 .collect_vec();
772 let fract = VecInstance::new(fracts).into();
773 let exp = VecInstance::new(exps).into();
774 Ok(make_frexp_inst(fract, exp))
775 }
776 _ => Err(ERR),
777 }
778}
779
780pub fn insertBits(
782 _a1: &Instance,
783 _a2: &Instance,
784 _a3: &Instance,
785 _a4: &Instance,
786) -> Result<Instance, E> {
787 Err(E::Todo("insertBits".to_string()))
788}
789
790pub fn inverseSqrt(e: &Instance) -> Result<Instance, E> {
796 const ERR: E = E::Builtin("`inverseSqrt` expects a float or vector of float argument");
797 fn lit_isqrt(l: &LiteralInstance) -> Result<LiteralInstance, E> {
798 match l {
799 LiteralInstance::Bool(_) => Err(ERR),
800 LiteralInstance::AbstractInt(_) => l
801 .convert_to(&Type::AbstractFloat)
802 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))
803 .map(|n| LiteralInstance::from(1.0 / n.unwrap_abstract_float().sqrt())),
804 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(1.0 / n.sqrt())),
805 LiteralInstance::I32(_) => Err(ERR),
806 LiteralInstance::U32(_) => Err(ERR),
807 LiteralInstance::F32(n) => Ok(LiteralInstance::from(1.0 / n.sqrt())),
808 LiteralInstance::F16(n) => Ok(LiteralInstance::from(f16::one() / n.sqrt())),
809 #[cfg(feature = "naga-ext")]
810 LiteralInstance::I64(_) => Err(ERR),
811 #[cfg(feature = "naga-ext")]
812 LiteralInstance::U64(_) => Err(ERR),
813 #[cfg(feature = "naga-ext")]
814 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(1.0 / n.sqrt())),
815 }
816 }
817 match e {
818 Instance::Literal(l) => lit_isqrt(l).map(Into::into),
819 Instance::Vec(v) => v.compwise_unary(lit_isqrt).map(Into::into),
820 _ => Err(ERR),
821 }
822}
823
824pub fn ldexp(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
828 fn scalbn(x: f64, mut n: i32) -> f64 {
830 let x1p1023 = f64::from_bits(0x7fe0000000000000); let x1p53 = f64::from_bits(0x4340000000000000); let x1p_1022 = f64::from_bits(0x0010000000000000); let mut y = x;
835
836 if n > 1023 {
837 y *= x1p1023;
838 n -= 1023;
839 if n > 1023 {
840 y *= x1p1023;
841 n -= 1023;
842 if n > 1023 {
843 n = 1023;
844 }
845 }
846 } else if n < -1022 {
847 y *= x1p_1022 * x1p53;
850 n += 1022 - 53;
851 if n < -1022 {
852 y *= x1p_1022 * x1p53;
853 n += 1022 - 53;
854 if n < -1022 {
855 n = -1022;
856 }
857 }
858 }
859 y * f64::from_bits(((0x3ff + n) as u64) << 52)
860 }
861 fn ldexp_lit(l1: &LiteralInstance, l2: &LiteralInstance) -> Result<LiteralInstance, E> {
862 match (l1, l2) {
863 (LiteralInstance::AbstractInt(n1), LiteralInstance::AbstractInt(n2)) => Ok(
864 LiteralInstance::AbstractFloat(scalbn(n1.to_f64().unwrap(), n2.to_i32().unwrap())),
865 ),
866 (LiteralInstance::AbstractFloat(n1), LiteralInstance::AbstractInt(n2)) => Ok(
867 LiteralInstance::AbstractFloat(scalbn(*n1, n2.to_i32().unwrap())),
868 ),
869 (LiteralInstance::AbstractInt(n1), LiteralInstance::I32(n2)) => Ok(
870 LiteralInstance::F32(scalbn(n1.to_f64().unwrap(), *n2) as f32),
871 ),
872 (LiteralInstance::AbstractFloat(n1), LiteralInstance::I32(n2)) => Ok(
873 LiteralInstance::F32(scalbn(*n1, n2.to_i32().unwrap()) as f32),
874 ),
875 (LiteralInstance::F32(n1), LiteralInstance::AbstractInt(n2)) => Ok(
876 LiteralInstance::F32(scalbn(n1.to_f64().unwrap(), n2.to_i32().unwrap()) as f32),
877 ),
878 (LiteralInstance::F32(n1), LiteralInstance::I32(n2)) => Ok(LiteralInstance::F32(
879 scalbn(n1.to_f64().unwrap(), n2.to_i32().unwrap()) as f32,
880 )),
881 (LiteralInstance::F16(n1), LiteralInstance::AbstractInt(n2)) => {
882 Ok(LiteralInstance::F16(f16::from_f64(scalbn(
883 n1.to_f64().unwrap(),
884 n2.to_i32().unwrap(),
885 ))))
886 }
887 (LiteralInstance::F16(n1), LiteralInstance::I32(n2)) => Ok(LiteralInstance::F16(
888 f16::from_f64(scalbn(n1.to_f64().unwrap(), *n2)),
889 )),
890 _ => Err(E::Builtin(
891 "`ldexp` with scalar arguments expects a float and a i32 arguments",
892 )),
893 }
894 }
895
896 match (e1, e2) {
898 (Instance::Literal(l1), Instance::Literal(l2)) => ldexp_lit(l1, l2).map(Into::into),
899 (Instance::Vec(v1), Instance::Vec(v2)) => v1.compwise_binary(v2, ldexp_lit).map(Into::into),
900 _ => Err(E::Builtin(
901 "`ldexp` expects two scalar or two vector arguments",
902 )),
903 }
904}
905
906pub fn length(e: &Instance) -> Result<Instance, E> {
910 const ERR: E = E::Builtin("`length` expects a float or vector of float argument");
911 match e {
912 Instance::Literal(_) => abs(e),
913 Instance::Vec(v) => sqrt(
914 &v.op_mul(v, ShaderStage::Exec)?
915 .into_iter()
916 .map(Ok)
917 .reduce(|a, b| a?.op_add(&b?, ShaderStage::Exec))
918 .unwrap()?,
919 ),
920 _ => Err(ERR),
921 }
922}
923
924pub fn log(e: &Instance) -> Result<Instance, E> {
928 impl_call_float_unary!("log", e, n => n.ln())
929}
930
931pub fn log2(e: &Instance) -> Result<Instance, E> {
935 impl_call_float_unary!("log2", e, n => n.log2())
936}
937
938pub fn max(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
942 const ERR: E = E::Builtin("`max` expects a scalar or vector of scalar argument");
943 fn lit_max(e1: &LiteralInstance, e2: &LiteralInstance) -> Result<LiteralInstance, E> {
944 match e1 {
945 LiteralInstance::Bool(_) => Err(ERR),
946 LiteralInstance::AbstractInt(e1) => {
947 Ok(LiteralInstance::from(*e1.max(&e2.unwrap_abstract_int())))
948 }
949 LiteralInstance::AbstractFloat(e1) => {
950 Ok(LiteralInstance::from(e1.max(e2.unwrap_abstract_float())))
951 }
952 LiteralInstance::I32(e1) => Ok(LiteralInstance::from(*e1.max(&e2.unwrap_i32()))),
953 LiteralInstance::U32(e1) => Ok(LiteralInstance::from(*e1.max(&e2.unwrap_u32()))),
954 LiteralInstance::F32(e1) => Ok(LiteralInstance::from(e1.max(e2.unwrap_f32()))),
955 LiteralInstance::F16(e1) => Ok(LiteralInstance::from(e1.max(e2.unwrap_f16()))),
956 #[cfg(feature = "naga-ext")]
957 LiteralInstance::I64(e1) => Ok(LiteralInstance::I64(*e1.max(&e2.unwrap_i64()))),
958 #[cfg(feature = "naga-ext")]
959 LiteralInstance::U64(e1) => Ok(LiteralInstance::U64(*e1.max(&e2.unwrap_u64()))),
960 #[cfg(feature = "naga-ext")]
961 LiteralInstance::F64(e1) => Ok(LiteralInstance::F64(e1.max(e2.unwrap_f64()))),
962 }
963 }
964 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`max` arguments are incompatible"))?;
965 match (e1, e2) {
966 (Instance::Literal(e1), Instance::Literal(e2)) => lit_max(&e1, &e2).map(Into::into),
967 (Instance::Vec(e1), Instance::Vec(e2)) => e1.compwise_binary(&e2, lit_max).map(Into::into),
968 _ => Err(ERR),
969 }
970}
971
972pub fn min(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
976 const ERR: E = E::Builtin("`min` expects a scalar or vector of scalar argument");
977 fn lit_min(e1: &LiteralInstance, e2: &LiteralInstance) -> Result<LiteralInstance, E> {
978 match e1 {
979 LiteralInstance::Bool(_) => Err(ERR),
980 LiteralInstance::AbstractInt(e1) => {
981 Ok(LiteralInstance::from(*e1.min(&e2.unwrap_abstract_int())))
982 }
983 LiteralInstance::AbstractFloat(e1) => {
984 Ok(LiteralInstance::from(e1.min(e2.unwrap_abstract_float())))
985 }
986 LiteralInstance::I32(e1) => Ok(LiteralInstance::from(*e1.min(&e2.unwrap_i32()))),
987 LiteralInstance::U32(e1) => Ok(LiteralInstance::from(*e1.min(&e2.unwrap_u32()))),
988 LiteralInstance::F32(e1) => Ok(LiteralInstance::from(e1.min(e2.unwrap_f32()))),
989 LiteralInstance::F16(e1) => Ok(LiteralInstance::from(e1.min(e2.unwrap_f16()))),
990 #[cfg(feature = "naga-ext")]
991 LiteralInstance::I64(e1) => Ok(LiteralInstance::I64(*e1.max(&e2.unwrap_i64()))),
992 #[cfg(feature = "naga-ext")]
993 LiteralInstance::U64(e1) => Ok(LiteralInstance::U64(*e1.max(&e2.unwrap_u64()))),
994 #[cfg(feature = "naga-ext")]
995 LiteralInstance::F64(e1) => Ok(LiteralInstance::F64(e1.max(e2.unwrap_f64()))),
996 }
997 }
998 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`min` arguments are incompatible"))?;
999 match (e1, e2) {
1000 (Instance::Literal(e1), Instance::Literal(e2)) => lit_min(&e1, &e2).map(Into::into),
1001 (Instance::Vec(e1), Instance::Vec(e2)) => e1.compwise_binary(&e2, lit_min).map(Into::into),
1002 _ => Err(ERR),
1003 }
1004}
1005
1006pub fn mix(e1: &Instance, e2: &Instance, e3: &Instance, stage: ShaderStage) -> Result<Instance, E> {
1010 let tys = [e1.inner_ty(), e2.inner_ty(), e3.inner_ty()];
1011 let inner_ty = convert_all_ty(&tys).ok_or(E::Builtin("`mix` arguments are incompatible"))?;
1012 let e1 = e1.convert_inner_to(inner_ty).unwrap();
1013 let e2 = e2.convert_inner_to(inner_ty).unwrap();
1014 let e3 = e3.convert_inner_to(inner_ty).unwrap();
1015 let (e1, e2) = convert(&e1, &e2).ok_or(E::Builtin("`mix` arguments are incompatible"))?;
1016
1017 let one = Instance::Literal(LiteralInstance::AbstractInt(1));
1019
1020 e1.op_mul(&one.op_sub(&e3, stage)?, stage)?
1021 .op_add(&e2.op_mul(&e3, stage)?, stage)
1022}
1023
1024pub fn modf(_a1: &Instance) -> Result<Instance, E> {
1026 Err(E::Todo("modf".to_string()))
1027}
1028
1029pub fn normalize(e: &Instance, stage: ShaderStage) -> Result<Instance, E> {
1033 e.op_div(&length(e)?, stage)
1034}
1035
1036pub fn pow(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1040 const ERR: E = E::Builtin("`pow` expects a scalar or vector of scalar argument");
1041 fn lit_powf(e1: &LiteralInstance, e2: &LiteralInstance) -> Result<LiteralInstance, E> {
1042 match e1 {
1043 LiteralInstance::Bool(_) => Err(ERR),
1044 LiteralInstance::AbstractInt(_) => {
1045 let e1 = e1
1046 .convert_to(&Type::AbstractFloat)
1047 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1048 .unwrap_abstract_float();
1049 let e2 = e2
1050 .convert_to(&Type::AbstractFloat)
1051 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1052 .unwrap_abstract_float();
1053 Ok(LiteralInstance::from(e1.powf(e2)))
1054 }
1055 LiteralInstance::AbstractFloat(e1) => {
1056 Ok(LiteralInstance::from(e1.powf(e2.unwrap_abstract_float())))
1057 }
1058 LiteralInstance::I32(_) => Err(ERR),
1059 LiteralInstance::U32(_) => Err(ERR),
1060 LiteralInstance::F32(e1) => Ok(LiteralInstance::from(e1.powf(e2.unwrap_f32()))),
1061 LiteralInstance::F16(e1) => Ok(LiteralInstance::from(e1.powf(e2.unwrap_f16()))),
1062 #[cfg(feature = "naga-ext")]
1063 LiteralInstance::I64(_) => Err(ERR),
1064 #[cfg(feature = "naga-ext")]
1065 LiteralInstance::U64(_) => Err(ERR),
1066 #[cfg(feature = "naga-ext")]
1067 LiteralInstance::F64(e1) => Ok(LiteralInstance::F64(e1.powf(e2.unwrap_f64()))),
1068 }
1069 }
1070 let (e1, e2) = convert(e1, e2).ok_or(E::Builtin("`pow` arguments are incompatible"))?;
1071 match (e1, e2) {
1072 (Instance::Literal(e1), Instance::Literal(e2)) => lit_powf(&e1, &e2).map(Into::into),
1073 (Instance::Vec(e1), Instance::Vec(e2)) => e1.compwise_binary(&e2, lit_powf).map(Into::into),
1074 _ => Err(ERR),
1075 }
1076}
1077
1078pub fn quantizeToF16(_a1: &Instance) -> Result<Instance, E> {
1080 Err(E::Todo("quantizeToF16".to_string()))
1081}
1082
1083pub fn radians(e: &Instance) -> Result<Instance, E> {
1087 impl_call_float_unary!("radians", e, n => n.to_radians())
1088}
1089
1090pub fn reflect(_a1: &Instance, _a2: &Instance) -> Result<Instance, E> {
1092 Err(E::Todo("reflect".to_string()))
1093}
1094
1095pub fn refract(_a1: &Instance, _a2: &Instance, _a3: &Instance) -> Result<Instance, E> {
1097 Err(E::Todo("refract".to_string()))
1098}
1099
1100pub fn reverseBits(_a1: &Instance) -> Result<Instance, E> {
1102 Err(E::Todo("reverseBits".to_string()))
1103}
1104
1105pub fn round(e: &Instance) -> Result<Instance, E> {
1109 const ERR: E = E::Builtin("`round` expects a float or vector of float argument");
1110 fn lit_fn(l: &LiteralInstance) -> Result<LiteralInstance, E> {
1111 match l {
1112 LiteralInstance::Bool(_) => Err(ERR),
1113 LiteralInstance::AbstractInt(_) => {
1114 let n = l
1115 .convert_to(&Type::AbstractFloat)
1116 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1117 .unwrap_abstract_float();
1118 Ok(LiteralInstance::from(n.round_ties_even()))
1119 }
1120 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(n.round_ties_even())),
1121 LiteralInstance::I32(_) => Err(ERR),
1122 LiteralInstance::U32(_) => Err(ERR),
1123 LiteralInstance::F32(n) => Ok(LiteralInstance::from(n.round_ties_even())),
1124 LiteralInstance::F16(n) => Ok(LiteralInstance::from(f16::from_f32(
1125 f16::to_f32(*n).round_ties_even(),
1126 ))),
1127 #[cfg(feature = "naga-ext")]
1128 LiteralInstance::I64(_) => Err(ERR),
1129 #[cfg(feature = "naga-ext")]
1130 LiteralInstance::U64(_) => Err(ERR),
1131 #[cfg(feature = "naga-ext")]
1132 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(n.round_ties_even())),
1133 }
1134 }
1135 match e {
1136 Instance::Literal(l) => lit_fn(l).map(Into::into),
1137 Instance::Vec(v) => v.compwise_unary(lit_fn).map(Into::into),
1138 _ => Err(ERR),
1139 }
1140}
1141
1142pub fn saturate(e: &Instance) -> Result<Instance, E> {
1146 match e {
1147 Instance::Literal(_) => {
1148 let zero = LiteralInstance::AbstractFloat(0.0);
1149 let one = LiteralInstance::AbstractFloat(1.0);
1150 clamp(e, &zero.into(), &one.into())
1151 }
1152 Instance::Vec(v) => {
1153 let n = v.n();
1154 let zero = Instance::from(LiteralInstance::AbstractFloat(0.0));
1155 let one = Instance::from(LiteralInstance::AbstractFloat(1.0));
1156 let zero = VecInstance::new((0..n).map(|_| zero.clone()).collect_vec());
1157 let one = VecInstance::new((0..n).map(|_| one.clone()).collect_vec());
1158 clamp(e, &zero.into(), &one.into())
1159 }
1160 _ => Err(E::Builtin(
1161 "`saturate` expects a float or vector of float argument",
1162 )),
1163 }
1164}
1165
1166pub fn sign(e: &Instance) -> Result<Instance, E> {
1170 const ERR: E = E::Builtin(concat!(
1171 "`",
1172 "sign",
1173 "` expects a float or vector of float argument"
1174 ));
1175 fn lit_fn(l: &LiteralInstance) -> Result<LiteralInstance, E> {
1176 match l {
1177 LiteralInstance::Bool(_) => Err(ERR),
1178 LiteralInstance::AbstractInt(n) => Ok(LiteralInstance::from(n.signum())),
1179 LiteralInstance::AbstractFloat(n) => Ok(LiteralInstance::from(if n.is_zero() {
1180 *n
1181 } else {
1182 n.signum()
1183 })),
1184 LiteralInstance::I32(n) => Ok(LiteralInstance::from(n.signum())),
1185 LiteralInstance::U32(n) => Ok(LiteralInstance::from(if n.is_zero() {
1186 *n
1187 } else {
1188 1
1189 })),
1190 LiteralInstance::F32(n) => Ok(LiteralInstance::from(if n.is_zero() {
1191 *n
1192 } else {
1193 n.signum()
1194 })),
1195 LiteralInstance::F16(n) => Ok(LiteralInstance::from(if n.is_zero() {
1196 *n
1197 } else {
1198 n.signum()
1199 })),
1200 #[cfg(feature = "naga-ext")]
1201 LiteralInstance::I64(n) => Ok(LiteralInstance::I64(n.signum())),
1202 #[cfg(feature = "naga-ext")]
1203 LiteralInstance::U64(n) => Ok(LiteralInstance::U64(if n.is_zero() {
1204 *n
1205 } else {
1206 1
1207 })),
1208 #[cfg(feature = "naga-ext")]
1209 LiteralInstance::F64(n) => Ok(LiteralInstance::F64(if n.is_zero() {
1210 *n
1211 } else {
1212 n.signum()
1213 })),
1214 }
1215 }
1216 match e {
1217 Instance::Literal(l) => lit_fn(l).map(Into::into),
1218 Instance::Vec(v) => v.compwise_unary(lit_fn).map(Into::into),
1219 _ => Err(ERR),
1220 }
1221}
1222
1223pub fn sin(e: &Instance) -> Result<Instance, E> {
1227 impl_call_float_unary!("sin", e, n => n.sin())
1228}
1229
1230pub fn sinh(e: &Instance) -> Result<Instance, E> {
1234 impl_call_float_unary!("sinh", e, n => n.sinh())
1235}
1236
1237pub fn smoothstep(_low: &Instance, _high: &Instance, _x: &Instance) -> Result<Instance, E> {
1239 Err(E::Todo("smoothstep".to_string()))
1240}
1241
1242pub fn sqrt(e: &Instance) -> Result<Instance, E> {
1246 impl_call_float_unary!("sqrt", e, n => n.sqrt())
1247}
1248
1249pub fn step(edge: &Instance, x: &Instance) -> Result<Instance, E> {
1253 const ERR: E = E::Builtin("`step` expects a float or vector of float argument");
1254 fn lit_step(edge: &LiteralInstance, x: &LiteralInstance) -> Result<LiteralInstance, E> {
1255 match edge {
1256 LiteralInstance::Bool(_) => Err(ERR),
1257 LiteralInstance::AbstractInt(_) => {
1258 let edge = edge
1259 .convert_to(&Type::AbstractFloat)
1260 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1261 .unwrap_abstract_float();
1262 let x = x
1263 .convert_to(&Type::AbstractFloat)
1264 .ok_or(E::Conversion(Type::AbstractInt, Type::AbstractFloat))?
1265 .unwrap_abstract_float();
1266 Ok(LiteralInstance::from(if edge <= x {
1267 1.0
1268 } else {
1269 0.0
1270 }))
1271 }
1272 LiteralInstance::AbstractFloat(edge) => Ok(LiteralInstance::from(
1273 if *edge <= x.unwrap_abstract_float() {
1274 1.0
1275 } else {
1276 0.0
1277 },
1278 )),
1279 LiteralInstance::I32(_) => Err(ERR),
1280 LiteralInstance::U32(_) => Err(ERR),
1281 LiteralInstance::F32(edge) => Ok(LiteralInstance::from(if *edge <= x.unwrap_f32() {
1282 1.0
1283 } else {
1284 0.0
1285 })),
1286 LiteralInstance::F16(edge) => Ok(LiteralInstance::from(if *edge <= x.unwrap_f16() {
1287 1.0
1288 } else {
1289 0.0
1290 })),
1291 #[cfg(feature = "naga-ext")]
1292 LiteralInstance::I64(_) => Err(ERR),
1293 #[cfg(feature = "naga-ext")]
1294 LiteralInstance::U64(_) => Err(ERR),
1295 #[cfg(feature = "naga-ext")]
1296 LiteralInstance::F64(edge) => Ok(LiteralInstance::F64(if *edge <= x.unwrap_f64() {
1297 1.0
1298 } else {
1299 0.0
1300 })),
1301 }
1302 }
1303 let (edge, x) = convert(edge, x).ok_or(E::Builtin("`step` arguments are incompatible"))?;
1304 match (edge, x) {
1305 (Instance::Literal(edge), Instance::Literal(x)) => lit_step(&edge, &x).map(Into::into),
1306 (Instance::Vec(edge), Instance::Vec(x)) => {
1307 edge.compwise_binary(&x, lit_step).map(Into::into)
1308 }
1309 _ => Err(ERR),
1310 }
1311}
1312
1313pub fn tan(e: &Instance) -> Result<Instance, E> {
1317 impl_call_float_unary!("tan", e, n => n.tan())
1318}
1319
1320pub fn tanh(e: &Instance) -> Result<Instance, E> {
1324 impl_call_float_unary!("tanh", e, n => n.tanh())
1325}
1326
1327pub fn transpose(e: &Instance) -> Result<Instance, E> {
1331 match e {
1332 Instance::Mat(e) => Ok(e.transpose().into()),
1333 _ => Err(E::Builtin("`transpose` expects a matrix argument")),
1334 }
1335}
1336
1337pub fn trunc(e: &Instance) -> Result<Instance, E> {
1341 impl_call_float_unary!("trunc", e, n => n.trunc())
1342}
1343
1344pub fn atomicLoad(e: &Instance) -> Result<Instance, E> {
1353 let err = E::Builtin("`atomicLoad` expects a pointer to atomic argument");
1354 if let Instance::Ptr(ptr) = e {
1355 let inst = ptr.ptr.read()?;
1357 if let Instance::Atomic(inst) = &*inst {
1358 Ok(inst.inner().clone())
1359 } else {
1360 Err(err)
1361 }
1362 } else {
1363 Err(err)
1364 }
1365}
1366
1367pub fn atomicStore(e1: &Instance, e2: &Instance) -> Result<(), E> {
1371 let err = E::Builtin("`atomicStore` expects a pointer to atomic argument");
1372 if let Instance::Ptr(ptr) = e1 {
1373 let mut inst = ptr.ptr.read_write()?;
1374 if let Instance::Atomic(inst) = &mut *inst {
1375 let ty = inst.inner().ty();
1376 let e2 = e2
1377 .convert_to(&ty)
1378 .ok_or_else(|| E::ParamType(ty, e2.ty()))?;
1379 *inst = AtomicInstance::new(e2);
1380 Ok(())
1381 } else {
1382 Err(err)
1383 }
1384 } else {
1385 Err(err)
1386 }
1387}
1388
1389pub fn atomicSub(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1393 let initial = atomicLoad(e1)?;
1394 atomicStore(e1, &initial.op_sub(e2, ShaderStage::Exec)?)?;
1395 Ok(initial)
1396}
1397
1398pub fn atomicMax(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1402 let initial = atomicLoad(e1)?;
1403 atomicStore(e1, &max(&initial, e2)?)?;
1404 Ok(initial)
1405}
1406
1407pub fn atomicMin(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1411 let initial = atomicLoad(e1)?;
1412 atomicStore(e1, &max(&initial, e2)?)?;
1413 Ok(initial)
1414}
1415
1416pub fn atomicAnd(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1420 let initial = atomicLoad(e1)?;
1421 atomicStore(e1, &initial.op_bitand(e2)?)?;
1422 Ok(initial)
1423}
1424
1425pub fn atomicOr(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1429 let initial = atomicLoad(e1)?;
1430 atomicStore(e1, &initial.op_bitor(e2)?)?;
1431 Ok(initial)
1432}
1433
1434pub fn atomicXor(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1438 let initial = atomicLoad(e1)?;
1439 atomicStore(e1, &initial.op_bitxor(e2)?)?;
1440 Ok(initial)
1441}
1442
1443pub fn atomicExchange(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1447 let initial = atomicLoad(e1)?;
1448 atomicStore(e1, e2)?;
1449 Ok(initial)
1450}
1451
1452pub fn atomicCompareExchangeWeak(e1: &Instance, e2: &Instance) -> Result<Instance, E> {
1456 let initial = atomicLoad(e1)?;
1457 let exchanged = if initial == *e2 {
1458 false
1459 } else {
1460 atomicStore(e1, e2)?;
1461 true
1462 };
1463 Ok(Instance::Struct(StructInstance::new(
1464 atomic_compare_exchange_struct_type(&initial.ty()),
1465 vec![initial, LiteralInstance::Bool(exchanged).into()],
1466 )))
1467}
1468
1469pub fn pack4x8snorm(e: &Instance) -> Result<Instance, E> {
1478 const ERR: E = E::Builtin("`pack4x8snorm` expects a `vec4<f32>` argument");
1479
1480 let v = e
1481 .convert_to(&Type::Vec(4, Type::F32.into()))
1482 .ok_or(ERR)?
1483 .unwrap_vec();
1484
1485 let mut result = 0u32;
1486 for i in 0..4 {
1487 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1488 let bits = (0.5 + 127.0 * val.clamp(-1.0, 1.0)).floor() as i8 as u8;
1489 result |= (bits as u32) << (8 * i);
1490 }
1491 Ok(LiteralInstance::U32(result).into())
1492}
1493
1494pub fn pack4x8unorm(e: &Instance) -> Result<Instance, E> {
1498 const ERR: E = E::Builtin("`pack4x8unorm` expects a `vec4<f32>` argument");
1499
1500 let v = e
1501 .convert_to(&Type::Vec(4, Type::F32.into()))
1502 .ok_or(ERR)?
1503 .unwrap_vec();
1504
1505 let mut result = 0u32;
1506 for i in 0..4 {
1507 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1508 let bits = (0.5 + 255.0 * val.clamp(0.0, 1.0)).floor() as u8;
1509 result |= (bits as u32) << (8 * i);
1510 }
1511 Ok(LiteralInstance::U32(result).into())
1512}
1513
1514pub fn pack4xI8(e: &Instance) -> Result<Instance, E> {
1518 const ERR: E = E::Builtin("`pack4xI8` expects a `vec4<i32>` argument");
1519
1520 let v = e
1521 .convert_to(&Type::Vec(4, Type::I32.into()))
1522 .ok_or(ERR)?
1523 .unwrap_vec();
1524
1525 let mut result = 0u32;
1526 for i in 0..4 {
1527 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_i32();
1528 result |= (val as u8 as u32) << (8 * i);
1529 }
1530 Ok(LiteralInstance::U32(result).into())
1531}
1532
1533pub fn pack4xU8(e: &Instance) -> Result<Instance, E> {
1537 const ERR: E = E::Builtin("`pack4xU8` expects a `vec4<u32>` argument");
1538
1539 let v = e
1540 .convert_to(&Type::Vec(4, Type::U32.into()))
1541 .ok_or(ERR)?
1542 .unwrap_vec();
1543
1544 let mut result = 0u32;
1545 for i in 0..4 {
1546 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_u32();
1547 result |= (val as u8 as u32) << (8 * i);
1548 }
1549 Ok(LiteralInstance::U32(result).into())
1550}
1551
1552pub fn pack4xI8Clamp(e: &Instance) -> Result<Instance, E> {
1556 const ERR: E = E::Builtin("`pack4xI8Clamp` expects a `vec4<i32>` argument");
1557
1558 let v = e
1559 .convert_to(&Type::Vec(4, Type::I32.into()))
1560 .ok_or(ERR)?
1561 .unwrap_vec();
1562
1563 let mut result = 0u32;
1564 for i in 0..4 {
1565 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_i32();
1566 result |= (val as i8 as u32) << (8 * i);
1567 }
1568 Ok(LiteralInstance::U32(result).into())
1569}
1570
1571pub fn pack4xU8Clamp(e: &Instance) -> Result<Instance, E> {
1575 const ERR: E = E::Builtin("`pack4xU8Clamp` expects a `vec4<u32>` argument");
1576
1577 let v = e
1578 .convert_to(&Type::Vec(4, Type::U32.into()))
1579 .ok_or(ERR)?
1580 .unwrap_vec();
1581
1582 let mut result = 0u32;
1583 for i in 0..4 {
1584 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_u32();
1585 result |= (val as u8 as u32) << (8 * i);
1586 }
1587 Ok(LiteralInstance::U32(result).into())
1588}
1589
1590pub fn pack2x16snorm(e: &Instance) -> Result<Instance, E> {
1594 const ERR: E = E::Builtin("`pack2x16snorm` expects a `vec2<f32>` argument");
1595
1596 let v = e
1597 .convert_to(&Type::Vec(2, Type::F32.into()))
1598 .ok_or(ERR)?
1599 .unwrap_vec();
1600
1601 let mut result = 0u32;
1602 for i in 0..2 {
1603 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1604 let bits = (0.5 + 32767.0 * val.clamp(-1.0, 1.0)).floor() as i16 as u16;
1605 result |= (bits as u32) << (16 * i);
1606 }
1607 Ok(LiteralInstance::U32(result).into())
1608}
1609
1610pub fn pack2x16unorm(e: &Instance) -> Result<Instance, E> {
1614 const ERR: E = E::Builtin("`pack2x16unorm` expects a `vec2<f32>` argument");
1615
1616 let v = e
1617 .convert_to(&Type::Vec(2, Type::F32.into()))
1618 .ok_or(ERR)?
1619 .unwrap_vec();
1620
1621 let mut result = 0u32;
1622 for i in 0..2 {
1623 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1624 let bits = (0.5 + 65535.0 * val.clamp(0.0, 1.0)).floor() as u16;
1625 result |= (bits as u32) << (16 * i);
1626 }
1627 Ok(LiteralInstance::U32(result).into())
1628}
1629
1630pub fn pack2x16float(e: &Instance) -> Result<Instance, E> {
1634 const ERR: E = E::Builtin("`pack2x16float` expects a `vec2<f32>` argument");
1635
1636 let v = e
1637 .convert_to(&Type::Vec(2, Type::F32.into()))
1638 .ok_or(ERR)?
1639 .unwrap_vec();
1640
1641 let mut result = 0u32;
1642 for i in 0..2 {
1643 let val = v.get(i).unwrap().unwrap_literal_ref().unwrap_f32();
1644 let bits = f16::from_f32(val).to_bits();
1645 result |= (bits as u32) << (16 * i);
1646 }
1647 Ok(LiteralInstance::U32(result).into())
1648}
1649
1650pub fn unpack4x8snorm(e: &Instance) -> Result<Instance, E> {
1654 const ERR: E = E::Builtin("`unpack4x8snorm` expects a `u32` argument");
1655
1656 let e = e
1657 .convert_to(&Type::U32)
1658 .ok_or(ERR)?
1659 .unwrap_literal()
1660 .unwrap_u32();
1661
1662 let comps = e
1663 .to_le_bytes()
1664 .map(|c| ((c as i8 as f32) / 127.0).max(-1.0))
1665 .map(Instance::from)
1666 .to_vec();
1667
1668 Ok(VecInstance::new(comps).into())
1669}
1670
1671pub fn unpack4x8unorm(e: &Instance) -> Result<Instance, E> {
1675 const ERR: E = E::Builtin("`unpack4x8unorm` expects a `u32` argument");
1676
1677 let e = e
1678 .convert_to(&Type::U32)
1679 .ok_or(ERR)?
1680 .unwrap_literal()
1681 .unwrap_u32();
1682
1683 let comps = e
1684 .to_le_bytes()
1685 .map(|c| (c as f32) / 255.0)
1686 .map(Instance::from)
1687 .to_vec();
1688
1689 Ok(VecInstance::new(comps).into())
1690}
1691
1692pub fn unpack4xI8(e: &Instance) -> Result<Instance, E> {
1696 const ERR: E = E::Builtin("`unpack4xI8` expects a `u32` argument");
1697
1698 let e = e
1699 .convert_to(&Type::U32)
1700 .ok_or(ERR)?
1701 .unwrap_literal()
1702 .unwrap_u32();
1703
1704 let comps = e
1705 .to_le_bytes()
1706 .map(|c| c as i8 as i32)
1707 .map(Instance::from)
1708 .to_vec();
1709
1710 Ok(VecInstance::new(comps).into())
1711}
1712
1713pub fn unpack4xU8(e: &Instance) -> Result<Instance, E> {
1717 const ERR: E = E::Builtin("`unpack4xU8` expects a `u32` argument");
1718
1719 let e = e
1720 .convert_to(&Type::U32)
1721 .ok_or(ERR)?
1722 .unwrap_literal()
1723 .unwrap_u32();
1724
1725 let comps = e
1726 .to_le_bytes()
1727 .map(|c| c as u32)
1728 .map(Instance::from)
1729 .to_vec();
1730
1731 Ok(VecInstance::new(comps).into())
1732}
1733
1734pub fn unpack2x16snorm(e: &Instance) -> Result<Instance, E> {
1738 const ERR: E = E::Builtin("`unpack2x16snorm` expects a `u32` argument");
1739
1740 let e = e
1741 .convert_to(&Type::U32)
1742 .ok_or(ERR)?
1743 .unwrap_literal()
1744 .unwrap_u32();
1745
1746 let lsb = e as u16 as i16;
1747 let msb = (e >> 16) as u16 as i16;
1748
1749 let comps = [lsb, msb]
1750 .map(|c| ((c as f32) / 32767.0).max(-1.0))
1751 .map(Instance::from)
1752 .to_vec();
1753
1754 Ok(VecInstance::new(comps).into())
1755}
1756
1757pub fn unpack2x16unorm(e: &Instance) -> Result<Instance, E> {
1761 const ERR: E = E::Builtin("`unpack2x16unorm` expects a `u32` argument");
1762
1763 let e = e
1764 .convert_to(&Type::U32)
1765 .ok_or(ERR)?
1766 .unwrap_literal()
1767 .unwrap_u32();
1768
1769 let lsb = e as u16;
1770 let msb = (e >> 16) as u16;
1771
1772 let comps = [lsb, msb]
1773 .map(|c| (c as f32) / 65535.0)
1774 .map(Instance::from)
1775 .to_vec();
1776
1777 Ok(VecInstance::new(comps).into())
1778}
1779
1780pub fn unpack2x16float(e: &Instance) -> Result<Instance, E> {
1784 const ERR: E = E::Builtin("`unpack2x16float` expects a `u32` argument");
1785
1786 let e = e
1787 .convert_to(&Type::U32)
1788 .ok_or(ERR)?
1789 .unwrap_literal()
1790 .unwrap_u32();
1791
1792 let lsb = e as u16;
1793 let msb = (e >> 16) as u16;
1794
1795 let comps = [lsb, msb]
1796 .map(|c| f16::from_bits(c).to_f32())
1797 .map(Instance::from)
1798 .to_vec();
1799
1800 Ok(VecInstance::new(comps).into())
1801}
1802
1803impl VecInstance {
1804 pub fn dot(&self, rhs: &VecInstance, stage: ShaderStage) -> Result<LiteralInstance, E> {
1806 self.compwise_binary(rhs, |a, b| a.op_mul(b, stage))?
1807 .into_iter()
1808 .map(|c| Ok(c.unwrap_literal()))
1809 .reduce(|a, b| a?.op_add(&b?, stage))
1810 .unwrap()
1811 }
1812}
1813
1814impl MatInstance {
1815 pub fn transpose(&self) -> MatInstance {
1817 let components = (0..self.r())
1818 .map(|j| {
1819 VecInstance::new(
1820 (0..self.c())
1821 .map(|i| self.get(i, j).unwrap().clone())
1822 .collect_vec(),
1823 )
1824 .into()
1825 })
1826 .collect_vec();
1827 MatInstance::from_cols(components)
1828 }
1829}