1use core::ops::Neg;
2
3use cubecl_macros_internal::{const_eval, cube_op, simplify};
4use half::{bf16, f16};
5use num::Integer;
6use num_traits::Float;
7use pliron::{
8 attribute::AttrObj,
9 builtin::{attributes::IntegerAttr, types::IntegerType},
10 utils::apint::{APInt, bw},
11};
12
13use crate::{
14 CanMaterialize, ConstantValue, NoMemoryEffect, NoSideEffects, Pure,
15 attributes::{BoolAttr, FloatAttr, IndexAttr, IntAttrExt},
16 dialect::{pure_binop, pure_unop},
17 interfaces::{TriviallyUnrollable, TypedExt},
18 prelude::*,
19 types::{VectorType, scalar::BoolType},
20};
21
22pure_unop!("math.s_abs", SAbsOp);
23const_eval!(SAbsOp, {
24 [IntegerAttr(i8, i16, i32, i64)]: |inp| inp.abs(),
25});
26
27pure_unop!("math.f_abs", FAbsOp);
28const_eval!(FAbsOp, {
29 [FloatAttr(f16, bf16, f32, f64)]: |inp| inp.abs(),
30});
31
32pure_unop!("math.exp", ExpOp);
33const_eval!(ExpOp, {
34 FloatAttr(f16, bf16, f32, f64): |inp| inp.exp(),
35});
36
37pure_unop!("math.log", LogOp);
38const_eval!(LogOp, {
39 FloatAttr(f16, bf16, f32, f64): |inp| inp.ln(),
40});
41
42pure_unop!("math.log1p", Log1pOp);
43const_eval!(Log1pOp, {
44 FloatAttr(f16, bf16, f32, f64): |inp| inp.ln_1p(),
45});
46
47pure_unop!("math.expm1", Expm1Op);
48const_eval!(Expm1Op, {
49 FloatAttr(f16, bf16, f32, f64): |inp| inp.exp_m1(),
50});
51
52pure_unop!("math.sin", SinOp);
53const_eval!(SinOp, {
54 FloatAttr(f16, bf16, f32, f64): |inp| inp.sin(),
55});
56
57pure_unop!("math.cos", CosOp);
58const_eval!(CosOp, {
59 FloatAttr(f16, bf16, f32, f64): |inp| inp.cos(),
60});
61
62pure_unop!("math.tan", TanOp);
63const_eval!(TanOp, {
64 FloatAttr(f16, bf16, f32, f64): |inp| inp.tan(),
65});
66
67pure_unop!("math.sinh", SinhOp);
68const_eval!(SinhOp, {
69 FloatAttr(f16, bf16, f32, f64): |inp| inp.sinh(),
70});
71
72pure_unop!("math.cosh", CoshOp);
73const_eval!(CoshOp, {
74 FloatAttr(f16, bf16, f32, f64): |inp| inp.cosh(),
75});
76
77pure_unop!("math.tanh", TanhOp);
78const_eval!(TanhOp, {
79 FloatAttr(f16, bf16, f32, f64): |inp| inp.tanh(),
80});
81
82pure_unop!("math.arcsin", ArcSinOp);
83const_eval!(ArcSinOp, {
84 FloatAttr(f16, bf16, f32, f64): |inp| inp.asin(),
85});
86
87pure_unop!("math.arccos", ArcCosOp);
88const_eval!(ArcCosOp, {
89 FloatAttr(f16, bf16, f32, f64): |inp| inp.acos(),
90});
91
92pure_unop!("math.arctan", ArcTanOp);
93const_eval!(ArcTanOp, {
94 FloatAttr(f16, bf16, f32, f64): |inp| inp.atan(),
95});
96
97pure_unop!("math.arcsinh", ArcSinhOp);
98const_eval!(ArcSinhOp, {
99 FloatAttr(f16, bf16, f32, f64): |inp| inp.asinh(),
100});
101
102pure_unop!("math.arccosh", ArcCoshOp);
103const_eval!(ArcCoshOp, {
104 FloatAttr(f16, bf16, f32, f64): |inp| inp.acosh(),
105});
106
107pure_unop!("math.arctanh", ArcTanhOp);
108const_eval!(ArcTanhOp, {
109 FloatAttr(f16, bf16, f32, f64): |inp| inp.atanh(),
110});
111
112pure_unop!("math.degrees", DegreesOp);
113const_eval!(DegreesOp, {
114 FloatAttr(f16, bf16, f32, f64): |inp| inp.to_degrees(),
115});
116
117pure_unop!("math.radians", RadiansOp);
118const_eval!(RadiansOp, {
119 FloatAttr(f16, bf16, f32, f64): |inp| inp.to_radians(),
120});
121
122pure_unop!("math.sqrt", SqrtOp);
123const_eval!(SqrtOp, {
124 FloatAttr(f16, bf16, f32, f64): |inp| inp.sqrt(),
125});
126
127pure_unop!("math.rsqrt", RsqrtOp);
128const_eval!(RsqrtOp, {
129 FloatAttr(f16, bf16, f32, f64): |inp| inp.sqrt().recip(),
130});
131
132pure_unop!("math.round", RoundOp);
133const_eval!(RoundOp, {
134 FloatAttr(f16, bf16, f32, f64): |inp| inp.round(),
135});
136
137pure_unop!("math.floor", FloorOp);
138const_eval!(FloorOp, {
139 FloatAttr(f16, bf16, f32, f64): |inp| inp.floor(),
140});
141
142pure_unop!("math.ceil", CeilOp);
143const_eval!(CeilOp, {
144 FloatAttr(f16, bf16, f32, f64): |inp| inp.ceil(),
145});
146
147pure_unop!("math.trunc", TruncOp);
148const_eval!(TruncOp, {
149 FloatAttr(f16, bf16, f32, f64): |inp| inp.trunc(),
150});
151
152pure_unop!("math.erf", ErfOp);
153pure_unop!("math.recip", RecipOp);
159const_eval!(RecipOp, {
160 FloatAttr(f16, bf16, f32, f64): |inp| inp.recip(),
161});
162
163pure_unop!("math.s_neg", SNegOp);
164const_eval!(SNegOp, {
165 [IntegerAttr(i8, i16, i32, i64)]: |inp| inp.neg(),
166});
167
168pure_unop!("math.f_neg", FNegOp);
169const_eval!(FNegOp, {
170 [FloatAttr(f16, bf16, f32, f64)]: |inp| inp.neg(),
171});
172
173#[cube_op(name = "math.is_nan")]
174#[result_ty(from_inputs = pred_result_ty)]
175#[op_interfaces(TriviallyUnrollable)]
176#[op_traits(Pure, CanMaterialize)]
177pub struct IsNanOp {
178 pub input: Value,
179}
180const_eval!(IsNanOp, {
181 FloatAttr(f16, bf16, f32, f64): |inp| -> BoolAttr { inp.is_nan().into() }
182});
183
184#[cube_op(name = "math.is_inf")]
185#[result_ty(from_inputs = pred_result_ty)]
186#[op_interfaces(TriviallyUnrollable)]
187#[op_traits(Pure, CanMaterialize)]
188pub struct IsInfOp {
189 pub input: Value,
190}
191const_eval!(IsInfOp, {
192 FloatAttr(f16, bf16, f32, f64): |inp| -> BoolAttr { inp.is_infinite().into() }
193});
194
195fn pred_result_ty(ctx: &Context, input: &Value) -> TypeHandle {
196 let vectorization = input.vector_size(ctx);
197 let bool = BoolType::get(ctx).into();
198 if vectorization == 1 {
199 bool
200 } else {
201 VectorType::get(ctx, bool, vectorization).into()
202 }
203}
204
205pure_binop!("math.i_add", IAddOp);
206const_eval!(IAddOp, {
207 [IndexAttr, IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs.wrapping_add(rhs),
208});
209simplify!(IAddOp, {
210 |lhs, _| match lhs?.as_const_val(ctx) {
211 ConstantValue::Int(0) | ConstantValue::UInt(0) => {
212 Some(self.rhs(ctx))
213 }
214 _ => None?,
215 },
216 |_, rhs| match rhs?.as_const_val(ctx) {
217 ConstantValue::Int(0) | ConstantValue::UInt(0) => {
218 Some(self.lhs(ctx))
219 }
220 _ => None?,
221 }
222});
223
224pure_binop!("math.f_add", FAddOp);
225const_eval!(FAddOp, {
226 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs + rhs
227});
228simplify!(FAddOp, {
229 |lhs, _| match lhs?.float_as_f64(ctx) {
230 Some(0.0) => Some(self.rhs(ctx)),
231 _ => None?,
232 },
233 |_, rhs| match rhs?.float_as_f64(ctx) {
234 Some(0.0) => Some(self.lhs(ctx)),
235 _ => None?,
236 }
237});
238
239pure_binop!("math.saturating_s_add", SaturatingSAddOp);
240const_eval!(SaturatingSAddOp, {
241 [IntegerAttr(i8, i16, i32, i64)]: |lhs, rhs| lhs.saturating_add(rhs)
242});
243simplify!(SaturatingSAddOp, {
244 |lhs, _| match lhs?.as_const_val(ctx) {
245 ConstantValue::Int(0) => Some(self.rhs(ctx)),
246 _ => None?,
247 },
248 |_, rhs| match rhs?.as_const_val(ctx) {
249 ConstantValue::Int(0) => Some(self.lhs(ctx)),
250 _ => None?,
251 }
252});
253
254pure_binop!("math.saturating_u_add", SaturatingUAddOp);
255const_eval!(SaturatingUAddOp, {
256 [IndexAttr, IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs.saturating_add(rhs)
257});
258simplify!(SaturatingUAddOp, {
259 |lhs, _| match lhs?.as_const_val(ctx) {
260 ConstantValue::UInt(0) => Some(self.rhs(ctx)),
261 _ => None?,
262 },
263 |_, rhs| match rhs?.as_const_val(ctx) {
264 ConstantValue::UInt(0) => Some(self.lhs(ctx)),
265 _ => None?,
266 }
267});
268
269pure_binop!("math.i_sub", ISubOp);
270const_eval!(ISubOp, {
271 [IndexAttr, IntegerAttr(i8, i16, i32, i64), IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs.wrapping_sub(rhs),
272 custom: |_, _| {
274 if self.lhs(ctx) == self.rhs(ctx) {
275 Some(int_attr(ctx, self.result_type(ctx), 0))
276 } else {
277 None
278 }
279 }
280});
281simplify!(ISubOp, {
282 |_, rhs| match rhs?.as_const_val(ctx) {
283 ConstantValue::Int(0) | ConstantValue::UInt(0) => Some(self.lhs(ctx)),
284 _ => None?,
285 }
286});
287
288pure_binop!("math.f_sub", FSubOp);
289const_eval!(FSubOp, {
290 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs - rhs,
291 custom: |_, _| {
293 if self.lhs(ctx) == self.rhs(ctx) {
294 Some(float_attr(ctx, self.result_type(ctx), 0.0))
295 } else {
296 None
297 }
298 }
299});
300simplify!(FSubOp, {
301 |_, rhs| match rhs?.as_const_val(ctx) {
302 ConstantValue::Float(val) if val.to_bits() == 0 => Some(self.lhs(ctx)),
303 _ => None?,
304 }
305});
306
307pure_binop!("math.saturating_s_sub", SaturatingSSubOp);
308const_eval!(SaturatingSSubOp, {
309 [IntegerAttr(i8, i16, i32, i64)]: |lhs, rhs| lhs.saturating_sub(rhs)
310});
311simplify!(SaturatingSSubOp, {
312 |_, rhs| match rhs?.as_const_val(ctx) {
313 ConstantValue::Int(0) => Some(self.lhs(ctx)),
314 _ => None?,
315 }
316});
317
318pure_binop!("math.saturating_u_sub", SaturatingUSubOp);
319const_eval!(SaturatingUSubOp, {
320 [IndexAttr, IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs.saturating_sub(rhs)
321});
322simplify!(SaturatingUSubOp, {
323 |_, rhs| match rhs?.as_const_val(ctx) {
324 ConstantValue::UInt(0) => Some(self.lhs(ctx)),
325 _ => None?,
326 }
327});
328
329pure_binop!("math.i_mul", IMulOp);
330const_eval!(IMulOp, {
331 [IndexAttr, IntegerAttr(i8, i16, i32, i64), IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs.wrapping_mul(rhs),
332 custom: |lhs, rhs| {
334 let const_val = lhs.or(rhs)?;
335 Some(match const_val.as_const_val(ctx) {
336 ConstantValue::Int(0) | ConstantValue::UInt(0) => int_attr(ctx, const_val.get_type(ctx), 0),
337 _ => None?
338 })
339 }
340});
341simplify!(IMulOp, {
342 |lhs, _| match lhs?.as_const_val(ctx) {
343 ConstantValue::Int(1) | ConstantValue::UInt(1) => {
344 Some(self.rhs(ctx))
345 }
346 _ => None?,
347 },
348 |_, rhs| match rhs?.as_const_val(ctx) {
349 ConstantValue::Int(1) | ConstantValue::UInt(1) => {
350 Some(self.lhs(ctx))
351 }
352 _ => None?,
353 }
354});
355
356pure_binop!("math.f_mul", FMulOp);
357const_eval!(FMulOp, {
358 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs * rhs,
359 custom: |lhs, rhs| {
361 let const_val = lhs.or(rhs)?;
362 Some(match const_val.float_as_f64(ctx) {
363 Some(0.0) => float_attr(ctx, const_val.get_type(ctx), 0.0),
364 _ => None?
365 })
366 }
367});
368simplify!(FMulOp, {
369 |lhs, _| match lhs?.float_as_f64(ctx) {
370 Some(1.0) => Some(self.rhs(ctx)),
371 _ => None?,
372 },
373 |_, rhs| match rhs?.float_as_f64(ctx) {
374 Some(1.0) => Some(self.lhs(ctx)),
375 _ => None?,
376 }
377});
378
379#[cube_op(name = "math.s_div")]
380#[result_ty(same_as = lhs)]
381#[op_interfaces(SameOperandsType, SameOperandsAndResultType, TriviallyUnrollable)]
382#[op_traits(CanMaterialize, NoSideEffects, NoMemoryEffect)] pub struct SDivOp {
384 pub lhs: Value,
385 pub rhs: Value,
386}
387const_eval!(SDivOp, {
388 [IntegerAttr(i8, i16, i32, i64)]: |lhs, rhs| lhs.wrapping_div(rhs),
389 custom: |lhs, _| {
391 Some(match lhs?.as_const_val(ctx) {
392 ConstantValue::Int(0) => int_attr(ctx, lhs?.get_type(ctx), 0),
393 _ => None?
394 })
395 },
396 custom: |_, _| {
398 let result = self.get_result(ctx);
399 if self.lhs(ctx) == self.rhs(ctx) && result.vector_size(ctx) == 1 {
400 Some(int_attr(ctx, result.get_type(ctx), 1))
401 } else {
402 None
403 }
404 }
405});
406simplify!(SDivOp, {
407 |_, rhs| match rhs?.as_const_val(ctx) {
408 ConstantValue::Int(1) => Some(self.lhs(ctx)),
409 _ => None?,
410 }
411});
412
413#[cube_op(name = "math.u_div")]
414#[result_ty(same_as = lhs)]
415#[op_interfaces(SameOperandsType, SameOperandsAndResultType, TriviallyUnrollable)]
416#[op_traits(CanMaterialize, NoSideEffects, NoMemoryEffect)] pub struct UDivOp {
418 pub lhs: Value,
419 pub rhs: Value,
420}
421const_eval!(UDivOp, {
422 [IndexAttr, IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs.wrapping_div(rhs),
423 custom: |lhs, _| {
425 Some(match lhs?.as_const_val(ctx) {
426 ConstantValue::UInt(0) => int_attr(ctx, lhs?.get_type(ctx), 0),
427 _ => None?
428 })
429 },
430 custom: |_, _| {
432 let result = self.get_result(ctx);
433 if self.lhs(ctx) == self.rhs(ctx) && result.vector_size(ctx) == 1 {
434 Some(int_attr(ctx, result.get_type(ctx), 1))
435 } else {
436 None
437 }
438 }
439});
440simplify!(UDivOp, {
441 |_, rhs| match rhs?.as_const_val(ctx) {
442 ConstantValue::UInt(1) => Some(self.lhs(ctx)),
443 _ => None?,
444 }
445});
446
447pure_binop!("math.f_div", FDivOp);
448const_eval!(FDivOp, {
449 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs / rhs,
450 custom: |lhs, _| {
452 Some(match lhs?.float_as_f64(ctx) {
453 Some(0.0) => float_attr(ctx, lhs?.get_type(ctx), 0.0),
454 _ => None?
455 })
456 },
457});
458simplify!(FDivOp, {
459 |_, rhs| match rhs?.float_as_f64(ctx) {
460 Some(1.0) => Some(self.lhs(ctx)),
461 _ => None?,
462 }
463});
464
465pure_binop!("math.arc_tan2", ArcTan2Op);
466const_eval!(ArcTan2Op, {
467 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs.atan2(rhs),
468});
469
470pure_binop!("math.powf", PowfOp);
471const_eval!(PowfOp, {
472 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs.powf(rhs),
473});
474
475#[cube_op(name = "math.powi")]
476#[result_ty(same_as = lhs)]
477#[op_traits(Pure, CanMaterialize)]
478pub struct PowiOp {
479 pub lhs: Value,
480 pub rhs: Value,
481}
482
483pure_binop!("math.hypot", HypotOp);
486const_eval!(HypotOp, {
487 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs.hypot(rhs),
488});
489
490pure_binop!("math.rhypot", RhypotOp);
491const_eval!(RhypotOp, {
492 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs.hypot(rhs).recip(),
493});
494
495#[cube_op(name = "math.s_rem")]
496#[result_ty(same_as = lhs)]
497#[op_interfaces(SameOperandsType, SameOperandsAndResultType, TriviallyUnrollable)]
498#[op_traits(CanMaterialize, NoSideEffects, NoMemoryEffect)] pub struct SRemOp {
500 pub lhs: Value,
501 pub rhs: Value,
502}
503const_eval!(SRemOp, {
504 [IntegerAttr(i8, i16, i32, i64)]: |lhs, rhs| lhs % rhs,
505 custom: |lhs, _| {
507 Some(match lhs?.as_const_val(ctx) {
508 ConstantValue::Int(0) => int_attr(ctx, lhs?.get_type(ctx), 0),
509 _ => None?
510 })
511 },
512 custom: |_, rhs| {
514 Some(match rhs?.as_const_val(ctx) {
515 ConstantValue::Int(1) => int_attr(ctx, rhs?.get_type(ctx), 0),
516 _ => None?
517 })
518 }
519});
520simplify!(SRemOp, {
521 |_, rhs| match rhs?.as_const_val(ctx) {
522 ConstantValue::Int(1) => Some(self.lhs(ctx)),
523 _ => None?,
524 }
525});
526
527#[cube_op(name = "math.u_rem")]
528#[result_ty(same_as = lhs)]
529#[op_interfaces(SameOperandsType, SameOperandsAndResultType, TriviallyUnrollable)]
530#[op_traits(CanMaterialize, NoSideEffects, NoMemoryEffect)] pub struct URemOp {
532 pub lhs: Value,
533 pub rhs: Value,
534}
535const_eval!(URemOp, {
536 [IndexAttr, IntegerAttr(u8, u16, u32, u64)]: |lhs, rhs| lhs % rhs,
537 custom: |lhs, _| {
539 Some(match lhs?.as_const_val(ctx) {
540 ConstantValue::UInt(0) => int_attr(ctx, lhs?.get_type(ctx), 0),
541 _ => None?
542 })
543 },
544 custom: |_, rhs| {
546 Some(match rhs?.as_const_val(ctx) {
547 ConstantValue::UInt(1) => int_attr(ctx, rhs?.get_type(ctx), 0),
548 _ => None?
549 })
550 }
551});
552simplify!(URemOp, {
553 |_, rhs| match rhs?.as_const_val(ctx) {
554 ConstantValue::UInt(1) => Some(self.lhs(ctx)),
555 _ => None?,
556 }
557});
558
559pure_binop!("math.f_rem", FRemOp);
560const_eval!(FRemOp, {
561 [FloatAttr(f16, bf16, f32, f64)]: |lhs, rhs| lhs % rhs,
562 custom: |lhs, _| {
564 Some(match lhs?.float_as_f64(ctx) {
565 Some(0.0) => float_attr(ctx, lhs?.get_type(ctx), 0.0),
566 _ => None?
567 })
568 },
569});
570simplify!(FRemOp, {
571 |_, rhs| match rhs?.float_as_f64(ctx) {
572 Some(1.0) => Some(self.lhs(ctx)),
573 _ => None?,
574 }
575});
576
577#[cube_op(name = "math.s_mod_floor")]
578#[result_ty(same_as = lhs)]
579#[op_interfaces(SameOperandsType, SameOperandsAndResultType, TriviallyUnrollable)]
580#[op_traits(CanMaterialize, NoSideEffects, NoMemoryEffect)] pub struct SModFloorOp {
582 pub lhs: Value,
583 pub rhs: Value,
584}
585const_eval!(SModFloorOp, {
586 IntegerAttr(i8, i16, i32, i64): |lhs, rhs| lhs.mod_floor(&rhs),
587 custom: |lhs, _| {
589 Some(match lhs?.as_const_val(ctx) {
590 ConstantValue::Int(0) => int_attr(ctx, lhs?.get_type(ctx), 0),
591 _ => None?
592 })
593 },
594 custom: |_, rhs| {
596 Some(match rhs?.as_const_val(ctx) {
597 ConstantValue::Int(1) => int_attr(ctx, rhs?.get_type(ctx), 0),
598 _ => None?
599 })
600 }
601});
602
603pure_binop!("math.f_mod_floor", FModFloorOp);
604const_eval!(FModFloorOp, {
605 FloatAttr(f16, bf16, f32, f64): |lhs, rhs| lhs - (lhs / rhs).floor() * rhs,
606 custom: |lhs, _| {
608 Some(match lhs?.float_as_f64(ctx) {
609 Some(0.0) => float_attr(ctx, lhs?.get_type(ctx), 0.0),
610 _ => None?
611 })
612 },
613});
614
615pure_binop!("math.s_mul_hi", SMulHiOp);
616const_eval!(SMulHiOp, {
617 IntegerAttr(i64): |lhs, rhs| ((lhs as i128 * rhs as i128) >> 64) as i64,
618 IntegerAttr(i32): |lhs, rhs| ((lhs as i64 * rhs as i64) >> 32) as i32,
619 custom: |lhs, rhs| {
621 let const_val = lhs.or(rhs)?;
622 Some(match const_val.as_const_val(ctx) {
623 ConstantValue::Int(0) => int_attr(ctx, const_val.get_type(ctx), 0),
624 _ => None?
625 })
626 }
627});
628simplify!(SMulHiOp, {
629 |lhs, _| match lhs?.as_const_val(ctx) {
630 ConstantValue::Int(1) => Some(self.rhs(ctx)),
631 _ => None?,
632 },
633 |_, rhs| match rhs?.as_const_val(ctx) {
634 ConstantValue::Int(1) => Some(self.lhs(ctx)),
635 _ => None?,
636 }
637});
638
639pure_binop!("math.u_mul_hi", UMulHiOp);
640const_eval!(UMulHiOp, {
641 IndexAttr: |lhs, rhs| ((lhs as u128 * rhs as u128) >> 64) as usize,
642 IntegerAttr(u64): |lhs, rhs| ((lhs as u128 * rhs as u128) >> 64) as u64,
643 IntegerAttr(u32): |lhs, rhs| ((lhs as u64 * rhs as u64) >> 32) as u32,
644 custom: |lhs, rhs| {
646 let const_val = lhs.or(rhs)?;
647 Some(match const_val.as_const_val(ctx) {
648 ConstantValue::UInt(0) => int_attr(ctx, const_val.get_type(ctx), 0),
649 _ => None?
650 })
651 }
652});
653simplify!(UMulHiOp, {
654 |lhs, _| match lhs?.as_const_val(ctx) {
655 ConstantValue::UInt(1) => Some(self.rhs(ctx)),
656 _ => None?,
657 },
658 |_, rhs| match rhs?.as_const_val(ctx) {
659 ConstantValue::UInt(1) => Some(self.lhs(ctx)),
660 _ => None?,
661 }
662});
663
664pub(super) fn index_attr(val: usize) -> AttrObj {
665 AttrObj::from(IndexAttr::new(val))
666}
667
668pub(super) fn int_attr(ctx: &Context, ty: TypeHandle, val: i128) -> AttrObj {
669 if ty.is_index(ctx) {
670 IndexAttr::new(val as usize).into()
671 } else {
672 let ty = TypedHandle::<IntegerType>::from_handle(ty, ctx).unwrap();
673 let width = bw(ty.deref(ctx).width() as usize);
674 let val = APInt::from_i128(val, width);
675 AttrObj::from(IntegerAttr::new(ty, val))
676 }
677}
678
679pub(super) fn float_attr(ctx: &Context, ty: TypeHandle, val: f64) -> AttrObj {
680 AttrObj::from(FloatAttr::from_f64(ctx, ty, val))
681}
682
683#[cube_op(name = "math.fma")]
684#[result_ty(same_as = a)]
685#[op_interfaces(SameOperandsType, SameOperandsAndResultType, TriviallyUnrollable)]
686#[op_traits(Pure, CanMaterialize)]
687pub struct FmaOp {
688 pub a: Value,
689 pub b: Value,
690 pub c: Value,
691}
692const_eval!(FmaOp, {
693 FloatAttr(f16, bf16, f32, f64): |a, b, c| a * b + c,
694});