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;
1137template <
typename OpTy>
1139 for (
bool reversePrev : {
false,
true}) {
1140 auto prev = (reversePrev ? op.getRhs() : op.getLhs())
1141 .template getDefiningOp<OpTy>();
1145 Value other = (reversePrev ? op.getLhs() : op.getRhs());
1146 if (other != prev.getLhs() && other != prev.getRhs())
1149 return prev.getResult();
1154OpFoldResult arith::AndIOp::fold(FoldAdaptor adaptor) {
1161 intValue.isAllOnes())
1166 intValue.isAllOnes())
1171 intValue.isAllOnes())
1179 adaptor.getOperands(),
1180 [](APInt a,
const APInt &
b) { return std::move(a) & b; });
1187OpFoldResult arith::OrIOp::fold(FoldAdaptor adaptor) {
1190 if (rhsVal.isZero())
1193 if (rhsVal.isAllOnes())
1194 return adaptor.getRhs();
1201 intValue.isAllOnes())
1202 return getRhs().getDefiningOp<XOrIOp>().getRhs();
1206 intValue.isAllOnes())
1207 return getLhs().getDefiningOp<XOrIOp>().getRhs();
1214 adaptor.getOperands(),
1215 [](APInt a,
const APInt &
b) { return std::move(a) | b; });
1222OpFoldResult arith::XOrIOp::fold(FoldAdaptor adaptor) {
1227 if (getLhs() == getRhs()) {
1230 auto shapedType = dyn_cast<ShapedType>(
getType());
1231 if (!shapedType || shapedType.hasStaticShape())
1236 if (arith::XOrIOp prev = getLhs().getDefiningOp<arith::XOrIOp>()) {
1237 if (prev.getRhs() == getRhs())
1238 return prev.getLhs();
1239 if (prev.getLhs() == getRhs())
1240 return prev.getRhs();
1244 if (arith::XOrIOp prev = getRhs().getDefiningOp<arith::XOrIOp>()) {
1245 if (prev.getRhs() == getLhs())
1246 return prev.getLhs();
1247 if (prev.getLhs() == getLhs())
1248 return prev.getRhs();
1252 adaptor.getOperands(),
1253 [](APInt a,
const APInt &
b) { return std::move(a) ^ b; });
1256void arith::XOrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1257 MLIRContext *context) {
1258 patterns.
add<XOrIXOrIConstant, XOrINotCmpI, XOrIOfExtUI, XOrIOfExtSI>(
1266OpFoldResult arith::NegFOp::fold(FoldAdaptor adaptor) {
1268 if (
auto op = this->getOperand().getDefiningOp<arith::NegFOp>())
1269 return op.getOperand();
1271 adaptor.getOperands(), [](
const APFloat &a) -> std::optional<APFloat> {
1272 if (!APFloat::semanticsHasSignedRepr(a.getSemantics()))
1273 return std::nullopt;
1282OpFoldResult arith::FlushDenormalsOp::fold(FoldAdaptor adaptor) {
1288 if (
auto op = this->getOperand().getDefiningOp<arith::FlushDenormalsOp>())
1289 return op.getResult();
1293 adaptor.getOperands(), [](
const APFloat &a) {
1295 return APFloat::getZero(a.getSemantics(), a.isNegative());
1304OpFoldResult arith::AddFOp::fold(FoldAdaptor adaptor) {
1309 bitEnumContainsAll(adaptor.getFastmath(), FastMathFlags::nsz))
1312 auto rm = getRoundingmode();
1314 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1316 result.add(b, convertArithRoundingModeToLLVMIR(rm));
1321void arith::AddFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1322 MLIRContext *context) {
1323 patterns.
add<AddFOfNegFLhs, AddFOfNegFRhs>(context);
1330OpFoldResult arith::SubFOp::fold(FoldAdaptor adaptor) {
1335 bitEnumContainsAll(adaptor.getFastmath(), FastMathFlags::nsz))
1338 auto rm = getRoundingmode();
1340 adaptor.getOperands(),
1341 [rm](
const APFloat &a,
const APFloat &
b) -> std::optional<APFloat> {
1344 if (!APFloat::semanticsHasSignedRepr(a.getSemantics()) &&
1345 a.compare(b) == APFloat::cmpLessThan)
1346 return std::nullopt;
1348 result.subtract(b, convertArithRoundingModeToLLVMIR(rm));
1353void arith::SubFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1354 MLIRContext *context) {
1355 patterns.
add<SubFOfNegZero>(context);
1368template <
typename TruncOp,
typename ExtOp,
typename ExtremumOp>
1369struct NarrowExtremum final : OpRewritePattern<TruncOp> {
1370 using OpRewritePattern<TruncOp>::OpRewritePattern;
1372 LogicalResult matchAndRewrite(TruncOp truncOp,
1373 PatternRewriter &rewriter)
const override {
1374 auto extremumOp = truncOp.getIn().template getDefiningOp<ExtremumOp>();
1375 if (!extremumOp || !extremumOp->hasOneUse())
1378 auto lhsExt = extremumOp.getLhs().template getDefiningOp<ExtOp>();
1379 auto rhsExt = extremumOp.getRhs().template getDefiningOp<ExtOp>();
1380 if (!lhsExt || !rhsExt)
1383 Value
lhs = lhsExt.getIn();
1384 Value
rhs = rhsExt.getIn();
1385 Type narrowType = truncOp.getType();
1386 if (
lhs.getType() != narrowType ||
rhs.getType() != narrowType)
1395 if (
auto narrowFloatType =
1397 auto wideFloatType =
1402 const llvm::fltSemantics &narrowSemantics =
1403 narrowFloatType.getFloatSemantics();
1404 const llvm::fltSemantics &wideSemantics =
1405 wideFloatType.getFloatSemantics();
1406 bool ignoreNaNs =
false;
1407 if constexpr (std::is_same_v<TruncOp, TruncFOp>)
1409 bitEnumContainsAll(extremumOp.getFastmath(), FastMathFlags::nnan);
1410 if (!llvm::APFloatBase::isLosslesslyConvertibleTo(
1411 narrowSemantics, wideSemantics, ignoreNaNs))
1417 extremumOp.getProperties(),
1418 extremumOp->getDiscardableAttrDictionary().getValue());
1429OpFoldResult arith::MaximumFOp::fold(FoldAdaptor adaptor) {
1431 if (getLhs() == getRhs())
1445OpFoldResult arith::MaxNumFOp::fold(FoldAdaptor adaptor) {
1447 if (getLhs() == getRhs())
1461OpFoldResult arith::MaximumNumFOp::fold(FoldAdaptor adaptor) {
1463 if (getLhs() == getRhs())
1477OpFoldResult MaxSIOp::fold(FoldAdaptor adaptor) {
1479 if (getLhs() == getRhs())
1485 if (intValue.isMaxSignedValue())
1488 if (intValue.isMinSignedValue())
1493 llvm::APIntOps::smax);
1500OpFoldResult MaxUIOp::fold(FoldAdaptor adaptor) {
1502 if (getLhs() == getRhs())
1508 if (intValue.isMaxValue())
1511 if (intValue.isMinValue())
1516 llvm::APIntOps::umax);
1523OpFoldResult arith::MinimumFOp::fold(FoldAdaptor adaptor) {
1525 if (getLhs() == getRhs())
1539OpFoldResult arith::MinNumFOp::fold(FoldAdaptor adaptor) {
1541 if (getLhs() == getRhs())
1555OpFoldResult arith::MinimumNumFOp::fold(FoldAdaptor adaptor) {
1557 if (getLhs() == getRhs())
1571OpFoldResult MinSIOp::fold(FoldAdaptor adaptor) {
1573 if (getLhs() == getRhs())
1579 if (intValue.isMinSignedValue())
1582 if (intValue.isMaxSignedValue())
1587 llvm::APIntOps::smin);
1594OpFoldResult MinUIOp::fold(FoldAdaptor adaptor) {
1596 if (getLhs() == getRhs())
1602 if (intValue.isMinValue())
1605 if (intValue.isMaxValue())
1610 llvm::APIntOps::umin);
1617OpFoldResult arith::MulFOp::fold(FoldAdaptor adaptor) {
1625 if (arith::bitEnumContainsAll(getFastmath(), arith::FastMathFlags::nnan |
1626 arith::FastMathFlags::nsz) &&
1627 !(adaptor.getLhs() && adaptor.getRhs())) {
1635 auto rm = getRoundingmode();
1637 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1639 result.multiply(b, convertArithRoundingModeToLLVMIR(rm));
1644void arith::MulFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1645 MLIRContext *context) {
1646 patterns.
add<MulFOfNegF>(context);
1653OpFoldResult arith::DivFOp::fold(FoldAdaptor adaptor) {
1658 auto rm = getRoundingmode();
1660 adaptor.getOperands(), [rm](
const APFloat &a,
const APFloat &
b) {
1662 result.divide(b, convertArithRoundingModeToLLVMIR(rm));
1667void arith::DivFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1668 MLIRContext *context) {
1669 patterns.
add<DivFOfNegF>(context);
1676OpFoldResult arith::RemFOp::fold(FoldAdaptor adaptor) {
1678 [](
const APFloat &a,
const APFloat &
b) {
1683 (void)result.mod(b);
1692template <
typename... Types>
1698template <
typename... ShapedTypes,
typename... ElementTypes>
1701 if (llvm::isa<ShapedType>(type) && !llvm::isa<ShapedTypes...>(type))
1705 if (!llvm::isa<ElementTypes...>(underlyingType))
1708 return underlyingType;
1712template <
typename... ElementTypes>
1719template <
typename... ElementTypes>
1728 auto rankedTensorA = dyn_cast<RankedTensorType>(typeA);
1729 auto rankedTensorB = dyn_cast<RankedTensorType>(typeB);
1730 if (!rankedTensorA || !rankedTensorB)
1732 return rankedTensorA.getEncoding() == rankedTensorB.getEncoding();
1736 if (inputs.size() != 1 || outputs.size() != 1)
1748template <
typename ValType,
typename Op>
1753 if (llvm::cast<ValType>(srcType).getWidth() >=
1754 llvm::cast<ValType>(dstType).getWidth())
1756 << dstType <<
" must be wider than operand type " << srcType;
1762template <
typename ValType,
typename Op>
1767 if (llvm::cast<ValType>(srcType).getWidth() <=
1768 llvm::cast<ValType>(dstType).getWidth())
1770 << dstType <<
" must be shorter than operand type " << srcType;
1776template <
template <
typename>
class WidthComparator,
typename... ElementTypes>
1781 auto srcType =
getTypeIfLike<ElementTypes...>(inputs.front());
1782 auto dstType =
getTypeIfLike<ElementTypes...>(outputs.front());
1783 if (!srcType || !dstType)
1786 return WidthComparator<unsigned>()(dstType.getIntOrFloatBitWidth(),
1787 srcType.getIntOrFloatBitWidth());
1792static FailureOr<APFloat>
1794 const llvm::fltSemantics &targetSemantics,
1798 using fltNonfiniteBehavior = llvm::fltNonfiniteBehavior;
1799 if (sourceValue.isInfinity() &&
1800 (targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
1801 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly))
1803 if (sourceValue.isNaN() &&
1804 targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
1807 bool losesInfo =
false;
1808 auto status = sourceValue.convert(targetSemantics, roundingMode, &losesInfo);
1809 if (losesInfo || status != APFloat::opOK)
1819OpFoldResult arith::ExtUIOp::fold(FoldAdaptor adaptor) {
1820 if (
auto lhs = getIn().getDefiningOp<ExtUIOp>()) {
1823 setNonNeg(
lhs.getNonNeg());
1824 getInMutable().assign(
lhs.getIn());
1829 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1831 adaptor.getOperands(),
getType(),
1832 [bitWidth](
const APInt &a,
bool &castStatus) {
1833 return a.zext(bitWidth);
1841LogicalResult arith::ExtUIOp::verify() {
1849OpFoldResult arith::ExtSIOp::fold(FoldAdaptor adaptor) {
1850 if (
auto lhs = getIn().getDefiningOp<ExtSIOp>()) {
1851 getInMutable().assign(
lhs.getIn());
1856 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
1858 adaptor.getOperands(),
getType(),
1859 [bitWidth](
const APInt &a,
bool &castStatus) {
1860 return a.sext(bitWidth);
1868void arith::ExtSIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
1869 MLIRContext *context) {
1870 patterns.
add<ExtSIOfExtUI>(context);
1873LogicalResult arith::ExtSIOp::verify() {
1883OpFoldResult arith::ExtFOp::fold(FoldAdaptor adaptor) {
1884 if (
auto truncFOp = getOperand().getDefiningOp<TruncFOp>()) {
1885 if (truncFOp.getOperand().getType() ==
getType()) {
1886 arith::FastMathFlags truncFMF =
1887 truncFOp.getFastmath().value_or(arith::FastMathFlags::none);
1888 bool isTruncContract =
1889 bitEnumContainsAll(truncFMF, arith::FastMathFlags::contract);
1890 arith::FastMathFlags extFMF =
1891 getFastmath().value_or(arith::FastMathFlags::none);
1892 bool isExtContract =
1893 bitEnumContainsAll(extFMF, arith::FastMathFlags::contract);
1894 if (isTruncContract && isExtContract) {
1895 return truncFOp.getOperand();
1901 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
1903 adaptor.getOperands(),
getType(),
1904 [&targetSemantics](
const APFloat &a,
bool &castStatus) {
1929 function_ref<std::optional<APFloat>(
const APFloat &,
const APFloat &)>
1932 if (isa_and_nonnull<ub::PoisonAttr>(inAttr))
1934 if (isa_and_nonnull<ub::PoisonAttr>(scaleAttr))
1937 if (!inAttr || !scaleAttr || !resultType)
1940 if (
auto inFloat = dyn_cast<FloatAttr>(inAttr)) {
1941 auto scaleFloat = dyn_cast<FloatAttr>(scaleAttr);
1944 std::optional<APFloat>
result =
1945 calculate(inFloat.getValue(), scaleFloat.getValue());
1948 return FloatAttr::get(resultType, *
result);
1951 auto inElements = dyn_cast<DenseFPElementsAttr>(inAttr);
1952 auto scaleElements = dyn_cast<DenseFPElementsAttr>(scaleAttr);
1953 auto shapedResultType = dyn_cast<ShapedType>(resultType);
1954 if (!inElements || !scaleElements || !shapedResultType ||
1955 !shapedResultType.hasStaticShape() ||
1956 inElements.getNumElements() != scaleElements.getNumElements())
1960 if (inElements.isSplat() && scaleElements.isSplat()) {
1961 std::optional<APFloat>
result =
1962 calculate(inElements.getSplatValue<APFloat>(),
1963 scaleElements.getSplatValue<APFloat>());
1970 results.reserve(inElements.getNumElements());
1971 for (
const auto &[in, scale] : llvm::zip_equal(inElements, scaleElements)) {
1972 std::optional<APFloat>
result = calculate(in, scale);
1975 results.push_back(*
result);
1988OpFoldResult arith::ScalingExtFOp::fold(FoldAdaptor adaptor) {
1996 const llvm::fltSemantics &resSemantics = resElemType.getFloatSemantics();
1998 adaptor.getIn(), adaptor.getScale(),
getType(),
1999 [&resSemantics](
const APFloat &in,
2000 const APFloat &scale) -> std::optional<APFloat> {
2004 return std::nullopt;
2011bool arith::ScalingExtFOp::areCastCompatible(
TypeRange inputs,
2016LogicalResult arith::ScalingExtFOp::verify() {
2024OpFoldResult arith::TruncIOp::fold(FoldAdaptor adaptor) {
2027 Value src = getOperand().getDefiningOp()->getOperand(0);
2032 if (llvm::cast<IntegerType>(srcType).getWidth() >
2033 llvm::cast<IntegerType>(dstType).getWidth()) {
2040 if (srcType == dstType)
2046 setOperand(getOperand().getDefiningOp()->getOperand(0));
2051 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2053 adaptor.getOperands(),
getType(),
2054 [bitWidth](
const APInt &a,
bool &castStatus) {
2055 return a.trunc(bitWidth);
2063void arith::TruncIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2064 MLIRContext *context) {
2065 patterns.
add<NarrowExtremum<TruncIOp, ExtSIOp, MaxSIOp>,
2066 NarrowExtremum<TruncIOp, ExtSIOp, MinSIOp>,
2067 NarrowExtremum<TruncIOp, ExtUIOp, MaxUIOp>,
2068 NarrowExtremum<TruncIOp, ExtUIOp, MinUIOp>, TruncIExtSIToExtSI,
2069 TruncIExtUIToExtUI, TruncIShrSIToTrunciShrUI>(context);
2072LogicalResult arith::TruncIOp::verify() {
2082OpFoldResult arith::TruncFOp::fold(FoldAdaptor adaptor) {
2084 if (
auto extOp = getOperand().getDefiningOp<arith::ExtFOp>()) {
2085 Value src = extOp.getIn();
2087 auto intermediateType =
2091 if (llvm::APFloatBase::isLosslesslyConvertibleTo(
2092 srcType.getFloatSemantics(),
2093 intermediateType.getFloatSemantics())) {
2095 if (srcType.getWidth() > resElemType.getWidth()) {
2101 if (srcType == resElemType)
2106 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
2108 adaptor.getOperands(),
getType(),
2109 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
2110 llvm::RoundingMode llvmRoundingMode =
2112 FailureOr<APFloat>
result =
2122void arith::TruncFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2123 MLIRContext *context) {
2124 patterns.
add<NarrowExtremum<TruncFOp, ExtFOp, MaximumFOp>,
2125 NarrowExtremum<TruncFOp, ExtFOp, MaxNumFOp>,
2126 NarrowExtremum<TruncFOp, ExtFOp, MaximumNumFOp>,
2127 NarrowExtremum<TruncFOp, ExtFOp, MinimumFOp>,
2128 NarrowExtremum<TruncFOp, ExtFOp, MinNumFOp>,
2129 NarrowExtremum<TruncFOp, ExtFOp, MinimumNumFOp>,
2130 TruncFSIToFPToSIToFP, TruncFUIToFPToUIToFP>(context);
2137LogicalResult arith::TruncFOp::verify() {
2145OpFoldResult arith::ConvertFOp::fold(FoldAdaptor adaptor) {
2147 const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
2149 adaptor.getOperands(),
getType(),
2150 [
this, &targetSemantics](
const APFloat &a,
bool &castStatus) {
2151 llvm::RoundingMode llvmRoundingMode =
2153 FailureOr<APFloat>
result =
2168 if (!srcType || !dstType)
2170 return srcType != dstType &&
2174LogicalResult arith::ConvertFOp::verify() {
2177 if (srcType == dstType)
2178 return emitError(
"result element type ")
2179 << dstType <<
" must be different from operand element type "
2181 if (srcType.getWidth() != dstType.getWidth())
2182 return emitError(
"result element type ")
2183 << dstType <<
" must have the same bitwidth as operand element type "
2192OpFoldResult arith::ScalingTruncFOp::fold(FoldAdaptor adaptor) {
2201 const llvm::fltSemantics &inSemantics = inElemType.getFloatSemantics();
2202 const llvm::fltSemantics &resSemantics = resElemType.getFloatSemantics();
2203 llvm::RoundingMode roundingMode =
2206 adaptor.getIn(), adaptor.getScale(),
getType(),
2207 [&](
const APFloat &in,
const APFloat &scale) -> std::optional<APFloat> {
2210 return std::nullopt;
2211 APFloat quotient(in);
2213 FailureOr<APFloat>
result =
2216 return std::nullopt;
2221bool arith::ScalingTruncFOp::areCastCompatible(
TypeRange inputs,
2226LogicalResult arith::ScalingTruncFOp::verify() {
2234void arith::AndIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2235 MLIRContext *context) {
2236 patterns.
add<AndIAndIConstant, AndOfExtUI, AndOfExtSI>(context);
2243void arith::OrIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2244 MLIRContext *context) {
2245 patterns.
add<OrIOrIConstant, OrOfExtUI, OrOfExtSI>(context);
2252template <
typename From,
typename To>
2260 return srcType && dstType;
2271OpFoldResult arith::UIToFPOp::fold(FoldAdaptor adaptor) {
2274 adaptor.getOperands(),
getType(),
2275 [&resEleType](
const APInt &a,
bool &castStatus) {
2276 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2277 APFloat apf(floatTy.getFloatSemantics(),
2278 APInt::getZero(floatTy.getWidth()));
2279 apf.convertFromAPInt(a,
false,
2280 APFloat::rmNearestTiesToEven);
2285void arith::UIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2286 MLIRContext *context) {
2287 patterns.
add<UIToFPOfExtUI>(context);
2298OpFoldResult arith::SIToFPOp::fold(FoldAdaptor adaptor) {
2301 adaptor.getOperands(),
getType(),
2302 [&resEleType](
const APInt &a,
bool &castStatus) {
2303 FloatType floatTy = llvm::cast<FloatType>(resEleType);
2304 APFloat apf(floatTy.getFloatSemantics(),
2305 APInt::getZero(floatTy.getWidth()));
2306 if (a.isNegative() &&
2307 !APFloat::semanticsHasSignedRepr(floatTy.getFloatSemantics())) {
2311 apf.convertFromAPInt(a,
true,
2312 APFloat::rmNearestTiesToEven);
2317void arith::SIToFPOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2318 MLIRContext *context) {
2319 patterns.
add<SIToFPOfExtSI, SIToFPOfExtUI>(context);
2330OpFoldResult arith::FPToUIOp::fold(FoldAdaptor adaptor) {
2332 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2334 adaptor.getOperands(),
getType(),
2335 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2337 APSInt api(bitWidth,
true);
2338 castStatus = APFloat::opInvalidOp !=
2339 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2352OpFoldResult arith::FPToSIOp::fold(FoldAdaptor adaptor) {
2354 unsigned bitWidth = llvm::cast<IntegerType>(resType).getWidth();
2356 adaptor.getOperands(),
getType(),
2357 [&bitWidth](
const APFloat &a,
bool &castStatus) {
2359 APSInt api(bitWidth,
false);
2360 castStatus = APFloat::opInvalidOp !=
2361 a.convertToInteger(api, APFloat::rmTowardZero, &ignored);
2375 return intTy.getWidth();
2376 return IndexType::kInternalStorageBitWidth;
2385 if (!srcType || !dstType)
2389 (srcType.isSignlessInteger() && dstType.
isIndex());
2392bool arith::IndexCastOp::areCastCompatible(
TypeRange inputs,
2397OpFoldResult arith::IndexCastOp::fold(FoldAdaptor adaptor) {
2399 unsigned resultBitwidth = 64;
2401 resultBitwidth = intTy.getWidth();
2404 adaptor.getOperands(),
getType(),
2405 [resultBitwidth](
const APInt &a,
bool & ) {
2406 return a.sextOrTrunc(resultBitwidth);
2413 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastOp>()) {
2414 Value x = inner.getOperand();
2423void arith::IndexCastOp::getCanonicalizationPatterns(
2424 RewritePatternSet &patterns, MLIRContext *context) {
2425 patterns.
add<IndexCastOfExtSI>(context);
2432bool arith::IndexCastUIOp::areCastCompatible(
TypeRange inputs,
2437OpFoldResult arith::IndexCastUIOp::fold(FoldAdaptor adaptor) {
2439 unsigned resultBitwidth = 64;
2441 resultBitwidth = intTy.getWidth();
2444 adaptor.getOperands(),
getType(),
2445 [resultBitwidth](
const APInt &a,
bool & ) {
2446 return a.zextOrTrunc(resultBitwidth);
2453 if (
auto inner = getOperand().getDefiningOp<arith::IndexCastUIOp>()) {
2454 Value x = inner.getOperand();
2463void arith::IndexCastUIOp::getCanonicalizationPatterns(
2464 RewritePatternSet &patterns, MLIRContext *context) {
2465 patterns.
add<IndexCastUIOfExtUI>(context);
2478 if (!srcType || !dstType)
2484OpFoldResult arith::BitcastOp::fold(FoldAdaptor adaptor) {
2486 auto operand = adaptor.getIn();
2491 if (
auto denseAttr = dyn_cast_or_null<DenseElementsAttr>(operand))
2492 return denseAttr.bitcast(llvm::cast<ShapedType>(resType).
getElementType());
2494 if (llvm::isa<ShapedType>(resType))
2502 if (!llvm::isa<FloatAttr, IntegerAttr>(operand))
2505 APInt bits = llvm::isa<FloatAttr>(operand)
2506 ? llvm::cast<FloatAttr>(operand).getValue().bitcastToAPInt()
2507 : llvm::cast<IntegerAttr>(operand).getValue();
2509 "trying to fold on broken IR: operands have incompatible types");
2511 if (
auto resFloatType = dyn_cast<FloatType>(resType))
2512 return FloatAttr::get(resType,
2513 APFloat(resFloatType.getFloatSemantics(), bits));
2514 return IntegerAttr::get(resType, bits);
2517void arith::BitcastOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2518 MLIRContext *context) {
2519 patterns.
add<BitcastOfBitcast>(context);
2529 const APInt &lhs,
const APInt &rhs) {
2530 switch (predicate) {
2531 case arith::CmpIPredicate::eq:
2533 case arith::CmpIPredicate::ne:
2535 case arith::CmpIPredicate::slt:
2536 return lhs.slt(rhs);
2537 case arith::CmpIPredicate::sle:
2538 return lhs.sle(rhs);
2539 case arith::CmpIPredicate::sgt:
2540 return lhs.sgt(rhs);
2541 case arith::CmpIPredicate::sge:
2542 return lhs.sge(rhs);
2543 case arith::CmpIPredicate::ult:
2544 return lhs.ult(rhs);
2545 case arith::CmpIPredicate::ule:
2546 return lhs.ule(rhs);
2547 case arith::CmpIPredicate::ugt:
2548 return lhs.ugt(rhs);
2549 case arith::CmpIPredicate::uge:
2550 return lhs.uge(rhs);
2552 llvm_unreachable(
"unknown cmpi predicate kind");
2557 switch (predicate) {
2558 case arith::CmpIPredicate::eq:
2559 case arith::CmpIPredicate::sle:
2560 case arith::CmpIPredicate::sge:
2561 case arith::CmpIPredicate::ule:
2562 case arith::CmpIPredicate::uge:
2564 case arith::CmpIPredicate::ne:
2565 case arith::CmpIPredicate::slt:
2566 case arith::CmpIPredicate::sgt:
2567 case arith::CmpIPredicate::ult:
2568 case arith::CmpIPredicate::ugt:
2571 llvm_unreachable(
"unknown cmpi predicate kind");
2575 if (
auto intType = dyn_cast<IntegerType>(t)) {
2576 return intType.getWidth();
2578 if (
auto vectorIntType = dyn_cast<VectorType>(t)) {
2579 return llvm::cast<IntegerType>(vectorIntType.getElementType()).getWidth();
2581 return std::nullopt;
2584OpFoldResult arith::CmpIOp::fold(FoldAdaptor adaptor) {
2586 if (getLhs() == getRhs()) {
2592 if (
auto extOp = getLhs().getDefiningOp<ExtSIOp>()) {
2594 std::optional<int64_t> integerWidth =
2596 if (integerWidth && integerWidth.value() == 1 &&
2597 getPredicate() == arith::CmpIPredicate::ne)
2598 return extOp.getOperand();
2600 if (
auto extOp = getLhs().getDefiningOp<ExtUIOp>()) {
2602 std::optional<int64_t> integerWidth =
2604 if (integerWidth && integerWidth.value() == 1 &&
2605 getPredicate() == arith::CmpIPredicate::ne)
2606 return extOp.getOperand();
2611 getPredicate() == arith::CmpIPredicate::ne)
2618 getPredicate() == arith::CmpIPredicate::eq)
2623 if (adaptor.getLhs() && !adaptor.getRhs()) {
2625 using Pred = CmpIPredicate;
2626 const std::pair<Pred, Pred> invPreds[] = {
2627 {Pred::slt, Pred::sgt}, {Pred::sgt, Pred::slt}, {Pred::sle, Pred::sge},
2628 {Pred::sge, Pred::sle}, {Pred::ult, Pred::ugt}, {Pred::ugt, Pred::ult},
2629 {Pred::ule, Pred::uge}, {Pred::uge, Pred::ule}, {Pred::eq, Pred::eq},
2630 {Pred::ne, Pred::ne},
2632 Pred origPred = getPredicate();
2633 for (
auto pred : invPreds) {
2634 if (origPred == pred.first) {
2635 setPredicate(pred.second);
2636 Value
lhs = getLhs();
2637 Value
rhs = getRhs();
2638 getLhsMutable().assign(
rhs);
2639 getRhsMutable().assign(
lhs);
2643 llvm_unreachable(
"unknown cmpi predicate kind");
2648 if (
auto lhs = dyn_cast_if_present<TypedAttr>(adaptor.getLhs())) {
2651 [pred = getPredicate()](
const APInt &
lhs,
const APInt &
rhs) {
2660void arith::CmpIOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
2661 MLIRContext *context) {
2662 patterns.
insert<CmpIExtSI, CmpIExtUI>(context);
2672 const APFloat &lhs,
const APFloat &rhs) {
2673 auto cmpResult = lhs.compare(rhs);
2674 switch (predicate) {
2675 case arith::CmpFPredicate::AlwaysFalse:
2677 case arith::CmpFPredicate::OEQ:
2678 return cmpResult == APFloat::cmpEqual;
2679 case arith::CmpFPredicate::OGT:
2680 return cmpResult == APFloat::cmpGreaterThan;
2681 case arith::CmpFPredicate::OGE:
2682 return cmpResult == APFloat::cmpGreaterThan ||
2683 cmpResult == APFloat::cmpEqual;
2684 case arith::CmpFPredicate::OLT:
2685 return cmpResult == APFloat::cmpLessThan;
2686 case arith::CmpFPredicate::OLE:
2687 return cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2688 case arith::CmpFPredicate::ONE:
2689 return cmpResult != APFloat::cmpUnordered && cmpResult != APFloat::cmpEqual;
2690 case arith::CmpFPredicate::ORD:
2691 return cmpResult != APFloat::cmpUnordered;
2692 case arith::CmpFPredicate::UEQ:
2693 return cmpResult == APFloat::cmpUnordered || cmpResult == APFloat::cmpEqual;
2694 case arith::CmpFPredicate::UGT:
2695 return cmpResult == APFloat::cmpUnordered ||
2696 cmpResult == APFloat::cmpGreaterThan;
2697 case arith::CmpFPredicate::UGE:
2698 return cmpResult == APFloat::cmpUnordered ||
2699 cmpResult == APFloat::cmpGreaterThan ||
2700 cmpResult == APFloat::cmpEqual;
2701 case arith::CmpFPredicate::ULT:
2702 return cmpResult == APFloat::cmpUnordered ||
2703 cmpResult == APFloat::cmpLessThan;
2704 case arith::CmpFPredicate::ULE:
2705 return cmpResult == APFloat::cmpUnordered ||
2706 cmpResult == APFloat::cmpLessThan || cmpResult == APFloat::cmpEqual;
2707 case arith::CmpFPredicate::UNE:
2708 return cmpResult != APFloat::cmpEqual;
2709 case arith::CmpFPredicate::UNO:
2710 return cmpResult == APFloat::cmpUnordered;
2711 case arith::CmpFPredicate::AlwaysTrue:
2714 llvm_unreachable(
"unknown cmpf predicate kind");
2718 auto lhs = dyn_cast_if_present<FloatAttr>(adaptor.getLhs());
2719 auto rhs = dyn_cast_if_present<FloatAttr>(adaptor.getRhs());
2722 if (lhs && lhs.getValue().isNaN())
2724 if (rhs && rhs.getValue().isNaN())
2740 using namespace arith;
2742 case CmpFPredicate::UEQ:
2743 case CmpFPredicate::OEQ:
2744 return CmpIPredicate::eq;
2745 case CmpFPredicate::UGT:
2746 case CmpFPredicate::OGT:
2747 return isUnsigned ? CmpIPredicate::ugt : CmpIPredicate::sgt;
2748 case CmpFPredicate::UGE:
2749 case CmpFPredicate::OGE:
2750 return isUnsigned ? CmpIPredicate::uge : CmpIPredicate::sge;
2751 case CmpFPredicate::ULT:
2752 case CmpFPredicate::OLT:
2753 return isUnsigned ? CmpIPredicate::ult : CmpIPredicate::slt;
2754 case CmpFPredicate::ULE:
2755 case CmpFPredicate::OLE:
2756 return isUnsigned ? CmpIPredicate::ule : CmpIPredicate::sle;
2757 case CmpFPredicate::UNE:
2758 case CmpFPredicate::ONE:
2759 return CmpIPredicate::ne;
2761 llvm_unreachable(
"Unexpected predicate!");
2771 const APFloat &rhs = flt.getValue();
2779 FloatType floatTy = llvm::cast<FloatType>(op.getRhs().getType());
2780 int mantissaWidth = floatTy.getFPMantissaWidth();
2781 if (mantissaWidth <= 0)
2787 if (
auto si = op.getLhs().getDefiningOp<SIToFPOp>()) {
2789 intVal = si.getIn();
2790 }
else if (
auto ui = op.getLhs().getDefiningOp<UIToFPOp>()) {
2792 intVal = ui.getIn();
2799 auto intTy = llvm::cast<IntegerType>(intVal.
getType());
2800 auto intWidth = intTy.getWidth();
2803 auto valueBits = isUnsigned ? intWidth : (intWidth - 1);
2808 if ((
int)intWidth > mantissaWidth) {
2810 int exponent = ilogb(rhs);
2811 if (exponent == APFloat::IEK_Inf) {
2812 int maxExponent = ilogb(APFloat::getLargest(rhs.getSemantics()));
2813 if (maxExponent < (
int)valueBits) {
2820 if (mantissaWidth <= exponent && exponent <= (
int)valueBits) {
2829 switch (op.getPredicate()) {
2830 case CmpFPredicate::ORD:
2835 case CmpFPredicate::UNO:
2848 APFloat signedMax(rhs.getSemantics());
2849 signedMax.convertFromAPInt(APInt::getSignedMaxValue(intWidth),
true,
2850 APFloat::rmNearestTiesToEven);
2851 if (signedMax < rhs) {
2852 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::slt ||
2853 pred == CmpIPredicate::sle)
2864 APFloat unsignedMax(rhs.getSemantics());
2865 unsignedMax.convertFromAPInt(APInt::getMaxValue(intWidth),
false,
2866 APFloat::rmNearestTiesToEven);
2867 if (unsignedMax < rhs) {
2868 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ult ||
2869 pred == CmpIPredicate::ule)
2881 APFloat signedMin(rhs.getSemantics());
2882 signedMin.convertFromAPInt(APInt::getSignedMinValue(intWidth),
true,
2883 APFloat::rmNearestTiesToEven);
2884 if (signedMin > rhs) {
2885 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::sgt ||
2886 pred == CmpIPredicate::sge)
2896 APFloat unsignedMin(rhs.getSemantics());
2897 unsignedMin.convertFromAPInt(APInt::getMinValue(intWidth),
false,
2898 APFloat::rmNearestTiesToEven);
2899 if (unsignedMin > rhs) {
2900 if (pred == CmpIPredicate::ne || pred == CmpIPredicate::ugt ||
2901 pred == CmpIPredicate::uge)
2916 APSInt rhsInt(intWidth, isUnsigned);
2917 if (APFloat::opInvalidOp ==
2918 rhs.convertToInteger(rhsInt, APFloat::rmTowardZero, &ignored)) {
2924 if (!rhs.isZero()) {
2925 APFloat apf(floatTy.getFloatSemantics(),
2926 APInt::getZero(floatTy.getWidth()));
2927 apf.convertFromAPInt(rhsInt, !isUnsigned, APFloat::rmNearestTiesToEven);
2929 bool equal = apf == rhs;
2935 case CmpIPredicate::ne:
2939 case CmpIPredicate::eq:
2943 case CmpIPredicate::ule:
2946 if (rhs.isNegative()) {
2952 case CmpIPredicate::sle:
2955 if (rhs.isNegative())
2956 pred = CmpIPredicate::slt;
2958 case CmpIPredicate::ult:
2961 if (rhs.isNegative()) {
2966 pred = CmpIPredicate::ule;
2968 case CmpIPredicate::slt:
2971 if (!rhs.isNegative())
2972 pred = CmpIPredicate::sle;
2974 case CmpIPredicate::ugt:
2977 if (rhs.isNegative()) {
2983 case CmpIPredicate::sgt:
2986 if (rhs.isNegative())
2987 pred = CmpIPredicate::sge;
2989 case CmpIPredicate::uge:
2992 if (rhs.isNegative()) {
2997 pred = CmpIPredicate::ugt;
2999 case CmpIPredicate::sge:
3002 if (!rhs.isNegative())
3003 pred = CmpIPredicate::sgt;
3013 ConstantOp::create(rewriter, op.getLoc(), intVal.
getType(),
3019void arith::CmpFOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
3020 MLIRContext *context) {
3021 patterns.
insert<CmpFIntToFPConst>(context);
3035 if (!llvm::isa<IntegerType>(op.getType()) || op.getType().isInteger(1))
3051 arith::XOrIOp::create(
3052 rewriter, op.getLoc(), op.getCondition(),
3054 op.getCondition().
getType(), 1)));
3062void arith::SelectOp::getCanonicalizationPatterns(RewritePatternSet &results,
3063 MLIRContext *context) {
3064 results.
add<RedundantSelectFalse, RedundantSelectTrue, SelectNotCond,
3065 SelectI1ToNot, SelectCmpISgeToMaxSI, SelectCmpISgeToMinSI,
3066 SelectCmpISgtToMaxSI, SelectCmpISgtToMinSI, SelectCmpISleToMaxSI,
3067 SelectCmpISleToMinSI, SelectCmpISltToMaxSI, SelectCmpISltToMinSI,
3068 SelectCmpIUgeToMaxUI, SelectCmpIUgeToMinUI, SelectCmpIUgtToMaxUI,
3069 SelectCmpIUgtToMinUI, SelectCmpIUleToMaxUI, SelectCmpIUleToMinUI,
3070 SelectCmpIUltToMaxUI, SelectCmpIUltToMinUI, SelectToExtUI>(
3074OpFoldResult arith::SelectOp::fold(FoldAdaptor adaptor) {
3075 Value trueVal = getTrueValue();
3076 Value falseVal = getFalseValue();
3077 if (trueVal == falseVal)
3080 Value condition = getCondition();
3098 if (
getType().isSignlessInteger(1) &&
3104 auto pred = cmp.getPredicate();
3105 if (pred == arith::CmpIPredicate::eq || pred == arith::CmpIPredicate::ne) {
3106 auto cmpLhs = cmp.getLhs();
3107 auto cmpRhs = cmp.getRhs();
3115 if ((cmpLhs == trueVal && cmpRhs == falseVal) ||
3116 (cmpRhs == trueVal && cmpLhs == falseVal))
3117 return pred == arith::CmpIPredicate::ne ? trueVal : falseVal;
3124 dyn_cast_if_present<DenseElementsAttr>(adaptor.getCondition())) {
3126 assert(cond.getType().hasStaticShape() &&
3127 "DenseElementsAttr must have static shape");
3129 dyn_cast_if_present<DenseElementsAttr>(adaptor.getTrueValue())) {
3131 dyn_cast_if_present<DenseElementsAttr>(adaptor.getFalseValue())) {
3132 SmallVector<Attribute> results;
3133 results.reserve(
static_cast<size_t>(cond.getNumElements()));
3134 auto condVals = llvm::make_range(cond.value_begin<BoolAttr>(),
3135 cond.value_end<BoolAttr>());
3136 auto lhsVals = llvm::make_range(
lhs.value_begin<Attribute>(),
3137 lhs.value_end<Attribute>());
3138 auto rhsVals = llvm::make_range(
rhs.value_begin<Attribute>(),
3139 rhs.value_end<Attribute>());
3141 for (
auto [condVal, lhsVal, rhsVal] :
3142 llvm::zip_equal(condVals, lhsVals, rhsVals))
3143 results.push_back(condVal.getValue() ? lhsVal : rhsVal);
3153ParseResult SelectOp::parse(OpAsmParser &parser, OperationState &
result) {
3154 Type conditionType, resultType;
3155 SmallVector<OpAsmParser::UnresolvedOperand, 3> operands;
3163 conditionType = resultType;
3170 result.addTypes(resultType);
3172 {conditionType, resultType, resultType},
3176void arith::SelectOp::print(OpAsmPrinter &p) {
3177 p <<
" " << getOperands();
3180 if (ShapedType condType = dyn_cast<ShapedType>(getCondition().
getType()))
3181 p << condType <<
", ";
3185LogicalResult arith::SelectOp::verify() {
3186 Type conditionType = getCondition().getType();
3193 if (!llvm::isa<TensorType, VectorType>(resultType))
3194 return emitOpError() <<
"expected condition to be a signless i1, but got "
3197 if (conditionType != shapedConditionType) {
3198 return emitOpError() <<
"expected condition type to have the same shape "
3199 "as the result type, expected "
3200 << shapedConditionType <<
", but got "
3209OpFoldResult arith::ShLIOp::fold(FoldAdaptor adaptor) {
3223 bool bounded =
false;
3225 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3226 bounded = b.ult(b.getBitWidth());
3229 return bounded ?
result : Attribute();
3236OpFoldResult arith::ShRUIOp::fold(FoldAdaptor adaptor) {
3251 if (getLhs() == getRhs())
3254 bool bounded =
false;
3256 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3257 bounded = b.ult(b.getBitWidth());
3260 return bounded ?
result : Attribute();
3267OpFoldResult arith::ShRSIOp::fold(FoldAdaptor adaptor) {
3282 if (getLhs() == getRhs())
3290 bool bounded =
false;
3292 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
3293 bounded = b.ult(b.getBitWidth());
3296 return bounded ?
result : Attribute();
3306 bool useOnlyFiniteValue) {
3308 case AtomicRMWKind::maximumf: {
3309 const llvm::fltSemantics &semantic =
3310 llvm::cast<FloatType>(resultType).getFloatSemantics();
3311 APFloat identity = useOnlyFiniteValue
3312 ? APFloat::getLargest(semantic,
true)
3313 : APFloat::getInf(semantic,
true);
3316 case AtomicRMWKind::maxnumf: {
3317 const llvm::fltSemantics &semantic =
3318 llvm::cast<FloatType>(resultType).getFloatSemantics();
3319 APFloat identity = APFloat::getNaN(semantic,
true);
3322 case AtomicRMWKind::addf:
3323 case AtomicRMWKind::addi:
3324 case AtomicRMWKind::maxu:
3325 case AtomicRMWKind::ori:
3326 case AtomicRMWKind::xori:
3328 case AtomicRMWKind::andi:
3331 APInt::getAllOnes(llvm::cast<IntegerType>(resultType).getWidth()));
3332 case AtomicRMWKind::maxs:
3334 resultType, APInt::getSignedMinValue(
3335 llvm::cast<IntegerType>(resultType).getWidth()));
3336 case AtomicRMWKind::minimumf: {
3337 const llvm::fltSemantics &semantic =
3338 llvm::cast<FloatType>(resultType).getFloatSemantics();
3339 APFloat identity = useOnlyFiniteValue
3340 ? APFloat::getLargest(semantic,
false)
3341 : APFloat::getInf(semantic,
false);
3345 case AtomicRMWKind::minnumf: {
3346 const llvm::fltSemantics &semantic =
3347 llvm::cast<FloatType>(resultType).getFloatSemantics();
3348 APFloat identity = APFloat::getNaN(semantic,
false);
3351 case AtomicRMWKind::mins:
3353 resultType, APInt::getSignedMaxValue(
3354 llvm::cast<IntegerType>(resultType).getWidth()));
3355 case AtomicRMWKind::minu:
3358 APInt::getMaxValue(llvm::cast<IntegerType>(resultType).getWidth()));
3359 case AtomicRMWKind::muli:
3361 case AtomicRMWKind::mulf:
3364 case AtomicRMWKind::assign:
3373 std::optional<AtomicRMWKind> maybeKind =
3376 .Case([](arith::AddFOp op) {
return AtomicRMWKind::addf; })
3377 .Case([](arith::MulFOp op) {
return AtomicRMWKind::mulf; })
3378 .Case([](arith::MaximumFOp op) {
return AtomicRMWKind::maximumf; })
3379 .Case([](arith::MinimumFOp op) {
return AtomicRMWKind::minimumf; })
3380 .Case([](arith::MaxNumFOp op) {
return AtomicRMWKind::maxnumf; })
3381 .Case([](arith::MinNumFOp op) {
return AtomicRMWKind::minnumf; })
3383 .Case([](arith::AddIOp op) {
return AtomicRMWKind::addi; })
3384 .Case([](arith::OrIOp op) {
return AtomicRMWKind::ori; })
3385 .Case([](arith::XOrIOp op) {
return AtomicRMWKind::xori; })
3386 .Case([](arith::AndIOp op) {
return AtomicRMWKind::andi; })
3387 .Case([](arith::MaxUIOp op) {
return AtomicRMWKind::maxu; })
3388 .Case([](arith::MinUIOp op) {
return AtomicRMWKind::minu; })
3389 .Case([](arith::MaxSIOp op) {
return AtomicRMWKind::maxs; })
3390 .Case([](arith::MinSIOp op) {
return AtomicRMWKind::mins; })
3391 .Case([](arith::MulIOp op) {
return AtomicRMWKind::muli; })
3392 .Default(std::nullopt);
3394 return std::nullopt;
3397 bool useOnlyFiniteValue =
false;
3398 auto fmfOpInterface = dyn_cast<ArithFastMathInterface>(op);
3399 if (fmfOpInterface) {
3400 arith::FastMathFlagsAttr fmfAttr = fmfOpInterface.getFastMathFlagsAttr();
3401 useOnlyFiniteValue =
3402 bitEnumContainsAny(fmfAttr.getValue(), arith::FastMathFlags::ninf);
3410 useOnlyFiniteValue);
3416 bool useOnlyFiniteValue) {
3418 useOnlyFiniteValue))
3419 return arith::ConstantOp::create(builder, loc, attr);
3428 case AtomicRMWKind::addf:
3429 return arith::AddFOp::create(builder, loc, lhs, rhs);
3430 case AtomicRMWKind::addi:
3431 return arith::AddIOp::create(builder, loc, lhs, rhs);
3432 case AtomicRMWKind::mulf:
3433 return arith::MulFOp::create(builder, loc, lhs, rhs);
3434 case AtomicRMWKind::muli:
3435 return arith::MulIOp::create(builder, loc, lhs, rhs);
3436 case AtomicRMWKind::maximumf:
3437 return arith::MaximumFOp::create(builder, loc, lhs, rhs);
3438 case AtomicRMWKind::minimumf:
3439 return arith::MinimumFOp::create(builder, loc, lhs, rhs);
3440 case AtomicRMWKind::maxnumf:
3441 return arith::MaxNumFOp::create(builder, loc, lhs, rhs);
3442 case AtomicRMWKind::minnumf:
3443 return arith::MinNumFOp::create(builder, loc, lhs, rhs);
3444 case AtomicRMWKind::maxs:
3445 return arith::MaxSIOp::create(builder, loc, lhs, rhs);
3446 case AtomicRMWKind::mins:
3447 return arith::MinSIOp::create(builder, loc, lhs, rhs);
3448 case AtomicRMWKind::maxu:
3449 return arith::MaxUIOp::create(builder, loc, lhs, rhs);
3450 case AtomicRMWKind::minu:
3451 return arith::MinUIOp::create(builder, loc, lhs, rhs);
3452 case AtomicRMWKind::ori:
3453 return arith::OrIOp::create(builder, loc, lhs, rhs);
3454 case AtomicRMWKind::andi:
3455 return arith::AndIOp::create(builder, loc, lhs, rhs);
3456 case AtomicRMWKind::xori:
3457 return arith::XOrIOp::create(builder, loc, lhs, rhs);
3459 case AtomicRMWKind::assign:
3470#define GET_OP_CLASSES
3471#include "mlir/Dialect/Arith/IR/ArithOps.cpp.inc"
3477#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 Value foldIdempotentOfSameOp(OpTy op)
Fold op(a, op(a, b)) to op(a, b) for an associative, commutative and idempotent op (e....
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 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...
Attribute constFoldBinaryOpConditional(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Performs constant folding calculate with element-wise behavior on the two attributes in operands and ...
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.
Attribute constFoldUnaryOpConditional(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Performs constant folding calculate with element-wise behavior on the one attributes in operands and ...
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.