11#include "llvm/ADT/TypeSwitch.h"
32#define GEN_PASS_DEF_ARITHINTRANGEOPTS
33#include "mlir/Dialect/Arith/Transforms/Passes.h.inc"
35#define GEN_PASS_DEF_ARITHINTRANGENARROWING
36#include "mlir/Dialect/Arith/Transforms/Passes.h.inc"
45 auto *maybeInferredRange =
47 if (!maybeInferredRange || maybeInferredRange->getValue().isUninitialized())
50 maybeInferredRange->getValue().getValue();
70 if (!maybeConstValue.has_value())
82 if (storageWidth != 0 && maybeConstValue->getBitWidth() != storageWidth)
88 maybeDefiningOp ? maybeDefiningOp->
getDialect()
92 if (
auto shaped = dyn_cast<ShapedType>(type)) {
123 void notifyOperationErased(Operation *op)
override {
137 MaterializeKnownConstantValues(MLIRContext *context, DataFlowSolver &s)
138 : RewritePattern::RewritePattern(Pattern::MatchAnyOpTypeTag(),
142 LogicalResult matchAndRewrite(Operation *op,
143 PatternRewriter &rewriter)
const override {
153 auto needsReplacing = [&](Value v) {
157 if (!maybeConstValue.has_value() || v.use_empty())
159 unsigned storageWidth =
161 return storageWidth == 0 ||
162 maybeConstValue->getBitWidth() == storageWidth;
164 bool hasConstantResults = llvm::any_of(op->
getResults(), needsReplacing);
166 if (!hasConstantResults)
168 bool hasConstantRegionArgs =
false;
170 for (
Block &block : region.getBlocks()) {
171 hasConstantRegionArgs |=
172 llvm::any_of(block.getArguments(), needsReplacing);
175 if (!hasConstantResults && !hasConstantRegionArgs)
188 PatternRewriter::InsertionGuard guard(rewriter);
190 for (
Block &block : region.getBlocks()) {
192 for (BlockArgument &arg : block.getArguments()) {
202 DataFlowSolver &solver;
205template <
typename RemOp>
207 DeleteTrivialRem(MLIRContext *context, DataFlowSolver &s)
208 : OpRewritePattern<RemOp>(context), solver(s) {}
210 LogicalResult matchAndRewrite(RemOp op,
211 PatternRewriter &rewriter)
const override {
212 Value
lhs = op.getOperand(0);
213 Value
rhs = op.getOperand(1);
215 if (!maybeModulus.has_value())
217 int64_t modulus = *maybeModulus;
220 auto *maybeLhsRange = solver.lookupState<IntegerValueRangeLattice>(
lhs);
221 if (!maybeLhsRange || maybeLhsRange->getValue().isUninitialized())
223 const ConstantIntRanges &lhsRange = maybeLhsRange->getValue().getValue();
224 const APInt &
min = isa<RemUIOp>(op) ? lhsRange.
umin() : lhsRange.
smin();
225 const APInt &
max = isa<RemUIOp>(op) ? lhsRange.
umax() : lhsRange.
smax();
228 if (
min.isNegative() ||
min.uge(modulus))
230 if (
max.isNegative() ||
max.uge(modulus))
243 DataFlowSolver &solver;
250 for (
Value val : values) {
251 auto *maybeInferredRange =
253 if (!maybeInferredRange || maybeInferredRange->getValue().isUninitialized())
257 maybeInferredRange->getValue().getValue();
258 ranges.push_back(inferredRange);
265static Type getTargetType(
Type srcType,
unsigned targetBitwidth) {
266 auto dstType = IntegerType::get(srcType.
getContext(), targetBitwidth);
267 if (
auto shaped = dyn_cast<ShapedType>(srcType))
268 return shaped.clone(dstType);
287 unsigned targetWidth) {
288 unsigned srcWidth = range.
smin().getBitWidth();
289 if (srcWidth <= targetWidth)
290 return CastKind::None;
291 unsigned removedWidth = srcWidth - targetWidth;
295 bool canTruncateSigned =
296 range.
smin().getNumSignBits() >= (removedWidth + 1) &&
297 range.
smax().getNumSignBits() >= (removedWidth + 1);
298 bool canTruncateUnsigned = range.
umin().countLeadingZeros() >= removedWidth &&
299 range.
umax().countLeadingZeros() >= removedWidth;
300 if (canTruncateSigned && canTruncateUnsigned)
301 return CastKind::Both;
302 if (canTruncateSigned)
303 return CastKind::Signed;
304 if (canTruncateUnsigned)
305 return CastKind::Unsigned;
306 return CastKind::None;
309static CastKind mergeCastKinds(CastKind lhs, CastKind rhs) {
310 if (lhs == CastKind::None || rhs == CastKind::None)
311 return CastKind::None;
312 if (lhs == CastKind::Both)
314 if (rhs == CastKind::Both)
318 return CastKind::None;
324 assert(isa<VectorType>(srcType) == isa<VectorType>(dstType) &&
325 "Mixing vector and non-vector types");
326 assert(castKind != CastKind::None &&
"Can't cast when casting isn't allowed");
329 assert(srcElemType.
isIntOrIndex() &&
"Invalid src type");
330 assert(dstElemType.
isIntOrIndex() &&
"Invalid dst type");
331 if (srcType == dstType)
334 if (isa<IndexType>(srcElemType) || isa<IndexType>(dstElemType)) {
335 if (castKind == CastKind::Signed)
336 return arith::IndexCastOp::create(builder, loc, dstType, src);
337 return arith::IndexCastUIOp::create(builder, loc, dstType, src);
340 auto srcInt = cast<IntegerType>(srcElemType);
341 auto dstInt = cast<IntegerType>(dstElemType);
342 if (dstInt.getWidth() < srcInt.getWidth())
343 return arith::TruncIOp::create(builder, loc, dstType, src);
345 if (castKind == CastKind::Signed)
346 return arith::ExtSIOp::create(builder, loc, dstType, src);
347 return arith::ExtUIOp::create(builder, loc, dstType, src);
351 NarrowElementwise(MLIRContext *context, DataFlowSolver &s,
352 ArrayRef<unsigned>
target)
353 : OpTraitRewritePattern(context), solver(s), targetBitwidths(
target) {}
356 LogicalResult matchAndRewrite(Operation *op,
357 PatternRewriter &rewriter)
const override {
363 SmallVector<ConstantIntRanges, 4> ranges;
374 [=](Type t) { return t == srcType; }))
376 op,
"no operands or operand types don't match result type");
378 for (
unsigned targetBitwidth : targetBitwidths) {
379 CastKind castKind = CastKind::Both;
380 for (
const ConstantIntRanges &range : ranges) {
381 castKind = mergeCastKinds(castKind,
382 checkTruncatability(range, targetBitwidth));
383 if (castKind == CastKind::None)
390 llvm::TypeSwitch<Operation *, CastKind>(op)
391 .Case<arith::DivSIOp, arith::CeilDivSIOp, arith::FloorDivSIOp,
392 arith::RemSIOp, arith::MaxSIOp, arith::MinSIOp,
393 arith::ShRSIOp>([](
auto) {
return CastKind::Signed; })
394 .Default(CastKind::Both);
395 castKind = mergeCastKinds(castKind, castKindForOp);
396 if (castKind == CastKind::None)
400 if (isa<arith::ShLIOp, arith::ShRSIOp, arith::ShRUIOp>(op) &&
401 !ranges[1].umax().
ult(targetBitwidth))
403 Type targetType = getTargetType(srcType, targetBitwidth);
404 if (targetType == srcType)
407 Location loc = op->
getLoc();
409 for (
auto [arg, argRange] : llvm::zip_first(op->
getOperands(), ranges)) {
410 CastKind argCastKind = castKind;
413 if (argCastKind == CastKind::Signed && argRange.smin().isNonNegative())
414 argCastKind = CastKind::Both;
415 Value newArg = doCast(rewriter, loc, arg, targetType, argCastKind);
416 mapping.
map(arg, newArg);
419 Operation *newOp = rewriter.
clone(*op, mapping);
425 SmallVector<Value> newResults;
426 for (
auto [newRes, oldRes] :
428 Value castBack = doCast(rewriter, loc, newRes, srcType, castKind);
430 newResults.push_back(castBack);
440 DataFlowSolver &solver;
441 SmallVector<unsigned, 4> targetBitwidths;
445 NarrowCmpI(MLIRContext *context, DataFlowSolver &s, ArrayRef<unsigned>
target)
446 : OpRewritePattern(context), solver(s), targetBitwidths(
target) {}
448 LogicalResult matchAndRewrite(arith::CmpIOp op,
449 PatternRewriter &rewriter)
const override {
450 Value
lhs = op.getLhs();
451 Value
rhs = op.getRhs();
453 SmallVector<ConstantIntRanges> ranges;
454 if (
failed(collectRanges(solver, op.getOperands(), ranges)))
456 const ConstantIntRanges &lhsRange = ranges[0];
457 const ConstantIntRanges &rhsRange = ranges[1];
459 auto isSignedCmpPredicate = [](arith::CmpIPredicate pred) ->
bool {
460 return pred == arith::CmpIPredicate::sge ||
461 pred == arith::CmpIPredicate::sgt ||
462 pred == arith::CmpIPredicate::sle ||
463 pred == arith::CmpIPredicate::slt;
467 CastKind predicateBasedCastRestriction =
468 isSignedCmpPredicate(op.getPredicate()) ? CastKind::Signed
471 Type srcType =
lhs.getType();
472 for (
unsigned targetBitwidth : targetBitwidths) {
473 CastKind lhsCastKind = checkTruncatability(lhsRange, targetBitwidth);
474 CastKind rhsCastKind = checkTruncatability(rhsRange, targetBitwidth);
475 CastKind castKind = mergeCastKinds(lhsCastKind, rhsCastKind);
476 castKind = mergeCastKinds(castKind, predicateBasedCastRestriction);
479 if (castKind == CastKind::None)
482 Type targetType = getTargetType(srcType, targetBitwidth);
483 if (targetType == srcType)
486 Location loc = op->getLoc();
488 Value lhsCast = doCast(rewriter, loc,
lhs, targetType, lhsCastKind);
489 Value rhsCast = doCast(rewriter, loc,
rhs, targetType, rhsCastKind);
490 mapping.
map(
lhs, lhsCast);
491 mapping.
map(
rhs, rhsCast);
493 Operation *newOp = rewriter.
clone(*op, mapping);
502 DataFlowSolver &solver;
503 SmallVector<unsigned, 4> targetBitwidths;
509template <
typename CastOp>
511 FoldIndexCastChain(MLIRContext *context, ArrayRef<unsigned>
target)
512 : OpRewritePattern<CastOp>(context), targetBitwidths(
target) {}
514 LogicalResult matchAndRewrite(CastOp op,
515 PatternRewriter &rewriter)
const override {
516 auto srcOp = op.getIn().template getDefiningOp<CastOp>();
520 Value src = srcOp.getIn();
521 if (src.
getType() != op.getType())
524 if (!srcOp.getType().isIndex())
527 auto intType = dyn_cast<IntegerType>(op.getType());
528 if (!intType || !llvm::is_contained(targetBitwidths, intType.getWidth()))
536 SmallVector<unsigned, 4> targetBitwidths;
540 NarrowLoopBounds(MLIRContext *context, DataFlowSolver &s,
541 ArrayRef<unsigned>
target)
542 : OpInterfaceRewritePattern<LoopLikeOpInterface>(context), solver(s),
544 boundsNarrowingFailedAttr(
545 StringAttr::
get(context,
"arith.bounds_narrowing_failed")) {}
547 LogicalResult matchAndRewrite(LoopLikeOpInterface loopLike,
548 PatternRewriter &rewriter)
const override {
550 if (loopLike->hasDiscardableAttr(boundsNarrowingFailedAttr))
552 "bounds narrowing previously failed");
554 std::optional<SmallVector<Value>> inductionVars =
555 loopLike.getLoopInductionVars();
556 if (!inductionVars.has_value() || inductionVars->empty())
559 std::optional<SmallVector<OpFoldResult>> lowerBounds =
560 loopLike.getLoopLowerBounds();
561 std::optional<SmallVector<OpFoldResult>> upperBounds =
562 loopLike.getLoopUpperBounds();
563 std::optional<SmallVector<OpFoldResult>> steps = loopLike.getLoopSteps();
565 if (!lowerBounds.has_value() || !upperBounds.has_value() ||
569 if (lowerBounds->size() != inductionVars->size() ||
570 upperBounds->size() != inductionVars->size() ||
571 steps->size() != inductionVars->size())
573 "mismatched bounds/steps count");
575 Location loc = loopLike->getLoc();
576 SmallVector<OpFoldResult> newLowerBounds(*lowerBounds);
577 SmallVector<OpFoldResult> newUpperBounds(*upperBounds);
578 SmallVector<OpFoldResult> newSteps(*steps);
579 SmallVector<std::tuple<size_t, Type, CastKind>> narrowings;
582 for (
auto [idx, indVar, lbOFR, ubOFR, stepOFR] :
583 llvm::enumerate(*inductionVars, *lowerBounds, *upperBounds, *steps)) {
586 auto maybeLb = dyn_cast<Value>(lbOFR);
587 auto maybeUb = dyn_cast<Value>(ubOFR);
588 auto maybeStep = dyn_cast<Value>(stepOFR);
590 if (!maybeLb || !maybeUb || !maybeStep)
594 SmallVector<ConstantIntRanges> ranges;
596 solver,
ValueRange{maybeLb, maybeUb, maybeStep, indVar}, ranges)))
599 const ConstantIntRanges &stepRange = ranges[2];
600 const ConstantIntRanges &indVarRange = ranges[3];
602 Type srcType = maybeLb.getType();
605 for (
unsigned targetBitwidth : targetBitwidths) {
606 Type targetType = getTargetType(srcType, targetBitwidth);
607 if (targetType == srcType)
612 if (!loopLike.isValidInductionVarType(targetType))
616 CastKind castKind = CastKind::Both;
617 for (
const ConstantIntRanges &range : ranges) {
618 castKind = mergeCastKinds(castKind,
619 checkTruncatability(range, targetBitwidth));
620 if (castKind == CastKind::None)
624 if (castKind == CastKind::None)
634 ConstantIntRanges indVarPlusStepRange(
635 indVarRange.
smin().sadd_sat(stepRange.
smin()),
636 indVarRange.
smax().sadd_sat(stepRange.
smax()),
637 indVarRange.
umin().uadd_sat(stepRange.
umin()),
638 indVarRange.
umax().uadd_sat(stepRange.
umax()));
640 if (checkTruncatability(indVarPlusStepRange, targetBitwidth) !=
645 Value newLb = doCast(rewriter, loc, maybeLb, targetType, castKind);
646 Value newUb = doCast(rewriter, loc, maybeUb, targetType, castKind);
647 Value newStep = doCast(rewriter, loc, maybeStep, targetType, castKind);
649 newLowerBounds[idx] = newLb;
650 newUpperBounds[idx] = newUb;
651 newSteps[idx] = newStep;
652 narrowings.push_back({idx, targetType, castKind});
657 if (narrowings.empty())
661 SmallVector<Type> origTypes;
662 for (
auto [idx, targetType, castKind] : narrowings) {
663 Value indVar = (*inductionVars)[idx];
664 origTypes.push_back(indVar.
getType());
669 bool updateFailed =
false;
672 if (
failed(loopLike.setLoopLowerBounds(newLowerBounds)) ||
673 failed(loopLike.setLoopUpperBounds(newUpperBounds)) ||
674 failed(loopLike.setLoopSteps(newSteps))) {
677 loopLike->setDiscardableAttr(boundsNarrowingFailedAttr,
684 for (
auto [idx, targetType, castKind] : narrowings) {
685 Value indVar = (*inductionVars)[idx];
686 auto blockArg = cast<BlockArgument>(indVar);
689 blockArg.setType(targetType);
697 for (
auto [narrowingIdx, narrowingInfo] : llvm::enumerate(narrowings)) {
698 auto [idx, targetType, castKind] = narrowingInfo;
699 Value indVar = (*inductionVars)[idx];
700 auto blockArg = cast<BlockArgument>(indVar);
701 Type origType = origTypes[narrowingIdx];
703 OpBuilder::InsertionGuard guard(rewriter);
705 Value casted = doCast(rewriter, loc, blockArg, origType, castKind);
716 DataFlowSolver &solver;
717 SmallVector<unsigned, 4> targetBitwidths;
718 StringAttr boundsNarrowingFailedAttr;
721struct IntRangeOptimizationsPass final
722 : arith::impl::ArithIntRangeOptsBase<IntRangeOptimizationsPass> {
724 void runOnOperation()
override {
725 Operation *op = getOperation();
727 DataFlowSolver solver;
729 solver.
load<IntegerRangeAnalysis>();
731 return signalPassFailure();
733 DataFlowListener listener(solver);
735 RewritePatternSet patterns(ctx);
746 GreedyRewriteConfig()
747 .enableFolding(
false)
748 .setRegionSimplificationLevel(
749 GreedySimplifyRegionLevel::Disabled)
750 .setListener(&listener))))
755struct IntRangeNarrowingPass final
756 : arith::impl::ArithIntRangeNarrowingBase<IntRangeNarrowingPass> {
757 using ArithIntRangeNarrowingBase::ArithIntRangeNarrowingBase;
759 void runOnOperation()
override {
760 Operation *op = getOperation();
762 DataFlowSolver solver;
764 solver.
load<IntegerRangeAnalysis>();
766 return signalPassFailure();
768 DataFlowListener listener(solver);
770 RewritePatternSet patterns(ctx);
778 op, std::move(patterns),
779 GreedyRewriteConfig().setUseTopDownTraversal(
false).setListener(
788 patterns.
add<MaterializeKnownConstantValues, DeleteTrivialRem<RemSIOp>,
789 DeleteTrivialRem<RemUIOp>>(patterns.
getContext(), solver);
795 patterns.
add<NarrowElementwise, NarrowCmpI>(patterns.
getContext(), solver,
797 patterns.
add<FoldIndexCastChain<arith::IndexCastUIOp>,
798 FoldIndexCastChain<arith::IndexCastOp>>(patterns.
getContext(),
805 patterns.
add<NarrowLoopBounds>(patterns.
getContext(), solver,
810 return std::make_unique<IntRangeOptimizationsPass>();
static Operation * materializeConstant(Dialect *dialect, OpBuilder &builder, Attribute value, Type type, Location loc)
A utility function used to materialize a constant for a given attribute and type.
static void copyIntegerRange(DataFlowSolver &solver, Value oldVal, Value newVal)
static std::optional< APInt > getMaybeConstantValue(DataFlowSolver &solver, Value value)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
Attributes are known-constant values of operations.
IntegerAttr getIntegerAttr(Type type, int64_t value)
MLIRContext * getContext() const
A set of arbitrary-precision integers representing bounds on a given integer value.
const APInt & smax() const
The maximum value of an integer when it is interpreted as signed.
const APInt & smin() const
The minimum value of an integer when it is interpreted as signed.
static unsigned getStorageBitwidth(Type type)
Return the bitwidth that should be used for integer ranges describing type.
std::optional< APInt > getConstantValue() const
If either the signed or unsigned interpretations of the range indicate that the value it bounds is a ...
const APInt & umax() const
The maximum value of an integer when it is interpreted as unsigned.
const APInt & umin() const
The minimum value of an integer when it is interpreted as unsigned.
The general data-flow analysis solver.
LogicalResult initializeAndRun(Operation *top, llvm::function_ref< bool(DataFlowAnalysis &)> analysisFilter=nullptr)
Initialize analyses starting from the provided top-level operation and run the analysis until fixpoin...
void eraseState(AnchorT anchor)
Erase any analysis state associated with the given lattice anchor.
const StateT * lookupState(AnchorT anchor) const
Lookup an analysis state for the given lattice anchor.
StateT * getOrCreateState(AnchorT anchor)
Get the state associated with the given lattice anchor.
AnalysisT * load(Args &&...args)
Load an analysis into the solver. Return the analysis instance.
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg)
Get an instance of a DenseIntElementsAttr with the given arguments.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual Operation * materializeConstant(OpBuilder &builder, Attribute value, Type type, Location loc)
Registered hook to materialize a single constant operation from a given attribute value with the desi...
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
This class helps build Operations.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
This is a value defined by a result of an operation.
OpTraitRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting again...
OpTraitRewritePattern(MLIRContext *context, PatternBenefit benefit=1)
Operation is the basic unit of execution within MLIR.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
operand_type_range getOperandTypes()
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
MLIRContext * getContext()
Return the context this operation is associated with.
unsigned getNumResults()
Return the number of results held by this operation.
Operation * getParentOp()
Return the parent operation this region is attached to.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
RewritePattern is the common base class for all DAG to DAG replacements.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void replaceAllUsesExcept(Value from, Value to, Operation *exceptedUser)
Find uses of from and replace them with to except if the user is exceptedUser.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
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 isIntOrIndex() const
Return true if this is an integer (of any signedness) or an index type.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void setType(Type newType)
Mutate the type of this Value to be of the specified type.
Type getType() const
Return the type of this value.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Region * getParentRegion()
Return the Region in which this Value is defined.
This lattice element represents the integer value range of an SSA value.
ChangeResult join(const AbstractSparseLattice &rhs) override
Join the information contained in 'rhs' into this lattice.
std::unique_ptr< Pass > createIntRangeOptimizationsPass()
Create a pass which do optimizations based on integer range analysis.
void populateControlFlowValuesNarrowingPatterns(RewritePatternSet &patterns, DataFlowSolver &solver, ArrayRef< unsigned > bitwidthsSupported)
Add patterns for narrowing control flow values (loop bounds, steps, etc.) based on int range analysis...
void populateIntRangeOptimizationsPatterns(RewritePatternSet &patterns, DataFlowSolver &solver)
Add patterns for int range based optimizations.
void populateIntRangeNarrowingPatterns(RewritePatternSet &patterns, DataFlowSolver &solver, ArrayRef< unsigned > bitwidthsSupported)
Add patterns for int range based narrowing.
LogicalResult maybeReplaceWithConstant(DataFlowSolver &solver, RewriterBase &rewriter, Value value)
Patterned after SCCP.
void loadBaselineAnalyses(DataFlowSolver &solver)
Populates a DataFlowSolver with analyses that are required to ensure user-defined analyses are run pr...
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
bool isOpTriviallyDead(Operation *op)
Return true if the given operation is unused, and has no side effects on memory that prevent erasing.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
OpInterfaceRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting a...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...