1use itertools::Itertools;
9use num_traits::{FromPrimitive, ToPrimitive};
10
11use crate::{
12 Error, Instance, f16,
13 inst::{ArrayInstance, LiteralInstance, MatInstance, StructInstance, VecInstance},
14 syntax::AccessMode,
15 ty::{Ty, Type},
16};
17
18pub trait Convert: Sized + Clone + Ty {
19 fn convert_to(&self, ty: &Type) -> Option<Self>;
25
26 fn convert_inner_to(&self, ty: &Type) -> Option<Self> {
38 self.convert_to(ty)
39 }
40
41 fn concretize(&self) -> Option<Self> {
45 self.convert_to(&self.ty().concretize())
46 }
47}
48
49impl Convert for Type {
50 fn convert_to(&self, ty: &Type) -> Option<Self> {
51 self.is_convertible_to(ty).then_some(ty.clone())
52 }
53 fn convert_inner_to(&self, ty: &Type) -> Option<Self> {
54 match self {
55 Type::Array(inner, n) => inner
56 .convert_to(ty)
57 .map(|inner| Type::Array(inner.into(), *n)),
58 Type::Vec(n, inner) => inner
59 .convert_to(ty)
60 .map(|inner| Type::Vec(*n, inner.into())),
61 Type::Mat(c, r, inner) => inner
62 .convert_to(ty)
63 .map(|inner| Type::Mat(*c, *r, inner.into())),
64 Type::Atomic(_) => (self == ty).then_some(ty.clone()),
65 Type::Ptr(_, _, _) => (self == ty).then_some(ty.clone()),
66 _ => self.convert_to(ty), }
68 }
69 fn concretize(&self) -> Option<Self> {
70 Some(self.concretize())
71 }
72}
73
74impl Type {
75 pub fn is_convertible_to(&self, ty: &Type) -> bool {
76 conversion_rank(self, ty).is_some()
77 }
78 pub fn concretize(&self) -> Self {
79 match self {
80 Self::AbstractInt => Type::I32,
81 Self::AbstractFloat => Type::F32,
82 Self::Array(ty, n) => Type::Array(ty.concretize().into(), *n),
83 Self::Vec(n, ty) => Type::Vec(*n, ty.concretize().into()),
84 Self::Mat(c, r, ty) if ty.is_abstract() => Type::Mat(*c, *r, Type::F32.into()),
85 _ => self.clone(),
86 }
87 }
88
89 pub fn loaded(self) -> Self {
93 if let Type::Ref(_, ty, _) = self {
94 ty.loaded()
95 } else {
96 self
97 }
98 }
99}
100
101impl Instance {
102 pub fn is_convertible_to(&self, ty: &Type) -> bool {
103 self.ty().is_convertible_to(ty)
104 }
105
106 pub fn loaded(mut self) -> Result<Self, Error> {
110 while let Instance::Ref(r) = self {
111 self = r.read()?.to_owned();
112 }
113 Ok(self)
114 }
115}
116
117impl LiteralInstance {
118 pub fn is_infinite(&self) -> bool {
119 match self {
120 LiteralInstance::Bool(_) => false,
121 LiteralInstance::AbstractInt(_) => false,
122 LiteralInstance::AbstractFloat(n) => n.is_infinite(),
123 LiteralInstance::I32(_) => false,
124 LiteralInstance::U32(_) => false,
125 LiteralInstance::F32(n) => n.is_infinite(),
126 LiteralInstance::F16(n) => n.is_infinite(),
127 #[cfg(feature = "naga-ext")]
128 LiteralInstance::I64(_) => false,
129 #[cfg(feature = "naga-ext")]
130 LiteralInstance::U64(_) => false,
131 #[cfg(feature = "naga-ext")]
132 LiteralInstance::F64(n) => n.is_infinite(),
133 }
134 }
135 pub fn is_finite(&self) -> bool {
136 !self.is_infinite()
137 }
138}
139
140impl Convert for LiteralInstance {
141 fn convert_to(&self, ty: &Type) -> Option<Self> {
142 if ty == &self.ty() {
143 return Some(*self);
144 }
145
146 match (self, ty) {
151 (Self::AbstractInt(n), Type::AbstractFloat) => n.to_f64().map(Self::AbstractFloat),
152 (Self::AbstractInt(n), Type::I32) => n.to_i32().map(Self::I32),
153 (Self::AbstractInt(n), Type::U32) => n.to_u32().map(Self::U32),
154 (Self::AbstractInt(n), Type::F32) => n.to_f32().map(Self::F32),
155 (Self::AbstractInt(n), Type::F16) => f16::from_i64(*n).map(Self::F16),
156 (Self::AbstractFloat(n), Type::F32) => n.to_f32().map(Self::F32),
157 (Self::AbstractFloat(n), Type::F16) => Some(Self::F16(f16::from_f64(*n))),
158 _ => None,
159 }
160 .and_then(|n| n.is_finite().then_some(n))
161 }
162}
163
164impl Convert for ArrayInstance {
165 fn convert_to(&self, ty: &Type) -> Option<Self> {
166 if let Type::Array(c_ty, Some(n)) = ty {
167 if *n == self.n() {
168 self.convert_inner_to(c_ty)
169 } else {
170 None
171 }
172 } else if let Type::Array(c_ty, None) = ty {
173 self.convert_inner_to(c_ty)
174 } else {
175 None
176 }
177 }
178 fn convert_inner_to(&self, ty: &Type) -> Option<Self> {
179 let components = self
180 .iter()
181 .map(|c| c.convert_to(ty))
182 .collect::<Option<Vec<_>>>()?;
183 Some(ArrayInstance::new(components, self.runtime_sized))
184 }
185}
186
187impl Convert for VecInstance {
188 fn convert_to(&self, ty: &Type) -> Option<Self> {
189 if let Type::Vec(n, c_ty) = ty {
190 if *n as usize == self.n() {
191 self.convert_inner_to(c_ty)
192 } else {
193 None
194 }
195 } else {
196 None
197 }
198 }
199 fn convert_inner_to(&self, ty: &Type) -> Option<Self> {
200 let components = self
201 .iter()
202 .map(|c| c.convert_to(ty))
203 .collect::<Option<Vec<_>>>()?;
204 Some(VecInstance::new(components))
205 }
206}
207
208impl Convert for MatInstance {
209 fn convert_to(&self, ty: &Type) -> Option<Self> {
210 if let Type::Mat(c, r, c_ty) = ty {
211 if *c as usize == self.c() && *r as usize == self.r() {
212 self.convert_inner_to(c_ty)
213 } else {
214 None
215 }
216 } else {
217 None
218 }
219 }
220 fn convert_inner_to(&self, ty: &Type) -> Option<Self> {
221 let components = self
222 .iter_cols()
223 .map(|c| c.convert_inner_to(ty))
224 .collect::<Option<Vec<_>>>()?;
225 Some(MatInstance::from_cols(components))
226 }
227}
228
229impl Convert for StructInstance {
230 fn convert_to(&self, ty: &Type) -> Option<Self> {
231 if &self.ty() == ty {
232 Some(self.clone())
233 } else if let Type::Struct(s2) = ty {
234 let s1 = &self.ty;
235 if s1.name.starts_with("__") && s2.name.starts_with("__") {
236 if s2.name.ends_with("f32") {
241 let members = self
242 .members
243 .iter()
244 .map(|inst| inst.convert_inner_to(&Type::F32))
245 .collect::<Option<Vec<_>>>()?;
246 Some(StructInstance::new((**s2).clone(), members))
247 } else if s2.name.ends_with("f16") {
248 let members = self
249 .members
250 .iter()
251 .map(|inst| inst.convert_inner_to(&Type::F16))
252 .collect::<Option<Vec<_>>>()?;
253 Some(StructInstance::new((**s2).clone(), members))
254 } else {
255 None
256 }
257 } else {
258 None
259 }
260 } else {
261 None
262 }
263 }
264}
265
266impl Convert for Instance {
267 fn convert_to(&self, ty: &Type) -> Option<Self> {
268 if &self.ty() == ty {
269 return Some(self.clone());
270 }
271 match self {
272 Self::Literal(l) => l.convert_to(ty).map(Self::Literal),
273 Self::Struct(s) => s.convert_to(ty).map(Self::Struct),
274 Self::Array(a) => a.convert_to(ty).map(Self::Array),
275 Self::Vec(v) => v.convert_to(ty).map(Self::Vec),
276 Self::Mat(m) => m.convert_to(ty).map(Self::Mat),
277 Self::Ptr(_) => None,
278 Self::Ref(r) => r.read().ok().and_then(|r| r.convert_to(ty)), Self::Atomic(_) => None,
280 Self::Opaque(_) => None,
281 }
282 }
283
284 fn convert_inner_to(&self, ty: &Type) -> Option<Self> {
285 match self {
286 Self::Literal(l) => l.convert_inner_to(ty).map(Self::Literal),
287 Self::Struct(_) => None,
288 Self::Array(a) => a.convert_inner_to(ty).map(Self::Array),
289 Self::Vec(v) => v.convert_inner_to(ty).map(Self::Vec),
290 Self::Mat(m) => m.convert_inner_to(ty).map(Self::Mat),
291 Self::Ptr(_) => None,
292 Self::Ref(r) => r.read().ok().and_then(|r| r.convert_inner_to(ty)), Self::Atomic(_) => None,
294 Self::Opaque(_) => None,
295 }
296 }
297}
298
299pub fn conversion_rank(ty1: &Type, ty2: &Type) -> Option<u32> {
301 match (ty1, ty2) {
303 (_, _) if ty1 == ty2 => Some(0),
304 (Type::Ref(_, ty1, AccessMode::Read | AccessMode::ReadWrite), ty2) if &**ty1 == ty2 => {
305 Some(0)
306 }
307 (Type::AbstractInt, Type::AbstractFloat) => Some(5),
308 (Type::AbstractInt, Type::I32) => Some(3),
309 (Type::AbstractInt, Type::U32) => Some(4),
310 (Type::AbstractInt, Type::F32) => Some(6),
311 (Type::AbstractInt, Type::F16) => Some(7),
312 (Type::AbstractFloat, Type::F32) => Some(1),
313 (Type::AbstractFloat, Type::F16) => Some(2),
314 (Type::Struct(s1), Type::Struct(s2)) => {
316 if s1.name.starts_with("__") && s1.name.ends_with("abstract") {
317 if s2.name.ends_with("f32") {
318 Some(1)
319 } else if s2.name.ends_with("f16") {
320 Some(2)
321 } else {
322 None
323 }
324 } else {
325 None
326 }
327 }
328 (Type::Array(ty1, n1), Type::Array(ty2, n2)) if n1 == n2 => conversion_rank(ty1, ty2),
329 (Type::Vec(n1, ty1), Type::Vec(n2, ty2)) if n1 == n2 => conversion_rank(ty1, ty2),
330 (Type::Mat(c1, r1, ty1), Type::Mat(c2, r2, ty2)) if c1 == c2 && r1 == r2 => {
331 conversion_rank(ty1, ty2)
332 }
333 _ => None,
334 }
335}
336
337pub fn convert<T: Convert + Ty + Clone>(i1: &T, i2: &T) -> Option<(T, T)> {
340 let (ty1, ty2) = (i1.ty(), i2.ty());
341 let ty = convert_ty(&ty1, &ty2)?;
342 let i1 = i1.convert_to(ty)?;
343 let i2 = i2.convert_to(ty)?;
344 Some((i1, i2))
345}
346
347pub fn convert_inner<T1: Convert + Ty + Clone, T2: Convert + Ty + Clone>(
349 i1: &T1,
350 i2: &T2,
351) -> Option<(T1, T2)> {
352 let (ty1, ty2) = (i1.inner_ty(), i2.inner_ty());
353 let ty = convert_ty(&ty1, &ty2)?;
354 let i1 = i1.convert_inner_to(ty)?;
355 let i2 = i2.convert_inner_to(ty)?;
356 Some((i1, i2))
357}
358
359pub fn convert_all<'a, T: Convert + Ty + Clone + 'a>(insts: &[T]) -> Option<Vec<T>> {
361 let tys = insts.iter().map(|i| i.ty()).collect_vec();
362 let ty = convert_all_ty(&tys)?;
363 convert_all_to(insts, ty)
364}
365
366pub fn convert_all_to<'a, T: Convert + Ty + Clone + 'a>(insts: &[T], ty: &Type) -> Option<Vec<T>> {
368 insts
369 .iter()
370 .map(|inst| inst.convert_to(ty))
371 .collect::<Option<Vec<_>>>()
372}
373
374pub fn convert_all_inner_to<'a, T: Convert + Ty + Clone + 'a>(
376 insts: &[T],
377 ty: &Type,
378) -> Option<Vec<T>> {
379 insts
380 .iter()
381 .map(|inst| inst.convert_inner_to(ty))
382 .collect::<Option<Vec<_>>>()
383}
384
385pub fn convert_ty<'a>(ty1: &'a Type, ty2: &'a Type) -> Option<&'a Type> {
388 conversion_rank(ty1, ty2)
389 .map(|_rank| ty2)
390 .or_else(|| conversion_rank(ty2, ty1).map(|_rank| ty1))
391}
392
393pub fn convert_all_ty<'a>(tys: impl IntoIterator<Item = &'a Type> + 'a) -> Option<&'a Type> {
395 tys.into_iter()
396 .map(Option::Some)
397 .reduce(|ty1, ty2| convert_ty(ty1?, ty2?))
398 .flatten()
399}