xref: /llvm-project/mlir/lib/Dialect/Math/IR/MathOps.cpp (revision b8dca4fa729fcbd5d42ce3ca056dc4d278da2548)
1 //===- MathOps.cpp - MLIR operations for math implementation --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "mlir/Dialect/Arith/IR/Arith.h"
10 #include "mlir/Dialect/CommonFolders.h"
11 #include "mlir/Dialect/Math/IR/Math.h"
12 #include "mlir/Dialect/UB/IR/UBOps.h"
13 #include "mlir/IR/Builders.h"
14 #include <optional>
15 
16 using namespace mlir;
17 using namespace mlir::math;
18 
19 //===----------------------------------------------------------------------===//
20 // TableGen'd op method definitions
21 //===----------------------------------------------------------------------===//
22 
23 #define GET_OP_CLASSES
24 #include "mlir/Dialect/Math/IR/MathOps.cpp.inc"
25 
26 //===----------------------------------------------------------------------===//
27 // AbsFOp folder
28 //===----------------------------------------------------------------------===//
29 
fold(FoldAdaptor adaptor)30 OpFoldResult math::AbsFOp::fold(FoldAdaptor adaptor) {
31   return constFoldUnaryOp<FloatAttr>(adaptor.getOperands(),
32                                      [](const APFloat &a) { return abs(a); });
33 }
34 
35 //===----------------------------------------------------------------------===//
36 // AbsIOp folder
37 //===----------------------------------------------------------------------===//
38 
fold(FoldAdaptor adaptor)39 OpFoldResult math::AbsIOp::fold(FoldAdaptor adaptor) {
40   return constFoldUnaryOp<IntegerAttr>(adaptor.getOperands(),
41                                        [](const APInt &a) { return a.abs(); });
42 }
43 
44 //===----------------------------------------------------------------------===//
45 // AcosOp folder
46 //===----------------------------------------------------------------------===//
47 
fold(FoldAdaptor adaptor)48 OpFoldResult math::AcosOp::fold(FoldAdaptor adaptor) {
49   return constFoldUnaryOpConditional<FloatAttr>(
50       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
51         switch (a.getSizeInBits(a.getSemantics())) {
52         case 64:
53           return APFloat(acos(a.convertToDouble()));
54         case 32:
55           return APFloat(acosf(a.convertToFloat()));
56         default:
57           return {};
58         }
59       });
60 }
61 
62 //===----------------------------------------------------------------------===//
63 // AcoshOp folder
64 //===----------------------------------------------------------------------===//
65 
fold(FoldAdaptor adaptor)66 OpFoldResult math::AcoshOp::fold(FoldAdaptor adaptor) {
67   return constFoldUnaryOpConditional<FloatAttr>(
68       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
69         switch (a.getSizeInBits(a.getSemantics())) {
70         case 64:
71           return APFloat(acosh(a.convertToDouble()));
72         case 32:
73           return APFloat(acoshf(a.convertToFloat()));
74         default:
75           return {};
76         }
77       });
78 }
79 
80 //===----------------------------------------------------------------------===//
81 // AsinOp folder
82 //===----------------------------------------------------------------------===//
83 
fold(FoldAdaptor adaptor)84 OpFoldResult math::AsinOp::fold(FoldAdaptor adaptor) {
85   return constFoldUnaryOpConditional<FloatAttr>(
86       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
87         switch (a.getSizeInBits(a.getSemantics())) {
88         case 64:
89           return APFloat(asin(a.convertToDouble()));
90         case 32:
91           return APFloat(asinf(a.convertToFloat()));
92         default:
93           return {};
94         }
95       });
96 }
97 
98 //===----------------------------------------------------------------------===//
99 // AsinhOp folder
100 //===----------------------------------------------------------------------===//
101 
fold(FoldAdaptor adaptor)102 OpFoldResult math::AsinhOp::fold(FoldAdaptor adaptor) {
103   return constFoldUnaryOpConditional<FloatAttr>(
104       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
105         switch (a.getSizeInBits(a.getSemantics())) {
106         case 64:
107           return APFloat(asinh(a.convertToDouble()));
108         case 32:
109           return APFloat(asinhf(a.convertToFloat()));
110         default:
111           return {};
112         }
113       });
114 }
115 
116 //===----------------------------------------------------------------------===//
117 // AtanOp folder
118 //===----------------------------------------------------------------------===//
119 
fold(FoldAdaptor adaptor)120 OpFoldResult math::AtanOp::fold(FoldAdaptor adaptor) {
121   return constFoldUnaryOpConditional<FloatAttr>(
122       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
123         switch (a.getSizeInBits(a.getSemantics())) {
124         case 64:
125           return APFloat(atan(a.convertToDouble()));
126         case 32:
127           return APFloat(atanf(a.convertToFloat()));
128         default:
129           return {};
130         }
131       });
132 }
133 
134 //===----------------------------------------------------------------------===//
135 // AtanhOp folder
136 //===----------------------------------------------------------------------===//
137 
fold(FoldAdaptor adaptor)138 OpFoldResult math::AtanhOp::fold(FoldAdaptor adaptor) {
139   return constFoldUnaryOpConditional<FloatAttr>(
140       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
141         switch (a.getSizeInBits(a.getSemantics())) {
142         case 64:
143           return APFloat(atanh(a.convertToDouble()));
144         case 32:
145           return APFloat(atanhf(a.convertToFloat()));
146         default:
147           return {};
148         }
149       });
150 }
151 
152 //===----------------------------------------------------------------------===//
153 // Atan2Op folder
154 //===----------------------------------------------------------------------===//
155 
fold(FoldAdaptor adaptor)156 OpFoldResult math::Atan2Op::fold(FoldAdaptor adaptor) {
157   return constFoldBinaryOpConditional<FloatAttr>(
158       adaptor.getOperands(),
159       [](const APFloat &a, const APFloat &b) -> std::optional<APFloat> {
160         if (a.isZero() && b.isZero())
161           return llvm::APFloat::getNaN(a.getSemantics());
162 
163         if (a.getSizeInBits(a.getSemantics()) == 64 &&
164             b.getSizeInBits(b.getSemantics()) == 64)
165           return APFloat(atan2(a.convertToDouble(), b.convertToDouble()));
166 
167         if (a.getSizeInBits(a.getSemantics()) == 32 &&
168             b.getSizeInBits(b.getSemantics()) == 32)
169           return APFloat(atan2f(a.convertToFloat(), b.convertToFloat()));
170 
171         return {};
172       });
173 }
174 
175 //===----------------------------------------------------------------------===//
176 // CeilOp folder
177 //===----------------------------------------------------------------------===//
178 
fold(FoldAdaptor adaptor)179 OpFoldResult math::CeilOp::fold(FoldAdaptor adaptor) {
180   return constFoldUnaryOp<FloatAttr>(
181       adaptor.getOperands(), [](const APFloat &a) {
182         APFloat result(a);
183         result.roundToIntegral(llvm::RoundingMode::TowardPositive);
184         return result;
185       });
186 }
187 
188 //===----------------------------------------------------------------------===//
189 // CopySignOp folder
190 //===----------------------------------------------------------------------===//
191 
fold(FoldAdaptor adaptor)192 OpFoldResult math::CopySignOp::fold(FoldAdaptor adaptor) {
193   return constFoldBinaryOp<FloatAttr>(adaptor.getOperands(),
194                                       [](const APFloat &a, const APFloat &b) {
195                                         APFloat result(a);
196                                         result.copySign(b);
197                                         return result;
198                                       });
199 }
200 
201 //===----------------------------------------------------------------------===//
202 // CosOp folder
203 //===----------------------------------------------------------------------===//
204 
fold(FoldAdaptor adaptor)205 OpFoldResult math::CosOp::fold(FoldAdaptor adaptor) {
206   return constFoldUnaryOpConditional<FloatAttr>(
207       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
208         switch (a.getSizeInBits(a.getSemantics())) {
209         case 64:
210           return APFloat(cos(a.convertToDouble()));
211         case 32:
212           return APFloat(cosf(a.convertToFloat()));
213         default:
214           return {};
215         }
216       });
217 }
218 
219 //===----------------------------------------------------------------------===//
220 // CoshOp folder
221 //===----------------------------------------------------------------------===//
222 
fold(FoldAdaptor adaptor)223 OpFoldResult math::CoshOp::fold(FoldAdaptor adaptor) {
224   return constFoldUnaryOpConditional<FloatAttr>(
225       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
226         switch (a.getSizeInBits(a.getSemantics())) {
227         case 64:
228           return APFloat(cosh(a.convertToDouble()));
229         case 32:
230           return APFloat(coshf(a.convertToFloat()));
231         default:
232           return {};
233         }
234       });
235 }
236 
237 //===----------------------------------------------------------------------===//
238 // SinOp folder
239 //===----------------------------------------------------------------------===//
240 
fold(FoldAdaptor adaptor)241 OpFoldResult math::SinOp::fold(FoldAdaptor adaptor) {
242   return constFoldUnaryOpConditional<FloatAttr>(
243       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
244         switch (a.getSizeInBits(a.getSemantics())) {
245         case 64:
246           return APFloat(sin(a.convertToDouble()));
247         case 32:
248           return APFloat(sinf(a.convertToFloat()));
249         default:
250           return {};
251         }
252       });
253 }
254 
255 //===----------------------------------------------------------------------===//
256 // SinhOp folder
257 //===----------------------------------------------------------------------===//
258 
fold(FoldAdaptor adaptor)259 OpFoldResult math::SinhOp::fold(FoldAdaptor adaptor) {
260   return constFoldUnaryOpConditional<FloatAttr>(
261       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
262         switch (a.getSizeInBits(a.getSemantics())) {
263         case 64:
264           return APFloat(sinh(a.convertToDouble()));
265         case 32:
266           return APFloat(sinhf(a.convertToFloat()));
267         default:
268           return {};
269         }
270       });
271 }
272 
273 //===----------------------------------------------------------------------===//
274 // CountLeadingZerosOp folder
275 //===----------------------------------------------------------------------===//
276 
fold(FoldAdaptor adaptor)277 OpFoldResult math::CountLeadingZerosOp::fold(FoldAdaptor adaptor) {
278   return constFoldUnaryOp<IntegerAttr>(
279       adaptor.getOperands(),
280       [](const APInt &a) { return APInt(a.getBitWidth(), a.countl_zero()); });
281 }
282 
283 //===----------------------------------------------------------------------===//
284 // CountTrailingZerosOp folder
285 //===----------------------------------------------------------------------===//
286 
fold(FoldAdaptor adaptor)287 OpFoldResult math::CountTrailingZerosOp::fold(FoldAdaptor adaptor) {
288   return constFoldUnaryOp<IntegerAttr>(
289       adaptor.getOperands(),
290       [](const APInt &a) { return APInt(a.getBitWidth(), a.countr_zero()); });
291 }
292 
293 //===----------------------------------------------------------------------===//
294 // CtPopOp folder
295 //===----------------------------------------------------------------------===//
296 
fold(FoldAdaptor adaptor)297 OpFoldResult math::CtPopOp::fold(FoldAdaptor adaptor) {
298   return constFoldUnaryOp<IntegerAttr>(
299       adaptor.getOperands(),
300       [](const APInt &a) { return APInt(a.getBitWidth(), a.popcount()); });
301 }
302 
303 //===----------------------------------------------------------------------===//
304 // ErfOp folder
305 //===----------------------------------------------------------------------===//
306 
fold(FoldAdaptor adaptor)307 OpFoldResult math::ErfOp::fold(FoldAdaptor adaptor) {
308   return constFoldUnaryOpConditional<FloatAttr>(
309       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
310         switch (a.getSizeInBits(a.getSemantics())) {
311         case 64:
312           return APFloat(erf(a.convertToDouble()));
313         case 32:
314           return APFloat(erff(a.convertToFloat()));
315         default:
316           return {};
317         }
318       });
319 }
320 
321 //===----------------------------------------------------------------------===//
322 // IPowIOp folder
323 //===----------------------------------------------------------------------===//
324 
fold(FoldAdaptor adaptor)325 OpFoldResult math::IPowIOp::fold(FoldAdaptor adaptor) {
326   return constFoldBinaryOpConditional<IntegerAttr>(
327       adaptor.getOperands(),
328       [](const APInt &base, const APInt &power) -> std::optional<APInt> {
329         unsigned width = base.getBitWidth();
330         auto zeroValue = APInt::getZero(width);
331         APInt oneValue{width, 1ULL, /*isSigned=*/true};
332         APInt minusOneValue{width, -1ULL, /*isSigned=*/true};
333 
334         if (power.isZero())
335           return oneValue;
336 
337         if (power.isNegative()) {
338           // Leave 0 raised to negative power not folded.
339           if (base.isZero())
340             return {};
341           if (base.eq(oneValue))
342             return oneValue;
343           // If abs(base) > 1, then the result is zero.
344           if (base.ne(minusOneValue))
345             return zeroValue;
346           // base == -1:
347           //   -1: power is odd
348           //    1: power is even
349           if (power[0] == 1)
350             return minusOneValue;
351 
352           return oneValue;
353         }
354 
355         // power is positive.
356         APInt result = oneValue;
357         APInt curBase = base;
358         APInt curPower = power;
359         while (true) {
360           if (curPower[0] == 1)
361             result *= curBase;
362           curPower.lshrInPlace(1);
363           if (curPower.isZero())
364             return result;
365           curBase *= curBase;
366         }
367       });
368 
369   return Attribute();
370 }
371 
372 //===----------------------------------------------------------------------===//
373 // LogOp folder
374 //===----------------------------------------------------------------------===//
375 
fold(FoldAdaptor adaptor)376 OpFoldResult math::LogOp::fold(FoldAdaptor adaptor) {
377   return constFoldUnaryOpConditional<FloatAttr>(
378       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
379         if (a.isNegative())
380           return {};
381 
382         if (a.getSizeInBits(a.getSemantics()) == 64)
383           return APFloat(log(a.convertToDouble()));
384 
385         if (a.getSizeInBits(a.getSemantics()) == 32)
386           return APFloat(logf(a.convertToFloat()));
387 
388         return {};
389       });
390 }
391 
392 //===----------------------------------------------------------------------===//
393 // Log2Op folder
394 //===----------------------------------------------------------------------===//
395 
fold(FoldAdaptor adaptor)396 OpFoldResult math::Log2Op::fold(FoldAdaptor adaptor) {
397   return constFoldUnaryOpConditional<FloatAttr>(
398       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
399         if (a.isNegative())
400           return {};
401 
402         if (a.getSizeInBits(a.getSemantics()) == 64)
403           return APFloat(log2(a.convertToDouble()));
404 
405         if (a.getSizeInBits(a.getSemantics()) == 32)
406           return APFloat(log2f(a.convertToFloat()));
407 
408         return {};
409       });
410 }
411 
412 //===----------------------------------------------------------------------===//
413 // Log10Op folder
414 //===----------------------------------------------------------------------===//
415 
fold(FoldAdaptor adaptor)416 OpFoldResult math::Log10Op::fold(FoldAdaptor adaptor) {
417   return constFoldUnaryOpConditional<FloatAttr>(
418       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
419         if (a.isNegative())
420           return {};
421 
422         switch (a.getSizeInBits(a.getSemantics())) {
423         case 64:
424           return APFloat(log10(a.convertToDouble()));
425         case 32:
426           return APFloat(log10f(a.convertToFloat()));
427         default:
428           return {};
429         }
430       });
431 }
432 
433 //===----------------------------------------------------------------------===//
434 // Log1pOp folder
435 //===----------------------------------------------------------------------===//
436 
fold(FoldAdaptor adaptor)437 OpFoldResult math::Log1pOp::fold(FoldAdaptor adaptor) {
438   return constFoldUnaryOpConditional<FloatAttr>(
439       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
440         switch (a.getSizeInBits(a.getSemantics())) {
441         case 64:
442           if ((a + APFloat(1.0)).isNegative())
443             return {};
444           return APFloat(log1p(a.convertToDouble()));
445         case 32:
446           if ((a + APFloat(1.0f)).isNegative())
447             return {};
448           return APFloat(log1pf(a.convertToFloat()));
449         default:
450           return {};
451         }
452       });
453 }
454 
455 //===----------------------------------------------------------------------===//
456 // PowFOp folder
457 //===----------------------------------------------------------------------===//
458 
fold(FoldAdaptor adaptor)459 OpFoldResult math::PowFOp::fold(FoldAdaptor adaptor) {
460   return constFoldBinaryOpConditional<FloatAttr>(
461       adaptor.getOperands(),
462       [](const APFloat &a, const APFloat &b) -> std::optional<APFloat> {
463         if (a.getSizeInBits(a.getSemantics()) == 64 &&
464             b.getSizeInBits(b.getSemantics()) == 64)
465           return APFloat(pow(a.convertToDouble(), b.convertToDouble()));
466 
467         if (a.getSizeInBits(a.getSemantics()) == 32 &&
468             b.getSizeInBits(b.getSemantics()) == 32)
469           return APFloat(powf(a.convertToFloat(), b.convertToFloat()));
470 
471         return {};
472       });
473 }
474 
475 //===----------------------------------------------------------------------===//
476 // SqrtOp folder
477 //===----------------------------------------------------------------------===//
478 
fold(FoldAdaptor adaptor)479 OpFoldResult math::SqrtOp::fold(FoldAdaptor adaptor) {
480   return constFoldUnaryOpConditional<FloatAttr>(
481       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
482         if (a.isNegative())
483           return {};
484 
485         switch (a.getSizeInBits(a.getSemantics())) {
486         case 64:
487           return APFloat(sqrt(a.convertToDouble()));
488         case 32:
489           return APFloat(sqrtf(a.convertToFloat()));
490         default:
491           return {};
492         }
493       });
494 }
495 
496 //===----------------------------------------------------------------------===//
497 // ExpOp folder
498 //===----------------------------------------------------------------------===//
499 
fold(FoldAdaptor adaptor)500 OpFoldResult math::ExpOp::fold(FoldAdaptor adaptor) {
501   return constFoldUnaryOpConditional<FloatAttr>(
502       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
503         switch (a.getSizeInBits(a.getSemantics())) {
504         case 64:
505           return APFloat(exp(a.convertToDouble()));
506         case 32:
507           return APFloat(expf(a.convertToFloat()));
508         default:
509           return {};
510         }
511       });
512 }
513 
514 //===----------------------------------------------------------------------===//
515 // Exp2Op folder
516 //===----------------------------------------------------------------------===//
517 
fold(FoldAdaptor adaptor)518 OpFoldResult math::Exp2Op::fold(FoldAdaptor adaptor) {
519   return constFoldUnaryOpConditional<FloatAttr>(
520       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
521         switch (a.getSizeInBits(a.getSemantics())) {
522         case 64:
523           return APFloat(exp2(a.convertToDouble()));
524         case 32:
525           return APFloat(exp2f(a.convertToFloat()));
526         default:
527           return {};
528         }
529       });
530 }
531 
532 //===----------------------------------------------------------------------===//
533 // ExpM1Op folder
534 //===----------------------------------------------------------------------===//
535 
fold(FoldAdaptor adaptor)536 OpFoldResult math::ExpM1Op::fold(FoldAdaptor adaptor) {
537   return constFoldUnaryOpConditional<FloatAttr>(
538       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
539         switch (a.getSizeInBits(a.getSemantics())) {
540         case 64:
541           return APFloat(expm1(a.convertToDouble()));
542         case 32:
543           return APFloat(expm1f(a.convertToFloat()));
544         default:
545           return {};
546         }
547       });
548 }
549 
550 //===----------------------------------------------------------------------===//
551 // TanOp folder
552 //===----------------------------------------------------------------------===//
553 
fold(FoldAdaptor adaptor)554 OpFoldResult math::TanOp::fold(FoldAdaptor adaptor) {
555   return constFoldUnaryOpConditional<FloatAttr>(
556       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
557         switch (a.getSizeInBits(a.getSemantics())) {
558         case 64:
559           return APFloat(tan(a.convertToDouble()));
560         case 32:
561           return APFloat(tanf(a.convertToFloat()));
562         default:
563           return {};
564         }
565       });
566 }
567 
568 //===----------------------------------------------------------------------===//
569 // TanhOp folder
570 //===----------------------------------------------------------------------===//
571 
fold(FoldAdaptor adaptor)572 OpFoldResult math::TanhOp::fold(FoldAdaptor adaptor) {
573   return constFoldUnaryOpConditional<FloatAttr>(
574       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
575         switch (a.getSizeInBits(a.getSemantics())) {
576         case 64:
577           return APFloat(tanh(a.convertToDouble()));
578         case 32:
579           return APFloat(tanhf(a.convertToFloat()));
580         default:
581           return {};
582         }
583       });
584 }
585 
586 //===----------------------------------------------------------------------===//
587 // RoundEvenOp folder
588 //===----------------------------------------------------------------------===//
589 
fold(FoldAdaptor adaptor)590 OpFoldResult math::RoundEvenOp::fold(FoldAdaptor adaptor) {
591   return constFoldUnaryOp<FloatAttr>(
592       adaptor.getOperands(), [](const APFloat &a) {
593         APFloat result(a);
594         result.roundToIntegral(llvm::RoundingMode::NearestTiesToEven);
595         return result;
596       });
597 }
598 
599 //===----------------------------------------------------------------------===//
600 // FloorOp folder
601 //===----------------------------------------------------------------------===//
602 
fold(FoldAdaptor adaptor)603 OpFoldResult math::FloorOp::fold(FoldAdaptor adaptor) {
604   return constFoldUnaryOp<FloatAttr>(
605       adaptor.getOperands(), [](const APFloat &a) {
606         APFloat result(a);
607         result.roundToIntegral(llvm::RoundingMode::TowardNegative);
608         return result;
609       });
610 }
611 
612 //===----------------------------------------------------------------------===//
613 // RoundOp folder
614 //===----------------------------------------------------------------------===//
615 
fold(FoldAdaptor adaptor)616 OpFoldResult math::RoundOp::fold(FoldAdaptor adaptor) {
617   return constFoldUnaryOpConditional<FloatAttr>(
618       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
619         switch (a.getSizeInBits(a.getSemantics())) {
620         case 64:
621           return APFloat(round(a.convertToDouble()));
622         case 32:
623           return APFloat(roundf(a.convertToFloat()));
624         default:
625           return {};
626         }
627       });
628 }
629 
630 //===----------------------------------------------------------------------===//
631 // TruncOp folder
632 //===----------------------------------------------------------------------===//
633 
fold(FoldAdaptor adaptor)634 OpFoldResult math::TruncOp::fold(FoldAdaptor adaptor) {
635   return constFoldUnaryOpConditional<FloatAttr>(
636       adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
637         switch (a.getSizeInBits(a.getSemantics())) {
638         case 64:
639           return APFloat(trunc(a.convertToDouble()));
640         case 32:
641           return APFloat(truncf(a.convertToFloat()));
642         default:
643           return {};
644         }
645       });
646 }
647 
648 /// Materialize an integer or floating point constant.
materializeConstant(OpBuilder & builder,Attribute value,Type type,Location loc)649 Operation *math::MathDialect::materializeConstant(OpBuilder &builder,
650                                                   Attribute value, Type type,
651                                                   Location loc) {
652   if (auto poison = dyn_cast<ub::PoisonAttr>(value))
653     return builder.create<ub::PoisonOp>(loc, type, poison);
654 
655   return arith::ConstantOp::materialize(builder, value, type, loc);
656 }
657