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>;
146 std::array<Value, 2> constituents =
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>
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(
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() ? (zero - c) : (b + c);
539 return a.isNegative() ? (
b - c) : c;
541 return div0OrOverflow ?
Attribute() : res;
563 bool div0OrOverflow =
false;
565 adaptor.getOperands(), [&](APInt a,
const APInt &
b) {
566 if (div0OrOverflow || isDivZeroOrOverflow(a, b)) {
567 div0OrOverflow = true;
572 return div0OrOverflow ?
Attribute() : res;
582 return getOperand1();
592 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
593 if (div0 || b.isZero()) {
619 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
620 if (div0 || b.isZero()) {
633OpFoldResult spirv::SNegateOp::fold(FoldAdaptor adaptor) {
635 auto op = getOperand();
636 if (
auto negateOp = op.getDefiningOp<spirv::SNegateOp>())
637 return negateOp->getOperand(0);
643 adaptor.getOperands(), [](
const APInt &a) {
644 APInt zero = APInt::getZero(a.getBitWidth());
653OpFoldResult spirv::NotOp::fold(spirv::NotOp::FoldAdaptor adaptor) {
655 auto op = getOperand();
656 if (
auto notOp = op.getDefiningOp<spirv::NotOp>())
657 return notOp->getOperand(0);
672OpFoldResult spirv::LogicalAndOp::fold(FoldAdaptor adaptor) {
673 if (std::optional<bool>
rhs =
677 return getOperand1();
681 return adaptor.getOperand2();
692spirv::LogicalEqualOp::fold(spirv::LogicalEqualOp::FoldAdaptor adaptor) {
694 if (getOperand1() == getOperand2()) {
696 if (isa<IntegerType>(
getType()))
698 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
703 adaptor.getOperands(), [](
const APInt &a,
const APInt &
b) {
704 return a == b ? APInt::getAllOnes(1) : APInt::getZero(1);
712OpFoldResult spirv::LogicalNotEqualOp::fold(FoldAdaptor adaptor) {
713 if (std::optional<bool>
rhs =
717 return getOperand1();
721 if (getOperand1() == getOperand2()) {
723 if (isa<IntegerType>(
getType()))
725 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
730 adaptor.getOperands(), [](
const APInt &a,
const APInt &
b) {
731 return a == b ? APInt::getZero(1) : APInt::getAllOnes(1);
739OpFoldResult spirv::LogicalNotOp::fold(FoldAdaptor adaptor) {
741 auto op = getOperand();
742 if (
auto notOp = op.getDefiningOp<spirv::LogicalNotOp>())
743 return notOp->getOperand(0);
750 APInt zero = APInt::getZero(1);
751 return a == 1 ? zero : (zero + 1);
755void spirv::LogicalNotOp::getCanonicalizationPatterns(
758 .
add<ConvertLogicalNotOfIEqual, ConvertLogicalNotOfINotEqual,
759 ConvertLogicalNotOfLogicalEqual, ConvertLogicalNotOfLogicalNotEqual>(
767OpFoldResult spirv::LogicalOrOp::fold(FoldAdaptor adaptor) {
771 return adaptor.getOperand2();
776 return getOperand1();
787OpFoldResult spirv::SelectOp::fold(FoldAdaptor adaptor) {
789 Value trueVals = getTrueValue();
790 Value falseVals = getFalseValue();
791 if (trueVals == falseVals)
799 return *boolAttr ? trueVals : falseVals;
802 if (!operands[0] || !operands[1] || !operands[2])
808 auto condAttrs = dyn_cast<DenseElementsAttr>(operands[0]);
809 auto trueAttrs = dyn_cast<DenseElementsAttr>(operands[1]);
810 auto falseAttrs = dyn_cast<DenseElementsAttr>(operands[2]);
811 if (!condAttrs || !trueAttrs || !falseAttrs)
814 auto elementResults = llvm::to_vector<4>(trueAttrs.getValues<
Attribute>());
815 auto iters = llvm::zip_equal(elementResults, condAttrs.getValues<
BoolAttr>(),
817 for (
auto [
result, cond, falseRes] : iters) {
818 if (!cond.getValue())
822 auto resultType = trueAttrs.getType();
830OpFoldResult spirv::IEqualOp::fold(spirv::IEqualOp::FoldAdaptor adaptor) {
832 if (getOperand1() == getOperand2()) {
834 if (isa<IntegerType>(
getType()))
836 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
841 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
842 return a ==
b ? APInt::getAllOnes(1) : APInt::
getZero(1);
850OpFoldResult spirv::INotEqualOp::fold(spirv::INotEqualOp::FoldAdaptor adaptor) {
852 if (getOperand1() == getOperand2()) {
854 if (isa<IntegerType>(
getType()))
856 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
861 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
862 return a ==
b ? APInt::getZero(1) : APInt::getAllOnes(1);
871spirv::SGreaterThanOp::fold(spirv::SGreaterThanOp::FoldAdaptor adaptor) {
873 if (getOperand1() == getOperand2()) {
875 if (isa<IntegerType>(
getType()))
877 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
882 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
883 return a.sgt(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
892 spirv::SGreaterThanEqualOp::FoldAdaptor adaptor) {
894 if (getOperand1() == getOperand2()) {
896 if (isa<IntegerType>(
getType()))
898 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
903 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
904 return a.sge(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
913spirv::UGreaterThanOp::fold(spirv::UGreaterThanOp::FoldAdaptor adaptor) {
915 if (getOperand1() == getOperand2()) {
917 if (isa<IntegerType>(
getType()))
919 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
924 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
925 return a.ugt(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
934 spirv::UGreaterThanEqualOp::FoldAdaptor adaptor) {
936 if (getOperand1() == getOperand2()) {
938 if (isa<IntegerType>(
getType()))
940 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
945 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
946 return a.uge(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
954OpFoldResult spirv::SLessThanOp::fold(spirv::SLessThanOp::FoldAdaptor adaptor) {
956 if (getOperand1() == getOperand2()) {
958 if (isa<IntegerType>(
getType()))
960 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
965 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
966 return a.slt(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
975spirv::SLessThanEqualOp::fold(spirv::SLessThanEqualOp::FoldAdaptor adaptor) {
977 if (getOperand1() == getOperand2()) {
979 if (isa<IntegerType>(
getType()))
981 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
986 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
987 return a.sle(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
995OpFoldResult spirv::ULessThanOp::fold(spirv::ULessThanOp::FoldAdaptor adaptor) {
997 if (getOperand1() == getOperand2()) {
999 if (isa<IntegerType>(
getType()))
1001 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
1006 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
1007 return a.ult(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
1016spirv::ULessThanEqualOp::fold(spirv::ULessThanEqualOp::FoldAdaptor adaptor) {
1018 if (getOperand1() == getOperand2()) {
1020 if (isa<IntegerType>(
getType()))
1022 if (
auto vecTy = dyn_cast<VectorType>(
getType()))
1027 adaptor.getOperands(),
getType(), [](
const APInt &a,
const APInt &
b) {
1028 return a.ule(
b) ? APInt::getAllOnes(1) : APInt::
getZero(1);
1037 spirv::ShiftLeftLogicalOp::FoldAdaptor adaptor) {
1040 return getOperand1();
1051 bool shiftToLarge =
false;
1053 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
1054 if (shiftToLarge || b.uge(a.getBitWidth())) {
1055 shiftToLarge = true;
1060 return shiftToLarge ?
Attribute() : res;
1068 spirv::ShiftRightArithmeticOp::FoldAdaptor adaptor) {
1071 return getOperand1();
1082 bool shiftToLarge =
false;
1084 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
1085 if (shiftToLarge || b.uge(a.getBitWidth())) {
1086 shiftToLarge = true;
1091 return shiftToLarge ?
Attribute() : res;
1099 spirv::ShiftRightLogicalOp::FoldAdaptor adaptor) {
1102 return getOperand1();
1113 bool shiftToLarge =
false;
1115 adaptor.getOperands(), [&](
const APInt &a,
const APInt &
b) {
1116 if (shiftToLarge || b.uge(a.getBitWidth())) {
1117 shiftToLarge = true;
1122 return shiftToLarge ?
Attribute() : res;
1130spirv::BitwiseAndOp::fold(spirv::BitwiseAndOp::FoldAdaptor adaptor) {
1132 if (getOperand1() == getOperand2()) {
1133 return getOperand1();
1139 if (rhsMask.isZero())
1140 return getOperand2();
1143 if (rhsMask.isAllOnes())
1144 return getOperand1();
1147 if (
auto zext = getOperand1().getDefiningOp<spirv::UConvertOp>()) {
1150 if (rhsMask.zextOrTrunc(valueBits).isAllOnes())
1151 return getOperand1();
1161 adaptor.getOperands(),
1162 [](
const APInt &a,
const APInt &
b) { return a & b; });
1169OpFoldResult spirv::BitwiseOrOp::fold(spirv::BitwiseOrOp::FoldAdaptor adaptor) {
1171 if (getOperand1() == getOperand2()) {
1172 return getOperand1();
1178 if (rhsMask.isZero())
1179 return getOperand1();
1182 if (rhsMask.isAllOnes())
1183 return getOperand2();
1192 adaptor.getOperands(),
1193 [](
const APInt &a,
const APInt &
b) { return a | b; });
1201spirv::BitwiseXorOp::fold(spirv::BitwiseXorOp::FoldAdaptor adaptor) {
1204 return getOperand1();
1208 if (getOperand1() == getOperand2())
1217 adaptor.getOperands(),
1218 [](
const APInt &a,
const APInt &
b) { return a ^ b; });
1251struct ConvertSelectionOpToSelect final :
OpRewritePattern<spirv::SelectionOp> {
1254 LogicalResult matchAndRewrite(spirv::SelectionOp selectionOp,
1255 PatternRewriter &rewriter)
const override {
1256 Operation *op = selectionOp.getOperation();
1265 if (llvm::range_size(body) != 4) {
1269 Block *headerBlock = selectionOp.getHeaderBlock();
1270 if (!onlyContainsBranchConditionalOp(headerBlock)) {
1274 auto brConditionalOp =
1275 cast<spirv::BranchConditionalOp>(headerBlock->
front());
1277 Block *trueBlock = brConditionalOp.getSuccessor(0);
1278 Block *falseBlock = brConditionalOp.getSuccessor(1);
1279 Block *mergeBlock = selectionOp.getMergeBlock();
1281 if (
failed(canCanonicalizeSelection(trueBlock, falseBlock, mergeBlock)))
1284 Value trueValue = getSrcValue(trueBlock);
1285 Value falseValue = getSrcValue(falseBlock);
1286 Value ptrValue = getDstPtr(trueBlock);
1287 auto storeOp = cast<spirv::StoreOp>(trueBlock->
front());
1289 auto selectOp = spirv::SelectOp::create(
1290 rewriter, selectionOp.getLoc(), trueValue.
getType(),
1291 brConditionalOp.getCondition(), trueValue, falseValue);
1292 auto newStore = spirv::StoreOp::create(
1293 rewriter, selectOp.getLoc(), ptrValue, selectOp.getResult(),
1294 storeOp.getMemoryAccessAttr(), storeOp.getAlignmentAttr());
1295 newStore->setDiscardableAttrs(storeOp->getDiscardableAttrDictionary());
1309 LogicalResult canCanonicalizeSelection(
Block *trueBlock,
Block *falseBlock,
1310 Block *mergeBlock)
const;
1312 bool onlyContainsBranchConditionalOp(
Block *block)
const {
1313 return llvm::hasSingleElement(*block) &&
1314 isa<spirv::BranchConditionalOp>(block->
front());
1317 bool isSameAttrList(spirv::StoreOp
lhs, spirv::StoreOp
rhs)
const {
1318 return lhs->getDiscardableAttrDictionary() ==
1319 rhs->getDiscardableAttrDictionary() &&
1320 lhs.getProperties() ==
rhs.getProperties();
1324 Value getSrcValue(
Block *block)
const {
1325 auto storeOp = cast<spirv::StoreOp>(block->
front());
1326 return storeOp.getValue();
1330 Value getDstPtr(
Block *block)
const {
1331 auto storeOp = cast<spirv::StoreOp>(block->
front());
1332 return storeOp.getPtr();
1336LogicalResult ConvertSelectionOpToSelect::canCanonicalizeSelection(
1339 if (llvm::range_size(*trueBlock) != 2 || llvm::range_size(*falseBlock) != 2) {
1343 auto trueBrStoreOp = dyn_cast<spirv::StoreOp>(trueBlock->
front());
1344 auto trueBrBranchOp =
1345 dyn_cast<spirv::BranchOp>(*std::next(trueBlock->
begin()));
1346 auto falseBrStoreOp = dyn_cast<spirv::StoreOp>(falseBlock->
front());
1347 auto falseBrBranchOp =
1348 dyn_cast<spirv::BranchOp>(*std::next(falseBlock->
begin()));
1350 if (!trueBrStoreOp || !trueBrBranchOp || !falseBrStoreOp ||
1360 bool isScalarOrVector =
1361 cast<spirv::SPIRVType>(trueBrStoreOp.getValue().getType())
1362 .isScalarOrVector();
1366 if ((trueBrStoreOp.getPtr() != falseBrStoreOp.getPtr()) ||
1367 !isSameAttrList(trueBrStoreOp, falseBrStoreOp) || !isScalarOrVector) {
1371 if ((trueBrBranchOp->getSuccessor(0) != mergeBlock) ||
1372 (falseBrBranchOp->getSuccessor(0) != mergeBlock)) {
1380void spirv::SelectionOp::getCanonicalizationPatterns(RewritePatternSet &results,
1381 MLIRContext *context) {
1382 results.
add<ConvertSelectionOpToSelect>(context);
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={})