26#include "llvm/ADT/APFloat.h"
27#include "llvm/ADT/APInt.h"
28#include "llvm/ADT/APSInt.h"
29#include "llvm/ADT/FloatingPointMode.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/SmallVector.h"
32#include "llvm/ADT/TypeSwitch.h"
39 llvm::RoundingMode::NearestTiesToEven;
48 function_ref<APInt(
const APInt &,
const APInt &)> binFn) {
49 const APInt &lhsVal = llvm::cast<IntegerAttr>(
lhs).getValue();
50 const APInt &rhsVal = llvm::cast<IntegerAttr>(
rhs).getValue();
51 APInt value = binFn(lhsVal, rhsVal);
52 return IntegerAttr::get(res.
getType(), value);
86static IntegerOverflowFlagsAttr
88 IntegerOverflowFlagsAttr val2) {
89 return IntegerOverflowFlagsAttr::get(val1.getContext(),
90 val1.getValue() & val2.getValue());
96 case arith::CmpIPredicate::eq:
97 return arith::CmpIPredicate::ne;
98 case arith::CmpIPredicate::ne:
99 return arith::CmpIPredicate::eq;
100 case arith::CmpIPredicate::slt:
101 return arith::CmpIPredicate::sge;
102 case arith::CmpIPredicate::sle:
103 return arith::CmpIPredicate::sgt;
104 case arith::CmpIPredicate::sgt:
105 return arith::CmpIPredicate::sle;
106 case arith::CmpIPredicate::sge:
107 return arith::CmpIPredicate::slt;
108 case arith::CmpIPredicate::ult:
109 return arith::CmpIPredicate::uge;
110 case arith::CmpIPredicate::ule:
111 return arith::CmpIPredicate::ugt;
112 case arith::CmpIPredicate::ugt:
113 return arith::CmpIPredicate::ule;
114 case arith::CmpIPredicate::uge:
115 return arith::CmpIPredicate::ult;
117 llvm_unreachable(
"unknown cmpi predicate kind");
126static llvm::RoundingMode
130 switch (*roundingMode) {
131 case RoundingMode::downward:
132 return llvm::RoundingMode::TowardNegative;
133 case RoundingMode::to_nearest_away:
134 return llvm::RoundingMode::NearestTiesToAway;
135 case RoundingMode::to_nearest_even:
136 return llvm::RoundingMode::NearestTiesToEven;
137 case RoundingMode::toward_zero:
138 return llvm::RoundingMode::TowardZero;
139 case RoundingMode::upward:
140 return llvm::RoundingMode::TowardPositive;
142 llvm_unreachable(
"Unhandled rounding mode");
146 return arith::CmpIPredicateAttr::get(pred.getContext(),
172 ShapedType shapedType = dyn_cast_or_null<ShapedType>(type);
176 if (!shapedType.hasStaticShape())
186 ShapedType shapedType = dyn_cast<ShapedType>(type);
189 if (!shapedType.hasStaticShape())
199#include "ArithCanonicalization.inc"
208 auto i1Type = IntegerType::get(type.
getContext(), 1);
209 if (
auto shapedType = dyn_cast<ShapedType>(type))
210 return shapedType.cloneWith(std::nullopt, i1Type);
211 if (llvm::isa<UnrankedTensorType>(type))
212 return UnrankedTensorType::get(i1Type);
220void arith::ConstantOp::getAsmResultNames(
223 if (
auto intCst = dyn_cast<IntegerAttr>(getValue())) {
224 auto intType = dyn_cast<IntegerType>(type);
227 if (intType && intType.getWidth() == 1)
228 return setNameFn(getResult(), (intCst.getInt() ?
"true" :
"false"));
231 SmallString<32> specialNameBuffer;
232 llvm::raw_svector_ostream specialName(specialNameBuffer);
233 specialName <<
'c' << intCst.getValue();
235 specialName <<
'_' << type;
236 setNameFn(getResult(), specialName.str());
238 setNameFn(getResult(),
"cst");
244LogicalResult arith::ConstantOp::verify() {
248 intType && !intType.isSignless())
249 return emitOpError(
"integer return type must be signless");
251 if (!llvm::isa<IntegerAttr, FloatAttr, ElementsAttr>(getValue())) {
253 "value must be an integer, float, or elements attribute");
259 if (isa<ScalableVectorType>(type) && !isa<SplatElementsAttr>(getValue()))
261 "initializing scalable vectors with elements attribute is not supported"
262 " unless it's a vector splat");
266bool arith::ConstantOp::isBuildableWith(Attribute value, Type type) {
268 auto typedAttr = dyn_cast<TypedAttr>(value);
269 if (!typedAttr || typedAttr.getType() != type)
273 if (!intType.isSignless())
277 return llvm::isa<IntegerAttr, FloatAttr, ElementsAttr>(value);
280ConstantOp arith::ConstantOp::materialize(OpBuilder &builder, Attribute value,
281 Type type, Location loc) {
282 if (isBuildableWith(value, type))
283 return arith::ConstantOp::create(builder, loc, cast<TypedAttr>(value));
287OpFoldResult arith::ConstantOp::fold(FoldAdaptor adaptor) {
return getValue(); }
292 arith::ConstantOp::build(builder,
result, type,
302 auto result = dyn_cast<ConstantIntOp>(builder.
create(state));
303 assert(
result &&
"builder didn't return the right type");
315 arith::ConstantOp::build(builder,
result, type,
324 auto result = dyn_cast<ConstantIntOp>(builder.
create(state));
325 assert(
result &&
"builder didn't return the right type");
336 arith::ConstantOp::build(builder,
result, type,
342 const APInt &
value) {
345 auto result = dyn_cast<ConstantIntOp>(builder.
create(state));
346 assert(
result &&
"builder didn't return the right type");
352 const APInt &
value) {
357 if (
auto constOp = dyn_cast_or_null<arith::ConstantOp>(op))
358 return constOp.getType().isSignlessInteger();
363 FloatType type,
const APFloat &
value) {
364 arith::ConstantOp::build(builder,
result, type,
371 const APFloat &
value) {
374 auto result = dyn_cast<ConstantFloatOp>(builder.
create(state));
375 assert(
result &&
"builder didn't return the right type");
381 const APFloat &
value) {
386 if (
auto constOp = dyn_cast_or_null<arith::ConstantOp>(op))
387 return llvm::isa<FloatType>(constOp.getType());
402 auto result = dyn_cast<ConstantIndexOp>(builder.
create(state));
403 assert(
result &&
"builder didn't return the right type");
413 if (
auto constOp = dyn_cast_or_null<arith::ConstantOp>(op))
414 return constOp.getType().isIndex();
422 "type doesn't have a zero representation");
424 assert(zeroAttr &&
"unsupported type for zero attribute");
425 return arith::ConstantOp::create(builder, loc, zeroAttr);
438 if (
auto sub = getLhs().getDefiningOp<SubIOp>())
439 if (getRhs() == sub.getRhs())
443 if (
auto sub = getRhs().getDefiningOp<SubIOp>())
444 if (getLhs() == sub.getRhs())
448 adaptor.getOperands(),
449 [](APInt a,
const APInt &
b) { return std::move(a) + b; });
454 patterns.
add<AddIAddConstant, AddISubConstantRHS, AddISubConstantLHS,
455 AddIMulNegativeOneRhs, AddIMulNegativeOneLhs>(context);
462std::optional<SmallVector<int64_t, 4>>
463arith::AddUIExtendedOp::getShapeForUnroll() {
464 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
465 return llvm::to_vector<4>(vt.getShape());
472 return sum.ult(operand) ? APInt::getAllOnes(1) : APInt::getZero(1);
476arith::AddUIExtendedOp::fold(FoldAdaptor adaptor,
477 SmallVectorImpl<OpFoldResult> &results) {
478 Type overflowTy = getOverflow().getType();
484 results.push_back(getLhs());
485 results.push_back(falseValue);
494 adaptor.getOperands(),
495 [](APInt a,
const APInt &
b) { return std::move(a) + b; })) {
498 results.push_back(sumAttr);
499 results.push_back(sumAttr);
503 ArrayRef({sumAttr, adaptor.getLhs()}),
509 results.push_back(sumAttr);
510 results.push_back(overflowAttr);
517void arith::AddUIExtendedOp::getCanonicalizationPatterns(
518 RewritePatternSet &patterns, MLIRContext *context) {
519 patterns.
add<AddUIExtendedToAddI>(context);
526std::optional<SmallVector<int64_t, 4>>
527arith::SubUIExtendedOp::getShapeForUnroll() {
528 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
529 return llvm::to_vector<4>(vt.getShape());
536 return lhs.ult(
rhs) ? APInt::getAllOnes(1) : APInt::getZero(1);
540arith::SubUIExtendedOp::fold(FoldAdaptor adaptor,
541 SmallVectorImpl<OpFoldResult> &results) {
542 Type borrowTy = getBorrow().getType();
548 results.push_back(getLhs());
549 results.push_back(falseValue);
554 if (getLhs() == getRhs()) {
557 auto shapedType = dyn_cast<ShapedType>(getDiff().
getType());
558 if (shapedType && !shapedType.hasStaticShape())
566 results.push_back(zeroDiff);
567 results.push_back(falseValue);
573 adaptor.getOperands(),
574 [](APInt a,
const APInt &
b) { return std::move(a) - b; })) {
577 results.push_back(diffAttr);
578 results.push_back(diffAttr);
582 adaptor.getOperands(),
588 results.push_back(diffAttr);
589 results.push_back(borrowAttr);
596void arith::SubUIExtendedOp::getCanonicalizationPatterns(
597 RewritePatternSet &patterns, MLIRContext *context) {
598 patterns.
add<SubUIExtendedToSubI>(context);
605OpFoldResult arith::SubIOp::fold(FoldAdaptor adaptor) {
607 if (getOperand(0) == getOperand(1)) {
608 auto shapedType = dyn_cast<ShapedType>(
getType());
610 if (!shapedType || shapedType.hasStaticShape())
617 if (
auto add = getLhs().getDefiningOp<AddIOp>()) {
619 if (getRhs() ==
add.getRhs())
622 if (getRhs() ==
add.getLhs())
627 if (
auto sub = getRhs().getDefiningOp<SubIOp>())
628 if (getLhs() == sub.getLhs())
632 adaptor.getOperands(),
633 [](APInt a,
const APInt &
b) { return std::move(a) - b; });
636void arith::SubIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
637 MLIRContext *context) {
638 patterns.
add<SubIRHSAddConstant, SubILHSAddConstant, SubIRHSSubConstantRHS,
639 SubIRHSSubConstantLHS, SubILHSSubConstantRHS,
640 SubILHSSubConstantLHS, SubISubILHSRHSLHS>(context);
647OpFoldResult arith::MulIOp::fold(FoldAdaptor adaptor) {
658 adaptor.getOperands(),
659 [](
const APInt &a,
const APInt &
b) { return a * b; });
662void arith::MulIOp::getAsmResultNames(
664 if (!isa<IndexType>(
getType()))
669 auto isVscale = [](Operation *op) {
670 return op && op->getName().getStringRef() ==
"vector.vscale";
673 IntegerAttr baseValue;
674 auto isVscaleExpr = [&](Value a, Value
b) {
676 isVscale(
b.getDefiningOp());
679 if (!isVscaleExpr(getLhs(), getRhs()) && !isVscaleExpr(getRhs(), getLhs()))
683 SmallString<32> specialNameBuffer;
684 llvm::raw_svector_ostream specialName(specialNameBuffer);
685 specialName <<
'c' << baseValue.getInt() <<
"_vscale";
686 setNameFn(getResult(), specialName.str());
689void arith::MulIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
690 MLIRContext *context) {
691 patterns.
add<MulIMulIConstant>(context);
698std::optional<SmallVector<int64_t, 4>>
699arith::MulSIExtendedOp::getShapeForUnroll() {
700 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
701 return llvm::to_vector<4>(vt.getShape());
706arith::MulSIExtendedOp::fold(FoldAdaptor adaptor,
707 SmallVectorImpl<OpFoldResult> &results) {
710 Attribute zero = adaptor.getRhs();
711 results.push_back(zero);
712 results.push_back(zero);
718 adaptor.getOperands(),
719 [](
const APInt &a,
const APInt &
b) { return a * b; })) {
722 llvm::APIntOps::mulhs);
723 assert(highAttr &&
"Unexpected constant-folding failure");
725 results.push_back(lowAttr);
726 results.push_back(highAttr);
733void arith::MulSIExtendedOp::getCanonicalizationPatterns(
734 RewritePatternSet &patterns, MLIRContext *context) {
735 patterns.
add<MulSIExtendedToMulI, MulSIExtendedRHSOne>(context);
742std::optional<SmallVector<int64_t, 4>>
743arith::MulUIExtendedOp::getShapeForUnroll() {
744 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
745 return llvm::to_vector<4>(vt.getShape());
750arith::MulUIExtendedOp::fold(FoldAdaptor adaptor,
751 SmallVectorImpl<OpFoldResult> &results) {
754 Attribute zero = adaptor.getRhs();
755 results.push_back(zero);
756 results.push_back(zero);
764 results.push_back(getLhs());
765 results.push_back(zero);
771 adaptor.getOperands(),
772 [](
const APInt &a,
const APInt &
b) { return a * b; })) {
775 llvm::APIntOps::mulhu);
776 assert(highAttr &&
"Unexpected constant-folding failure");
778 results.push_back(lowAttr);
779 results.push_back(highAttr);
786void arith::MulUIExtendedOp::getCanonicalizationPatterns(
787 RewritePatternSet &patterns, MLIRContext *context) {
788 patterns.
add<MulUIExtendedToMulI>(context);
797 arith::IntegerOverflowFlags ovfFlags) {
798 auto mul =
lhs.getDefiningOp<mlir::arith::MulIOp>();
799 if (!
mul || !bitEnumContainsAll(
mul.getOverflowFlags(), ovfFlags))
811OpFoldResult arith::DivUIOp::fold(FoldAdaptor adaptor) {
825 if (getLhs() == getRhs())
829 if (Value val =
foldDivMul(getLhs(), getRhs(), IntegerOverflowFlags::nuw))
835 [&](APInt a,
const APInt &
b) {
843 return div0 ? Attribute() :
result;
863OpFoldResult arith::DivSIOp::fold(FoldAdaptor adaptor) {
877 if (getLhs() == getRhs())
881 if (Value val =
foldDivMul(getLhs(), getRhs(), IntegerOverflowFlags::nsw))
885 bool overflowOrDiv0 =
false;
887 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
888 if (overflowOrDiv0 || !b) {
889 overflowOrDiv0 = true;
892 return a.sdiv_ov(
b, overflowOrDiv0);
895 return overflowOrDiv0 ? Attribute() :
result;
922 APInt one(a.getBitWidth(), 1,
true);
923 APInt val = a.ssub_ov(one, overflow).sdiv_ov(
b, overflow);
924 return val.sadd_ov(one, overflow);
931OpFoldResult arith::CeilDivUIOp::fold(FoldAdaptor adaptor) {
945 if (getLhs() == getRhs())
948 bool overflowOrDiv0 =
false;
950 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
951 if (overflowOrDiv0 || !b) {
952 overflowOrDiv0 = true;
955 APInt quotient = a.udiv(
b);
958 APInt one(a.getBitWidth(), 1,
true);
959 return quotient.uadd_ov(one, overflowOrDiv0);
962 return overflowOrDiv0 ? Attribute() :
result;
973OpFoldResult arith::CeilDivSIOp::fold(FoldAdaptor adaptor) {
987 if (getLhs() == getRhs())
993 bool overflowOrDiv0 =
false;
995 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
996 if (overflowOrDiv0 || !b) {
997 overflowOrDiv0 = true;
1003 unsigned bits = a.getBitWidth();
1004 APInt zero = APInt::getZero(bits);
1005 bool aGtZero = a.sgt(zero);
1006 bool bGtZero =
b.sgt(zero);
1007 if (aGtZero && bGtZero) {
1014 bool overflowNegA =
false;
1015 bool overflowNegB =
false;
1016 bool overflowDiv =
false;
1017 bool overflowNegRes =
false;
1018 if (!aGtZero && !bGtZero) {
1020 APInt posA = zero.ssub_ov(a, overflowNegA);
1021 APInt posB = zero.ssub_ov(
b, overflowNegB);
1023 overflowOrDiv0 = (overflowNegA || overflowNegB || overflowDiv);
1026 if (!aGtZero && bGtZero) {
1028 APInt posA = zero.ssub_ov(a, overflowNegA);
1029 APInt
div = posA.sdiv_ov(
b, overflowDiv);
1030 APInt res = zero.ssub_ov(
div, overflowNegRes);
1031 overflowOrDiv0 = (overflowNegA || overflowDiv || overflowNegRes);
1035 APInt posB = zero.ssub_ov(
b, overflowNegB);
1036 APInt
div = a.sdiv_ov(posB, overflowDiv);
1037 APInt res = zero.ssub_ov(
div, overflowNegRes);
1039 overflowOrDiv0 = (overflowNegB || overflowDiv || overflowNegRes);
1043 return overflowOrDiv0 ? Attribute() :
result;
1054OpFoldResult arith::FloorDivSIOp::fold(FoldAdaptor adaptor) {
1068 if (getLhs() == getRhs())
1072 bool overflowOrDiv =
false;
1074 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
1076 overflowOrDiv = true;
1079 return a.sfloordiv_ov(
b, overflowOrDiv);
1082 return overflowOrDiv ? Attribute() :
result;
1089OpFoldResult arith::RemUIOp::fold(FoldAdaptor adaptor) {
1106 [&](APInt a,
const APInt &
b) {
1107 if (div0 || b.isZero()) {
1114 return div0 ? Attribute() :
result;
1125OpFoldResult arith::RemSIOp::fold(FoldAdaptor adaptor) {
1142 [&](APInt a,
const APInt &
b) {
1143 if (div0 || b.isZero()) {
1150 return div0 ? Attribute() :
result;
1168 for (
bool reversePrev : {
false,
true}) {
1169 auto prev = (reversePrev ? op.getRhs() : op.getLhs())
1170 .getDefiningOp<arith::AndIOp>();
1174 Value other = (reversePrev ? op.getLhs() : op.getRhs());
1175 if (other != prev.getLhs() && other != prev.getRhs())
1178 return prev.getResult();
1183OpFoldResult arith::AndIOp::fold(FoldAdaptor adaptor) {
1190 intValue.isAllOnes())
1195 intValue.isAllOnes())
1200 intValue.isAllOnes())
1208 adaptor.getOperands(),
1209 [](APInt a,
const APInt &
b) { return std::move(a) & b; });
1216OpFoldResult arith::OrIOp::fold(FoldAdaptor adaptor) {
1219 if (rhsVal.isZero())
1222 if (rhsVal.isAllOnes())
1223 return adaptor.getRhs();
1230 intValue.isAllOnes())
1231 return getRhs().getDefiningOp<XOrIOp>().getRhs();
1235 intValue.isAllOnes())
1236 return getLhs().getDefiningOp<XOrIOp>().getRhs();
1239 adaptor.getOperands(),
1240 [](APInt a,
const APInt &
b) { return std::move(a) | b; });
1247OpFoldResult arith::XOrIOp::fold(FoldAdaptor adaptor) {
1252 if (getLhs() == getRhs()) {
1255 auto shapedType = dyn_cast<ShapedType>(
getType());
1256 if (!shapedType || shapedType.hasStaticShape())
1261 if (arith::XOrIOp prev = getLhs().getDefiningOp<arith::XOrIOp>()) {
1262 if (prev.getRhs() == getRhs())
1263 return prev.getLhs();
1264 if (prev.getLhs() == getRhs())
1265 return prev.getRhs();
1269 if (arith::XOrIOp prev = getRhs().getDefiningOp<arith::XOrIOp>()) {
1270 if (prev.getRhs() == getLhs())
1271 return prev.getLhs();
1272 if (prev.getLhs() == getLhs())
1273 return prev.getRhs();
1277 adaptor.getOperands(),
1278 [](APInt a,
const APInt &
b) { return std::move(a) ^ b; });
1281void arith::XOrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1282 MLIRContext *context) {
1283 patterns.
add<XOrIXOrIConstant, XOrINotCmpI, XOrIOfExtUI, XOrIOfExtSI>(
1291OpFoldResult arith::NegFOp::fold(FoldAdaptor adaptor) {
1293 if (
auto op = this->getOperand().getDefiningOp<arith::NegFOp>())
1294 return op.getOperand();
1296 [](
const APFloat &a) { return -a; });
1303OpFoldResult arith::FlushDenormalsOp::fold(FoldAdaptor adaptor) {
1309 if (
auto op = this->getOperand().getDefiningOp<arith::FlushDenormalsOp>())
1310 return op.getResult();
1314 adaptor.getOperands(), [](
const APFloat &a) {
1316 return APFloat::getZero(a.getSemantics(), a.isNegative());
1325OpFoldResult arith::AddFOp::fold(FoldAdaptor adaptor) {
1330 auto rm = getRoundingmode();
1332 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1334 result.add(b, convertArithRoundingModeToLLVMIR(rm));
1339void arith::AddFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1340 MLIRContext *context) {
1341 patterns.
add<AddFOfNegFLhs, AddFOfNegFRhs>(context);
1348OpFoldResult arith::SubFOp::fold(FoldAdaptor adaptor) {
1353 auto rm = getRoundingmode();
1355 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1357 result.subtract(b, convertArithRoundingModeToLLVMIR(rm));
1362void arith::SubFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1363 MLIRContext *context) {
1364 patterns.
add<SubFOfNegZero>(context);
1371OpFoldResult arith::MaximumFOp::fold(FoldAdaptor adaptor) {
1373 if (getLhs() == getRhs())
1387OpFoldResult arith::MaxNumFOp::fold(FoldAdaptor adaptor) {
1389 if (getLhs() == getRhs())
1403OpFoldResult MaxSIOp::fold(FoldAdaptor adaptor) {
1405 if (getLhs() == getRhs())
1411 if (intValue.isMaxSignedValue())
1414 if (intValue.isMinSignedValue())
1419 llvm::APIntOps::smax);
1426OpFoldResult MaxUIOp::fold(FoldAdaptor adaptor) {
1428 if (getLhs() == getRhs())
1434 if (intValue.isMaxValue())
1437 if (intValue.isMinValue())
1442 llvm::APIntOps::umax);
1449OpFoldResult arith::MinimumFOp::fold(FoldAdaptor adaptor) {
1451 if (getLhs() == getRhs())
1465OpFoldResult arith::MinNumFOp::fold(FoldAdaptor adaptor) {
1467 if (getLhs() == getRhs())
1481OpFoldResult MinSIOp::fold(FoldAdaptor adaptor) {
1483 if (getLhs() == getRhs())
1489 if (intValue.isMinSignedValue())
1492 if (intValue.isMaxSignedValue())
1497 llvm::APIntOps::smin);
1504OpFoldResult MinUIOp::fold(FoldAdaptor adaptor) {
1506 if (getLhs() == getRhs())
1512 if (intValue.isMinValue())
1515 if (intValue.isMaxValue())
1520 llvm::APIntOps::umin);
1527OpFoldResult arith::MulFOp::fold(FoldAdaptor adaptor) {
1532 if (arith::bitEnumContainsAll(getFastmath(), arith::FastMathFlags::nnan |
1533 arith::FastMathFlags::nsz)) {
1539 auto rm = getRoundingmode();
1541 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1543 result.multiply(b, convertArithRoundingModeToLLVMIR(rm));
1548void arith::MulFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1549 MLIRContext *context) {
1550 patterns.
add<MulFOfNegF>(context);
1557OpFoldResult arith::DivFOp::fold(FoldAdaptor adaptor) {
1562 auto rm = getRoundingmode();
1564 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1566 result.divide(b, convertArithRoundingModeToLLVMIR(rm));
1571void arith::DivFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1572 MLIRContext *context) {
1573 patterns.
add<DivFOfNegF>(context);
1580OpFoldResult arith::RemFOp::fold(FoldAdaptor adaptor) {
1582 [](
const APFloat &a,
const APFloat &
b) {
1587 (void)result.mod(b);
1596template <
typename... Types>
1602template <
typename... ShapedTypes,
typename... ElementTypes>
1605 if (llvm::isa<ShapedType>(type) && !llvm::isa<ShapedTypes...>(type))
1609 if (!llvm::isa<ElementTypes...>(underlyingType))
1612 return underlyingType;
1616template <
typename... ElementTypes>
1623template <
typename... ElementTypes>
1632 auto rankedTensorA = dyn_cast<RankedTensorType>(typeA);
1633 auto rankedTensorB = dyn_cast<RankedTensorType>(typeB);
1634 if (!rankedTensorA || !rankedTensorB)
1636 return rankedTensorA.getEncoding() == rankedTensorB.getEncoding();
1640 if (inputs.size() != 1 || outputs.size() != 1)
1652template <
typename ValType,
typename Op>
1657 if (llvm::cast<ValType>(srcType).getWidth() >=
1658 llvm::cast<ValType>(dstType).getWidth())
1660 << dstType <<
" must be wider than operand type " << srcType;
1666template <
typename ValType,
typename Op>
1671 if (llvm::cast<ValType>(srcType).getWidth() <=
1672 llvm::cast<ValType>(dstType).getWidth())
1674 << dstType <<
" must be shorter than operand type " << srcType;
1680template <
template <
typename>
class WidthComparator,
typename... ElementTypes>
1685 auto srcType =
getTypeIfLike<ElementTypes...>(inputs.front());
1686 auto dstType =
getTypeIfLike<ElementTypes...>(outputs.front());
1687 if (!srcType || !dstType)
1690 return WidthComparator<unsigned>()(dstType.getIntOrFloatBitWidth(),
1691 srcType.getIntOrFloatBitWidth());
1696static FailureOr<APFloat>
1698 const llvm::fltSemantics &targetSemantics,
1702 using fltNonfiniteBehavior = llvm::fltNonfiniteBehavior;
1703 if (sourceValue.isInfinity() &&
1704 (targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
1705 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly))
1707 if (sourceValue.isNaN() &&
1708 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
1711 bool losesInfo =
false;
1712 auto status = sourceValue.convert(targetSemantics, roundingMode, &losesInfo);
1713 if (losesInfo || status != APFloat::opOK)
1723OpFoldResult arith::ExtUIOp::fold(FoldAdaptor adaptor) {
1724 if (
auto lhs = getIn().getDefiningOp<ExtUIOp>()) {
1725 getInMutable().assign(
lhs.getIn());
1730 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1732 adaptor.getOperands(),
getType(),
1733 [bitWidth](
const APInt &a,
bool &castStatus) {
1734 return a.zext(bitWidth);
1742LogicalResult arith::ExtUIOp::verify() {
1750OpFoldResult arith::ExtSIOp::fold(FoldAdaptor adaptor) {
1751 if (
auto lhs = getIn().getDefiningOp<ExtSIOp>()) {
1752 getInMutable().assign(
lhs.getIn());
1757 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1759 adaptor.getOperands(),
getType(),
1760 [bitWidth](
const APInt &a,
bool &castStatus) {
1761 return a.sext(bitWidth);
1769void arith::ExtSIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1770 MLIRContext *context) {
1771 patterns.
add<ExtSIOfExtUI>(context);
1774LogicalResult arith::ExtSIOp::verify() {
1784OpFoldResult arith::ExtFOp::fold(FoldAdaptor adaptor) {
1785 if (
auto truncFOp = getOperand().getDefiningOp<TruncFOp>()) {
1786 if (truncFOp.getOperand().getType() ==
getType()) {
1787 arith::FastMathFlags truncFMF =
1788 truncFOp.getFastmath().value_or(arith::FastMathFlags::none);
1789 bool isTruncContract =
1790 bitEnumContainsAll(truncFMF, arith::FastMathFlags::contract);
1791 arith::FastMathFlags extFMF =
1792 getFastmath().value_or(arith::FastMathFlags::none);
1793 bool isExtContract =
1794 bitEnumContainsAll(extFMF, arith::FastMathFlags::contract);
1795 if (isTruncContract && isExtContract) {
1796 return truncFOp.getOperand();
1802 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
1804 adaptor.getOperands(),
getType(),
1805 [&targetSemantics](
const APFloat &a,
bool &castStatus) {
1825bool arith::ScalingExtFOp::areCastCompatible(
TypeRange inputs,
1830LogicalResult arith::ScalingExtFOp::verify() {
1838OpFoldResult arith::TruncIOp::fold(FoldAdaptor adaptor) {
1841 Value src = getOperand().getDefiningOp()->getOperand(0);
1846 if (llvm::cast<IntegerType>(srcType).getWidth() >
1847 llvm::cast<IntegerType>(dstType).getWidth()) {
1854 if (srcType == dstType)
1860 setOperand(getOperand().getDefiningOp()->getOperand(0));
1865 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1867 adaptor.getOperands(),
getType(),
1868 [bitWidth](
const APInt &a,
bool &castStatus) {
1869 return a.trunc(bitWidth);
1877void arith::TruncIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1878 MLIRContext *context) {
1880 .
add<TruncIExtSIToExtSI, TruncIExtUIToExtUI, TruncIShrSIToTrunciShrUI>(
1884LogicalResult arith::TruncIOp::verify() {
1894OpFoldResult arith::TruncFOp::fold(FoldAdaptor adaptor) {
1896 if (
auto extOp = getOperand().getDefiningOp<arith::ExtFOp>()) {
1897 Value src = extOp.getIn();
1899 auto intermediateType =
1902 if (llvm::APFloatBase::isRepresentableBy(
1903 srcType.getFloatSemantics(),
1904 intermediateType.getFloatSemantics())) {
1906 if (srcType.getWidth() > resElemType.getWidth()) {
1912 if (srcType == resElemType)
1917 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
1919 adaptor.getOperands(),
getType(),
1920 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
1921 llvm::RoundingMode llvmRoundingMode =
1923 FailureOr<APFloat>
result =
1933void arith::TruncFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1934 MLIRContext *context) {
1935 patterns.
add<TruncFSIToFPToSIToFP, TruncFUIToFPToUIToFP>(context);
1942LogicalResult arith::TruncFOp::verify() {
1950OpFoldResult arith::ConvertFOp::fold(FoldAdaptor adaptor) {
1952 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
1954 adaptor.getOperands(),
getType(),
1955 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
1956 llvm::RoundingMode llvmRoundingMode =
1958 FailureOr<APFloat>
result =
1973 if (!srcType || !dstType)
1975 return srcType != dstType &&
1979LogicalResult arith::ConvertFOp::verify() {
1982 if (srcType == dstType)
1983 return emitError(
"result element type ")
1984 << dstType <<
" must be different from operand element type "
1986 if (srcType.getWidth() != dstType.getWidth())
1987 return emitError(
"result element type ")
1988 << dstType <<
" must have the same bitwidth as operand element type "
1997bool arith::ScalingTruncFOp::areCastCompatible(
TypeRange inputs,
2002LogicalResult arith::ScalingTruncFOp::verify() {
2010void arith::AndIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2011 MLIRContext *context) {
2012 patterns.
add<AndIAndIConstant, AndOfExtUI, AndOfExtSI>(context);
2019void arith::OrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2020 MLIRContext *context) {
2021 patterns.
add<OrIOrIConstant, OrOfExtUI, OrOfExtSI>(context);
2028template <
typename From,
typename To>
2036 return srcType && dstType;
2047OpFoldResult arith::UIToFPOp::fold(FoldAdaptor adaptor) {
2050 adaptor.getOperands(),
getType(),
2051 [&resEleType](
const APInt &a,
bool &castStatus) {
2052 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2053 APFloat apf(floatTy.getFloatSemantics(),
2054 APInt::getZero(floatTy.getWidth()));
2055 apf.convertFromAPInt(a,
false,
2056 APFloat::rmNearestTiesToEven);
2061void arith::UIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2062 MLIRContext *context) {
2063 patterns.
add<UIToFPOfExtUI>(context);
2074OpFoldResult arith::SIToFPOp::fold(FoldAdaptor adaptor) {
2077 adaptor.getOperands(),
getType(),
2078 [&resEleType](
const APInt &a,
bool &castStatus) {
2079 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2080 APFloat apf(floatTy.getFloatSemantics(),
2081 APInt::getZero(floatTy.getWidth()));
2082 apf.convertFromAPInt(a,
true,
2083 APFloat::rmNearestTiesToEven);
2088void arith::SIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2089 MLIRContext *context) {
2090 patterns.
add<SIToFPOfExtSI, SIToFPOfExtUI>(context);
2101OpFoldResult arith::FPToUIOp::fold(FoldAdaptor adaptor) {
2103 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2105 adaptor.getOperands(),
getType(),
2106 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2108 APSInt api(bitWidth,
true);
2109 castStatus = APFloat::opInvalidOp !=
2110 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2123OpFoldResult arith::FPToSIOp::fold(FoldAdaptor adaptor) {
2125 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2127 adaptor.getOperands(),
getType(),
2128 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2130 APSInt api(bitWidth,
false);
2131 castStatus = APFloat::opInvalidOp !=
2132 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2146 return intTy.getWidth();
2147 return IndexType::kInternalStorageBitWidth;
2156 if (!srcType || !dstType)
2160 (srcType.isSignlessInteger() && dstType.
isIndex());
2163bool arith::IndexCastOp::areCastCompatible(
TypeRange inputs,
2168OpFoldResult arith::IndexCastOp::fold(FoldAdaptor adaptor) {
2170 unsigned resultBitwidth = 64;
2172 resultBitwidth = intTy.getWidth();
2175 adaptor.getOperands(),
getType(),
2176 [resultBitwidth](
const APInt &a,
bool & ) {
2177 return a.sextOrTrunc(resultBitwidth);
2184 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastOp>()) {
2185 Value x = inner.getOperand();
2194void arith::IndexCastOp::getCanonicalizationPatterns(
2195 RewritePatternSet &patterns, MLIRContext *context) {
2196 patterns.
add<IndexCastOfExtSI>(context);
2203bool arith::IndexCastUIOp::areCastCompatible(
TypeRange inputs,
2208OpFoldResult arith::IndexCastUIOp::fold(FoldAdaptor adaptor) {
2210 unsigned resultBitwidth = 64;
2212 resultBitwidth = intTy.getWidth();
2215 adaptor.getOperands(),
getType(),
2216 [resultBitwidth](
const APInt &a,
bool & ) {
2217 return a.zextOrTrunc(resultBitwidth);
2224 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastUIOp>()) {
2225 Value x = inner.getOperand();
2234void arith::IndexCastUIOp::getCanonicalizationPatterns(
2235 RewritePatternSet &patterns, MLIRContext *context) {
2236 patterns.
add<IndexCastUIOfExtUI>(context);
2249 if (!srcType || !dstType)
2255OpFoldResult arith::BitcastOp::fold(FoldAdaptor adaptor) {
2257 auto operand = adaptor.getIn();
2262 if (
auto denseAttr = dyn_cast_or_null<DenseElementsAttr>(operand))
2263 return denseAttr.bitcast(llvm::cast<ShapedType>(resType).
getElementType());
2265 if (llvm::isa<ShapedType>(resType))
2273 APInt bits = llvm::isa<FloatAttr>(operand)
2274 ? llvm::cast<FloatAttr>(operand).getValue().bitcastToAPInt()
2275 : llvm::cast<IntegerAttr>(operand).getValue();
2277 "trying to fold on broken IR: operands have incompatible types");
2279 if (
auto resFloatType = dyn_cast<FloatType>(resType))
2280 return FloatAttr::get(resType,
2281 APFloat(resFloatType.getFloatSemantics(), bits));
2282 return IntegerAttr::get(resType, bits);
2285void arith::BitcastOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2286 MLIRContext *context) {
2287 patterns.
add<BitcastOfBitcast>(context);
2297 const APInt &
lhs,
const APInt &
rhs) {
2298 switch (predicate) {
2299 case arith::CmpIPredicate::eq:
2301 case arith::CmpIPredicate::ne:
2303 case arith::CmpIPredicate::slt:
2305 case arith::CmpIPredicate::sle:
2307 case arith::CmpIPredicate::sgt:
2309 case arith::CmpIPredicate::sge:
2311 case arith::CmpIPredicate::ult:
2313 case arith::CmpIPredicate::ule:
2315 case arith::CmpIPredicate::ugt:
2317 case arith::CmpIPredicate::uge:
2320 llvm_unreachable(
"unknown cmpi predicate kind");
2325 switch (predicate) {
2326 case arith::CmpIPredicate::eq:
2327 case arith::CmpIPredicate::sle:
2328 case arith::CmpIPredicate::sge:
2329 case arith::CmpIPredicate::ule:
2330 case arith::CmpIPredicate::uge:
2332 case arith::CmpIPredicate::ne:
2333 case arith::CmpIPredicate::slt:
2334 case arith::CmpIPredicate::sgt:
2335 case arith::CmpIPredicate::ult:
2336 case arith::CmpIPredicate::ugt:
2339 llvm_unreachable(
"unknown cmpi predicate kind");
2343 if (
auto intType = dyn_cast<IntegerType>(t)) {
2344 return intType.getWidth();
2346 if (
auto vectorIntType = dyn_cast<VectorType>(t)) {
2347 return llvm::cast<IntegerType>(vectorIntType.getElementType()).getWidth();
2349 return std::nullopt;
2352OpFoldResult arith::CmpIOp::fold(FoldAdaptor adaptor) {
2354 if (getLhs() == getRhs()) {
2360 if (
auto extOp = getLhs().getDefiningOp<ExtSIOp>()) {
2362 std::optional<int64_t> integerWidth =
2364 if (integerWidth && integerWidth.value() == 1 &&
2365 getPredicate() == arith::CmpIPredicate::ne)
2366 return extOp.getOperand();
2368 if (
auto extOp = getLhs().getDefiningOp<ExtUIOp>()) {
2370 std::optional<int64_t> integerWidth =
2372 if (integerWidth && integerWidth.value() == 1 &&
2373 getPredicate() == arith::CmpIPredicate::ne)
2374 return extOp.getOperand();
2379 getPredicate() == arith::CmpIPredicate::ne)
2386 getPredicate() == arith::CmpIPredicate::eq)
2391 if (adaptor.getLhs() && !adaptor.getRhs()) {
2393 using Pred = CmpIPredicate;
2394 const std::pair<Pred, Pred> invPreds[] = {
2395 {Pred::slt, Pred::sgt}, {Pred::sgt, Pred::slt}, {Pred::sle, Pred::sge},
2396 {Pred::sge, Pred::sle}, {Pred::ult, Pred::ugt}, {Pred::ugt, Pred::ult},
2397 {Pred::ule, Pred::uge}, {Pred::uge, Pred::ule}, {Pred::eq, Pred::eq},
2398 {Pred::ne, Pred::ne},
2400 Pred origPred = getPredicate();
2401 for (
auto pred : invPreds) {
2402 if (origPred == pred.first) {
2403 setPredicate(pred.second);
2404 Value
lhs = getLhs();
2405 Value
rhs = getRhs();
2406 getLhsMutable().assign(
rhs);
2407 getRhsMutable().assign(
lhs);
2411 llvm_unreachable(
"unknown cmpi predicate kind");
2416 if (
auto lhs = dyn_cast_if_present<TypedAttr>(adaptor.getLhs())) {
2419 [pred = getPredicate()](
const APInt &
lhs,
const APInt &
rhs) {
2428void arith::CmpIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2429 MLIRContext *context) {
2430 patterns.
insert<CmpIExtSI, CmpIExtUI>(context);
2440 const APFloat &
lhs,
const APFloat &
rhs) {
2441 auto cmpResult =
lhs.compare(
rhs);
2442 switch (predicate) {
2443 case arith::CmpFPredicate::AlwaysFalse:
2445 case arith::CmpFPredicate::OEQ:
2446 return cmpResult == APFloat::cmpEqual;
2447 case arith::CmpFPredicate::OGT:
2448 return cmpResult == APFloat::cmpGreaterThan;
2449 case arith::CmpFPredicate::OGE:
2450 return cmpResult == APFloat::cmpGreaterThan ||
2451 cmpResult == APFloat::cmpEqual;
2452 case arith::CmpFPredicate::OLT:
2453 return cmpResult == APFloat::cmpLessThan;
2454 case arith::CmpFPredicate::OLE:
2455 return cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2456 case arith::CmpFPredicate::ONE:
2457 return cmpResult != APFloat::cmpUnordered && cmpResult != APFloat::cmpEqual;
2458 case arith::CmpFPredicate::ORD:
2459 return cmpResult != APFloat::cmpUnordered;
2460 case arith::CmpFPredicate::UEQ:
2461 return cmpResult == APFloat::cmpUnordered || cmpResult == APFloat::cmpEqual;
2462 case arith::CmpFPredicate::UGT:
2463 return cmpResult == APFloat::cmpUnordered ||
2464 cmpResult == APFloat::cmpGreaterThan;
2465 case arith::CmpFPredicate::UGE:
2466 return cmpResult == APFloat::cmpUnordered ||
2467 cmpResult == APFloat::cmpGreaterThan ||
2468 cmpResult == APFloat::cmpEqual;
2469 case arith::CmpFPredicate::ULT:
2470 return cmpResult == APFloat::cmpUnordered ||
2471 cmpResult == APFloat::cmpLessThan;
2472 case arith::CmpFPredicate::ULE:
2473 return cmpResult == APFloat::cmpUnordered ||
2474 cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2475 case arith::CmpFPredicate::UNE:
2476 return cmpResult != APFloat::cmpEqual;
2477 case arith::CmpFPredicate::UNO:
2478 return cmpResult == APFloat::cmpUnordered;
2479 case arith::CmpFPredicate::AlwaysTrue:
2482 llvm_unreachable(
"unknown cmpf predicate kind");
2486 auto lhs = dyn_cast_if_present<FloatAttr>(adaptor.getLhs());
2487 auto rhs = dyn_cast_if_present<FloatAttr>(adaptor.getRhs());
2490 if (
lhs &&
lhs.getValue().isNaN())
2492 if (
rhs &&
rhs.getValue().isNaN())
2508 using namespace arith;
2510 case CmpFPredicate::UEQ:
2511 case CmpFPredicate::OEQ:
2512 return CmpIPredicate::eq;
2513 case CmpFPredicate::UGT:
2514 case CmpFPredicate::OGT:
2515 return isUnsigned ? CmpIPredicate::ugt : CmpIPredicate::sgt;
2516 case CmpFPredicate::UGE:
2517 case CmpFPredicate::OGE:
2518 return isUnsigned ? CmpIPredicate::uge : CmpIPredicate::sge;
2519 case CmpFPredicate::ULT:
2520 case CmpFPredicate::OLT:
2521 return isUnsigned ? CmpIPredicate::ult : CmpIPredicate::slt;
2522 case CmpFPredicate::ULE:
2523 case CmpFPredicate::OLE:
2524 return isUnsigned ? CmpIPredicate::ule : CmpIPredicate::sle;
2525 case CmpFPredicate::UNE:
2526 case CmpFPredicate::ONE:
2527 return CmpIPredicate::ne;
2529 llvm_unreachable(
"Unexpected predicate!");
2539 const APFloat &
rhs = flt.getValue();
2547 FloatType floatTy = llvm::cast<FloatType>(op.getRhs().getType());
2548 int mantissaWidth = floatTy.getFPMantissaWidth();
2549 if (mantissaWidth <= 0)
2555 if (
auto si = op.getLhs().getDefiningOp<SIToFPOp>()) {
2557 intVal = si.getIn();
2558 }
else if (
auto ui = op.getLhs().getDefiningOp<UIToFPOp>()) {
2560 intVal = ui.getIn();
2567 auto intTy = llvm::cast<IntegerType>(intVal.
getType());
2568 auto intWidth = intTy.getWidth();
2571 auto valueBits = isUnsigned ? intWidth : (intWidth - 1);
2576 if ((
int)intWidth > mantissaWidth) {
2578 int exponent = ilogb(
rhs);
2579 if (exponent == APFloat::IEK_Inf) {
2580 int maxExponent = ilogb(APFloat::getLargest(
rhs.getSemantics()));
2581 if (maxExponent < (
int)valueBits) {
2588 if (mantissaWidth <= exponent && exponent <= (
int)valueBits) {
2597 switch (op.getPredicate()) {
2598 case CmpFPredicate::ORD:
2603 case CmpFPredicate::UNO:
2616 APFloat signedMax(
rhs.getSemantics());
2617 signedMax.convertFromAPInt(APInt::getSignedMaxValue(intWidth),
true,
2618 APFloat::rmNearestTiesToEven);
2619 if (signedMax <
rhs) {
2620 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::slt ||
2621 pred == CmpIPredicate::sle)
2632 APFloat unsignedMax(
rhs.getSemantics());
2633 unsignedMax.convertFromAPInt(APInt::getMaxValue(intWidth),
false,
2634 APFloat::rmNearestTiesToEven);
2635 if (unsignedMax <
rhs) {
2636 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ult ||
2637 pred == CmpIPredicate::ule)
2649 APFloat signedMin(
rhs.getSemantics());
2650 signedMin.convertFromAPInt(APInt::getSignedMinValue(intWidth),
true,
2651 APFloat::rmNearestTiesToEven);
2652 if (signedMin >
rhs) {
2653 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::sgt ||
2654 pred == CmpIPredicate::sge)
2664 APFloat unsignedMin(
rhs.getSemantics());
2665 unsignedMin.convertFromAPInt(APInt::getMinValue(intWidth),
false,
2666 APFloat::rmNearestTiesToEven);
2667 if (unsignedMin >
rhs) {
2668 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ugt ||
2669 pred == CmpIPredicate::uge)
2684 APSInt rhsInt(intWidth, isUnsigned);
2685 if (APFloat::opInvalidOp ==
2686 rhs.convertToInteger(rhsInt, APFloat::rmTowardZero, &ignored)) {
2692 if (!
rhs.isZero()) {
2693 APFloat apf(floatTy.getFloatSemantics(),
2694 APInt::getZero(floatTy.getWidth()));
2695 apf.convertFromAPInt(rhsInt, !isUnsigned, APFloat::rmNearestTiesToEven);
2697 bool equal = apf ==
rhs;
2703 case CmpIPredicate::ne:
2707 case CmpIPredicate::eq:
2711 case CmpIPredicate::ule:
2714 if (
rhs.isNegative()) {
2720 case CmpIPredicate::sle:
2723 if (
rhs.isNegative())
2724 pred = CmpIPredicate::slt;
2726 case CmpIPredicate::ult:
2729 if (
rhs.isNegative()) {
2734 pred = CmpIPredicate::ule;
2736 case CmpIPredicate::slt:
2739 if (!
rhs.isNegative())
2740 pred = CmpIPredicate::sle;
2742 case CmpIPredicate::ugt:
2745 if (
rhs.isNegative()) {
2751 case CmpIPredicate::sgt:
2754 if (
rhs.isNegative())
2755 pred = CmpIPredicate::sge;
2757 case CmpIPredicate::uge:
2760 if (
rhs.isNegative()) {
2765 pred = CmpIPredicate::ugt;
2767 case CmpIPredicate::sge:
2770 if (!
rhs.isNegative())
2771 pred = CmpIPredicate::sgt;
2781 ConstantOp::create(rewriter, op.getLoc(), intVal.
getType(),
2787void arith::CmpFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2788 MLIRContext *context) {
2789 patterns.
insert<CmpFIntToFPConst>(context);
2803 if (!llvm::isa<IntegerType>(op.getType()) || op.getType().isInteger(1))
2819 arith::XOrIOp::create(
2820 rewriter, op.getLoc(), op.getCondition(),
2822 op.getCondition().
getType(), 1)));
2830void arith::SelectOp::getCanonicalizationPatterns(RewritePatternSet &results,
2831 MLIRContext *context) {
2832 results.
add<RedundantSelectFalse, RedundantSelectTrue, SelectNotCond,
2833 SelectI1ToNot, SelectCmpISgeToMaxSI, SelectCmpISgeToMinSI,
2834 SelectCmpISgtToMaxSI, SelectCmpISgtToMinSI, SelectCmpISleToMaxSI,
2835 SelectCmpISleToMinSI, SelectCmpISltToMaxSI, SelectCmpISltToMinSI,
2836 SelectCmpIUgeToMaxUI, SelectCmpIUgeToMinUI, SelectCmpIUgtToMaxUI,
2837 SelectCmpIUgtToMinUI, SelectCmpIUleToMaxUI, SelectCmpIUleToMinUI,
2838 SelectCmpIUltToMaxUI, SelectCmpIUltToMinUI, SelectToExtUI>(
2842OpFoldResult arith::SelectOp::fold(FoldAdaptor adaptor) {
2843 Value trueVal = getTrueValue();
2844 Value falseVal = getFalseValue();
2845 if (trueVal == falseVal)
2848 Value condition = getCondition();
2866 if (
getType().isSignlessInteger(1) &&
2872 auto pred = cmp.getPredicate();
2873 if (pred == arith::CmpIPredicate::eq || pred == arith::CmpIPredicate::ne) {
2874 auto cmpLhs = cmp.getLhs();
2875 auto cmpRhs = cmp.getRhs();
2883 if ((cmpLhs == trueVal && cmpRhs == falseVal) ||
2884 (cmpRhs == trueVal && cmpLhs == falseVal))
2885 return pred == arith::CmpIPredicate::ne ? trueVal : falseVal;
2892 dyn_cast_if_present<DenseElementsAttr>(adaptor.getCondition())) {
2894 assert(cond.getType().hasStaticShape() &&
2895 "DenseElementsAttr must have static shape");
2897 dyn_cast_if_present<DenseElementsAttr>(adaptor.getTrueValue())) {
2899 dyn_cast_if_present<DenseElementsAttr>(adaptor.getFalseValue())) {
2900 SmallVector<Attribute> results;
2901 results.reserve(
static_cast<size_t>(cond.getNumElements()));
2902 auto condVals = llvm::make_range(cond.value_begin<BoolAttr>(),
2903 cond.value_end<BoolAttr>());
2904 auto lhsVals = llvm::make_range(
lhs.value_begin<Attribute>(),
2905 lhs.value_end<Attribute>());
2906 auto rhsVals = llvm::make_range(
rhs.value_begin<Attribute>(),
2907 rhs.value_end<Attribute>());
2909 for (
auto [condVal, lhsVal, rhsVal] :
2910 llvm::zip_equal(condVals, lhsVals, rhsVals))
2911 results.push_back(condVal.getValue() ? lhsVal : rhsVal);
2921ParseResult SelectOp::parse(OpAsmParser &parser, OperationState &
result) {
2922 Type conditionType, resultType;
2923 SmallVector<OpAsmParser::UnresolvedOperand, 3> operands;
2931 conditionType = resultType;
2938 result.addTypes(resultType);
2940 {conditionType, resultType, resultType},
2944void arith::SelectOp::print(OpAsmPrinter &p) {
2945 p <<
" " << getOperands();
2948 if (ShapedType condType = dyn_cast<ShapedType>(getCondition().
getType()))
2949 p << condType <<
", ";
2953LogicalResult arith::SelectOp::verify() {
2954 Type conditionType = getCondition().getType();
2961 if (!llvm::isa<TensorType, VectorType>(resultType))
2962 return emitOpError() <<
"expected condition to be a signless i1, but got "
2965 if (conditionType != shapedConditionType) {
2966 return emitOpError() <<
"expected condition type to have the same shape "
2967 "as the result type, expected "
2968 << shapedConditionType <<
", but got "
2977OpFoldResult arith::ShLIOp::fold(FoldAdaptor adaptor) {
2991 bool bounded =
false;
2993 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
2994 bounded = b.ult(b.getBitWidth());
2997 return bounded ?
result : Attribute();
3004OpFoldResult arith::ShRUIOp::fold(FoldAdaptor adaptor) {
3019 if (getLhs() == getRhs())
3022 bool bounded =
false;
3024 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3025 bounded = b.ult(b.getBitWidth());
3028 return bounded ?
result : Attribute();
3035OpFoldResult arith::ShRSIOp::fold(FoldAdaptor adaptor) {
3050 if (getLhs() == getRhs())
3058 bool bounded =
false;
3060 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3061 bounded = b.ult(b.getBitWidth());
3064 return bounded ?
result : Attribute();
3074 bool useOnlyFiniteValue) {
3076 case AtomicRMWKind::maximumf: {
3077 const llvm::fltSemantics &semantic =
3078 llvm::cast<FloatType>(resultType).getFloatSemantics();
3079 APFloat identity = useOnlyFiniteValue
3080 ? APFloat::getLargest(semantic,
true)
3081 : APFloat::getInf(semantic,
true);
3084 case AtomicRMWKind::maxnumf: {
3085 const llvm::fltSemantics &semantic =
3086 llvm::cast<FloatType>(resultType).getFloatSemantics();
3087 APFloat identity = APFloat::getNaN(semantic,
true);
3090 case AtomicRMWKind::addf:
3091 case AtomicRMWKind::addi:
3092 case AtomicRMWKind::maxu:
3093 case AtomicRMWKind::ori:
3094 case AtomicRMWKind::xori:
3096 case AtomicRMWKind::andi:
3099 APInt::getAllOnes(llvm::cast<IntegerType>(resultType).getWidth()));
3100 case AtomicRMWKind::maxs:
3102 resultType, APInt::getSignedMinValue(
3103 llvm::cast<IntegerType>(resultType).getWidth()));
3104 case AtomicRMWKind::minimumf: {
3105 const llvm::fltSemantics &semantic =
3106 llvm::cast<FloatType>(resultType).getFloatSemantics();
3107 APFloat identity = useOnlyFiniteValue
3108 ? APFloat::getLargest(semantic,
false)
3109 : APFloat::getInf(semantic,
false);
3113 case AtomicRMWKind::minnumf: {
3114 const llvm::fltSemantics &semantic =
3115 llvm::cast<FloatType>(resultType).getFloatSemantics();
3116 APFloat identity = APFloat::getNaN(semantic,
false);
3119 case AtomicRMWKind::mins:
3121 resultType, APInt::getSignedMaxValue(
3122 llvm::cast<IntegerType>(resultType).getWidth()));
3123 case AtomicRMWKind::minu:
3126 APInt::getMaxValue(llvm::cast<IntegerType>(resultType).getWidth()));
3127 case AtomicRMWKind::muli:
3129 case AtomicRMWKind::mulf:
3141 std::optional<AtomicRMWKind> maybeKind =
3144 .Case([](arith::AddFOp op) {
return AtomicRMWKind::addf; })
3145 .Case([](arith::MulFOp op) {
return AtomicRMWKind::mulf; })
3146 .Case([](arith::MaximumFOp op) {
return AtomicRMWKind::maximumf; })
3147 .Case([](arith::MinimumFOp op) {
return AtomicRMWKind::minimumf; })
3148 .Case([](arith::MaxNumFOp op) {
return AtomicRMWKind::maxnumf; })
3149 .Case([](arith::MinNumFOp op) {
return AtomicRMWKind::minnumf; })
3151 .Case([](arith::AddIOp op) {
return AtomicRMWKind::addi; })
3152 .Case([](arith::OrIOp op) {
return AtomicRMWKind::ori; })
3153 .Case([](arith::XOrIOp op) {
return AtomicRMWKind::xori; })
3154 .Case([](arith::AndIOp op) {
return AtomicRMWKind::andi; })
3155 .Case([](arith::MaxUIOp op) {
return AtomicRMWKind::maxu; })
3156 .Case([](arith::MinUIOp op) {
return AtomicRMWKind::minu; })
3157 .Case([](arith::MaxSIOp op) {
return AtomicRMWKind::maxs; })
3158 .Case([](arith::MinSIOp op) {
return AtomicRMWKind::mins; })
3159 .Case([](arith::MulIOp op) {
return AtomicRMWKind::muli; })
3160 .Default(std::nullopt);
3162 return std::nullopt;
3165 bool useOnlyFiniteValue =
false;
3166 auto fmfOpInterface = dyn_cast<ArithFastMathInterface>(op);
3167 if (fmfOpInterface) {
3168 arith::FastMathFlagsAttr fmfAttr = fmfOpInterface.getFastMathFlagsAttr();
3169 useOnlyFiniteValue =
3170 bitEnumContainsAny(fmfAttr.getValue(), arith::FastMathFlags::ninf);
3178 useOnlyFiniteValue);
3184 bool useOnlyFiniteValue) {
3186 useOnlyFiniteValue))
3187 return arith::ConstantOp::create(builder, loc, attr);
3196 case AtomicRMWKind::addf:
3197 return arith::AddFOp::create(builder, loc,
lhs,
rhs);
3198 case AtomicRMWKind::addi:
3199 return arith::AddIOp::create(builder, loc,
lhs,
rhs);
3200 case AtomicRMWKind::mulf:
3201 return arith::MulFOp::create(builder, loc,
lhs,
rhs);
3202 case AtomicRMWKind::muli:
3203 return arith::MulIOp::create(builder, loc,
lhs,
rhs);
3204 case AtomicRMWKind::maximumf:
3205 return arith::MaximumFOp::create(builder, loc,
lhs,
rhs);
3206 case AtomicRMWKind::minimumf:
3207 return arith::MinimumFOp::create(builder, loc,
lhs,
rhs);
3208 case AtomicRMWKind::maxnumf:
3209 return arith::MaxNumFOp::create(builder, loc,
lhs,
rhs);
3210 case AtomicRMWKind::minnumf:
3211 return arith::MinNumFOp::create(builder, loc,
lhs,
rhs);
3212 case AtomicRMWKind::maxs:
3213 return arith::MaxSIOp::create(builder, loc,
lhs,
rhs);
3214 case AtomicRMWKind::mins:
3215 return arith::MinSIOp::create(builder, loc,
lhs,
rhs);
3216 case AtomicRMWKind::maxu:
3217 return arith::MaxUIOp::create(builder, loc,
lhs,
rhs);
3218 case AtomicRMWKind::minu:
3219 return arith::MinUIOp::create(builder, loc,
lhs,
rhs);
3220 case AtomicRMWKind::ori:
3221 return arith::OrIOp::create(builder, loc,
lhs,
rhs);
3222 case AtomicRMWKind::andi:
3223 return arith::AndIOp::create(builder, loc,
lhs,
rhs);
3224 case AtomicRMWKind::xori:
3225 return arith::XOrIOp::create(builder, loc,
lhs,
rhs);
3238#define GET_OP_CLASSES
3239#include "mlir/Dialect/Arith/IR/ArithOps.cpp.inc"
3245#include "mlir/Dialect/Arith/IR/ArithOpsEnums.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static Speculation::Speculatability getDivUISpeculatability(Value divisor)
Returns whether an unsigned division by divisor is speculatable.
static bool checkWidthChangeCast(TypeRange inputs, TypeRange outputs)
Validate a cast that changes the width of a type.
static IntegerAttr mulIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs)
static IntegerOverflowFlagsAttr mergeOverflowFlags(IntegerOverflowFlagsAttr val1, IntegerOverflowFlagsAttr val2)
static constexpr llvm::RoundingMode kDefaultRoundingMode
Default rounding mode according to default LLVM floating-point environment.
static Type getTypeIfLike(Type type)
Get allowed underlying types for vectors and tensors.
static bool applyCmpPredicateToEqualOperands(arith::CmpIPredicate predicate)
Returns true if the predicate is true for two equal operands.
static FailureOr< APFloat > convertFloatValue(APFloat sourceValue, const llvm::fltSemantics &targetSemantics, llvm::RoundingMode roundingMode=kDefaultRoundingMode)
Attempts to convert sourceValue to an APFloat value with targetSemantics and roundingMode,...
static Value foldDivMul(Value lhs, Value rhs, arith::IntegerOverflowFlags ovfFlags)
Fold (a * b) / b -> a
static bool hasSameEncoding(Type typeA, Type typeB)
Return false if both types are ranked tensor with mismatching encoding.
static llvm::RoundingMode convertArithRoundingModeToLLVMIR(std::optional< RoundingMode > roundingMode)
Equivalent to convertRoundingModeToLLVM(convertArithRoundingModeToLLVM(roundingMode)).
static Type getUnderlyingType(Type type, type_list< ShapedTypes... >, type_list< ElementTypes... >)
Returns a non-null type only if the provided type is one of the allowed types or one of the allowed s...
static APInt signedCeilNonnegInputs(const APInt &a, const APInt &b, bool &overflow)
static std::optional< int64_t > getIntegerWidth(Type t)
static Speculation::Speculatability getDivSISpeculatability(Value divisor)
Returns whether a signed division by divisor is speculatable.
static IntegerAttr orIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs)
static IntegerAttr addIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs)
static Attribute getBoolAttribute(Type type, bool value)
static bool areIndexCastCompatible(TypeRange inputs, TypeRange outputs)
static bool checkIntFloatCast(TypeRange inputs, TypeRange outputs)
static LogicalResult verifyExtOp(Op op)
static IntegerAttr subIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs)
static Attribute getIntegerAttrOfType(Type type, int64_t value)
Return a scalar or splat integer attribute of type (an integer/index type or a shaped type thereof) h...
static IntegerAttr andIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs)
static int64_t getScalarOrElementWidth(Type type)
static Value foldAndIofAndI(arith::AndIOp op)
Fold and(a, and(a, b)) to and(a, b)
static Type getTypeIfLikeOrMemRef(Type type)
Get allowed underlying types for vectors, tensors, and memrefs.
static Type getI1SameShape(Type type)
Return the type of the same shape (scalar, vector or tensor) containing i1.
static bool areValidCastInputsAndOutputs(TypeRange inputs, TypeRange outputs)
static IntegerAttr xorIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs)
static APInt calculateUnsignedBorrow(const APInt &lhs, const APInt &rhs)
std::tuple< Types... > * type_list
static IntegerAttr applyToIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, Attribute rhs, function_ref< APInt(const APInt &, const APInt &)> binFn)
static APInt calculateUnsignedOverflow(const APInt &sum, const APInt &operand)
static FailureOr< APInt > getIntOrSplatIntValue(Attribute attr)
static unsigned getIndexCastWidth(Type t)
Return the bit-width of t for the purpose of index_cast width checks.
static LogicalResult verifyTruncateOp(Op op)
static Type getElementType(Type type)
Determine the element type of type.
LogicalResult matchAndRewrite(CmpFOp op, PatternRewriter &rewriter) const override
static CmpIPredicate convertToIntegerPredicate(CmpFPredicate pred, bool isUnsigned)
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
Attributes are known-constant values of operations.
static BoolAttr get(MLIRContext *context, bool value)
IntegerAttr getIndexAttr(int64_t value)
IntegerAttr getIntegerAttr(Type type, int64_t value)
FloatAttr getFloatAttr(Type type, double value)
IntegerType getIntegerType(unsigned width)
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
TypedAttr getZeroAttr(Type type)
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...
Location getLoc() const
Accessors for the implied location.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
This class helps build Operations.
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
This class represents a single result from folding an operation.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
This provides public APIs that all operations should have.
Operation is the basic unit of execution within MLIR.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
MLIRContext * getContext()
Return the context this operation is associated with.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
RewritePatternSet & insert(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
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.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Specialization of arith.constant op that returns a floating point value.
static ConstantFloatOp create(OpBuilder &builder, Location location, FloatType type, const APFloat &value)
static bool classof(Operation *op)
static void build(OpBuilder &builder, OperationState &result, FloatType type, const APFloat &value)
Build a constant float op that produces a float of the specified type.
Specialization of arith.constant op that returns an integer of index type.
static void build(OpBuilder &builder, OperationState &result, int64_t value)
Build a constant int op that produces an index.
static bool classof(Operation *op)
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Specialization of arith.constant op that returns an integer value.
static ConstantIntOp create(OpBuilder &builder, Location location, int64_t value, unsigned width)
static void build(OpBuilder &builder, OperationState &result, int64_t value, unsigned width)
Build a constant int op that produces an integer of the specified width.
static bool classof(Operation *op)
Speculatability
This enum is returned from the getSpeculatability method in the ConditionallySpeculatable op interfac...
constexpr auto Speculatable
constexpr auto NotSpeculatable
std::optional< TypedAttr > getNeutralElement(Operation *op)
Return the identity numeric value associated to the give op.
bool applyCmpPredicate(arith::CmpIPredicate predicate, const APInt &lhs, const APInt &rhs)
Compute lhs pred rhs, where pred is one of the known integer comparison predicates.
TypedAttr getIdentityValueAttr(AtomicRMWKind kind, Type resultType, OpBuilder &builder, Location loc, bool useOnlyFiniteValue=false)
Returns the identity value attribute associated with an AtomicRMWKind op.
Value getReductionOp(AtomicRMWKind op, OpBuilder &builder, Location loc, Value lhs, Value rhs)
Returns the value obtained by applying the reduction operation kind associated with a binary AtomicRM...
Value getIdentityValue(AtomicRMWKind op, Type resultType, OpBuilder &builder, Location loc, bool useOnlyFiniteValue=false)
Returns the identity value associated with an AtomicRMWKind op.
arith::CmpIPredicate invertPredicate(arith::CmpIPredicate pred)
Invert an integer comparison predicate.
Value getZeroConstant(OpBuilder &builder, Location loc, Type type)
Creates an arith.constant operation with a zero value of type type.
detail::poison_attr_matcher m_Poison()
Matches a poison constant (any attribute implementing PoisonAttrInterface).
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
detail::constant_float_predicate_matcher m_NaNFloat()
Matches a constant scalar / vector splat / tensor splat float ones.
LogicalResult verifyCompatibleShapes(TypeRange types1, TypeRange types2)
Returns success if the given two arrays have the same number of elements and each pair wise entries h...
Attribute constFoldCastOp(ArrayRef< Attribute > operands, Type resType, CalculationT &&calculate)
Attribute constFoldBinaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
detail::constant_int_range_predicate_matcher m_IntRangeWithoutNegOneS()
Matches a constant scalar / vector splat / tensor splat integer or a signed integer range that does n...
LogicalResult emitOptionalError(std::optional< Location > loc, Args &&...args)
Overloads of the above emission functions that take an optionally null location.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
detail::constant_float_predicate_matcher m_PosZeroFloat()
Matches a constant scalar / vector splat / tensor splat float positive zero.
detail::constant_int_predicate_matcher m_Zero()
Matches a constant scalar / vector splat / tensor splat integer zero.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
detail::constant_float_predicate_matcher m_AnyZeroFloat()
Matches a constant scalar / vector splat / tensor splat float (both positive and negative) zero.
detail::constant_int_predicate_matcher m_One()
Matches a constant scalar / vector splat / tensor splat integer one.
detail::constant_float_predicate_matcher m_NegInfFloat()
Matches a constant scalar / vector splat / tensor splat float negative infinity.
detail::constant_float_predicate_matcher m_NegZeroFloat()
Matches a constant scalar / vector splat / tensor splat float negative zero.
detail::constant_int_range_predicate_matcher m_IntRangeWithoutZeroS()
Matches a constant scalar / vector splat / tensor splat integer or a signed integer range that does n...
detail::op_matcher< OpClass > m_Op()
Matches the given OpClass.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Attribute constFoldUnaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
detail::constant_float_predicate_matcher m_PosInfFloat()
Matches a constant scalar / vector splat / tensor splat float positive infinity.
llvm::function_ref< Fn > function_ref
detail::constant_float_predicate_matcher m_OneFloat()
Matches a constant scalar / vector splat / tensor splat float ones.
detail::constant_int_range_predicate_matcher m_IntRangeWithoutZeroU()
Matches a constant scalar / vector splat / tensor splat integer or a unsigned integer range that does...
LogicalResult matchAndRewrite(arith::SelectOp op, PatternRewriter &rewriter) const override
OpRewritePattern Base
Type alias to allow derived classes to inherit constructors with using Base::Base;.
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
This represents an operation in an abstracted form, suitable for use with the builder APIs.