1use std::mem::size_of;
10use std::ptr::null_mut;
11use std::sync::Arc;
12use std::sync::Mutex;
13use crate::Backend;
14use crate::BackendArray;
15use crate::Error;
16use crate::Result;
17use crate::mutex_lock;
18
19pub use opencl3::context::Context;
20pub use opencl3::device::Device;
21pub use opencl3::device::CL_DEVICE_TYPE_ACCELERATOR;
22pub use opencl3::device::CL_DEVICE_TYPE_ALL;
23pub use opencl3::device::CL_DEVICE_TYPE_CPU;
24pub use opencl3::device::CL_DEVICE_TYPE_CUSTOM;
25pub use opencl3::device::CL_DEVICE_TYPE_DEFAULT;
26pub use opencl3::device::CL_DEVICE_TYPE_GPU;
27pub use opencl3::device::cl_device_id;
28pub use opencl3::error_codes::ClError;
29pub use opencl3::platform::Platform;
30pub use opencl3::platform::get_platforms;
31
32use cl3::info_type::InfoType;
33use opencl3::command_queue::CommandQueue;
34use opencl3::device::CL_DEVICE_MAX_WORK_GROUP_SIZE;
35use opencl3::device::get_device_info;
36use opencl3::event::Event;
37use opencl3::kernel::ExecuteKernel;
38use opencl3::kernel::Kernel;
39use opencl3::memory::Buffer;
40use opencl3::memory::ClMem;
41use opencl3::memory::cl_mem;
42use opencl3::memory::CL_MEM_READ_WRITE;
43use opencl3::program::Program;
44use opencl3::types::CL_TRUE;
45
46const SOURCE: &'static str = include_str!("opencl.cl");
47
48#[derive(Debug)]
52pub struct ClBackendArray
53{
54 buffer: Arc<Mutex<Buffer<f32>>>,
55 len: usize,
56}
57
58struct ClInnerBackend
59{
60 context: Context,
61 command_queue: CommandQueue,
62 program: Program,
63 group_size_for_1d: usize,
64 group_size_for_2d: usize,
65}
66
67pub struct ClBackend
69{
70 inner: Mutex<ClInnerBackend>,
71}
72
73fn preferred_work_sizes(n: usize, m: usize, group_size_for_1d: usize, group_size_for_2d: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool, is_mul: bool) -> (usize, usize, usize, usize)
74{
75 if m <= item_col_count && !is_mul {
76 let n2 = (((n + item_row_count - 1) / item_row_count + group_size_for_1d - 1) / group_size_for_1d) * group_size_for_1d;
77 if !are_swapped_dims {
78 (group_size_for_1d, 1, n2, 1)
79 } else {
80 (1, group_size_for_1d, 1, n2)
81 }
82 } else if n <= item_row_count && !is_mul {
83 let m2 = (((m + item_col_count - 1) / item_col_count + group_size_for_1d - 1) / group_size_for_1d) * group_size_for_1d;
84 if !are_swapped_dims {
85 (1, group_size_for_1d, 1, m2)
86 } else {
87 (group_size_for_1d, 1, m2, 1)
88 }
89 } else if is_mul {
90 let n2 = (((n + 7) / 8 + ((group_size_for_2d + 1) / 2) - 1) / ((group_size_for_2d + 1) / 2)) * ((group_size_for_2d + 1) / 2);
91 let m2 = (((m + 3) / 4 + ((group_size_for_2d + 1) / 2) - 1) / ((group_size_for_2d + 1) / 2)) * ((group_size_for_2d + 1) / 2);
92 if !are_swapped_dims {
93 ((group_size_for_2d + 1) / 2, (group_size_for_2d + 1) / 2, n2, m2)
94 } else {
95 ((group_size_for_2d + 1) / 2, (group_size_for_2d + 1) / 2, m2, n2)
96 }
97 } else {
98 let n2 = (((n + item_row_count - 1) / item_row_count + group_size_for_2d - 1) / group_size_for_2d) * group_size_for_2d;
99 let m2 = (((m + item_col_count - 1) / item_col_count + group_size_for_2d - 1) / group_size_for_2d) * group_size_for_2d;
100 if !are_swapped_dims {
101 (group_size_for_2d, group_size_for_2d, n2, m2)
102 } else {
103 (group_size_for_2d, group_size_for_2d, m2, n2)
104 }
105 }
106}
107
108impl ClBackend
109{
110 pub fn new() -> Result<ClBackend>
112 {
113 let platforms = match get_platforms() {
114 Ok(tmp_platforms) => tmp_platforms,
115 Err(err) => return Err(Error::OpenCl(err)),
116 };
117 if platforms.is_empty() {
118 return Err(Error::NoPlatform);
119 }
120 let device_ids = match platforms[0].get_devices(CL_DEVICE_TYPE_DEFAULT) {
121 Ok(tmp_device_ids) => tmp_device_ids,
122 Err(err) => return Err(Error::OpenCl(err)),
123 };
124 if device_ids.is_empty() {
125 return Err(Error::NoDevice);
126 }
127 let device = Device::new(device_ids[0]);
128 let context = match Context::from_device(&device) {
129 Ok(tmp_context) => tmp_context,
130 Err(err) => return Err(Error::OpenCl(err)),
131 };
132 Self::new_with_context(context)
133 }
134
135 pub fn new_with_context(context: Context) -> Result<ClBackend>
137 {
138 let command_queue = match CommandQueue::create_default_with_properties(&context, 0, 0) {
139 Ok(tmp_command_queue) => tmp_command_queue,
140 Err(err) => return Err(Error::OpenCl(err)),
141 };
142 let program = match Program::create_and_build_from_source(&context, SOURCE, "") {
143 Ok(tmp_program) => tmp_program,
144 Err(msg) => return Err(Error::Compilation(msg)),
145 };
146 let group_size_for_1d = match get_device_info(context.default_device(), CL_DEVICE_MAX_WORK_GROUP_SIZE) {
147 Ok(InfoType::Size(tmp_group_size_for_1d)) => tmp_group_size_for_1d,
148 _ => return Err(Error::InvalidDeviceInfoType),
149 };
150 let group_size_for_2d = (group_size_for_1d as f64).sqrt().floor() as usize;
151 let inner = ClInnerBackend {
152 context,
153 command_queue,
154 program,
155 group_size_for_1d,
156 group_size_for_2d,
157 };
158 Ok(ClBackend { inner: Mutex::new(inner), })
159 }
160
161 fn check_and_enqueue_nd_range2<F, G>(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, f: F, g: G) -> Result<()>
162 where F: FnOnce(&ClBackendArray, &ClBackendArray) -> Result<()>,
163 G: FnOnce(&ClInnerBackend, &Kernel, cl_mem, cl_mem) -> Result<Event>
164 {
165 #[allow(unreachable_patterns)]
166 match (a, b) {
167 (BackendArray::OpenCl(a2), BackendArray::OpenCl(b2)) => {
168 f(a2, b2)?;
169 let inner_g = mutex_lock(&self.inner)?;
170 let kernel = match Kernel::create(&inner_g.program, kernel_name) {
171 Ok(tmp_kernel) => tmp_kernel,
172 Err(err) => return Err(Error::OpenCl(err)),
173 };
174 let event = if !Arc::ptr_eq(&a2.buffer, &b2.buffer) {
175 let a_buffer_g = mutex_lock(&a2.buffer)?;
176 let mut b_buffer_g = mutex_lock(&b2.buffer)?;
177 g(&*inner_g, &kernel, a_buffer_g.get(), b_buffer_g.get_mut())?
178 } else {
179 let mut a_buffer_g = mutex_lock(&a2.buffer)?;
180 g(&*inner_g, &kernel, a_buffer_g.get(), a_buffer_g.get_mut())?
181 };
182 match event.wait() {
183 Ok(()) => (),
184 Err(err) => return Err(Error::OpenCl(err)),
185 }
186 Ok(())
187 },
188 _ => Err(Error::InvalidBackendArray),
189 }
190 }
191
192 fn check_and_enqueue_nd_range3<F, G>(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, c: &BackendArray, f: F, g: G) -> Result<()>
193 where F: FnOnce(&ClBackendArray, &ClBackendArray, &ClBackendArray) -> Result<()>,
194 G: FnOnce(&ClInnerBackend, &Kernel, cl_mem, cl_mem, cl_mem) -> Result<Event>
195 {
196 #[allow(unreachable_patterns)]
197 match (a, b, c) {
198 (BackendArray::OpenCl(a2), BackendArray::OpenCl(b2), BackendArray::OpenCl(c2)) => {
199 f(a2, b2, c2)?;
200 let inner_g = mutex_lock(&self.inner)?;
201 let kernel = match Kernel::create(&inner_g.program, kernel_name) {
202 Ok(tmp_kernel) => tmp_kernel,
203 Err(err) => return Err(Error::OpenCl(err)),
204 };
205 let event = match (Arc::ptr_eq(&a2.buffer, &b2.buffer), Arc::ptr_eq(&a2.buffer, &c2.buffer), Arc::ptr_eq(&b2.buffer, &c2.buffer)) {
206 (false, false, false) => {
207 let a_buffer_g = mutex_lock(&a2.buffer)?;
208 let b_buffer_g = mutex_lock(&b2.buffer)?;
209 let mut c_buffer_g = mutex_lock(&c2.buffer)?;
210 g(&*inner_g, &kernel, a_buffer_g.get(), b_buffer_g.get(), c_buffer_g.get_mut())?
211 },
212 (true, false, false) => {
213 let a_buffer_g = mutex_lock(&a2.buffer)?;
214 let mut c_buffer_g = mutex_lock(&c2.buffer)?;
215 g(&*inner_g, &kernel, a_buffer_g.get(), a_buffer_g.get(), c_buffer_g.get_mut())?
216 },
217 (false, true, false) => {
218 let mut a_buffer_g = mutex_lock(&a2.buffer)?;
219 let b_buffer_g = mutex_lock(&b2.buffer)?;
220 g(&*inner_g, &kernel, a_buffer_g.get(), b_buffer_g.get(), a_buffer_g.get_mut())?
221 },
222 (false, false, true) => {
223 let a_buffer_g = mutex_lock(&a2.buffer)?;
224 let mut b_buffer_g = mutex_lock(&b2.buffer)?;
225 g(&*inner_g, &kernel, a_buffer_g.get(), b_buffer_g.get(), b_buffer_g.get_mut())?
226 },
227 _ => {
228 let mut a_buffer_g = mutex_lock(&a2.buffer)?;
229 g(&*inner_g, &kernel, a_buffer_g.get(), a_buffer_g.get(), a_buffer_g.get_mut())?
230 },
231 };
232 match event.wait() {
233 Ok(()) => (),
234 Err(err) => return Err(Error::OpenCl(err)),
235 }
236 Ok(())
237 },
238 _ => Err(Error::InvalidBackendArray),
239 }
240 }
241
242 fn check_and_enqueue_nd_range_for_fun(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, n: usize, m: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
243 {
244 self.check_and_enqueue_nd_range2(kernel_name, a, b, |a2, b2| {
245 if a2.len != n * m {
246 return Err(Error::BackendArrayElemCount(a2.len, n * m));
247 }
248 if b2.len != n * m {
249 return Err(Error::BackendArrayElemCount(b2.len, n * m));
250 }
251 Ok(())
252 }, |inner, kernel, a_mem, b_mem| {
253 let n2 = n as u64;
254 let m2 = m as u64;
255 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, false);
256 unsafe {
257 let res = ExecuteKernel::new(kernel)
258 .set_arg(&a_mem)
259 .set_arg(&b_mem)
260 .set_arg(&n2)
261 .set_arg(&m2)
262 .set_local_work_sizes(&[n3, m3])
263 .set_global_work_sizes(&[n4, m4])
264 .enqueue_nd_range(&inner.command_queue);
265 match res {
266 Ok(event) => Ok(event),
267 Err(err) => Err(Error::OpenCl(err)),
268 }
269 }
270 })
271 }
272
273 fn check_and_enqueue_nd_range_for_op(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
274 {
275 self.check_and_enqueue_nd_range3(kernel_name, a, b, c, |a2, b2, c2| {
276 if a2.len != n * m {
277 return Err(Error::BackendArrayElemCount(a2.len, n * m));
278 }
279 if b2.len != n * m {
280 return Err(Error::BackendArrayElemCount(b2.len, n * m));
281 }
282 if c2.len != n * m {
283 return Err(Error::BackendArrayElemCount(c2.len, n * m));
284 }
285 Ok(())
286 }, |inner, kernel, a_mem, b_mem, c_mem| {
287 let n2 = n as u64;
288 let m2 = m as u64;
289 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, false);
290 unsafe {
291 let res = ExecuteKernel::new(kernel)
292 .set_arg(&a_mem)
293 .set_arg(&b_mem)
294 .set_arg(&c_mem)
295 .set_arg(&n2)
296 .set_arg(&m2)
297 .set_local_work_sizes(&[n3, m3])
298 .set_global_work_sizes(&[n4, m4])
299 .enqueue_nd_range(&inner.command_queue);
300 match res {
301 Ok(event) => Ok(event),
302 Err(err) => Err(Error::OpenCl(err)),
303 }
304 }
305 })
306 }
307
308 fn check_and_enqueue_nd_range_for_mul(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize, l: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
309 {
310 self.check_and_enqueue_nd_range3(kernel_name, a, b, c, |a2, b2, c2| {
311 if a2.len != n * l {
312 return Err(Error::BackendArrayElemCount(a2.len, n * l));
313 }
314 if b2.len != l * m {
315 return Err(Error::BackendArrayElemCount(b2.len, l * m));
316 }
317 if c2.len != n * m {
318 return Err(Error::BackendArrayElemCount(c2.len, n * m));
319 }
320 Ok(())
321 }, |inner, kernel, a_mem, b_mem, c_mem| {
322 let n2 = n as u64;
323 let m2 = m as u64;
324 let l2 = l as u64;
325 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, true);
326 unsafe {
327 let res = ExecuteKernel::new(kernel)
328 .set_arg(&a_mem)
329 .set_arg(&b_mem)
330 .set_arg(&c_mem)
331 .set_arg_local_buffer(n3 * m3 * 8 * size_of::<f32>())
332 .set_arg_local_buffer(n3 * m3 * 4 * size_of::<f32>())
333 .set_arg(&n2)
334 .set_arg(&m2)
335 .set_arg(&l2)
336 .set_local_work_sizes(&[n3, m3])
337 .set_global_work_sizes(&[n4, m4])
338 .enqueue_nd_range(&inner.command_queue);
339 match res {
340 Ok(event) => Ok(event),
341 Err(err) => Err(Error::OpenCl(err)),
342 }
343 }
344 })
345 }
346
347 fn check_and_enqueue_nd_range_for_scalar(&self, kernel_name: &str, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
348 {
349 self.check_and_enqueue_nd_range2(kernel_name, a, c, |a2, c2| {
350 if a2.len != n * m {
351 return Err(Error::BackendArrayElemCount(a2.len, n * m));
352 }
353 if c2.len != n * m {
354 return Err(Error::BackendArrayElemCount(c2.len, n * m));
355 }
356 Ok(())
357 }, |inner, kernel, a_mem, c_mem| {
358 let n2 = n as u64;
359 let m2 = m as u64;
360 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, false);
361 unsafe {
362 let res = ExecuteKernel::new(kernel)
363 .set_arg(&a_mem)
364 .set_arg(&b)
365 .set_arg(&c_mem)
366 .set_arg(&n2)
367 .set_arg(&m2)
368 .set_local_work_sizes(&[n3, m3])
369 .set_global_work_sizes(&[n4, m4])
370 .enqueue_nd_range(&inner.command_queue);
371 match res {
372 Ok(event) => Ok(event),
373 Err(err) => Err(Error::OpenCl(err)),
374 }
375 }
376 })
377 }
378
379 fn check_and_enqueue_nd_range_for_fun_and_tiles(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, n: usize, m: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
380 {
381 self.check_and_enqueue_nd_range2(kernel_name, a, b, |a2, b2| {
382 if a2.len != n * m {
383 return Err(Error::BackendArrayElemCount(a2.len, n * m));
384 }
385 if b2.len != n * m {
386 return Err(Error::BackendArrayElemCount(b2.len, n * m));
387 }
388 Ok(())
389 }, |inner, kernel, a_mem, b_mem| {
390 let n2 = n as u64;
391 let m2 = m as u64;
392 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, false);
393 unsafe {
394 let res = ExecuteKernel::new(kernel)
395 .set_arg(&a_mem)
396 .set_arg(&b_mem)
397 .set_arg_local_buffer(n3 * item_row_count * m3 * item_col_count * size_of::<f32>())
398 .set_arg(&n2)
399 .set_arg(&m2)
400 .set_local_work_sizes(&[n3, m3])
401 .set_global_work_sizes(&[n4, m4])
402 .enqueue_nd_range(&inner.command_queue);
403 match res {
404 Ok(event) => Ok(event),
405 Err(err) => Err(Error::OpenCl(err)),
406 }
407 }
408 })
409 }
410
411 fn check_and_enqueue_nd_range_for_repeat_col(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, n: usize, m: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
412 {
413 self.check_and_enqueue_nd_range2(kernel_name, a, b, |a2, b2| {
414 if a2.len != n {
415 return Err(Error::BackendArrayElemCount(a2.len, n));
416 }
417 if b2.len != n * m {
418 return Err(Error::BackendArrayElemCount(b2.len, n * m));
419 }
420 Ok(())
421 }, |inner, kernel, a_mem, b_mem| {
422 let n2 = n as u64;
423 let m2 = m as u64;
424 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, false);
425 unsafe {
426 let res = ExecuteKernel::new(kernel)
427 .set_arg(&a_mem)
428 .set_arg(&b_mem)
429 .set_arg(&n2)
430 .set_arg(&m2)
431 .set_local_work_sizes(&[n3, m3])
432 .set_global_work_sizes(&[n4, m4])
433 .enqueue_nd_range(&inner.command_queue);
434 match res {
435 Ok(event) => Ok(event),
436 Err(err) => Err(Error::OpenCl(err)),
437 }
438 }
439 })
440 }
441
442 fn check_and_enqueue_nd_range_for_repeat_row(&self, kernel_name: &str, a: &BackendArray, b: &BackendArray, n: usize, m: usize, item_row_count: usize, item_col_count: usize, are_swapped_dims: bool) -> Result<()>
443 {
444 self.check_and_enqueue_nd_range2(kernel_name, a, b, |a2, b2| {
445 if a2.len != m {
446 return Err(Error::BackendArrayElemCount(a2.len, m));
447 }
448 if b2.len != n * m {
449 return Err(Error::BackendArrayElemCount(b2.len, n * m));
450 }
451 Ok(())
452 }, |inner, kernel, a_mem, b_mem| {
453 let n2 = n as u64;
454 let m2 = m as u64;
455 let (n3, m3, n4, m4) = preferred_work_sizes(n, m, inner.group_size_for_1d, inner.group_size_for_2d, item_row_count, item_col_count, are_swapped_dims, false);
456 unsafe {
457 let res = ExecuteKernel::new(kernel)
458 .set_arg(&a_mem)
459 .set_arg(&b_mem)
460 .set_arg(&n2)
461 .set_arg(&m2)
462 .set_local_work_sizes(&[n3, m3])
463 .set_global_work_sizes(&[n4, m4])
464 .enqueue_nd_range(&inner.command_queue);
465 match res {
466 Ok(event) => Ok(event),
467 Err(err) => Err(Error::OpenCl(err)),
468 }
469 }
470 })
471 }
472}
473
474impl Backend for ClBackend
475{
476 fn name(&self) -> &'static str
477 { "OpenCL" }
478
479 fn has_cublas(&self) -> bool
480 { false }
481
482 unsafe fn alloc(&self, n: usize) -> Result<BackendArray>
483 {
484 let inner_g = mutex_lock(&self.inner)?;
485 let buffer: Buffer<f32> = match Buffer::create(&inner_g.context, CL_MEM_READ_WRITE, n, null_mut()) {
486 Ok(tmp_buffer) => tmp_buffer,
487 Err(err) => return Err(Error::OpenCl(err)),
488 };
489 let cl_array = ClBackendArray { buffer: Arc::new(Mutex::new(buffer)), len: n, };
490 Ok(BackendArray::OpenCl(cl_array))
491 }
492
493 fn alloc_and_store_zeros(&self, n: usize) -> Result<BackendArray>
494 {
495 let inner_g = mutex_lock(&self.inner)?;
496 let mut buffer: Buffer<f32> = match unsafe { Buffer::create(&inner_g.context, CL_MEM_READ_WRITE, n, null_mut()) } {
497 Ok(tmp_buffer) => tmp_buffer,
498 Err(err) => return Err(Error::OpenCl(err)),
499 };
500 let event = match unsafe { inner_g.command_queue.enqueue_fill_buffer(&mut buffer, &[0.0f32], 0, n * size_of::<f32>(), &[]) } {
501 Ok(tmp_event) => tmp_event,
502 Err(err) => return Err(Error::OpenCl(err)),
503 };
504 match event.wait() {
505 Ok(()) => (),
506 Err(err) => return Err(Error::OpenCl(err)),
507 }
508 let cl_array = ClBackendArray { buffer: Arc::new(Mutex::new(buffer)), len: n, };
509 Ok(BackendArray::OpenCl(cl_array))
510 }
511
512 fn alloc_and_store(&self, elems: &[f32]) -> Result<BackendArray>
513 {
514 let inner_g = mutex_lock(&self.inner)?;
515 let mut buffer: Buffer<f32> = match unsafe { Buffer::create(&inner_g.context, CL_MEM_READ_WRITE, elems.len(), null_mut()) } {
516 Ok(tmp_buffer) => tmp_buffer,
517 Err(err) => return Err(Error::OpenCl(err)),
518 };
519 let event = match unsafe { inner_g.command_queue.enqueue_write_buffer(&mut buffer, CL_TRUE, 0, elems, &[]) } {
520 Ok(tmp_event) => tmp_event,
521 Err(err) => return Err(Error::OpenCl(err)),
522 };
523 match event.wait() {
524 Ok(()) => (),
525 Err(err) => return Err(Error::OpenCl(err)),
526 }
527 let cl_array = ClBackendArray { buffer: Arc::new(Mutex::new(buffer)), len: elems.len(), };
528 Ok(BackendArray::OpenCl(cl_array))
529 }
530
531 fn load(&self, a: &BackendArray, elems: &mut [f32]) -> Result<()>
532 {
533 #[allow(unreachable_patterns)]
534 match a {
535 BackendArray::OpenCl(a2) => {
536 if a2.len != elems.len() {
537 return Err(Error::BackendArrayElemCount(a2.len, elems.len()));
538 }
539 let inner_g = mutex_lock(&self.inner)?;
540 let a_buffer_g = mutex_lock(&a2.buffer)?;
541 let event = match unsafe { inner_g.command_queue.enqueue_read_buffer(&*a_buffer_g, CL_TRUE, 0, elems, &[]) } {
542 Ok(tmp_event) => tmp_event,
543 Err(err) => return Err(Error::OpenCl(err)),
544 };
545 match event.wait() {
546 Ok(()) => (),
547 Err(err) => return Err(Error::OpenCl(err)),
548 }
549 },
550 _ => return Err(Error::InvalidBackendArray),
551 }
552 Ok(())
553 }
554
555 fn store(&self, a: &BackendArray, elems: &[f32]) -> Result<()>
556 {
557 #[allow(unreachable_patterns)]
558 match a {
559 BackendArray::OpenCl(a2) => {
560 if a2.len != elems.len() {
561 return Err(Error::BackendArrayElemCount(a2.len, elems.len()));
562 }
563 let inner_g = mutex_lock(&self.inner)?;
564 let mut a_buffer_g = mutex_lock(&a2.buffer)?;
565 let event = match unsafe { inner_g.command_queue.enqueue_write_buffer(&mut *a_buffer_g, CL_TRUE, 0, elems, &[]) } {
566 Ok(tmp_event) => tmp_event,
567 Err(err) => return Err(Error::OpenCl(err)),
568 };
569 match event.wait() {
570 Ok(()) => (),
571 Err(err) => return Err(Error::OpenCl(err)),
572 }
573 },
574 _ => return Err(Error::InvalidBackendArray),
575 }
576 Ok(())
577 }
578
579 fn copy(&self, a: &BackendArray, b: &BackendArray) -> Result<()>
580 {
581 #[allow(unreachable_patterns)]
582 match (a, b) {
583 (BackendArray::OpenCl(a2), BackendArray::OpenCl(b2)) => {
584 if Arc::ptr_eq(&a2.buffer, &b2.buffer) {
585 return Ok(());
586 }
587 if a2.len != b2.len {
588 return Err(Error::TwoBackendArrayElemCounts(a2.len, b2.len));
589 }
590 let inner_g = mutex_lock(&self.inner)?;
591 let a_buffer_g = mutex_lock(&a2.buffer)?;
592 let mut b_buffer_g = mutex_lock(&b2.buffer)?;
593 let event = match unsafe { inner_g.command_queue.enqueue_copy_buffer(&*a_buffer_g, &mut *b_buffer_g, 0, 0, a2.len * size_of::<f32>(), &[]) } {
594 Ok(tmp_event) => tmp_event,
595 Err(err) => return Err(Error::OpenCl(err)),
596 };
597 match event.wait() {
598 Ok(()) => (),
599 Err(err) => return Err(Error::OpenCl(err)),
600 }
601 },
602 _ => return Err(Error::InvalidBackendArray),
603 }
604 Ok(())
605 }
606
607 fn transpose_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
608 { self.check_and_enqueue_nd_range_for_fun("transpose_a", a, b, n, m, 2, 2, true) }
609
610 fn add_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
611 { self.check_and_enqueue_nd_range_for_op("add_a_b", a, b, c, n, m, 2, 2, true) }
612
613 fn add_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
614 { self.check_and_enqueue_nd_range_for_op("add_at_b", a, b, c, n, m, 2, 2, true) }
615
616 fn add_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
617 { self.check_and_enqueue_nd_range_for_op("add_a_bt", a, b, c, n, m, 2, 2, true) }
618
619 fn add_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
620 { self.check_and_enqueue_nd_range_for_op("add_at_bt", a, b, c, n, m, 2, 2, true) }
621
622 fn sub_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
623 { self.check_and_enqueue_nd_range_for_op("sub_a_b", a, b, c, n, m, 2, 2, true) }
624
625 fn sub_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
626 { self.check_and_enqueue_nd_range_for_op("sub_at_b", a, b, c, n, m, 2, 2, true) }
627
628 fn sub_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
629 { self.check_and_enqueue_nd_range_for_op("sub_a_bt", a, b, c, n, m, 2, 2, true) }
630
631 fn sub_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
632 { self.check_and_enqueue_nd_range_for_op("sub_at_bt", a, b, c, n, m, 2, 2, true) }
633
634 fn mul_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize, l: usize) -> Result<()>
635 { self.check_and_enqueue_nd_range_for_mul("mul_a_b", a, b, c, n, m, l, 8, 4, true) }
636
637 fn mul_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize, l: usize) -> Result<()>
638 { self.check_and_enqueue_nd_range_for_mul("mul_at_b", a, b, c, n, m, l, 8, 4, false) }
639
640 fn mul_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize, l: usize) -> Result<()>
641 { self.check_and_enqueue_nd_range_for_mul("mul_a_bt", a, b, c, n, m, l, 8, 4, true) }
642
643 fn mul_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize, l: usize) -> Result<()>
644 { self.check_and_enqueue_nd_range_for_mul("mul_at_bt", a, b, c, n, m, l, 8, 4, false) }
645
646 fn mul_a_b_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
647 { self.check_and_enqueue_nd_range_for_op("mul_a_b_for_elems", a, b, c, n, m, 2, 2, true) }
648
649 fn mul_at_b_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
650 { self.check_and_enqueue_nd_range_for_op("mul_at_b_for_elems", a, b, c, n, m, 2, 2, true) }
651
652 fn mul_a_bt_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
653 { self.check_and_enqueue_nd_range_for_op("mul_a_bt_for_elems", a, b, c, n, m, 2, 2, true) }
654
655 fn mul_at_bt_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
656 { self.check_and_enqueue_nd_range_for_op("mul_at_bt_for_elems", a, b, c, n, m, 2, 2, true) }
657
658 fn div_a_b_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
659 { self.check_and_enqueue_nd_range_for_op("div_a_b_for_elems", a, b, c, n, m, 2, 2, true) }
660
661 fn div_at_b_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
662 { self.check_and_enqueue_nd_range_for_op("div_at_b_for_elems", a, b, c, n, m, 2, 2, true) }
663
664 fn div_a_bt_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
665 { self.check_and_enqueue_nd_range_for_op("div_a_bt_for_elems", a, b, c, n, m, 2, 2, true) }
666
667 fn div_at_bt_for_elems(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
668 { self.check_and_enqueue_nd_range_for_op("div_at_bt_for_elems", a, b, c, n, m, 2, 2, true) }
669
670 fn add_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
671 { self.check_and_enqueue_nd_range_for_scalar("add_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
672
673 fn add_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
674 { self.check_and_enqueue_nd_range_for_scalar("add_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
675
676 fn sub_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
677 { self.check_and_enqueue_nd_range_for_scalar("sub_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
678
679 fn sub_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
680 { self.check_and_enqueue_nd_range_for_scalar("sub_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
681
682 fn rsub_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
683 { self.check_and_enqueue_nd_range_for_scalar("rsub_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
684
685 fn rsub_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
686 { self.check_and_enqueue_nd_range_for_scalar("rsub_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
687
688 fn mul_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
689 { self.check_and_enqueue_nd_range_for_scalar("mul_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
690
691 fn mul_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
692 { self.check_and_enqueue_nd_range_for_scalar("mul_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
693
694 fn div_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
695 { self.check_and_enqueue_nd_range_for_scalar("div_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
696
697 fn div_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
698 { self.check_and_enqueue_nd_range_for_scalar("div_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
699
700 fn rdiv_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
701 { self.check_and_enqueue_nd_range_for_scalar("rdiv_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
702
703 fn rdiv_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
704 { self.check_and_enqueue_nd_range_for_scalar("rdiv_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
705
706 fn sigmoid_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
707 { self.check_and_enqueue_nd_range_for_fun("sigmoid_a", a, b, n, m, 2, 2, true) }
708
709 fn sigmoid_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
710 { self.check_and_enqueue_nd_range_for_fun("sigmoid_at", a, b, n, m, 2, 2, true) }
711
712 fn tanh_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
713 { self.check_and_enqueue_nd_range_for_fun("tanh_a", a, b, n, m, 2, 2, true) }
714
715 fn tanh_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
716 { self.check_and_enqueue_nd_range_for_fun("tanh_at", a, b, n, m, 2, 2, true) }
717
718 fn swish_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
719 { self.check_and_enqueue_nd_range_for_fun("swish_a", a, b, n, m, 2, 2, true) }
720
721 fn swish_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
722 { self.check_and_enqueue_nd_range_for_fun("swish_at", a, b, n, m, 2, 2, true) }
723
724 fn softmax_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
725 { self.check_and_enqueue_nd_range_for_fun_and_tiles("softmax_a", a, b, n, m, 2, 2, true) }
726
727 fn softmax_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
728 { self.check_and_enqueue_nd_range_for_fun_and_tiles("softmax_at", a, b, n, m, 2, 2, false) }
729
730 fn sqrt_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
731 { self.check_and_enqueue_nd_range_for_fun("sqrt_a", a, b, n, m, 2, 2, true) }
732
733 fn sqrt_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
734 { self.check_and_enqueue_nd_range_for_fun("sqrt_at", a, b, n, m, 2, 2, true) }
735
736 fn repeat_col_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
737 { self.check_and_enqueue_nd_range_for_repeat_col("repeat_col_a", a, b, n, m, 2, 2, true) }
738
739 fn repeat_row_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
740 { self.check_and_enqueue_nd_range_for_repeat_row("repeat_row_a", a, b, n, m, 2, 2, true) }
741
742 fn abs_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
743 { self.check_and_enqueue_nd_range_for_fun("abs_a", a, b, n, m, 2, 2, true) }
744
745 fn abs_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
746 { self.check_and_enqueue_nd_range_for_fun("abs_at", a, b, n, m, 2, 2, true) }
747
748 fn pow_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
749 { self.check_and_enqueue_nd_range_for_op("pow_a_b", a, b, c, n, m, 2, 2, true) }
750
751 fn pow_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
752 { self.check_and_enqueue_nd_range_for_op("pow_at_b", a, b, c, n, m, 2, 2, true) }
753
754 fn pow_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
755 { self.check_and_enqueue_nd_range_for_op("pow_a_bt", a, b, c, n, m, 2, 2, true) }
756
757 fn pow_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
758 { self.check_and_enqueue_nd_range_for_op("pow_at_bt", a, b, c, n, m, 2, 2, true) }
759
760 fn pow_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
761 { self.check_and_enqueue_nd_range_for_scalar("pow_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
762
763 fn pow_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
764 { self.check_and_enqueue_nd_range_for_scalar("pow_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
765
766 fn rpow_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
767 { self.check_and_enqueue_nd_range_for_scalar("rpow_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
768
769 fn rpow_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
770 { self.check_and_enqueue_nd_range_for_scalar("rpow_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
771
772 fn exp_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
773 { self.check_and_enqueue_nd_range_for_fun("exp_a", a, b, n, m, 2, 2, true) }
774
775 fn exp_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
776 { self.check_and_enqueue_nd_range_for_fun("exp_at", a, b, n, m, 2, 2, true) }
777
778 fn ln_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
779 { self.check_and_enqueue_nd_range_for_fun("ln_a", a, b, n, m, 2, 2, true) }
780
781 fn ln_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
782 { self.check_and_enqueue_nd_range_for_fun("ln_at", a, b, n, m, 2, 2, true) }
783
784 fn log2_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
785 { self.check_and_enqueue_nd_range_for_fun("log2_a", a, b, n, m, 2, 2, true) }
786
787 fn log2_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
788 { self.check_and_enqueue_nd_range_for_fun("log2_at", a, b, n, m, 2, 2, true) }
789
790 fn log10_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
791 { self.check_and_enqueue_nd_range_for_fun("log10_a", a, b, n, m, 2, 2, true) }
792
793 fn log10_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
794 { self.check_and_enqueue_nd_range_for_fun("log10_at", a, b, n, m, 2, 2, true) }
795
796 fn sin_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
797 { self.check_and_enqueue_nd_range_for_fun("sin_a", a, b, n, m, 2, 2, true) }
798
799 fn sin_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
800 { self.check_and_enqueue_nd_range_for_fun("sin_at", a, b, n, m, 2, 2, true) }
801
802 fn cos_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
803 { self.check_and_enqueue_nd_range_for_fun("cos_a", a, b, n, m, 2, 2, true) }
804
805 fn cos_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
806 { self.check_and_enqueue_nd_range_for_fun("cos_at", a, b, n, m, 2, 2, true) }
807
808 fn tan_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
809 { self.check_and_enqueue_nd_range_for_fun("tan_a", a, b, n, m, 2, 2, true) }
810
811 fn tan_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
812 { self.check_and_enqueue_nd_range_for_fun("tan_at", a, b, n, m, 2, 2, true) }
813
814 fn asin_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
815 { self.check_and_enqueue_nd_range_for_fun("asin_a", a, b, n, m, 2, 2, true) }
816
817 fn asin_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
818 { self.check_and_enqueue_nd_range_for_fun("asin_at", a, b, n, m, 2, 2, true) }
819
820 fn acos_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
821 { self.check_and_enqueue_nd_range_for_fun("acos_a", a, b, n, m, 2, 2, true) }
822
823 fn acos_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
824 { self.check_and_enqueue_nd_range_for_fun("acos_at", a, b, n, m, 2, 2, true) }
825
826 fn atan_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
827 { self.check_and_enqueue_nd_range_for_fun("atan_a", a, b, n, m, 2, 2, true) }
828
829 fn atan_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
830 { self.check_and_enqueue_nd_range_for_fun("atan_at", a, b, n, m, 2, 2, true) }
831
832 fn atan2_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
833 { self.check_and_enqueue_nd_range_for_op("atan2_a_b", a, b, c, n, m, 2, 2, true) }
834
835 fn atan2_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
836 { self.check_and_enqueue_nd_range_for_op("atan2_at_b", a, b, c, n, m, 2, 2, true) }
837
838 fn atan2_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
839 { self.check_and_enqueue_nd_range_for_op("atan2_a_bt", a, b, c, n, m, 2, 2, true) }
840
841 fn atan2_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
842 { self.check_and_enqueue_nd_range_for_op("atan2_at_bt", a, b, c, n, m, 2, 2, true) }
843
844 fn atan2_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
845 { self.check_and_enqueue_nd_range_for_scalar("atan2_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
846
847 fn atan2_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
848 { self.check_and_enqueue_nd_range_for_scalar("atan2_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
849
850 fn ratan2_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
851 { self.check_and_enqueue_nd_range_for_scalar("ratan2_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
852
853 fn ratan2_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
854 { self.check_and_enqueue_nd_range_for_scalar("ratan2_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
855
856 fn sinh_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
857 { self.check_and_enqueue_nd_range_for_fun("sinh_a", a, b, n, m, 2, 2, true) }
858
859 fn sinh_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
860 { self.check_and_enqueue_nd_range_for_fun("sinh_at", a, b, n, m, 2, 2, true) }
861
862 fn cosh_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
863 { self.check_and_enqueue_nd_range_for_fun("cosh_a", a, b, n, m, 2, 2, true) }
864
865 fn cosh_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
866 { self.check_and_enqueue_nd_range_for_fun("cosh_at", a, b, n, m, 2, 2, true) }
867
868 fn asinh_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
869 { self.check_and_enqueue_nd_range_for_fun("asinh_a", a, b, n, m, 2, 2, true) }
870
871 fn asinh_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
872 { self.check_and_enqueue_nd_range_for_fun("asinh_at", a, b, n, m, 2, 2, true) }
873
874 fn acosh_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
875 { self.check_and_enqueue_nd_range_for_fun("acosh_a", a, b, n, m, 2, 2, true) }
876
877 fn acosh_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
878 { self.check_and_enqueue_nd_range_for_fun("acosh_at", a, b, n, m, 2, 2, true) }
879
880 fn atanh_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
881 { self.check_and_enqueue_nd_range_for_fun("atanh_a", a, b, n, m, 2, 2, true) }
882
883 fn atanh_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
884 { self.check_and_enqueue_nd_range_for_fun("atanh_at", a, b, n, m, 2, 2, true) }
885
886 fn signum_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
887 { self.check_and_enqueue_nd_range_for_fun("signum_a", a, b, n, m, 2, 2, true) }
888
889 fn signum_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
890 { self.check_and_enqueue_nd_range_for_fun("signum_at", a, b, n, m, 2, 2, true) }
891
892 fn ceil_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
893 { self.check_and_enqueue_nd_range_for_fun("ceil_a", a, b, n, m, 2, 2, true) }
894
895 fn ceil_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
896 { self.check_and_enqueue_nd_range_for_fun("ceil_at", a, b, n, m, 2, 2, true) }
897
898 fn floor_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
899 { self.check_and_enqueue_nd_range_for_fun("floor_a", a, b, n, m, 2, 2, true) }
900
901 fn floor_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
902 { self.check_and_enqueue_nd_range_for_fun("floor_at", a, b, n, m, 2, 2, true) }
903
904 fn round_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
905 { self.check_and_enqueue_nd_range_for_fun("round_a", a, b, n, m, 2, 2, true) }
906
907 fn round_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
908 { self.check_and_enqueue_nd_range_for_fun("round_at", a, b, n, m, 2, 2, true) }
909
910 fn trunc_a(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
911 { self.check_and_enqueue_nd_range_for_fun("trunc_a", a, b, n, m, 2, 2, true) }
912
913 fn trunc_at(&self, a: &BackendArray, b: &BackendArray, n: usize, m: usize) -> Result<()>
914 { self.check_and_enqueue_nd_range_for_fun("trunc_at", a, b, n, m, 2, 2, true) }
915
916 fn max_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
917 { self.check_and_enqueue_nd_range_for_op("max_a_b", a, b, c, n, m, 2, 2, true) }
918
919 fn max_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
920 { self.check_and_enqueue_nd_range_for_op("max_at_b", a, b, c, n, m, 2, 2, true) }
921
922 fn max_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
923 { self.check_and_enqueue_nd_range_for_op("max_a_bt", a, b, c, n, m, 2, 2, true) }
924
925 fn max_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
926 { self.check_and_enqueue_nd_range_for_op("max_at_bt", a, b, c, n, m, 2, 2, true) }
927
928 fn max_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
929 { self.check_and_enqueue_nd_range_for_scalar("max_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
930
931 fn max_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
932 { self.check_and_enqueue_nd_range_for_scalar("max_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
933
934 fn min_a_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
935 { self.check_and_enqueue_nd_range_for_op("min_a_b", a, b, c, n, m, 2, 2, true) }
936
937 fn min_at_b(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
938 { self.check_and_enqueue_nd_range_for_op("min_at_b", a, b, c, n, m, 2, 2, true) }
939
940 fn min_a_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
941 { self.check_and_enqueue_nd_range_for_op("min_a_bt", a, b, c, n, m, 2, 2, true) }
942
943 fn min_at_bt(&self, a: &BackendArray, b: &BackendArray, c: &BackendArray, n: usize, m: usize) -> Result<()>
944 { self.check_and_enqueue_nd_range_for_op("min_at_bt", a, b, c, n, m, 2, 2, true) }
945
946 fn min_a_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
947 { self.check_and_enqueue_nd_range_for_scalar("min_a_b_for_scalar", a, b, c, n, m, 2, 2, true) }
948
949 fn min_at_b_for_scalar(&self, a: &BackendArray, b: f32, c: &BackendArray, n: usize, m: usize) -> Result<()>
950 { self.check_and_enqueue_nd_range_for_scalar("min_at_b_for_scalar", a, b, c, n, m, 2, 2, true) }
951}
952
953#[cfg(test)]
954mod tests;