25#define GEN_PASS_DEF_MATHEXPANDOPSPASS
26#include "mlir/Dialect/Math/Transforms/Passes.h.inc"
32 auto shapedTy = dyn_cast<ShapedType>(type);
33 return shapedTy && !shapedTy.hasRank();
41 bool losesInfo =
false;
44 value.convert(cast<FloatType>(eltType).getFloatSemantics(),
45 APFloat::rmNearestTiesToEven, &losesInfo);
46 auto attr =
b.getFloatAttr(eltType, value);
47 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
48 if (shapedTy.hasStaticShape())
49 return arith::ConstantOp::create(
b, loc,
53 Value scalar = arith::ConstantOp::create(
b, loc, eltType, attr);
55 for (
int64_t i = 0; i < shapedTy.getRank(); ++i) {
56 if (shapedTy.isDynamicDim(i))
57 dynamicSizes.push_back(
58 tensor::DimOp::create(
b, loc, dynamicShapeRef, i));
60 return tensor::SplatOp::create(
b, loc, type, scalar, dynamicSizes);
63 return arith::ConstantOp::create(
b, loc, attr);
77 auto attr =
b.getIntegerAttr(eltType, value);
78 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
79 if (shapedTy.hasStaticShape())
80 return arith::ConstantOp::create(
b, loc,
84 Value scalar = arith::ConstantOp::create(
b, loc, eltType, attr);
86 for (
int64_t i = 0; i < shapedTy.getRank(); ++i) {
87 if (shapedTy.isDynamicDim(i))
88 dynamicSizes.push_back(
89 tensor::DimOp::create(
b, loc, dynamicShapeRef, i));
91 return tensor::SplatOp::create(
b, loc, type, scalar, dynamicSizes);
94 return arith::ConstantOp::create(
b, loc, attr);
100 if (
auto shapedTy = dyn_cast<ShapedType>(opType))
101 i64Ty = shapedTy.clone(i64Ty);
102 Value fixedConvert = arith::FPToSIOp::create(
b, i64Ty, operand);
103 Value fpFixedConvert = arith::SIToFPOp::create(
b, opType, fixedConvert);
106 return math::CopySignOp::create(
b, fpFixedConvert, operand);
112 Value operand = op.getOperand();
118 Value exp = math::ExpOp::create(
b, operand);
119 Value neg = arith::NegFOp::create(
b, operand);
120 Value nexp = math::ExpOp::create(
b, neg);
121 Value sub = arith::SubFOp::create(
b, exp, nexp);
123 Value res = arith::MulFOp::create(
b, sub, half);
131 Value operand = op.getOperand();
137 Value exp = math::ExpOp::create(
b, operand);
138 Value neg = arith::NegFOp::create(
b, operand);
139 Value nexp = math::ExpOp::create(
b, neg);
140 Value add = arith::AddFOp::create(
b, exp, nexp);
142 Value res = arith::MulFOp::create(
b,
add, half);
156 Value operand = op.getOperand();
157 auto floatType = operand.
getType();
168 Value isNegative = arith::CmpFOp::create(
169 rewriter, loc, arith::CmpFPredicate::OLT, operand, zero);
170 Value isNegativeFloat =
171 arith::UIToFPOp::create(rewriter, loc, floatType, isNegative);
172 Value isNegativeTimesNegTwo =
173 arith::MulFOp::create(rewriter, loc, isNegativeFloat, negTwo);
174 Value sign = arith::AddFOp::create(rewriter, loc, isNegativeTimesNegTwo, one);
177 Value positiveX = arith::MulFOp::create(rewriter, loc, sign, operand);
180 Value negDoubledX = arith::MulFOp::create(rewriter, loc, negTwo, positiveX);
181 Value exp2x = math::ExpOp::create(rewriter, loc, negDoubledX);
182 Value dividend = arith::SubFOp::create(rewriter, loc, one, exp2x);
183 Value divisor = arith::AddFOp::create(rewriter, loc, one, exp2x);
184 Value positiveRes = arith::DivFOp::create(rewriter, loc, dividend, divisor);
195 Value operand = op.getOperand();
197 Value sin = math::SinOp::create(
b, type, operand);
198 Value cos = math::CosOp::create(
b, type, operand);
199 Value div = arith::DivFOp::create(
b, type, sin, cos);
208 Value operand = op.getOperand();
215 Value fma = math::FmaOp::create(
b, operand, operand, one);
216 Value sqrt = math::SqrtOp::create(
b, fma);
217 Value add = arith::AddFOp::create(
b, operand, sqrt);
227 Value operand = op.getOperand();
235 Value fma = math::FmaOp::create(
b, operand, operand, negOne);
236 Value sqrt = math::SqrtOp::create(
b, fma);
237 Value add = arith::AddFOp::create(
b, operand, sqrt);
247 Value operand = op.getOperand();
254 Value add = arith::AddFOp::create(
b, operand, one);
255 Value neg = arith::NegFOp::create(
b, operand);
256 Value sub = arith::AddFOp::create(
b, neg, one);
260 Value res = arith::MulFOp::create(
b, log, half);
267 Value operandA = op.getOperand(0);
268 Value operandB = op.getOperand(1);
269 Value operandC = op.getOperand(2);
270 Type type = op.getType();
271 Value mult = arith::MulFOp::create(
b, type, operandA, operandB);
272 Value add = arith::AddFOp::create(
b, type, mult, operandC);
284 Value operand = op.getOperand();
291 FloatType floatTy = llvm::dyn_cast<FloatType>(operandETy);
292 const llvm::fltSemantics &semantics = floatTy.getFloatSemantics();
294 unsigned bitWidth = floatTy.getWidth();
295 unsigned mantissaWidth = floatTy.getFPMantissaWidth() - 1;
296 const int bias = (&semantics == &APFloat::Float8E8M0FNU())
297 ? -semantics.minExponent
298 : -(semantics.minExponent - 1);
299 bool hasNegativeZeroNaNEncoding =
300 (semantics.nanEncoding == llvm::fltNanEncoding::NegativeZero);
303 if (
auto shapedTy = dyn_cast<ShapedType>(opType))
304 iTy = shapedTy.clone(iTy);
313 Value operandBitcast = arith::BitcastOp::create(
b, iTy, operand);
315 op->getLoc(), iTy,
static_cast<int64_t>((1ull << (bitWidth - 1)) - 1),
b,
317 Value unsignedBits = arith::AndIOp::create(
b, operandBitcast, cMask);
320 static_cast<int64_t>((uint64_t(bias + mantissaWidth)) << mantissaWidth),
322 Value isLargeExp = arith::CmpIOp::create(
b, arith::CmpIPredicate::uge,
323 unsignedBits, cThreshold);
324 Value isSpecialValOrLargeVal = isLargeExp;
328 if (hasNegativeZeroNaNEncoding) {
330 op->getLoc(), iTy,
static_cast<int64_t>(1ull << (bitWidth - 1)),
b,
332 Value isNegZeroEncoding = arith::CmpIOp::create(
333 b, arith::CmpIPredicate::eq, operandBitcast, cNegZeroBits);
334 isSpecialValOrLargeVal =
335 arith::OrIOp::create(
b, isLargeExp, isNegZeroEncoding);
344 Value gtCheck = arith::CmpFOp::create(
b, arith::CmpFPredicate::OGT, operand,
347 arith::SelectOp::create(
b, op->getLoc(), gtCheck, one, zero);
349 Value add = arith::AddFOp::create(
b, opType, fpFixedConvert, incrValue);
350 Value ret = arith::SelectOp::create(
b, isSpecialValOrLargeVal, operand,
add);
362 Value base = op.getOperand(0);
363 Value power = op.getOperand(1);
366 auto convertFPowItoPowf = [&]() -> LogicalResult {
367 Value castPowerToFp =
368 arith::SIToFPOp::create(rewriter, op.getLoc(), baseType, power);
369 Value res = math::PowFOp::create(rewriter, op.getLoc(), baseType, base,
377 return convertFPowItoPowf();
381 return convertFPowItoPowf();
383 int64_t powerInt = value.getSExtValue();
384 bool isNegative = powerInt < 0;
385 int64_t absPower = std::abs(powerInt);
389 while (absPower > 0) {
391 res = arith::MulFOp::create(
b, baseType, base, res);
393 base = arith::MulFOp::create(
b, baseType, base, base);
399 .getFloatSemantics();
402 APFloat::getZero(sem,
false), rewriter);
405 APFloat::getZero(sem,
true), rewriter);
408 APFloat::getInf(sem,
false), rewriter);
411 APFloat::getInf(sem,
true), rewriter);
413 arith::CmpFOp::create(
b, arith::CmpFPredicate::OEQ, res, zero);
414 Value negZeroEqCheck =
415 arith::CmpFOp::create(
b, arith::CmpFPredicate::OEQ, res, negZero);
416 res = arith::DivFOp::create(
b, baseType, one, res);
418 arith::SelectOp::create(
b, op->getLoc(), zeroEqCheck, posInfinity, res);
419 res = arith::SelectOp::create(
b, op->getLoc(), negZeroEqCheck, negInfinity,
432 Value operandA = op.getOperand(0);
433 Value operandB = op.getOperand(1);
434 auto typeA = operandA.
getType();
435 auto typeB = operandB.
getType();
441 return arith::MulFOp::create(
b, x, y);
444 if (valueB.isZero()) {
450 if (valueB.isExactlyValue(1.0)) {
455 if (valueB.isExactlyValue(-1.0)) {
458 Value div = arith::DivFOp::create(
b, one, operandA);
462 if (valueB.isExactlyValue(0.5)) {
464 Value sqrt = math::SqrtOp::create(
b, operandA);
468 if (valueB.isExactlyValue(-0.5)) {
470 Value rsqrt = math::RsqrtOp::create(
b, operandA);
474 if (valueB.isExactlyValue(2.0)) {
476 rewriter.
replaceOp(op, mulf(operandA, operandA));
479 if (valueB.isExactlyValue(-2.0)) {
483 Value div = arith::DivFOp::create(
b, one, mulf(operandA, operandA));
487 if (valueB.isExactlyValue(3.0)) {
488 rewriter.
replaceOp(op, mulf(mulf(operandA, operandA), operandA));
493 Value logA = math::LogOp::create(
b, operandA);
494 Value mult = arith::MulFOp::create(
b, operandB, logA);
495 Value expResult = math::ExpOp::create(
b, mult);
507 Value operand = op.getOperand();
515 Value mult = arith::MulFOp::create(
b, opType, operand, ln2);
516 Value exp = math::ExpOp::create(
b, op->getLoc(), mult);
525 Value operand = op.getOperand();
532 if (!opEType.
isF32()) {
536 Type i32Ty =
b.getI32Type();
537 if (
auto shapedTy = dyn_cast<ShapedType>(opType))
538 i32Ty = shapedTy.clone(i32Ty);
545 Value incrValue = math::CopySignOp::create(
b, half, operand);
546 Value add = arith::AddFOp::create(
b, opType, operand, incrValue);
569 Value operandBitcast = arith::BitcastOp::create(
b, i32Ty, operand);
570 Value operandExp = arith::AndIOp::create(
571 b, arith::ShRUIOp::create(
b, operandBitcast, c23), expMask);
572 Value operandBiasedExp = arith::SubIOp::create(
b, operandExp, c127);
573 Value isSpecialValOrLargeVal = arith::CmpIOp::create(
574 b, arith::CmpIPredicate::sge, operandBiasedExp, c23);
576 Value result = arith::SelectOp::create(
b, isSpecialValOrLargeVal, operand,
586 auto operand = op.getOperand();
587 auto operandTy = operand.
getType();
595 if (!eTy.isIntOrFloat()) {
596 return rewriter.
notifyMatchFailure(op,
"ctlz expansion only supports int or float types");
599 int32_t bitwidth = eTy.getIntOrFloatBitWidth();
603 uint64_t allbits = -1;
605 allbits = allbits >> (64 - bitwidth);
610 for (int32_t bw = bitwidth; bw > 1; bw = bw / 2) {
612 auto bits =
createIntConst(loc, operandTy, half, rewriter, operand);
614 createIntConst(loc, operandTy, allbits >> half, rewriter, operand);
616 Value pred = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::ule,
618 Value add = arith::AddIOp::create(rewriter, loc, count, bits);
619 Value shift = arith::ShLIOp::create(rewriter, loc, x, bits);
621 x = arith::SelectOp::create(rewriter, loc, pred, shift, x);
622 count = arith::SelectOp::create(rewriter, loc, pred,
add, count);
626 Value pred = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::eq,
630 Value sel = arith::SelectOp::create(rewriter, loc, pred, bwval, count);
640 auto operand = op.getOperand();
642 Type resultTy = op.getType();
649 if (!isa<FloatType>(operandETy) || !isa<FloatType>(resultETy)) {
653 Type fTy = operandTy;
655 if (
auto shapedTy = dyn_cast<ShapedType>(fTy)) {
656 iTy = shapedTy.clone(iTy);
661 unsigned mantissaWidth =
662 llvm::cast<FloatType>(operandETy).getFPMantissaWidth() - 1;
663 unsigned exponentWidth = bitWidth - mantissaWidth - 1;
676 createIntConst(loc, iTy, (1ull << (exponentWidth - 1)) - 1,
b, operand);
684 Value operandBitcast = arith::BitcastOp::create(
b, iTy, operand);
685 Value round = math::RoundOp::create(
b, operand);
686 Value roundBitcast = arith::BitcastOp::create(
b, iTy, round);
689 Value operandExp = arith::AndIOp::create(
690 b, arith::ShRUIOp::create(
b, operandBitcast, c23), expMask);
691 Value operandBiasedExp = arith::SubIOp::create(
b, operandExp, c127);
692 Value roundExp = arith::AndIOp::create(
693 b, arith::ShRUIOp::create(
b, roundBitcast, c23), expMask);
694 Value roundBiasedExp = arith::SubIOp::create(
b, roundExp, c127);
698 Value clampedShift = arith::MaxSIOp::create(
b, shift, c0);
699 clampedShift = arith::MinSIOp::create(
b, clampedShift, c31);
700 return arith::ShRUIOp::create(
b, x, clampedShift);
703 auto maskMantissa = [&](
Value mantissa,
705 Value shiftedMantissaMask = safeShiftRight(c23Mask, mantissaMaskRightShift);
706 return arith::AndIOp::create(
b, mantissa, shiftedMantissaMask);
723 Value roundBiasedExpEq0 =
724 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, roundBiasedExp, c0);
725 Value roundBiasedExpMinus1 = arith::SubIOp::create(
b, roundBiasedExp, c1);
726 Value roundMaskedMantissa = maskMantissa(roundBitcast, roundBiasedExpMinus1);
727 Value roundIsNotEvenOrSpecialVal = arith::CmpIOp::create(
728 b, arith::CmpIPredicate::ne, roundMaskedMantissa, c0);
729 roundIsNotEvenOrSpecialVal =
730 arith::OrIOp::create(
b, roundIsNotEvenOrSpecialVal, roundBiasedExpEq0);
739 Value operandBiasedExpEqNeg1 = arith::CmpIOp::create(
740 b, arith::CmpIPredicate::eq, operandBiasedExp, cNeg1);
741 Value expectedOperandMaskedMantissa = arith::SelectOp::create(
742 b, operandBiasedExpEqNeg1, c0, safeShiftRight(c2To22, operandBiasedExp));
743 Value operandMaskedMantissa = maskMantissa(operandBitcast, operandBiasedExp);
744 Value operandIsHalfway =
745 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, operandMaskedMantissa,
746 expectedOperandMaskedMantissa);
748 Value operandBiasedExpGeNeg1 = arith::CmpIOp::create(
749 b, arith::CmpIPredicate::sge, operandBiasedExp, cNeg1);
750 Value operandBiasedExpLt23 = arith::CmpIOp::create(
751 b, arith::CmpIPredicate::slt, operandBiasedExp, c23);
753 arith::AndIOp::create(
b, operandIsHalfway, operandBiasedExpLt23);
755 arith::AndIOp::create(
b, operandIsHalfway, operandBiasedExpGeNeg1);
759 Value sign = math::CopySignOp::create(
b, c1Float, operand);
760 Value roundShifted = arith::SubFOp::create(
b, round, sign);
764 arith::AndIOp::create(
b, roundIsNotEvenOrSpecialVal, operandIsHalfway);
765 Value result = arith::SelectOp::create(
b, needsShift, roundShifted, round);
777 auto operand = op.getOperand();
778 auto operandTy = operand.
getType();
784 if (!isa<FloatType>(eTy))
788 auto constOneFloat =
createFloatConst(loc, operandTy, 1.0, rewriter, operand);
789 auto sqrtOp = math::SqrtOp::create(rewriter, loc, operand);
797 auto minOp = arith::MinimumFOp::create(rewriter, op.getLoc(), op.getValue(),
798 op.getMax(), op.getFastmath());
806 auto filter = [&](StringRef name) {
810 assert(
"math" == MathDialect::getDialectNamespace());
811 name.consume_front(
"math.");
812 return opMnemonics.empty() || (llvm::count(opMnemonics, name) > 0);
814 if (filter(CountLeadingZerosOp::getOperationName()))
816 if (filter(SinhOp::getOperationName()))
818 if (filter(CoshOp::getOperationName()))
820 if (filter(TanOp::getOperationName()))
822 if (filter(TanhOp::getOperationName()))
824 if (filter(AsinhOp::getOperationName()))
826 if (filter(AcoshOp::getOperationName()))
828 if (filter(AtanhOp::getOperationName()))
830 if (filter(FmaOp::getOperationName()))
832 if (filter(CeilOp::getOperationName()))
834 if (filter(Exp2Op::getOperationName()))
836 if (filter(PowFOp::getOperationName()))
838 if (filter(FPowIOp::getOperationName()))
840 if (filter(RoundOp::getOperationName()))
842 if (filter(RoundEvenOp::getOperationName()))
844 if (filter(RsqrtOp::getOperationName()))
846 if (filter(ClampFOp::getOperationName()))
854struct MathExpandOpsPass final
856 using MathExpandOpsPassBase::MathExpandOpsPassBase;
858 void runOnOperation()
override {
861 llvm::to_vector_of<StringRef>(opMnemonics);
864 return signalPassFailure();
Attributes are known-constant values of operations.
IntegerType getIntegerType(unsigned width)
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
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...
This class helps build Operations.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
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...
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 represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
void populateExpansionPatterns(RewritePatternSet &patterns, ArrayRef< StringRef > opMnemonics={})
Adds patterns to expand math operations into other more fundamental operations.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
detail::constant_float_value_binder m_ConstantFloat(FloatAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor float (splat) and writes the float value to bind_va...