23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/SmallVectorExtras.h"
38 if (
auto boolAttr = dyn_cast<BoolAttr>(attr))
39 return boolAttr.getValue();
40 if (
auto splatAttr = dyn_cast<SplatElementsAttr>(attr))
41 if (splatAttr.getElementType().isInteger(1))
42 return splatAttr.getSplatValue<
bool>();
57 if (
auto vector = dyn_cast<ElementsAttr>(composite)) {
58 assert(
indices.size() == 1 &&
"must have exactly one index for a vector");
62 if (
auto array = dyn_cast<ArrayAttr>(composite)) {
63 assert(!
indices.empty() &&
"must have at least one index for an array");
72 bool div0 =
b.isZero();
73 bool overflow = a.isMinSignedValue() &&
b.isAllOnes();
75 return div0 || overflow;
83#include "SPIRVCanonicalization.inc"
93template <
typename AccessChainOp>
95 using OpRewritePattern<AccessChainOp>::OpRewritePattern;
97 LogicalResult matchAndRewrite(AccessChainOp accessChainOp,
98 PatternRewriter &rewriter)
const override {
99 auto parentAccessChainOp =
100 accessChainOp.getBasePtr().template getDefiningOp<AccessChainOp>();
102 if (!parentAccessChainOp) {
107 SmallVector<Value, 4>
indices(parentAccessChainOp.getIndices());
108 llvm::append_range(
indices, accessChainOp.getIndices());
111 accessChainOp, parentAccessChainOp.getBasePtr(),
indices);
118void spirv::AccessChainOp::getCanonicalizationPatterns(
120 results.
add<CombineChainedAccessChain<spirv::AccessChainOp>>(context);
123void spirv::InBoundsAccessChainOp::getCanonicalizationPatterns(
125 results.
add<CombineChainedAccessChain<spirv::InBoundsAccessChainOp>>(context);
132template <
typename Op>
136 static constexpr bool IsSub = std::is_same_v<Op, spirv::ISubBorrowOp>;
140 Value lhs = op.getOperand1();
141 Value rhs = op.getOperand2();
146 std::array<Value, 2> constituents =
147 IsSub ? std::array{lhs, rhs} : std::array{rhs, lhs};
161 [](
const APInt &a,
const APInt &
b) {
return IsSub ? a -
b : a +
b; });
166 {lhsAttr, rhsAttr}, [](
const APInt &a,
const APInt &
b) {
167 bool wrapped =
IsSub ? a.ult(
b) : (a +
b).ult(a);
168 return APInt(a.getBitWidth(), wrapped ? 1 : 0);
174 op, op.getType(), rewriter.
getArrayAttr({lowBits, wrapBit}));
180void spirv::IAddCarryOp::getCanonicalizationPatterns(
186void spirv::ISubBorrowOp::getCanonicalizationPatterns(
195template <
typename MulOp,
bool IsSigned>
202 Value lhs = op.getOperand1();
203 Value rhs = op.getOperand2();
204 Type constituentType = lhs.getType();
208 Value zero = spirv::ConstantOp::getZero(constituentType, loc, rewriter);
209 Value constituents[2] = {zero, zero};
231 [](
const APInt &a,
const APInt &
b) {
return a *
b; });
237 {lhsAttr, rhsAttr}, [](
const APInt &a,
const APInt &
b) {
239 return llvm::APIntOps::mulhs(a,
b);
241 return llvm::APIntOps::mulhu(a,
b);
248 op, op.getType(), rewriter.
getArrayAttr({lowBits, highBits}));
254void spirv::SMulExtendedOp::getCanonicalizationPatterns(
265 Value lhs = op.getOperand1();
266 Value rhs = op.getOperand2();
267 Type constituentType = lhs.getType();
271 Value zero = spirv::ConstantOp::getZero(constituentType, loc, rewriter);
272 Value constituents[2] = {lhs, zero};
283void spirv::UMulExtendedOp::getCanonicalizationPatterns(
306 auto prevUMod = umodOp.getOperand(0).getDefiningOp<spirv::UModOp>();
318 bool isApplicable =
false;
319 if (
auto prevInt = dyn_cast<IntegerAttr>(prevValue)) {
320 auto currInt = cast<IntegerAttr>(currValue);
321 if (currInt.getValue().isZero())
323 isApplicable = prevInt.getValue().urem(currInt.getValue()) == 0;
324 }
else if (
auto prevVec = dyn_cast<DenseElementsAttr>(prevValue)) {
325 auto currVec = cast<DenseElementsAttr>(currValue);
326 if (llvm::any_of(currVec.getValues<APInt>(),
327 [](
const APInt &curr) { return curr.isZero(); }))
329 isApplicable = llvm::all_of(llvm::zip_equal(prevVec.getValues<APInt>(),
330 currVec.getValues<APInt>()),
331 [](
const auto &pair) {
332 auto &[prev, curr] = pair;
333 return prev.urem(curr) == 0;
343 umodOp, umodOp.getType(), prevUMod.getOperand(0), umodOp.getOperand(1));
359 Value curInput = getOperand();
364 if (
auto prevCast = curInput.
getDefiningOp<spirv::BitcastOp>()) {
365 Value prevInput = prevCast.getOperand();
369 getOperandMutable().assign(prevInput);
381OpFoldResult spirv::CompositeExtractOp::fold(FoldAdaptor adaptor) {
382 Value compositeOp = getComposite();
384 while (
auto insertOp =
387 return insertOp.getObject();
388 compositeOp = insertOp.getComposite();
391 if (
auto constructOp =
393 auto type = cast<spirv::CompositeType>(constructOp.getType());
395 constructOp.getConstituents().size() == type.getNumElements()) {
396 auto i = cast<IntegerAttr>(*
getIndices().begin());
397 if (i.getValue().getSExtValue() <
398 static_cast<int64_t>(constructOp.getConstituents().size()))
399 return constructOp.getConstituents()[i.getValue().getSExtValue()];
404 return static_cast<unsigned>(cast<IntegerAttr>(attr).getInt());
424 return getOperand1();
432 adaptor.getOperands(),
433 [](APInt a,
const APInt &
b) { return std::move(a) + b; });
443 return getOperand2();
446 return getOperand1();
454 adaptor.getOperands(),
455 [](
const APInt &a,
const APInt &
b) { return a * b; });
464 if (getOperand1() == getOperand2())
473 adaptor.getOperands(),
474 [](APInt a,
const APInt &
b) { return std::move(a) - b; });
484 return getOperand1();
494 bool div0OrOverflow =
false;
496 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
497 if (div0OrOverflow || isDivZeroOrOverflow(a, b)) {
498 div0OrOverflow = true;
503 return div0OrOverflow ?
Attribute() : res;
525 bool div0OrOverflow =
false;
527 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
528 if (div0OrOverflow || isDivZeroOrOverflow(a, b)) {
529 div0OrOverflow = true;
532 APInt c = a.abs().urem(
b.abs());
535 if (
b.isNegative()) {
536 APInt zero = APInt::getZero(c.getBitWidth());
537 return a.isNegative() ? (std::move(zero) - c) : (b + std::move(c));
540 return b - std::move(c);
543 return div0OrOverflow ?
Attribute() : res;
565 bool div0OrOverflow =
false;
567 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
568 if (div0OrOverflow || isDivZeroOrOverflow(a, b)) {
569 div0OrOverflow = true;
574 return div0OrOverflow ?
Attribute() : res;
584 return getOperand1();
594 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
595 if (div0 || b.isZero()) {
621 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
622 if (div0 || b.isZero()) {
635OpFoldResult spirv::SNegateOp::fold(FoldAdaptor adaptor) {
637 auto op = getOperand();
638 if (
auto negateOp = op.getDefiningOp<spirv::SNegateOp>())
639 return negateOp->getOperand(0);
645 adaptor.getOperands(), [](
const APInt &a) {
646 APInt zero = APInt::getZero(a.getBitWidth());
647 return std::move(zero) - a;
655OpFoldResult spirv::NotOp::fold(spirv::NotOp::FoldAdaptor adaptor) {
657 auto op = getOperand();
658 if (
auto notOp = op.getDefiningOp<spirv::NotOp>())
659 return notOp->getOperand(0);
674OpFoldResult spirv::LogicalAndOp::fold(FoldAdaptor adaptor) {
675 if (std::optional<bool> rhs =
679 return getOperand1();
683 return adaptor.getOperand2();
694spirv::LogicalEqualOp::fold(spirv::LogicalEqualOp::FoldAdaptor adaptor) {
696 if (getOperand1() == getOperand2()) {
698 if (isa<IntegerType>(
getType()))
700 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
705 adaptor.getOperands(), [](
const APInt &a,
const APInt &
b) {
706 return a == b ? APInt::getAllOnes(1) : APInt::getZero(1);
714OpFoldResult spirv::LogicalNotEqualOp::fold(FoldAdaptor adaptor) {
715 if (std::optional<bool> rhs =
719 return getOperand1();
723 if (getOperand1() == getOperand2()) {
725 if (isa<IntegerType>(
getType()))
727 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
732 adaptor.getOperands(), [](
const APInt &a,
const APInt &
b) {
733 return a == b ? APInt::getZero(1) : APInt::getAllOnes(1);
741OpFoldResult spirv::LogicalNotOp::fold(FoldAdaptor adaptor) {
743 auto op = getOperand();
744 if (
auto notOp = op.getDefiningOp<spirv::LogicalNotOp>())
745 return notOp->getOperand(0);
751 adaptor.getOperands(), [](
const APInt &a) {
752 return a == 1 ? APInt::getZero(1) : APInt::getAllOnes(1);
756void spirv::LogicalNotOp::getCanonicalizationPatterns(
759 .
add<ConvertLogicalNotOfIEqual, ConvertLogicalNotOfINotEqual,
760 ConvertLogicalNotOfLogicalEqual, ConvertLogicalNotOfLogicalNotEqual>(
768OpFoldResult spirv::LogicalOrOp::fold(FoldAdaptor adaptor) {
772 return adaptor.getOperand2();
777 return getOperand1();
788OpFoldResult spirv::SelectOp::fold(FoldAdaptor adaptor) {
790 Value trueVals = getTrueValue();
791 Value falseVals = getFalseValue();
792 if (trueVals == falseVals)
800 return *boolAttr ? trueVals : falseVals;
803 if (!operands[0] || !operands[1] || !operands[2])
809 auto condAttrs = dyn_cast<DenseElementsAttr>(operands[0]);
810 auto trueAttrs = dyn_cast<DenseElementsAttr>(operands[1]);
811 auto falseAttrs = dyn_cast<DenseElementsAttr>(operands[2]);
812 if (!condAttrs || !trueAttrs || !falseAttrs)
815 auto elementResults = llvm::to_vector<4>(trueAttrs.getValues<
Attribute>());
816 auto iters = llvm::zip_equal(elementResults, condAttrs.getValues<
BoolAttr>(),
818 for (
auto [
result, cond, falseRes] : iters) {
819 if (!cond.getValue())
823 auto resultType = trueAttrs.getType();
831OpFoldResult spirv::IEqualOp::fold(spirv::IEqualOp::FoldAdaptor adaptor) {
833 if (getOperand1() == getOperand2()) {
835 if (isa<IntegerType>(
getType()))
837 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
842 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
843 return a ==
b ? APInt::getAllOnes(1) : APInt::
getZero(1);
851OpFoldResult spirv::INotEqualOp::fold(spirv::INotEqualOp::FoldAdaptor adaptor) {
853 if (getOperand1() == getOperand2()) {
855 if (isa<IntegerType>(
getType()))
857 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
862 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
863 return a ==
b ? APInt::getZero(1) : APInt::getAllOnes(1);
872spirv::SGreaterThanOp::fold(spirv::SGreaterThanOp::FoldAdaptor adaptor) {
874 if (getOperand1() == getOperand2()) {
876 if (isa<IntegerType>(
getType()))
878 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
883 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
884 return a.sgt(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
893 spirv::SGreaterThanEqualOp::FoldAdaptor adaptor) {
895 if (getOperand1() == getOperand2()) {
897 if (isa<IntegerType>(
getType()))
899 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
904 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
905 return a.sge(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
914spirv::UGreaterThanOp::fold(spirv::UGreaterThanOp::FoldAdaptor adaptor) {
916 if (getOperand1() == getOperand2()) {
918 if (isa<IntegerType>(
getType()))
920 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
925 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
926 return a.ugt(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
935 spirv::UGreaterThanEqualOp::FoldAdaptor adaptor) {
937 if (getOperand1() == getOperand2()) {
939 if (isa<IntegerType>(
getType()))
941 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
946 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
947 return a.uge(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
955OpFoldResult spirv::SLessThanOp::fold(spirv::SLessThanOp::FoldAdaptor adaptor) {
957 if (getOperand1() == getOperand2()) {
959 if (isa<IntegerType>(
getType()))
961 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
966 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
967 return a.slt(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
976spirv::SLessThanEqualOp::fold(spirv::SLessThanEqualOp::FoldAdaptor adaptor) {
978 if (getOperand1() == getOperand2()) {
980 if (isa<IntegerType>(
getType()))
982 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
987 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
988 return a.sle(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
996OpFoldResult spirv::ULessThanOp::fold(spirv::ULessThanOp::FoldAdaptor adaptor) {
998 if (getOperand1() == getOperand2()) {
1000 if (isa<IntegerType>(
getType()))
1002 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
1007 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
1008 return a.ult(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
1017spirv::ULessThanEqualOp::fold(spirv::ULessThanEqualOp::FoldAdaptor adaptor) {
1019 if (getOperand1() == getOperand2()) {
1021 if (isa<IntegerType>(
getType()))
1023 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
1028 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
1029 return a.ule(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
1038 spirv::ShiftLeftLogicalOp::FoldAdaptor adaptor) {
1041 return getOperand1();
1052 bool shiftToLarge =
false;
1054 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
1055 if (shiftToLarge || b.uge(a.getBitWidth())) {
1056 shiftToLarge = true;
1061 return shiftToLarge ?
Attribute() : res;
1069 spirv::ShiftRightArithmeticOp::FoldAdaptor adaptor) {
1072 return getOperand1();
1083 bool shiftToLarge =
false;
1085 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
1086 if (shiftToLarge || b.uge(a.getBitWidth())) {
1087 shiftToLarge = true;
1092 return shiftToLarge ?
Attribute() : res;
1100 spirv::ShiftRightLogicalOp::FoldAdaptor adaptor) {
1103 return getOperand1();
1114 bool shiftToLarge =
false;
1116 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
1117 if (shiftToLarge || b.uge(a.getBitWidth())) {
1118 shiftToLarge = true;
1123 return shiftToLarge ?
Attribute() : res;
1131spirv::BitwiseAndOp::fold(spirv::BitwiseAndOp::FoldAdaptor adaptor) {
1133 if (getOperand1() == getOperand2()) {
1134 return getOperand1();
1140 if (rhsMask.isZero())
1141 return getOperand2();
1144 if (rhsMask.isAllOnes())
1145 return getOperand1();
1148 if (
auto zext = getOperand1().getDefiningOp<spirv::UConvertOp>()) {
1151 if (rhsMask.zextOrTrunc(valueBits).isAllOnes())
1152 return getOperand1();
1162 adaptor.getOperands(),
1163 [](
const APInt &a,
const APInt &
b) { return a & b; });
1170OpFoldResult spirv::BitwiseOrOp::fold(spirv::BitwiseOrOp::FoldAdaptor adaptor) {
1172 if (getOperand1() == getOperand2()) {
1173 return getOperand1();
1179 if (rhsMask.isZero())
1180 return getOperand1();
1183 if (rhsMask.isAllOnes())
1184 return getOperand2();
1193 adaptor.getOperands(),
1194 [](
const APInt &a,
const APInt &
b) { return a | b; });
1202spirv::BitwiseXorOp::fold(spirv::BitwiseXorOp::FoldAdaptor adaptor) {
1205 return getOperand1();
1209 if (getOperand1() == getOperand2())
1218 adaptor.getOperands(),
1219 [](
const APInt &a,
const APInt &
b) { return a ^ b; });
1252struct ConvertSelectionOpToSelect final :
OpRewritePattern<spirv::SelectionOp> {
1255 LogicalResult matchAndRewrite(spirv::SelectionOp selectionOp,
1256 PatternRewriter &rewriter)
const override {
1257 Operation *op = selectionOp.getOperation();
1266 if (llvm::range_size(body) != 4) {
1270 Block *headerBlock = selectionOp.getHeaderBlock();
1271 if (!onlyContainsBranchConditionalOp(headerBlock)) {
1275 auto brConditionalOp =
1276 cast<spirv::BranchConditionalOp>(headerBlock->
front());
1278 Block *trueBlock = brConditionalOp.getSuccessor(0);
1279 Block *falseBlock = brConditionalOp.getSuccessor(1);
1280 Block *mergeBlock = selectionOp.getMergeBlock();
1282 if (
failed(canCanonicalizeSelection(trueBlock, falseBlock, mergeBlock)))
1285 Value trueValue = getSrcValue(trueBlock);
1286 Value falseValue = getSrcValue(falseBlock);
1287 Value ptrValue = getDstPtr(trueBlock);
1288 auto storeOp = cast<spirv::StoreOp>(trueBlock->
front());
1290 auto selectOp = spirv::SelectOp::create(
1291 rewriter, selectionOp.getLoc(), trueValue.
getType(),
1292 brConditionalOp.getCondition(), trueValue, falseValue);
1293 auto newStore = spirv::StoreOp::create(
1294 rewriter, selectOp.getLoc(), ptrValue, selectOp.getResult(),
1295 storeOp.getMemoryAccessAttr(), storeOp.getAlignmentAttr());
1296 newStore->setDiscardableAttrs(storeOp->getDiscardableAttrDictionary());
1310 LogicalResult canCanonicalizeSelection(
Block *trueBlock,
Block *falseBlock,
1311 Block *mergeBlock)
const;
1313 bool onlyContainsBranchConditionalOp(
Block *block)
const {
1314 return llvm::hasSingleElement(*block) &&
1315 isa<spirv::BranchConditionalOp>(block->
front());
1318 bool isSameAttrList(spirv::StoreOp
lhs, spirv::StoreOp
rhs)
const {
1319 return lhs->getDiscardableAttrDictionary() ==
1320 rhs->getDiscardableAttrDictionary() &&
1321 lhs.getProperties() ==
rhs.getProperties();
1325 Value getSrcValue(
Block *block)
const {
1326 auto storeOp = cast<spirv::StoreOp>(block->
front());
1327 return storeOp.getValue();
1331 Value getDstPtr(
Block *block)
const {
1332 auto storeOp = cast<spirv::StoreOp>(block->
front());
1333 return storeOp.getPtr();
1337LogicalResult ConvertSelectionOpToSelect::canCanonicalizeSelection(
1340 if (llvm::range_size(*trueBlock) != 2 || llvm::range_size(*falseBlock) != 2) {
1344 auto trueBrStoreOp = dyn_cast<spirv::StoreOp>(trueBlock->
front());
1345 auto trueBrBranchOp =
1346 dyn_cast<spirv::BranchOp>(*std::next(trueBlock->
begin()));
1347 auto falseBrStoreOp = dyn_cast<spirv::StoreOp>(falseBlock->
front());
1348 auto falseBrBranchOp =
1349 dyn_cast<spirv::BranchOp>(*std::next(falseBlock->
begin()));
1351 if (!trueBrStoreOp || !trueBrBranchOp || !falseBrStoreOp ||
1361 bool isScalarOrVector =
1362 cast<spirv::SPIRVType>(trueBrStoreOp.getValue().getType())
1363 .isScalarOrVector();
1367 if ((trueBrStoreOp.getPtr() != falseBrStoreOp.getPtr()) ||
1368 !isSameAttrList(trueBrStoreOp, falseBrStoreOp) || !isScalarOrVector) {
1372 if ((trueBrBranchOp->getSuccessor(0) != mergeBlock) ||
1373 (falseBrBranchOp->getSuccessor(0) != mergeBlock)) {
1381void spirv::SelectionOp::getCanonicalizationPatterns(RewritePatternSet &results,
1382 MLIRContext *context) {
1383 results.
add<ConvertSelectionOpToSelect>(context);
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
static Value getZero(OpBuilder &b, Location loc, Type elementType)
Get zero value for an element type.
static uint64_t zext(uint32_t arg)
ArithmeticExtendedBinaryFold< spirv::ISubBorrowOp > ISubBorrowFold
static Attribute extractCompositeElement(Attribute composite, ArrayRef< unsigned > indices)
MulExtendedFold< spirv::UMulExtendedOp, false > UMulExtendedOpFold
MulExtendedFold< spirv::SMulExtendedOp, true > SMulExtendedOpFold
static std::optional< bool > getScalarOrSplatBoolAttr(Attribute attr)
Returns the boolean value under the hood if the given boolAttr is a scalar or splat vector bool const...
static bool isDivZeroOrOverflow(const APInt &a, const APInt &b)
ArithmeticExtendedBinaryFold< spirv::IAddCarryOp > IAddCarryFold
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
static BoolAttr get(MLIRContext *context, bool value)
This class is a general helper class for creating context-global objects like types,...
TypedAttr getZeroAttr(Type type)
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class represents a single result from folding an operation.
This provides public APIs that all operations should have.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
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 constFoldBinaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
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_int_predicate_matcher m_One()
Matches a constant scalar / vector splat / tensor splat integer one.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Attribute constFoldUnaryOp(ArrayRef< Attribute > operands, Type resultType, CalculationT &&calculate)
LogicalResult matchAndRewrite(Op op, PatternRewriter &rewriter) const override
static constexpr bool IsSub
LogicalResult matchAndRewrite(MulOp op, PatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(spirv::UModOp umodOp, PatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(spirv::UMulExtendedOp op, PatternRewriter &rewriter) const override
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern Base
Type alias to allow derived classes to inherit constructors with using Base::Base;.
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})