19#define GEN_PASS_DEF_ARITHEXPANDOPSPASS
20#include "mlir/Dialect/Arith/Transforms/Passes.h.inc"
30 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
31 return arith::ConstantOp::create(rewriter, loc,
34 return arith::ConstantOp::create(rewriter, loc, attr);
41 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
42 return arith::ConstantOp::create(rewriter, loc,
45 return arith::ConstantOp::create(rewriter, loc, attr);
52 if (
auto shapedTy = dyn_cast<ShapedType>(type)) {
53 return arith::ConstantOp::create(rewriter, loc,
57 return arith::ConstantOp::create(rewriter, loc, attr);
62 if (
auto shapedTy = dyn_cast<ShapedType>(cloneFrom)) {
63 return shapedTy.clone(cloneTo);
74 LogicalResult matchAndRewrite(arith::CeilDivUIOp op,
75 PatternRewriter &rewriter)
const final {
76 Location loc = op.getLoc();
77 Value a = op.getLhs();
78 Value
b = op.getRhs();
81 arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::eq, a, zero);
83 Value minusOne = arith::SubIOp::create(rewriter, loc, a, one);
84 Value quotient = arith::DivUIOp::create(rewriter, loc, minusOne,
b);
85 Value plusOne = arith::AddIOp::create(rewriter, loc, quotient, one);
86 rewriter.replaceOpWithNewOp<arith::SelectOp>(op,
compare, zero, plusOne);
100 LogicalResult matchAndRewrite(arith::CeilDivSIOp op,
101 PatternRewriter &rewriter)
const final {
102 Location loc = op.getLoc();
103 Type type = op.getType();
104 Value a = op.getLhs();
105 Value
b = op.getRhs();
110 Value quotient = arith::DivSIOp::create(rewriter, loc, a,
b);
111 Value
product = arith::MulIOp::create(rewriter, loc, quotient,
b);
112 Value notEqualDivisor = arith::CmpIOp::create(
113 rewriter, loc, arith::CmpIPredicate::ne, a,
product);
115 Value aNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
117 Value bNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
120 Value signEqual = arith::CmpIOp::create(
121 rewriter, loc, arith::CmpIPredicate::eq, aNeg, bNeg);
123 arith::AndIOp::create(rewriter, loc, notEqualDivisor, signEqual);
125 Value quotientPlusOne = arith::AddIOp::create(rewriter, loc, quotient, one);
127 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cond, quotientPlusOne,
140struct FloorDivSIOpConverter :
public OpRewritePattern<arith::FloorDivSIOp> {
142 LogicalResult matchAndRewrite(arith::FloorDivSIOp op,
143 PatternRewriter &rewriter)
const final {
144 Location loc = op.getLoc();
145 Type type = op.getType();
146 Value a = op.getLhs();
147 Value
b = op.getRhs();
149 Value quotient = arith::DivSIOp::create(rewriter, loc, a,
b);
150 Value
product = arith::MulIOp::create(rewriter, loc, quotient,
b);
151 Value notEqualDivisor = arith::CmpIOp::create(
152 rewriter, loc, arith::CmpIPredicate::ne, a,
product);
155 Value aNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
157 Value bNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
160 Value signOpposite = arith::CmpIOp::create(
161 rewriter, loc, arith::CmpIPredicate::ne, aNeg, bNeg);
163 arith::AndIOp::create(rewriter, loc, notEqualDivisor, signOpposite);
165 Value minusOne =
createConst(loc, type, -1, rewriter);
166 Value quotientMinusOne =
167 arith::AddIOp::create(rewriter, loc, quotient, minusOne);
169 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cond, quotientMinusOne,
175template <
typename OpTy, arith::CmpIPredicate pred>
178 using OpRewritePattern<OpTy>::OpRewritePattern;
180 LogicalResult matchAndRewrite(OpTy op,
181 PatternRewriter &rewriter)
const final {
182 Value
lhs = op.getLhs();
183 Value
rhs = op.getRhs();
185 Value cmp = arith::CmpIOp::create(rewriter, op.getLoc(), pred,
lhs,
rhs);
186 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cmp,
lhs,
rhs);
191template <
typename OpTy, arith::CmpFPredicate pred>
194 using OpRewritePattern<OpTy>::OpRewritePattern;
196 LogicalResult matchAndRewrite(OpTy op,
197 PatternRewriter &rewriter)
const final {
198 Value
lhs = op.getLhs();
199 Value
rhs = op.getRhs();
201 Location loc = op.getLoc();
203 static_assert(pred == arith::CmpFPredicate::UGT ||
204 pred == arith::CmpFPredicate::ULT,
205 "pred must be either UGT or ULT");
206 Value cmp = arith::CmpFOp::create(rewriter, loc, pred,
lhs,
rhs);
207 Value select = arith::SelectOp::create(rewriter, loc, cmp,
lhs,
rhs);
210 Value isNaN = arith::CmpFOp::create(rewriter, loc,
211 arith::CmpFPredicate::UNO,
rhs,
rhs);
212 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, isNaN,
rhs, select);
217template <
typename OpTy, arith::CmpFPredicate pred>
220 using OpRewritePattern<OpTy>::OpRewritePattern;
222 LogicalResult matchAndRewrite(OpTy op,
223 PatternRewriter &rewriter)
const final {
224 Value
lhs = op.getLhs();
225 Value
rhs = op.getRhs();
227 Location loc = op.getLoc();
229 static_assert(pred == arith::CmpFPredicate::UGT ||
230 pred == arith::CmpFPredicate::ULT,
231 "pred must be either UGT or ULT");
232 Value cmp = arith::CmpFOp::create(rewriter, loc, pred,
lhs,
rhs);
233 Value select = arith::SelectOp::create(rewriter, loc, cmp,
lhs,
rhs);
236 Value isNaN = arith::CmpFOp::create(rewriter, loc,
237 arith::CmpFPredicate::UNO,
lhs,
lhs);
238 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, isNaN,
rhs, select);
245 LogicalResult matchAndRewrite(arith::ExtFOp op,
246 PatternRewriter &rewriter)
const final {
247 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
248 auto operand = op.getOperand();
249 Type operandTy = operand.getType();
250 Type resultTy = op.getType();
255 return rewriter.notifyMatchFailure(op,
"not a ext of bf16 to f32.");
261 Value bitcast = arith::BitcastOp::create(
b, i16Ty, operand);
262 Value exti = arith::ExtUIOp::create(
b, i32Ty, bitcast);
264 Value c16 =
createConst(op.getLoc(), i32Ty, 16, rewriter);
265 Value shl = arith::ShLIOp::create(
b, exti, c16);
266 Value
result = arith::BitcastOp::create(
b, resultTy, shl);
268 rewriter.replaceOp(op,
result);
273struct BFloat16TruncFOpConverter :
public OpRewritePattern<arith::TruncFOp> {
275 LogicalResult matchAndRewrite(arith::TruncFOp op,
276 PatternRewriter &rewriter)
const final {
277 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
278 auto operand = op.getOperand();
279 Type operandTy = operand.getType();
280 Type resultTy = op.getType();
285 return rewriter.notifyMatchFailure(op,
"not a trunc of f32 to bf16.");
288 if (op.getRoundingmodeAttr()) {
289 return rewriter.notifyMatchFailure(
290 op,
"only applicable to default rounding mode.");
310 arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, operand, operand);
312 Value c7FFF =
createConst(op.getLoc(), i32Ty, 0x7fff, rewriter);
314 Value c7FC0I16 =
createConst(op.getLoc(), i16Ty, 0x7fc0, rewriter);
316 Value c16 =
createConst(op.getLoc(), i32Ty, 16, rewriter);
317 Value c1 =
createConst(op.getLoc(), i32Ty, 1, rewriter);
319 Value bitcast = arith::BitcastOp::create(
b, i32Ty, operand);
322 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, bitcast, c16), c1);
325 Value roundingBias = arith::AddIOp::create(
b, bit16, c7FFF);
332 Value biased = arith::AddIOp::create(
b, bitcast, roundingBias);
335 Value biasedAndShifted = arith::ShRUIOp::create(
b, biased, c16);
336 Value normalCaseResultI16 =
337 arith::TruncIOp::create(
b, i16Ty, biasedAndShifted);
341 arith::SelectOp::create(
b, isNan, c7FC0I16, normalCaseResultI16);
342 Value
result = arith::BitcastOp::create(
b, resultTy, select);
343 rewriter.replaceOp(op,
result);
379 LogicalResult matchAndRewrite(arith::ExtFOp op,
380 PatternRewriter &rewriter)
const final {
381 Location loc = op.getLoc();
382 ImplicitLocOpBuilder
b(loc, rewriter);
383 Value operand = op.getOperand();
384 Type operandTy = operand.
getType();
385 Type resultTy = op.getType();
389 if (!isa<Float4E2M1FNType>(operandETy))
390 return rewriter.notifyMatchFailure(op,
"not a ext of F4E2M1FN");
395 Value i4Bits = arith::BitcastOp::create(
b, i4Ty, operand);
397 Value c0x0 =
createConst(loc, i4Ty, 0x0, rewriter);
398 Value c0x1 =
createConst(loc, i4Ty, 0x1, rewriter);
399 Value c0x2 =
createConst(loc, i4Ty, 0x2, rewriter);
400 Value c0x4 =
createConst(loc, i4Ty, 0x4, rewriter);
401 Value c0x7 =
createConst(loc, i4Ty, 0x7, rewriter);
403 Value i4BitsNoSign = arith::AndIOp::create(
b, i4Bits, c0x7);
406 Value c0x00000014 =
createConst(loc, i32Ty, 0x14, rewriter);
407 Value bits1To24 = arith::ShLIOp::create(
b, i4BitsNoSign, c0x2);
409 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, i4BitsNoSign, c0x1);
410 bits1To24 = arith::SelectOp::create(
b, isHalf, c0x0, bits1To24);
411 bits1To24 = arith::ExtUIOp::create(
b, i32Ty, bits1To24);
412 bits1To24 = arith::ShLIOp::create(
b, bits1To24, c0x00000014);
415 Value zeroExpBits =
createConst(loc, i32Ty, 0x00000000, rewriter);
416 Value highExpBits =
createConst(loc, i32Ty, 0x40000000, rewriter);
417 Value lowExpBits =
createConst(loc, i32Ty, 0x3f000000, rewriter);
419 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, i4BitsNoSign, c0x4);
421 arith::SelectOp::create(
b, useLargerExp, highExpBits, lowExpBits);
423 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, i4BitsNoSign, c0x0);
424 bits25To31 = arith::SelectOp::create(
b, zeroExp, zeroExpBits, bits25To31);
427 Value c0x80000000 =
createConst(loc, i32Ty, 0x80000000, rewriter);
428 Value c0x8 =
createConst(loc, i4Ty, 0x8, rewriter);
430 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, i4Bits, c0x8);
432 arith::SelectOp::create(
b, negative, c0x80000000, zeroExpBits);
435 Value bits1To31 = arith::AddIOp::create(
b, bits1To24, bits25To31);
436 Value bits1To32 = arith::AddIOp::create(
b, bits1To31, bit32);
437 Value
result = arith::BitcastOp::create(
b, f32Ty, bits1To32);
438 if (!isa<Float32Type>(resultETy))
441 rewriter.replaceOp(op,
result);
448 LogicalResult matchAndRewrite(arith::ExtFOp op,
449 PatternRewriter &rewriter)
const final {
450 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
451 Value operand = op.getOperand();
452 Type operandTy = operand.
getType();
453 Type resultTy = op.getType();
457 if (!llvm::isa<Float8E8M0FNUType>(operandETy)) {
458 return rewriter.notifyMatchFailure(op,
"not a ext of F8E8M0FNU");
465 Value bitcast = arith::BitcastOp::create(
b, i8Ty, operand);
466 Value cF32MantissaWidth =
createConst(op->getLoc(), i32Ty, 23, rewriter);
467 Value exti = arith::ExtUIOp::create(
b, i32Ty, bitcast);
468 Value f32Bits = arith::ShLIOp::create(
b, exti, cF32MantissaWidth);
471 auto fastMath = op.getFastmathAttr();
472 bool NoNaN = fastMath
473 ? (fastMath.getValue() & arith::FastMathFlags::nnan) ==
474 arith::FastMathFlags::nnan
477 Value cF8NaN =
createConst(op.getLoc(), i8Ty, 0xff, rewriter);
478 Value cF32NaN =
createConst(op.getLoc(), i32Ty, 0xffffffff, rewriter);
480 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, bitcast, cF8NaN);
482 f32Bits = arith::SelectOp::create(
b, isNan, cF32NaN, f32Bits);
485 Value
result = arith::BitcastOp::create(
b, f32Ty, f32Bits);
487 result = arith::TruncFOp::create(
b, resultTy,
result,
nullptr,
488 op.getFastmathAttr());
490 result = arith::ExtFOp::create(
b, resultTy,
result, op.getFastmathAttr());
492 rewriter.replaceOp(op,
result);
527 LogicalResult matchAndRewrite(arith::TruncFOp op,
528 PatternRewriter &rewriter)
const final {
529 Location loc = op.getLoc();
530 ImplicitLocOpBuilder
b(loc, rewriter);
531 Value operand = op.getOperand();
532 Type operandTy = operand.
getType();
533 Type resultTy = op.getType();
542 if (!isa<Float4E2M1FNType>(resultETy))
543 return rewriter.notifyMatchFailure(op,
"not a trunc of F4E2M1FN");
544 if (!isa<Float32Type>(operandETy))
545 operand = arith::ExtFOp::create(
b, f32Ty, operand);
549 Value c0x00000016 =
createConst(loc, i32Ty, 22, rewriter);
550 Value c0x00 =
createConst(loc, i8Ty, 0x00, rewriter);
551 Value c0xff =
createConst(loc, i8Ty, 0xff, rewriter);
552 Value zeroExpBits =
createConst(loc, i32Ty, 0, rewriter);
557 Value operandClamped = arith::MinNumFOp::create(
b, cHigherBound, operand);
558 operandClamped = arith::MaxNumFOp::create(
b, cLowerBound, operandClamped);
559 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, operandClamped);
562 Value cF32ExpManWidth =
createConst(loc, i32Ty, 31, rewriter);
563 Value f32Sign = arith::ShRUIOp::create(
b, f32Bits, cF32ExpManWidth);
564 Value f4Sign = arith::TruncIOp::create(
b, i4Ty, f32Sign);
565 Value f4Bits = arith::ShLIOp::create(
b, f4Sign, c0x3);
568 Value biasAdjustment =
createConst(loc, i32Ty, 0x7e, rewriter);
569 Value cF4MantissaWidth = c0x1;
570 Value cF32MantissaWidth =
createConst(loc, i32Ty, 23, rewriter);
571 Value f32SignExp = arith::ShRUIOp::create(
b, f32Bits, cF32MantissaWidth);
572 Value biasAdjustedSignExp =
573 arith::SubIOp::create(
b, f32SignExp, biasAdjustment);
574 Value f4Exp = arith::TruncIOp::create(
b, i4Ty, biasAdjustedSignExp);
575 f4Exp = arith::ShLIOp::create(
b, f4Exp, cF4MantissaWidth);
576 f4Bits = arith::AddIOp::create(
b, f4Bits, f4Exp);
579 Value cF32FirstBitMask =
createConst(loc, i32Ty, 0x400000, rewriter);
580 Value man1Bit = arith::AndIOp::create(
b, f32Bits, cF32FirstBitMask);
581 man1Bit = arith::ShRUIOp::create(
b, man1Bit, c0x00000016);
582 Value f4Man = arith::TruncIOp::create(
b, i4Ty, man1Bit);
583 f4Bits = arith::AddIOp::create(
b, f4Bits, f4Man);
586 Value cF32MantissaMask =
createConst(loc, i32Ty, 0x7fffff, rewriter);
587 Value f8Exp = arith::TruncIOp::create(
b, i8Ty, biasAdjustedSignExp);
589 arith::CmpIOp::create(
b, arith::CmpIPredicate::sle, f8Exp, c0x00);
591 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, f8Exp, c0xff);
592 Value man23Bits = arith::AndIOp::create(
b, f32Bits, cF32MantissaMask);
593 Value isNonZeroMan = arith::CmpIOp::create(
b, arith::CmpIPredicate::ugt,
594 man23Bits, zeroExpBits);
595 Value roundToHalf = arith::AndIOp::create(
b, isNegOneExp, isNonZeroMan);
597 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, f8Exp, c0x00);
598 Value subnormalF4Bits =
createConst(loc, i4Ty, 0xf, rewriter);
599 Value halfF4Bits =
createConst(loc, i4Ty, 0x0, rewriter);
601 arith::SelectOp::create(
b, isSubnormal, subnormalF4Bits, f4Bits);
602 subResult = arith::SelectOp::create(
b, roundToHalf, halfF4Bits, subResult);
603 f4Bits = arith::SelectOp::create(
b, isZeroExp, f4Bits, subResult);
606 Value cF32Last22BitMask =
createConst(loc, i32Ty, 0x3fffff, rewriter);
607 Value cRound =
createConst(loc, i32Ty, 0x200000, rewriter);
608 Value man22Bits = arith::AndIOp::create(
b, f32Bits, cF32Last22BitMask);
610 arith::CmpIOp::create(
b, arith::CmpIPredicate::uge, man22Bits, cRound);
611 shouldRound = arith::OrIOp::create(
b, shouldRound, isSubnormal);
612 Value roundedF4Bits = arith::AddIOp::create(
b, f4Bits, c0x1);
613 f4Bits = arith::SelectOp::create(
b, shouldRound, roundedF4Bits, f4Bits);
615 Value
result = arith::BitcastOp::create(
b, resultTy, f4Bits);
616 rewriter.replaceOp(op,
result);
628 LogicalResult matchAndRewrite(arith::TruncFOp op,
629 PatternRewriter &rewriter)
const final {
630 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
631 Value operand = op.getOperand();
632 Type operandTy = operand.
getType();
634 Type resultTy = op.getType();
636 if (!llvm::isa<Float8E8M0FNUType>(resultETy)) {
637 return rewriter.notifyMatchFailure(op,
"not a truncf to f8E8M0FNU");
640 if (op.getRoundingmodeAttr()) {
641 return rewriter.notifyMatchFailure(
642 op,
"only applicable to default rounding mode.");
650 operand = arith::ExtFOp::create(
b, f32Ty, operand, op.getFastmathAttr());
652 operand = arith::TruncFOp::create(
653 b, f32Ty, operand, op.getRoundingmodeAttr(), op.getFastmathAttr());
655 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, operand);
656 Value cF32MantissaWidth =
createConst(op->getLoc(), i32Ty, 23, rewriter);
657 Value f32SignExp = arith::ShRUIOp::create(
b, f32Bits, cF32MantissaWidth);
658 Value exp8Bits = arith::TruncIOp::create(
b, i8Ty, f32SignExp);
659 Value
result = arith::BitcastOp::create(
b, resultTy, exp8Bits);
660 rewriter.replaceOp(op,
result);
673 LogicalResult matchAndRewrite(arith::ExtFOp op,
674 PatternRewriter &rewriter)
const final {
675 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
676 Value operand = op.getOperand();
677 Type operandTy = operand.
getType();
678 Type resultTy = op.getType();
682 if (!llvm::isa<Float8E5M2Type>(operandETy))
683 return rewriter.notifyMatchFailure(op,
"not a ext of F8E5M2");
689 Value bitcast = arith::BitcastOp::create(
b, i8Ty, operand);
690 Value exti = arith::ExtUIOp::create(
b, i16Ty, bitcast);
691 Value c8 =
createConst(op.getLoc(), i16Ty, 8, rewriter);
692 Value f16Bits = arith::ShLIOp::create(
b, exti, c8);
693 Value f16 = arith::BitcastOp::create(
b, f16Ty, f16Bits);
696 if (!resultETy.
isF16()) {
698 result = arith::TruncFOp::create(
b, resultTy, f16,
nullptr,
699 op.getFastmathAttr());
701 result = arith::ExtFOp::create(
b, resultTy, f16, op.getFastmathAttr());
703 rewriter.replaceOp(op,
result);
717 LogicalResult matchAndRewrite(arith::TruncFOp op,
718 PatternRewriter &rewriter)
const final {
719 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
720 Value operand = op.getOperand();
721 Type operandTy = operand.
getType();
722 Type resultTy = op.getType();
726 if (!llvm::isa<Float8E5M2Type>(resultETy))
727 return rewriter.notifyMatchFailure(op,
"not a trunc to F8E5M2");
728 if (op.getRoundingmodeAttr())
729 return rewriter.notifyMatchFailure(
730 op,
"only applicable to default rounding mode.");
737 if (!operandETy.
isF16())
738 h16 = arith::TruncFOp::create(
b, f16Ty, operand,
nullptr,
739 op.getFastmathAttr());
741 Value isNan = arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, h16, h16);
742 Value h16Bits = arith::BitcastOp::create(
b, i16Ty, h16);
744 Value c7F =
createConst(op.getLoc(), i16Ty, 0x7f, rewriter);
745 Value c8 =
createConst(op.getLoc(), i16Ty, 8, rewriter);
746 Value c1 =
createConst(op.getLoc(), i16Ty, 1, rewriter);
748 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, h16Bits, c8), c1);
749 Value roundingBias = arith::AddIOp::create(
b, bit8, c7F);
750 Value biased = arith::AddIOp::create(
b, h16Bits, roundingBias);
751 Value biasedAndShifted = arith::ShRUIOp::create(
b, biased, c8);
752 Value normalCaseResult = arith::TruncIOp::create(
b, i8Ty, biasedAndShifted);
754 Value cNan =
createConst(op.getLoc(), i8Ty, 0x7e, rewriter);
755 Value select = arith::SelectOp::create(
b, isNan, cNan, normalCaseResult);
756 Value
result = arith::BitcastOp::create(
b, resultTy, select);
757 rewriter.replaceOp(op,
result);
772 LogicalResult matchAndRewrite(arith::ExtFOp op,
773 PatternRewriter &rewriter)
const final {
774 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
775 Value operand = op.getOperand();
776 Type operandTy = operand.
getType();
777 Type resultTy = op.getType();
781 if (!llvm::isa<Float8E4M3FNType>(operandETy))
782 return rewriter.notifyMatchFailure(op,
"not a ext of F8E4M3FN");
790 Value bits = arith::BitcastOp::create(
b, i8Ty, operand);
791 Value c7F8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
792 Value mag8 = arith::AndIOp::create(
b, bits, c7F8);
794 Value mag16 = arith::ExtUIOp::create(
b, i16Ty, mag8);
795 Value c7 =
createConst(op.getLoc(), i16Ty, 7, rewriter);
796 Value g16Bits = arith::ShLIOp::create(
b, mag16, c7);
797 Value g16 = arith::BitcastOp::create(
b, f16Ty, g16Bits);
798 Value gF32 = arith::ExtFOp::create(
b, f32Ty, g16, op.getFastmathAttr());
801 Value magF32 = arith::MulFOp::create(
b, gF32, c256, op.getFastmathAttr());
803 Value magI32 = arith::BitcastOp::create(
b, i32Ty, magF32);
804 Value c80I8 =
createConst(op.getLoc(), i8Ty, 0x80, rewriter);
805 Value sign8 = arith::AndIOp::create(
b, bits, c80I8);
806 Value sign32 = arith::ExtUIOp::create(
b, i32Ty, sign8);
807 Value c24 =
createConst(op.getLoc(), i32Ty, 24, rewriter);
808 Value signBit = arith::ShLIOp::create(
b, sign32, c24);
809 Value signedI32 = arith::OrIOp::create(
b, magI32, signBit);
810 Value signedF32 = arith::BitcastOp::create(
b, f32Ty, signedI32);
813 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, mag8, c7F8);
814 Value cNan32 =
createConst(op.getLoc(), i32Ty, 0x7fc00000, rewriter);
815 Value nanSigned = arith::OrIOp::create(
b, cNan32, signBit);
816 Value nanF32 = arith::BitcastOp::create(
b, f32Ty, nanSigned);
817 Value resultF32 = arith::SelectOp::create(
b, isNan, nanF32, signedF32);
820 if (!resultETy.
isF32()) {
822 result = arith::TruncFOp::create(
b, resultTy, resultF32,
nullptr,
823 op.getFastmathAttr());
826 arith::ExtFOp::create(
b, resultTy, resultF32, op.getFastmathAttr());
828 rewriter.replaceOp(op,
result);
841struct F8E4M3FNTruncFOpConverter :
public OpRewritePattern<arith::TruncFOp> {
843 LogicalResult matchAndRewrite(arith::TruncFOp op,
844 PatternRewriter &rewriter)
const final {
845 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
846 Value operand = op.getOperand();
847 Type operandTy = operand.
getType();
848 Type resultTy = op.getType();
852 if (!llvm::isa<Float8E4M3FNType>(resultETy))
853 return rewriter.notifyMatchFailure(op,
"not a trunc to F8E4M3FN");
854 if (op.getRoundingmodeAttr())
855 return rewriter.notifyMatchFailure(
856 op,
"only applicable to default rounding mode.");
865 if (!operandETy.
isF32()) {
867 f32 = arith::ExtFOp::create(
b, f32Ty, operand, op.getFastmathAttr());
869 f32 = arith::TruncFOp::create(
b, f32Ty, operand,
nullptr,
870 op.getFastmathAttr());
873 Value isNan = arith::CmpFOp::create(
b, arith::CmpFPredicate::UNE, f32, f32);
875 Value f32Bits = arith::BitcastOp::create(
b, i32Ty, f32);
876 Value cSignMask =
createConst(op.getLoc(), i32Ty, 0x80000000, rewriter);
877 Value cAbsMask =
createConst(op.getLoc(), i32Ty, 0x7fffffff, rewriter);
878 Value signBits = arith::AndIOp::create(
b, f32Bits, cSignMask);
879 Value absBits = arith::AndIOp::create(
b, f32Bits, cAbsMask);
880 Value absF32 = arith::BitcastOp::create(
b, f32Ty, absBits);
886 arith::CmpFOp::create(
b, arith::CmpFPredicate::OGT, absF32, cOverflow);
891 absF32 = arith::MinNumFOp::create(
b, absF32, cMax);
894 Value scaled = arith::MulFOp::create(
b, absF32, cInv256,
nullptr);
895 Value h16 = arith::TruncFOp::create(
b, f16Ty, scaled,
nullptr,
896 op.getFastmathAttr());
897 Value h16Bits = arith::BitcastOp::create(
b, i16Ty, h16);
899 Value c3F =
createConst(op.getLoc(), i16Ty, 0x3f, rewriter);
900 Value c7 =
createConst(op.getLoc(), i16Ty, 7, rewriter);
901 Value c1 =
createConst(op.getLoc(), i16Ty, 1, rewriter);
903 arith::AndIOp::create(
b, arith::ShRUIOp::create(
b, h16Bits, c7), c1);
904 Value roundingBias = arith::AddIOp::create(
b, bit7, c3F);
905 Value biased = arith::AddIOp::create(
b, h16Bits, roundingBias);
906 Value shifted = arith::ShRUIOp::create(
b, biased, c7);
907 Value mag8 = arith::TruncIOp::create(
b, i8Ty, shifted);
908 Value c7F8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
909 mag8 = arith::AndIOp::create(
b, mag8, c7F8);
911 Value c24 =
createConst(op.getLoc(), i32Ty, 24, rewriter);
912 Value sign8 = arith::TruncIOp::create(
913 b, i8Ty, arith::ShRUIOp::create(
b, signBits, c24));
914 Value res8 = arith::OrIOp::create(
b, mag8, sign8);
916 Value isNanOrOverflow = arith::OrIOp::create(
b, isNan, isOverflow);
917 Value cNan8 =
createConst(op.getLoc(), i8Ty, 0x7f, rewriter);
918 Value res = arith::SelectOp::create(
b, isNanOrOverflow, cNan8, res8);
919 Value
result = arith::BitcastOp::create(
b, resultTy, res);
920 rewriter.replaceOp(op,
result);
925struct ScalingExtFOpConverter :
public OpRewritePattern<arith::ScalingExtFOp> {
927 LogicalResult matchAndRewrite(arith::ScalingExtFOp op,
928 PatternRewriter &rewriter)
const final {
929 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
930 Value inputOperand = op.getIn();
931 Value scaleOperand = op.getScale();
932 Type scaleTy = scaleOperand.
getType();
936 scaleETy =
b.getF8E8M0Type();
938 scaleOperand = arith::TruncFOp::create(
b, scaleTy, scaleOperand,
nullptr,
939 op.getFastmathAttr());
942 if (!llvm::isa<Float8E8M0FNUType>(scaleETy)) {
943 return rewriter.notifyMatchFailure(
944 op,
"scaling_extf is using scales of type which can not be converted "
947 Type resultTy = op.getType();
951 arith::ExtFOp::create(
b, resultTy, scaleOperand, op.getFastmathAttr());
953 arith::ExtFOp::create(
b, resultTy, inputOperand, op.getFastmathAttr());
955 arith::MulFOp::create(
b, inputExt, scaleExt, op.getFastmathAttr());
956 rewriter.replaceOp(op,
result);
966struct ScalingTruncFOpConverter
969 LogicalResult matchAndRewrite(arith::ScalingTruncFOp op,
970 PatternRewriter &rewriter)
const final {
971 ImplicitLocOpBuilder
b(op.getLoc(), rewriter);
972 Value inputOperand = op.getIn();
973 Value scaleOperand = op.getScale();
974 Type scaleTy = scaleOperand.
getType();
978 scaleETy =
b.getF8E8M0Type();
980 scaleOperand = arith::TruncFOp::create(
b, scaleTy, scaleOperand,
nullptr,
981 op.getFastmathAttr());
983 if (!llvm::isa<Float8E8M0FNUType>(scaleETy)) {
984 return rewriter.notifyMatchFailure(
985 op,
"scaling_truncf is using scales type which can not be converted "
988 Type resultTy = op.getType();
989 Type inputTy = inputOperand.
getType();
993 arith::ExtFOp::create(
b, inputTy, scaleOperand, op.getFastmathAttr());
994 Value
result = arith::DivFOp::create(
b, inputOperand, scaleOperand,
995 op.getFastmathAttr());
996 Value resultCast = arith::TruncFOp::create(
997 b, resultTy,
result, op.getRoundingmodeAttr(), op.getFastmathAttr());
998 rewriter.replaceOp(op, resultCast);
1019struct FlushDenormalsOpConverter
1022 LogicalResult matchAndRewrite(arith::FlushDenormalsOp op,
1023 PatternRewriter &rewriter)
const final {
1024 Location loc = op.getLoc();
1025 ImplicitLocOpBuilder
b(loc, rewriter);
1026 Value operand = op.getOperand();
1027 Type operandTy = operand.
getType();
1030 return rewriter.notifyMatchFailure(op,
"operand is not a float type");
1032 const llvm::fltSemantics &sem = floatTy.getFloatSemantics();
1035 if (!llvm::APFloatBase::isIEEELikeFP(sem))
1036 return rewriter.notifyMatchFailure(
1037 op,
"only IEEE-like floating-point types are supported");
1039 unsigned totalBits = llvm::APFloatBase::semanticsSizeInBits(sem);
1040 unsigned precision = llvm::APFloatBase::semanticsPrecision(sem);
1043 if (precision < 1 || precision > totalBits)
1044 return rewriter.notifyMatchFailure(op,
"unexpected float semantics");
1045 unsigned mantissaBits = precision - 1;
1046 unsigned expBits = totalBits - 1 - mantissaBits;
1047 if (expBits == 0 || mantissaBits == 0)
1048 return rewriter.notifyMatchFailure(
1049 op,
"degenerate float encoding has no exponent or mantissa");
1053 Value bits = arith::BitcastOp::create(
b, intTy, operand);
1055 APInt::getBitsSet(totalBits, mantissaBits, mantissaBits + expBits);
1056 APInt clearMantissaMaskVal = ~APInt::getLowBitsSet(totalBits, mantissaBits);
1057 APInt zeroVal = APInt::getZero(totalBits);
1059 Value clearMantissaMask =
1064 Value expField = arith::AndIOp::create(
b, bits, expMask);
1066 arith::CmpIOp::create(
b, arith::CmpIPredicate::eq, expField, zero);
1069 Value cleared = arith::AndIOp::create(
b, bits, clearMantissaMask);
1070 Value resultBits = arith::SelectOp::create(
b, expIsZero, cleared, bits);
1071 Value
result = arith::BitcastOp::create(
b, operandTy, resultBits);
1073 rewriter.replaceOp(op,
result);
1078struct ArithExpandOpsPass
1079 :
public arith::impl::ArithExpandOpsPassBase<ArithExpandOpsPass> {
1080 using ArithExpandOpsPassBase::ArithExpandOpsPassBase;
1082 void runOnOperation()
override {
1086 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
1087 arith::populateExpandScalingExtTruncPatterns(patterns);
1089 target.addLegalDialect<arith::ArithDialect>();
1090 target.addLegalDialect<vector::VectorDialect>();
1096 arith::FloorDivSIOp,
1097 arith::ScalingExtFOp,
1098 arith::ScalingTruncFOp
1108 if (includeMinMaxF) {
1109 arith::populateExpandMinMaxFPatterns(patterns);
1119 if (includeMinMaxI) {
1120 arith::populateExpandMinMaxIPatterns(patterns);
1132 arith::populateExpandBFloat16Patterns(patterns);
1134 arith::populateExpandF8E8M0Patterns(patterns);
1136 arith::populateExpandF4E2M1Patterns(patterns);
1138 arith::populateExpandF8E5M2Patterns(patterns);
1139 if (includeF8E4M3FN)
1140 arith::populateExpandF8E4M3FNPatterns(patterns);
1141 if (includeFlushDenormals) {
1142 arith::populateExpandFlushDenormalsPatterns(patterns);
1145 target.addDynamicallyLegalOp<arith::FlushDenormalsOp>(
1146 [](arith::FlushDenormalsOp op) {
1151 return !llvm::APFloatBase::isIEEELikeFP(
1152 floatTy.getFloatSemantics());
1156 target.addDynamicallyLegalOp<arith::ExtFOp>([=](arith::ExtFOp op) {
1159 bool legalTypes =
true;
1161 legalTypes &= !(inETy.
isBF16() && outETy.
isF32());
1163 legalTypes &= !llvm::isa<Float8E8M0FNUType>(inETy);
1165 legalTypes &= !llvm::isa<Float4E2M1FNType>(inETy);
1167 legalTypes &= !llvm::isa<Float8E5M2Type>(inETy);
1168 if (includeF8E4M3FN)
1169 legalTypes &= !llvm::isa<Float8E4M3FNType>(inETy);
1173 target.addDynamicallyLegalOp<arith::TruncFOp>([=](arith::TruncFOp op) {
1176 bool legalTypes =
true;
1178 legalTypes &= !(inETy.
isF32() && outETy.
isBF16());
1180 legalTypes &= !(llvm::isa<Float8E8M0FNUType>(outETy));
1182 legalTypes &= !llvm::isa<Float4E2M1FNType>(outETy);
1184 legalTypes &= !llvm::isa<Float8E5M2Type>(outETy);
1185 if (includeF8E4M3FN)
1186 legalTypes &= !llvm::isa<Float8E4M3FNType>(outETy);
1191 if (
failed(applyPartialConversion(getOperation(),
target,
1192 std::move(patterns))))
1193 signalPassFailure();
1202 .
add<CeilDivSIOpConverter, CeilDivUIOpConverter, FloorDivSIOpConverter>(
1207 patterns.
add<BFloat16ExtFOpConverter, BFloat16TruncFOpConverter>(
1212 patterns.
add<F4E2M1ExtFOpConverter, F4E2M1TruncFOpConverter>(
1217 patterns.
add<F8E5M2ExtFOpConverter, F8E5M2TruncFOpConverter>(
1222 patterns.
add<F8E4M3FNExtFOpConverter, F8E4M3FNTruncFOpConverter>(
1227 patterns.
add<F8E8M0ExtFOpConverter, F8E8M0TruncFOpConverter>(
1233 patterns.
add<ScalingExtFOpConverter, ScalingTruncFOpConverter>(
1239 patterns.
add<FlushDenormalsOpConverter>(patterns.
getContext());
1245 MaximumMinimumFOpConverter<MaximumFOp, arith::CmpFPredicate::UGT>,
1246 MaximumMinimumFOpConverter<MinimumFOp, arith::CmpFPredicate::ULT>,
1247 MaxNumMinNumFOpConverter<MaxNumFOp, arith::CmpFPredicate::UGT>,
1248 MaxNumMinNumFOpConverter<MinNumFOp, arith::CmpFPredicate::ULT>
1256 MaxMinIOpConverter<MaxSIOp, arith::CmpIPredicate::sgt>,
1257 MaxMinIOpConverter<MaxUIOp, arith::CmpIPredicate::ugt>,
1258 MaxMinIOpConverter<MinSIOp, arith::CmpIPredicate::slt>,
1259 MaxMinIOpConverter<MinUIOp, arith::CmpIPredicate::ult>
static int64_t product(ArrayRef< int64_t > vals)
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.
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.
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)
Add patterns to expand Arith ceil/floor division ops.
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.
int compare(const Fraction &x, const Fraction &y)
Three-way comparison between two fractions.
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...