1use crate::ir::{ExpandValue, Scope};
2use crate::{
3 flex32,
4 frontend::{CubePrimitive, NativeExpand},
5 prelude::*,
6};
7use crate::{frontend::CubeType, tf32};
8use crate::{frontend::operation::base::binary_expand, unexpanded};
9use core::ops::*;
10use cubecl_ir::dialect::{
11 bitwise::*,
12 cmp::BoolNotEqualOp,
13 general::{BoolAndOp, BoolOrOp},
14 math::*,
15 vector::{FDotOp, SDotOp, UDotOp},
16};
17use half::{bf16, f16};
18
19pub mod sub {
20 use cubecl_ir::{ConstantValue, ExpandValue};
21
22 use super::*;
23
24 pub fn expand<C: CubeSub>(
25 scope: &Scope,
26 lhs: NativeExpand<C>,
27 rhs: NativeExpand<C>,
28 ) -> NativeExpand<C> {
29 match (lhs.expand, rhs.expand.as_const()) {
31 (
32 ExpandValue::Constant {
33 value: ConstantValue::UInt(lhs_val),
34 ty,
35 },
36 Some(ConstantValue::UInt(rhs_val)),
37 ) => {
38 let value = (lhs_val - rhs_val).into();
39 ExpandValue::constant(value, ty).into()
40 }
41 _ => C::Scalar::__expand_native_sub(scope, lhs.into(), rhs.into()).into(),
42 }
43 }
44}
45
46pub mod clamp {
47 use super::*;
48
49 pub fn expand<C: CubePartialOrd>(
50 scope: &Scope,
51 input: NativeExpand<C>,
52 min: NativeExpand<C>,
53 max: NativeExpand<C>,
54 ) -> NativeExpand<C> {
55 C::Scalar::__expand_native_clamp(scope, input.into(), min.into(), max.into()).into()
56 }
57}
58
59#[allow(unused_variables)]
63pub fn min_nan<C: CubePrimitive<Scalar: Float>>(lhs: C, rhs: C) -> C {
64 unexpanded!()
65}
66
67pub mod min_nan {
69 use super::*;
70 use cubecl_ir::dialect::cmp::FMinNanOp;
71
72 pub fn expand<C: CubePrimitive<Scalar: Float>>(
73 scope: &Scope,
74 lhs: NativeExpand<C>,
75 rhs: NativeExpand<C>,
76 ) -> NativeExpand<C> {
77 let [lhs, rhs] =
78 normalize_same_vectorization(scope, [lhs.read_value(scope), rhs.read_value(scope)]);
79 let op = FMinNanOp::new(scope.ctx_mut(), lhs, rhs);
80 scope.register_with_result(&op).into()
81 }
82}
83
84#[allow(unused_variables)]
88pub fn max_nan<C: CubePrimitive<Scalar: Float>>(lhs: C, rhs: C) -> C {
89 unexpanded!()
90}
91
92pub mod max_nan {
94 use super::*;
95 use cubecl_ir::dialect::cmp::FMaxNanOp;
96
97 pub fn expand<C: CubePrimitive<Scalar: Float>>(
98 scope: &Scope,
99 lhs: NativeExpand<C>,
100 rhs: NativeExpand<C>,
101 ) -> NativeExpand<C> {
102 let [lhs, rhs] =
103 normalize_same_vectorization(scope, [lhs.read_value(scope), rhs.read_value(scope)]);
104 let op = FMaxNanOp::new(scope.ctx_mut(), lhs, rhs);
105 scope.register_with_result(&op).into()
106 }
107}
108
109#[allow(unused_variables)]
115pub fn clamp_nan<C: CubePrimitive<Scalar: Float>>(input: C, min: C, max: C) -> C {
116 unexpanded!()
117}
118
119pub mod clamp_nan {
121 use super::*;
122 use cubecl_ir::dialect::cmp::FClampNanOp;
123
124 pub fn expand<C: CubePrimitive<Scalar: Float>>(
125 scope: &Scope,
126 input: NativeExpand<C>,
127 min: NativeExpand<C>,
128 max: NativeExpand<C>,
129 ) -> NativeExpand<C> {
130 let [input, min, max] = normalize_same_vectorization(
131 scope,
132 [
133 input.read_value(scope),
134 min.read_value(scope),
135 max.read_value(scope),
136 ],
137 );
138 let op = FClampNanOp::new(scope.ctx_mut(), input, min, max);
139 scope.register_with_result(&op).into()
140 }
141}
142
143pub mod clamp_max {
144 use super::*;
145
146 pub fn expand<C: CubePartialOrd>(
147 scope: &Scope,
148 lhs: NativeExpand<C>,
149 rhs: NativeExpand<C>,
150 ) -> NativeExpand<C> {
151 C::Scalar::__expand_native_min(scope, lhs.into(), rhs.into()).into()
152 }
153}
154
155pub mod clamp_min {
156 use super::*;
157
158 pub fn expand<C: CubePartialOrd>(
159 scope: &Scope,
160 lhs: NativeExpand<C>,
161 rhs: NativeExpand<C>,
162 ) -> NativeExpand<C> {
163 C::Scalar::__expand_native_max(scope, lhs.into(), rhs.into()).into()
164 }
165}
166
167pub fn min<T: CubePartialOrd>(lhs: T, rhs: T) -> T {
170 clamp_max(lhs, rhs)
171}
172
173pub mod min {
174 use super::*;
175
176 pub fn expand<C: CubePartialOrd>(
177 scope: &Scope,
178 lhs: NativeExpand<C>,
179 rhs: NativeExpand<C>,
180 ) -> NativeExpand<C> {
181 C::Scalar::__expand_native_min(scope, lhs.into(), rhs.into()).into()
182 }
183}
184
185pub fn max<T: CubePartialOrd>(lhs: T, rhs: T) -> T {
188 clamp_min(lhs, rhs)
189}
190
191pub mod max {
192 use super::*;
193
194 pub fn expand<C: CubePartialOrd>(
195 scope: &Scope,
196 lhs: NativeExpand<C>,
197 rhs: NativeExpand<C>,
198 ) -> NativeExpand<C> {
199 C::Scalar::__expand_native_max(scope, lhs.into(), rhs.into()).into()
200 }
201}
202
203macro_rules! define_binary_func {
205 ($trait_name:ident, $method_name:ident) => {
206 paste::paste! {
207 pub trait [<Scalar $trait_name>]: $trait_name + [<$trait_name NativeExpand>] {}
208 impl<T: $trait_name + [<$trait_name NativeExpand>]> [<Scalar $trait_name>] for T {}
209
210 pub trait $trait_name: CubePrimitive<Scalar: [<$trait_name NativeExpand>]>
211 + CubeType<ExpandType: [<$trait_name Expand>]> + Sized {
212 fn $method_name(self, _rhs: Self) -> Self {
213 unexpanded!()
214 }
215
216 fn [<__expand_ $method_name>](
217 scope: &Scope,
218 lhs: NativeExpand<Self>,
219 rhs: NativeExpand<Self>,
220 ) -> NativeExpand<Self> {
221 lhs.[<__expand_ $method_name _method>](scope, rhs)
222 }
223 }
224
225 pub trait [<$trait_name Expand>] {
226 fn [<__expand_ $method_name _method>](self, scope: &Scope, rhs: Self) -> Self;
227 }
228
229 pub trait [<$trait_name NativeExpand>] {
230 fn [<__expand_native_ $method_name>](scope: &Scope, lhs: ExpandValue, rhs: ExpandValue) -> ExpandValue;
231 }
232
233 impl<T: $trait_name> [<$trait_name Expand>] for NativeExpand<T> {
234 fn [<__expand_ $method_name _method>](self, scope: &Scope, rhs: Self) -> Self {
235 T::Scalar::[<__expand_native_ $method_name>](scope, self.into(), rhs.into()).into()
236 }
237 }
238 }
239 }
240}
241
242macro_rules! impl_binary_func {
243 ($($type:ty),*; $trait_name:ident, $method_name:ident, $operator:expr) => {
244 paste::paste! {
245 $(impl $trait_name for $type {})*
246 $(impl [<$trait_name NativeExpand>] for $type {
247 fn [<__expand_native_ $method_name>](scope: &Scope, lhs: ExpandValue, rhs: ExpandValue) -> ExpandValue {
248 binary_expand(scope, lhs, rhs, $operator::new)
249 }
250 })*
251 }
252 }
253}
254
255macro_rules! define_binary_func_scalar_out {
256 ($trait_name:ident, $method_name:ident) => {
257 paste::paste! {
258 pub trait [<Scalar $trait_name>]: $trait_name + [<$trait_name NativeExpand>] {}
259 impl<T: $trait_name + [<$trait_name NativeExpand>]> [<Scalar $trait_name>] for T {}
260
261 pub trait $trait_name: CubePrimitive<Scalar: [<$trait_name NativeExpand>]>
262 + CubeType<ExpandType: [<$trait_name Expand>]
263 + CubePrimitiveExpand<Scalar = NativeExpand<Self::Scalar>>>
264 + Sized {
265 fn $method_name(self, _rhs: Self) -> Self::Scalar {
266 unexpanded!()
267 }
268
269 fn [<__expand_ $method_name>](
270 scope: &Scope,
271 lhs: NativeExpand<Self>,
272 rhs: NativeExpand<Self>,
273 ) -> NativeExpand<Self::Scalar> {
274 lhs.[<__expand_ $method_name _method>](scope, rhs)
275 }
276 }
277
278 pub trait [<$trait_name Expand>]: CubePrimitiveExpand {
279 fn [<__expand_ $method_name _method>](self, scope: &Scope, rhs: Self) -> Self::Scalar;
280 }
281
282 pub trait [<$trait_name NativeExpand>] {
283 fn [<__expand_native_ $method_name _scalar>](scope: &Scope, lhs: ExpandValue, rhs: ExpandValue) -> ExpandValue;
284 fn [<__expand_native_ $method_name>](scope: &Scope, lhs: ExpandValue, rhs: ExpandValue) -> ExpandValue;
285 }
286
287 impl<T: CubePrimitive + $trait_name> [<$trait_name Expand>] for NativeExpand<T> {
288 fn [<__expand_ $method_name _method>](self, scope: &Scope, rhs: Self) -> Self::Scalar {
289 if self.__expand_vector_size_method(scope) == 1 {
292 T::Scalar::[<__expand_native_ $method_name _scalar>](scope, self.into(), rhs.into()).into()
293 } else {
294 T::Scalar::[<__expand_native_ $method_name>](scope, self.into(), rhs.into()).into()
295 }
296 }
297 }
298 }
299 }
300}
301
302macro_rules! impl_binary_func_scalar_out {
303 ($($type:ty),*; $trait_name:ident, $method_name:ident, $operator:expr, $scalar_op:expr) => {
304 paste::paste! {
305 $(impl $trait_name for $type {})*
306 $(impl [<$trait_name NativeExpand>] for $type {
307 fn [<__expand_native_ $method_name _scalar>](scope: &Scope, lhs: ExpandValue, rhs: ExpandValue) -> ExpandValue {
308 binary_expand(scope, lhs, rhs, $scalar_op::new)
309 }
310 fn [<__expand_native_ $method_name>](scope: &Scope, lhs: ExpandValue, rhs: ExpandValue) -> ExpandValue {
311 binary_expand(scope, lhs, rhs, $operator::new)
312 }
313 })*
314 }
315 }
316}
317
318macro_rules! impl_binary_func_mixed_types {
319 ($trait_name:ident, $method_name:ident, $rhs_ty: ident, $operator:expr, $($type:ty),*) => {
320 paste::paste! {
321 pub trait $trait_name<Rhs: CubePrimitive + CubeType<ExpandType: Into<ExpandValue>> + Sized>:
322 CubePrimitive + CubeType<ExpandType: [<$trait_name Expand>]<Rhs>> + Sized {
323 fn $method_name(self, _rhs: Rhs) -> Self {
324 unexpanded!()
325 }
326
327 fn [<__expand_ $method_name>](
328 scope: &Scope,
329 lhs: NativeExpand<Self>,
330 rhs: NativeExpand<Rhs>,
331 ) -> NativeExpand<Self> {
332 binary_expand(scope, lhs.into(), rhs.into(), $operator::new).into()
333 }
334 }
335
336 pub trait [<$trait_name Expand>]<Rhs: CubeType>{
337 fn [<__expand_ $method_name _method>](self, scope: &Scope, rhs: Rhs::ExpandType) -> Self;
338 }
339
340 $(impl $trait_name<$rhs_ty> for $type {})*
341 impl<Rhs: CubePrimitive, T: CubePrimitive + $trait_name<Rhs>> [<$trait_name Expand>]<Rhs> for NativeExpand<T> {
342 fn [<__expand_ $method_name _method>](self, scope: &Scope, rhs: NativeExpand<Rhs>) -> Self {
343 binary_expand(scope, self.into(), rhs.into(), $operator::new).into()
344 }
345 }
346 }
347 }
348}
349
350macro_rules! define_core_binop {
351 ($trait: ident, $method: ident) => {
352 paste::paste! {
353 pub trait [<Scalar $trait>]: [<Cube $trait>] + [<$trait NativeExpand>] {}
354 impl<T: [<Cube $trait>] + [<$trait NativeExpand>]> [<Scalar $trait>] for T {}
355
356 pub trait [<Cube $trait>]:
357 $trait<Output = Self> + CubePrimitive<Scalar: [<$trait NativeExpand>]> + IntoRuntime
358 + CubeType<ExpandType: [<$trait Expand>]> + Sized {
359 fn [<__expand_ $method _method>](self, scope: &Scope, rhs: NativeExpand<Self>) -> NativeExpand<Self> {
360 let this = self.__expand_runtime_method(scope);
361 this.[<__expand_ $method _method>](scope, rhs)
362 }
363
364 fn [<__expand_ $method>](
365 scope: &Scope,
366 lhs: NativeExpand<Self>,
367 rhs: NativeExpand<Self>,
368 ) -> NativeExpand<Self> {
369 lhs.[<__expand_ $method _method>](scope, rhs)
370 }
371 }
372
373 pub trait [<$trait Expand>] {
374 fn [<__expand_ $method _method>](self, scope: &Scope, rhs: Self) -> Self;
375 }
376
377 pub trait [<$trait NativeExpand>] {
378 fn [<__expand_native_ $method>](scope: &Scope, this: ExpandValue, rhs: ExpandValue) -> ExpandValue;
379 }
380
381 impl<T: $trait<Output = Self> + CubePrimitive<Scalar: [<$trait NativeExpand>]> + IntoRuntime> [<Cube $trait>] for T {}
382 impl<T: [<Cube $trait>]> [<$trait Expand>] for NativeExpand<T> {
383 fn [<__expand_ $method _method>](self, scope: &Scope, rhs: Self) -> Self {
384 T::Scalar::[<__expand_native_ $method>](scope, self.into(), rhs.into()).into()
385 }
386 }
387 }
388 };
389}
390
391macro_rules! impl_core_binop {
392 ($($ty: ty),*; $trait: ident, $method: ident, $op: expr) => {
393 paste::paste! {
394 $(impl [<$trait NativeExpand>] for $ty {
395 fn [<__expand_native_ $method>](scope: &Scope, this: ExpandValue, rhs: ExpandValue) -> ExpandValue {
396 binary_expand(scope, this, rhs, $op::new)
397 }
398 })*
399 }
400 };
401}
402macro_rules! define_core_assign_binop {
403 ($trait: ident, $base_trait: ident, $method: ident, $base_method: ident) => {
404 paste::paste! {
405 pub trait [<Cube $trait>]: $trait + CubePrimitive<Scalar: [<$base_trait NativeExpand>]>
406 + CubeType<ExpandType: [<$trait Expand>]> + Sized {
407 fn [<__expand_ $method>](
408 scope: &Scope,
409 lhs: &mut NativeExpand<Self>,
410 rhs: NativeExpand<Self>,
411 ) {
412 lhs.[<__expand_ $method _method>](scope, rhs)
413 }
414 }
415
416 pub trait [<$trait Expand>] {
417 fn [<__expand_ $method _method>](&mut self, scope: &Scope, rhs: Self);
418 }
419
420 impl<T: $trait + [<Cube $base_trait>]> [<Cube $trait>] for T {}
421 impl<T: $trait + [<Cube $base_trait>]> [<$trait Expand>] for NativeExpand<T> {
422 fn [<__expand_ $method _method>](&mut self, scope: &Scope, rhs: Self) {
423 assign_binop_expand(scope, self, rhs, T::Scalar::[<__expand_native_ $base_method>]);
424 }
425 }
426 }
427 };
428}
429
430define_core_binop!(Add, add);
431define_core_binop!(Sub, sub);
432define_core_binop!(Mul, mul);
433define_core_binop!(Div, div);
434define_core_binop!(Rem, rem);
435
436impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; Add, add, IAddOp);
437impl_core_binop!(f16, bf16, f32, flex32, tf32, f64; Add, add, FAddOp);
438
439impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; Sub, sub, ISubOp);
440impl_core_binop!(f16, bf16, f32, flex32, tf32, f64; Sub, sub, FSubOp);
441
442impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; Mul, mul, IMulOp);
443impl_core_binop!(f16, bf16, f32, flex32, tf32, f64; Mul, mul, FMulOp);
444
445impl_core_binop!(i8, i16, i32, i64, isize; Div, div, SDivOp);
446impl_core_binop!(u8, u16, u32, u64, usize; Div, div, UDivOp);
447impl_core_binop!(f16, bf16, f32, flex32, tf32, f64; Div, div, FDivOp);
448
449impl_core_binop!(i8, i16, i32, i64, isize; Rem, rem, SRemOp);
450impl_core_binop!(u8, u16, u32, u64, usize; Rem, rem, URemOp);
451impl_core_binop!(f16, bf16, f32, flex32, tf32, f64; Rem, rem, FRemOp);
452
453define_core_assign_binop!(AddAssign, Add, add_assign, add);
454define_core_assign_binop!(SubAssign, Sub, sub_assign, sub);
455define_core_assign_binop!(MulAssign, Mul, mul_assign, mul);
456define_core_assign_binop!(DivAssign, Div, div_assign, div);
457define_core_assign_binop!(RemAssign, Rem, rem_assign, rem);
458
459define_core_binop!(BitAnd, bitand);
460define_core_binop!(BitOr, bitor);
461define_core_binop!(BitXor, bitxor);
462define_core_binop!(Shl, shl);
463define_core_binop!(Shr, shr);
464
465impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; BitAnd, bitand, BitwiseAndOp);
466impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; BitOr, bitor, BitwiseOrOp);
467impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; BitXor, bitxor, BitwiseXorOp);
468impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; Shl, shl, ShiftLeftOp);
469impl_core_binop!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; Shr, shr, ShiftRightOp);
470
471define_core_assign_binop!(BitAndAssign, BitAnd, bitand_assign, bitand);
472define_core_assign_binop!(BitOrAssign, BitOr, bitor_assign, bitor);
473define_core_assign_binop!(BitXorAssign, BitXor, bitxor_assign, bitxor);
474define_core_assign_binop!(ShlAssign, Shl, shl_assign, shl);
475define_core_assign_binop!(ShrAssign, Shr, shr_assign, shr);
476
477impl BitAndNativeExpand for bool {
478 fn __expand_native_bitand(scope: &Scope, this: ExpandValue, rhs: ExpandValue) -> ExpandValue {
479 binary_expand(scope, this, rhs, BoolAndOp::new)
480 }
481}
482impl BitOrNativeExpand for bool {
483 fn __expand_native_bitor(scope: &Scope, this: ExpandValue, rhs: ExpandValue) -> ExpandValue {
484 binary_expand(scope, this, rhs, BoolOrOp::new)
485 }
486}
487impl BitXorNativeExpand for bool {
488 fn __expand_native_bitxor(scope: &Scope, this: ExpandValue, rhs: ExpandValue) -> ExpandValue {
489 binary_expand(scope, this, rhs, BoolNotEqualOp::new)
490 }
491}
492
493pub trait CubeAnd:
494 CubePrimitive + Into<ExpandValue> + CubeType<ExpandType: AndExpand> + Sized
495{
496 fn __expand_and_method(self, scope: &Scope, rhs: NativeExpand<Self>) -> NativeExpand<Self> {
497 let this: ExpandValue = self.into();
498 let this: NativeExpand<Self> = this.into();
499 this.__expand_and_method(scope, rhs)
500 }
501 fn __expand_and(
502 scope: &Scope,
503 lhs: NativeExpand<Self>,
504 rhs: NativeExpand<Self>,
505 ) -> NativeExpand<Self> {
506 lhs.__expand_and_method(scope, rhs)
507 }
508}
509pub trait AndExpand {
510 fn __expand_and_method(self, scope: &Scope, rhs: Self) -> Self;
511}
512
513impl CubeAnd for bool {}
514impl<T: CubeAnd + CubePrimitive> AndExpand for NativeExpand<T> {
515 fn __expand_and_method(self, scope: &Scope, rhs: Self) -> Self {
516 binary_expand(scope, self.into(), rhs.into(), BoolAndOp::new).into()
517 }
518}
519
520pub trait CubeOr:
521 CubePrimitive + Into<ExpandValue> + CubeType<ExpandType: OrExpand> + Sized
522{
523 fn __expand_or_method(self, scope: &Scope, rhs: NativeExpand<Self>) -> NativeExpand<Self> {
524 let this: ExpandValue = self.into();
525 let this: NativeExpand<Self> = this.into();
526 this.__expand_or_method(scope, rhs)
527 }
528 fn __expand_or(
529 scope: &Scope,
530 lhs: NativeExpand<Self>,
531 rhs: NativeExpand<Self>,
532 ) -> NativeExpand<Self> {
533 lhs.__expand_or_method(scope, rhs)
534 }
535}
536pub trait OrExpand {
537 fn __expand_or_method(self, scope: &Scope, rhs: Self) -> Self;
538}
539
540impl CubeOr for bool {}
541impl<T: CubeOr + CubePrimitive> OrExpand for NativeExpand<T> {
542 fn __expand_or_method(self, scope: &Scope, rhs: Self) -> Self {
543 binary_expand(scope, self.into(), rhs.into(), BoolOrOp::new).into()
544 }
545}
546
547define_binary_func!(Powf, powf);
548impl_binary_func!(f16, bf16, flex32, tf32, f32, f64; Powf, powf, PowfOp);
549
550define_binary_func!(Hypot, hypot);
551impl_binary_func!(f16, bf16, flex32, tf32, f32, f64; Hypot, hypot, HypotOp);
552
553define_binary_func!(Rhypot, rhypot);
554impl_binary_func!(f16, bf16, flex32, tf32, f32, f64; Rhypot, rhypot, RhypotOp);
555
556define_binary_func!(ArcTan2, atan2);
557impl_binary_func!(f16, bf16, flex32, tf32, f32, f64; ArcTan2, atan2, ArcTan2Op);
558
559define_binary_func!(ModFloor, mod_floor);
560impl_binary_func!(i8, i16, i32, i64, isize; ModFloor, mod_floor, SModFloorOp);
561impl_binary_func!(u8, u16, u32, u64, usize; ModFloor, mod_floor, URemOp);
562impl_binary_func!(f16, bf16, flex32, tf32, f32, f64; ModFloor, mod_floor, FModFloorOp);
563
564define_binary_func!(MulHi, mul_hi);
565impl_binary_func!(i32, i64, isize; MulHi, mul_hi, SMulHiOp);
566impl_binary_func!(u32, u64, usize; MulHi, mul_hi, UMulHiOp);
567
568define_binary_func!(SaturatingAdd, saturating_add);
569impl_binary_func!(i8, i16, i32, i64, isize; SaturatingAdd, saturating_add, SaturatingSAddOp);
570impl_binary_func!(u8, u16, u32, u64, usize; SaturatingAdd, saturating_add, SaturatingUAddOp);
571
572define_binary_func!(SaturatingSub, saturating_sub);
573impl_binary_func!(i8, i16, i32, i64, isize; SaturatingSub, saturating_sub, SaturatingSSubOp);
574impl_binary_func!(u8, u16, u32, u64, usize; SaturatingSub, saturating_sub, SaturatingUSubOp);
575
576define_binary_func_scalar_out!(Dot, dot);
577impl_binary_func_scalar_out!(i8, i16, i32, i64, isize; Dot, dot, SDotOp, IMulOp);
578impl_binary_func_scalar_out!(u8, u16, u32, u64, usize; Dot, dot, UDotOp, IMulOp);
579impl_binary_func_scalar_out!(f16, bf16, flex32, tf32, f32, f64; Dot, dot, FDotOp, FMulOp);
580
581impl_binary_func_mixed_types!(
582 Powi, powi, i32, PowiOp, f16, bf16, flex32, tf32, f32, f64, i8, i16, i32, i64, u8, u16, u32,
583 u64, usize, isize
584);