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;
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 res = arith::DivFOp::create(
b, baseType, one, res);
410 Value operandA = op.getOperand(0);
411 Value operandB = op.getOperand(1);
412 auto typeA = operandA.
getType();
413 auto typeB = operandB.
getType();
419 return arith::MulFOp::create(
b, x, y);
422 if (valueB.isZero()) {
428 if (valueB.isExactlyValue(1.0)) {
433 if (valueB.isExactlyValue(-1.0)) {
436 Value div = arith::DivFOp::create(
b, one, operandA);
440 if (valueB.isExactlyValue(0.5)) {
442 Value sqrt = math::SqrtOp::create(
b, operandA);
446 if (valueB.isExactlyValue(-0.5)) {
448 Value rsqrt = math::RsqrtOp::create(
b, operandA);
452 if (valueB.isExactlyValue(2.0)) {
454 rewriter.
replaceOp(op, mulf(operandA, operandA));
457 if (valueB.isExactlyValue(-2.0)) {
461 Value div = arith::DivFOp::create(
b, one, mulf(operandA, operandA));
465 if (valueB.isExactlyValue(3.0)) {
466 rewriter.
replaceOp(op, mulf(mulf(operandA, operandA), operandA));
471 Value logA = math::LogOp::create(
b, operandA);
472 Value mult = arith::MulFOp::create(
b, operandB, logA);
473 Value expResult = math::ExpOp::create(
b, mult);
485 Value operand = op.getOperand();
493 Value mult = arith::MulFOp::create(
b, opType, operand, ln2);
494 Value exp = math::ExpOp::create(
b, op->getLoc(), mult);
503 Value operand = op.getOperand();
510 if (!opEType.
isF32()) {
514 Type i32Ty =
b.getI32Type();
515 if (
auto shapedTy = dyn_cast<ShapedType>(opType))
516 i32Ty = shapedTy.clone(i32Ty);
523 Value incrValue = math::CopySignOp::create(
b, half, operand);
524 Value add = arith::AddFOp::create(
b, opType, operand, incrValue);
547 Value operandBitcast = arith::BitcastOp::create(
b, i32Ty, operand);
548 Value operandExp = arith::AndIOp::create(
549 b, arith::ShRUIOp::create(
b, operandBitcast, c23), expMask);
550 Value operandBiasedExp = arith::SubIOp::create(
b, operandExp, c127);
551 Value isSpecialValOrLargeVal = arith::CmpIOp::create(
552 b, arith::CmpIPredicate::sge, operandBiasedExp, c23);
554 Value result = arith::SelectOp::create(
b, isSpecialValOrLargeVal, operand,
564 auto operand = op.getOperand();
565 auto operandTy = operand.
getType();
573 if (!eTy.isIntOrFloat()) {
574 return rewriter.
notifyMatchFailure(op,
"ctlz expansion only supports int or float types");
577 int32_t bitwidth = eTy.getIntOrFloatBitWidth();
581 uint64_t allbits = -1;
583 allbits = allbits >> (64 - bitwidth);
588 for (int32_t bw = bitwidth; bw > 1; bw = bw / 2) {
590 auto bits =
createIntConst(loc, operandTy, half, rewriter, operand);
592 createIntConst(loc, operandTy, allbits >> half, rewriter, operand);
594 Value pred = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::ule,
596 Value add = arith::AddIOp::create(rewriter, loc, count, bits);
597 Value shift = arith::ShLIOp::create(rewriter, loc, x, bits);
599 x = arith::SelectOp::create(rewriter, loc, pred, shift, x);
600 count = arith::SelectOp::create(rewriter, loc, pred,
add, count);
604 Value pred = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::eq,
608 Value sel = arith::SelectOp::create(rewriter, loc, pred, bwval, count);
618 auto operand = op.getOperand();
620 Type resultTy = op.getType();
627 if (!isa<FloatType>(operandETy) || !isa<FloatType>(resultETy)) {
631 Type fTy = operandTy;
633 if (
auto shapedTy = dyn_cast<ShapedType>(fTy)) {
634 iTy = shapedTy.clone(iTy);
639 unsigned mantissaWidth =
640 llvm::cast<FloatType>(operandETy).getFPMantissaWidth() - 1;
641 unsigned exponentWidth = bitWidth - mantissaWidth - 1;
654 createIntConst(loc, iTy, (1ull << (exponentWidth - 1)) - 1,
b, operand);
662 Value operandBitcast = arith::BitcastOp::create(
b, iTy, operand);
663 Value round = math::RoundOp::create(
b, operand);
664 Value roundBitcast = arith::BitcastOp::create(
b, iTy, round);
667 Value operandExp = arith::AndIOp::create(
668 b, arith::ShRUIOp::create(
b, operandBitcast, c23), expMask);
669 Value operandBiasedExp = arith::SubIOp::create(
b, operandExp, c127);
670 Value roundExp = arith::AndIOp::create(
671 b, arith::ShRUIOp::create(
b, roundBitcast, c23), expMask);
672 Value roundBiasedExp = arith::SubIOp::create(
b, roundExp, c127);
676 Value clampedShift = arith::MaxSIOp::create(
b, shift, c0);
677 clampedShift = arith::MinSIOp::create(
b, clampedShift, c31);
678 return arith::ShRUIOp::create(
b, x, clampedShift);
681 auto maskMantissa = [&](
Value mantissa,
683 Value shiftedMantissaMask = safeShiftRight(c23Mask, mantissaMaskRightShift);
684 return arith::AndIOp::create(
b, mantissa, shiftedMantissaMask);
701 Value roundBiasedExpEq0 =
702 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, roundBiasedExp, c0);
703 Value roundBiasedExpMinus1 = arith::SubIOp::create(
b, roundBiasedExp, c1);
704 Value roundMaskedMantissa = maskMantissa(roundBitcast, roundBiasedExpMinus1);
705 Value roundIsNotEvenOrSpecialVal = arith::CmpIOp::create(
706 b, arith::CmpIPredicate::ne, roundMaskedMantissa, c0);
707 roundIsNotEvenOrSpecialVal =
708 arith::OrIOp::create(
b, roundIsNotEvenOrSpecialVal, roundBiasedExpEq0);
717 Value operandBiasedExpEqNeg1 = arith::CmpIOp::create(
718 b, arith::CmpIPredicate::eq, operandBiasedExp, cNeg1);
719 Value expectedOperandMaskedMantissa = arith::SelectOp::create(
720 b, operandBiasedExpEqNeg1, c0, safeShiftRight(c2To22, operandBiasedExp));
721 Value operandMaskedMantissa = maskMantissa(operandBitcast, operandBiasedExp);
722 Value operandIsHalfway =
723 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, operandMaskedMantissa,
724 expectedOperandMaskedMantissa);
726 Value operandBiasedExpGeNeg1 = arith::CmpIOp::create(
727 b, arith::CmpIPredicate::sge, operandBiasedExp, cNeg1);
728 Value operandBiasedExpLt23 = arith::CmpIOp::create(
729 b, arith::CmpIPredicate::slt, operandBiasedExp, c23);
731 arith::AndIOp::create(
b, operandIsHalfway, operandBiasedExpLt23);
733 arith::AndIOp::create(
b, operandIsHalfway, operandBiasedExpGeNeg1);
737 Value sign = math::CopySignOp::create(
b, c1Float, operand);
738 Value roundShifted = arith::SubFOp::create(
b, round, sign);
742 arith::AndIOp::create(
b, roundIsNotEvenOrSpecialVal, operandIsHalfway);
743 Value result = arith::SelectOp::create(
b, needsShift, roundShifted, round);
755 auto operand = op.getOperand();
756 auto operandTy = operand.
getType();
762 if (!isa<FloatType>(eTy))
766 auto constOneFloat =
createFloatConst(loc, operandTy, 1.0, rewriter, operand);
767 auto sqrtOp = math::SqrtOp::create(rewriter, loc, operand);
775 auto minOp = arith::MinimumFOp::create(rewriter, op.getLoc(), op.getValue(),
776 op.getMax(), op.getFastmath());
784 auto filter = [&](StringRef name) {
788 assert(
"math" == MathDialect::getDialectNamespace());
789 name.consume_front(
"math.");
790 return opMnemonics.empty() || (llvm::count(opMnemonics, name) > 0);
792 if (filter(CountLeadingZerosOp::getOperationName()))
794 if (filter(SinhOp::getOperationName()))
796 if (filter(CoshOp::getOperationName()))
798 if (filter(TanOp::getOperationName()))
800 if (filter(TanhOp::getOperationName()))
802 if (filter(AsinhOp::getOperationName()))
804 if (filter(AcoshOp::getOperationName()))
806 if (filter(AtanhOp::getOperationName()))
808 if (filter(FmaOp::getOperationName()))
810 if (filter(CeilOp::getOperationName()))
812 if (filter(Exp2Op::getOperationName()))
814 if (filter(PowFOp::getOperationName()))
816 if (filter(FPowIOp::getOperationName()))
818 if (filter(RoundOp::getOperationName()))
820 if (filter(RoundEvenOp::getOperationName()))
822 if (filter(RsqrtOp::getOperationName()))
824 if (filter(ClampFOp::getOperationName()))
832struct MathExpandOpsPass final
834 using MathExpandOpsPassBase::MathExpandOpsPassBase;
836 void runOnOperation()
override {
839 llvm::to_vector_of<StringRef>(opMnemonics);
842 return signalPassFailure();
static const llvm::fltSemantics * getFloatSemantics(TruncfSrcElemTypes etype)
Float semantics the element type attributes of xevm.truncf and xevm.extf stand for.
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...