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