20#define GEN_PASS_DEF_ARITHEXPANDOPSPASS
21#include "mlir/Dialect/Arith/Transforms/Passes.h.inc"
31 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
32 return arith::ConstantOp::create(rewriter, loc,
35 return arith::ConstantOp::create(rewriter, loc, attr);
42 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
43 return arith::ConstantOp::create(rewriter, loc,
46 return arith::ConstantOp::create(rewriter, loc, attr);
53 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
54 return arith::ConstantOp::create(rewriter, loc,
58 return arith::ConstantOp::create(rewriter, loc, attr);
63 if (
auto shapedTy = dyn_cast<ShapedType>(cloneFrom)) {
64 return shapedTy.clone(cloneTo);
71template <
typename OpTy, arith::CmpIPredicate pred>
74 using OpRewritePattern<OpTy>::OpRewritePattern;
76 LogicalResult matchAndRewrite(OpTy op,
77 PatternRewriter &rewriter)
const final {
78 Value
lhs = op.getLhs();
79 Value
rhs = op.getRhs();
81 Value cmp = arith::CmpIOp::create(rewriter, op.getLoc(), pred,
lhs,
rhs);
82 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cmp,
lhs,
rhs);
87template <
typename OpTy, arith::CmpFPredicate pred>
90 using OpRewritePattern<OpTy>::OpRewritePattern;
92 LogicalResult matchAndRewrite(OpTy op,
93 PatternRewriter &rewriter)
const final {
94 Value
lhs = op.getLhs();
95 Value
rhs = op.getRhs();
97 Location loc = op.getLoc();
99 static_assert(pred == arith::CmpFPredicate::UGT ||
100 pred == arith::CmpFPredicate::ULT,
101 "pred must be either UGT or ULT");
102 Value cmp = arith::CmpFOp::create(rewriter, loc, pred,
lhs,
rhs);
103 Value select = arith::SelectOp::create(rewriter, loc, cmp,
lhs,
rhs);
106 Value isNaN = arith::CmpFOp::create(rewriter, loc,
107 arith::CmpFPredicate::UNO,
rhs,
rhs);
108 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, isNaN,
rhs, select);
113template <
typename OpTy, arith::CmpFPredicate pred>
116 using OpRewritePattern<OpTy>::OpRewritePattern;
118 LogicalResult matchAndRewrite(OpTy op,
119 PatternRewriter &rewriter)
const final {
120 Value
lhs = op.getLhs();
121 Value
rhs = op.getRhs();
123 Location loc = op.getLoc();
125 static_assert(pred == arith::CmpFPredicate::UGT ||
126 pred == arith::CmpFPredicate::ULT,
127 "pred must be either UGT or ULT");
128 Value cmp = arith::CmpFOp::create(rewriter, loc, pred,
lhs,
rhs);
129 Value select = arith::SelectOp::create(rewriter, loc, cmp,
lhs,
rhs);
132 Value isNaN = arith::CmpFOp::create(rewriter, loc,
133 arith::CmpFPredicate::UNO,
lhs,
lhs);
134 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, isNaN,
rhs, select);
141 LogicalResult matchAndRewrite(arith::ExtFOp op,
142 PatternRewriter &rewriter)
const final {
143 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
144 auto operand = op.getOperand();
145 Type operandTy = operand.getType();
146 Type resultTy = op.getType();
151 return rewriter.notifyMatchFailure(op,
"not a ext of bf16 to f32.");
157 Value bitcast = arith::BitcastOp::create(
b, i16Ty, operand);
158 Value exti = arith::ExtUIOp::create(
b, i32Ty, bitcast);
160 Value c16 =
createConst(op.getLoc(), i32Ty, 16, rewriter);
161 Value shl = arith::ShLIOp::create(
b, exti, c16);
162 Value
result = arith::BitcastOp::create(
b, resultTy, shl);
164 rewriter.replaceOp(op,
result);
169struct BFloat16TruncFOpConverter :
public OpRewritePattern<arith::TruncFOp> {
171 LogicalResult matchAndRewrite(arith::TruncFOp op,
172 PatternRewriter &rewriter)
const final {
173 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
174 auto operand = op.getOperand();
175 Type operandTy = operand.getType();
176 Type resultTy = op.getType();
181 return rewriter.notifyMatchFailure(op,
"not a trunc of f32 to bf16.");
184 if (op.getRoundingmodeAttr()) {
185 return rewriter.notifyMatchFailure(
186 op,
"only applicable to default rounding mode.");
206 arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, operand, operand);
208 Value c7FFF =
createConst(op.getLoc(), i32Ty, 0x7fff, rewriter);
210 Value c7FC0I16 =
createConst(op.getLoc(), i16Ty, 0x7fc0, rewriter);
212 Value c16 =
createConst(op.getLoc(), i32Ty, 16, rewriter);
213 Value c1 =
createConst(op.getLoc(), i32Ty, 1, rewriter);
215 Value bitcast = arith::BitcastOp::create(
b, i32Ty, operand);
218 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, bitcast, c16), c1);
221 Value roundingBias = arith::AddIOp::create(
b, bit16, c7FFF);
228 Value biased = arith::AddIOp::create(
b, bitcast, roundingBias);
231 Value biasedAndShifted = arith::ShRUIOp::create(
b, biased, c16);
232 Value normalCaseResultI16 =
233 arith::TruncIOp::create(
b, i16Ty, biasedAndShifted);
237 arith::SelectOp::create(
b, isNan, c7FC0I16, normalCaseResultI16);
239 rewriter.replaceOp(op,
result);
275 LogicalResult matchAndRewrite(arith::ExtFOp op,
279 Value operand = op.getOperand();
281 Type resultTy = op.getType();
285 if (!isa<Float4E2M1FNType>(operandETy))
286 return rewriter.notifyMatchFailure(op,
"not a ext of F4E2M1FN");
291 Value i4Bits = arith::BitcastOp::create(
b, i4Ty, operand);
299 Value i4BitsNoSign = arith::AndIOp::create(
b, i4Bits, c0x7);
303 Value bits1To24 = arith::ShLIOp::create(
b, i4BitsNoSign, c0x2);
305 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, i4BitsNoSign, c0x1);
306 bits1To24 = arith::SelectOp::create(
b, isHalf, c0x0, bits1To24);
307 bits1To24 = arith::ExtUIOp::create(
b, i32Ty, bits1To24);
308 bits1To24 = arith::ShLIOp::create(
b, bits1To24, c0x00000014);
315 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, i4BitsNoSign, c0x4);
317 arith::SelectOp::create(
b, useLargerExp, highExpBits, lowExpBits);
319 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, i4BitsNoSign, c0x0);
320 bits25To31 = arith::SelectOp::create(
b, zeroExp, zeroExpBits, bits25To31);
326 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, i4Bits, c0x8);
328 arith::SelectOp::create(
b, negative, c0x80000000, zeroExpBits);
331 Value bits1To31 = arith::AddIOp::create(
b, bits1To24, bits25To31);
332 Value bits1To32 = arith::AddIOp::create(
b, bits1To31, bit32);
333 Value result = arith::BitcastOp::create(
b, f32Ty, bits1To32);
334 if (!isa<Float32Type>(resultETy))
337 rewriter.replaceOp(op,
result);
344 LogicalResult matchAndRewrite(arith::ExtFOp op,
347 Value operand = op.getOperand();
349 Type resultTy = op.getType();
353 if (!llvm::isa<Float8E8M0FNUType>(operandETy)) {
354 return rewriter.notifyMatchFailure(op,
"not a ext of F8E8M0FNU");
361 Value bitcast = arith::BitcastOp::create(
b, i8Ty, operand);
362 Value cF32MantissaWidth =
createConst(op->getLoc(), i32Ty, 23, rewriter);
363 Value exti = arith::ExtUIOp::create(
b, i32Ty, bitcast);
364 Value f32Bits = arith::ShLIOp::create(
b, exti, cF32MantissaWidth);
368 Value cF8Min =
createConst(op.getLoc(), i8Ty, 0, rewriter);
369 Value cF32Min =
createConst(op.getLoc(), i32Ty, 0x00400000, rewriter);
371 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, bitcast, cF8Min);
372 f32Bits = arith::SelectOp::create(
b, isMin, cF32Min, f32Bits);
375 auto fastMath = op.getFastmathAttr();
376 bool NoNaN = fastMath
377 ? (fastMath.getValue() & arith::FastMathFlags::nnan) ==
378 arith::FastMathFlags::nnan
381 Value cF8NaN =
createConst(op.getLoc(), i8Ty, 0xff, rewriter);
382 Value cF32NaN =
createConst(op.getLoc(), i32Ty, 0xffffffff, rewriter);
384 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, bitcast, cF8NaN);
386 f32Bits = arith::SelectOp::create(
b, isNan, cF32NaN, f32Bits);
389 Value
result = arith::BitcastOp::create(
b, f32Ty, f32Bits);
391 result = arith::TruncFOp::create(
b, resultTy,
result,
nullptr,
392 op.getFastmathAttr());
394 result = arith::ExtFOp::create(
b, resultTy,
result, op.getFastmathAttr());
396 rewriter.replaceOp(op,
result);
431 LogicalResult matchAndRewrite(arith::TruncFOp op,
432 PatternRewriter &rewriter)
const final {
433 Location loc = op.getLoc();
434 ImplicitLocOpBuilder
b(loc, rewriter);
435 Value operand = op.getOperand();
436 Type operandTy = operand.
getType();
437 Type resultTy = op.getType();
446 if (!isa<Float4E2M1FNType>(resultETy))
447 return rewriter.notifyMatchFailure(op,
"not a trunc of F4E2M1FN");
448 if (!isa<Float32Type>(operandETy))
450 arith::ExtFOp::create(
b, f32Ty, operand, arith::FastMathFlagsAttr{});
454 Value c0x00000016 =
createConst(loc, i32Ty, 22, rewriter);
455 Value c0x00 =
createConst(loc, i8Ty, 0x00, rewriter);
456 Value c0xff =
createConst(loc, i8Ty, 0xff, rewriter);
457 Value zeroExpBits =
createConst(loc, i32Ty, 0, rewriter);
462 Value operandClamped = arith::MinNumFOp::create(
b, cHigherBound, operand);
463 operandClamped = arith::MaxNumFOp::create(
b, cLowerBound, operandClamped);
464 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, operandClamped);
467 Value cF32ExpManWidth =
createConst(loc, i32Ty, 31, rewriter);
468 Value f32Sign = arith::ShRUIOp::create(
b, f32Bits, cF32ExpManWidth);
469 Value f4Sign = arith::TruncIOp::create(
b, i4Ty, f32Sign);
470 Value f4Bits = arith::ShLIOp::create(
b, f4Sign, c0x3);
473 Value biasAdjustment =
createConst(loc, i32Ty, 0x7e, rewriter);
474 Value cF4MantissaWidth = c0x1;
475 Value cF32MantissaWidth =
createConst(loc, i32Ty, 23, rewriter);
476 Value f32SignExp = arith::ShRUIOp::create(
b, f32Bits, cF32MantissaWidth);
477 Value biasAdjustedSignExp =
478 arith::SubIOp::create(
b, f32SignExp, biasAdjustment);
479 Value f4Exp = arith::TruncIOp::create(
b, i4Ty, biasAdjustedSignExp);
480 f4Exp = arith::ShLIOp::create(
b, f4Exp, cF4MantissaWidth);
481 f4Bits = arith::AddIOp::create(
b, f4Bits, f4Exp);
484 Value cF32FirstBitMask =
createConst(loc, i32Ty, 0x400000, rewriter);
485 Value man1Bit = arith::AndIOp::create(
b, f32Bits, cF32FirstBitMask);
486 man1Bit = arith::ShRUIOp::create(
b, man1Bit, c0x00000016);
487 Value f4Man = arith::TruncIOp::create(
b, i4Ty, man1Bit);
488 f4Bits = arith::AddIOp::create(
b, f4Bits, f4Man);
491 Value cF32MantissaMask =
createConst(loc, i32Ty, 0x7fffff, rewriter);
492 Value f8Exp = arith::TruncIOp::create(
b, i8Ty, biasAdjustedSignExp);
494 arith::CmpIOp::create(
b, arith::CmpIPredicate::sle, f8Exp, c0x00);
496 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, f8Exp, c0xff);
497 Value man23Bits = arith::AndIOp::create(
b, f32Bits, cF32MantissaMask);
498 Value isNonZeroMan = arith::CmpIOp::create(
b, arith::CmpIPredicate::ugt,
499 man23Bits, zeroExpBits);
500 Value roundToHalf = arith::AndIOp::create(
b, isNegOneExp, isNonZeroMan);
502 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, f8Exp, c0x00);
503 Value subnormalF4Bits =
createConst(loc, i4Ty, 0xf, rewriter);
504 Value halfF4Bits =
createConst(loc, i4Ty, 0x0, rewriter);
506 arith::SelectOp::create(
b, isSubnormal, subnormalF4Bits, f4Bits);
507 subResult = arith::SelectOp::create(
b, roundToHalf, halfF4Bits, subResult);
508 f4Bits = arith::SelectOp::create(
b, isZeroExp, f4Bits, subResult);
511 Value cF32Last22BitMask =
createConst(loc, i32Ty, 0x3fffff, rewriter);
512 Value cRound =
createConst(loc, i32Ty, 0x200000, rewriter);
513 Value man22Bits = arith::AndIOp::create(
b, f32Bits, cF32Last22BitMask);
515 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, man22Bits, cRound);
516 shouldRound = arith::OrIOp::create(
b, shouldRound, isSubnormal);
517 Value roundedF4Bits = arith::AddIOp::create(
b, f4Bits, c0x1);
518 f4Bits = arith::SelectOp::create(
b, shouldRound, roundedF4Bits, f4Bits);
520 Value
result = arith::BitcastOp::create(
b, resultTy, f4Bits);
521 rewriter.replaceOp(op,
result);
533 LogicalResult matchAndRewrite(arith::TruncFOp op,
534 PatternRewriter &rewriter)
const final {
535 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
536 Value operand = op.getOperand();
537 Type operandTy = operand.
getType();
539 Type resultTy = op.getType();
541 if (!llvm::isa<Float8E8M0FNUType>(resultETy)) {
542 return rewriter.notifyMatchFailure(op,
"not a truncf to f8E8M0FNU");
545 if (op.getRoundingmodeAttr()) {
546 return rewriter.notifyMatchFailure(
547 op,
"only applicable to default rounding mode.");
555 operand = arith::ExtFOp::create(
b, f32Ty, operand, op.getFastmathAttr());
557 operand = arith::TruncFOp::create(
558 b, f32Ty, operand, op.getRoundingmodeAttr(), op.getFastmathAttr());
560 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, operand);
561 Value cF32MantissaWidth =
createConst(op->getLoc(), i32Ty, 23, rewriter);
562 Value f32SignExp = arith::ShRUIOp::create(
b, f32Bits, cF32MantissaWidth);
563 Value exp8Bits = arith::TruncIOp::create(
b, i8Ty, f32SignExp);
564 Value
result = arith::BitcastOp::create(
b, resultTy, exp8Bits);
565 rewriter.replaceOp(op,
result);
578 LogicalResult matchAndRewrite(arith::ExtFOp op,
579 PatternRewriter &rewriter)
const final {
580 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
581 Value operand = op.getOperand();
582 Type operandTy = operand.
getType();
583 Type resultTy = op.getType();
587 if (!llvm::isa<Float8E5M2Type>(operandETy))
588 return rewriter.notifyMatchFailure(op,
"not a ext of F8E5M2");
594 Value bitcast = arith::BitcastOp::create(
b, i8Ty, operand);
595 Value exti = arith::ExtUIOp::create(
b, i16Ty, bitcast);
596 Value c8 =
createConst(op.getLoc(), i16Ty, 8, rewriter);
597 Value f16Bits = arith::ShLIOp::create(
b, exti, c8);
598 Value f16 = arith::BitcastOp::create(
b, f16Ty, f16Bits);
601 if (!resultETy.
isF16()) {
603 result = arith::TruncFOp::create(
b, resultTy, f16,
nullptr,
604 op.getFastmathAttr());
606 result = arith::ExtFOp::create(
b, resultTy, f16, op.getFastmathAttr());
608 rewriter.replaceOp(op,
result);
622 LogicalResult matchAndRewrite(arith::TruncFOp op,
623 PatternRewriter &rewriter)
const final {
624 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
625 Value operand = op.getOperand();
626 Type operandTy = operand.
getType();
627 Type resultTy = op.getType();
631 if (!llvm::isa<Float8E5M2Type>(resultETy))
632 return rewriter.notifyMatchFailure(op,
"not a trunc to F8E5M2");
633 if (op.getRoundingmodeAttr())
634 return rewriter.notifyMatchFailure(
635 op,
"only applicable to default rounding mode.");
642 if (!operandETy.
isF16())
643 h16 = arith::TruncFOp::create(
b, f16Ty, operand,
nullptr,
644 op.getFastmathAttr());
646 Value isNan = arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, h16, h16);
647 Value h16Bits = arith::BitcastOp::create(
b, i16Ty, h16);
649 Value c7F =
createConst(op.getLoc(), i16Ty, 0x7f, rewriter);
650 Value c8 =
createConst(op.getLoc(), i16Ty, 8, rewriter);
651 Value c1 =
createConst(op.getLoc(), i16Ty, 1, rewriter);
653 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, h16Bits, c8), c1);
654 Value roundingBias = arith::AddIOp::create(
b, bit8, c7F);
655 Value biased = arith::AddIOp::create(
b, h16Bits, roundingBias);
656 Value biasedAndShifted = arith::ShRUIOp::create(
b, biased, c8);
657 Value normalCaseResult = arith::TruncIOp::create(
b, i8Ty, biasedAndShifted);
659 Value cNan =
createConst(op.getLoc(), i8Ty, 0x7e, rewriter);
660 Value select = arith::SelectOp::create(
b, isNan, cNan, normalCaseResult);
661 Value
result = arith::BitcastOp::create(
b, resultTy, select);
662 rewriter.replaceOp(op,
result);
677 LogicalResult matchAndRewrite(arith::ExtFOp op,
678 PatternRewriter &rewriter)
const final {
679 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
680 Value operand = op.getOperand();
681 Type operandTy = operand.
getType();
682 Type resultTy = op.getType();
686 if (!llvm::isa<Float8E4M3FNType>(operandETy))
687 return rewriter.notifyMatchFailure(op,
"not a ext of F8E4M3FN");
695 Value bits = arith::BitcastOp::create(
b, i8Ty, operand);
696 Value c7F8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
697 Value mag8 = arith::AndIOp::create(
b, bits, c7F8);
699 Value mag16 = arith::ExtUIOp::create(
b, i16Ty, mag8);
700 Value c7 =
createConst(op.getLoc(), i16Ty, 7, rewriter);
701 Value g16Bits = arith::ShLIOp::create(
b, mag16, c7);
702 Value g16 = arith::BitcastOp::create(
b, f16Ty, g16Bits);
703 Value gF32 = arith::ExtFOp::create(
b, f32Ty, g16, op.getFastmathAttr());
706 Value magF32 = arith::MulFOp::create(
b, gF32, c256, op.getFastmathAttr());
708 Value magI32 = arith::BitcastOp::create(
b, i32Ty, magF32);
709 Value c80I8 =
createConst(op.getLoc(), i8Ty, 0x80, rewriter);
710 Value sign8 = arith::AndIOp::create(
b, bits, c80I8);
711 Value sign32 = arith::ExtUIOp::create(
b, i32Ty, sign8);
712 Value c24 =
createConst(op.getLoc(), i32Ty, 24, rewriter);
713 Value signBit = arith::ShLIOp::create(
b, sign32, c24);
714 Value signedI32 = arith::OrIOp::create(
b, magI32, signBit);
715 Value signedF32 = arith::BitcastOp::create(
b, f32Ty, signedI32);
718 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, mag8, c7F8);
719 Value cNan32 =
createConst(op.getLoc(), i32Ty, 0x7fc00000, rewriter);
720 Value nanSigned = arith::OrIOp::create(
b, cNan32, signBit);
721 Value nanF32 = arith::BitcastOp::create(
b, f32Ty, nanSigned);
722 Value resultF32 = arith::SelectOp::create(
b, isNan, nanF32, signedF32);
725 if (!resultETy.
isF32()) {
727 result = arith::TruncFOp::create(
b, resultTy, resultF32,
nullptr,
728 op.getFastmathAttr());
731 arith::ExtFOp::create(
b, resultTy, resultF32, op.getFastmathAttr());
733 rewriter.replaceOp(op,
result);
746struct F8E4M3FNTruncFOpConverter :
public OpRewritePattern<arith::TruncFOp> {
748 LogicalResult matchAndRewrite(arith::TruncFOp op,
749 PatternRewriter &rewriter)
const final {
750 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
751 Value operand = op.getOperand();
752 Type operandTy = operand.
getType();
753 Type resultTy = op.getType();
757 if (!llvm::isa<Float8E4M3FNType>(resultETy))
758 return rewriter.notifyMatchFailure(op,
"not a trunc to F8E4M3FN");
759 if (op.getRoundingmodeAttr())
760 return rewriter.notifyMatchFailure(
761 op,
"only applicable to default rounding mode.");
770 if (!operandETy.
isF32()) {
772 f32 = arith::ExtFOp::create(
b, f32Ty, operand, op.getFastmathAttr());
774 f32 = arith::TruncFOp::create(
b, f32Ty, operand,
nullptr,
775 op.getFastmathAttr());
778 Value isNan = arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, f32, f32);
780 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, f32);
781 Value cSignMask =
createConst(op.getLoc(), i32Ty, 0x80000000, rewriter);
782 Value cAbsMask =
createConst(op.getLoc(), i32Ty, 0x7fffffff, rewriter);
783 Value signBits = arith::AndIOp::create(
b, f32Bits, cSignMask);
784 Value absBits = arith::AndIOp::create(
b, f32Bits, cAbsMask);
785 Value absF32 = arith::BitcastOp::create(
b, f32Ty, absBits);
791 arith::CmpFOp::create(
b, arith::CmpFPredicate::OGT, absF32, cOverflow);
796 absF32 = arith::MinNumFOp::create(
b, absF32, cMax);
799 Value scaled = arith::MulFOp::create(
b, absF32, cInv256,
nullptr);
800 Value h16 = arith::TruncFOp::create(
b, f16Ty, scaled,
nullptr,
801 op.getFastmathAttr());
802 Value h16Bits = arith::BitcastOp::create(
b, i16Ty, h16);
804 Value c3F =
createConst(op.getLoc(), i16Ty, 0x3f, rewriter);
805 Value c7 =
createConst(op.getLoc(), i16Ty, 7, rewriter);
806 Value c1 =
createConst(op.getLoc(), i16Ty, 1, rewriter);
808 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, h16Bits, c7), c1);
809 Value roundingBias = arith::AddIOp::create(
b, bit7, c3F);
810 Value biased = arith::AddIOp::create(
b, h16Bits, roundingBias);
811 Value shifted = arith::ShRUIOp::create(
b, biased, c7);
812 Value mag8 = arith::TruncIOp::create(
b, i8Ty, shifted);
813 Value c7F8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
814 mag8 = arith::AndIOp::create(
b, mag8, c7F8);
816 Value c24 =
createConst(op.getLoc(), i32Ty, 24, rewriter);
817 Value sign8 = arith::TruncIOp::create(
818 b, i8Ty, arith::ShRUIOp::create(
b, signBits, c24));
819 Value res8 = arith::OrIOp::create(
b, mag8, sign8);
821 Value isNanOrOverflow = arith::OrIOp::create(
b, isNan, isOverflow);
822 Value cNan8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
823 Value res = arith::SelectOp::create(
b, isNanOrOverflow, cNan8, res8);
824 Value
result = arith::BitcastOp::create(
b, resultTy, res);
825 rewriter.replaceOp(op,
result);
830struct ScalingExtFOpConverter :
public OpRewritePattern<arith::ScalingExtFOp> {
832 LogicalResult matchAndRewrite(arith::ScalingExtFOp op,
833 PatternRewriter &rewriter)
const final {
834 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
835 Value inputOperand = op.getIn();
836 Value scaleOperand = op.getScale();
837 Type scaleTy = scaleOperand.
getType();
841 scaleETy =
b.getF8E8M0Type();
843 scaleOperand = arith::TruncFOp::create(
b, scaleTy, scaleOperand,
nullptr,
844 op.getFastmathAttr());
847 if (!llvm::isa<Float8E8M0FNUType>(scaleETy)) {
848 return rewriter.notifyMatchFailure(
849 op,
"scaling_extf is using scales of type which can not be converted "
852 Type resultTy = op.getType();
856 arith::ExtFOp::create(
b, resultTy, scaleOperand, op.getFastmathAttr());
858 arith::ExtFOp::create(
b, resultTy, inputOperand, op.getFastmathAttr());
860 arith::MulFOp::create(
b, inputExt, scaleExt, op.getFastmathAttr());
861 rewriter.replaceOp(op,
result);
871struct ScalingTruncFOpConverter
874 LogicalResult matchAndRewrite(arith::ScalingTruncFOp op,
875 PatternRewriter &rewriter)
const final {
876 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
877 Value inputOperand = op.getIn();
878 Value scaleOperand = op.getScale();
879 Type scaleTy = scaleOperand.
getType();
883 scaleETy =
b.getF8E8M0Type();
885 scaleOperand = arith::TruncFOp::create(
b, scaleTy, scaleOperand,
nullptr,
886 op.getFastmathAttr());
888 if (!llvm::isa<Float8E8M0FNUType>(scaleETy)) {
889 return rewriter.notifyMatchFailure(
890 op,
"scaling_truncf is using scales type which can not be converted "
893 Type resultTy = op.getType();
894 Type inputTy = inputOperand.
getType();
898 arith::ExtFOp::create(
b, inputTy, scaleOperand, op.getFastmathAttr());
899 Value
result = arith::DivFOp::create(
b, inputOperand, scaleOperand,
900 op.getFastmathAttr());
901 Value resultCast = arith::TruncFOp::create(
902 b, resultTy,
result, op.getRoundingmodeAttr(), op.getFastmathAttr());
903 rewriter.replaceOp(op, resultCast);
924struct FlushDenormalsOpConverter
927 LogicalResult matchAndRewrite(arith::FlushDenormalsOp op,
928 PatternRewriter &rewriter)
const final {
929 Location loc = op.getLoc();
930 ImplicitLocOpBuilder
b(loc, rewriter);
931 Value operand = op.getOperand();
932 Type operandTy = operand.
getType();
935 return rewriter.notifyMatchFailure(op,
"operand is not a float type");
937 const llvm::fltSemantics &sem = floatTy.getFloatSemantics();
940 if (!llvm::APFloatBase::isIEEELikeFP(sem))
941 return rewriter.notifyMatchFailure(
942 op,
"only IEEE-like floating-point types are supported");
944 unsigned totalBits = llvm::APFloatBase::semanticsSizeInBits(sem);
945 unsigned precision = llvm::APFloatBase::semanticsPrecision(sem);
948 if (precision < 1 || precision > totalBits)
949 return rewriter.notifyMatchFailure(op,
"unexpected float semantics");
950 unsigned mantissaBits = precision - 1;
951 unsigned expBits = totalBits - 1 - mantissaBits;
952 if (expBits == 0 || mantissaBits == 0)
953 return rewriter.notifyMatchFailure(
954 op,
"degenerate float encoding has no exponent or mantissa");
958 Value bits = arith::BitcastOp::create(
b, intTy, operand);
960 APInt::getBitsSet(totalBits, mantissaBits, mantissaBits + expBits);
961 APInt clearMantissaMaskVal = ~APInt::getLowBitsSet(totalBits, mantissaBits);
962 APInt zeroVal = APInt::getZero(totalBits);
964 Value clearMantissaMask =
969 Value expField = arith::AndIOp::create(
b, bits, expMask);
971 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, expField, zero);
974 Value cleared = arith::AndIOp::create(
b, bits, clearMantissaMask);
975 Value resultBits = arith::SelectOp::create(
b, expIsZero, cleared, bits);
976 Value
result = arith::BitcastOp::create(
b, operandTy, resultBits);
978 rewriter.replaceOp(op,
result);
983struct ArithExpandOpsPass
985 using ArithExpandOpsPassBase::ArithExpandOpsPassBase;
987 void runOnOperation()
override {
991 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
992 arith::populateExpandScalingExtTruncPatterns(patterns);
994 target.addLegalDialect<arith::ArithDialect>();
995 target.addLegalDialect<vector::VectorDialect>();
1001 arith::FloorDivSIOp,
1002 arith::ScalingExtFOp,
1003 arith::ScalingTruncFOp
1013 if (includeMinMaxF) {
1014 arith::populateExpandMinMaxFPatterns(patterns);
1024 if (includeMinMaxI) {
1025 arith::populateExpandMinMaxIPatterns(patterns);
1037 arith::populateExpandBFloat16Patterns(patterns);
1039 arith::populateExpandF8E8M0Patterns(patterns);
1041 arith::populateExpandF4E2M1Patterns(patterns);
1043 arith::populateExpandF8E5M2Patterns(patterns);
1044 if (includeF8E4M3FN)
1045 arith::populateExpandF8E4M3FNPatterns(patterns);
1046 if (includeFlushDenormals) {
1047 arith::populateExpandFlushDenormalsPatterns(patterns);
1050 target.addDynamicallyLegalOp<arith::FlushDenormalsOp>(
1051 [](arith::FlushDenormalsOp op) {
1056 return !llvm::APFloatBase::isIEEELikeFP(
1057 floatTy.getFloatSemantics());
1061 target.addDynamicallyLegalOp<arith::ExtFOp>([=](arith::ExtFOp op) {
1064 bool legalTypes =
true;
1066 legalTypes &= !(inETy.
isBF16() && outETy.
isF32());
1068 legalTypes &= !llvm::isa<Float8E8M0FNUType>(inETy);
1070 legalTypes &= !llvm::isa<Float4E2M1FNType>(inETy);
1072 legalTypes &= !llvm::isa<Float8E5M2Type>(inETy);
1073 if (includeF8E4M3FN)
1074 legalTypes &= !llvm::isa<Float8E4M3FNType>(inETy);
1078 target.addDynamicallyLegalOp<arith::TruncFOp>([=](arith::TruncFOp op) {
1081 bool legalTypes =
true;
1083 legalTypes &= !(inETy.
isF32() && outETy.
isBF16());
1085 legalTypes &= !(llvm::isa<Float8E8M0FNUType>(outETy));
1087 legalTypes &= !llvm::isa<Float4E2M1FNType>(outETy);
1089 legalTypes &= !llvm::isa<Float8E5M2Type>(outETy);
1090 if (includeF8E4M3FN)
1091 legalTypes &= !llvm::isa<Float8E4M3FNType>(outETy);
1096 if (
failed(applyPartialConversion(getOperation(),
target,
1097 std::move(patterns))))
1098 signalPassFailure();
1105 patterns.
add<BFloat16ExtFOpConverter, BFloat16TruncFOpConverter>(
1110 patterns.
add<F4E2M1ExtFOpConverter, F4E2M1TruncFOpConverter>(
1115 patterns.
add<F8E5M2ExtFOpConverter, F8E5M2TruncFOpConverter>(
1120 patterns.
add<F8E4M3FNExtFOpConverter, F8E4M3FNTruncFOpConverter>(
1125 patterns.
add<F8E8M0ExtFOpConverter, F8E8M0TruncFOpConverter>(
1131 patterns.
add<ScalingExtFOpConverter, ScalingTruncFOpConverter>(
1137 patterns.
add<FlushDenormalsOpConverter>(patterns.
getContext());
1143 MaximumMinimumFOpConverter<MaximumFOp, arith::CmpFPredicate::UGT>,
1144 MaximumMinimumFOpConverter<MinimumFOp, arith::CmpFPredicate::ULT>,
1145 MaxNumMinNumFOpConverter<MaxNumFOp, arith::CmpFPredicate::UGT>,
1146 MaxNumMinNumFOpConverter<MinNumFOp, arith::CmpFPredicate::ULT>
1154 MaxMinIOpConverter<MaxSIOp, arith::CmpIPredicate::sgt>,
1155 MaxMinIOpConverter<MaxUIOp, arith::CmpIPredicate::ugt>,
1156 MaxMinIOpConverter<MinSIOp, arith::CmpIPredicate::slt>,
1157 MaxMinIOpConverter<MinUIOp, arith::CmpIPredicate::ult>
IntegerAttr getIntegerAttr(Type type, int64_t value)
FloatAttr getFloatAttr(Type type, double value)
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...
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.
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.
ArithExpandOpsPassBase Base
void populateExpandF8E4M3FNPatterns(RewritePatternSet &patterns)
Add patterns to expand Arith f8e4m3fn patterns to lower level bitcasts/shifts.
void populateExpandBFloat16Patterns(RewritePatternSet &patterns)
Add patterns to expand Arith bf16 patterns to lower level bitcasts/shifts.
void populateExpandScalingExtTruncPatterns(RewritePatternSet &patterns)
Add patterns to expand scaling ExtF/TruncF ops to equivalent arith ops.
void populateExpandF8E8M0Patterns(RewritePatternSet &patterns)
Add patterns to expand Arith f8e8m0 patterns to lower level bitcasts/shifts.
void populateCeilFloorDivExpandOpsPatterns(RewritePatternSet &patterns)
void populateExpandF4E2M1Patterns(RewritePatternSet &patterns)
Add patterns to expand Arith f4e2m1 patterns to lower level bitcasts/shifts.
void populateExpandFlushDenormalsPatterns(RewritePatternSet &patterns)
Add patterns to expand arith.flush_denormals into integer arithmetic (bitcast + bit masks + compare +...
void populateExpandMinMaxFPatterns(RewritePatternSet &patterns)
Add patterns to expand the floating-point min/max ops (arith.maximumf/ minimumf/maxnumf/minnumf) into...
void populateExpandMinMaxIPatterns(RewritePatternSet &patterns)
Add patterns to expand the signed/unsigned integer min/max ops (arith.maxsi/maxui/minsi/minui) into c...
void populateExpandMinMaxPatterns(RewritePatternSet &patterns)
Add patterns to expand both the floating-point and integer min/max ops into cmpf/cmpi + select sequen...
void populateArithExpandOpsPatterns(RewritePatternSet &patterns)
Add patterns to expand Arith ops.
void populateExpandF8E5M2Patterns(RewritePatternSet &patterns)
Add patterns to expand Arith f8e5m2 patterns to lower level bitcasts/shifts.
Include the generated interface declarations.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...