MLIR 24.0.0git
MathOps.cpp
Go to the documentation of this file.
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
13#include "mlir/IR/Builders.h"
14#include <optional>
15
16using namespace mlir;
17using namespace mlir::math;
18
19//===----------------------------------------------------------------------===//
20// Common helpers
21//===----------------------------------------------------------------------===//
22
23/// Return the type of the same shape (scalar, vector or tensor) containing i1.
24static Type getI1SameShape(Type type) {
25 auto i1Type = IntegerType::get(type.getContext(), 1);
26 if (auto shapedType = llvm::dyn_cast<ShapedType>(type))
27 return shapedType.cloneWith(std::nullopt, i1Type);
28 if (llvm::isa<UnrankedTensorType>(type))
29 return UnrankedTensorType::get(i1Type);
30 return i1Type;
31}
32
33//===----------------------------------------------------------------------===//
34// TableGen'd op method definitions
35//===----------------------------------------------------------------------===//
36
37#define GET_OP_CLASSES
38#include "mlir/Dialect/Math/IR/MathOps.cpp.inc"
39
40//===----------------------------------------------------------------------===//
41// AbsFOp folder
42//===----------------------------------------------------------------------===//
43
44OpFoldResult math::AbsFOp::fold(FoldAdaptor adaptor) {
45 return constFoldUnaryOp<FloatAttr>(adaptor.getOperands(),
46 [](const APFloat &a) { return abs(a); });
47}
48
49//===----------------------------------------------------------------------===//
50// AbsIOp folder
51//===----------------------------------------------------------------------===//
52
53OpFoldResult math::AbsIOp::fold(FoldAdaptor adaptor) {
54 return constFoldUnaryOp<IntegerAttr>(adaptor.getOperands(),
55 [](const APInt &a) { return a.abs(); });
56}
57
58//===----------------------------------------------------------------------===//
59// AcosOp folder
60//===----------------------------------------------------------------------===//
61
62OpFoldResult math::AcosOp::fold(FoldAdaptor adaptor) {
64 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
65 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
66 case APFloat::Semantics::S_IEEEdouble:
67 return APFloat(acos(a.convertToDouble()));
68 case APFloat::Semantics::S_IEEEsingle:
69 return APFloat(acosf(a.convertToFloat()));
70 default:
71 return {};
72 }
73 });
74}
75
76//===----------------------------------------------------------------------===//
77// AcoshOp folder
78//===----------------------------------------------------------------------===//
79
80OpFoldResult math::AcoshOp::fold(FoldAdaptor adaptor) {
82 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
83 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
84 case APFloat::Semantics::S_IEEEdouble:
85 return APFloat(acosh(a.convertToDouble()));
86 case APFloat::Semantics::S_IEEEsingle:
87 return APFloat(acoshf(a.convertToFloat()));
88 default:
89 return {};
90 }
91 });
92}
93
94//===----------------------------------------------------------------------===//
95// AsinOp folder
96//===----------------------------------------------------------------------===//
97
98OpFoldResult math::AsinOp::fold(FoldAdaptor adaptor) {
100 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
101 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
102 case APFloat::Semantics::S_IEEEdouble:
103 return APFloat(asin(a.convertToDouble()));
104 case APFloat::Semantics::S_IEEEsingle:
105 return APFloat(asinf(a.convertToFloat()));
106 default:
107 return {};
108 }
109 });
110}
111
112//===----------------------------------------------------------------------===//
113// AsinhOp folder
114//===----------------------------------------------------------------------===//
115
116OpFoldResult math::AsinhOp::fold(FoldAdaptor adaptor) {
118 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
119 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
120 case APFloat::Semantics::S_IEEEdouble:
121 return APFloat(asinh(a.convertToDouble()));
122 case APFloat::Semantics::S_IEEEsingle:
123 return APFloat(asinhf(a.convertToFloat()));
124 default:
125 return {};
126 }
127 });
128}
129
130//===----------------------------------------------------------------------===//
131// AtanOp folder
132//===----------------------------------------------------------------------===//
133
134OpFoldResult math::AtanOp::fold(FoldAdaptor adaptor) {
136 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
137 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
138 case APFloat::Semantics::S_IEEEdouble:
139 return APFloat(atan(a.convertToDouble()));
140 case APFloat::Semantics::S_IEEEsingle:
141 return APFloat(atanf(a.convertToFloat()));
142 default:
143 return {};
144 }
145 });
146}
147
148//===----------------------------------------------------------------------===//
149// AtanhOp folder
150//===----------------------------------------------------------------------===//
151
152OpFoldResult math::AtanhOp::fold(FoldAdaptor adaptor) {
154 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
155 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
156 case APFloat::Semantics::S_IEEEdouble:
157 return APFloat(atanh(a.convertToDouble()));
158 case APFloat::Semantics::S_IEEEsingle:
159 return APFloat(atanhf(a.convertToFloat()));
160 default:
161 return {};
162 }
163 });
164}
165
166//===----------------------------------------------------------------------===//
167// Atan2Op folder
168//===----------------------------------------------------------------------===//
169
170OpFoldResult math::Atan2Op::fold(FoldAdaptor adaptor) {
172 adaptor.getOperands(),
173 [](const APFloat &a, const APFloat &b) -> std::optional<APFloat> {
174 if (a.isZero() && b.isZero())
175 return llvm::APFloat::getNaN(a.getSemantics());
176
177 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
178 case APFloat::Semantics::S_IEEEdouble:
179 return APFloat(atan2(a.convertToDouble(), b.convertToDouble()));
180 case APFloat::Semantics::S_IEEEsingle:
181 return APFloat(atan2f(a.convertToFloat(), b.convertToFloat()));
182 default:
183 return {};
184 }
185 });
186}
187
188//===----------------------------------------------------------------------===//
189// CbrtOp folder
190//===----------------------------------------------------------------------===//
191
192OpFoldResult math::CbrtOp::fold(FoldAdaptor adaptor) {
194 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
195 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
196 case APFloat::Semantics::S_IEEEdouble:
197 return APFloat(cbrt(a.convertToDouble()));
198 case APFloat::Semantics::S_IEEEsingle:
199 return APFloat(cbrtf(a.convertToFloat()));
200 default:
201 return {};
202 }
203 });
204}
205
206//===----------------------------------------------------------------------===//
207// CeilOp folder
208//===----------------------------------------------------------------------===//
209
210OpFoldResult math::CeilOp::fold(FoldAdaptor adaptor) {
212 adaptor.getOperands(), [](const APFloat &a) {
213 APFloat result(a);
214 result.roundToIntegral(llvm::RoundingMode::TowardPositive);
215 return result;
216 });
217}
218
219//===----------------------------------------------------------------------===//
220// CopySignOp folder
221//===----------------------------------------------------------------------===//
222
223OpFoldResult math::CopySignOp::fold(FoldAdaptor adaptor) {
224 return constFoldBinaryOp<FloatAttr>(adaptor.getOperands(),
225 [](const APFloat &a, const APFloat &b) {
226 APFloat result(a);
227 result.copySign(b);
228 return result;
229 });
230}
231
232//===----------------------------------------------------------------------===//
233// CosOp folder
234//===----------------------------------------------------------------------===//
235
236OpFoldResult math::CosOp::fold(FoldAdaptor adaptor) {
238 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
239 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
240 case APFloat::Semantics::S_IEEEdouble:
241 return APFloat(cos(a.convertToDouble()));
242 case APFloat::Semantics::S_IEEEsingle:
243 return APFloat(cosf(a.convertToFloat()));
244 default:
245 return {};
246 }
247 });
248}
249
250//===----------------------------------------------------------------------===//
251// CoshOp folder
252//===----------------------------------------------------------------------===//
253
254OpFoldResult math::CoshOp::fold(FoldAdaptor adaptor) {
256 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
257 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
258 case APFloat::Semantics::S_IEEEdouble:
259 return APFloat(cosh(a.convertToDouble()));
260 case APFloat::Semantics::S_IEEEsingle:
261 return APFloat(coshf(a.convertToFloat()));
262 default:
263 return {};
264 }
265 });
266}
267
268//===----------------------------------------------------------------------===//
269// SinOp folder
270//===----------------------------------------------------------------------===//
271
272OpFoldResult math::SinOp::fold(FoldAdaptor adaptor) {
274 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
275 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
276 case APFloat::Semantics::S_IEEEdouble:
277 return APFloat(sin(a.convertToDouble()));
278 case APFloat::Semantics::S_IEEEsingle:
279 return APFloat(sinf(a.convertToFloat()));
280 default:
281 return {};
282 }
283 });
284}
285
286//===----------------------------------------------------------------------===//
287// SinhOp folder
288//===----------------------------------------------------------------------===//
289
290OpFoldResult math::SinhOp::fold(FoldAdaptor adaptor) {
292 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
293 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
294 case APFloat::Semantics::S_IEEEdouble:
295 return APFloat(sinh(a.convertToDouble()));
296 case APFloat::Semantics::S_IEEEsingle:
297 return APFloat(sinhf(a.convertToFloat()));
298 default:
299 return {};
300 }
301 });
302}
303
304//===----------------------------------------------------------------------===//
305// SinCosOp
306//===----------------------------------------------------------------------===//
307
308std::optional<SmallVector<int64_t, 4>>
309math::SincosOp::getIterationShapeToUnroll() {
310 if (auto vt = mlir::dyn_cast<VectorType>(getOperand().getType()))
311 return llvm::to_vector<4>(vt.getShape());
312 return std::nullopt;
313}
314
315LogicalResult math::SincosOp::fold(FoldAdaptor adaptor,
317 auto foldSincos = [](const APFloat &a, double (*fnDouble)(double),
318 float (*fnFloat)(float)) -> std::optional<APFloat> {
319 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
320 case APFloat::Semantics::S_IEEEdouble:
321 return APFloat(fnDouble(a.convertToDouble()));
322 case APFloat::Semantics::S_IEEEsingle:
323 return APFloat(fnFloat(a.convertToFloat()));
324 default:
325 return {};
326 }
327 };
328
330 adaptor.getOperands(),
331 [&](const APFloat &a) { return foldSincos(a, sin, sinf); });
333 adaptor.getOperands(),
334 [&](const APFloat &a) { return foldSincos(a, cos, cosf); });
335
336 if (sinRes && cosRes) {
337 result.push_back(sinRes);
338 result.push_back(cosRes);
339 return success();
340 }
341 return failure();
342}
343
344//===----------------------------------------------------------------------===//
345// CountLeadingZerosOp folder
346//===----------------------------------------------------------------------===//
347
348OpFoldResult math::CountLeadingZerosOp::fold(FoldAdaptor adaptor) {
350 adaptor.getOperands(),
351 [](const APInt &a) { return APInt(a.getBitWidth(), a.countl_zero()); });
352}
353
354//===----------------------------------------------------------------------===//
355// CountTrailingZerosOp folder
356//===----------------------------------------------------------------------===//
357
358OpFoldResult math::CountTrailingZerosOp::fold(FoldAdaptor adaptor) {
360 adaptor.getOperands(),
361 [](const APInt &a) { return APInt(a.getBitWidth(), a.countr_zero()); });
362}
363
364//===----------------------------------------------------------------------===//
365// CtPopOp folder
366//===----------------------------------------------------------------------===//
367
368OpFoldResult math::CtPopOp::fold(FoldAdaptor adaptor) {
370 adaptor.getOperands(),
371 [](const APInt &a) { return APInt(a.getBitWidth(), a.popcount()); });
372}
373
374//===----------------------------------------------------------------------===//
375// ErfOp folder
376//===----------------------------------------------------------------------===//
377
378OpFoldResult math::ErfOp::fold(FoldAdaptor adaptor) {
380 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
381 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
382 case APFloat::Semantics::S_IEEEdouble:
383 return APFloat(erf(a.convertToDouble()));
384 case APFloat::Semantics::S_IEEEsingle:
385 return APFloat(erff(a.convertToFloat()));
386 default:
387 return {};
388 }
389 });
390}
391
392//===----------------------------------------------------------------------===//
393// ErfcOp folder
394//===----------------------------------------------------------------------===//
395
396OpFoldResult math::ErfcOp::fold(FoldAdaptor adaptor) {
398 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
399 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
400 case APFloat::Semantics::S_IEEEdouble:
401 return APFloat(erfc(a.convertToDouble()));
402 case APFloat::Semantics::S_IEEEsingle:
403 return APFloat(erfcf(a.convertToFloat()));
404 default:
405 return {};
406 }
407 });
408}
409
410//===----------------------------------------------------------------------===//
411// IPowIOp folder
412//===----------------------------------------------------------------------===//
413
414OpFoldResult math::IPowIOp::fold(FoldAdaptor adaptor) {
416 adaptor.getOperands(),
417 [](const APInt &base, const APInt &power) -> std::optional<APInt> {
418 unsigned width = base.getBitWidth();
419 auto zeroValue = APInt::getZero(width);
420 // i1 folding is ambiguous with signed semantics, don't fold.
421 if (width == 1)
422 return {};
423 APInt oneValue{width, 1ULL, /*isSigned=*/true};
424 APInt minusOneValue{width, -1ULL, /*isSigned=*/true};
425
426 if (power.isZero())
427 return oneValue;
428
429 if (power.isNegative()) {
430 // Leave 0 raised to negative power not folded.
431 if (base.isZero())
432 return {};
433 if (base.isOne())
434 return oneValue;
435 // If abs(base) > 1, then the result is zero.
436 if (base.ne(minusOneValue))
437 return zeroValue;
438 // base == -1:
439 // -1: power is odd
440 // 1: power is even
441 if (power[0] == 1)
442 return minusOneValue;
443
444 return oneValue;
445 }
446
447 // power is positive.
448 APInt result = oneValue;
449 APInt curBase = base;
450 APInt curPower = power;
451 while (true) {
452 if (curPower[0] == 1)
453 result *= curBase;
454 curPower.lshrInPlace(1);
455 if (curPower.isZero())
456 return result;
457 curBase *= curBase;
458 }
459 });
460}
461
462//===----------------------------------------------------------------------===//
463// LogOp folder
464//===----------------------------------------------------------------------===//
465
466OpFoldResult math::LogOp::fold(FoldAdaptor adaptor) {
468 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
469 if (a.isNegative())
470 return {};
471
472 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
473 case APFloat::Semantics::S_IEEEdouble:
474 return APFloat(log(a.convertToDouble()));
475 case APFloat::Semantics::S_IEEEsingle:
476 return APFloat(logf(a.convertToFloat()));
477 default:
478 return {};
479 }
480 });
481}
482
483//===----------------------------------------------------------------------===//
484// Log2Op folder
485//===----------------------------------------------------------------------===//
486
487OpFoldResult math::Log2Op::fold(FoldAdaptor adaptor) {
489 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
490 if (a.isNegative())
491 return {};
492
493 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
494 case APFloat::Semantics::S_IEEEdouble:
495 return APFloat(log2(a.convertToDouble()));
496 case APFloat::Semantics::S_IEEEsingle:
497 return APFloat(log2f(a.convertToFloat()));
498 default:
499 return {};
500 }
501 });
502}
503
504//===----------------------------------------------------------------------===//
505// Log10Op folder
506//===----------------------------------------------------------------------===//
507
508OpFoldResult math::Log10Op::fold(FoldAdaptor adaptor) {
510 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
511 if (a.isNegative())
512 return {};
513
514 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
515 case APFloat::Semantics::S_IEEEdouble:
516 return APFloat(log10(a.convertToDouble()));
517 case APFloat::Semantics::S_IEEEsingle:
518 return APFloat(log10f(a.convertToFloat()));
519 default:
520 return {};
521 }
522 });
523}
524
525//===----------------------------------------------------------------------===//
526// Log1pOp folder
527//===----------------------------------------------------------------------===//
528
529OpFoldResult math::Log1pOp::fold(FoldAdaptor adaptor) {
531 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
532 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
533 case APFloat::Semantics::S_IEEEdouble:
534 if ((a + APFloat(1.0)).isNegative())
535 return {};
536 return APFloat(log1p(a.convertToDouble()));
537 case APFloat::Semantics::S_IEEEsingle:
538 if ((a + APFloat(1.0f)).isNegative())
539 return {};
540 return APFloat(log1pf(a.convertToFloat()));
541 default:
542 return {};
543 }
544 });
545}
546
547//===----------------------------------------------------------------------===//
548// PowFOp folder
549//===----------------------------------------------------------------------===//
550
551OpFoldResult math::PowFOp::fold(FoldAdaptor adaptor) {
553 adaptor.getOperands(),
554 [](const APFloat &a, const APFloat &b) -> std::optional<APFloat> {
555 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
556 case APFloat::Semantics::S_IEEEdouble:
557 return APFloat(pow(a.convertToDouble(), b.convertToDouble()));
558 case APFloat::Semantics::S_IEEEsingle:
559 return APFloat(powf(a.convertToFloat(), b.convertToFloat()));
560 default:
561 return {};
562 }
563 });
564}
565
566//===----------------------------------------------------------------------===//
567// RsqrtOp folder
568//===----------------------------------------------------------------------===//
569
570OpFoldResult math::RsqrtOp::fold(FoldAdaptor adaptor) {
572 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
573 if (a.isNegative())
574 return {};
575
576 APFloat one(a.getSemantics(), 1);
577 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
578 case APFloat::Semantics::S_IEEEdouble:
579 return one / APFloat(sqrt(a.convertToDouble()));
580 case APFloat::Semantics::S_IEEEsingle:
581 return one / APFloat(sqrtf(a.convertToFloat()));
582 default:
583 return {};
584 }
585 });
586}
587
588//===----------------------------------------------------------------------===//
589// SqrtOp folder
590//===----------------------------------------------------------------------===//
591
592OpFoldResult math::SqrtOp::fold(FoldAdaptor adaptor) {
594 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
595 if (a.isNegative())
596 return {};
597
598 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
599 case APFloat::Semantics::S_IEEEdouble:
600 return APFloat(sqrt(a.convertToDouble()));
601 case APFloat::Semantics::S_IEEEsingle:
602 return APFloat(sqrtf(a.convertToFloat()));
603 default:
604 return {};
605 }
606 });
607}
608
609//===----------------------------------------------------------------------===//
610// ExpOp folder
611//===----------------------------------------------------------------------===//
612
613OpFoldResult math::ExpOp::fold(FoldAdaptor adaptor) {
615 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
616 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
617 case APFloat::Semantics::S_IEEEdouble:
618 return APFloat(exp(a.convertToDouble()));
619 case APFloat::Semantics::S_IEEEsingle:
620 return APFloat(expf(a.convertToFloat()));
621 default:
622 return {};
623 }
624 });
625}
626
627//===----------------------------------------------------------------------===//
628// Exp2Op folder
629//===----------------------------------------------------------------------===//
630
631OpFoldResult math::Exp2Op::fold(FoldAdaptor adaptor) {
633 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
634 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
635 case APFloat::Semantics::S_IEEEdouble:
636 return APFloat(exp2(a.convertToDouble()));
637 case APFloat::Semantics::S_IEEEsingle:
638 return APFloat(exp2f(a.convertToFloat()));
639 default:
640 return {};
641 }
642 });
643}
644
645//===----------------------------------------------------------------------===//
646// ExpM1Op folder
647//===----------------------------------------------------------------------===//
648
649OpFoldResult math::ExpM1Op::fold(FoldAdaptor adaptor) {
651 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
652 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
653 case APFloat::Semantics::S_IEEEdouble:
654 return APFloat(expm1(a.convertToDouble()));
655 case APFloat::Semantics::S_IEEEsingle:
656 return APFloat(expm1f(a.convertToFloat()));
657 default:
658 return {};
659 }
660 });
661}
662
663//===----------------------------------------------------------------------===//
664// IsFiniteOp folder
665//===----------------------------------------------------------------------===//
666
667OpFoldResult math::IsFiniteOp::fold(FoldAdaptor adaptor) {
668 if (auto val = dyn_cast_or_null<FloatAttr>(adaptor.getOperand())) {
669 return BoolAttr::get(val.getContext(), val.getValue().isFinite());
670 }
671 if (auto splat = dyn_cast_or_null<SplatElementsAttr>(adaptor.getOperand())) {
673 cast<ShapedType>(getType()),
674 APInt(1, splat.getSplatValue<APFloat>().isFinite()));
675 }
676 return {};
677}
678
679//===----------------------------------------------------------------------===//
680// IsInfOp folder
681//===----------------------------------------------------------------------===//
682
683OpFoldResult math::IsInfOp::fold(FoldAdaptor adaptor) {
684 if (auto val = dyn_cast_or_null<FloatAttr>(adaptor.getOperand())) {
685 return BoolAttr::get(val.getContext(), val.getValue().isInfinity());
686 }
687 if (auto splat = dyn_cast_or_null<SplatElementsAttr>(adaptor.getOperand())) {
689 cast<ShapedType>(getType()),
690 APInt(1, splat.getSplatValue<APFloat>().isInfinity()));
691 }
692 return {};
693}
694
695//===----------------------------------------------------------------------===//
696// IsNaNOp folder
697//===----------------------------------------------------------------------===//
698
699OpFoldResult math::IsNaNOp::fold(FoldAdaptor adaptor) {
700 if (auto val = dyn_cast_or_null<FloatAttr>(adaptor.getOperand())) {
701 return BoolAttr::get(val.getContext(), val.getValue().isNaN());
702 }
703 if (auto splat = dyn_cast_or_null<SplatElementsAttr>(adaptor.getOperand())) {
705 cast<ShapedType>(getType()),
706 APInt(1, splat.getSplatValue<APFloat>().isNaN()));
707 }
708 return {};
709}
710
711//===----------------------------------------------------------------------===//
712// IsNormalOp folder
713//===----------------------------------------------------------------------===//
714
715OpFoldResult math::IsNormalOp::fold(FoldAdaptor adaptor) {
716 if (auto val = dyn_cast_or_null<FloatAttr>(adaptor.getOperand())) {
717 return BoolAttr::get(val.getContext(), val.getValue().isNormal());
718 }
719 if (auto splat = dyn_cast_or_null<SplatElementsAttr>(adaptor.getOperand())) {
721 cast<ShapedType>(getType()),
722 APInt(1, splat.getSplatValue<APFloat>().isNormal()));
723 }
724 return {};
725}
726
727//===----------------------------------------------------------------------===//
728// TanOp folder
729//===----------------------------------------------------------------------===//
730
731OpFoldResult math::TanOp::fold(FoldAdaptor adaptor) {
733 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
734 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
735 case APFloat::Semantics::S_IEEEdouble:
736 return APFloat(tan(a.convertToDouble()));
737 case APFloat::Semantics::S_IEEEsingle:
738 return APFloat(tanf(a.convertToFloat()));
739 default:
740 return {};
741 }
742 });
743}
744
745//===----------------------------------------------------------------------===//
746// TanhOp folder
747//===----------------------------------------------------------------------===//
748
749OpFoldResult math::TanhOp::fold(FoldAdaptor adaptor) {
751 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
752 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
753 case APFloat::Semantics::S_IEEEdouble:
754 return APFloat(tanh(a.convertToDouble()));
755 case APFloat::Semantics::S_IEEEsingle:
756 return APFloat(tanhf(a.convertToFloat()));
757 default:
758 return {};
759 }
760 });
761}
762
763//===----------------------------------------------------------------------===//
764// RoundEvenOp folder
765//===----------------------------------------------------------------------===//
766
767OpFoldResult math::RoundEvenOp::fold(FoldAdaptor adaptor) {
769 adaptor.getOperands(), [](const APFloat &a) {
770 APFloat result(a);
771 result.roundToIntegral(llvm::RoundingMode::NearestTiesToEven);
772 return result;
773 });
774}
775
776//===----------------------------------------------------------------------===//
777// FloorOp folder
778//===----------------------------------------------------------------------===//
779
780OpFoldResult math::FloorOp::fold(FoldAdaptor adaptor) {
782 adaptor.getOperands(), [](const APFloat &a) {
783 APFloat result(a);
784 result.roundToIntegral(llvm::RoundingMode::TowardNegative);
785 return result;
786 });
787}
788
789//===----------------------------------------------------------------------===//
790// RoundOp folder
791//===----------------------------------------------------------------------===//
792
793OpFoldResult math::RoundOp::fold(FoldAdaptor adaptor) {
795 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
796 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
797 case APFloat::Semantics::S_IEEEdouble:
798 return APFloat(round(a.convertToDouble()));
799 case APFloat::Semantics::S_IEEEsingle:
800 return APFloat(roundf(a.convertToFloat()));
801 default:
802 return {};
803 }
804 });
805}
806
807//===----------------------------------------------------------------------===//
808// TruncOp folder
809//===----------------------------------------------------------------------===//
810
811OpFoldResult math::TruncOp::fold(FoldAdaptor adaptor) {
813 adaptor.getOperands(), [](const APFloat &a) -> std::optional<APFloat> {
814 switch (APFloat::SemanticsToEnum(a.getSemantics())) {
815 case APFloat::Semantics::S_IEEEdouble:
816 return APFloat(trunc(a.convertToDouble()));
817 case APFloat::Semantics::S_IEEEsingle:
818 return APFloat(truncf(a.convertToFloat()));
819 default:
820 return {};
821 }
822 });
823}
824
825//===----------------------------------------------------------------------===//
826// FPowIOp folder
827//===----------------------------------------------------------------------===//
828
829OpFoldResult math::FPowIOp::fold(FoldAdaptor adaptor) {
831 adaptor.getOperands(),
832 [](const APFloat &base, const APInt &exp) -> std::optional<APFloat> {
833 switch (APFloat::SemanticsToEnum(base.getSemantics())) {
834 case APFloat::Semantics::S_IEEEdouble:
835 case APFloat::Semantics::S_IEEEsingle:
836 break;
837 default:
838 return {};
839 }
840
841 // Square-and-multiply using the base's own semantics, matching the
842 // multiply sequence ExpandPowI builds in SelectionDAGBuilder.cpp.
843 const llvm::fltSemantics &sem = base.getSemantics();
844 APInt magnitude = exp.abs();
845 APFloat res = APFloat::getOne(sem);
846 APFloat curSquare = base;
847 while (!magnitude.isZero()) {
848 if (magnitude[0])
849 res = res * curSquare;
850 curSquare = curSquare * curSquare;
851 magnitude.lshrInPlace(1);
852 }
853 if (exp.isNegative())
854 res = APFloat::getOne(sem) / res;
855 return res;
856 });
857}
858
859/// Materialize an integer or floating point constant.
860Operation *math::MathDialect::materializeConstant(OpBuilder &builder,
861 Attribute value, Type type,
862 Location loc) {
863 if (auto poison = dyn_cast<ub::PoisonAttr>(value))
864 return ub::PoisonOp::create(builder, loc, type, poison);
865
866 return arith::ConstantOp::materialize(builder, value, type, loc);
867}
return success()
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
static Type getI1SameShape(Type type)
Return the type of the same shape (scalar, vector or tensor) containing i1.
Definition MathOps.cpp:24
while(succeeded(parser.parseOptionalComma()))
Attributes are known-constant values of operations.
Definition Attributes.h:25
static BoolAttr get(MLIRContext *context, bool value)
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:210
This class represents a single result from folding an operation.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition Types.cpp:35
Include the generated interface declarations.
Attribute constFoldBinaryOpConditional(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Performs constant folding calculate with element-wise behavior on the two attributes in operands and ...
Attribute constFoldBinaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:311
Attribute constFoldUnaryOpConditional(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Performs constant folding calculate with element-wise behavior on the one attributes in operands and ...
Attribute constFoldUnaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)