32#include "llvm/ADT/ArrayRef.h"
33#include "llvm/ADT/STLExtras.h"
34#include "llvm/Support/MathExtras.h"
48 if (
auto vectorType = dyn_cast<VectorType>(type)) {
49 return VectorShape{vectorType.getShape(), vectorType.getScalableDims()};
64 assert(!isa<VectorType>(type) &&
"must be scalar type");
65 return shape ? VectorType::get(
shape->sizes, type,
shape->scalableFlags)
71 std::optional<VectorShape>
shape) {
72 assert(!isa<VectorType>(value.
getType()) &&
"must be scalar value");
74 return shape ? BroadcastOp::create(builder, type, value) : value;
100 assert(!operands.empty() &&
"operands must be not empty");
101 assert(vectorWidth > 0 &&
"vector width must be larger than 0");
103 VectorType inputType = cast<VectorType>(operands[0].
getType());
109 return compute(operands);
113 int64_t innerDim = inputShape.back();
114 int64_t expansionDim = innerDim / vectorWidth;
115 assert((innerDim % vectorWidth == 0) &&
"invalid inner dimension size");
122 if (expansionDim > 1) {
124 expandedShape.insert(expandedShape.end() - 1, expansionDim);
125 expandedShape.back() = vectorWidth;
127 for (
unsigned i = 0; i < operands.size(); ++i) {
128 auto operand = operands[i];
129 auto eltType = cast<VectorType>(operand.getType()).getElementType();
130 auto expandedType = VectorType::get(expandedShape, eltType);
131 expandedOperands[i] =
132 vector::ShapeCastOp::create(builder, expandedType, operand);
144 for (
int64_t i = 0; i < maxIndex; ++i) {
148 for (
const auto &tuple : llvm::enumerate(expandedOperands))
149 extracted[tuple.index()] =
150 vector::ExtractOp::create(builder, tuple.value(), offsets);
152 results[i] = compute(extracted);
156 Type resultEltType = cast<VectorType>(results[0].
getType()).getElementType();
157 Type resultExpandedType = VectorType::get(expandedShape, resultEltType);
159 builder, resultExpandedType, builder.
getZeroAttr(resultExpandedType));
161 for (
int64_t i = 0; i < maxIndex; ++i)
162 result = vector::InsertOp::create(builder, results[i],
result,
166 return vector::ShapeCastOp::create(
167 builder, VectorType::get(inputShape, resultEltType),
result);
175 return arith::ConstantOp::create(builder, builder.
getBoolAttr(value));
180 assert((elementType.
isF16() || elementType.
isF32()) &&
181 "x must be f16 or f32 type.");
182 return arith::ConstantOp::create(builder,
187 return arith::ConstantOp::create(builder, builder.
getF32FloatAttr(value));
195 Value i32Value =
i32Cst(builder,
static_cast<int32_t
>(bits));
196 return arith::BitcastOp::create(builder, builder.
getF32Type(), i32Value);
205 return arith::SelectOp::create(
207 arith::CmpFOp::create(builder, arith::CmpFPredicate::ULT, value, bound),
213 return arith::SelectOp::create(
215 arith::CmpFOp::create(builder, arith::CmpFPredicate::UGT, value, bound),
222 return max(builder,
min(builder, value, upperBound), lowerBound);
228 bool isPositive =
false) {
245 Value i32Half = arith::BitcastOp::create(builder, i32, cstHalf);
246 Value i32InvMantMask = arith::BitcastOp::create(builder, i32, cstInvMantMask);
247 Value i32Arg = arith::BitcastOp::create(builder, i32Vec, arg);
250 Value tmp0 = arith::AndIOp::create(builder, i32Arg, bcast(i32InvMantMask));
251 Value tmp1 = arith::OrIOp::create(builder, tmp0, bcast(i32Half));
252 Value normalizedFraction = arith::BitcastOp::create(builder, f32Vec, tmp1);
255 Value arg0 = isPositive ? arg : math::AbsFOp::create(builder, arg);
256 Value biasedExponentBits = arith::ShRUIOp::create(
257 builder, arith::BitcastOp::create(builder, i32Vec, arg0),
258 bcast(
i32Cst(builder, 23)));
259 Value biasedExponent =
260 arith::SIToFPOp::create(builder, f32Vec, biasedExponentBits);
262 arith::SubFOp::create(builder, biasedExponent, bcast(cst126f));
264 return {normalizedFraction, exponent};
278 auto exponetBitLocation = bcast(
i32Cst(builder, 23));
280 auto bias = bcast(
i32Cst(builder, 127));
282 Value biasedArg = arith::AddIOp::create(builder, arg, bias);
284 arith::ShLIOp::create(builder, biasedArg, exponetBitLocation);
285 Value exp2ValueF32 = arith::BitcastOp::create(builder, f32Vec, exp2ValueInt);
294 assert((elementType.
isF32() || elementType.
isF16()) &&
295 "x must be f32 or f16 type");
301 if (coeffs.size() == 1)
304 Value res = math::FmaOp::create(builder, x, coeffs[coeffs.size() - 1],
305 coeffs[coeffs.size() - 2]);
306 for (
auto i = ptrdiff_t(coeffs.size()) - 3; i >= 0; --i) {
307 res = math::FmaOp::create(builder, x, res, coeffs[i]);
335 if (
auto shaped = dyn_cast<ShapedType>(origType)) {
336 newType = shaped.clone(rewriter.
getF32Type());
337 }
else if (isa<FloatType>(origType)) {
341 "unable to find F32 equivalent type");
347 operands.push_back(arith::ExtFOp::create(rewriter, loc,
TypeRange{newType},
349 arith::ExtFOp::Properties{}));
351 cast<T>(op).getProperties(),
366 using OpRewritePattern<T>::OpRewritePattern;
367 LogicalResult matchAndRewrite(T op, PatternRewriter &rewriter)
const final {
369 T::template hasTrait<mlir::OpTrait::SameOperandsAndResultType>(),
370 "requires same operands and result types");
385 LogicalResult matchAndRewrite(math::AtanOp op,
386 PatternRewriter &rewriter)
const final;
391AtanApproximation::matchAndRewrite(math::AtanOp op,
393 auto operand = op.getOperand();
397 std::optional<VectorShape> shape =
vectorShape(op.getOperand());
399 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
400 Value
abs = math::AbsFOp::create(builder, operand);
407 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, abs, twoThirds);
408 Value addone = arith::AddFOp::create(builder, abs, one);
409 Value subone = arith::SubFOp::create(builder, abs, one);
410 Value xnum = arith::SelectOp::create(builder, cmp2, subone, abs);
411 Value xden = arith::SelectOp::create(builder, cmp2, addone, one);
413 auto bcast = [&](Value value) -> Value {
418 auto tan3pio8 = bcast(
f32Cst(builder, 2.41421356237309504880));
420 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, abs, tan3pio8);
421 xnum = arith::SelectOp::create(builder, cmp1, one, xnum);
422 xden = arith::SelectOp::create(builder, cmp1, abs, xden);
424 Value x = arith::DivFOp::create(builder, xnum, xden);
425 Value xx = arith::MulFOp::create(builder, x, x);
429 auto p0 = bcast(
f32Cst(builder, -8.750608600031904122785e-01));
430 auto p1 = bcast(
f32Cst(builder, -1.615753718733365076637e+01));
431 auto p2 = bcast(
f32Cst(builder, -7.500855792314704667340e+01));
432 auto p3 = bcast(
f32Cst(builder, -1.228866684490136173410e+02));
433 auto p4 = bcast(
f32Cst(builder, -6.485021904942025371773e+01));
434 auto q0 = bcast(
f32Cst(builder, +2.485846490142306297962e+01));
435 auto q1 = bcast(
f32Cst(builder, +1.650270098316988542046e+02));
436 auto q2 = bcast(
f32Cst(builder, +4.328810604912902668951e+02));
437 auto q3 = bcast(
f32Cst(builder, +4.853903996359136964868e+02));
438 auto q4 = bcast(
f32Cst(builder, +1.945506571482613964425e+02));
442 n = math::FmaOp::create(builder, xx, n, p1);
443 n = math::FmaOp::create(builder, xx, n, p2);
444 n = math::FmaOp::create(builder, xx, n, p3);
445 n = math::FmaOp::create(builder, xx, n, p4);
446 n = arith::MulFOp::create(builder, n, xx);
450 d = math::FmaOp::create(builder, xx, d, q1);
451 d = math::FmaOp::create(builder, xx, d, q2);
452 d = math::FmaOp::create(builder, xx, d, q3);
453 d = math::FmaOp::create(builder, xx, d, q4);
456 Value ans0 = arith::DivFOp::create(builder, n, d);
457 ans0 = math::FmaOp::create(builder, ans0, x, x);
460 Value mpi4 = bcast(
f32Cst(builder, llvm::numbers::pi / 4));
461 Value ans2 = arith::AddFOp::create(builder, mpi4, ans0);
462 Value ans = arith::SelectOp::create(builder, cmp2, ans2, ans0);
464 Value mpi2 = bcast(
f32Cst(builder, llvm::numbers::pi / 2));
465 Value ans1 = arith::SubFOp::create(builder, mpi2, ans0);
466 ans = arith::SelectOp::create(builder, cmp1, ans1, ans);
478struct Atan2Approximation :
public OpRewritePattern<math::Atan2Op> {
482 LogicalResult matchAndRewrite(math::Atan2Op op,
483 PatternRewriter &rewriter)
const final;
488Atan2Approximation::matchAndRewrite(math::Atan2Op op,
489 PatternRewriter &rewriter)
const {
490 auto y = op.getOperand(0);
491 auto x = op.getOperand(1);
495 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
496 std::optional<VectorShape> shape =
vectorShape(op.getResult());
499 auto div = arith::DivFOp::create(builder, y, x);
500 auto atan = math::AtanOp::create(builder,
div);
505 auto addPi = arith::AddFOp::create(builder, atan, pi);
506 auto subPi = arith::SubFOp::create(builder, atan, pi);
508 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, atan, zero);
509 auto flippedAtan = arith::SelectOp::create(builder, atanGt, subPi, addPi);
512 auto xGt = arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, x, zero);
513 Value
result = arith::SelectOp::create(builder, xGt, atan, flippedAtan);
517 arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ, x, zero);
519 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, y, zero);
520 Value isHalfPi = arith::AndIOp::create(builder, xZero, yGt);
521 auto halfPi =
broadcast(builder,
f32Cst(builder, 1.57079632679f), shape);
522 result = arith::SelectOp::create(builder, isHalfPi, halfPi,
result);
526 arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, y, zero);
527 Value isNegativeHalfPiPi = arith::AndIOp::create(builder, xZero, yLt);
528 auto negativeHalfPiPi =
530 result = arith::SelectOp::create(builder, isNegativeHalfPiPi,
531 negativeHalfPiPi,
result);
535 arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ, y, zero);
536 Value isNan = arith::AndIOp::create(builder, xZero, yZero);
538 result = arith::SelectOp::create(builder, isNan, cstNan,
result);
549struct TanhApproximation :
public OpRewritePattern<math::TanhOp> {
553 LogicalResult matchAndRewrite(math::TanhOp op,
554 PatternRewriter &rewriter)
const final;
559TanhApproximation::matchAndRewrite(math::TanhOp op,
560 PatternRewriter &rewriter)
const {
564 std::optional<VectorShape> shape =
vectorShape(op.getOperand());
566 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
567 auto bcast = [&](Value value) -> Value {
572 Value minusClamp = bcast(
f32Cst(builder, -7.99881172180175781f));
573 Value plusClamp = bcast(
f32Cst(builder, 7.99881172180175781f));
574 Value x =
clamp(builder, op.getOperand(), minusClamp, plusClamp);
577 Value tiny = bcast(
f32Cst(builder, 0.0004f));
578 Value tinyMask = arith::CmpFOp::create(
579 builder, arith::CmpFPredicate::OLT,
580 math::AbsFOp::create(builder, op.getOperand()), tiny);
583 Value alpha1 = bcast(
f32Cst(builder, 4.89352455891786e-03f));
584 Value alpha3 = bcast(
f32Cst(builder, 6.37261928875436e-04f));
585 Value alpha5 = bcast(
f32Cst(builder, 1.48572235717979e-05f));
586 Value alpha7 = bcast(
f32Cst(builder, 5.12229709037114e-08f));
587 Value alpha9 = bcast(
f32Cst(builder, -8.60467152213735e-11f));
588 Value alpha11 = bcast(
f32Cst(builder, 2.00018790482477e-13f));
589 Value alpha13 = bcast(
f32Cst(builder, -2.76076847742355e-16f));
592 Value beta0 = bcast(
f32Cst(builder, 4.89352518554385e-03f));
593 Value beta2 = bcast(
f32Cst(builder, 2.26843463243900e-03f));
594 Value beta4 = bcast(
f32Cst(builder, 1.18534705686654e-04f));
595 Value beta6 = bcast(
f32Cst(builder, 1.19825839466702e-06f));
598 Value x2 = arith::MulFOp::create(builder, x, x);
601 Value p = math::FmaOp::create(builder, x2, alpha13, alpha11);
602 p = math::FmaOp::create(builder, x2, p, alpha9);
603 p = math::FmaOp::create(builder, x2, p, alpha7);
604 p = math::FmaOp::create(builder, x2, p, alpha5);
605 p = math::FmaOp::create(builder, x2, p, alpha3);
606 p = math::FmaOp::create(builder, x2, p, alpha1);
607 p = arith::MulFOp::create(builder, x, p);
610 Value q = math::FmaOp::create(builder, x2, beta6, beta4);
611 q = math::FmaOp::create(builder, x2, q, beta2);
612 q = math::FmaOp::create(builder, x2, q, beta0);
615 Value res = arith::SelectOp::create(builder, tinyMask, x,
616 arith::DivFOp::create(builder, p, q));
624 0.693147180559945309417232121458176568075500134360255254120680009493393621L
626 1.442695040888963407359924681001892137426645954152985934135449406931109219L
633template <
typename Op>
645template <
typename Op>
647LogApproximationBase<Op>::logMatchAndRewrite(Op op, PatternRewriter &rewriter,
652 std::optional<VectorShape> shape =
vectorShape(op.getOperand());
654 ImplicitLocOpBuilder builder(op->
getLoc(), rewriter);
655 auto bcast = [&](Value value) -> Value {
659 Value cstZero = bcast(
f32Cst(builder, 0.0f));
660 Value cstOne = bcast(
f32Cst(builder, 1.0f));
661 Value cstNegHalf = bcast(
f32Cst(builder, -0.5f));
664 Value cstMinNormPos = bcast(
f32FromBits(builder, 0x00800000u));
665 Value cstMinusInf = bcast(
f32FromBits(builder, 0xff800000u));
666 Value cstPosInf = bcast(
f32FromBits(builder, 0x7f800000u));
667 Value cstNan = bcast(
f32FromBits(builder, 0x7fc00000));
670 Value cstCephesSQRTHF = bcast(
f32Cst(builder, 0.707106781186547524f));
671 Value cstCephesLogP0 = bcast(
f32Cst(builder, 7.0376836292E-2f));
672 Value cstCephesLogP1 = bcast(
f32Cst(builder, -1.1514610310E-1f));
673 Value cstCephesLogP2 = bcast(
f32Cst(builder, 1.1676998740E-1f));
674 Value cstCephesLogP3 = bcast(
f32Cst(builder, -1.2420140846E-1f));
675 Value cstCephesLogP4 = bcast(
f32Cst(builder, +1.4249322787E-1f));
676 Value cstCephesLogP5 = bcast(
f32Cst(builder, -1.6668057665E-1f));
677 Value cstCephesLogP6 = bcast(
f32Cst(builder, +2.0000714765E-1f));
678 Value cstCephesLogP7 = bcast(
f32Cst(builder, -2.4999993993E-1f));
679 Value cstCephesLogP8 = bcast(
f32Cst(builder, +3.3333331174E-1f));
681 Value x = op.getOperand();
684 x =
max(builder, x, cstMinNormPos);
687 std::pair<Value, Value> pair =
frexp(builder, x,
true);
689 Value e = pair.second;
699 Value mask = arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, x,
701 Value tmp = arith::SelectOp::create(builder, mask, x, cstZero);
703 x = arith::SubFOp::create(builder, x, cstOne);
704 e = arith::SubFOp::create(
705 builder, e, arith::SelectOp::create(builder, mask, cstOne, cstZero));
706 x = arith::AddFOp::create(builder, x, tmp);
708 Value x2 = arith::MulFOp::create(builder, x, x);
709 Value x3 = arith::MulFOp::create(builder, x2, x);
713 y0 = math::FmaOp::create(builder, cstCephesLogP0, x, cstCephesLogP1);
714 y1 = math::FmaOp::create(builder, cstCephesLogP3, x, cstCephesLogP4);
715 y2 = math::FmaOp::create(builder, cstCephesLogP6, x, cstCephesLogP7);
716 y0 = math::FmaOp::create(builder, y0, x, cstCephesLogP2);
717 y1 = math::FmaOp::create(builder, y1, x, cstCephesLogP5);
718 y2 = math::FmaOp::create(builder, y2, x, cstCephesLogP8);
719 y0 = math::FmaOp::create(builder, y0, x3, y1);
720 y0 = math::FmaOp::create(builder, y0, x3, y2);
721 y0 = arith::MulFOp::create(builder, y0, x3);
723 y0 = math::FmaOp::create(builder, cstNegHalf, x2, y0);
724 x = arith::AddFOp::create(builder, x, y0);
728 x = math::FmaOp::create(builder, x, cstLog2e, e);
731 x = math::FmaOp::create(builder, e, cstLn2, x);
734 Value invalidMask = arith::CmpFOp::create(builder, arith::CmpFPredicate::ULT,
735 op.getOperand(), cstZero);
736 Value zeroMask = arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ,
737 op.getOperand(), cstZero);
738 Value posInfMask = arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ,
739 op.getOperand(), cstPosInf);
745 Value aproximation = arith::SelectOp::create(
746 builder, zeroMask, cstMinusInf,
747 arith::SelectOp::create(
748 builder, invalidMask, cstNan,
749 arith::SelectOp::create(builder, posInfMask, cstPosInf, x)));
757struct LogApproximation :
public LogApproximationBase<math::LogOp> {
758 using LogApproximationBase::LogApproximationBase;
760 LogicalResult matchAndRewrite(math::LogOp op,
761 PatternRewriter &rewriter)
const final {
762 return logMatchAndRewrite(op, rewriter,
false);
768struct Log2Approximation :
public LogApproximationBase<math::Log2Op> {
769 using LogApproximationBase::LogApproximationBase;
771 LogicalResult matchAndRewrite(math::Log2Op op,
772 PatternRewriter &rewriter)
const final {
773 return logMatchAndRewrite(op, rewriter,
true);
783struct Log1pApproximation :
public OpRewritePattern<math::Log1pOp> {
787 LogicalResult matchAndRewrite(math::Log1pOp op,
788 PatternRewriter &rewriter)
const final;
794Log1pApproximation::matchAndRewrite(math::Log1pOp op,
795 PatternRewriter &rewriter)
const {
799 std::optional<VectorShape> shape =
vectorShape(op.getOperand());
801 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
802 auto bcast = [&](Value value) -> Value {
812 Value cstOne = bcast(
f32Cst(builder, 1.0f));
813 Value x = op.getOperand();
814 Value u = arith::AddFOp::create(builder, x, cstOne);
816 arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ, u, cstOne);
817 Value logU = math::LogOp::create(builder, u);
819 arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ, u, logU);
820 Value logLarge = arith::MulFOp::create(
822 arith::DivFOp::create(builder, logU,
823 arith::SubFOp::create(builder, u, cstOne)));
824 Value approximation = arith::SelectOp::create(
825 builder, arith::OrIOp::create(builder, uSmall, uInf), x, logLarge);
838struct AsinPolynomialApproximation :
public OpRewritePattern<math::AsinOp> {
842 LogicalResult matchAndRewrite(math::AsinOp op,
843 PatternRewriter &rewriter)
const final;
847AsinPolynomialApproximation::matchAndRewrite(math::AsinOp op,
848 PatternRewriter &rewriter)
const {
849 Value operand = op.getOperand();
852 if (!(elementType.
isF32() || elementType.
isF16()))
854 "only f32 and f16 type is supported.");
855 std::optional<VectorShape> shape =
vectorShape(operand);
857 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
858 auto bcast = [&](Value value) -> Value {
862 auto fma = [&](Value a, Value
b, Value c) -> Value {
863 return math::FmaOp::create(builder, a,
b, c);
866 auto mul = [&](Value a, Value
b) -> Value {
867 return arith::MulFOp::create(builder, a,
b);
870 auto sub = [&](Value a, Value
b) -> Value {
871 return arith::SubFOp::create(builder, a,
b);
874 auto abs = [&](Value a) -> Value {
return math::AbsFOp::create(builder, a); };
876 auto sqrt = [&](Value a) -> Value {
877 return math::SqrtOp::create(builder, a);
880 auto scopy = [&](Value a, Value
b) -> Value {
881 return math::CopySignOp::create(builder, a,
b);
884 auto sel = [&](Value a, Value
b, Value c) -> Value {
885 return arith::SelectOp::create(builder, a,
b, c);
888 Value abso =
abs(operand);
889 Value aa =
mul(operand, operand);
890 Value opp = sqrt(sub(bcast(
floatCst(builder, 1.0, elementType)), aa));
892 Value gt = arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, aa,
893 bcast(
floatCst(builder, 0.5, elementType)));
895 Value x = sel(gt, opp, abso);
900 Value r = bcast(
floatCst(builder, 5.5579749017470502e-2, elementType));
901 Value t = bcast(
floatCst(builder, -6.2027913464120114e-2, elementType));
903 r = fma(r, q, bcast(
floatCst(builder, 5.4224464349245036e-2, elementType)));
904 t = fma(t, q, bcast(
floatCst(builder, -1.1326992890324464e-2, elementType)));
905 r = fma(r, q, bcast(
floatCst(builder, 1.5268872539397656e-2, elementType)));
906 t = fma(t, q, bcast(
floatCst(builder, 1.0493798473372081e-2, elementType)));
907 r = fma(r, q, bcast(
floatCst(builder, 1.4106045900607047e-2, elementType)));
908 t = fma(t, q, bcast(
floatCst(builder, 1.7339776384962050e-2, elementType)));
909 r = fma(r, q, bcast(
floatCst(builder, 2.2372961589651054e-2, elementType)));
910 t = fma(t, q, bcast(
floatCst(builder, 3.0381912707941005e-2, elementType)));
911 r = fma(r, q, bcast(
floatCst(builder, 4.4642857881094775e-2, elementType)));
912 t = fma(t, q, bcast(
floatCst(builder, 7.4999999991367292e-2, elementType)));
914 r = fma(r, s, bcast(
floatCst(builder, 1.6666666666670193e-1, elementType)));
918 Value rsub = sub(bcast(
floatCst(builder, 1.57079632679, elementType)), r);
919 r = sel(gt, rsub, r);
920 r = scopy(r, operand);
934struct AcosPolynomialApproximation :
public OpRewritePattern<math::AcosOp> {
938 LogicalResult matchAndRewrite(math::AcosOp op,
939 PatternRewriter &rewriter)
const final;
943AcosPolynomialApproximation::matchAndRewrite(math::AcosOp op,
944 PatternRewriter &rewriter)
const {
945 Value operand = op.getOperand();
948 if (!(elementType.
isF32() || elementType.
isF16()))
950 "only f32 and f16 type is supported.");
951 std::optional<VectorShape> shape =
vectorShape(operand);
953 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
954 auto bcast = [&](Value value) -> Value {
958 auto fma = [&](Value a, Value
b, Value c) -> Value {
959 return math::FmaOp::create(builder, a,
b, c);
962 auto mul = [&](Value a, Value
b) -> Value {
963 return arith::MulFOp::create(builder, a,
b);
966 Value negOperand = arith::NegFOp::create(builder, operand);
967 Value zero = bcast(
floatCst(builder, 0.0, elementType));
968 Value half = bcast(
floatCst(builder, 0.5, elementType));
969 Value negOne = bcast(
floatCst(builder, -1.0, elementType));
971 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, operand, zero);
972 Value r = arith::SelectOp::create(builder, selR, negOperand, operand);
973 Value chkConst = bcast(
floatCst(builder, -0.5625, elementType));
975 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, r, chkConst);
978 fma(bcast(
floatCst(builder, 9.3282184640716537e-1, elementType)),
979 bcast(
floatCst(builder, 1.6839188885261840e+0, elementType)),
980 math::AsinOp::create(builder, r));
982 Value falseVal = math::SqrtOp::create(builder, fma(half, r, half));
983 falseVal = math::AsinOp::create(builder, falseVal);
984 falseVal =
mul(bcast(
floatCst(builder, 2.0, elementType)), falseVal);
986 r = arith::SelectOp::create(builder, firstPred, trueVal, falseVal);
989 Value greaterThanNegOne = arith::CmpFOp::create(
990 builder, arith::CmpFPredicate::OGE, operand, negOne);
993 arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, operand, zero);
995 Value betweenNegOneZero =
996 arith::AndIOp::create(builder, greaterThanNegOne, lessThanZero);
998 trueVal = fma(bcast(
floatCst(builder, 1.8656436928143307e+0, elementType)),
999 bcast(
floatCst(builder, 1.6839188885261840e+0, elementType)),
1000 arith::NegFOp::create(builder, r));
1003 arith::SelectOp::create(builder, betweenNegOneZero, trueVal, r);
1023 Value operand = op.getOperand();
1026 if (!(elementType.
isF32() || elementType.
isF16()))
1028 "only f32 and f16 type is supported.");
1036 const int intervalsCount = 3;
1037 const int polyDegree = 4;
1041 Value pp[intervalsCount][polyDegree + 1];
1042 pp[0][0] = bcast(
floatCst(builder, +0.00000000000000000e+00f, elementType));
1043 pp[0][1] = bcast(
floatCst(builder, +1.12837916222975858e+00f, elementType));
1044 pp[0][2] = bcast(
floatCst(builder, -5.23018562988006470e-01f, elementType));
1045 pp[0][3] = bcast(
floatCst(builder, +2.09741709609267072e-01f, elementType));
1046 pp[0][4] = bcast(
floatCst(builder, +2.58146801602987875e-02f, elementType));
1047 pp[1][0] = bcast(
floatCst(builder, +0.00000000000000000e+00f, elementType));
1048 pp[1][1] = bcast(
floatCst(builder, +1.12750687816789140e+00f, elementType));
1049 pp[1][2] = bcast(
floatCst(builder, -3.64721408487825775e-01f, elementType));
1050 pp[1][3] = bcast(
floatCst(builder, +1.18407396425136952e-01f, elementType));
1051 pp[1][4] = bcast(
floatCst(builder, +3.70645533056476558e-02f, elementType));
1052 pp[2][0] = bcast(
floatCst(builder, -3.30093071049483172e-03f, elementType));
1053 pp[2][1] = bcast(
floatCst(builder, +3.51961938357697011e-03f, elementType));
1054 pp[2][2] = bcast(
floatCst(builder, -1.41373622814988039e-03f, elementType));
1055 pp[2][3] = bcast(
floatCst(builder, +2.53447094961941348e-04f, elementType));
1056 pp[2][4] = bcast(
floatCst(builder, -1.71048029455037401e-05f, elementType));
1058 Value qq[intervalsCount][polyDegree + 1];
1059 qq[0][0] = bcast(
floatCst(builder, +1.000000000000000000e+00f, elementType));
1060 qq[0][1] = bcast(
floatCst(builder, -4.635138185962547255e-01f, elementType));
1061 qq[0][2] = bcast(
floatCst(builder, +5.192301327279782447e-01f, elementType));
1062 qq[0][3] = bcast(
floatCst(builder, -1.318089722204810087e-01f, elementType));
1063 qq[0][4] = bcast(
floatCst(builder, +7.397964654672315005e-02f, elementType));
1064 qq[1][0] = bcast(
floatCst(builder, +1.00000000000000000e+00f, elementType));
1065 qq[1][1] = bcast(
floatCst(builder, -3.27607011824493086e-01f, elementType));
1066 qq[1][2] = bcast(
floatCst(builder, +4.48369090658821977e-01f, elementType));
1067 qq[1][3] = bcast(
floatCst(builder, -8.83462621207857930e-02f, elementType));
1068 qq[1][4] = bcast(
floatCst(builder, +5.72442770283176093e-02f, elementType));
1069 qq[2][0] = bcast(
floatCst(builder, +1.00000000000000000e+00f, elementType));
1070 qq[2][1] = bcast(
floatCst(builder, -2.06069165953913769e+00f, elementType));
1071 qq[2][2] = bcast(
floatCst(builder, +1.62705939945477759e+00f, elementType));
1072 qq[2][3] = bcast(
floatCst(builder, -5.83389859211130017e-01f, elementType));
1073 qq[2][4] = bcast(
floatCst(builder, +8.21908939856640930e-02f, elementType));
1075 Value offsets[intervalsCount];
1076 offsets[0] = bcast(
floatCst(builder, 0.0f, elementType));
1077 offsets[1] = bcast(
floatCst(builder, 0.0f, elementType));
1078 offsets[2] = bcast(
floatCst(builder, 1.0f, elementType));
1080 Value bounds[intervalsCount];
1081 bounds[0] = bcast(
floatCst(builder, 0.8f, elementType));
1082 bounds[1] = bcast(
floatCst(builder, 2.0f, elementType));
1083 bounds[2] = bcast(
floatCst(builder, 3.75f, elementType));
1085 Value isNegativeArg =
1086 arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, operand, zero);
1087 Value negArg = arith::NegFOp::create(builder, operand);
1088 Value x = arith::SelectOp::create(builder, isNegativeArg, negArg, operand);
1090 Value offset = offsets[0];
1091 Value p[polyDegree + 1];
1092 Value q[polyDegree + 1];
1093 for (
int i = 0; i <= polyDegree; ++i) {
1099 Value isLessThanBound[intervalsCount];
1100 for (
int j = 0;
j < intervalsCount - 1; ++
j) {
1101 isLessThanBound[
j] =
1102 arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, x, bounds[
j]);
1103 for (
int i = 0; i <= polyDegree; ++i) {
1104 p[i] = arith::SelectOp::create(builder, isLessThanBound[
j], p[i],
1106 q[i] = arith::SelectOp::create(builder, isLessThanBound[
j], q[i],
1109 offset = arith::SelectOp::create(builder, isLessThanBound[
j], offset,
1112 isLessThanBound[intervalsCount - 1] = arith::CmpFOp::create(
1113 builder, arith::CmpFPredicate::ULT, x, bounds[intervalsCount - 1]);
1115 Value pPoly = makePolynomialCalculation(builder, p, x);
1116 Value qPoly = makePolynomialCalculation(builder, q, x);
1117 Value rationalPoly = arith::DivFOp::create(builder, pPoly, qPoly);
1118 Value formula = arith::AddFOp::create(builder, offset, rationalPoly);
1119 formula = arith::SelectOp::create(
1120 builder, isLessThanBound[intervalsCount - 1], formula, one);
1123 Value negFormula = arith::NegFOp::create(builder, formula);
1125 arith::SelectOp::create(builder, isNegativeArg, negFormula, formula);
1144 Value x = op.getOperand();
1166 Value a = math::AbsFOp::create(builder, x);
1167 Value p = arith::AddFOp::create(builder, a, pos2);
1168 Value r = arith::DivFOp::create(builder, one, p);
1169 Value q = math::FmaOp::create(builder, neg4, r, one);
1170 Value t = math::FmaOp::create(builder, arith::AddFOp::create(builder, q, one),
1173 math::FmaOp::create(builder, arith::NegFOp::create(builder, a), q, t);
1174 q = math::FmaOp::create(builder, r, e, q);
1176 p = bcast(
floatCst(builder, -0x1.a4a000p-12f, et));
1178 p = math::FmaOp::create(builder, p, q, c1);
1180 p = math::FmaOp::create(builder, p, q, c2);
1182 p = math::FmaOp::create(builder, p, q, c3);
1184 p = math::FmaOp::create(builder, p, q, c4);
1186 p = math::FmaOp::create(builder, p, q, c5);
1188 p = math::FmaOp::create(builder, p, q, c6);
1190 p = math::FmaOp::create(builder, p, q, c7);
1192 p = math::FmaOp::create(builder, p, q, c8);
1194 p = math::FmaOp::create(builder, p, q, c9);
1196 Value d = math::FmaOp::create(builder, pos2, a, one);
1197 r = arith::DivFOp::create(builder, one, d);
1198 q = math::FmaOp::create(builder, p, r, r);
1199 Value negfa = arith::NegFOp::create(builder, a);
1200 Value fmaqah = math::FmaOp::create(builder, q, negfa, onehalf);
1201 Value psubq = arith::SubFOp::create(builder, p, q);
1202 e = math::FmaOp::create(builder, fmaqah, pos2, psubq);
1203 r = math::FmaOp::create(builder, e, r, q);
1205 Value s = arith::MulFOp::create(builder, a, a);
1206 e = math::ExpOp::create(builder, arith::NegFOp::create(builder, s));
1208 t = math::FmaOp::create(builder, arith::NegFOp::create(builder, a), a, s);
1209 r = math::FmaOp::create(
1211 arith::MulFOp::create(builder, arith::MulFOp::create(builder, r, e), t));
1213 Value isNotLessThanInf = arith::XOrIOp::create(
1215 arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, a, posInf),
1217 r = arith::SelectOp::create(builder, isNotLessThanInf,
1218 arith::AddFOp::create(builder, x, x), r);
1219 Value isGreaterThanClamp =
1220 arith::CmpFOp::create(builder, arith::CmpFPredicate::OGT, a, clampVal);
1221 r = arith::SelectOp::create(builder, isGreaterThanClamp, zero, r);
1224 arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT, x, zero);
1225 r = arith::SelectOp::create(builder, isNegative,
1226 arith::SubFOp::create(builder, pos2, r), r);
1238 const std::optional<VectorShape>
shape,
Value value,
1239 float lowerBound,
float upperBound) {
1240 assert(!std::isnan(lowerBound));
1241 assert(!std::isnan(upperBound));
1247 auto selectCmp = [&builder](
auto pred,
Value value,
Value bound) {
1248 return arith::SelectOp::create(
1249 builder, arith::CmpFOp::create(builder, pred, value, bound), value,
1256 value = selectCmp(arith::CmpFPredicate::UGE, value,
1257 bcast(
f32Cst(builder, lowerBound)));
1258 value = selectCmp(arith::CmpFPredicate::ULE, value,
1259 bcast(
f32Cst(builder, upperBound)));
1263struct ExpApproximation :
public OpRewritePattern<math::ExpOp> {
1267 LogicalResult matchAndRewrite(math::ExpOp op,
1268 PatternRewriter &rewriter)
const final;
1272ExpApproximation::matchAndRewrite(math::ExpOp op,
1273 PatternRewriter &rewriter)
const {
1274 auto shape =
vectorShape(op.getOperand().getType());
1276 if (!elementTy.isF32())
1279 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
1281 auto add = [&](Value a, Value
b) -> Value {
1282 return arith::AddFOp::create(builder, a,
b);
1284 auto bcast = [&](Value value) -> Value {
1285 return broadcast(builder, value, shape);
1287 auto floor = [&](Value a) {
return math::FloorOp::create(builder, a); };
1288 auto fmla = [&](Value a, Value
b, Value c) {
1289 return math::FmaOp::create(builder, a,
b, c);
1291 auto mul = [&](Value a, Value
b) -> Value {
1292 return arith::MulFOp::create(builder, a,
b);
1316 Value cstHalf = bcast(
f32Cst(builder, 0.5f));
1317 Value cstOne = bcast(
f32Cst(builder, 1.0f));
1320 Value cstLog2ef = bcast(
f32Cst(builder, 1.44269504088896341f));
1322 Value cstExpC1 = bcast(
f32Cst(builder, -0.693359375f));
1323 Value cstExpC2 = bcast(
f32Cst(builder, 2.12194440e-4f));
1324 Value cstExpP0 = bcast(
f32Cst(builder, 1.9875691500E-4f));
1325 Value cstExpP1 = bcast(
f32Cst(builder, 1.3981999507E-3f));
1326 Value cstExpP2 = bcast(
f32Cst(builder, 8.3334519073E-3f));
1327 Value cstExpP3 = bcast(
f32Cst(builder, 4.1665795894E-2f));
1328 Value cstExpP4 = bcast(
f32Cst(builder, 1.6666665459E-1f));
1329 Value cstExpP5 = bcast(
f32Cst(builder, 5.0000001201E-1f));
1336 Value x = op.getOperand();
1337 x = clampWithNormals(builder, shape, x, -87.8f, 88.8f);
1338 Value n =
floor(fmla(x, cstLog2ef, cstHalf));
1379 n = clampWithNormals(builder, shape, n, -127.0f, 127.0f);
1382 x = fmla(cstExpC1, n, x);
1383 x = fmla(cstExpC2, n, x);
1386 Value z = fmla(x, cstExpP0, cstExpP1);
1387 z = fmla(z, x, cstExpP2);
1388 z = fmla(z, x, cstExpP3);
1389 z = fmla(z, x, cstExpP4);
1390 z = fmla(z, x, cstExpP5);
1391 z = fmla(z,
mul(x, x), x);
1396 Value nI32 = arith::FPToSIOp::create(builder, i32Vec, n);
1399 Value pow2 =
exp2I32(builder, nI32);
1402 Value ret =
mul(z, pow2);
1405 return mlir::success();
1416struct ExpM1Approximation :
public OpRewritePattern<math::ExpM1Op> {
1420 LogicalResult matchAndRewrite(math::ExpM1Op op,
1421 PatternRewriter &rewriter)
const final;
1426ExpM1Approximation::matchAndRewrite(math::ExpM1Op op,
1427 PatternRewriter &rewriter)
const {
1431 std::optional<VectorShape> shape =
vectorShape(op.getOperand());
1433 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
1434 auto bcast = [&](Value value) -> Value {
1435 return broadcast(builder, value, shape);
1441 Value cstOne = bcast(
f32Cst(builder, 1.0f));
1442 Value cstNegOne = bcast(
f32Cst(builder, -1.0f));
1443 Value x = op.getOperand();
1444 Value u = math::ExpOp::create(builder, x);
1446 arith::CmpFOp::create(builder, arith::CmpFPredicate::UEQ, u, cstOne);
1447 Value uMinusOne = arith::SubFOp::create(builder, u, cstOne);
1448 Value uMinusOneEqNegOne = arith::CmpFOp::create(
1449 builder, arith::CmpFPredicate::OEQ, uMinusOne, cstNegOne);
1451 Value logU = math::LogOp::create(builder, u);
1455 arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ, logU, u);
1458 Value expm1 = arith::MulFOp::create(builder, uMinusOne,
1459 arith::DivFOp::create(builder, x, logU));
1460 expm1 = arith::SelectOp::create(builder, isInf, u, expm1);
1461 Value approximation = arith::SelectOp::create(
1462 builder, uEqOneOrNaN, x,
1463 arith::SelectOp::create(builder, uMinusOneEqNegOne, cstNegOne, expm1));
1474template <
bool isSine,
typename OpTy>
1475struct SinAndCosApproximation :
public OpRewritePattern<OpTy> {
1477 using OpRewritePattern<OpTy>::OpRewritePattern;
1479 LogicalResult matchAndRewrite(OpTy op, PatternRewriter &rewriter)
const final;
1483#define TWO_OVER_PI \
1484 0.6366197723675813430755350534900574481378385829618257949906693762L
1486 1.5707963267948966192313216916397514420985846996875529104874722961L
1491template <
bool isSine,
typename OpTy>
1492LogicalResult SinAndCosApproximation<isSine, OpTy>::matchAndRewrite(
1495 llvm::is_one_of<OpTy, math::SinOp, math::CosOp>::value,
1496 "SinAndCosApproximation pattern expects math::SinOp or math::CosOp");
1508 return arith::MulFOp::create(builder, a,
b);
1511 return arith::SubFOp::create(builder, a,
b);
1513 auto floor = [&](
Value a) {
return math::FloorOp::create(builder, a); };
1516 auto fPToSingedInteger = [&](
Value a) ->
Value {
1517 return arith::FPToSIOp::create(builder, i32Vec, a);
1521 return arith::AndIOp::create(builder, a, bcast(
i32Cst(builder, 3)));
1525 return arith::CmpIOp::create(builder, arith::CmpIPredicate::eq, a,
b);
1529 return arith::CmpIOp::create(builder, arith::CmpIPredicate::sgt, a,
b);
1533 return arith::SelectOp::create(builder, cond, t, f);
1537 return math::FmaOp::create(builder, a,
b, c);
1541 return arith::OrIOp::create(builder, a,
b);
1547 Value x = op.getOperand();
1549 Value k = floor(
mul(x, twoOverPi));
1551 Value y = sub(x,
mul(k, piOverTwo));
1554 Value cstNegativeOne = bcast(
f32Cst(builder, -1.0));
1556 Value cstSC2 = bcast(
f32Cst(builder, -0.16666667163372039794921875f));
1557 Value cstSC4 = bcast(
f32Cst(builder, 8.333347737789154052734375e-3f));
1558 Value cstSC6 = bcast(
f32Cst(builder, -1.9842604524455964565277099609375e-4f));
1560 bcast(
f32Cst(builder, 2.760012648650445044040679931640625e-6f));
1562 bcast(
f32Cst(builder, -2.50293279435709337121807038784027099609375e-8f));
1565 Value cstCC4 = bcast(
f32Cst(builder, 4.166664183139801025390625e-2f));
1566 Value cstCC6 = bcast(
f32Cst(builder, -1.388833043165504932403564453125e-3f));
1567 Value cstCC8 = bcast(
f32Cst(builder, 2.47562347794882953166961669921875e-5f));
1569 bcast(
f32Cst(builder, -2.59630184018533327616751194000244140625e-7f));
1571 Value kMod4 = modulo4(fPToSingedInteger(k));
1573 Value kR0 = isEqualTo(kMod4, bcast(
i32Cst(builder, 0)));
1574 Value kR1 = isEqualTo(kMod4, bcast(
i32Cst(builder, 1)));
1575 Value kR2 = isEqualTo(kMod4, bcast(
i32Cst(builder, 2)));
1576 Value kR3 = isEqualTo(kMod4, bcast(
i32Cst(builder, 3)));
1578 Value sinuseCos = isSine ? bitwiseOr(kR1, kR3) : bitwiseOr(kR0, kR2);
1579 Value negativeRange = isSine ? isGreaterThan(kMod4, bcast(
i32Cst(builder, 1)))
1580 : bitwiseOr(kR1, kR2);
1584 Value base = select(sinuseCos, cstOne, y);
1585 Value cstC2 = select(sinuseCos, cstCC2, cstSC2);
1586 Value cstC4 = select(sinuseCos, cstCC4, cstSC4);
1587 Value cstC6 = select(sinuseCos, cstCC6, cstSC6);
1588 Value cstC8 = select(sinuseCos, cstCC8, cstSC8);
1589 Value cstC10 = select(sinuseCos, cstCC10, cstSC10);
1591 Value v1 = fmla(y2, cstC10, cstC8);
1592 Value v2 = fmla(y2, v1, cstC6);
1593 Value v3 = fmla(y2, v2, cstC4);
1594 Value v4 = fmla(y2, v3, cstC2);
1595 Value v5 = fmla(y2, v4, cstOne);
1598 Value approximation = select(negativeRange,
mul(cstNegativeOne, v6), v6);
1610struct CbrtApproximation :
public OpRewritePattern<math::CbrtOp> {
1613 LogicalResult matchAndRewrite(math::CbrtOp op,
1614 PatternRewriter &rewriter)
const final;
1621CbrtApproximation::matchAndRewrite(math::CbrtOp op,
1622 PatternRewriter &rewriter)
const {
1623 auto operand = op.getOperand();
1627 ImplicitLocOpBuilder
b(op->getLoc(), rewriter);
1628 std::optional<VectorShape> shape =
vectorShape(operand);
1637 auto bconst = [&](TypedAttr attr) -> Value {
1638 Value value = arith::ConstantOp::create(
b, attr);
1643 Value intTwo = bconst(
b.getI32IntegerAttr(2));
1644 Value intFour = bconst(
b.getI32IntegerAttr(4));
1645 Value intEight = bconst(
b.getI32IntegerAttr(8));
1646 Value intMagic = bconst(
b.getI32IntegerAttr(0x2a5137a0));
1647 Value fpThird = bconst(
b.getF32FloatAttr(0.33333333f));
1648 Value fpTwo = bconst(
b.getF32FloatAttr(2.0f));
1649 Value fpZero = bconst(
b.getF32FloatAttr(0.0f));
1655 Value absValue = math::AbsFOp::create(
b, operand);
1656 Value intValue = arith::BitcastOp::create(
b, intTy, absValue);
1657 Value divideBy4 = arith::ShRSIOp::create(
b, intValue, intTwo);
1658 Value divideBy16 = arith::ShRSIOp::create(
b, intValue, intFour);
1659 intValue = arith::AddIOp::create(
b, divideBy4, divideBy16);
1662 divideBy16 = arith::ShRSIOp::create(
b, intValue, intFour);
1663 intValue = arith::AddIOp::create(
b, intValue, divideBy16);
1666 Value divideBy256 = arith::ShRSIOp::create(
b, intValue, intEight);
1667 intValue = arith::AddIOp::create(
b, intValue, divideBy256);
1670 intValue = arith::AddIOp::create(
b, intValue, intMagic);
1674 Value floatValue = arith::BitcastOp::create(
b, floatTy, intValue);
1675 Value squared = arith::MulFOp::create(
b, floatValue, floatValue);
1676 Value mulTwo = arith::MulFOp::create(
b, floatValue, fpTwo);
1677 Value divSquared = arith::DivFOp::create(
b, absValue, squared);
1678 floatValue = arith::AddFOp::create(
b, mulTwo, divSquared);
1679 floatValue = arith::MulFOp::create(
b, floatValue, fpThird);
1682 squared = arith::MulFOp::create(
b, floatValue, floatValue);
1683 mulTwo = arith::MulFOp::create(
b, floatValue, fpTwo);
1684 divSquared = arith::DivFOp::create(
b, absValue, squared);
1685 floatValue = arith::AddFOp::create(
b, mulTwo, divSquared);
1686 floatValue = arith::MulFOp::create(
b, floatValue, fpThird);
1690 arith::CmpFOp::create(
b, arith::CmpFPredicate::OEQ, absValue, fpZero);
1691 floatValue = arith::SelectOp::create(
b, isZero, fpZero, floatValue);
1692 floatValue = math::CopySignOp::create(
b, floatValue, operand);
1703struct RsqrtApproximation :
public OpRewritePattern<math::RsqrtOp> {
1706 LogicalResult matchAndRewrite(math::RsqrtOp op,
1707 PatternRewriter &rewriter)
const final;
1712RsqrtApproximation::matchAndRewrite(math::RsqrtOp op,
1713 PatternRewriter &rewriter)
const {
1717 std::optional<VectorShape> shape =
vectorShape(op.getOperand());
1720 if (!shape || shape->sizes.empty() || shape->sizes.back() % 8 != 0)
1723 ImplicitLocOpBuilder builder(op->getLoc(), rewriter);
1724 auto bcast = [&](Value value) -> Value {
1725 return broadcast(builder, value, shape);
1728 Value cstPosInf = bcast(
f32FromBits(builder, 0x7f800000u));
1729 Value cstOnePointFive = bcast(
f32Cst(builder, 1.5f));
1730 Value cstNegHalf = bcast(
f32Cst(builder, -0.5f));
1731 Value cstMinNormPos = bcast(
f32FromBits(builder, 0x00800000u));
1733 Value negHalf = arith::MulFOp::create(builder, op.getOperand(), cstNegHalf);
1737 Value ltMinMask = arith::CmpFOp::create(builder, arith::CmpFPredicate::OLT,
1738 op.getOperand(), cstMinNormPos);
1739 Value infMask = arith::CmpFOp::create(builder, arith::CmpFPredicate::OEQ,
1740 op.getOperand(), cstPosInf);
1741 Value notNormalFiniteMask = arith::OrIOp::create(builder, ltMinMask, infMask);
1745 builder, op->getOperands(), 8, [&builder](
ValueRange operands) -> Value {
1746 return x86::avx::RsqrtOp::create(builder, operands);
1753 Value inner = arith::MulFOp::create(builder, negHalf, yApprox);
1754 Value fma = math::FmaOp::create(builder, yApprox, inner, cstOnePointFive);
1755 Value yNewton = arith::MulFOp::create(builder, yApprox, fma);
1763 arith::SelectOp::create(builder, notNormalFiniteMask, yApprox, yNewton);
1786template <
typename OpType>
1791 if (predicate(OpType::getOperationName())) {
1792 patterns.
add<ReuseF32Expansion<OpType>>(patterns.
getContext(), benefit);
1827template <
typename OpType,
typename PatternType>
1831 if (predicate(OpType::getOperationName())) {
1840 AcosPolynomialApproximation>(
1841 patterns, predicate, benefit);
1843 AsinPolynomialApproximation>(
1844 patterns, predicate, benefit);
1846 patterns, predicate, benefit);
1848 patterns, predicate, benefit);
1850 patterns, predicate, benefit);
1852 CosOp, SinAndCosApproximation<false, math::CosOp>>(patterns, predicate,
1855 patterns, predicate, benefit);
1858 patterns, predicate, benefit);
1860 patterns, predicate, benefit);
1862 patterns, predicate, benefit);
1864 patterns, predicate, benefit);
1866 patterns, predicate, benefit);
1868 patterns, predicate, benefit);
1870 patterns, predicate, benefit);
1872 SinOp, SinAndCosApproximation<true, math::SinOp>>(patterns, predicate,
1875 patterns, predicate, benefit);
1882 return llvm::is_contained(
1883 {math::AtanOp::getOperationName(), math::Atan2Op::getOperationName(),
1884 math::TanhOp::getOperationName(), math::LogOp::getOperationName(),
1885 math::Log2Op::getOperationName(), math::Log1pOp::getOperationName(),
1886 math::ErfOp::getOperationName(), math::ErfcOp::getOperationName(),
1887 math::ExpOp::getOperationName(), math::ExpM1Op::getOperationName(),
1888 math::CbrtOp::getOperationName(), math::SinOp::getOperationName(),
1889 math::CosOp::getOperationName()},
1894 patterns, [](StringRef name) ->
bool {
1895 return llvm::is_contained(
1896 {math::AtanOp::getOperationName(),
1897 math::Atan2Op::getOperationName(),
1898 math::TanhOp::getOperationName(), math::LogOp::getOperationName(),
1899 math::Log2Op::getOperationName(),
1900 math::Log1pOp::getOperationName(), math::ErfOp::getOperationName(),
1901 math::ErfcOp::getOperationName(), math::AsinOp::getOperationName(),
1902 math::AcosOp::getOperationName(), math::ExpOp::getOperationName(),
1903 math::ExpM1Op::getOperationName(),
1904 math::CbrtOp::getOperationName(), math::SinOp::getOperationName(),
1905 math::CosOp::getOperationName()},
1910 auto predicateRsqrt = [](StringRef name) {
1911 return name == math::RsqrtOp::getOperationName();
static llvm::ManagedStatic< PassManagerOptions > options
static Value exp2I32(ImplicitLocOpBuilder &builder, Value arg)
static void populateMathF32ExpansionPattern(RewritePatternSet &patterns, llvm::function_ref< bool(StringRef)> predicate, PatternBenefit benefit)
static Value boolCst(ImplicitLocOpBuilder &builder, bool value)
static Value floatCst(ImplicitLocOpBuilder &builder, float value, Type elementType)
static Value handleMultidimensionalVectors(ImplicitLocOpBuilder &builder, ValueRange operands, int64_t vectorWidth, llvm::function_ref< Value(ValueRange)> compute)
LogicalResult insertCasts(Operation *op, PatternRewriter &rewriter)
static Value clamp(ImplicitLocOpBuilder &builder, Value value, Value lowerBound, Value upperBound)
static std::pair< Value, Value > frexp(ImplicitLocOpBuilder &builder, Value arg, bool isPositive=false)
static std::optional< VectorShape > vectorShape(Type type)
static Value i32Cst(ImplicitLocOpBuilder &builder, int32_t value)
static Type broadcast(Type type, std::optional< VectorShape > shape)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value f32FromBits(ImplicitLocOpBuilder &builder, uint32_t bits)
static Value f32Cst(ImplicitLocOpBuilder &builder, double value)
static void populateMathPolynomialApproximationPattern(RewritePatternSet &patterns, llvm::function_ref< bool(StringRef)> predicate, PatternBenefit benefit)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
IntegerAttr getI32IntegerAttr(int32_t value)
FloatAttr getFloatAttr(Type type, double value)
IntegerType getIntegerType(unsigned width)
BoolAttr getBoolAttr(bool value)
TypedAttr getZeroAttr(Type type)
FloatAttr getF32FloatAttr(float value)
ImplicitLocOpBuilder maintains a 'current location', allowing use of the create<> method without spec...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
Operation is the basic unit of execution within MLIR.
Location getLoc()
The source location the operation was defined or derived from.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
Type front()
Return first type in the range.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
DynamicAPInt floor(const Fraction &f)
Fraction abs(const Fraction &f)
Include the generated interface declarations.
void populatePolynomialApproximateErfcPattern(RewritePatternSet &patterns)
SmallVector< int64_t > computeStrides(ArrayRef< int64_t > sizes)
void populateMathF32ExpansionPatterns(RewritePatternSet &patterns, llvm::function_ref< bool(StringRef)> predicate, PatternBenefit=1)
void populatePolynomialApproximateErfPattern(RewritePatternSet &patterns)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
void populatePolynomialApproximateTanhPattern(RewritePatternSet &patterns)
SmallVector< int64_t > delinearize(int64_t linearIndex, ArrayRef< int64_t > strides)
Given the strides together with a linear index in the dimension space, return the vector-space offset...
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
int64_t computeMaxLinearIndex(ArrayRef< int64_t > basis)
Return the number of elements of basis (i.e.
void populateMathPolynomialApproximationPatterns(RewritePatternSet &patterns, llvm::function_ref< bool(StringRef)> predicate, PatternBenefit=1)
ArrayRef< int64_t > sizes
ArrayRef< bool > scalableFlags
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
Patterns must specify the root operation name they match against, and can also specify the benefit of...
LogicalResult matchAndRewrite(math::ErfOp op, PatternRewriter &rewriter) const final
LogicalResult matchAndRewrite(math::ErfcOp op, PatternRewriter &rewriter) const final
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.