27#include "llvm/ADT/APFloat.h"
28#include "llvm/ADT/APInt.h"
29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/FloatingPointMode.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/TypeSwitch.h"
40 llvm::RoundingMode::NearestTiesToEven;
49 function_ref<APInt(
const APInt &,
const APInt &)> binFn) {
50 const APInt &lhsVal = llvm::cast<IntegerAttr>(lhs).getValue();
51 const APInt &rhsVal = llvm::cast<IntegerAttr>(rhs).getValue();
52 APInt value = binFn(lhsVal, rhsVal);
53 return IntegerAttr::get(res.getType(), value);
87static IntegerOverflowFlagsAttr
89 IntegerOverflowFlagsAttr val2) {
90 return IntegerOverflowFlagsAttr::get(val1.getContext(),
91 val1.getValue() & val2.getValue());
97 case arith::CmpIPredicate::eq:
98 return arith::CmpIPredicate::ne;
99 case arith::CmpIPredicate::ne:
100 return arith::CmpIPredicate::eq;
101 case arith::CmpIPredicate::slt:
102 return arith::CmpIPredicate::sge;
103 case arith::CmpIPredicate::sle:
104 return arith::CmpIPredicate::sgt;
105 case arith::CmpIPredicate::sgt:
106 return arith::CmpIPredicate::sle;
107 case arith::CmpIPredicate::sge:
108 return arith::CmpIPredicate::slt;
109 case arith::CmpIPredicate::ult:
110 return arith::CmpIPredicate::uge;
111 case arith::CmpIPredicate::ule:
112 return arith::CmpIPredicate::ugt;
113 case arith::CmpIPredicate::ugt:
114 return arith::CmpIPredicate::ule;
115 case arith::CmpIPredicate::uge:
116 return arith::CmpIPredicate::ult;
118 llvm_unreachable(
"unknown cmpi predicate kind");
127static llvm::RoundingMode
131 switch (*roundingMode) {
132 case RoundingMode::downward:
133 return llvm::RoundingMode::TowardNegative;
134 case RoundingMode::to_nearest_away:
135 return llvm::RoundingMode::NearestTiesToAway;
136 case RoundingMode::to_nearest_even:
137 return llvm::RoundingMode::NearestTiesToEven;
138 case RoundingMode::toward_zero:
139 return llvm::RoundingMode::TowardZero;
140 case RoundingMode::upward:
141 return llvm::RoundingMode::TowardPositive;
143 llvm_unreachable(
"Unhandled rounding mode");
147 return arith::CmpIPredicateAttr::get(pred.getContext(),
173 ShapedType shapedType = dyn_cast_or_null<ShapedType>(type);
177 if (!shapedType.hasStaticShape())
187 ShapedType shapedType = dyn_cast<ShapedType>(type);
190 if (!shapedType.hasStaticShape())
200#include "ArithCanonicalization.inc"
209 auto i1Type = IntegerType::get(type.
getContext(), 1);
210 if (
auto shapedType = dyn_cast<ShapedType>(type))
211 return shapedType.cloneWith(std::nullopt, i1Type);
212 if (llvm::isa<UnrankedTensorType>(type))
213 return UnrankedTensorType::get(i1Type);
221void arith::ConstantOp::getAsmResultNames(
224 if (
auto intCst = dyn_cast<IntegerAttr>(getValue())) {
225 auto intType = dyn_cast<IntegerType>(type);
228 if (intType && intType.getWidth() == 1)
229 return setNameFn(getResult(), (intCst.getInt() ?
"true" :
"false"));
232 SmallString<32> specialNameBuffer;
233 llvm::raw_svector_ostream specialName(specialNameBuffer);
234 specialName <<
'c' << intCst.getValue();
236 specialName <<
'_' << type;
237 setNameFn(getResult(), specialName.str());
239 setNameFn(getResult(),
"cst");
245LogicalResult arith::ConstantOp::verify() {
249 intType && !intType.isSignless())
250 return emitOpError(
"integer return type must be signless");
252 if (!llvm::isa<IntegerAttr, FloatAttr, ElementsAttr>(getValue())) {
254 "value must be an integer, float, or elements attribute");
260 if (isa<ScalableVectorType>(type) && !isa<SplatElementsAttr>(getValue()))
262 "initializing scalable vectors with elements attribute is not supported"
263 " unless it's a vector splat");
267bool arith::ConstantOp::isBuildableWith(Attribute value, Type type) {
269 auto typedAttr = dyn_cast<TypedAttr>(value);
270 if (!typedAttr || typedAttr.getType() != type)
274 if (!intType.isSignless())
278 return llvm::isa<IntegerAttr, FloatAttr, ElementsAttr>(value);
281ConstantOp arith::ConstantOp::materialize(OpBuilder &builder, Attribute value,
282 Type type, Location loc) {
283 if (isBuildableWith(value, type))
284 return arith::ConstantOp::create(builder, loc, cast<TypedAttr>(value));
288OpFoldResult arith::ConstantOp::fold(FoldAdaptor adaptor) {
return getValue(); }
293 arith::ConstantOp::build(builder,
result, type,
303 auto result = dyn_cast<ConstantIntOp>(builder.
create(state));
304 assert(
result &&
"builder didn't return the right type");
316 arith::ConstantOp::build(builder,
result, type,
325 auto result = dyn_cast<ConstantIntOp>(builder.
create(state));
326 assert(
result &&
"builder didn't return the right type");
337 arith::ConstantOp::build(builder,
result, type,
343 const APInt &
value) {
346 auto result = dyn_cast<ConstantIntOp>(builder.
create(state));
347 assert(
result &&
"builder didn't return the right type");
353 const APInt &
value) {
358 if (
auto constOp = dyn_cast_or_null<arith::ConstantOp>(op))
359 return constOp.getType().isSignlessInteger();
364 FloatType type,
const APFloat &
value) {
365 arith::ConstantOp::build(builder,
result, type,
372 const APFloat &
value) {
375 auto result = dyn_cast<ConstantFloatOp>(builder.
create(state));
376 assert(
result &&
"builder didn't return the right type");
382 const APFloat &
value) {
387 if (
auto constOp = dyn_cast_or_null<arith::ConstantOp>(op))
388 return llvm::isa<FloatType>(constOp.getType());
403 auto result = dyn_cast<ConstantIndexOp>(builder.
create(state));
404 assert(
result &&
"builder didn't return the right type");
414 if (
auto constOp = dyn_cast_or_null<arith::ConstantOp>(op))
415 return constOp.getType().isIndex();
423 "type doesn't have a zero representation");
425 assert(zeroAttr &&
"unsupported type for zero attribute");
426 return arith::ConstantOp::create(builder, loc, zeroAttr);
439 if (
auto sub = getLhs().getDefiningOp<SubIOp>())
440 if (getRhs() == sub.getRhs())
444 if (
auto sub = getRhs().getDefiningOp<SubIOp>())
445 if (getLhs() == sub.getRhs())
449 adaptor.getOperands(),
450 [](APInt a,
const APInt &
b) { return std::move(a) + b; });
455 patterns.
add<AddIAddConstant, AddISubConstantRHS, AddISubConstantLHS,
456 AddIMulNegativeOneRhs, AddIMulNegativeOneLhs>(context);
463std::optional<SmallVector<int64_t, 4>>
464arith::AddUIExtendedOp::getShapeForUnroll() {
465 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
466 return llvm::to_vector<4>(vt.getShape());
473 return sum.ult(operand) ? APInt::getAllOnes(1) : APInt::getZero(1);
477arith::AddUIExtendedOp::fold(FoldAdaptor adaptor,
478 SmallVectorImpl<OpFoldResult> &results) {
479 Type overflowTy = getOverflow().getType();
485 results.push_back(getLhs());
486 results.push_back(falseValue);
495 adaptor.getOperands(),
496 [](APInt a,
const APInt &
b) { return std::move(a) + b; })) {
499 results.push_back(sumAttr);
500 results.push_back(sumAttr);
504 ArrayRef({sumAttr, adaptor.getLhs()}),
510 results.push_back(sumAttr);
511 results.push_back(overflowAttr);
518void arith::AddUIExtendedOp::getCanonicalizationPatterns(
519 RewritePatternSet &patterns, MLIRContext *context) {
520 patterns.
add<AddUIExtendedToAddI>(context);
527std::optional<SmallVector<int64_t, 4>>
528arith::SubUIExtendedOp::getShapeForUnroll() {
529 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
530 return llvm::to_vector<4>(vt.getShape());
537 return lhs.ult(rhs) ? APInt::getAllOnes(1) : APInt::getZero(1);
541arith::SubUIExtendedOp::fold(FoldAdaptor adaptor,
542 SmallVectorImpl<OpFoldResult> &results) {
543 Type borrowTy = getBorrow().getType();
549 results.push_back(getLhs());
550 results.push_back(falseValue);
555 if (getLhs() == getRhs()) {
558 auto shapedType = dyn_cast<ShapedType>(getDiff().
getType());
559 if (shapedType && !shapedType.hasStaticShape())
567 results.push_back(zeroDiff);
568 results.push_back(falseValue);
574 adaptor.getOperands(),
575 [](APInt a,
const APInt &
b) { return std::move(a) - b; })) {
578 results.push_back(diffAttr);
579 results.push_back(diffAttr);
583 adaptor.getOperands(),
589 results.push_back(diffAttr);
590 results.push_back(borrowAttr);
597void arith::SubUIExtendedOp::getCanonicalizationPatterns(
598 RewritePatternSet &patterns, MLIRContext *context) {
599 patterns.
add<SubUIExtendedToSubI>(context);
606OpFoldResult arith::SubIOp::fold(FoldAdaptor adaptor) {
608 if (getOperand(0) == getOperand(1)) {
609 auto shapedType = dyn_cast<ShapedType>(
getType());
611 if (!shapedType || shapedType.hasStaticShape())
618 if (
auto add = getLhs().getDefiningOp<AddIOp>()) {
620 if (getRhs() ==
add.getRhs())
623 if (getRhs() ==
add.getLhs())
628 if (
auto sub = getRhs().getDefiningOp<SubIOp>())
629 if (getLhs() == sub.getLhs())
633 adaptor.getOperands(),
634 [](APInt a,
const APInt &
b) { return std::move(a) - b; });
637void arith::SubIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
638 MLIRContext *context) {
639 patterns.
add<SubIRHSAddConstant, SubILHSAddConstant, SubIRHSSubConstantRHS,
640 SubIRHSSubConstantLHS, SubILHSSubConstantRHS,
641 SubILHSSubConstantLHS, SubISubILHSRHSLHS>(context);
648OpFoldResult arith::MulIOp::fold(FoldAdaptor adaptor) {
659 adaptor.getOperands(),
660 [](
const APInt &a,
const APInt &
b) { return a * b; });
663void arith::MulIOp::getAsmResultNames(
665 if (!isa<IndexType>(
getType()))
670 auto isVscale = [](Operation *op) {
671 return op && op->getName().getStringRef() ==
"vector.vscale";
674 IntegerAttr baseValue;
675 auto isVscaleExpr = [&](Value a, Value
b) {
677 isVscale(
b.getDefiningOp());
680 if (!isVscaleExpr(getLhs(), getRhs()) && !isVscaleExpr(getRhs(), getLhs()))
684 SmallString<32> specialNameBuffer;
685 llvm::raw_svector_ostream specialName(specialNameBuffer);
686 specialName <<
'c' << baseValue.getInt() <<
"_vscale";
687 setNameFn(getResult(), specialName.str());
690void arith::MulIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
691 MLIRContext *context) {
692 patterns.
add<MulIMulIConstant>(context);
699std::optional<SmallVector<int64_t, 4>>
700arith::MulSIExtendedOp::getShapeForUnroll() {
701 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
702 return llvm::to_vector<4>(vt.getShape());
707arith::MulSIExtendedOp::fold(FoldAdaptor adaptor,
708 SmallVectorImpl<OpFoldResult> &results) {
711 Attribute zero = adaptor.getRhs();
712 results.push_back(zero);
713 results.push_back(zero);
719 adaptor.getOperands(),
720 [](
const APInt &a,
const APInt &
b) { return a * b; })) {
723 llvm::APIntOps::mulhs);
724 assert(highAttr &&
"Unexpected constant-folding failure");
726 results.push_back(lowAttr);
727 results.push_back(highAttr);
734void arith::MulSIExtendedOp::getCanonicalizationPatterns(
735 RewritePatternSet &patterns, MLIRContext *context) {
736 patterns.
add<MulSIExtendedToMulI, MulSIExtendedRHSOne>(context);
743std::optional<SmallVector<int64_t, 4>>
744arith::MulUIExtendedOp::getShapeForUnroll() {
745 if (
auto vt = dyn_cast<VectorType>(
getType(0)))
746 return llvm::to_vector<4>(vt.getShape());
751arith::MulUIExtendedOp::fold(FoldAdaptor adaptor,
752 SmallVectorImpl<OpFoldResult> &results) {
755 Attribute zero = adaptor.getRhs();
756 results.push_back(zero);
757 results.push_back(zero);
765 results.push_back(getLhs());
766 results.push_back(zero);
772 adaptor.getOperands(),
773 [](
const APInt &a,
const APInt &
b) { return a * b; })) {
776 llvm::APIntOps::mulhu);
777 assert(highAttr &&
"Unexpected constant-folding failure");
779 results.push_back(lowAttr);
780 results.push_back(highAttr);
787void arith::MulUIExtendedOp::getCanonicalizationPatterns(
788 RewritePatternSet &patterns, MLIRContext *context) {
789 patterns.
add<MulUIExtendedToMulI>(context);
798 arith::IntegerOverflowFlags ovfFlags) {
799 auto mul = lhs.getDefiningOp<mlir::arith::MulIOp>();
800 if (!
mul || !bitEnumContainsAll(
mul.getOverflowFlags(), ovfFlags))
803 if (
mul.getLhs() == rhs)
806 if (
mul.getRhs() == rhs)
812OpFoldResult arith::DivUIOp::fold(FoldAdaptor adaptor) {
826 if (getLhs() == getRhs())
830 if (Value val =
foldDivMul(getLhs(), getRhs(), IntegerOverflowFlags::nuw))
836 [&](APInt a,
const APInt &
b) {
844 return div0 ? Attribute() :
result;
864OpFoldResult arith::DivSIOp::fold(FoldAdaptor adaptor) {
878 if (getLhs() == getRhs())
882 if (Value val =
foldDivMul(getLhs(), getRhs(), IntegerOverflowFlags::nsw))
886 bool overflowOrDiv0 =
false;
888 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
889 if (overflowOrDiv0 || !b) {
890 overflowOrDiv0 = true;
893 return a.sdiv_ov(
b, overflowOrDiv0);
896 return overflowOrDiv0 ? Attribute() :
result;
920OpFoldResult arith::CeilDivUIOp::fold(FoldAdaptor adaptor) {
934 if (getLhs() == getRhs())
937 bool overflowOrDiv0 =
false;
939 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
940 if (overflowOrDiv0 || !b) {
941 overflowOrDiv0 = true;
944 APInt quotient = a.udiv(
b);
947 APInt one(a.getBitWidth(), 1,
true);
948 return quotient.uadd_ov(one, overflowOrDiv0);
951 return overflowOrDiv0 ? Attribute() :
result;
962OpFoldResult arith::CeilDivSIOp::fold(FoldAdaptor adaptor) {
976 if (getLhs() == getRhs())
980 bool overflowOrDiv0 =
false;
982 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
983 if (overflowOrDiv0 || !b) {
984 overflowOrDiv0 = true;
994 bool overflowDiv =
false;
995 APInt quotient = a.sdiv_ov(
b, overflowDiv);
999 overflowOrDiv0 =
true;
1002 if (a.isNegative() !=
b.isNegative() || quotient *
b == a)
1008 APInt one(a.getBitWidth(), 1,
true);
1009 return quotient.sadd_ov(one, overflowOrDiv0);
1012 return overflowOrDiv0 ? Attribute() :
result;
1023OpFoldResult arith::FloorDivSIOp::fold(FoldAdaptor adaptor) {
1037 if (getLhs() == getRhs())
1041 bool overflowOrDiv =
false;
1043 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
1045 overflowOrDiv = true;
1048 return a.sfloordiv_ov(
b, overflowOrDiv);
1051 return overflowOrDiv ? Attribute() :
result;
1058OpFoldResult arith::RemUIOp::fold(FoldAdaptor adaptor) {
1075 [&](APInt a,
const APInt &
b) {
1076 if (div0 || b.isZero()) {
1083 return div0 ? Attribute() :
result;
1094OpFoldResult arith::RemSIOp::fold(FoldAdaptor adaptor) {
1111 [&](APInt a,
const APInt &
b) {
1112 if (div0 || b.isZero()) {
1119 return div0 ? Attribute() :
result;
1137 for (
bool reversePrev : {
false,
true}) {
1138 auto prev = (reversePrev ? op.getRhs() : op.getLhs())
1139 .getDefiningOp<arith::AndIOp>();
1143 Value other = (reversePrev ? op.getLhs() : op.getRhs());
1144 if (other != prev.getLhs() && other != prev.getRhs())
1147 return prev.getResult();
1152OpFoldResult arith::AndIOp::fold(FoldAdaptor adaptor) {
1159 intValue.isAllOnes())
1164 intValue.isAllOnes())
1169 intValue.isAllOnes())
1177 adaptor.getOperands(),
1178 [](APInt a,
const APInt &
b) { return std::move(a) & b; });
1185OpFoldResult arith::OrIOp::fold(FoldAdaptor adaptor) {
1188 if (rhsVal.isZero())
1191 if (rhsVal.isAllOnes())
1192 return adaptor.getRhs();
1199 intValue.isAllOnes())
1200 return getRhs().getDefiningOp<XOrIOp>().getRhs();
1204 intValue.isAllOnes())
1205 return getLhs().getDefiningOp<XOrIOp>().getRhs();
1208 adaptor.getOperands(),
1209 [](APInt a,
const APInt &
b) { return std::move(a) | b; });
1216OpFoldResult arith::XOrIOp::fold(FoldAdaptor adaptor) {
1221 if (getLhs() == getRhs()) {
1224 auto shapedType = dyn_cast<ShapedType>(
getType());
1225 if (!shapedType || shapedType.hasStaticShape())
1230 if (arith::XOrIOp prev = getLhs().getDefiningOp<arith::XOrIOp>()) {
1231 if (prev.getRhs() == getRhs())
1232 return prev.getLhs();
1233 if (prev.getLhs() == getRhs())
1234 return prev.getRhs();
1238 if (arith::XOrIOp prev = getRhs().getDefiningOp<arith::XOrIOp>()) {
1239 if (prev.getRhs() == getLhs())
1240 return prev.getLhs();
1241 if (prev.getLhs() == getLhs())
1242 return prev.getRhs();
1246 adaptor.getOperands(),
1247 [](APInt a,
const APInt &
b) { return std::move(a) ^ b; });
1250void arith::XOrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1251 MLIRContext *context) {
1252 patterns.
add<XOrIXOrIConstant, XOrINotCmpI, XOrIOfExtUI, XOrIOfExtSI>(
1260OpFoldResult arith::NegFOp::fold(FoldAdaptor adaptor) {
1262 if (
auto op = this->getOperand().getDefiningOp<arith::NegFOp>())
1263 return op.getOperand();
1265 [](
const APFloat &a) { return -a; });
1272OpFoldResult arith::FlushDenormalsOp::fold(FoldAdaptor adaptor) {
1278 if (
auto op = this->getOperand().getDefiningOp<arith::FlushDenormalsOp>())
1279 return op.getResult();
1283 adaptor.getOperands(), [](
const APFloat &a) {
1285 return APFloat::getZero(a.getSemantics(), a.isNegative());
1294OpFoldResult arith::AddFOp::fold(FoldAdaptor adaptor) {
1299 bitEnumContainsAll(adaptor.getFastmath(), FastMathFlags::nsz))
1302 auto rm = getRoundingmode();
1304 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1306 result.add(b, convertArithRoundingModeToLLVMIR(rm));
1311void arith::AddFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1312 MLIRContext *context) {
1313 patterns.
add<AddFOfNegFLhs, AddFOfNegFRhs>(context);
1320OpFoldResult arith::SubFOp::fold(FoldAdaptor adaptor) {
1325 bitEnumContainsAll(adaptor.getFastmath(), FastMathFlags::nsz))
1328 auto rm = getRoundingmode();
1330 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1332 result.subtract(b, convertArithRoundingModeToLLVMIR(rm));
1337void arith::SubFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1338 MLIRContext *context) {
1339 patterns.
add<SubFOfNegZero>(context);
1352template <
typename TruncOp,
typename ExtOp,
typename ExtremumOp>
1353struct NarrowExtremum final : OpRewritePattern<TruncOp> {
1354 using OpRewritePattern<TruncOp>::OpRewritePattern;
1356 LogicalResult matchAndRewrite(TruncOp truncOp,
1357 PatternRewriter &rewriter)
const override {
1358 auto extremumOp = truncOp.getIn().template getDefiningOp<ExtremumOp>();
1359 if (!extremumOp || !extremumOp->hasOneUse())
1362 auto lhsExt = extremumOp.getLhs().template getDefiningOp<ExtOp>();
1363 auto rhsExt = extremumOp.getRhs().template getDefiningOp<ExtOp>();
1364 if (!lhsExt || !rhsExt)
1367 Value
lhs = lhsExt.getIn();
1368 Value
rhs = rhsExt.getIn();
1369 Type narrowType = truncOp.getType();
1370 if (
lhs.getType() != narrowType ||
rhs.getType() != narrowType)
1379 if (
auto narrowFloatType =
1381 auto wideFloatType =
1386 const llvm::fltSemantics &narrowSemantics =
1387 narrowFloatType.getFloatSemantics();
1388 const llvm::fltSemantics &wideSemantics =
1389 wideFloatType.getFloatSemantics();
1390 bool ignoreNaNs =
false;
1391 if constexpr (std::is_same_v<TruncOp, TruncFOp>)
1393 bitEnumContainsAll(extremumOp.getFastmath(), FastMathFlags::nnan);
1394 if (!llvm::APFloatBase::isLosslesslyConvertibleTo(
1395 narrowSemantics, wideSemantics, ignoreNaNs))
1401 extremumOp.getProperties(),
1402 extremumOp->getDiscardableAttrDictionary().getValue());
1413OpFoldResult arith::MaximumFOp::fold(FoldAdaptor adaptor) {
1415 if (getLhs() == getRhs())
1429OpFoldResult arith::MaxNumFOp::fold(FoldAdaptor adaptor) {
1431 if (getLhs() == getRhs())
1445OpFoldResult MaxSIOp::fold(FoldAdaptor adaptor) {
1447 if (getLhs() == getRhs())
1453 if (intValue.isMaxSignedValue())
1456 if (intValue.isMinSignedValue())
1461 llvm::APIntOps::smax);
1468OpFoldResult MaxUIOp::fold(FoldAdaptor adaptor) {
1470 if (getLhs() == getRhs())
1476 if (intValue.isMaxValue())
1479 if (intValue.isMinValue())
1484 llvm::APIntOps::umax);
1491OpFoldResult arith::MinimumFOp::fold(FoldAdaptor adaptor) {
1493 if (getLhs() == getRhs())
1507OpFoldResult arith::MinNumFOp::fold(FoldAdaptor adaptor) {
1509 if (getLhs() == getRhs())
1523OpFoldResult MinSIOp::fold(FoldAdaptor adaptor) {
1525 if (getLhs() == getRhs())
1531 if (intValue.isMinSignedValue())
1534 if (intValue.isMaxSignedValue())
1539 llvm::APIntOps::smin);
1546OpFoldResult MinUIOp::fold(FoldAdaptor adaptor) {
1548 if (getLhs() == getRhs())
1554 if (intValue.isMinValue())
1557 if (intValue.isMaxValue())
1562 llvm::APIntOps::umin);
1569OpFoldResult arith::MulFOp::fold(FoldAdaptor adaptor) {
1574 if (arith::bitEnumContainsAll(getFastmath(), arith::FastMathFlags::nnan |
1575 arith::FastMathFlags::nsz)) {
1581 auto rm = getRoundingmode();
1583 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1585 result.multiply(b, convertArithRoundingModeToLLVMIR(rm));
1590void arith::MulFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1591 MLIRContext *context) {
1592 patterns.
add<MulFOfNegF>(context);
1599OpFoldResult arith::DivFOp::fold(FoldAdaptor adaptor) {
1604 auto rm = getRoundingmode();
1606 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1608 result.divide(b, convertArithRoundingModeToLLVMIR(rm));
1613void arith::DivFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1614 MLIRContext *context) {
1615 patterns.
add<DivFOfNegF>(context);
1622OpFoldResult arith::RemFOp::fold(FoldAdaptor adaptor) {
1624 [](
const APFloat &a,
const APFloat &
b) {
1629 (void)result.mod(b);
1638template <
typename... Types>
1644template <
typename... ShapedTypes,
typename... ElementTypes>
1647 if (llvm::isa<ShapedType>(type) && !llvm::isa<ShapedTypes...>(type))
1651 if (!llvm::isa<ElementTypes...>(underlyingType))
1654 return underlyingType;
1658template <
typename... ElementTypes>
1665template <
typename... ElementTypes>
1674 auto rankedTensorA = dyn_cast<RankedTensorType>(typeA);
1675 auto rankedTensorB = dyn_cast<RankedTensorType>(typeB);
1676 if (!rankedTensorA || !rankedTensorB)
1678 return rankedTensorA.getEncoding() == rankedTensorB.getEncoding();
1682 if (inputs.size() != 1 || outputs.size() != 1)
1694template <
typename ValType,
typename Op>
1699 if (llvm::cast<ValType>(srcType).getWidth() >=
1700 llvm::cast<ValType>(dstType).getWidth())
1702 << dstType <<
" must be wider than operand type " << srcType;
1708template <
typename ValType,
typename Op>
1713 if (llvm::cast<ValType>(srcType).getWidth() <=
1714 llvm::cast<ValType>(dstType).getWidth())
1716 << dstType <<
" must be shorter than operand type " << srcType;
1722template <
template <
typename>
class WidthComparator,
typename... ElementTypes>
1727 auto srcType =
getTypeIfLike<ElementTypes...>(inputs.front());
1728 auto dstType =
getTypeIfLike<ElementTypes...>(outputs.front());
1729 if (!srcType || !dstType)
1732 return WidthComparator<unsigned>()(dstType.getIntOrFloatBitWidth(),
1733 srcType.getIntOrFloatBitWidth());
1738static FailureOr<APFloat>
1740 const llvm::fltSemantics &targetSemantics,
1744 using fltNonfiniteBehavior = llvm::fltNonfiniteBehavior;
1745 if (sourceValue.isInfinity() &&
1746 (targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
1747 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly))
1749 if (sourceValue.isNaN() &&
1750 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
1753 bool losesInfo =
false;
1754 auto status = sourceValue.convert(targetSemantics, roundingMode, &losesInfo);
1755 if (losesInfo || status != APFloat::opOK)
1765OpFoldResult arith::ExtUIOp::fold(FoldAdaptor adaptor) {
1766 if (
auto lhs = getIn().getDefiningOp<ExtUIOp>()) {
1769 setNonNeg(
lhs.getNonNeg());
1770 getInMutable().assign(
lhs.getIn());
1775 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1777 adaptor.getOperands(),
getType(),
1778 [bitWidth](
const APInt &a,
bool &castStatus) {
1779 return a.zext(bitWidth);
1787LogicalResult arith::ExtUIOp::verify() {
1795OpFoldResult arith::ExtSIOp::fold(FoldAdaptor adaptor) {
1796 if (
auto lhs = getIn().getDefiningOp<ExtSIOp>()) {
1797 getInMutable().assign(
lhs.getIn());
1802 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1804 adaptor.getOperands(),
getType(),
1805 [bitWidth](
const APInt &a,
bool &castStatus) {
1806 return a.sext(bitWidth);
1814void arith::ExtSIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1815 MLIRContext *context) {
1816 patterns.
add<ExtSIOfExtUI>(context);
1819LogicalResult arith::ExtSIOp::verify() {
1829OpFoldResult arith::ExtFOp::fold(FoldAdaptor adaptor) {
1830 if (
auto truncFOp = getOperand().getDefiningOp<TruncFOp>()) {
1831 if (truncFOp.getOperand().getType() ==
getType()) {
1832 arith::FastMathFlags truncFMF =
1833 truncFOp.getFastmath().value_or(arith::FastMathFlags::none);
1834 bool isTruncContract =
1835 bitEnumContainsAll(truncFMF, arith::FastMathFlags::contract);
1836 arith::FastMathFlags extFMF =
1837 getFastmath().value_or(arith::FastMathFlags::none);
1838 bool isExtContract =
1839 bitEnumContainsAll(extFMF, arith::FastMathFlags::contract);
1840 if (isTruncContract && isExtContract) {
1841 return truncFOp.getOperand();
1847 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
1849 adaptor.getOperands(),
getType(),
1850 [&targetSemantics](
const APFloat &a,
bool &castStatus) {
1875 function_ref<std::optional<APFloat>(
const APFloat &,
const APFloat &)>
1878 if (isa_and_nonnull<ub::PoisonAttr>(inAttr))
1880 if (isa_and_nonnull<ub::PoisonAttr>(scaleAttr))
1883 if (!inAttr || !scaleAttr || !resultType)
1886 if (
auto inFloat = dyn_cast<FloatAttr>(inAttr)) {
1887 auto scaleFloat = dyn_cast<FloatAttr>(scaleAttr);
1890 std::optional<APFloat>
result =
1891 calculate(inFloat.getValue(), scaleFloat.getValue());
1894 return FloatAttr::get(resultType, *
result);
1897 auto inElements = dyn_cast<DenseFPElementsAttr>(inAttr);
1898 auto scaleElements = dyn_cast<DenseFPElementsAttr>(scaleAttr);
1899 auto shapedResultType = dyn_cast<ShapedType>(resultType);
1900 if (!inElements || !scaleElements || !shapedResultType ||
1901 !shapedResultType.hasStaticShape() ||
1902 inElements.getNumElements() != scaleElements.getNumElements())
1906 if (inElements.isSplat() && scaleElements.isSplat()) {
1907 std::optional<APFloat>
result =
1908 calculate(inElements.getSplatValue<APFloat>(),
1909 scaleElements.getSplatValue<APFloat>());
1916 results.reserve(inElements.getNumElements());
1917 for (
const auto &[in, scale] : llvm::zip_equal(inElements, scaleElements)) {
1918 std::optional<APFloat>
result = calculate(in, scale);
1921 results.push_back(*
result);
1934OpFoldResult arith::ScalingExtFOp::fold(FoldAdaptor adaptor) {
1942 const llvm::fltSemantics &resSemantics = resElemType.getFloatSemantics();
1944 adaptor.getIn(), adaptor.getScale(),
getType(),
1945 [&resSemantics](
const APFloat &in,
1946 const APFloat &scale) -> std::optional<APFloat> {
1950 return std::nullopt;
1957bool arith::ScalingExtFOp::areCastCompatible(
TypeRange inputs,
1962LogicalResult arith::ScalingExtFOp::verify() {
1970OpFoldResult arith::TruncIOp::fold(FoldAdaptor adaptor) {
1973 Value src = getOperand().getDefiningOp()->getOperand(0);
1978 if (llvm::cast<IntegerType>(srcType).getWidth() >
1979 llvm::cast<IntegerType>(dstType).getWidth()) {
1986 if (srcType == dstType)
1992 setOperand(getOperand().getDefiningOp()->getOperand(0));
1997 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1999 adaptor.getOperands(),
getType(),
2000 [bitWidth](
const APInt &a,
bool &castStatus) {
2001 return a.trunc(bitWidth);
2009void arith::TruncIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2010 MLIRContext *context) {
2011 patterns.
add<NarrowExtremum<TruncIOp, ExtSIOp, MaxSIOp>,
2012 NarrowExtremum<TruncIOp, ExtSIOp, MinSIOp>,
2013 NarrowExtremum<TruncIOp, ExtUIOp, MaxUIOp>,
2014 NarrowExtremum<TruncIOp, ExtUIOp, MinUIOp>, TruncIExtSIToExtSI,
2015 TruncIExtUIToExtUI, TruncIShrSIToTrunciShrUI>(context);
2018LogicalResult arith::TruncIOp::verify() {
2028OpFoldResult arith::TruncFOp::fold(FoldAdaptor adaptor) {
2030 if (
auto extOp = getOperand().getDefiningOp<arith::ExtFOp>()) {
2031 Value src = extOp.getIn();
2033 auto intermediateType =
2037 if (llvm::APFloatBase::isLosslesslyConvertibleTo(
2038 srcType.getFloatSemantics(),
2039 intermediateType.getFloatSemantics())) {
2041 if (srcType.getWidth() > resElemType.getWidth()) {
2047 if (srcType == resElemType)
2052 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
2054 adaptor.getOperands(),
getType(),
2055 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
2056 llvm::RoundingMode llvmRoundingMode =
2058 FailureOr<APFloat>
result =
2068void arith::TruncFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2069 MLIRContext *context) {
2070 patterns.
add<NarrowExtremum<TruncFOp, ExtFOp, MaximumFOp>,
2071 NarrowExtremum<TruncFOp, ExtFOp, MaxNumFOp>,
2072 NarrowExtremum<TruncFOp, ExtFOp, MinimumFOp>,
2073 NarrowExtremum<TruncFOp, ExtFOp, MinNumFOp>,
2074 TruncFSIToFPToSIToFP, TruncFUIToFPToUIToFP>(context);
2081LogicalResult arith::TruncFOp::verify() {
2089OpFoldResult arith::ConvertFOp::fold(FoldAdaptor adaptor) {
2091 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
2093 adaptor.getOperands(),
getType(),
2094 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
2095 llvm::RoundingMode llvmRoundingMode =
2097 FailureOr<APFloat>
result =
2112 if (!srcType || !dstType)
2114 return srcType != dstType &&
2118LogicalResult arith::ConvertFOp::verify() {
2121 if (srcType == dstType)
2122 return emitError(
"result element type ")
2123 << dstType <<
" must be different from operand element type "
2125 if (srcType.getWidth() != dstType.getWidth())
2126 return emitError(
"result element type ")
2127 << dstType <<
" must have the same bitwidth as operand element type "
2136OpFoldResult arith::ScalingTruncFOp::fold(FoldAdaptor adaptor) {
2145 const llvm::fltSemantics &inSemantics = inElemType.getFloatSemantics();
2146 const llvm::fltSemantics &resSemantics = resElemType.getFloatSemantics();
2147 llvm::RoundingMode roundingMode =
2150 adaptor.getIn(), adaptor.getScale(),
getType(),
2151 [&](
const APFloat &in,
const APFloat &scale) -> std::optional<APFloat> {
2154 return std::nullopt;
2155 APFloat quotient(in);
2157 FailureOr<APFloat>
result =
2160 return std::nullopt;
2165bool arith::ScalingTruncFOp::areCastCompatible(
TypeRange inputs,
2170LogicalResult arith::ScalingTruncFOp::verify() {
2178void arith::AndIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2179 MLIRContext *context) {
2180 patterns.
add<AndIAndIConstant, AndOfExtUI, AndOfExtSI>(context);
2187void arith::OrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2188 MLIRContext *context) {
2189 patterns.
add<OrIOrIConstant, OrOfExtUI, OrOfExtSI>(context);
2196template <
typename From,
typename To>
2204 return srcType && dstType;
2215OpFoldResult arith::UIToFPOp::fold(FoldAdaptor adaptor) {
2218 adaptor.getOperands(),
getType(),
2219 [&resEleType](
const APInt &a,
bool &castStatus) {
2220 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2221 APFloat apf(floatTy.getFloatSemantics(),
2222 APInt::getZero(floatTy.getWidth()));
2223 apf.convertFromAPInt(a,
false,
2224 APFloat::rmNearestTiesToEven);
2229void arith::UIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2230 MLIRContext *context) {
2231 patterns.
add<UIToFPOfExtUI>(context);
2242OpFoldResult arith::SIToFPOp::fold(FoldAdaptor adaptor) {
2245 adaptor.getOperands(),
getType(),
2246 [&resEleType](
const APInt &a,
bool &castStatus) {
2247 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2248 APFloat apf(floatTy.getFloatSemantics(),
2249 APInt::getZero(floatTy.getWidth()));
2250 apf.convertFromAPInt(a,
true,
2251 APFloat::rmNearestTiesToEven);
2256void arith::SIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2257 MLIRContext *context) {
2258 patterns.
add<SIToFPOfExtSI, SIToFPOfExtUI>(context);
2269OpFoldResult arith::FPToUIOp::fold(FoldAdaptor adaptor) {
2271 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2273 adaptor.getOperands(),
getType(),
2274 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2276 APSInt api(bitWidth,
true);
2277 castStatus = APFloat::opInvalidOp !=
2278 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2291OpFoldResult arith::FPToSIOp::fold(FoldAdaptor adaptor) {
2293 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2295 adaptor.getOperands(),
getType(),
2296 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2298 APSInt api(bitWidth,
false);
2299 castStatus = APFloat::opInvalidOp !=
2300 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2314 return intTy.getWidth();
2315 return IndexType::kInternalStorageBitWidth;
2324 if (!srcType || !dstType)
2328 (srcType.isSignlessInteger() && dstType.
isIndex());
2331bool arith::IndexCastOp::areCastCompatible(
TypeRange inputs,
2336OpFoldResult arith::IndexCastOp::fold(FoldAdaptor adaptor) {
2338 unsigned resultBitwidth = 64;
2340 resultBitwidth = intTy.getWidth();
2343 adaptor.getOperands(),
getType(),
2344 [resultBitwidth](
const APInt &a,
bool & ) {
2345 return a.sextOrTrunc(resultBitwidth);
2352 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastOp>()) {
2353 Value x = inner.getOperand();
2362void arith::IndexCastOp::getCanonicalizationPatterns(
2363 RewritePatternSet &patterns, MLIRContext *context) {
2364 patterns.
add<IndexCastOfExtSI>(context);
2371bool arith::IndexCastUIOp::areCastCompatible(
TypeRange inputs,
2376OpFoldResult arith::IndexCastUIOp::fold(FoldAdaptor adaptor) {
2378 unsigned resultBitwidth = 64;
2380 resultBitwidth = intTy.getWidth();
2383 adaptor.getOperands(),
getType(),
2384 [resultBitwidth](
const APInt &a,
bool & ) {
2385 return a.zextOrTrunc(resultBitwidth);
2392 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastUIOp>()) {
2393 Value x = inner.getOperand();
2402void arith::IndexCastUIOp::getCanonicalizationPatterns(
2403 RewritePatternSet &patterns, MLIRContext *context) {
2404 patterns.
add<IndexCastUIOfExtUI>(context);
2417 if (!srcType || !dstType)
2423OpFoldResult arith::BitcastOp::fold(FoldAdaptor adaptor) {
2425 auto operand = adaptor.getIn();
2430 if (
auto denseAttr = dyn_cast_or_null<DenseElementsAttr>(operand))
2431 return denseAttr.bitcast(llvm::cast<ShapedType>(resType).
getElementType());
2433 if (llvm::isa<ShapedType>(resType))
2441 if (!llvm::isa<FloatAttr, IntegerAttr>(operand))
2444 APInt bits = llvm::isa<FloatAttr>(operand)
2445 ? llvm::cast<FloatAttr>(operand).getValue().bitcastToAPInt()
2446 : llvm::cast<IntegerAttr>(operand).getValue();
2448 "trying to fold on broken IR: operands have incompatible types");
2450 if (
auto resFloatType = dyn_cast<FloatType>(resType))
2451 return FloatAttr::get(resType,
2452 APFloat(resFloatType.getFloatSemantics(), bits));
2453 return IntegerAttr::get(resType, bits);
2456void arith::BitcastOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2457 MLIRContext *context) {
2458 patterns.
add<BitcastOfBitcast>(context);
2468 const APInt &lhs,
const APInt &rhs) {
2469 switch (predicate) {
2470 case arith::CmpIPredicate::eq:
2472 case arith::CmpIPredicate::ne:
2474 case arith::CmpIPredicate::slt:
2475 return lhs.slt(rhs);
2476 case arith::CmpIPredicate::sle:
2477 return lhs.sle(rhs);
2478 case arith::CmpIPredicate::sgt:
2479 return lhs.sgt(rhs);
2480 case arith::CmpIPredicate::sge:
2481 return lhs.sge(rhs);
2482 case arith::CmpIPredicate::ult:
2483 return lhs.ult(rhs);
2484 case arith::CmpIPredicate::ule:
2485 return lhs.ule(rhs);
2486 case arith::CmpIPredicate::ugt:
2487 return lhs.ugt(rhs);
2488 case arith::CmpIPredicate::uge:
2489 return lhs.uge(rhs);
2491 llvm_unreachable(
"unknown cmpi predicate kind");
2496 switch (predicate) {
2497 case arith::CmpIPredicate::eq:
2498 case arith::CmpIPredicate::sle:
2499 case arith::CmpIPredicate::sge:
2500 case arith::CmpIPredicate::ule:
2501 case arith::CmpIPredicate::uge:
2503 case arith::CmpIPredicate::ne:
2504 case arith::CmpIPredicate::slt:
2505 case arith::CmpIPredicate::sgt:
2506 case arith::CmpIPredicate::ult:
2507 case arith::CmpIPredicate::ugt:
2510 llvm_unreachable(
"unknown cmpi predicate kind");
2514 if (
auto intType = dyn_cast<IntegerType>(t)) {
2515 return intType.getWidth();
2517 if (
auto vectorIntType = dyn_cast<VectorType>(t)) {
2518 return llvm::cast<IntegerType>(vectorIntType.getElementType()).getWidth();
2520 return std::nullopt;
2523OpFoldResult arith::CmpIOp::fold(FoldAdaptor adaptor) {
2525 if (getLhs() == getRhs()) {
2531 if (
auto extOp = getLhs().getDefiningOp<ExtSIOp>()) {
2533 std::optional<int64_t> integerWidth =
2535 if (integerWidth && integerWidth.value() == 1 &&
2536 getPredicate() == arith::CmpIPredicate::ne)
2537 return extOp.getOperand();
2539 if (
auto extOp = getLhs().getDefiningOp<ExtUIOp>()) {
2541 std::optional<int64_t> integerWidth =
2543 if (integerWidth && integerWidth.value() == 1 &&
2544 getPredicate() == arith::CmpIPredicate::ne)
2545 return extOp.getOperand();
2550 getPredicate() == arith::CmpIPredicate::ne)
2557 getPredicate() == arith::CmpIPredicate::eq)
2562 if (adaptor.getLhs() && !adaptor.getRhs()) {
2564 using Pred = CmpIPredicate;
2565 const std::pair<Pred, Pred> invPreds[] = {
2566 {Pred::slt, Pred::sgt}, {Pred::sgt, Pred::slt}, {Pred::sle, Pred::sge},
2567 {Pred::sge, Pred::sle}, {Pred::ult, Pred::ugt}, {Pred::ugt, Pred::ult},
2568 {Pred::ule, Pred::uge}, {Pred::uge, Pred::ule}, {Pred::eq, Pred::eq},
2569 {Pred::ne, Pred::ne},
2571 Pred origPred = getPredicate();
2572 for (
auto pred : invPreds) {
2573 if (origPred == pred.first) {
2574 setPredicate(pred.second);
2575 Value
lhs = getLhs();
2576 Value
rhs = getRhs();
2577 getLhsMutable().assign(
rhs);
2578 getRhsMutable().assign(
lhs);
2582 llvm_unreachable(
"unknown cmpi predicate kind");
2587 if (
auto lhs = dyn_cast_if_present<TypedAttr>(adaptor.getLhs())) {
2590 [pred = getPredicate()](
const APInt &
lhs,
const APInt &
rhs) {
2599void arith::CmpIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2600 MLIRContext *context) {
2601 patterns.
insert<CmpIExtSI, CmpIExtUI>(context);
2611 const APFloat &lhs,
const APFloat &rhs) {
2612 auto cmpResult = lhs.compare(rhs);
2613 switch (predicate) {
2614 case arith::CmpFPredicate::AlwaysFalse:
2616 case arith::CmpFPredicate::OEQ:
2617 return cmpResult == APFloat::cmpEqual;
2618 case arith::CmpFPredicate::OGT:
2619 return cmpResult == APFloat::cmpGreaterThan;
2620 case arith::CmpFPredicate::OGE:
2621 return cmpResult == APFloat::cmpGreaterThan ||
2622 cmpResult == APFloat::cmpEqual;
2623 case arith::CmpFPredicate::OLT:
2624 return cmpResult == APFloat::cmpLessThan;
2625 case arith::CmpFPredicate::OLE:
2626 return cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2627 case arith::CmpFPredicate::ONE:
2628 return cmpResult != APFloat::cmpUnordered && cmpResult != APFloat::cmpEqual;
2629 case arith::CmpFPredicate::ORD:
2630 return cmpResult != APFloat::cmpUnordered;
2631 case arith::CmpFPredicate::UEQ:
2632 return cmpResult == APFloat::cmpUnordered || cmpResult == APFloat::cmpEqual;
2633 case arith::CmpFPredicate::UGT:
2634 return cmpResult == APFloat::cmpUnordered ||
2635 cmpResult == APFloat::cmpGreaterThan;
2636 case arith::CmpFPredicate::UGE:
2637 return cmpResult == APFloat::cmpUnordered ||
2638 cmpResult == APFloat::cmpGreaterThan ||
2639 cmpResult == APFloat::cmpEqual;
2640 case arith::CmpFPredicate::ULT:
2641 return cmpResult == APFloat::cmpUnordered ||
2642 cmpResult == APFloat::cmpLessThan;
2643 case arith::CmpFPredicate::ULE:
2644 return cmpResult == APFloat::cmpUnordered ||
2645 cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2646 case arith::CmpFPredicate::UNE:
2647 return cmpResult != APFloat::cmpEqual;
2648 case arith::CmpFPredicate::UNO:
2649 return cmpResult == APFloat::cmpUnordered;
2650 case arith::CmpFPredicate::AlwaysTrue:
2653 llvm_unreachable(
"unknown cmpf predicate kind");
2657 auto lhs = dyn_cast_if_present<FloatAttr>(adaptor.getLhs());
2658 auto rhs = dyn_cast_if_present<FloatAttr>(adaptor.getRhs());
2661 if (lhs && lhs.getValue().isNaN())
2663 if (rhs && rhs.getValue().isNaN())
2679 using namespace arith;
2681 case CmpFPredicate::UEQ:
2682 case CmpFPredicate::OEQ:
2683 return CmpIPredicate::eq;
2684 case CmpFPredicate::UGT:
2685 case CmpFPredicate::OGT:
2686 return isUnsigned ? CmpIPredicate::ugt : CmpIPredicate::sgt;
2687 case CmpFPredicate::UGE:
2688 case CmpFPredicate::OGE:
2689 return isUnsigned ? CmpIPredicate::uge : CmpIPredicate::sge;
2690 case CmpFPredicate::ULT:
2691 case CmpFPredicate::OLT:
2692 return isUnsigned ? CmpIPredicate::ult : CmpIPredicate::slt;
2693 case CmpFPredicate::ULE:
2694 case CmpFPredicate::OLE:
2695 return isUnsigned ? CmpIPredicate::ule : CmpIPredicate::sle;
2696 case CmpFPredicate::UNE:
2697 case CmpFPredicate::ONE:
2698 return CmpIPredicate::ne;
2700 llvm_unreachable(
"Unexpected predicate!");
2710 const APFloat &rhs = flt.getValue();
2718 FloatType floatTy = llvm::cast<FloatType>(op.getRhs().getType());
2719 int mantissaWidth = floatTy.getFPMantissaWidth();
2720 if (mantissaWidth <= 0)
2726 if (
auto si = op.getLhs().getDefiningOp<SIToFPOp>()) {
2728 intVal = si.getIn();
2729 }
else if (
auto ui = op.getLhs().getDefiningOp<UIToFPOp>()) {
2731 intVal = ui.getIn();
2738 auto intTy = llvm::cast<IntegerType>(intVal.
getType());
2739 auto intWidth = intTy.getWidth();
2742 auto valueBits = isUnsigned ? intWidth : (intWidth - 1);
2747 if ((
int)intWidth > mantissaWidth) {
2749 int exponent = ilogb(rhs);
2750 if (exponent == APFloat::IEK_Inf) {
2751 int maxExponent = ilogb(APFloat::getLargest(rhs.getSemantics()));
2752 if (maxExponent < (
int)valueBits) {
2759 if (mantissaWidth <= exponent && exponent <= (
int)valueBits) {
2768 switch (op.getPredicate()) {
2769 case CmpFPredicate::ORD:
2774 case CmpFPredicate::UNO:
2787 APFloat signedMax(rhs.getSemantics());
2788 signedMax.convertFromAPInt(APInt::getSignedMaxValue(intWidth),
true,
2789 APFloat::rmNearestTiesToEven);
2790 if (signedMax < rhs) {
2791 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::slt ||
2792 pred == CmpIPredicate::sle)
2803 APFloat unsignedMax(rhs.getSemantics());
2804 unsignedMax.convertFromAPInt(APInt::getMaxValue(intWidth),
false,
2805 APFloat::rmNearestTiesToEven);
2806 if (unsignedMax < rhs) {
2807 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ult ||
2808 pred == CmpIPredicate::ule)
2820 APFloat signedMin(rhs.getSemantics());
2821 signedMin.convertFromAPInt(APInt::getSignedMinValue(intWidth),
true,
2822 APFloat::rmNearestTiesToEven);
2823 if (signedMin > rhs) {
2824 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::sgt ||
2825 pred == CmpIPredicate::sge)
2835 APFloat unsignedMin(rhs.getSemantics());
2836 unsignedMin.convertFromAPInt(APInt::getMinValue(intWidth),
false,
2837 APFloat::rmNearestTiesToEven);
2838 if (unsignedMin > rhs) {
2839 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ugt ||
2840 pred == CmpIPredicate::uge)
2855 APSInt rhsInt(intWidth, isUnsigned);
2856 if (APFloat::opInvalidOp ==
2857 rhs.convertToInteger(rhsInt, APFloat::rmTowardZero, &ignored)) {
2863 if (!rhs.isZero()) {
2864 APFloat apf(floatTy.getFloatSemantics(),
2865 APInt::getZero(floatTy.getWidth()));
2866 apf.convertFromAPInt(rhsInt, !isUnsigned, APFloat::rmNearestTiesToEven);
2868 bool equal = apf == rhs;
2874 case CmpIPredicate::ne:
2878 case CmpIPredicate::eq:
2882 case CmpIPredicate::ule:
2885 if (rhs.isNegative()) {
2891 case CmpIPredicate::sle:
2894 if (rhs.isNegative())
2895 pred = CmpIPredicate::slt;
2897 case CmpIPredicate::ult:
2900 if (rhs.isNegative()) {
2905 pred = CmpIPredicate::ule;
2907 case CmpIPredicate::slt:
2910 if (!rhs.isNegative())
2911 pred = CmpIPredicate::sle;
2913 case CmpIPredicate::ugt:
2916 if (rhs.isNegative()) {
2922 case CmpIPredicate::sgt:
2925 if (rhs.isNegative())
2926 pred = CmpIPredicate::sge;
2928 case CmpIPredicate::uge:
2931 if (rhs.isNegative()) {
2936 pred = CmpIPredicate::ugt;
2938 case CmpIPredicate::sge:
2941 if (!rhs.isNegative())
2942 pred = CmpIPredicate::sgt;
2952 ConstantOp::create(rewriter, op.getLoc(), intVal.
getType(),
2958void arith::CmpFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2959 MLIRContext *context) {
2960 patterns.
insert<CmpFIntToFPConst>(context);
2974 if (!llvm::isa<IntegerType>(op.getType()) || op.getType().isInteger(1))
2990 arith::XOrIOp::create(
2991 rewriter, op.getLoc(), op.getCondition(),
2993 op.getCondition().
getType(), 1)));
3001void arith::SelectOp::getCanonicalizationPatterns(RewritePatternSet &results,
3002 MLIRContext *context) {
3003 results.
add<RedundantSelectFalse, RedundantSelectTrue, SelectNotCond,
3004 SelectI1ToNot, SelectCmpISgeToMaxSI, SelectCmpISgeToMinSI,
3005 SelectCmpISgtToMaxSI, SelectCmpISgtToMinSI, SelectCmpISleToMaxSI,
3006 SelectCmpISleToMinSI, SelectCmpISltToMaxSI, SelectCmpISltToMinSI,
3007 SelectCmpIUgeToMaxUI, SelectCmpIUgeToMinUI, SelectCmpIUgtToMaxUI,
3008 SelectCmpIUgtToMinUI, SelectCmpIUleToMaxUI, SelectCmpIUleToMinUI,
3009 SelectCmpIUltToMaxUI, SelectCmpIUltToMinUI, SelectToExtUI>(
3013OpFoldResult arith::SelectOp::fold(FoldAdaptor adaptor) {
3014 Value trueVal = getTrueValue();
3015 Value falseVal = getFalseValue();
3016 if (trueVal == falseVal)
3019 Value condition = getCondition();
3037 if (
getType().isSignlessInteger(1) &&
3043 auto pred = cmp.getPredicate();
3044 if (pred == arith::CmpIPredicate::eq || pred == arith::CmpIPredicate::ne) {
3045 auto cmpLhs = cmp.getLhs();
3046 auto cmpRhs = cmp.getRhs();
3054 if ((cmpLhs == trueVal && cmpRhs == falseVal) ||
3055 (cmpRhs == trueVal && cmpLhs == falseVal))
3056 return pred == arith::CmpIPredicate::ne ? trueVal : falseVal;
3063 dyn_cast_if_present<DenseElementsAttr>(adaptor.getCondition())) {
3065 assert(cond.getType().hasStaticShape() &&
3066 "DenseElementsAttr must have static shape");
3068 dyn_cast_if_present<DenseElementsAttr>(adaptor.getTrueValue())) {
3070 dyn_cast_if_present<DenseElementsAttr>(adaptor.getFalseValue())) {
3071 SmallVector<Attribute> results;
3072 results.reserve(
static_cast<size_t>(cond.getNumElements()));
3073 auto condVals = llvm::make_range(cond.value_begin<BoolAttr>(),
3074 cond.value_end<BoolAttr>());
3075 auto lhsVals = llvm::make_range(
lhs.value_begin<Attribute>(),
3076 lhs.value_end<Attribute>());
3077 auto rhsVals = llvm::make_range(
rhs.value_begin<Attribute>(),
3078 rhs.value_end<Attribute>());
3080 for (
auto [condVal, lhsVal, rhsVal] :
3081 llvm::zip_equal(condVals, lhsVals, rhsVals))
3082 results.push_back(condVal.getValue() ? lhsVal : rhsVal);
3092ParseResult SelectOp::parse(OpAsmParser &parser, OperationState &
result) {
3093 Type conditionType, resultType;
3094 SmallVector<OpAsmParser::UnresolvedOperand, 3> operands;
3102 conditionType = resultType;
3109 result.addTypes(resultType);
3111 {conditionType, resultType, resultType},
3115void arith::SelectOp::print(OpAsmPrinter &p) {
3116 p <<
" " << getOperands();
3119 if (ShapedType condType = dyn_cast<ShapedType>(getCondition().
getType()))
3120 p << condType <<
", ";
3124LogicalResult arith::SelectOp::verify() {
3125 Type conditionType = getCondition().getType();
3132 if (!llvm::isa<TensorType, VectorType>(resultType))
3133 return emitOpError() <<
"expected condition to be a signless i1, but got "
3136 if (conditionType != shapedConditionType) {
3137 return emitOpError() <<
"expected condition type to have the same shape "
3138 "as the result type, expected "
3139 << shapedConditionType <<
", but got "
3148OpFoldResult arith::ShLIOp::fold(FoldAdaptor adaptor) {
3162 bool bounded =
false;
3164 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3165 bounded = b.ult(b.getBitWidth());
3168 return bounded ?
result : Attribute();
3175OpFoldResult arith::ShRUIOp::fold(FoldAdaptor adaptor) {
3190 if (getLhs() == getRhs())
3193 bool bounded =
false;
3195 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3196 bounded = b.ult(b.getBitWidth());
3199 return bounded ?
result : Attribute();
3206OpFoldResult arith::ShRSIOp::fold(FoldAdaptor adaptor) {
3221 if (getLhs() == getRhs())
3229 bool bounded =
false;
3231 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3232 bounded = b.ult(b.getBitWidth());
3235 return bounded ?
result : Attribute();
3245 bool useOnlyFiniteValue) {
3247 case AtomicRMWKind::maximumf: {
3248 const llvm::fltSemantics &semantic =
3249 llvm::cast<FloatType>(resultType).getFloatSemantics();
3250 APFloat identity = useOnlyFiniteValue
3251 ? APFloat::getLargest(semantic,
true)
3252 : APFloat::getInf(semantic,
true);
3255 case AtomicRMWKind::maxnumf: {
3256 const llvm::fltSemantics &semantic =
3257 llvm::cast<FloatType>(resultType).getFloatSemantics();
3258 APFloat identity = APFloat::getNaN(semantic,
true);
3261 case AtomicRMWKind::addf:
3262 case AtomicRMWKind::addi:
3263 case AtomicRMWKind::maxu:
3264 case AtomicRMWKind::ori:
3265 case AtomicRMWKind::xori:
3267 case AtomicRMWKind::andi:
3270 APInt::getAllOnes(llvm::cast<IntegerType>(resultType).getWidth()));
3271 case AtomicRMWKind::maxs:
3273 resultType, APInt::getSignedMinValue(
3274 llvm::cast<IntegerType>(resultType).getWidth()));
3275 case AtomicRMWKind::minimumf: {
3276 const llvm::fltSemantics &semantic =
3277 llvm::cast<FloatType>(resultType).getFloatSemantics();
3278 APFloat identity = useOnlyFiniteValue
3279 ? APFloat::getLargest(semantic,
false)
3280 : APFloat::getInf(semantic,
false);
3284 case AtomicRMWKind::minnumf: {
3285 const llvm::fltSemantics &semantic =
3286 llvm::cast<FloatType>(resultType).getFloatSemantics();
3287 APFloat identity = APFloat::getNaN(semantic,
false);
3290 case AtomicRMWKind::mins:
3292 resultType, APInt::getSignedMaxValue(
3293 llvm::cast<IntegerType>(resultType).getWidth()));
3294 case AtomicRMWKind::minu:
3297 APInt::getMaxValue(llvm::cast<IntegerType>(resultType).getWidth()));
3298 case AtomicRMWKind::muli:
3300 case AtomicRMWKind::mulf:
3303 case AtomicRMWKind::assign:
3312 std::optional<AtomicRMWKind> maybeKind =
3315 .Case([](arith::AddFOp op) {
return AtomicRMWKind::addf; })
3316 .Case([](arith::MulFOp op) {
return AtomicRMWKind::mulf; })
3317 .Case([](arith::MaximumFOp op) {
return AtomicRMWKind::maximumf; })
3318 .Case([](arith::MinimumFOp op) {
return AtomicRMWKind::minimumf; })
3319 .Case([](arith::MaxNumFOp op) {
return AtomicRMWKind::maxnumf; })
3320 .Case([](arith::MinNumFOp op) {
return AtomicRMWKind::minnumf; })
3322 .Case([](arith::AddIOp op) {
return AtomicRMWKind::addi; })
3323 .Case([](arith::OrIOp op) {
return AtomicRMWKind::ori; })
3324 .Case([](arith::XOrIOp op) {
return AtomicRMWKind::xori; })
3325 .Case([](arith::AndIOp op) {
return AtomicRMWKind::andi; })
3326 .Case([](arith::MaxUIOp op) {
return AtomicRMWKind::maxu; })
3327 .Case([](arith::MinUIOp op) {
return AtomicRMWKind::minu; })
3328 .Case([](arith::MaxSIOp op) {
return AtomicRMWKind::maxs; })
3329 .Case([](arith::MinSIOp op) {
return AtomicRMWKind::mins; })
3330 .Case([](arith::MulIOp op) {
return AtomicRMWKind::muli; })
3331 .Default(std::nullopt);
3333 return std::nullopt;
3336 bool useOnlyFiniteValue =
false;
3337 auto fmfOpInterface = dyn_cast<ArithFastMathInterface>(op);
3338 if (fmfOpInterface) {
3339 arith::FastMathFlagsAttr fmfAttr = fmfOpInterface.getFastMathFlagsAttr();
3340 useOnlyFiniteValue =
3341 bitEnumContainsAny(fmfAttr.getValue(), arith::FastMathFlags::ninf);
3349 useOnlyFiniteValue);
3355 bool useOnlyFiniteValue) {
3357 useOnlyFiniteValue))
3358 return arith::ConstantOp::create(builder, loc, attr);
3367 case AtomicRMWKind::addf:
3368 return arith::AddFOp::create(builder, loc, lhs, rhs);
3369 case AtomicRMWKind::addi:
3370 return arith::AddIOp::create(builder, loc, lhs, rhs);
3371 case AtomicRMWKind::mulf:
3372 return arith::MulFOp::create(builder, loc, lhs, rhs);
3373 case AtomicRMWKind::muli:
3374 return arith::MulIOp::create(builder, loc, lhs, rhs);
3375 case AtomicRMWKind::maximumf:
3376 return arith::MaximumFOp::create(builder, loc, lhs, rhs);
3377 case AtomicRMWKind::minimumf:
3378 return arith::MinimumFOp::create(builder, loc, lhs, rhs);
3379 case AtomicRMWKind::maxnumf:
3380 return arith::MaxNumFOp::create(builder, loc, lhs, rhs);
3381 case AtomicRMWKind::minnumf:
3382 return arith::MinNumFOp::create(builder, loc, lhs, rhs);
3383 case AtomicRMWKind::maxs:
3384 return arith::MaxSIOp::create(builder, loc, lhs, rhs);
3385 case AtomicRMWKind::mins:
3386 return arith::MinSIOp::create(builder, loc, lhs, rhs);
3387 case AtomicRMWKind::maxu:
3388 return arith::MaxUIOp::create(builder, loc, lhs, rhs);
3389 case AtomicRMWKind::minu:
3390 return arith::MinUIOp::create(builder, loc, lhs, rhs);
3391 case AtomicRMWKind::ori:
3392 return arith::OrIOp::create(builder, loc, lhs, rhs);
3393 case AtomicRMWKind::andi:
3394 return arith::AndIOp::create(builder, loc, lhs, rhs);
3395 case AtomicRMWKind::xori:
3396 return arith::XOrIOp::create(builder, loc, lhs, rhs);
3398 case AtomicRMWKind::assign:
3409#define GET_OP_CLASSES
3410#include "mlir/Dialect/Arith/IR/ArithOps.cpp.inc"
3416#include "mlir/Dialect/Arith/IR/ArithOpsEnums.cpp.inc"
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
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 Attribute foldScalingCastOp(Attribute inAttr, Attribute scaleAttr, Type resultType, function_ref< std::optional< APFloat >(const APFloat &, const APFloat &)> calculate)
Fold calculate element-wise over the operands of a scaling cast op.
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 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 isFoldableScalingScale(Value scale)
Only scales that already are f8E8M0FNU fold.
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, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
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.