1use crate::backend::BackendStorage;
2use crate::op::{self, CmpOp, ReduceOp};
3use crate::scalar::Scalar;
4#[cfg(feature = "rocm")]
5use crate::RocmStorage;
6#[cfg(feature = "vulkan")]
7use crate::VulkanStorage;
8#[cfg(feature = "wgpu")]
9use crate::WgpuStorage;
10use crate::{CpuStorage, CudaStorage, DType, Device, Error, Layout, MetalStorage, Result, Shape};
11use crate::{CustomOp1, CustomOp2, CustomOp3, InplaceOp1, InplaceOp2, InplaceOp3};
12
13#[derive(Debug)]
16pub enum Storage {
17 Cpu(CpuStorage),
18 Cuda(CudaStorage),
19 Metal(MetalStorage),
20 #[cfg(feature = "rocm")]
21 Rocm(RocmStorage),
22 #[cfg(feature = "vulkan")]
23 Vulkan(VulkanStorage),
24 #[cfg(feature = "wgpu")]
25 Wgpu(WgpuStorage),
26}
27
28impl Storage {
29 pub fn try_clone(&self, layout: &Layout) -> Result<Self> {
30 match self {
31 Self::Cpu(storage) => Ok(Self::Cpu(storage.clone())),
32 Self::Cuda(storage) => {
33 let storage = storage.try_clone(layout)?;
34 Ok(Self::Cuda(storage))
35 }
36 Self::Metal(storage) => {
37 let storage = storage.try_clone(layout)?;
38 Ok(Self::Metal(storage))
39 }
40 #[cfg(feature = "rocm")]
41 Self::Rocm(storage) => {
42 let storage = storage.try_clone(layout)?;
43 Ok(Self::Rocm(storage))
44 }
45 #[cfg(feature = "vulkan")]
46 Self::Vulkan(storage) => {
47 let storage = storage.try_clone(layout)?;
48 Ok(Self::Vulkan(storage))
49 }
50 #[cfg(feature = "wgpu")]
51 Self::Wgpu(storage) => {
52 let storage = storage.try_clone(layout)?;
53 Ok(Self::Wgpu(storage))
54 }
55 }
56 }
57
58 pub fn device(&self) -> Device {
59 match self {
60 Self::Cpu(_) => Device::Cpu,
61 Self::Cuda(storage) => Device::Cuda(storage.device().clone()),
62 Self::Metal(storage) => Device::Metal(storage.device().clone()),
63 #[cfg(feature = "rocm")]
64 Self::Rocm(storage) => Device::Rocm(storage.device().clone()),
65 #[cfg(feature = "vulkan")]
66 Self::Vulkan(storage) => Device::Vulkan(storage.device().clone()),
67 #[cfg(feature = "wgpu")]
68 Self::Wgpu(storage) => Device::Wgpu(storage.device().clone()),
69 }
70 }
71
72 pub fn dtype(&self) -> DType {
73 match self {
74 Self::Cpu(storage) => storage.dtype(),
75 Self::Cuda(storage) => storage.dtype(),
76 Self::Metal(storage) => storage.dtype(),
77 #[cfg(feature = "rocm")]
78 Self::Rocm(storage) => storage.dtype(),
79 #[cfg(feature = "vulkan")]
80 Self::Vulkan(storage) => storage.dtype(),
81 #[cfg(feature = "wgpu")]
82 Self::Wgpu(storage) => storage.dtype(),
83 }
84 }
85
86 pub(crate) fn same_device(&self, rhs: &Self, op: &'static str) -> Result<()> {
87 let lhs_device = self.device();
88 let rhs_device = rhs.device();
89 let lhs = lhs_device.location();
90 let rhs = rhs_device.location();
91 let same_device = if self.device().is_metal() {
92 lhs_device.same_device(&rhs_device)
96 } else {
97 lhs == rhs
98 };
99 if !same_device {
100 Err(Error::DeviceMismatchBinaryOp { lhs, rhs, op }.bt())
101 } else {
102 Ok(())
103 }
104 }
105
106 pub(crate) fn same_dtype(&self, rhs: &Self, op: &'static str) -> Result<()> {
107 let lhs = self.dtype();
108 let rhs = rhs.dtype();
109 if lhs != rhs {
110 Err(Error::DTypeMismatchBinaryOp { lhs, rhs, op }.bt())
111 } else {
112 Ok(())
113 }
114 }
115
116 pub(crate) fn const_set(&mut self, v: Scalar, l: &Layout) -> Result<()> {
117 match self {
118 Storage::Cpu(storage) => storage.const_set(v, l),
119 Storage::Cuda(storage) => storage.const_set(v, l),
120 Storage::Metal(storage) => storage.const_set(v, l),
121 #[cfg(feature = "rocm")]
122 Storage::Rocm(storage) => storage.const_set(v, l),
123 #[cfg(feature = "vulkan")]
124 Storage::Vulkan(storage) => storage.const_set(v, l),
125 #[cfg(feature = "wgpu")]
126 Storage::Wgpu(storage) => storage.const_set(v, l),
127 }
128 }
129
130 pub(crate) fn affine(&self, layout: &Layout, mul: f64, add: f64) -> Result<Self> {
131 match self {
132 Storage::Cpu(storage) => {
133 let storage = storage.affine(layout, mul, add)?;
134 Ok(Self::Cpu(storage))
135 }
136 Self::Cuda(storage) => {
137 let storage = storage.affine(layout, mul, add)?;
138 Ok(Self::Cuda(storage))
139 }
140 Self::Metal(storage) => {
141 let storage = storage.affine(layout, mul, add)?;
142 Ok(Self::Metal(storage))
143 }
144 #[cfg(feature = "rocm")]
145 Self::Rocm(storage) => {
146 let storage = storage.affine(layout, mul, add)?;
147 Ok(Self::Rocm(storage))
148 }
149 #[cfg(feature = "vulkan")]
150 Self::Vulkan(storage) => {
151 let storage = storage.affine(layout, mul, add)?;
152 Ok(Self::Vulkan(storage))
153 }
154 #[cfg(feature = "wgpu")]
155 Self::Wgpu(storage) => {
156 let storage = storage.affine(layout, mul, add)?;
157 Ok(Self::Wgpu(storage))
158 }
159 }
160 }
161
162 pub(crate) fn powf(&self, layout: &Layout, alpha: f64) -> Result<Self> {
163 match self {
164 Storage::Cpu(storage) => {
165 let storage = storage.powf(layout, alpha)?;
166 Ok(Self::Cpu(storage))
167 }
168 Self::Cuda(storage) => {
169 let storage = storage.powf(layout, alpha)?;
170 Ok(Self::Cuda(storage))
171 }
172 Self::Metal(storage) => {
173 let storage = storage.powf(layout, alpha)?;
174 Ok(Self::Metal(storage))
175 }
176 #[cfg(feature = "rocm")]
177 Self::Rocm(storage) => {
178 let storage = storage.powf(layout, alpha)?;
179 Ok(Self::Rocm(storage))
180 }
181 #[cfg(feature = "vulkan")]
182 Self::Vulkan(storage) => {
183 let storage = storage.powf(layout, alpha)?;
184 Ok(Self::Vulkan(storage))
185 }
186 #[cfg(feature = "wgpu")]
187 Self::Wgpu(storage) => {
188 let storage = storage.powf(layout, alpha)?;
189 Ok(Self::Wgpu(storage))
190 }
191 }
192 }
193
194 pub(crate) fn elu(&self, layout: &Layout, alpha: f64) -> Result<Self> {
195 match self {
196 Storage::Cpu(storage) => {
197 let storage = storage.elu(layout, alpha)?;
198 Ok(Self::Cpu(storage))
199 }
200 Self::Cuda(storage) => {
201 let storage = storage.elu(layout, alpha)?;
202 Ok(Self::Cuda(storage))
203 }
204 Self::Metal(storage) => {
205 let storage = storage.elu(layout, alpha)?;
206 Ok(Self::Metal(storage))
207 }
208 #[cfg(feature = "rocm")]
209 Self::Rocm(storage) => {
210 let storage = storage.elu(layout, alpha)?;
211 Ok(Self::Rocm(storage))
212 }
213 #[cfg(feature = "vulkan")]
214 Self::Vulkan(storage) => {
215 let storage = storage.elu(layout, alpha)?;
216 Ok(Self::Vulkan(storage))
217 }
218 #[cfg(feature = "wgpu")]
219 Self::Wgpu(storage) => {
220 let storage = storage.elu(layout, alpha)?;
221 Ok(Self::Wgpu(storage))
222 }
223 }
224 }
225
226 pub(crate) fn cmp(
227 &self,
228 op: CmpOp,
229 rhs: &Self,
230 lhs_layout: &Layout,
231 rhs_layout: &Layout,
232 ) -> Result<Self> {
233 self.same_device(rhs, "cmp")?;
234 self.same_dtype(rhs, "cmp")?;
235 match (self, rhs) {
236 (Storage::Cpu(lhs), Storage::Cpu(rhs)) => {
237 let storage = lhs.cmp(op, rhs, lhs_layout, rhs_layout)?;
238 Ok(Self::Cpu(storage))
239 }
240 (Self::Cuda(lhs), Self::Cuda(rhs)) => {
241 let storage = lhs.cmp(op, rhs, lhs_layout, rhs_layout)?;
242 Ok(Self::Cuda(storage))
243 }
244 (Self::Metal(lhs), Self::Metal(rhs)) => {
245 let storage = lhs.cmp(op, rhs, lhs_layout, rhs_layout)?;
246 Ok(Self::Metal(storage))
247 }
248 #[cfg(feature = "rocm")]
249 (Self::Rocm(lhs), Self::Rocm(rhs)) => {
250 let storage = lhs.cmp(op, rhs, lhs_layout, rhs_layout)?;
251 Ok(Self::Rocm(storage))
252 }
253 #[cfg(feature = "vulkan")]
254 (Self::Vulkan(lhs), Self::Vulkan(rhs)) => {
255 let storage = lhs.cmp(op, rhs, lhs_layout, rhs_layout)?;
256 Ok(Self::Vulkan(storage))
257 }
258 #[cfg(feature = "wgpu")]
259 (Self::Wgpu(lhs), Self::Wgpu(rhs)) => {
260 let storage = lhs.cmp(op, rhs, lhs_layout, rhs_layout)?;
261 Ok(Self::Wgpu(storage))
262 }
263 (lhs, rhs) => {
264 Err(Error::DeviceMismatchBinaryOp {
267 lhs: lhs.device().location(),
268 rhs: rhs.device().location(),
269 op: "cmp",
270 }
271 .bt())
272 }
273 }
274 }
275
276 pub(crate) fn reduce_op(&self, op: ReduceOp, layout: &Layout, s: &[usize]) -> Result<Self> {
277 match self {
278 Storage::Cpu(storage) => {
279 let storage = storage.reduce_op(op, layout, s)?;
280 Ok(Self::Cpu(storage))
281 }
282 Self::Cuda(storage) => {
283 let storage = storage.reduce_op(op, layout, s)?;
284 Ok(Self::Cuda(storage))
285 }
286 Self::Metal(storage) => {
287 let storage = storage.reduce_op(op, layout, s)?;
288 Ok(Self::Metal(storage))
289 }
290 #[cfg(feature = "rocm")]
291 Self::Rocm(storage) => {
292 let storage = storage.reduce_op(op, layout, s)?;
293 Ok(Self::Rocm(storage))
294 }
295 #[cfg(feature = "vulkan")]
296 Self::Vulkan(storage) => {
297 let storage = storage.reduce_op(op, layout, s)?;
298 Ok(Self::Vulkan(storage))
299 }
300 #[cfg(feature = "wgpu")]
301 Self::Wgpu(storage) => {
302 let storage = storage.reduce_op(op, layout, s)?;
303 Ok(Self::Wgpu(storage))
304 }
305 }
306 }
307
308 pub(crate) fn to_dtype(&self, layout: &Layout, dtype: DType) -> Result<Self> {
309 match self {
310 Storage::Cpu(storage) => {
311 let storage = storage.to_dtype(layout, dtype)?;
312 Ok(Self::Cpu(storage))
313 }
314 Self::Cuda(storage) => {
315 let storage = storage.to_dtype(layout, dtype)?;
316 Ok(Self::Cuda(storage))
317 }
318 Self::Metal(storage) => {
319 let storage = storage.to_dtype(layout, dtype)?;
320 Ok(Self::Metal(storage))
321 }
322 #[cfg(feature = "rocm")]
323 Self::Rocm(storage) => {
324 let storage = storage.to_dtype(layout, dtype)?;
325 Ok(Self::Rocm(storage))
326 }
327 #[cfg(feature = "vulkan")]
328 Self::Vulkan(storage) => {
329 let storage = storage.to_dtype(layout, dtype)?;
330 Ok(Self::Vulkan(storage))
331 }
332 #[cfg(feature = "wgpu")]
333 Self::Wgpu(storage) => {
334 let storage = storage.to_dtype(layout, dtype)?;
335 Ok(Self::Wgpu(storage))
336 }
337 }
338 }
339
340 pub(crate) fn apply_op1(&self, l: &Layout, c: &dyn CustomOp1) -> Result<(Self, Shape)> {
341 match self {
342 Self::Cpu(storage) => {
343 let (storage, shape) = c.cpu_fwd(storage, l)?;
344 Ok((Self::Cpu(storage), shape))
345 }
346 Self::Cuda(storage) => {
347 let (storage, shape) = c.cuda_fwd(storage, l)?;
348 Ok((Self::Cuda(storage), shape))
349 }
350 Self::Metal(storage) => {
351 let (storage, shape) = c.metal_fwd(storage, l)?;
352 Ok((Self::Metal(storage), shape))
353 }
354 #[cfg(feature = "rocm")]
355 Self::Rocm(storage) => {
356 let (storage, shape) = c.rocm_fwd(storage, l)?;
357 Ok((Self::Rocm(storage), shape))
358 }
359 #[cfg(feature = "vulkan")]
360 Self::Vulkan(storage) => {
361 let (storage, shape) = c.vulkan_fwd(storage, l)?;
362 Ok((Self::Vulkan(storage), shape))
363 }
364 #[cfg(feature = "wgpu")]
365 Self::Wgpu(storage) => {
366 let (storage, shape) = c.wgpu_fwd(storage, l)?;
367 Ok((Self::Wgpu(storage), shape))
368 }
369 }
370 }
371
372 pub(crate) fn apply_op2(
373 &self,
374 l1: &Layout,
375 t2: &Self,
376 l2: &Layout,
377 c: &dyn CustomOp2,
378 ) -> Result<(Self, Shape)> {
379 self.same_device(t2, c.name())?;
380 match (self, t2) {
381 (Self::Cpu(s1), Self::Cpu(s2)) => {
382 let (s, shape) = c.cpu_fwd(s1, l1, s2, l2)?;
383 Ok((Self::Cpu(s), shape))
384 }
385 (Self::Cuda(s1), Self::Cuda(s2)) => {
386 let (s, shape) = c.cuda_fwd(s1, l1, s2, l2)?;
387 Ok((Self::Cuda(s), shape))
388 }
389 (Self::Metal(s1), Self::Metal(s2)) => {
390 let (s, shape) = c.metal_fwd(s1, l1, s2, l2)?;
391 Ok((Self::Metal(s), shape))
392 }
393 #[cfg(feature = "rocm")]
394 (Self::Rocm(s1), Self::Rocm(s2)) => {
395 let (s, shape) = c.rocm_fwd(s1, l1, s2, l2)?;
396 Ok((Self::Rocm(s), shape))
397 }
398 #[cfg(feature = "vulkan")]
399 (Self::Vulkan(s1), Self::Vulkan(s2)) => {
400 let (s, shape) = c.vulkan_fwd(s1, l1, s2, l2)?;
401 Ok((Self::Vulkan(s), shape))
402 }
403 #[cfg(feature = "wgpu")]
404 (Self::Wgpu(s1), Self::Wgpu(s2)) => {
405 let (s, shape) = c.wgpu_fwd(s1, l1, s2, l2)?;
406 Ok((Self::Wgpu(s), shape))
407 }
408 _ => unreachable!(),
409 }
410 }
411
412 pub(crate) fn apply_op3(
413 &self,
414 l1: &Layout,
415 t2: &Self,
416 l2: &Layout,
417 t3: &Self,
418 l3: &Layout,
419 c: &dyn CustomOp3,
420 ) -> Result<(Self, Shape)> {
421 self.same_device(t2, c.name())?;
422 self.same_device(t3, c.name())?;
423 match (self, t2, t3) {
424 (Self::Cpu(s1), Self::Cpu(s2), Self::Cpu(s3)) => {
425 let (s, shape) = c.cpu_fwd(s1, l1, s2, l2, s3, l3)?;
426 Ok((Self::Cpu(s), shape))
427 }
428 (Self::Cuda(s1), Self::Cuda(s2), Self::Cuda(s3)) => {
429 let (s, shape) = c.cuda_fwd(s1, l1, s2, l2, s3, l3)?;
430 Ok((Self::Cuda(s), shape))
431 }
432 (Self::Metal(s1), Self::Metal(s2), Self::Metal(s3)) => {
433 let (s, shape) = c.metal_fwd(s1, l1, s2, l2, s3, l3)?;
434 Ok((Self::Metal(s), shape))
435 }
436 #[cfg(feature = "rocm")]
437 (Self::Rocm(s1), Self::Rocm(s2), Self::Rocm(s3)) => {
438 let (s, shape) = c.rocm_fwd(s1, l1, s2, l2, s3, l3)?;
439 Ok((Self::Rocm(s), shape))
440 }
441 #[cfg(feature = "vulkan")]
442 (Self::Vulkan(s1), Self::Vulkan(s2), Self::Vulkan(s3)) => {
443 let (s, shape) = c.vulkan_fwd(s1, l1, s2, l2, s3, l3)?;
444 Ok((Self::Vulkan(s), shape))
445 }
446 #[cfg(feature = "wgpu")]
447 (Self::Wgpu(s1), Self::Wgpu(s2), Self::Wgpu(s3)) => {
448 let (s, shape) = c.wgpu_fwd(s1, l1, s2, l2, s3, l3)?;
449 Ok((Self::Wgpu(s), shape))
450 }
451 _ => unreachable!(),
452 }
453 }
454
455 pub(crate) fn inplace_op1(&mut self, l: &Layout, c: &dyn InplaceOp1) -> Result<()> {
456 match self {
457 Self::Cpu(storage) => c.cpu_fwd(storage, l),
458 Self::Cuda(storage) => c.cuda_fwd(storage, l),
459 Self::Metal(storage) => c.metal_fwd(storage, l),
460 #[cfg(feature = "rocm")]
461 Self::Rocm(storage) => c.rocm_fwd(storage, l),
462 #[cfg(feature = "vulkan")]
463 Self::Vulkan(storage) => c.vulkan_fwd(storage, l),
464 #[cfg(feature = "wgpu")]
465 Self::Wgpu(storage) => c.wgpu_fwd(storage, l),
466 }
467 }
468
469 pub(crate) fn inplace_op2(
470 &mut self,
471 l1: &Layout,
472 t2: &Self,
473 l2: &Layout,
474 c: &dyn InplaceOp2,
475 ) -> Result<()> {
476 self.same_device(t2, c.name())?;
477 match (self, t2) {
478 (Self::Cpu(s1), Self::Cpu(s2)) => c.cpu_fwd(s1, l1, s2, l2),
479 (Self::Cuda(s1), Self::Cuda(s2)) => c.cuda_fwd(s1, l1, s2, l2),
480 (Self::Metal(s1), Self::Metal(s2)) => c.metal_fwd(s1, l1, s2, l2),
481 #[cfg(feature = "rocm")]
482 (Self::Rocm(s1), Self::Rocm(s2)) => c.rocm_fwd(s1, l1, s2, l2),
483 #[cfg(feature = "vulkan")]
484 (Self::Vulkan(s1), Self::Vulkan(s2)) => c.vulkan_fwd(s1, l1, s2, l2),
485 #[cfg(feature = "wgpu")]
486 (Self::Wgpu(s1), Self::Wgpu(s2)) => c.wgpu_fwd(s1, l1, s2, l2),
487 _ => unreachable!(),
488 }
489 }
490
491 pub(crate) fn inplace_op3(
492 &mut self,
493 l1: &Layout,
494 t2: &Self,
495 l2: &Layout,
496 t3: &Self,
497 l3: &Layout,
498 c: &dyn InplaceOp3,
499 ) -> Result<()> {
500 self.same_device(t2, c.name())?;
501 self.same_device(t3, c.name())?;
502 match (self, t2, t3) {
503 (Self::Cpu(s1), Self::Cpu(s2), Self::Cpu(s3)) => c.cpu_fwd(s1, l1, s2, l2, s3, l3),
504 (Self::Cuda(s1), Self::Cuda(s2), Self::Cuda(s3)) => c.cuda_fwd(s1, l1, s2, l2, s3, l3),
505 (Self::Metal(s1), Self::Metal(s2), Self::Metal(s3)) => {
506 c.metal_fwd(s1, l1, s2, l2, s3, l3)
507 }
508 #[cfg(feature = "rocm")]
509 (Self::Rocm(s1), Self::Rocm(s2), Self::Rocm(s3)) => c.rocm_fwd(s1, l1, s2, l2, s3, l3),
510 #[cfg(feature = "vulkan")]
511 (Self::Vulkan(s1), Self::Vulkan(s2), Self::Vulkan(s3)) => {
512 c.vulkan_fwd(s1, l1, s2, l2, s3, l3)
513 }
514 #[cfg(feature = "wgpu")]
515 (Self::Wgpu(s1), Self::Wgpu(s2), Self::Wgpu(s3)) => c.wgpu_fwd(s1, l1, s2, l2, s3, l3),
516 _ => unreachable!(),
517 }
518 }
519
520 pub(crate) fn unary_impl<B: op::UnaryOpT>(&self, layout: &Layout) -> Result<Self> {
521 match self {
522 Storage::Cpu(storage) => {
523 let storage = storage.unary_impl::<B>(layout)?;
524 Ok(Self::Cpu(storage))
525 }
526 Self::Cuda(storage) => {
527 let storage = storage.unary_impl::<B>(layout)?;
528 Ok(Self::Cuda(storage))
529 }
530 Self::Metal(storage) => {
531 let storage = storage.unary_impl::<B>(layout)?;
532 Ok(Self::Metal(storage))
533 }
534 #[cfg(feature = "rocm")]
535 Self::Rocm(storage) => {
536 let storage = storage.unary_impl::<B>(layout)?;
537 Ok(Self::Rocm(storage))
538 }
539 #[cfg(feature = "vulkan")]
540 Self::Vulkan(storage) => {
541 let storage = storage.unary_impl::<B>(layout)?;
542 Ok(Self::Vulkan(storage))
543 }
544 #[cfg(feature = "wgpu")]
545 Self::Wgpu(storage) => {
546 let storage = storage.unary_impl::<B>(layout)?;
547 Ok(Self::Wgpu(storage))
548 }
549 }
550 }
551
552 pub(crate) fn binary_impl<B: op::BinaryOpT>(
553 &self,
554 rhs: &Self,
555 lhs_layout: &Layout,
556 rhs_layout: &Layout,
557 ) -> Result<Self> {
558 self.same_device(rhs, B::NAME)?;
559 self.same_dtype(rhs, B::NAME)?;
560 match (self, rhs) {
561 (Storage::Cpu(lhs), Storage::Cpu(rhs)) => {
562 let storage = lhs.binary_impl::<B>(rhs, lhs_layout, rhs_layout)?;
563 Ok(Self::Cpu(storage))
564 }
565 (Self::Cuda(lhs), Self::Cuda(rhs)) => {
566 let storage = lhs.binary_impl::<B>(rhs, lhs_layout, rhs_layout)?;
567 Ok(Self::Cuda(storage))
568 }
569 (Self::Metal(lhs), Self::Metal(rhs)) => {
570 let storage = lhs.binary_impl::<B>(rhs, lhs_layout, rhs_layout)?;
571 Ok(Self::Metal(storage))
572 }
573 #[cfg(feature = "rocm")]
574 (Self::Rocm(lhs), Self::Rocm(rhs)) => {
575 let storage = lhs.binary_impl::<B>(rhs, lhs_layout, rhs_layout)?;
576 Ok(Self::Rocm(storage))
577 }
578 #[cfg(feature = "vulkan")]
579 (Self::Vulkan(lhs), Self::Vulkan(rhs)) => {
580 let storage = lhs.binary_impl::<B>(rhs, lhs_layout, rhs_layout)?;
581 Ok(Self::Vulkan(storage))
582 }
583 #[cfg(feature = "wgpu")]
584 (Self::Wgpu(lhs), Self::Wgpu(rhs)) => {
585 let storage = lhs.binary_impl::<B>(rhs, lhs_layout, rhs_layout)?;
586 Ok(Self::Wgpu(storage))
587 }
588 (lhs, rhs) => {
589 Err(Error::DeviceMismatchBinaryOp {
592 lhs: lhs.device().location(),
593 rhs: rhs.device().location(),
594 op: B::NAME,
595 }
596 .bt())
597 }
598 }
599 }
600
601 pub(crate) fn conv1d(
602 &self,
603 l: &Layout,
604 kernel: &Self,
605 kernel_l: &Layout,
606 params: &crate::conv::ParamsConv1D,
607 ) -> Result<Self> {
608 self.same_device(kernel, "conv1d")?;
609 self.same_dtype(kernel, "conv1d")?;
610 match (self, &kernel) {
611 (Storage::Cpu(inp), Storage::Cpu(kernel)) => {
612 let s = inp.conv1d(l, kernel, kernel_l, params)?;
613 Ok(Self::Cpu(s))
614 }
615 (Storage::Cuda(inp), Storage::Cuda(kernel)) => {
616 let s = inp.conv1d(l, kernel, kernel_l, params)?;
617 Ok(Self::Cuda(s))
618 }
619 (Storage::Metal(inp), Storage::Metal(kernel)) => {
620 let s = inp.conv1d(l, kernel, kernel_l, params)?;
621 Ok(Self::Metal(s))
622 }
623 #[cfg(feature = "rocm")]
624 (Storage::Rocm(inp), Storage::Rocm(kernel)) => {
625 let s = inp.conv1d(l, kernel, kernel_l, params)?;
626 Ok(Self::Rocm(s))
627 }
628 #[cfg(feature = "vulkan")]
629 (Storage::Vulkan(inp), Storage::Vulkan(kernel)) => {
630 let s = inp.conv1d(l, kernel, kernel_l, params)?;
631 Ok(Self::Vulkan(s))
632 }
633 #[cfg(feature = "wgpu")]
634 (Storage::Wgpu(inp), Storage::Wgpu(kernel)) => {
635 let s = inp.conv1d(l, kernel, kernel_l, params)?;
636 Ok(Self::Wgpu(s))
637 }
638 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
639 lhs: lhs.device().location(),
640 rhs: rhs.device().location(),
641 op: "conv1d",
642 }
643 .bt()),
644 }
645 }
646
647 pub(crate) fn conv_transpose1d(
648 &self,
649 l: &Layout,
650 kernel: &Self,
651 kernel_l: &Layout,
652 params: &crate::conv::ParamsConvTranspose1D,
653 ) -> Result<Self> {
654 self.same_device(kernel, "conv-transpose1d")?;
655 self.same_dtype(kernel, "conv-transpose1d")?;
656 match (self, &kernel) {
657 (Storage::Cpu(inp), Storage::Cpu(kernel)) => {
658 let s = inp.conv_transpose1d(l, kernel, kernel_l, params)?;
659 Ok(Self::Cpu(s))
660 }
661 (Storage::Cuda(inp), Storage::Cuda(kernel)) => {
662 let s = inp.conv_transpose1d(l, kernel, kernel_l, params)?;
663 Ok(Self::Cuda(s))
664 }
665 (Storage::Metal(inp), Storage::Metal(kernel)) => {
666 let s = inp.conv_transpose1d(l, kernel, kernel_l, params)?;
667 Ok(Self::Metal(s))
668 }
669 #[cfg(feature = "rocm")]
670 (Storage::Rocm(inp), Storage::Rocm(kernel)) => {
671 let s = inp.conv_transpose1d(l, kernel, kernel_l, params)?;
672 Ok(Self::Rocm(s))
673 }
674 #[cfg(feature = "vulkan")]
675 (Storage::Vulkan(inp), Storage::Vulkan(kernel)) => {
676 let s = inp.conv_transpose1d(l, kernel, kernel_l, params)?;
677 Ok(Self::Vulkan(s))
678 }
679 #[cfg(feature = "wgpu")]
680 (Storage::Wgpu(inp), Storage::Wgpu(kernel)) => {
681 let s = inp.conv_transpose1d(l, kernel, kernel_l, params)?;
682 Ok(Self::Wgpu(s))
683 }
684 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
685 lhs: lhs.device().location(),
686 rhs: rhs.device().location(),
687 op: "conv-transpose1d",
688 }
689 .bt()),
690 }
691 }
692
693 pub(crate) fn conv2d(
694 &self,
695 l: &Layout,
696 kernel: &Self,
697 kernel_l: &Layout,
698 params: &crate::conv::ParamsConv2D,
699 ) -> Result<Self> {
700 self.same_device(kernel, "conv2d")?;
701 self.same_dtype(kernel, "conv2d")?;
702 match (self, &kernel) {
703 (Storage::Cpu(inp), Storage::Cpu(kernel)) => {
704 let s = inp.conv2d(l, kernel, kernel_l, params)?;
705 Ok(Self::Cpu(s))
706 }
707 (Storage::Cuda(inp), Storage::Cuda(kernel)) => {
708 let s = inp.conv2d(l, kernel, kernel_l, params)?;
709 Ok(Self::Cuda(s))
710 }
711 (Storage::Metal(inp), Storage::Metal(kernel)) => {
712 let s = inp.conv2d(l, kernel, kernel_l, params)?;
713 Ok(Self::Metal(s))
714 }
715 #[cfg(feature = "rocm")]
716 (Storage::Rocm(inp), Storage::Rocm(kernel)) => {
717 let s = inp.conv2d(l, kernel, kernel_l, params)?;
718 Ok(Self::Rocm(s))
719 }
720 #[cfg(feature = "vulkan")]
721 (Storage::Vulkan(inp), Storage::Vulkan(kernel)) => {
722 let s = inp.conv2d(l, kernel, kernel_l, params)?;
723 Ok(Self::Vulkan(s))
724 }
725 #[cfg(feature = "wgpu")]
726 (Storage::Wgpu(inp), Storage::Wgpu(kernel)) => {
727 let s = inp.conv2d(l, kernel, kernel_l, params)?;
728 Ok(Self::Wgpu(s))
729 }
730 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
731 lhs: lhs.device().location(),
732 rhs: rhs.device().location(),
733 op: "conv2d",
734 }
735 .bt()),
736 }
737 }
738
739 pub(crate) fn conv_transpose2d(
740 &self,
741 l: &Layout,
742 kernel: &Self,
743 kernel_l: &Layout,
744 params: &crate::conv::ParamsConvTranspose2D,
745 ) -> Result<Self> {
746 self.same_device(kernel, "conv_transpose2d")?;
747 self.same_dtype(kernel, "conv_transpose2d")?;
748 match (self, &kernel) {
749 (Storage::Cpu(inp), Storage::Cpu(kernel)) => {
750 let s = inp.conv_transpose2d(l, kernel, kernel_l, params)?;
751 Ok(Self::Cpu(s))
752 }
753 (Storage::Cuda(inp), Storage::Cuda(kernel)) => {
754 let s = inp.conv_transpose2d(l, kernel, kernel_l, params)?;
755 Ok(Self::Cuda(s))
756 }
757 (Storage::Metal(inp), Storage::Metal(kernel)) => {
758 let s = inp.conv_transpose2d(l, kernel, kernel_l, params)?;
759 Ok(Self::Metal(s))
760 }
761 #[cfg(feature = "rocm")]
762 (Storage::Rocm(inp), Storage::Rocm(kernel)) => {
763 let s = inp.conv_transpose2d(l, kernel, kernel_l, params)?;
764 Ok(Self::Rocm(s))
765 }
766 #[cfg(feature = "vulkan")]
767 (Storage::Vulkan(inp), Storage::Vulkan(kernel)) => {
768 let s = inp.conv_transpose2d(l, kernel, kernel_l, params)?;
769 Ok(Self::Vulkan(s))
770 }
771 #[cfg(feature = "wgpu")]
772 (Storage::Wgpu(inp), Storage::Wgpu(kernel)) => {
773 let s = inp.conv_transpose2d(l, kernel, kernel_l, params)?;
774 Ok(Self::Wgpu(s))
775 }
776 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
777 lhs: lhs.device().location(),
778 rhs: rhs.device().location(),
779 op: "conv_transpose2d",
780 }
781 .bt()),
782 }
783 }
784
785 pub(crate) fn avg_pool2d(
786 &self,
787 layout: &Layout,
788 kernel_size: (usize, usize),
789 stride: (usize, usize),
790 ) -> Result<Self> {
791 match self {
792 Storage::Cpu(storage) => {
793 let storage = storage.avg_pool2d(layout, kernel_size, stride)?;
794 Ok(Self::Cpu(storage))
795 }
796 Self::Cuda(storage) => {
797 let storage = storage.avg_pool2d(layout, kernel_size, stride)?;
798 Ok(Self::Cuda(storage))
799 }
800 Self::Metal(storage) => {
801 let storage = storage.avg_pool2d(layout, kernel_size, stride)?;
802 Ok(Self::Metal(storage))
803 }
804 #[cfg(feature = "rocm")]
805 Self::Rocm(storage) => {
806 let storage = storage.avg_pool2d(layout, kernel_size, stride)?;
807 Ok(Self::Rocm(storage))
808 }
809 #[cfg(feature = "vulkan")]
810 Self::Vulkan(storage) => {
811 let storage = storage.avg_pool2d(layout, kernel_size, stride)?;
812 Ok(Self::Vulkan(storage))
813 }
814 #[cfg(feature = "wgpu")]
815 Self::Wgpu(storage) => {
816 let storage = storage.avg_pool2d(layout, kernel_size, stride)?;
817 Ok(Self::Wgpu(storage))
818 }
819 }
820 }
821
822 pub(crate) fn max_pool2d(
823 &self,
824 layout: &Layout,
825 kernel_size: (usize, usize),
826 stride: (usize, usize),
827 ) -> Result<Self> {
828 match self {
829 Storage::Cpu(storage) => {
830 let storage = storage.max_pool2d(layout, kernel_size, stride)?;
831 Ok(Self::Cpu(storage))
832 }
833 Self::Cuda(storage) => {
834 let storage = storage.max_pool2d(layout, kernel_size, stride)?;
835 Ok(Self::Cuda(storage))
836 }
837 Self::Metal(storage) => {
838 let storage = storage.max_pool2d(layout, kernel_size, stride)?;
839 Ok(Self::Metal(storage))
840 }
841 #[cfg(feature = "rocm")]
842 Self::Rocm(storage) => {
843 let storage = storage.max_pool2d(layout, kernel_size, stride)?;
844 Ok(Self::Rocm(storage))
845 }
846 #[cfg(feature = "vulkan")]
847 Self::Vulkan(storage) => {
848 let storage = storage.max_pool2d(layout, kernel_size, stride)?;
849 Ok(Self::Vulkan(storage))
850 }
851 #[cfg(feature = "wgpu")]
852 Self::Wgpu(storage) => {
853 let storage = storage.max_pool2d(layout, kernel_size, stride)?;
854 Ok(Self::Wgpu(storage))
855 }
856 }
857 }
858
859 pub(crate) fn upsample_nearest1d(&self, layout: &Layout, sz: usize) -> Result<Self> {
860 match self {
861 Storage::Cpu(storage) => {
862 let storage = storage.upsample_nearest1d(layout, sz)?;
863 Ok(Self::Cpu(storage))
864 }
865 Self::Cuda(storage) => {
866 let storage = storage.upsample_nearest1d(layout, sz)?;
867 Ok(Self::Cuda(storage))
868 }
869 Self::Metal(storage) => {
870 let storage = storage.upsample_nearest1d(layout, sz)?;
871 Ok(Self::Metal(storage))
872 }
873 #[cfg(feature = "rocm")]
874 Self::Rocm(storage) => {
875 let storage = storage.upsample_nearest1d(layout, sz)?;
876 Ok(Self::Rocm(storage))
877 }
878 #[cfg(feature = "vulkan")]
879 Self::Vulkan(storage) => {
880 let storage = storage.upsample_nearest1d(layout, sz)?;
881 Ok(Self::Vulkan(storage))
882 }
883 #[cfg(feature = "wgpu")]
884 Self::Wgpu(storage) => {
885 let storage = storage.upsample_nearest1d(layout, sz)?;
886 Ok(Self::Wgpu(storage))
887 }
888 }
889 }
890
891 pub(crate) fn upsample_nearest2d(&self, layout: &Layout, h: usize, w: usize) -> Result<Self> {
892 match self {
893 Storage::Cpu(storage) => {
894 let storage = storage.upsample_nearest2d(layout, h, w)?;
895 Ok(Self::Cpu(storage))
896 }
897 Self::Cuda(storage) => {
898 let storage = storage.upsample_nearest2d(layout, h, w)?;
899 Ok(Self::Cuda(storage))
900 }
901 Self::Metal(storage) => {
902 let storage = storage.upsample_nearest2d(layout, h, w)?;
903 Ok(Self::Metal(storage))
904 }
905 #[cfg(feature = "rocm")]
906 Self::Rocm(storage) => {
907 let storage = storage.upsample_nearest2d(layout, h, w)?;
908 Ok(Self::Rocm(storage))
909 }
910 #[cfg(feature = "vulkan")]
911 Self::Vulkan(storage) => {
912 let storage = storage.upsample_nearest2d(layout, h, w)?;
913 Ok(Self::Vulkan(storage))
914 }
915 #[cfg(feature = "wgpu")]
916 Self::Wgpu(storage) => {
917 let storage = storage.upsample_nearest2d(layout, h, w)?;
918 Ok(Self::Wgpu(storage))
919 }
920 }
921 }
922
923 pub(crate) fn upsample_bilinear2d(
924 &self,
925 layout: &Layout,
926 h: usize,
927 w: usize,
928 align_corners: bool,
929 scale_h: Option<f64>,
930 scale_w: Option<f64>,
931 ) -> Result<Self> {
932 match self {
933 Storage::Cpu(storage) => {
934 let storage =
935 storage.upsample_bilinear2d(layout, h, w, align_corners, scale_h, scale_w)?;
936 Ok(Self::Cpu(storage))
937 }
938 Self::Cuda(storage) => {
939 let storage =
940 storage.upsample_bilinear2d(layout, h, w, align_corners, scale_h, scale_w)?;
941 Ok(Self::Cuda(storage))
942 }
943 Self::Metal(storage) => {
944 let storage =
945 storage.upsample_bilinear2d(layout, h, w, align_corners, scale_h, scale_w)?;
946 Ok(Self::Metal(storage))
947 }
948 #[cfg(feature = "rocm")]
949 Self::Rocm(storage) => {
950 let storage =
951 storage.upsample_bilinear2d(layout, h, w, align_corners, scale_h, scale_w)?;
952 Ok(Self::Rocm(storage))
953 }
954 #[cfg(feature = "vulkan")]
955 Self::Vulkan(storage) => {
956 let storage =
957 storage.upsample_bilinear2d(layout, h, w, align_corners, scale_h, scale_w)?;
958 Ok(Self::Vulkan(storage))
959 }
960 #[cfg(feature = "wgpu")]
961 Self::Wgpu(storage) => {
962 let storage =
963 storage.upsample_bilinear2d(layout, h, w, align_corners, scale_h, scale_w)?;
964 Ok(Self::Wgpu(storage))
965 }
966 }
967 }
968
969 pub(crate) fn where_cond(
970 &self,
971 layout: &Layout,
972 t: &Self,
973 layout_t: &Layout,
974 f: &Self,
975 layout_f: &Layout,
976 ) -> Result<Self> {
977 self.same_device(t, "where")?;
978 self.same_device(f, "where")?;
979 t.same_dtype(f, "where")?;
980 match (self, t, f) {
981 (Storage::Cpu(cond), Storage::Cpu(t), Storage::Cpu(f)) => {
982 let storage = cond.where_cond(layout, t, layout_t, f, layout_f)?;
983 Ok(Self::Cpu(storage))
984 }
985 (Self::Cuda(cond), Self::Cuda(t), Self::Cuda(f)) => {
986 let storage = cond.where_cond(layout, t, layout_t, f, layout_f)?;
987 Ok(Self::Cuda(storage))
988 }
989 (Self::Metal(cond), Self::Metal(t), Self::Metal(f)) => {
990 let storage = cond.where_cond(layout, t, layout_t, f, layout_f)?;
991 Ok(Self::Metal(storage))
992 }
993 #[cfg(feature = "rocm")]
994 (Self::Rocm(cond), Self::Rocm(t), Self::Rocm(f)) => {
995 let storage = cond.where_cond(layout, t, layout_t, f, layout_f)?;
996 Ok(Self::Rocm(storage))
997 }
998 #[cfg(feature = "vulkan")]
999 (Self::Vulkan(cond), Self::Vulkan(t), Self::Vulkan(f)) => {
1000 let storage = cond.where_cond(layout, t, layout_t, f, layout_f)?;
1001 Ok(Self::Vulkan(storage))
1002 }
1003 #[cfg(feature = "wgpu")]
1004 (Self::Wgpu(cond), Self::Wgpu(t), Self::Wgpu(f)) => {
1005 let storage = cond.where_cond(layout, t, layout_t, f, layout_f)?;
1006 Ok(Self::Wgpu(storage))
1007 }
1008 (_, lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
1009 lhs: lhs.device().location(),
1010 rhs: rhs.device().location(),
1011 op: "where",
1012 }
1013 .bt()),
1014 }
1015 }
1016
1017 pub(crate) fn gather(
1018 &self,
1019 l: &Layout,
1020 indexes: &Self,
1021 indexes_l: &Layout,
1022 d: usize,
1023 ) -> Result<Self> {
1024 self.same_device(indexes, "index-add")?;
1025 match (self, indexes) {
1026 (Self::Cpu(s), Self::Cpu(indexes)) => {
1027 let storage = s.gather(l, indexes, indexes_l, d)?;
1028 Ok(Self::Cpu(storage))
1029 }
1030 (Self::Cuda(s), Self::Cuda(indexes)) => {
1031 let storage = s.gather(l, indexes, indexes_l, d)?;
1032 Ok(Self::Cuda(storage))
1033 }
1034 (Self::Metal(s), Self::Metal(indexes)) => {
1035 let storage = s.gather(l, indexes, indexes_l, d)?;
1036 Ok(Self::Metal(storage))
1037 }
1038 #[cfg(feature = "rocm")]
1039 (Self::Rocm(s), Self::Rocm(indexes)) => {
1040 let storage = s.gather(l, indexes, indexes_l, d)?;
1041 Ok(Self::Rocm(storage))
1042 }
1043 #[cfg(feature = "vulkan")]
1044 (Self::Vulkan(s), Self::Vulkan(indexes)) => {
1045 let storage = s.gather(l, indexes, indexes_l, d)?;
1046 Ok(Self::Vulkan(storage))
1047 }
1048 #[cfg(feature = "wgpu")]
1049 (Self::Wgpu(s), Self::Wgpu(indexes)) => {
1050 let storage = s.gather(l, indexes, indexes_l, d)?;
1051 Ok(Self::Wgpu(storage))
1052 }
1053 _ => unreachable!(),
1054 }
1055 }
1056
1057 pub(crate) fn scatter_set(
1058 &mut self,
1059 l: &Layout,
1060 indexes: &Self,
1061 indexes_l: &Layout,
1062 source: &Self,
1063 source_l: &Layout,
1064 d: usize,
1065 ) -> Result<()> {
1066 self.same_device(indexes, "scatter-set")?;
1067 self.same_device(source, "scatter-set")?;
1068 match (self, indexes, source) {
1069 (Self::Cpu(s), Self::Cpu(indexes), Self::Cpu(source)) => {
1070 s.scatter_set(l, indexes, indexes_l, source, source_l, d)?;
1071 }
1072 (Self::Cuda(s), Self::Cuda(indexes), Self::Cuda(source)) => {
1073 s.scatter_set(l, indexes, indexes_l, source, source_l, d)?;
1074 }
1075 (Self::Metal(s), Self::Metal(indexes), Self::Metal(source)) => {
1076 s.scatter_set(l, indexes, indexes_l, source, source_l, d)?;
1077 }
1078 #[cfg(feature = "rocm")]
1079 (Self::Rocm(s), Self::Rocm(indexes), Self::Rocm(source)) => {
1080 s.scatter_set(l, indexes, indexes_l, source, source_l, d)?;
1081 }
1082 #[cfg(feature = "vulkan")]
1083 (Self::Vulkan(s), Self::Vulkan(indexes), Self::Vulkan(source)) => {
1084 s.scatter_set(l, indexes, indexes_l, source, source_l, d)?;
1085 }
1086 #[cfg(feature = "wgpu")]
1087 (Self::Wgpu(s), Self::Wgpu(indexes), Self::Wgpu(source)) => {
1088 s.scatter_set(l, indexes, indexes_l, source, source_l, d)?;
1089 }
1090 _ => unreachable!(),
1091 }
1092 Ok(())
1093 }
1094
1095 pub(crate) fn scatter_add(
1096 &mut self,
1097 l: &Layout,
1098 indexes: &Self,
1099 indexes_l: &Layout,
1100 source: &Self,
1101 source_l: &Layout,
1102 d: usize,
1103 ) -> Result<()> {
1104 self.same_device(indexes, "scatter-add")?;
1105 self.same_device(source, "scatter-add")?;
1106 match (self, indexes, source) {
1107 (Self::Cpu(s), Self::Cpu(indexes), Self::Cpu(source)) => {
1108 s.scatter_add_set(l, indexes, indexes_l, source, source_l, d)?;
1109 }
1110 (Self::Cuda(s), Self::Cuda(indexes), Self::Cuda(source)) => {
1111 s.scatter_add_set(l, indexes, indexes_l, source, source_l, d)?;
1112 }
1113 (Self::Metal(s), Self::Metal(indexes), Self::Metal(source)) => {
1114 s.scatter_add_set(l, indexes, indexes_l, source, source_l, d)?;
1115 }
1116 #[cfg(feature = "rocm")]
1117 (Self::Rocm(s), Self::Rocm(indexes), Self::Rocm(source)) => {
1118 s.scatter_add_set(l, indexes, indexes_l, source, source_l, d)?;
1119 }
1120 #[cfg(feature = "vulkan")]
1121 (Self::Vulkan(s), Self::Vulkan(indexes), Self::Vulkan(source)) => {
1122 s.scatter_add_set(l, indexes, indexes_l, source, source_l, d)?;
1123 }
1124 #[cfg(feature = "wgpu")]
1125 (Self::Wgpu(s), Self::Wgpu(indexes), Self::Wgpu(source)) => {
1126 s.scatter_add_set(l, indexes, indexes_l, source, source_l, d)?;
1127 }
1128 _ => unreachable!(),
1129 }
1130 Ok(())
1131 }
1132
1133 pub(crate) fn index_add(
1134 &self,
1135 l: &Layout,
1136 indexes: &Self,
1137 indexes_l: &Layout,
1138 source: &Self,
1139 source_l: &Layout,
1140 d: usize,
1141 ) -> Result<Self> {
1142 self.same_device(indexes, "index-add")?;
1143 self.same_device(source, "index-add")?;
1144 match (self, indexes, source) {
1145 (Self::Cpu(s), Self::Cpu(indexes), Self::Cpu(source)) => {
1146 let storage = s.index_add(l, indexes, indexes_l, source, source_l, d)?;
1147 Ok(Self::Cpu(storage))
1148 }
1149 (Self::Cuda(s), Self::Cuda(indexes), Self::Cuda(source)) => {
1150 let storage = s.index_add(l, indexes, indexes_l, source, source_l, d)?;
1151 Ok(Self::Cuda(storage))
1152 }
1153 (Self::Metal(s), Self::Metal(indexes), Self::Metal(source)) => {
1154 let storage = s.index_add(l, indexes, indexes_l, source, source_l, d)?;
1155 Ok(Self::Metal(storage))
1156 }
1157 #[cfg(feature = "rocm")]
1158 (Self::Rocm(s), Self::Rocm(indexes), Self::Rocm(source)) => {
1159 let storage = s.index_add(l, indexes, indexes_l, source, source_l, d)?;
1160 Ok(Self::Rocm(storage))
1161 }
1162 #[cfg(feature = "vulkan")]
1163 (Self::Vulkan(s), Self::Vulkan(indexes), Self::Vulkan(source)) => {
1164 let storage = s.index_add(l, indexes, indexes_l, source, source_l, d)?;
1165 Ok(Self::Vulkan(storage))
1166 }
1167 #[cfg(feature = "wgpu")]
1168 (Self::Wgpu(s), Self::Wgpu(indexes), Self::Wgpu(source)) => {
1169 let storage = s.index_add(l, indexes, indexes_l, source, source_l, d)?;
1170 Ok(Self::Wgpu(storage))
1171 }
1172 _ => unreachable!(),
1173 }
1174 }
1175
1176 pub(crate) fn index_select(
1177 &self,
1178 rhs: &Self,
1179 lhs_l: &Layout,
1180 rhs_l: &Layout,
1181 d: usize,
1182 ) -> Result<Self> {
1183 self.same_device(rhs, "index-select")?;
1184 match (self, rhs) {
1185 (Self::Cpu(lhs), Self::Cpu(rhs)) => {
1186 let storage = lhs.index_select(rhs, lhs_l, rhs_l, d)?;
1187 Ok(Self::Cpu(storage))
1188 }
1189 (Self::Cuda(lhs), Self::Cuda(rhs)) => {
1190 let storage = lhs.index_select(rhs, lhs_l, rhs_l, d)?;
1191 Ok(Self::Cuda(storage))
1192 }
1193 (Self::Metal(lhs), Self::Metal(rhs)) => {
1194 let storage = lhs.index_select(rhs, lhs_l, rhs_l, d)?;
1195 Ok(Self::Metal(storage))
1196 }
1197 #[cfg(feature = "rocm")]
1198 (Self::Rocm(lhs), Self::Rocm(rhs)) => {
1199 let storage = lhs.index_select(rhs, lhs_l, rhs_l, d)?;
1200 Ok(Self::Rocm(storage))
1201 }
1202 #[cfg(feature = "vulkan")]
1203 (Self::Vulkan(lhs), Self::Vulkan(rhs)) => {
1204 let storage = lhs.index_select(rhs, lhs_l, rhs_l, d)?;
1205 Ok(Self::Vulkan(storage))
1206 }
1207 #[cfg(feature = "wgpu")]
1208 (Self::Wgpu(lhs), Self::Wgpu(rhs)) => {
1209 let storage = lhs.index_select(rhs, lhs_l, rhs_l, d)?;
1210 Ok(Self::Wgpu(storage))
1211 }
1212 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
1213 lhs: lhs.device().location(),
1214 rhs: rhs.device().location(),
1215 op: "index-select",
1216 }
1217 .bt()),
1218 }
1219 }
1220
1221 pub(crate) fn matmul(
1222 &self,
1223 rhs: &Self,
1224 bmnk: (usize, usize, usize, usize),
1225 lhs_layout: &Layout,
1226 rhs_layout: &Layout,
1227 ) -> Result<Self> {
1228 self.same_device(rhs, "matmul")?;
1229 self.same_dtype(rhs, "matmul")?;
1230 match (self, rhs) {
1231 (Self::Cpu(lhs), Self::Cpu(rhs)) => {
1232 let storage = lhs.matmul(rhs, bmnk, lhs_layout, rhs_layout)?;
1233 Ok(Self::Cpu(storage))
1234 }
1235 (Self::Cuda(lhs), Self::Cuda(rhs)) => {
1236 let storage = lhs.matmul(rhs, bmnk, lhs_layout, rhs_layout)?;
1237 Ok(Self::Cuda(storage))
1238 }
1239 (Self::Metal(lhs), Self::Metal(rhs)) => {
1240 let storage = lhs.matmul(rhs, bmnk, lhs_layout, rhs_layout)?;
1241 Ok(Self::Metal(storage))
1242 }
1243 #[cfg(feature = "rocm")]
1244 (Self::Rocm(lhs), Self::Rocm(rhs)) => {
1245 let storage = lhs.matmul(rhs, bmnk, lhs_layout, rhs_layout)?;
1246 Ok(Self::Rocm(storage))
1247 }
1248 #[cfg(feature = "vulkan")]
1249 (Self::Vulkan(lhs), Self::Vulkan(rhs)) => {
1250 let storage = lhs.matmul(rhs, bmnk, lhs_layout, rhs_layout)?;
1251 Ok(Self::Vulkan(storage))
1252 }
1253 #[cfg(feature = "wgpu")]
1254 (Self::Wgpu(lhs), Self::Wgpu(rhs)) => {
1255 let storage = lhs.matmul(rhs, bmnk, lhs_layout, rhs_layout)?;
1256 Ok(Self::Wgpu(storage))
1257 }
1258 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
1259 lhs: lhs.device().location(),
1260 rhs: rhs.device().location(),
1261 op: "matmul",
1262 }
1263 .bt()),
1264 }
1265 }
1266
1267 pub(crate) fn copy_strided_src(
1269 &self,
1270 dst: &mut Self,
1271 dst_offset: usize,
1272 src_l: &Layout,
1273 ) -> Result<()> {
1274 match (self, dst) {
1275 (Self::Cpu(src), Self::Cpu(dst)) => src.copy_strided_src(dst, dst_offset, src_l),
1276 (Self::Cuda(src), Self::Cuda(dst)) => Ok(src.copy_strided_src(dst, dst_offset, src_l)?),
1277 (Self::Metal(src), Self::Metal(dst)) => {
1278 Ok(src.copy_strided_src(dst, dst_offset, src_l)?)
1279 }
1280 #[cfg(feature = "rocm")]
1281 (Self::Rocm(src), Self::Rocm(dst)) => Ok(src.copy_strided_src(dst, dst_offset, src_l)?),
1282 #[cfg(feature = "vulkan")]
1283 (Self::Vulkan(src), Self::Vulkan(dst)) => {
1284 Ok(src.copy_strided_src(dst, dst_offset, src_l)?)
1285 }
1286 #[cfg(feature = "wgpu")]
1287 (Self::Wgpu(src), Self::Wgpu(dst)) => Ok(src.copy_strided_src(dst, dst_offset, src_l)?),
1288 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
1289 lhs: lhs.device().location(),
1290 rhs: rhs.device().location(),
1291 op: "copy",
1292 }
1293 .bt()),
1294 }
1295 }
1296
1297 #[allow(clippy::too_many_arguments)]
1298 pub(crate) fn copy2d(
1299 &self,
1300 dst: &mut Self,
1301 d1: usize,
1302 d2: usize,
1303 src_s: usize,
1304 dst_s: usize,
1305 src_o: usize,
1306 dst_o: usize,
1307 ) -> Result<()> {
1308 match (self, dst) {
1309 (Self::Cpu(src), Self::Cpu(dst)) => src.copy2d(dst, d1, d2, src_s, dst_s, src_o, dst_o),
1310 (Self::Cuda(src), Self::Cuda(dst)) => {
1311 Ok(src.copy2d(dst, d1, d2, src_s, dst_s, src_o, dst_o)?)
1312 }
1313 (Self::Metal(src), Self::Metal(dst)) => {
1314 Ok(src.copy2d(dst, d1, d2, src_s, dst_s, src_o, dst_o)?)
1315 }
1316 #[cfg(feature = "rocm")]
1317 (Self::Rocm(src), Self::Rocm(dst)) => {
1318 Ok(src.copy2d(dst, d1, d2, src_s, dst_s, src_o, dst_o)?)
1319 }
1320 #[cfg(feature = "vulkan")]
1321 (Self::Vulkan(src), Self::Vulkan(dst)) => {
1322 Ok(src.copy2d(dst, d1, d2, src_s, dst_s, src_o, dst_o)?)
1323 }
1324 #[cfg(feature = "wgpu")]
1325 (Self::Wgpu(src), Self::Wgpu(dst)) => {
1326 Ok(src.copy2d(dst, d1, d2, src_s, dst_s, src_o, dst_o)?)
1327 }
1328 (lhs, rhs) => Err(Error::DeviceMismatchBinaryOp {
1329 lhs: lhs.device().location(),
1330 rhs: rhs.device().location(),
1331 op: "copy2d",
1332 }
1333 .bt()),
1334 }
1335 }
1336}