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))
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);
1356static bool isLosslesslyConvertibleTo(
const llvm::fltSemantics &from,
1357 const llvm::fltSemantics &to,
1358 bool ignoreNaNs =
false) {
1359 if (!llvm::APFloatBase::isRepresentableBy(from, to))
1362 if ((from.hasZero && !to.hasZero) ||
1363 (from.hasSignedRepr && !to.hasSignedRepr))
1368 bool fromHasSignedZero =
1369 from.hasZero && from.hasSignedRepr &&
1370 from.nanEncoding != llvm::fltNanEncoding::NegativeZero;
1371 bool toHasSignedZero = to.hasZero && to.hasSignedRepr &&
1372 to.nanEncoding != llvm::fltNanEncoding::NegativeZero;
1373 if (fromHasSignedZero && !toHasSignedZero)
1379 llvm::APFloat smallestFrom = llvm::APFloat::getSmallest(from);
1380 bool losesInfo =
false;
1381 (void)smallestFrom.convert(to, llvm::APFloat::rmNearestTiesToEven,
1386 if (from.nonFiniteBehavior == llvm::fltNonfiniteBehavior::FiniteOnly)
1392 return to.nonFiniteBehavior != llvm::fltNonfiniteBehavior::FiniteOnly;
1394 if (from.nonFiniteBehavior == llvm::fltNonfiniteBehavior::IEEE754) {
1403 if (to.nonFiniteBehavior == llvm::fltNonfiniteBehavior::IEEE754)
1405 return to.nonFiniteBehavior == llvm::fltNonfiniteBehavior::NanOnly &&
1406 from.nanEncoding == to.nanEncoding;
1417template <
typename TruncOp,
typename ExtOp,
typename ExtremumOp>
1418struct NarrowExtremum final : OpRewritePattern<TruncOp> {
1419 using OpRewritePattern<TruncOp>::OpRewritePattern;
1421 LogicalResult matchAndRewrite(TruncOp truncOp,
1422 PatternRewriter &rewriter)
const override {
1423 auto extremumOp = truncOp.getIn().template getDefiningOp<ExtremumOp>();
1424 if (!extremumOp || !extremumOp->hasOneUse())
1427 auto lhsExt = extremumOp.getLhs().template getDefiningOp<ExtOp>();
1428 auto rhsExt = extremumOp.getRhs().template getDefiningOp<ExtOp>();
1429 if (!lhsExt || !rhsExt)
1432 Value
lhs = lhsExt.getIn();
1433 Value
rhs = rhsExt.getIn();
1434 Type narrowType = truncOp.getType();
1435 if (
lhs.getType() != narrowType ||
rhs.getType() != narrowType)
1444 if (
auto narrowFloatType =
1446 auto wideFloatType =
1451 const llvm::fltSemantics &narrowSemantics =
1452 narrowFloatType.getFloatSemantics();
1453 const llvm::fltSemantics &wideSemantics =
1454 wideFloatType.getFloatSemantics();
1455 bool ignoreNaNs =
false;
1456 if constexpr (std::is_same_v<TruncOp, TruncFOp>)
1458 bitEnumContainsAll(extremumOp.getFastmath(), FastMathFlags::nnan);
1459 if (!isLosslesslyConvertibleTo(narrowSemantics, wideSemantics,
1466 extremumOp->getAttrs());
1477OpFoldResult arith::MaximumFOp::fold(FoldAdaptor adaptor) {
1479 if (getLhs() == getRhs())
1493OpFoldResult arith::MaxNumFOp::fold(FoldAdaptor adaptor) {
1495 if (getLhs() == getRhs())
1509OpFoldResult MaxSIOp::fold(FoldAdaptor adaptor) {
1511 if (getLhs() == getRhs())
1517 if (intValue.isMaxSignedValue())
1520 if (intValue.isMinSignedValue())
1525 llvm::APIntOps::smax);
1532OpFoldResult MaxUIOp::fold(FoldAdaptor adaptor) {
1534 if (getLhs() == getRhs())
1540 if (intValue.isMaxValue())
1543 if (intValue.isMinValue())
1548 llvm::APIntOps::umax);
1555OpFoldResult arith::MinimumFOp::fold(FoldAdaptor adaptor) {
1557 if (getLhs() == getRhs())
1571OpFoldResult arith::MinNumFOp::fold(FoldAdaptor adaptor) {
1573 if (getLhs() == getRhs())
1587OpFoldResult MinSIOp::fold(FoldAdaptor adaptor) {
1589 if (getLhs() == getRhs())
1595 if (intValue.isMinSignedValue())
1598 if (intValue.isMaxSignedValue())
1603 llvm::APIntOps::smin);
1610OpFoldResult MinUIOp::fold(FoldAdaptor adaptor) {
1612 if (getLhs() == getRhs())
1618 if (intValue.isMinValue())
1621 if (intValue.isMaxValue())
1626 llvm::APIntOps::umin);
1633OpFoldResult arith::MulFOp::fold(FoldAdaptor adaptor) {
1638 if (arith::bitEnumContainsAll(getFastmath(), arith::FastMathFlags::nnan |
1639 arith::FastMathFlags::nsz)) {
1645 auto rm = getRoundingmode();
1647 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1649 result.multiply(b, convertArithRoundingModeToLLVMIR(rm));
1654void arith::MulFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1655 MLIRContext *context) {
1656 patterns.
add<MulFOfNegF>(context);
1663OpFoldResult arith::DivFOp::fold(FoldAdaptor adaptor) {
1668 auto rm = getRoundingmode();
1670 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1672 result.divide(b, convertArithRoundingModeToLLVMIR(rm));
1677void arith::DivFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1678 MLIRContext *context) {
1679 patterns.
add<DivFOfNegF>(context);
1686OpFoldResult arith::RemFOp::fold(FoldAdaptor adaptor) {
1688 [](
const APFloat &a,
const APFloat &
b) {
1693 (void)result.mod(b);
1702template <
typename... Types>
1708template <
typename... ShapedTypes,
typename... ElementTypes>
1711 if (llvm::isa<ShapedType>(type) && !llvm::isa<ShapedTypes...>(type))
1715 if (!llvm::isa<ElementTypes...>(underlyingType))
1718 return underlyingType;
1722template <
typename... ElementTypes>
1729template <
typename... ElementTypes>
1738 auto rankedTensorA = dyn_cast<RankedTensorType>(typeA);
1739 auto rankedTensorB = dyn_cast<RankedTensorType>(typeB);
1740 if (!rankedTensorA || !rankedTensorB)
1742 return rankedTensorA.getEncoding() == rankedTensorB.getEncoding();
1746 if (inputs.size() != 1 || outputs.size() != 1)
1758template <
typename ValType,
typename Op>
1763 if (llvm::cast<ValType>(srcType).getWidth() >=
1764 llvm::cast<ValType>(dstType).getWidth())
1766 << dstType <<
" must be wider than operand type " << srcType;
1772template <
typename ValType,
typename Op>
1777 if (llvm::cast<ValType>(srcType).getWidth() <=
1778 llvm::cast<ValType>(dstType).getWidth())
1780 << dstType <<
" must be shorter than operand type " << srcType;
1786template <
template <
typename>
class WidthComparator,
typename... ElementTypes>
1791 auto srcType =
getTypeIfLike<ElementTypes...>(inputs.front());
1792 auto dstType =
getTypeIfLike<ElementTypes...>(outputs.front());
1793 if (!srcType || !dstType)
1796 return WidthComparator<unsigned>()(dstType.getIntOrFloatBitWidth(),
1797 srcType.getIntOrFloatBitWidth());
1802static FailureOr<APFloat>
1804 const llvm::fltSemantics &targetSemantics,
1808 using fltNonfiniteBehavior = llvm::fltNonfiniteBehavior;
1809 if (sourceValue.isInfinity() &&
1810 (targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
1811 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly))
1813 if (sourceValue.isNaN() &&
1814 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
1817 bool losesInfo =
false;
1818 auto status = sourceValue.convert(targetSemantics, roundingMode, &losesInfo);
1819 if (losesInfo || status != APFloat::opOK)
1829OpFoldResult arith::ExtUIOp::fold(FoldAdaptor adaptor) {
1830 if (
auto lhs = getIn().getDefiningOp<ExtUIOp>()) {
1833 setNonNeg(
lhs.getNonNeg());
1834 getInMutable().assign(
lhs.getIn());
1839 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1841 adaptor.getOperands(),
getType(),
1842 [bitWidth](
const APInt &a,
bool &castStatus) {
1843 return a.zext(bitWidth);
1851LogicalResult arith::ExtUIOp::verify() {
1859OpFoldResult arith::ExtSIOp::fold(FoldAdaptor adaptor) {
1860 if (
auto lhs = getIn().getDefiningOp<ExtSIOp>()) {
1861 getInMutable().assign(
lhs.getIn());
1866 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1868 adaptor.getOperands(),
getType(),
1869 [bitWidth](
const APInt &a,
bool &castStatus) {
1870 return a.sext(bitWidth);
1878void arith::ExtSIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1879 MLIRContext *context) {
1880 patterns.
add<ExtSIOfExtUI>(context);
1883LogicalResult arith::ExtSIOp::verify() {
1893OpFoldResult arith::ExtFOp::fold(FoldAdaptor adaptor) {
1894 if (
auto truncFOp = getOperand().getDefiningOp<TruncFOp>()) {
1895 if (truncFOp.getOperand().getType() ==
getType()) {
1896 arith::FastMathFlags truncFMF =
1897 truncFOp.getFastmath().value_or(arith::FastMathFlags::none);
1898 bool isTruncContract =
1899 bitEnumContainsAll(truncFMF, arith::FastMathFlags::contract);
1900 arith::FastMathFlags extFMF =
1901 getFastmath().value_or(arith::FastMathFlags::none);
1902 bool isExtContract =
1903 bitEnumContainsAll(extFMF, arith::FastMathFlags::contract);
1904 if (isTruncContract && isExtContract) {
1905 return truncFOp.getOperand();
1911 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
1913 adaptor.getOperands(),
getType(),
1914 [&targetSemantics](
const APFloat &a,
bool &castStatus) {
1934bool arith::ScalingExtFOp::areCastCompatible(
TypeRange inputs,
1939LogicalResult arith::ScalingExtFOp::verify() {
1947OpFoldResult arith::TruncIOp::fold(FoldAdaptor adaptor) {
1950 Value src = getOperand().getDefiningOp()->getOperand(0);
1955 if (llvm::cast<IntegerType>(srcType).getWidth() >
1956 llvm::cast<IntegerType>(dstType).getWidth()) {
1963 if (srcType == dstType)
1969 setOperand(getOperand().getDefiningOp()->getOperand(0));
1974 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1976 adaptor.getOperands(),
getType(),
1977 [bitWidth](
const APInt &a,
bool &castStatus) {
1978 return a.trunc(bitWidth);
1986void arith::TruncIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1987 MLIRContext *context) {
1988 patterns.
add<NarrowExtremum<TruncIOp, ExtSIOp, MaxSIOp>,
1989 NarrowExtremum<TruncIOp, ExtSIOp, MinSIOp>,
1990 NarrowExtremum<TruncIOp, ExtUIOp, MaxUIOp>,
1991 NarrowExtremum<TruncIOp, ExtUIOp, MinUIOp>, TruncIExtSIToExtSI,
1992 TruncIExtUIToExtUI, TruncIShrSIToTrunciShrUI>(context);
1995LogicalResult arith::TruncIOp::verify() {
2005OpFoldResult arith::TruncFOp::fold(FoldAdaptor adaptor) {
2007 if (
auto extOp = getOperand().getDefiningOp<arith::ExtFOp>()) {
2008 Value src = extOp.getIn();
2010 auto intermediateType =
2014 if (isLosslesslyConvertibleTo(srcType.getFloatSemantics(),
2015 intermediateType.getFloatSemantics())) {
2017 if (srcType.getWidth() > resElemType.getWidth()) {
2023 if (srcType == resElemType)
2028 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
2030 adaptor.getOperands(),
getType(),
2031 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
2032 llvm::RoundingMode llvmRoundingMode =
2034 FailureOr<APFloat>
result =
2044void arith::TruncFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2045 MLIRContext *context) {
2046 patterns.
add<NarrowExtremum<TruncFOp, ExtFOp, MaximumFOp>,
2047 NarrowExtremum<TruncFOp, ExtFOp, MaxNumFOp>,
2048 NarrowExtremum<TruncFOp, ExtFOp, MinimumFOp>,
2049 NarrowExtremum<TruncFOp, ExtFOp, MinNumFOp>,
2050 TruncFSIToFPToSIToFP, TruncFUIToFPToUIToFP>(context);
2057LogicalResult arith::TruncFOp::verify() {
2065OpFoldResult arith::ConvertFOp::fold(FoldAdaptor adaptor) {
2067 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
2069 adaptor.getOperands(),
getType(),
2070 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
2071 llvm::RoundingMode llvmRoundingMode =
2073 FailureOr<APFloat>
result =
2088 if (!srcType || !dstType)
2090 return srcType != dstType &&
2094LogicalResult arith::ConvertFOp::verify() {
2097 if (srcType == dstType)
2098 return emitError(
"result element type ")
2099 << dstType <<
" must be different from operand element type "
2101 if (srcType.getWidth() != dstType.getWidth())
2102 return emitError(
"result element type ")
2103 << dstType <<
" must have the same bitwidth as operand element type "
2112bool arith::ScalingTruncFOp::areCastCompatible(
TypeRange inputs,
2117LogicalResult arith::ScalingTruncFOp::verify() {
2125void arith::AndIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2126 MLIRContext *context) {
2127 patterns.
add<AndIAndIConstant, AndOfExtUI, AndOfExtSI>(context);
2134void arith::OrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2135 MLIRContext *context) {
2136 patterns.
add<OrIOrIConstant, OrOfExtUI, OrOfExtSI>(context);
2143template <
typename From,
typename To>
2151 return srcType && dstType;
2162OpFoldResult arith::UIToFPOp::fold(FoldAdaptor adaptor) {
2165 adaptor.getOperands(),
getType(),
2166 [&resEleType](
const APInt &a,
bool &castStatus) {
2167 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2168 APFloat apf(floatTy.getFloatSemantics(),
2169 APInt::getZero(floatTy.getWidth()));
2170 apf.convertFromAPInt(a,
false,
2171 APFloat::rmNearestTiesToEven);
2176void arith::UIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2177 MLIRContext *context) {
2178 patterns.
add<UIToFPOfExtUI>(context);
2189OpFoldResult arith::SIToFPOp::fold(FoldAdaptor adaptor) {
2192 adaptor.getOperands(),
getType(),
2193 [&resEleType](
const APInt &a,
bool &castStatus) {
2194 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2195 APFloat apf(floatTy.getFloatSemantics(),
2196 APInt::getZero(floatTy.getWidth()));
2197 apf.convertFromAPInt(a,
true,
2198 APFloat::rmNearestTiesToEven);
2203void arith::SIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2204 MLIRContext *context) {
2205 patterns.
add<SIToFPOfExtSI, SIToFPOfExtUI>(context);
2216OpFoldResult arith::FPToUIOp::fold(FoldAdaptor adaptor) {
2218 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2220 adaptor.getOperands(),
getType(),
2221 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2223 APSInt api(bitWidth,
true);
2224 castStatus = APFloat::opInvalidOp !=
2225 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2238OpFoldResult arith::FPToSIOp::fold(FoldAdaptor adaptor) {
2240 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2242 adaptor.getOperands(),
getType(),
2243 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2245 APSInt api(bitWidth,
false);
2246 castStatus = APFloat::opInvalidOp !=
2247 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2261 return intTy.getWidth();
2262 return IndexType::kInternalStorageBitWidth;
2271 if (!srcType || !dstType)
2275 (srcType.isSignlessInteger() && dstType.
isIndex());
2278bool arith::IndexCastOp::areCastCompatible(
TypeRange inputs,
2283OpFoldResult arith::IndexCastOp::fold(FoldAdaptor adaptor) {
2285 unsigned resultBitwidth = 64;
2287 resultBitwidth = intTy.getWidth();
2290 adaptor.getOperands(),
getType(),
2291 [resultBitwidth](
const APInt &a,
bool & ) {
2292 return a.sextOrTrunc(resultBitwidth);
2299 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastOp>()) {
2300 Value x = inner.getOperand();
2309void arith::IndexCastOp::getCanonicalizationPatterns(
2310 RewritePatternSet &patterns, MLIRContext *context) {
2311 patterns.
add<IndexCastOfExtSI>(context);
2318bool arith::IndexCastUIOp::areCastCompatible(
TypeRange inputs,
2323OpFoldResult arith::IndexCastUIOp::fold(FoldAdaptor adaptor) {
2325 unsigned resultBitwidth = 64;
2327 resultBitwidth = intTy.getWidth();
2330 adaptor.getOperands(),
getType(),
2331 [resultBitwidth](
const APInt &a,
bool & ) {
2332 return a.zextOrTrunc(resultBitwidth);
2339 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastUIOp>()) {
2340 Value x = inner.getOperand();
2349void arith::IndexCastUIOp::getCanonicalizationPatterns(
2350 RewritePatternSet &patterns, MLIRContext *context) {
2351 patterns.
add<IndexCastUIOfExtUI>(context);
2364 if (!srcType || !dstType)
2370OpFoldResult arith::BitcastOp::fold(FoldAdaptor adaptor) {
2372 auto operand = adaptor.getIn();
2377 if (
auto denseAttr = dyn_cast_or_null<DenseElementsAttr>(operand))
2378 return denseAttr.bitcast(llvm::cast<ShapedType>(resType).
getElementType());
2380 if (llvm::isa<ShapedType>(resType))
2388 if (!llvm::isa<FloatAttr, IntegerAttr>(operand))
2391 APInt bits = llvm::isa<FloatAttr>(operand)
2392 ? llvm::cast<FloatAttr>(operand).getValue().bitcastToAPInt()
2393 : llvm::cast<IntegerAttr>(operand).getValue();
2395 "trying to fold on broken IR: operands have incompatible types");
2397 if (
auto resFloatType = dyn_cast<FloatType>(resType))
2398 return FloatAttr::get(resType,
2399 APFloat(resFloatType.getFloatSemantics(), bits));
2400 return IntegerAttr::get(resType, bits);
2403void arith::BitcastOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2404 MLIRContext *context) {
2405 patterns.
add<BitcastOfBitcast>(context);
2415 const APInt &
lhs,
const APInt &
rhs) {
2416 switch (predicate) {
2417 case arith::CmpIPredicate::eq:
2419 case arith::CmpIPredicate::ne:
2421 case arith::CmpIPredicate::slt:
2423 case arith::CmpIPredicate::sle:
2425 case arith::CmpIPredicate::sgt:
2427 case arith::CmpIPredicate::sge:
2429 case arith::CmpIPredicate::ult:
2431 case arith::CmpIPredicate::ule:
2433 case arith::CmpIPredicate::ugt:
2435 case arith::CmpIPredicate::uge:
2438 llvm_unreachable(
"unknown cmpi predicate kind");
2443 switch (predicate) {
2444 case arith::CmpIPredicate::eq:
2445 case arith::CmpIPredicate::sle:
2446 case arith::CmpIPredicate::sge:
2447 case arith::CmpIPredicate::ule:
2448 case arith::CmpIPredicate::uge:
2450 case arith::CmpIPredicate::ne:
2451 case arith::CmpIPredicate::slt:
2452 case arith::CmpIPredicate::sgt:
2453 case arith::CmpIPredicate::ult:
2454 case arith::CmpIPredicate::ugt:
2457 llvm_unreachable(
"unknown cmpi predicate kind");
2461 if (
auto intType = dyn_cast<IntegerType>(t)) {
2462 return intType.getWidth();
2464 if (
auto vectorIntType = dyn_cast<VectorType>(t)) {
2465 return llvm::cast<IntegerType>(vectorIntType.getElementType()).getWidth();
2467 return std::nullopt;
2470OpFoldResult arith::CmpIOp::fold(FoldAdaptor adaptor) {
2472 if (getLhs() == getRhs()) {
2478 if (
auto extOp = getLhs().getDefiningOp<ExtSIOp>()) {
2480 std::optional<int64_t> integerWidth =
2482 if (integerWidth && integerWidth.value() == 1 &&
2483 getPredicate() == arith::CmpIPredicate::ne)
2484 return extOp.getOperand();
2486 if (
auto extOp = getLhs().getDefiningOp<ExtUIOp>()) {
2488 std::optional<int64_t> integerWidth =
2490 if (integerWidth && integerWidth.value() == 1 &&
2491 getPredicate() == arith::CmpIPredicate::ne)
2492 return extOp.getOperand();
2497 getPredicate() == arith::CmpIPredicate::ne)
2504 getPredicate() == arith::CmpIPredicate::eq)
2509 if (adaptor.getLhs() && !adaptor.getRhs()) {
2511 using Pred = CmpIPredicate;
2512 const std::pair<Pred, Pred> invPreds[] = {
2513 {Pred::slt, Pred::sgt}, {Pred::sgt, Pred::slt}, {Pred::sle, Pred::sge},
2514 {Pred::sge, Pred::sle}, {Pred::ult, Pred::ugt}, {Pred::ugt, Pred::ult},
2515 {Pred::ule, Pred::uge}, {Pred::uge, Pred::ule}, {Pred::eq, Pred::eq},
2516 {Pred::ne, Pred::ne},
2518 Pred origPred = getPredicate();
2519 for (
auto pred : invPreds) {
2520 if (origPred == pred.first) {
2521 setPredicate(pred.second);
2522 Value
lhs = getLhs();
2523 Value
rhs = getRhs();
2524 getLhsMutable().assign(
rhs);
2525 getRhsMutable().assign(
lhs);
2529 llvm_unreachable(
"unknown cmpi predicate kind");
2534 if (
auto lhs = dyn_cast_if_present<TypedAttr>(adaptor.getLhs())) {
2537 [pred = getPredicate()](
const APInt &
lhs,
const APInt &
rhs) {
2546void arith::CmpIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2547 MLIRContext *context) {
2548 patterns.
insert<CmpIExtSI, CmpIExtUI>(context);
2558 const APFloat &
lhs,
const APFloat &
rhs) {
2559 auto cmpResult =
lhs.compare(
rhs);
2560 switch (predicate) {
2561 case arith::CmpFPredicate::AlwaysFalse:
2563 case arith::CmpFPredicate::OEQ:
2564 return cmpResult == APFloat::cmpEqual;
2565 case arith::CmpFPredicate::OGT:
2566 return cmpResult == APFloat::cmpGreaterThan;
2567 case arith::CmpFPredicate::OGE:
2568 return cmpResult == APFloat::cmpGreaterThan ||
2569 cmpResult == APFloat::cmpEqual;
2570 case arith::CmpFPredicate::OLT:
2571 return cmpResult == APFloat::cmpLessThan;
2572 case arith::CmpFPredicate::OLE:
2573 return cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2574 case arith::CmpFPredicate::ONE:
2575 return cmpResult != APFloat::cmpUnordered && cmpResult != APFloat::cmpEqual;
2576 case arith::CmpFPredicate::ORD:
2577 return cmpResult != APFloat::cmpUnordered;
2578 case arith::CmpFPredicate::UEQ:
2579 return cmpResult == APFloat::cmpUnordered || cmpResult == APFloat::cmpEqual;
2580 case arith::CmpFPredicate::UGT:
2581 return cmpResult == APFloat::cmpUnordered ||
2582 cmpResult == APFloat::cmpGreaterThan;
2583 case arith::CmpFPredicate::UGE:
2584 return cmpResult == APFloat::cmpUnordered ||
2585 cmpResult == APFloat::cmpGreaterThan ||
2586 cmpResult == APFloat::cmpEqual;
2587 case arith::CmpFPredicate::ULT:
2588 return cmpResult == APFloat::cmpUnordered ||
2589 cmpResult == APFloat::cmpLessThan;
2590 case arith::CmpFPredicate::ULE:
2591 return cmpResult == APFloat::cmpUnordered ||
2592 cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2593 case arith::CmpFPredicate::UNE:
2594 return cmpResult != APFloat::cmpEqual;
2595 case arith::CmpFPredicate::UNO:
2596 return cmpResult == APFloat::cmpUnordered;
2597 case arith::CmpFPredicate::AlwaysTrue:
2600 llvm_unreachable(
"unknown cmpf predicate kind");
2604 auto lhs = dyn_cast_if_present<FloatAttr>(adaptor.getLhs());
2605 auto rhs = dyn_cast_if_present<FloatAttr>(adaptor.getRhs());
2608 if (
lhs &&
lhs.getValue().isNaN())
2610 if (
rhs &&
rhs.getValue().isNaN())
2626 using namespace arith;
2628 case CmpFPredicate::UEQ:
2629 case CmpFPredicate::OEQ:
2630 return CmpIPredicate::eq;
2631 case CmpFPredicate::UGT:
2632 case CmpFPredicate::OGT:
2633 return isUnsigned ? CmpIPredicate::ugt : CmpIPredicate::sgt;
2634 case CmpFPredicate::UGE:
2635 case CmpFPredicate::OGE:
2636 return isUnsigned ? CmpIPredicate::uge : CmpIPredicate::sge;
2637 case CmpFPredicate::ULT:
2638 case CmpFPredicate::OLT:
2639 return isUnsigned ? CmpIPredicate::ult : CmpIPredicate::slt;
2640 case CmpFPredicate::ULE:
2641 case CmpFPredicate::OLE:
2642 return isUnsigned ? CmpIPredicate::ule : CmpIPredicate::sle;
2643 case CmpFPredicate::UNE:
2644 case CmpFPredicate::ONE:
2645 return CmpIPredicate::ne;
2647 llvm_unreachable(
"Unexpected predicate!");
2657 const APFloat &
rhs = flt.getValue();
2665 FloatType floatTy = llvm::cast<FloatType>(op.getRhs().getType());
2666 int mantissaWidth = floatTy.getFPMantissaWidth();
2667 if (mantissaWidth <= 0)
2673 if (
auto si = op.getLhs().getDefiningOp<SIToFPOp>()) {
2675 intVal = si.getIn();
2676 }
else if (
auto ui = op.getLhs().getDefiningOp<UIToFPOp>()) {
2678 intVal = ui.getIn();
2685 auto intTy = llvm::cast<IntegerType>(intVal.
getType());
2686 auto intWidth = intTy.getWidth();
2689 auto valueBits = isUnsigned ? intWidth : (intWidth - 1);
2694 if ((
int)intWidth > mantissaWidth) {
2696 int exponent = ilogb(
rhs);
2697 if (exponent == APFloat::IEK_Inf) {
2698 int maxExponent = ilogb(APFloat::getLargest(
rhs.getSemantics()));
2699 if (maxExponent < (
int)valueBits) {
2706 if (mantissaWidth <= exponent && exponent <= (
int)valueBits) {
2715 switch (op.getPredicate()) {
2716 case CmpFPredicate::ORD:
2721 case CmpFPredicate::UNO:
2734 APFloat signedMax(
rhs.getSemantics());
2735 signedMax.convertFromAPInt(APInt::getSignedMaxValue(intWidth),
true,
2736 APFloat::rmNearestTiesToEven);
2737 if (signedMax <
rhs) {
2738 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::slt ||
2739 pred == CmpIPredicate::sle)
2750 APFloat unsignedMax(
rhs.getSemantics());
2751 unsignedMax.convertFromAPInt(APInt::getMaxValue(intWidth),
false,
2752 APFloat::rmNearestTiesToEven);
2753 if (unsignedMax <
rhs) {
2754 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ult ||
2755 pred == CmpIPredicate::ule)
2767 APFloat signedMin(
rhs.getSemantics());
2768 signedMin.convertFromAPInt(APInt::getSignedMinValue(intWidth),
true,
2769 APFloat::rmNearestTiesToEven);
2770 if (signedMin >
rhs) {
2771 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::sgt ||
2772 pred == CmpIPredicate::sge)
2782 APFloat unsignedMin(
rhs.getSemantics());
2783 unsignedMin.convertFromAPInt(APInt::getMinValue(intWidth),
false,
2784 APFloat::rmNearestTiesToEven);
2785 if (unsignedMin >
rhs) {
2786 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ugt ||
2787 pred == CmpIPredicate::uge)
2802 APSInt rhsInt(intWidth, isUnsigned);
2803 if (APFloat::opInvalidOp ==
2804 rhs.convertToInteger(rhsInt, APFloat::rmTowardZero, &ignored)) {
2810 if (!
rhs.isZero()) {
2811 APFloat apf(floatTy.getFloatSemantics(),
2812 APInt::getZero(floatTy.getWidth()));
2813 apf.convertFromAPInt(rhsInt, !isUnsigned, APFloat::rmNearestTiesToEven);
2815 bool equal = apf ==
rhs;
2821 case CmpIPredicate::ne:
2825 case CmpIPredicate::eq:
2829 case CmpIPredicate::ule:
2832 if (
rhs.isNegative()) {
2838 case CmpIPredicate::sle:
2841 if (
rhs.isNegative())
2842 pred = CmpIPredicate::slt;
2844 case CmpIPredicate::ult:
2847 if (
rhs.isNegative()) {
2852 pred = CmpIPredicate::ule;
2854 case CmpIPredicate::slt:
2857 if (!
rhs.isNegative())
2858 pred = CmpIPredicate::sle;
2860 case CmpIPredicate::ugt:
2863 if (
rhs.isNegative()) {
2869 case CmpIPredicate::sgt:
2872 if (
rhs.isNegative())
2873 pred = CmpIPredicate::sge;
2875 case CmpIPredicate::uge:
2878 if (
rhs.isNegative()) {
2883 pred = CmpIPredicate::ugt;
2885 case CmpIPredicate::sge:
2888 if (!
rhs.isNegative())
2889 pred = CmpIPredicate::sgt;
2899 ConstantOp::create(rewriter, op.getLoc(), intVal.
getType(),
2905void arith::CmpFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2906 MLIRContext *context) {
2907 patterns.
insert<CmpFIntToFPConst>(context);
2921 if (!llvm::isa<IntegerType>(op.getType()) || op.getType().isInteger(1))
2937 arith::XOrIOp::create(
2938 rewriter, op.getLoc(), op.getCondition(),
2940 op.getCondition().
getType(), 1)));
2948void arith::SelectOp::getCanonicalizationPatterns(RewritePatternSet &results,
2949 MLIRContext *context) {
2950 results.
add<RedundantSelectFalse, RedundantSelectTrue, SelectNotCond,
2951 SelectI1ToNot, SelectCmpISgeToMaxSI, SelectCmpISgeToMinSI,
2952 SelectCmpISgtToMaxSI, SelectCmpISgtToMinSI, SelectCmpISleToMaxSI,
2953 SelectCmpISleToMinSI, SelectCmpISltToMaxSI, SelectCmpISltToMinSI,
2954 SelectCmpIUgeToMaxUI, SelectCmpIUgeToMinUI, SelectCmpIUgtToMaxUI,
2955 SelectCmpIUgtToMinUI, SelectCmpIUleToMaxUI, SelectCmpIUleToMinUI,
2956 SelectCmpIUltToMaxUI, SelectCmpIUltToMinUI, SelectToExtUI>(
2960OpFoldResult arith::SelectOp::fold(FoldAdaptor adaptor) {
2961 Value trueVal = getTrueValue();
2962 Value falseVal = getFalseValue();
2963 if (trueVal == falseVal)
2966 Value condition = getCondition();
2984 if (
getType().isSignlessInteger(1) &&
2990 auto pred = cmp.getPredicate();
2991 if (pred == arith::CmpIPredicate::eq || pred == arith::CmpIPredicate::ne) {
2992 auto cmpLhs = cmp.getLhs();
2993 auto cmpRhs = cmp.getRhs();
3001 if ((cmpLhs == trueVal && cmpRhs == falseVal) ||
3002 (cmpRhs == trueVal && cmpLhs == falseVal))
3003 return pred == arith::CmpIPredicate::ne ? trueVal : falseVal;
3010 dyn_cast_if_present<DenseElementsAttr>(adaptor.getCondition())) {
3012 assert(cond.getType().hasStaticShape() &&
3013 "DenseElementsAttr must have static shape");
3015 dyn_cast_if_present<DenseElementsAttr>(adaptor.getTrueValue())) {
3017 dyn_cast_if_present<DenseElementsAttr>(adaptor.getFalseValue())) {
3018 SmallVector<Attribute> results;
3019 results.reserve(
static_cast<size_t>(cond.getNumElements()));
3020 auto condVals = llvm::make_range(cond.value_begin<BoolAttr>(),
3021 cond.value_end<BoolAttr>());
3022 auto lhsVals = llvm::make_range(
lhs.value_begin<Attribute>(),
3023 lhs.value_end<Attribute>());
3024 auto rhsVals = llvm::make_range(
rhs.value_begin<Attribute>(),
3025 rhs.value_end<Attribute>());
3027 for (
auto [condVal, lhsVal, rhsVal] :
3028 llvm::zip_equal(condVals, lhsVals, rhsVals))
3029 results.push_back(condVal.getValue() ? lhsVal : rhsVal);
3039ParseResult SelectOp::parse(OpAsmParser &parser, OperationState &
result) {
3040 Type conditionType, resultType;
3041 SmallVector<OpAsmParser::UnresolvedOperand, 3> operands;
3049 conditionType = resultType;
3056 result.addTypes(resultType);
3058 {conditionType, resultType, resultType},
3062void arith::SelectOp::print(OpAsmPrinter &p) {
3063 p <<
" " << getOperands();
3066 if (ShapedType condType = dyn_cast<ShapedType>(getCondition().
getType()))
3067 p << condType <<
", ";
3071LogicalResult arith::SelectOp::verify() {
3072 Type conditionType = getCondition().getType();
3079 if (!llvm::isa<TensorType, VectorType>(resultType))
3080 return emitOpError() <<
"expected condition to be a signless i1, but got "
3083 if (conditionType != shapedConditionType) {
3084 return emitOpError() <<
"expected condition type to have the same shape "
3085 "as the result type, expected "
3086 << shapedConditionType <<
", but got "
3095OpFoldResult arith::ShLIOp::fold(FoldAdaptor adaptor) {
3109 bool bounded =
false;
3111 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3112 bounded = b.ult(b.getBitWidth());
3115 return bounded ?
result : Attribute();
3122OpFoldResult arith::ShRUIOp::fold(FoldAdaptor adaptor) {
3137 if (getLhs() == getRhs())
3140 bool bounded =
false;
3142 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3143 bounded = b.ult(b.getBitWidth());
3146 return bounded ?
result : Attribute();
3153OpFoldResult arith::ShRSIOp::fold(FoldAdaptor adaptor) {
3168 if (getLhs() == getRhs())
3176 bool bounded =
false;
3178 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3179 bounded = b.ult(b.getBitWidth());
3182 return bounded ?
result : Attribute();
3192 bool useOnlyFiniteValue) {
3194 case AtomicRMWKind::maximumf: {
3195 const llvm::fltSemantics &semantic =
3196 llvm::cast<FloatType>(resultType).getFloatSemantics();
3197 APFloat identity = useOnlyFiniteValue
3198 ? APFloat::getLargest(semantic,
true)
3199 : APFloat::getInf(semantic,
true);
3202 case AtomicRMWKind::maxnumf: {
3203 const llvm::fltSemantics &semantic =
3204 llvm::cast<FloatType>(resultType).getFloatSemantics();
3205 APFloat identity = APFloat::getNaN(semantic,
true);
3208 case AtomicRMWKind::addf:
3209 case AtomicRMWKind::addi:
3210 case AtomicRMWKind::maxu:
3211 case AtomicRMWKind::ori:
3212 case AtomicRMWKind::xori:
3214 case AtomicRMWKind::andi:
3217 APInt::getAllOnes(llvm::cast<IntegerType>(resultType).getWidth()));
3218 case AtomicRMWKind::maxs:
3220 resultType, APInt::getSignedMinValue(
3221 llvm::cast<IntegerType>(resultType).getWidth()));
3222 case AtomicRMWKind::minimumf: {
3223 const llvm::fltSemantics &semantic =
3224 llvm::cast<FloatType>(resultType).getFloatSemantics();
3225 APFloat identity = useOnlyFiniteValue
3226 ? APFloat::getLargest(semantic,
false)
3227 : APFloat::getInf(semantic,
false);
3231 case AtomicRMWKind::minnumf: {
3232 const llvm::fltSemantics &semantic =
3233 llvm::cast<FloatType>(resultType).getFloatSemantics();
3234 APFloat identity = APFloat::getNaN(semantic,
false);
3237 case AtomicRMWKind::mins:
3239 resultType, APInt::getSignedMaxValue(
3240 llvm::cast<IntegerType>(resultType).getWidth()));
3241 case AtomicRMWKind::minu:
3244 APInt::getMaxValue(llvm::cast<IntegerType>(resultType).getWidth()));
3245 case AtomicRMWKind::muli:
3247 case AtomicRMWKind::mulf:
3250 case AtomicRMWKind::assign:
3259 std::optional<AtomicRMWKind> maybeKind =
3262 .Case([](arith::AddFOp op) {
return AtomicRMWKind::addf; })
3263 .Case([](arith::MulFOp op) {
return AtomicRMWKind::mulf; })
3264 .Case([](arith::MaximumFOp op) {
return AtomicRMWKind::maximumf; })
3265 .Case([](arith::MinimumFOp op) {
return AtomicRMWKind::minimumf; })
3266 .Case([](arith::MaxNumFOp op) {
return AtomicRMWKind::maxnumf; })
3267 .Case([](arith::MinNumFOp op) {
return AtomicRMWKind::minnumf; })
3269 .Case([](arith::AddIOp op) {
return AtomicRMWKind::addi; })
3270 .Case([](arith::OrIOp op) {
return AtomicRMWKind::ori; })
3271 .Case([](arith::XOrIOp op) {
return AtomicRMWKind::xori; })
3272 .Case([](arith::AndIOp op) {
return AtomicRMWKind::andi; })
3273 .Case([](arith::MaxUIOp op) {
return AtomicRMWKind::maxu; })
3274 .Case([](arith::MinUIOp op) {
return AtomicRMWKind::minu; })
3275 .Case([](arith::MaxSIOp op) {
return AtomicRMWKind::maxs; })
3276 .Case([](arith::MinSIOp op) {
return AtomicRMWKind::mins; })
3277 .Case([](arith::MulIOp op) {
return AtomicRMWKind::muli; })
3278 .Default(std::nullopt);
3280 return std::nullopt;
3283 bool useOnlyFiniteValue =
false;
3284 auto fmfOpInterface = dyn_cast<ArithFastMathInterface>(op);
3285 if (fmfOpInterface) {
3286 arith::FastMathFlagsAttr fmfAttr = fmfOpInterface.getFastMathFlagsAttr();
3287 useOnlyFiniteValue =
3288 bitEnumContainsAny(fmfAttr.getValue(), arith::FastMathFlags::ninf);
3296 useOnlyFiniteValue);
3302 bool useOnlyFiniteValue) {
3304 useOnlyFiniteValue))
3305 return arith::ConstantOp::create(builder, loc, attr);
3314 case AtomicRMWKind::addf:
3315 return arith::AddFOp::create(builder, loc,
lhs,
rhs);
3316 case AtomicRMWKind::addi:
3317 return arith::AddIOp::create(builder, loc,
lhs,
rhs);
3318 case AtomicRMWKind::mulf:
3319 return arith::MulFOp::create(builder, loc,
lhs,
rhs);
3320 case AtomicRMWKind::muli:
3321 return arith::MulIOp::create(builder, loc,
lhs,
rhs);
3322 case AtomicRMWKind::maximumf:
3323 return arith::MaximumFOp::create(builder, loc,
lhs,
rhs);
3324 case AtomicRMWKind::minimumf:
3325 return arith::MinimumFOp::create(builder, loc,
lhs,
rhs);
3326 case AtomicRMWKind::maxnumf:
3327 return arith::MaxNumFOp::create(builder, loc,
lhs,
rhs);
3328 case AtomicRMWKind::minnumf:
3329 return arith::MinNumFOp::create(builder, loc,
lhs,
rhs);
3330 case AtomicRMWKind::maxs:
3331 return arith::MaxSIOp::create(builder, loc,
lhs,
rhs);
3332 case AtomicRMWKind::mins:
3333 return arith::MinSIOp::create(builder, loc,
lhs,
rhs);
3334 case AtomicRMWKind::maxu:
3335 return arith::MaxUIOp::create(builder, loc,
lhs,
rhs);
3336 case AtomicRMWKind::minu:
3337 return arith::MinUIOp::create(builder, loc,
lhs,
rhs);
3338 case AtomicRMWKind::ori:
3339 return arith::OrIOp::create(builder, loc,
lhs,
rhs);
3340 case AtomicRMWKind::andi:
3341 return arith::AndIOp::create(builder, loc,
lhs,
rhs);
3342 case AtomicRMWKind::xori:
3343 return arith::XOrIOp::create(builder, loc,
lhs,
rhs);
3345 case AtomicRMWKind::assign:
3356#define GET_OP_CLASSES
3357#include "mlir/Dialect/Arith/IR/ArithOps.cpp.inc"
3363#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 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.