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);
367 auto fastMath = op.getFastmathAttr();
368 bool NoNaN = fastMath
369 ? (fastMath.getValue() & arith::FastMathFlags::nnan) ==
370 arith::FastMathFlags::nnan
373 Value cF8NaN =
createConst(op.getLoc(), i8Ty, 0xff, rewriter);
374 Value cF32NaN =
createConst(op.getLoc(), i32Ty, 0xffffffff, rewriter);
376 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, bitcast, cF8NaN);
378 f32Bits = arith::SelectOp::create(
b, isNan, cF32NaN, f32Bits);
381 Value
result = arith::BitcastOp::create(
b, f32Ty, f32Bits);
383 result = arith::TruncFOp::create(
b, resultTy,
result,
nullptr,
384 op.getFastmathAttr());
386 result = arith::ExtFOp::create(
b, resultTy,
result, op.getFastmathAttr());
388 rewriter.replaceOp(op,
result);
423 LogicalResult matchAndRewrite(arith::TruncFOp op,
424 PatternRewriter &rewriter)
const final {
425 Location loc = op.getLoc();
426 ImplicitLocOpBuilder
b(loc, rewriter);
427 Value operand = op.getOperand();
428 Type operandTy = operand.
getType();
429 Type resultTy = op.getType();
438 if (!isa<Float4E2M1FNType>(resultETy))
439 return rewriter.notifyMatchFailure(op,
"not a trunc of F4E2M1FN");
440 if (!isa<Float32Type>(operandETy))
442 arith::ExtFOp::create(
b, f32Ty, operand, arith::FastMathFlagsAttr{});
446 Value c0x00000016 =
createConst(loc, i32Ty, 22, rewriter);
447 Value c0x00 =
createConst(loc, i8Ty, 0x00, rewriter);
448 Value c0xff =
createConst(loc, i8Ty, 0xff, rewriter);
449 Value zeroExpBits =
createConst(loc, i32Ty, 0, rewriter);
454 Value operandClamped = arith::MinNumFOp::create(
b, cHigherBound, operand);
455 operandClamped = arith::MaxNumFOp::create(
b, cLowerBound, operandClamped);
456 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, operandClamped);
459 Value cF32ExpManWidth =
createConst(loc, i32Ty, 31, rewriter);
460 Value f32Sign = arith::ShRUIOp::create(
b, f32Bits, cF32ExpManWidth);
461 Value f4Sign = arith::TruncIOp::create(
b, i4Ty, f32Sign);
462 Value f4Bits = arith::ShLIOp::create(
b, f4Sign, c0x3);
465 Value biasAdjustment =
createConst(loc, i32Ty, 0x7e, rewriter);
466 Value cF4MantissaWidth = c0x1;
467 Value cF32MantissaWidth =
createConst(loc, i32Ty, 23, rewriter);
468 Value f32SignExp = arith::ShRUIOp::create(
b, f32Bits, cF32MantissaWidth);
469 Value biasAdjustedSignExp =
470 arith::SubIOp::create(
b, f32SignExp, biasAdjustment);
471 Value f4Exp = arith::TruncIOp::create(
b, i4Ty, biasAdjustedSignExp);
472 f4Exp = arith::ShLIOp::create(
b, f4Exp, cF4MantissaWidth);
473 f4Bits = arith::AddIOp::create(
b, f4Bits, f4Exp);
476 Value cF32FirstBitMask =
createConst(loc, i32Ty, 0x400000, rewriter);
477 Value man1Bit = arith::AndIOp::create(
b, f32Bits, cF32FirstBitMask);
478 man1Bit = arith::ShRUIOp::create(
b, man1Bit, c0x00000016);
479 Value f4Man = arith::TruncIOp::create(
b, i4Ty, man1Bit);
480 f4Bits = arith::AddIOp::create(
b, f4Bits, f4Man);
483 Value cF32MantissaMask =
createConst(loc, i32Ty, 0x7fffff, rewriter);
484 Value f8Exp = arith::TruncIOp::create(
b, i8Ty, biasAdjustedSignExp);
486 arith::CmpIOp::create(
b, arith::CmpIPredicate::sle, f8Exp, c0x00);
488 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, f8Exp, c0xff);
489 Value man23Bits = arith::AndIOp::create(
b, f32Bits, cF32MantissaMask);
490 Value isNonZeroMan = arith::CmpIOp::create(
b, arith::CmpIPredicate::ugt,
491 man23Bits, zeroExpBits);
492 Value roundToHalf = arith::AndIOp::create(
b, isNegOneExp, isNonZeroMan);
494 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, f8Exp, c0x00);
495 Value subnormalF4Bits =
createConst(loc, i4Ty, 0xf, rewriter);
496 Value halfF4Bits =
createConst(loc, i4Ty, 0x0, rewriter);
498 arith::SelectOp::create(
b, isSubnormal, subnormalF4Bits, f4Bits);
499 subResult = arith::SelectOp::create(
b, roundToHalf, halfF4Bits, subResult);
500 f4Bits = arith::SelectOp::create(
b, isZeroExp, f4Bits, subResult);
503 Value cF32Last22BitMask =
createConst(loc, i32Ty, 0x3fffff, rewriter);
504 Value cRound =
createConst(loc, i32Ty, 0x200000, rewriter);
505 Value man22Bits = arith::AndIOp::create(
b, f32Bits, cF32Last22BitMask);
507 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, man22Bits, cRound);
508 shouldRound = arith::OrIOp::create(
b, shouldRound, isSubnormal);
509 Value roundedF4Bits = arith::AddIOp::create(
b, f4Bits, c0x1);
510 f4Bits = arith::SelectOp::create(
b, shouldRound, roundedF4Bits, f4Bits);
512 Value
result = arith::BitcastOp::create(
b, resultTy, f4Bits);
513 rewriter.replaceOp(op,
result);
525 LogicalResult matchAndRewrite(arith::TruncFOp op,
526 PatternRewriter &rewriter)
const final {
527 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
528 Value operand = op.getOperand();
529 Type operandTy = operand.
getType();
531 Type resultTy = op.getType();
533 if (!llvm::isa<Float8E8M0FNUType>(resultETy)) {
534 return rewriter.notifyMatchFailure(op,
"not a truncf to f8E8M0FNU");
537 if (op.getRoundingmodeAttr()) {
538 return rewriter.notifyMatchFailure(
539 op,
"only applicable to default rounding mode.");
547 operand = arith::ExtFOp::create(
b, f32Ty, operand, op.getFastmathAttr());
549 operand = arith::TruncFOp::create(
550 b, f32Ty, operand, op.getRoundingmodeAttr(), op.getFastmathAttr());
552 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, operand);
553 Value cF32MantissaWidth =
createConst(op->getLoc(), i32Ty, 23, rewriter);
554 Value f32SignExp = arith::ShRUIOp::create(
b, f32Bits, cF32MantissaWidth);
555 Value exp8Bits = arith::TruncIOp::create(
b, i8Ty, f32SignExp);
556 Value
result = arith::BitcastOp::create(
b, resultTy, exp8Bits);
557 rewriter.replaceOp(op,
result);
570 LogicalResult matchAndRewrite(arith::ExtFOp op,
571 PatternRewriter &rewriter)
const final {
572 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
573 Value operand = op.getOperand();
574 Type operandTy = operand.
getType();
575 Type resultTy = op.getType();
579 if (!llvm::isa<Float8E5M2Type>(operandETy))
580 return rewriter.notifyMatchFailure(op,
"not a ext of F8E5M2");
586 Value bitcast = arith::BitcastOp::create(
b, i8Ty, operand);
587 Value exti = arith::ExtUIOp::create(
b, i16Ty, bitcast);
588 Value c8 =
createConst(op.getLoc(), i16Ty, 8, rewriter);
589 Value f16Bits = arith::ShLIOp::create(
b, exti, c8);
590 Value f16 = arith::BitcastOp::create(
b, f16Ty, f16Bits);
593 if (!resultETy.
isF16()) {
595 result = arith::TruncFOp::create(
b, resultTy, f16,
nullptr,
596 op.getFastmathAttr());
598 result = arith::ExtFOp::create(
b, resultTy, f16, op.getFastmathAttr());
600 rewriter.replaceOp(op,
result);
614 LogicalResult matchAndRewrite(arith::TruncFOp op,
615 PatternRewriter &rewriter)
const final {
616 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
617 Value operand = op.getOperand();
618 Type operandTy = operand.
getType();
619 Type resultTy = op.getType();
623 if (!llvm::isa<Float8E5M2Type>(resultETy))
624 return rewriter.notifyMatchFailure(op,
"not a trunc to F8E5M2");
625 if (op.getRoundingmodeAttr())
626 return rewriter.notifyMatchFailure(
627 op,
"only applicable to default rounding mode.");
634 if (!operandETy.
isF16())
635 h16 = arith::TruncFOp::create(
b, f16Ty, operand,
nullptr,
636 op.getFastmathAttr());
638 Value isNan = arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, h16, h16);
639 Value h16Bits = arith::BitcastOp::create(
b, i16Ty, h16);
641 Value c7F =
createConst(op.getLoc(), i16Ty, 0x7f, rewriter);
642 Value c8 =
createConst(op.getLoc(), i16Ty, 8, rewriter);
643 Value c1 =
createConst(op.getLoc(), i16Ty, 1, rewriter);
645 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, h16Bits, c8), c1);
646 Value roundingBias = arith::AddIOp::create(
b, bit8, c7F);
647 Value biased = arith::AddIOp::create(
b, h16Bits, roundingBias);
648 Value biasedAndShifted = arith::ShRUIOp::create(
b, biased, c8);
649 Value normalCaseResult = arith::TruncIOp::create(
b, i8Ty, biasedAndShifted);
651 Value cNan =
createConst(op.getLoc(), i8Ty, 0x7e, rewriter);
652 Value select = arith::SelectOp::create(
b, isNan, cNan, normalCaseResult);
653 Value
result = arith::BitcastOp::create(
b, resultTy, select);
654 rewriter.replaceOp(op,
result);
669 LogicalResult matchAndRewrite(arith::ExtFOp op,
670 PatternRewriter &rewriter)
const final {
671 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
672 Value operand = op.getOperand();
673 Type operandTy = operand.
getType();
674 Type resultTy = op.getType();
678 if (!llvm::isa<Float8E4M3FNType>(operandETy))
679 return rewriter.notifyMatchFailure(op,
"not a ext of F8E4M3FN");
687 Value bits = arith::BitcastOp::create(
b, i8Ty, operand);
688 Value c7F8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
689 Value mag8 = arith::AndIOp::create(
b, bits, c7F8);
691 Value mag16 = arith::ExtUIOp::create(
b, i16Ty, mag8);
692 Value c7 =
createConst(op.getLoc(), i16Ty, 7, rewriter);
693 Value g16Bits = arith::ShLIOp::create(
b, mag16, c7);
694 Value g16 = arith::BitcastOp::create(
b, f16Ty, g16Bits);
695 Value gF32 = arith::ExtFOp::create(
b, f32Ty, g16, op.getFastmathAttr());
698 Value magF32 = arith::MulFOp::create(
b, gF32, c256, op.getFastmathAttr());
700 Value magI32 = arith::BitcastOp::create(
b, i32Ty, magF32);
701 Value c80I8 =
createConst(op.getLoc(), i8Ty, 0x80, rewriter);
702 Value sign8 = arith::AndIOp::create(
b, bits, c80I8);
703 Value sign32 = arith::ExtUIOp::create(
b, i32Ty, sign8);
704 Value c24 =
createConst(op.getLoc(), i32Ty, 24, rewriter);
705 Value signBit = arith::ShLIOp::create(
b, sign32, c24);
706 Value signedI32 = arith::OrIOp::create(
b, magI32, signBit);
707 Value signedF32 = arith::BitcastOp::create(
b, f32Ty, signedI32);
710 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, mag8, c7F8);
711 Value cNan32 =
createConst(op.getLoc(), i32Ty, 0x7fc00000, rewriter);
712 Value nanSigned = arith::OrIOp::create(
b, cNan32, signBit);
713 Value nanF32 = arith::BitcastOp::create(
b, f32Ty, nanSigned);
714 Value resultF32 = arith::SelectOp::create(
b, isNan, nanF32, signedF32);
717 if (!resultETy.
isF32()) {
719 result = arith::TruncFOp::create(
b, resultTy, resultF32,
nullptr,
720 op.getFastmathAttr());
723 arith::ExtFOp::create(
b, resultTy, resultF32, op.getFastmathAttr());
725 rewriter.replaceOp(op,
result);
738struct F8E4M3FNTruncFOpConverter :
public OpRewritePattern<arith::TruncFOp> {
740 LogicalResult matchAndRewrite(arith::TruncFOp op,
741 PatternRewriter &rewriter)
const final {
742 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
743 Value operand = op.getOperand();
744 Type operandTy = operand.
getType();
745 Type resultTy = op.getType();
749 if (!llvm::isa<Float8E4M3FNType>(resultETy))
750 return rewriter.notifyMatchFailure(op,
"not a trunc to F8E4M3FN");
751 if (op.getRoundingmodeAttr())
752 return rewriter.notifyMatchFailure(
753 op,
"only applicable to default rounding mode.");
762 if (!operandETy.
isF32()) {
764 f32 = arith::ExtFOp::create(
b, f32Ty, operand, op.getFastmathAttr());
766 f32 = arith::TruncFOp::create(
b, f32Ty, operand,
nullptr,
767 op.getFastmathAttr());
770 Value isNan = arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, f32, f32);
772 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, f32);
773 Value cSignMask =
createConst(op.getLoc(), i32Ty, 0x80000000, rewriter);
774 Value cAbsMask =
createConst(op.getLoc(), i32Ty, 0x7fffffff, rewriter);
775 Value signBits = arith::AndIOp::create(
b, f32Bits, cSignMask);
776 Value absBits = arith::AndIOp::create(
b, f32Bits, cAbsMask);
777 Value absF32 = arith::BitcastOp::create(
b, f32Ty, absBits);
783 arith::CmpFOp::create(
b, arith::CmpFPredicate::OGT, absF32, cOverflow);
788 absF32 = arith::MinNumFOp::create(
b, absF32, cMax);
791 Value scaled = arith::MulFOp::create(
b, absF32, cInv256,
nullptr);
792 Value h16 = arith::TruncFOp::create(
b, f16Ty, scaled,
nullptr,
793 op.getFastmathAttr());
794 Value h16Bits = arith::BitcastOp::create(
b, i16Ty, h16);
796 Value c3F =
createConst(op.getLoc(), i16Ty, 0x3f, rewriter);
797 Value c7 =
createConst(op.getLoc(), i16Ty, 7, rewriter);
798 Value c1 =
createConst(op.getLoc(), i16Ty, 1, rewriter);
800 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, h16Bits, c7), c1);
801 Value roundingBias = arith::AddIOp::create(
b, bit7, c3F);
802 Value biased = arith::AddIOp::create(
b, h16Bits, roundingBias);
803 Value shifted = arith::ShRUIOp::create(
b, biased, c7);
804 Value mag8 = arith::TruncIOp::create(
b, i8Ty, shifted);
805 Value c7F8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
806 mag8 = arith::AndIOp::create(
b, mag8, c7F8);
808 Value c24 =
createConst(op.getLoc(), i32Ty, 24, rewriter);
809 Value sign8 = arith::TruncIOp::create(
810 b, i8Ty, arith::ShRUIOp::create(
b, signBits, c24));
811 Value res8 = arith::OrIOp::create(
b, mag8, sign8);
813 Value isNanOrOverflow = arith::OrIOp::create(
b, isNan, isOverflow);
814 Value cNan8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
815 Value res = arith::SelectOp::create(
b, isNanOrOverflow, cNan8, res8);
816 Value
result = arith::BitcastOp::create(
b, resultTy, res);
817 rewriter.replaceOp(op,
result);
822struct ScalingExtFOpConverter :
public OpRewritePattern<arith::ScalingExtFOp> {
824 LogicalResult matchAndRewrite(arith::ScalingExtFOp op,
825 PatternRewriter &rewriter)
const final {
826 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
827 Value inputOperand = op.getIn();
828 Value scaleOperand = op.getScale();
829 Type scaleTy = scaleOperand.
getType();
833 scaleETy =
b.getF8E8M0Type();
835 scaleOperand = arith::TruncFOp::create(
b, scaleTy, scaleOperand,
nullptr,
836 op.getFastmathAttr());
839 if (!llvm::isa<Float8E8M0FNUType>(scaleETy)) {
840 return rewriter.notifyMatchFailure(
841 op,
"scaling_extf is using scales of type which can not be converted "
844 Type resultTy = op.getType();
848 arith::ExtFOp::create(
b, resultTy, scaleOperand, op.getFastmathAttr());
850 arith::ExtFOp::create(
b, resultTy, inputOperand, op.getFastmathAttr());
852 arith::MulFOp::create(
b, inputExt, scaleExt, op.getFastmathAttr());
853 rewriter.replaceOp(op,
result);
863struct ScalingTruncFOpConverter
866 LogicalResult matchAndRewrite(arith::ScalingTruncFOp op,
867 PatternRewriter &rewriter)
const final {
868 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
869 Value inputOperand = op.getIn();
870 Value scaleOperand = op.getScale();
871 Type scaleTy = scaleOperand.
getType();
875 scaleETy =
b.getF8E8M0Type();
877 scaleOperand = arith::TruncFOp::create(
b, scaleTy, scaleOperand,
nullptr,
878 op.getFastmathAttr());
880 if (!llvm::isa<Float8E8M0FNUType>(scaleETy)) {
881 return rewriter.notifyMatchFailure(
882 op,
"scaling_truncf is using scales type which can not be converted "
885 Type resultTy = op.getType();
886 Type inputTy = inputOperand.
getType();
890 arith::ExtFOp::create(
b, inputTy, scaleOperand, op.getFastmathAttr());
891 Value
result = arith::DivFOp::create(
b, inputOperand, scaleOperand,
892 op.getFastmathAttr());
893 Value resultCast = arith::TruncFOp::create(
894 b, resultTy,
result, op.getRoundingmodeAttr(), op.getFastmathAttr());
895 rewriter.replaceOp(op, resultCast);
916struct FlushDenormalsOpConverter
919 LogicalResult matchAndRewrite(arith::FlushDenormalsOp op,
920 PatternRewriter &rewriter)
const final {
921 Location loc = op.getLoc();
922 ImplicitLocOpBuilder
b(loc, rewriter);
923 Value operand = op.getOperand();
924 Type operandTy = operand.
getType();
927 return rewriter.notifyMatchFailure(op,
"operand is not a float type");
929 const llvm::fltSemantics &sem = floatTy.getFloatSemantics();
932 if (!llvm::APFloatBase::isIEEELikeFP(sem))
933 return rewriter.notifyMatchFailure(
934 op,
"only IEEE-like floating-point types are supported");
936 unsigned totalBits = llvm::APFloatBase::semanticsSizeInBits(sem);
937 unsigned precision = llvm::APFloatBase::semanticsPrecision(sem);
940 if (precision < 1 || precision > totalBits)
941 return rewriter.notifyMatchFailure(op,
"unexpected float semantics");
942 unsigned mantissaBits = precision - 1;
943 unsigned expBits = totalBits - 1 - mantissaBits;
944 if (expBits == 0 || mantissaBits == 0)
945 return rewriter.notifyMatchFailure(
946 op,
"degenerate float encoding has no exponent or mantissa");
950 Value bits = arith::BitcastOp::create(
b, intTy, operand);
952 APInt::getBitsSet(totalBits, mantissaBits, mantissaBits + expBits);
953 APInt clearMantissaMaskVal = ~APInt::getLowBitsSet(totalBits, mantissaBits);
954 APInt zeroVal = APInt::getZero(totalBits);
956 Value clearMantissaMask =
961 Value expField = arith::AndIOp::create(
b, bits, expMask);
963 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, expField, zero);
966 Value cleared = arith::AndIOp::create(
b, bits, clearMantissaMask);
967 Value resultBits = arith::SelectOp::create(
b, expIsZero, cleared, bits);
968 Value
result = arith::BitcastOp::create(
b, operandTy, resultBits);
970 rewriter.replaceOp(op,
result);
975struct ArithExpandOpsPass
977 using ArithExpandOpsPassBase::ArithExpandOpsPassBase;
979 void runOnOperation()
override {
983 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
984 arith::populateExpandScalingExtTruncPatterns(patterns);
986 target.addLegalDialect<arith::ArithDialect>();
987 target.addLegalDialect<vector::VectorDialect>();
994 arith::ScalingExtFOp,
995 arith::ScalingTruncFOp
1005 if (includeMinMaxF) {
1006 arith::populateExpandMinMaxFPatterns(patterns);
1016 if (includeMinMaxI) {
1017 arith::populateExpandMinMaxIPatterns(patterns);
1029 arith::populateExpandBFloat16Patterns(patterns);
1031 arith::populateExpandF8E8M0Patterns(patterns);
1033 arith::populateExpandF4E2M1Patterns(patterns);
1035 arith::populateExpandF8E5M2Patterns(patterns);
1036 if (includeF8E4M3FN)
1037 arith::populateExpandF8E4M3FNPatterns(patterns);
1038 if (includeFlushDenormals) {
1039 arith::populateExpandFlushDenormalsPatterns(patterns);
1042 target.addDynamicallyLegalOp<arith::FlushDenormalsOp>(
1043 [](arith::FlushDenormalsOp op) {
1048 return !llvm::APFloatBase::isIEEELikeFP(
1049 floatTy.getFloatSemantics());
1053 target.addDynamicallyLegalOp<arith::ExtFOp>([=](arith::ExtFOp op) {
1056 bool legalTypes =
true;
1058 legalTypes &= !(inETy.
isBF16() && outETy.
isF32());
1060 legalTypes &= !llvm::isa<Float8E8M0FNUType>(inETy);
1062 legalTypes &= !llvm::isa<Float4E2M1FNType>(inETy);
1064 legalTypes &= !llvm::isa<Float8E5M2Type>(inETy);
1065 if (includeF8E4M3FN)
1066 legalTypes &= !llvm::isa<Float8E4M3FNType>(inETy);
1070 target.addDynamicallyLegalOp<arith::TruncFOp>([=](arith::TruncFOp op) {
1073 bool legalTypes =
true;
1075 legalTypes &= !(inETy.
isF32() && outETy.
isBF16());
1077 legalTypes &= !(llvm::isa<Float8E8M0FNUType>(outETy));
1079 legalTypes &= !llvm::isa<Float4E2M1FNType>(outETy);
1081 legalTypes &= !llvm::isa<Float8E5M2Type>(outETy);
1082 if (includeF8E4M3FN)
1083 legalTypes &= !llvm::isa<Float8E4M3FNType>(outETy);
1088 if (
failed(applyPartialConversion(getOperation(),
target,
1089 std::move(patterns))))
1090 signalPassFailure();
1097 patterns.
add<BFloat16ExtFOpConverter, BFloat16TruncFOpConverter>(
1102 patterns.
add<F4E2M1ExtFOpConverter, F4E2M1TruncFOpConverter>(
1107 patterns.
add<F8E5M2ExtFOpConverter, F8E5M2TruncFOpConverter>(
1112 patterns.
add<F8E4M3FNExtFOpConverter, F8E4M3FNTruncFOpConverter>(
1117 patterns.
add<F8E8M0ExtFOpConverter, F8E8M0TruncFOpConverter>(
1123 patterns.
add<ScalingExtFOpConverter, ScalingTruncFOpConverter>(
1129 patterns.
add<FlushDenormalsOpConverter>(patterns.
getContext());
1135 MaximumMinimumFOpConverter<MaximumFOp, arith::CmpFPredicate::UGT>,
1136 MaximumMinimumFOpConverter<MinimumFOp, arith::CmpFPredicate::ULT>,
1137 MaxNumMinNumFOpConverter<MaxNumFOp, arith::CmpFPredicate::UGT>,
1138 MaxNumMinNumFOpConverter<MinNumFOp, arith::CmpFPredicate::ULT>
1146 MaxMinIOpConverter<MaxSIOp, arith::CmpIPredicate::sgt>,
1147 MaxMinIOpConverter<MaxUIOp, arith::CmpIPredicate::ugt>,
1148 MaxMinIOpConverter<MinSIOp, arith::CmpIPredicate::slt>,
1149 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...