MLIR 22.0.0git
AffineOps.cpp File Reference
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Affine/IR/AffineValueMap.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/UB/IR/UBOps.h"
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineExprVisitor.h"
#include "mlir/IR/IRMapping.h"
#include "mlir/IR/IntegerSet.h"
#include "mlir/IR/Matchers.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/Value.h"
#include "mlir/Interfaces/ShapedOpInterfaces.h"
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Transforms/InliningUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/DebugLog.h"
#include "llvm/Support/LogicalResult.h"
#include "llvm/Support/MathExtras.h"
#include <numeric>
#include <optional>
#include "mlir/Dialect/Affine/IR/AffineOpsDialect.cpp.inc"
#include "mlir/Dialect/Affine/IR/AffineOps.cpp.inc"

Go to the source code of this file.

Classes

struct  DeduplicateAffineMinMaxExpressions< T >
 Remove duplicated expressions in affine min/max ops. More...
struct  MergeAffineMinMaxOp< T >
 Merge an affine min/max op to its consumers if its consumer is also an affine min/max op. More...
struct  CanonicalizeAffineMinMaxOpExprAndTermOrder< T >
 Canonicalize the affine map result expression order of an affine min/max operation. More...
struct  CanonicalizeSingleResultAffineMinMaxOp< T >

Macros

#define DEBUG_TYPE   "affine-ops"
#define GET_OP_LIST
#define GET_OP_CLASSES

Functions

static bool remainsLegalAfterInline (Value value, Region *src, Region *dest, const IRMapping &mapping, function_ref< bool(Value, Region *)> legalityCheck)
 Checks if value known to be a legal affine dimension or symbol in src region remains legal if the operation that uses it is inlined into dest with the given value mapping.
static bool remainsLegalAfterInline (ValueRange values, Region *src, Region *dest, const IRMapping &mapping, function_ref< bool(Value, Region *)> legalityCheck)
 Checks if all values known to be legal affine dimensions or symbols in src remain so if their respective users are inlined into dest.
template<typename OpTy>
static bool remainsLegalAfterInline (OpTy op, Region *src, Region *dest, const IRMapping &mapping)
 Checks if an affine read or write operation remains legal after inlining from src to dest.
template<>
bool remainsLegalAfterInline (AffineApplyOp op, Region *src, Region *dest, const IRMapping &mapping)
 Checks if an affine apply operation remains legal after inlining from src to dest.
template<typename AnyMemRefDefOp>
static bool isMemRefSizeValidSymbol (AnyMemRefDefOp memrefDefOp, unsigned index, Region *region)
 Returns true if the 'index' dimension of the memref defined by memrefDefOp is a statically shaped one or defined using a valid symbol for region.
static bool isDimOpValidSymbol (ShapedDimOpInterface dimOp, Region *region)
 Returns true if the result of the dim op is a valid symbol for region.
static bool isTopLevelValueOrAbove (Value value, Region *region)
 A utility function to check if a value is defined at the top level of region or is an argument of region or is defined above the region.
static bool isValidAffineIndexOperand (Value value, Region *region)
static void printDimAndSymbolList (Operation::operand_iterator begin, Operation::operand_iterator end, unsigned numDims, OpAsmPrinter &printer)
 Prints dimension and symbol list.
template<typename OpTy>
static LogicalResult verifyDimAndSymbolIdentifiers (OpTy &op, Operation::operand_range operands, unsigned numDims)
 Utility function to verify that a set of operands are valid dimension and symbol identifiers.
static int64_t getLargestKnownDivisor (AffineExpr e, ArrayRef< Value > operands)
 Returns the largest known divisor of e.
static bool isNonNegativeBoundedBy (AffineExpr e, ArrayRef< Value > operands, int64_t k)
 Check if e is known to be: 0 <= e < k.
static bool isQTimesDPlusR (AffineExpr e, ArrayRef< Value > operands, int64_t &div, AffineExpr &quotientTimesDiv, AffineExpr &rem)
 Check if expression e is of the form d*e_1 + e_2 where 0 <= e_2 < d.
static std::optional< int64_tgetLowerBound (Value iv)
 Gets the constant lower bound on an iv.
static std::optional< int64_tgetUpperBound (Value iv)
 Gets the constant upper bound on an affine.for iv.
static std::optional< int64_tgetUpperBound (AffineExpr expr, unsigned numDims, unsigned numSymbols, ArrayRef< Value > operands)
 Determine a constant upper bound for expr if one exists while exploiting values in operands.
static std::optional< int64_tgetLowerBound (AffineExpr expr, unsigned numDims, unsigned numSymbols, ArrayRef< Value > operands)
 Determine a constant lower bound for expr if one exists while exploiting values in operands.
static void simplifyExprAndOperands (AffineExpr &expr, unsigned numDims, unsigned numSymbols, ArrayRef< Value > operands)
 Simplify expr while exploiting information from the values in operands.
static void simplifyMinOrMaxExprWithOperands (AffineMap &map, ArrayRef< Value > operands, bool isMax)
 Simplify the expressions in map while making use of lower or upper bounds of its operands.
static void simplifyMapWithOperands (AffineMap &map, ArrayRef< Value > operands)
 Simplify the map while exploiting information on the values in operands.
static LogicalResult replaceAffineMinBoundingBoxExpression (AffineMinOp minOp, AffineExpr dimOrSym, AffineMap *map, ValueRange dims, ValueRange syms)
 Assuming dimOrSym is a quantity in the apply op map map and defined by minOp = affine_min(x_1, ..., x_n).
static void shortenAddChainsContainingAll (AffineExpr e, const llvm::SmallDenseSet< AffineExpr, 4 > &exprsToRemove, AffineExpr newVal, DenseMap< AffineExpr, AffineExpr > &replacementsMap)
 Recursively traverse e.
static LogicalResult replaceAffineDelinearizeIndexInverseExpression (AffineDelinearizeIndexOp delinOp, Value resultToReplace, AffineMap *map, SmallVectorImpl< Value > &dims, SmallVectorImpl< Value > &syms)
 If this map contains of the expression x_1 + x_1 * C_1 + ... x_n * C_N + / ... (not necessarily in order) where the set of the x_i is the set of outputs of an affine.delinearize_index whos inverse is that expression, replace that expression with the input of that delinearize_index op.
static LogicalResult replaceDimOrSym (AffineMap *map, unsigned dimOrSymbolPosition, SmallVectorImpl< Value > &dims, SmallVectorImpl< Value > &syms, bool replaceAffineMin)
 Replace all occurrences of AffineExpr at position pos in map by the defining AffineApplyOp expression and operands.
static void composeAffineMapAndOperands (AffineMap *map, SmallVectorImpl< Value > *operands, bool composeAffineMin=false)
 Iterate over operands and fold away all those produced by an AffineApplyOp iteratively.
static void composeMultiResultAffineMap (AffineMap &map, SmallVectorImpl< Value > &operands, bool composeAffineMin=false)
 Composes the given affine map with the given list of operands, pulling in the maps from any affine.apply operations that supply the operands.
template<typename OpTy>
static OpTy makeComposedMinMax (OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands)
template<typename OpTy>
static OpFoldResult makeComposedFoldedMinMax (OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands)
template<class MapOrSet>
static void canonicalizePromotedSymbols (MapOrSet *mapOrSet, SmallVectorImpl< Value > *operands)
template<class MapOrSet>
static void legalizeDemotedDims (MapOrSet &mapOrSet, SmallVectorImpl< Value > &operands)
 A valid affine dimension may appear as a symbol in affine.apply operations.
template<class MapOrSet>
static void canonicalizeMapOrSetAndOperands (MapOrSet *mapOrSet, SmallVectorImpl< Value > *operands)
static ParseResult parseBound (bool isLower, OperationState &result, OpAsmParser &p)
 Parse a for operation loop bounds.
static void printBound (AffineMapAttr boundMap, Operation::operand_range boundOperands, const char *prefix, OpAsmPrinter &p)
static LogicalResult foldLoopBounds (AffineForOp forOp)
 Fold the constant bounds of a loop.
static std::optional< uint64_t > getTrivialConstantTripCount (AffineForOp forOp)
 Returns constant trip count in trivial cases.
static SmallVector< OpFoldResultAffineForEmptyLoopFolder (AffineForOp forOp)
 Fold the empty loop.
static LogicalResult canonicalizeLoopBounds (AffineForOp forOp)
 Canonicalize the bounds of the given loop.
static bool hasTrivialZeroTripCount (AffineForOp op)
 Returns true if the affine.for has zero iterations in trivial cases.
template<typename BoundListTy, typename LoopCreatorTy>
static void buildAffineLoopNestImpl (OpBuilder &builder, Location loc, BoundListTy lbs, BoundListTy ubs, ArrayRef< int64_t > steps, function_ref< void(OpBuilder &, Location, ValueRange)> bodyBuilderFn, LoopCreatorTy &&loopCreatorFn)
 Builds an affine loop nest, using "loopCreatorFn" to create individual loop operations.
static AffineForOp buildAffineLoopFromConstants (OpBuilder &builder, Location loc, int64_t lb, int64_t ub, int64_t step, AffineForOp::BodyBuilderFn bodyBuilderFn)
 Creates an affine loop from the bounds known to be constants.
static AffineForOp buildAffineLoopFromValues (OpBuilder &builder, Location loc, Value lb, Value ub, int64_t step, AffineForOp::BodyBuilderFn bodyBuilderFn)
 Creates an affine loop from the bounds that may or may not be constants.
static void composeSetAndOperands (IntegerSet &set, SmallVectorImpl< Value > &operands, bool composeAffineMin=false)
 Compose any affine.apply ops feeding into operands of the integer set set by composing the maps of such affine.apply ops with the integer set constraints.
template<typename AffineMemOpTy>
static LogicalResult verifyMemoryOpIndexing (AffineMemOpTy op, AffineMapAttr mapAttr, Operation::operand_range mapOperands, MemRefType memrefType, unsigned numIndexOperands)
 Verify common indexing invariants of affine.load, affine.store, affine.vector_load and affine.vector_store.
template<typename T>
static LogicalResult verifyAffineMinMaxOp (T op)
template<typename T>
static void printAffineMinMaxOp (OpAsmPrinter &p, T op)
template<typename T>
static ParseResult parseAffineMinMaxOp (OpAsmParser &parser, OperationState &result)
template<typename T>
static OpFoldResult foldMinMaxOp (T op, ArrayRef< Attribute > operands)
 Fold an affine min or max operation with the given operands.
static LogicalResult canonicalizeMapExprAndTermOrder (AffineMap &map)
 Canonicalize the result expression order of an affine map and return success if the order changed.
static bool isResultTypeMatchAtomicRMWKind (Type resultType, arith::AtomicRMWKind op)
static LogicalResult canonicalizeLoopBounds (AffineParallelOp op)
 Canonicalize the bounds of the given loop.
static void printMinMaxBound (OpAsmPrinter &p, AffineMapAttr mapAttr, DenseIntElementsAttr group, ValueRange operands, StringRef keyword)
 Prints a lower(upper) bound of an affine parallel loop with max(min) conditions in it.
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError ("requires memref and vector types of the same elemental type")
 Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
return success ()
static std::optional< SmallVector< int64_t > > foldCstValueToCstAttrBasis (ArrayRef< OpFoldResult > mixedBasis, MutableOperandRange mutableDynamicBasis, ArrayRef< Attribute > dynamicBasis)
 Given mixed basis of affine.delinearize_index/linearize_index replace constant SSA values with the constant integer value and return the new static basis. In case no such candidate for replacement exists, this utility returns std::nullopt.

Macro Definition Documentation

◆ DEBUG_TYPE

#define DEBUG_TYPE   "affine-ops"

Definition at line 42 of file AffineOps.cpp.

◆ GET_OP_CLASSES

#define GET_OP_CLASSES

Definition at line 5699 of file AffineOps.cpp.

◆ GET_OP_LIST

#define GET_OP_LIST

Function Documentation

◆ AffineForEmptyLoopFolder()

SmallVector< OpFoldResult > AffineForEmptyLoopFolder ( AffineForOp forOp)
static

Fold the empty loop.

Definition at line 2614 of file AffineOps.cpp.

References getTrivialConstantTripCount().

◆ buildAffineLoopFromConstants()

AffineForOp buildAffineLoopFromConstants ( OpBuilder & builder,
Location loc,
int64_t lb,
int64_t ub,
int64_t step,
AffineForOp::BodyBuilderFn bodyBuilderFn )
static

Creates an affine loop from the bounds known to be constants.

Definition at line 3026 of file AffineOps.cpp.

References ValueRange.

Referenced by buildAffineLoopFromValues(), and mlir::affine::buildAffineLoopNest().

◆ buildAffineLoopFromValues()

AffineForOp buildAffineLoopFromValues ( OpBuilder & builder,
Location loc,
Value lb,
Value ub,
int64_t step,
AffineForOp::BodyBuilderFn bodyBuilderFn )
static

Creates an affine loop from the bounds that may or may not be constants.

Definition at line 3035 of file AffineOps.cpp.

References buildAffineLoopFromConstants(), mlir::getConstantIntValue(), and mlir::Builder::getDimIdentityMap().

Referenced by mlir::affine::buildAffineLoopNest().

◆ buildAffineLoopNestImpl()

template<typename BoundListTy, typename LoopCreatorTy>
void buildAffineLoopNestImpl ( OpBuilder & builder,
Location loc,
BoundListTy lbs,
BoundListTy ubs,
ArrayRef< int64_t > steps,
function_ref< void(OpBuilder &, Location, ValueRange)> bodyBuilderFn,
LoopCreatorTy && loopCreatorFn )
static

Builds an affine loop nest, using "loopCreatorFn" to create individual loop operations.

Definition at line 2985 of file AffineOps.cpp.

References mlir::OpBuilder::setInsertionPointToStart(), and ValueRange.

Referenced by mlir::affine::buildAffineLoopNest(), and mlir::affine::buildAffineLoopNest().

◆ canonicalizeLoopBounds() [1/2]

LogicalResult canonicalizeLoopBounds ( AffineForOp forOp)
static

◆ canonicalizeLoopBounds() [2/2]

LogicalResult canonicalizeLoopBounds ( AffineParallelOp op)
static

◆ canonicalizeMapExprAndTermOrder()

LogicalResult canonicalizeMapExprAndTermOrder ( AffineMap & map)
static

Canonicalize the result expression order of an affine map and return success if the order changed.

The function flattens the map's affine expressions to coefficient arrays and sorts them in lexicographic order. A coefficient array contains a multiplier for every dimension/symbol and a constant term. The canonicalization fails if a result expression is not pure or if the flattening requires local variables that, unlike dimensions and symbols, have no global order.

Definition at line 3796 of file AffineOps.cpp.

References mlir::AffineMap::get(), mlir::AffineMap::getContext(), mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::AffineMap::getResult(), mlir::AffineMap::getResults(), lhs, mlir::SimpleAffineExprFlattener::operandExprStack, rhs, success(), and mlir::AffineExprVisitor< SubClass, RetTy >::walkPostOrder().

Referenced by CanonicalizeAffineMinMaxOpExprAndTermOrder< T >::matchAndRewrite().

◆ canonicalizeMapOrSetAndOperands()

◆ canonicalizePromotedSymbols()

template<class MapOrSet>
void canonicalizePromotedSymbols ( MapOrSet * mapOrSet,
SmallVectorImpl< Value > * operands )
static

◆ composeAffineMapAndOperands()

◆ composeMultiResultAffineMap()

void composeMultiResultAffineMap ( AffineMap & map,
SmallVectorImpl< Value > & operands,
bool composeAffineMin = false )
static

◆ composeSetAndOperands()

void composeSetAndOperands ( IntegerSet & set,
SmallVectorImpl< Value > & operands,
bool composeAffineMin = false )
static

◆ emitOpError()

p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError ( "requires memref and vector types of the same elemental type" )

Given a list of lists of parsed operands, populates uniqueOperands with unique operands.

Also populates replacements with affine expressions of / kind that can be used to update affine maps previously accepting a / operands to accept uniqueOperands` instead. static ParseResult deduplicateAndResolveOperands( OpAsmParser &parser, ArrayRef<SmallVector<OpAsmParser::UnresolvedOperand>> operands, SmallVectorImpl<Value> &uniqueOperands, SmallVectorImpl<AffineExpr> &replacements, AffineExprKind kind) { assert((kind == AffineExprKind::DimId || kind == AffineExprKind::SymbolId) && "expected operands to be dim or symbol expression");

Type indexType = parser.getBuilder().getIndexType(); for (const auto &list : operands) { SmallVector<Value> valueOperands; if (parser.resolveOperands(list, indexType, valueOperands)) return failure(); for (Value operand : valueOperands) { unsigned pos = std::distance(uniqueOperands.begin(), llvm::find(uniqueOperands, operand)); if (pos == uniqueOperands.size()) uniqueOperands.push_back(operand); replacements.push_back( kind == AffineExprKind::DimId ? getAffineDimExpr(pos, parser.getContext()) : getAffineSymbolExpr(pos, parser.getContext())); } } return success(); }

namespace { enum class MinMaxKind { Min, Max }; } // namespace

/ Parses an affine map that can contain a min/max for groups of its results, / e.g., max(expr-1, expr-2), expr-3, max(expr-4, expr-5, expr-6). Populates / result attributes with the map (flat list of expressions) and the grouping / (list of integers that specify how many expressions to put into each / min/max) attributes. Deduplicates repeated operands. / / parallel-bound ::= ( parallel-group-list ) / parallel-group-list ::= parallel-group (, parallel-group-list)? / parallel-group ::= simple-group | min-max-group / simple-group ::= expr-of-ssa-ids / min-max-group ::= ( min | max ) ( expr-of-ssa-ids-list ) / expr-of-ssa-ids-list ::= expr-of-ssa-ids (, expr-of-ssa-id-list)? / / Examples: / (%0, min(%1 + %2, %3), %4, min(%5 floordiv 32, %6)) / (%0, max(%1 - 2 * %2)) static ParseResult parseAffineMapWithMinMax(OpAsmParser &parser, OperationState &result, MinMaxKind kind) { Using const not constexpr below to workaround a MSVC optimizer bug, see: https://reviews.llvm.org/D134227#3821753 const llvm::StringLiteral tmpAttrStrName = "__pseudo_bound_map";

StringRef mapName = kind == MinMaxKind::Min ? AffineParallelOp::getUpperBoundsMapAttrStrName() : AffineParallelOp::getLowerBoundsMapAttrStrName(); StringRef groupsName = kind == MinMaxKind::Min ? AffineParallelOp::getUpperBoundsGroupsAttrStrName() : AffineParallelOp::getLowerBoundsGroupsAttrStrName();

if (failed(parser.parseLParen())) return failure();

if (succeeded(parser.parseOptionalRParen())) { result.addAttribute( mapName, AffineMapAttr::get(parser.getBuilder().getEmptyAffineMap())); result.addAttribute(groupsName, parser.getBuilder().getI32TensorAttr({})); return success(); }

SmallVector<AffineExpr> flatExprs; SmallVector<SmallVector<OpAsmParser::UnresolvedOperand>> flatDimOperands; SmallVector<SmallVector<OpAsmParser::UnresolvedOperand>> flatSymOperands; SmallVector<int32_t> numMapsPerGroup; SmallVector<OpAsmParser::UnresolvedOperand> mapOperands; auto parseOperands = [&]() { if (succeeded(parser.parseOptionalKeyword( kind == MinMaxKind::Min ? "min" : "max"))) { mapOperands.clear(); AffineMapAttr map; if (failed(parser.parseAffineMapOfSSAIds(mapOperands, map, tmpAttrStrName, result.attributes, OpAsmParser::Delimiter::Paren))) return failure(); result.attributes.erase(tmpAttrStrName); llvm::append_range(flatExprs, map.getValue().getResults()); auto operandsRef = llvm::ArrayRef(mapOperands); auto dimsRef = operandsRef.take_front(map.getValue().getNumDims()); SmallVector<OpAsmParser::UnresolvedOperand> dims(dimsRef); auto symsRef = operandsRef.drop_front(map.getValue().getNumDims()); SmallVector<OpAsmParser::UnresolvedOperand> syms(symsRef); flatDimOperands.append(map.getValue().getNumResults(), dims); flatSymOperands.append(map.getValue().getNumResults(), syms); numMapsPerGroup.push_back(map.getValue().getNumResults()); } else { if (failed(parser.parseAffineExprOfSSAIds(flatDimOperands.emplace_back(), flatSymOperands.emplace_back(), flatExprs.emplace_back()))) return failure(); numMapsPerGroup.push_back(1); } return success(); }; if (parser.parseCommaSeparatedList(parseOperands) || parser.parseRParen()) return failure();

unsigned totalNumDims = 0; unsigned totalNumSyms = 0; for (unsigned i = 0, e = flatExprs.size(); i < e; ++i) { unsigned numDims = flatDimOperands[i].size(); unsigned numSyms = flatSymOperands[i].size(); flatExprs[i] = flatExprs[i] .shiftDims(numDims, totalNumDims) .shiftSymbols(numSyms, totalNumSyms); totalNumDims += numDims; totalNumSyms += numSyms; }

Deduplicate map operands. SmallVector<Value> dimOperands, symOperands; SmallVector<AffineExpr> dimRplacements, symRepacements; if (deduplicateAndResolveOperands(parser, flatDimOperands, dimOperands, dimRplacements, AffineExprKind::DimId) || deduplicateAndResolveOperands(parser, flatSymOperands, symOperands, symRepacements, AffineExprKind::SymbolId)) return failure();

result.operands.append(dimOperands.begin(), dimOperands.end()); result.operands.append(symOperands.begin(), symOperands.end());

Builder &builder = parser.getBuilder(); auto flatMap = AffineMap::get(totalNumDims, totalNumSyms, flatExprs, parser.getContext()); flatMap = flatMap.replaceDimsAndSymbols( dimRplacements, symRepacements, dimOperands.size(), symOperands.size());

result.addAttribute(mapName, AffineMapAttr::get(flatMap)); result.addAttribute(groupsName, builder.getI32TensorAttr(numMapsPerGroup)); return success(); }

operation ::= affine.parallel ( ssa-ids ) = parallel-bound to parallel-bound steps? region attr-dict? steps ::= steps ( integer-literals )

ParseResult AffineParallelOp::parse(OpAsmParser &parser, OperationState &result) { auto &builder = parser.getBuilder(); auto indexType = builder.getIndexType(); SmallVector<OpAsmParser::Argument, 4> ivs; if (parser.parseArgumentList(ivs, OpAsmParser::Delimiter::Paren) || parser.parseEqual() || parseAffineMapWithMinMax(parser, result, MinMaxKind::Max) || parser.parseKeyword("to") || parseAffineMapWithMinMax(parser, result, MinMaxKind::Min)) return failure();

AffineMapAttr stepsMapAttr; NamedAttrList stepsAttrs; SmallVector<OpAsmParser::UnresolvedOperand, 4> stepsMapOperands; if (failed(parser.parseOptionalKeyword("step"))) { SmallVector<int64_t, 4> steps(ivs.size(), 1); result.addAttribute(AffineParallelOp::getStepsAttrStrName(), builder.getI64ArrayAttr(steps)); } else { if (parser.parseAffineMapOfSSAIds(stepsMapOperands, stepsMapAttr, AffineParallelOp::getStepsAttrStrName(), stepsAttrs, OpAsmParser::Delimiter::Paren)) return failure();

Convert steps from an AffineMap into an I64ArrayAttr. SmallVector<int64_t, 4> steps; auto stepsMap = stepsMapAttr.getValue(); for (const auto &result : stepsMap.getResults()) { auto constExpr = dyn_cast<AffineConstantExpr>(result); if (!constExpr) return parser.emitError(parser.getNameLoc(), "steps must be constant integers"); steps.push_back(constExpr.getValue()); } result.addAttribute(AffineParallelOp::getStepsAttrStrName(), builder.getI64ArrayAttr(steps)); }

Parse optional clause of the form: reduce ("addf", "maxf"), where the quoted strings are a member of the enum AtomicRMWKind. SmallVector<Attribute, 4> reductions; if (succeeded(parser.parseOptionalKeyword("reduce"))) { if (parser.parseLParen()) return failure(); auto parseAttributes = [&]() -> ParseResult { Parse a single quoted string via the attribute parsing, and then verify it is a member of the enum and convert to it's integer representation. StringAttr attrVal; NamedAttrList attrStorage; auto loc = parser.getCurrentLocation(); if (parser.parseAttribute(attrVal, builder.getNoneType(), "reduce", attrStorage)) return failure(); std::optional<arith::AtomicRMWKind> reduction = arith::symbolizeAtomicRMWKind(attrVal.getValue()); if (!reduction) return parser.emitError(loc, "invalid reduction value: ") << attrVal; reductions.push_back( builder.getI64IntegerAttr(static_cast<int64_t>(reduction.value()))); While we keep getting commas, keep parsing. return success(); }; if (parser.parseCommaSeparatedList(parseAttributes) || parser.parseRParen()) return failure(); } result.addAttribute(AffineParallelOp::getReductionsAttrStrName(), builder.getArrayAttr(reductions));

Parse return types of reductions (if any) if (parser.parseOptionalArrowTypeList(result.types)) return failure();

Now parse the body. Region *body = result.addRegion(); for (auto &iv : ivs) iv.type = indexType; if (parser.parseRegion(*body, ivs) || parser.parseOptionalAttrDict(result.attributes)) return failure();

Add a terminator if none was parsed. AffineParallelOp::ensureTerminator(*body, builder, result.location); return success(); }

===-------------------------------------------------------------------—===// AffineYieldOp ===-------------------------------------------------------------------—===//

LogicalResult AffineYieldOp::verify() { auto *parentOp = (*this)->getParentOp(); auto results = parentOp->getResults(); auto operands = getOperands();

if (!isa<AffineParallelOp, AffineIfOp, AffineForOp>(parentOp)) return emitOpError() << "only terminates affine.if/for/parallel regions"; if (parentOp->getNumResults() != getNumOperands()) return emitOpError() << "parent of yield must have same number of " "results as the yield operands"; for (auto it : llvm::zip(results, operands)) { if (std::get<0>(it).getType() != std::get<1>(it).getType()) return emitOpError() << "types mismatch between yield op and its parent"; }

return success(); }

===-------------------------------------------------------------------—===// AffineVectorLoadOp ===-------------------------------------------------------------------—===//

void AffineVectorLoadOp::build(OpBuilder &builder, OperationState &result, VectorType resultType, AffineMap map, ValueRange operands) { assert(operands.size() == 1 + map.getNumInputs() && "inconsistent operands"); result.addOperands(operands); if (map) result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map)); result.types.push_back(resultType); }

void AffineVectorLoadOp::build(OpBuilder &builder, OperationState &result, VectorType resultType, Value memref, AffineMap map, ValueRange mapOperands) { assert(map.getNumInputs() == mapOperands.size() && "inconsistent index info"); result.addOperands(memref); result.addOperands(mapOperands); result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map)); result.types.push_back(resultType); }

void AffineVectorLoadOp::build(OpBuilder &builder, OperationState &result, VectorType resultType, Value memref, ValueRange indices) { auto memrefType = llvm::cast<MemRefType>(memref.getType()); int64_t rank = memrefType.getRank(); Create identity map for memrefs with at least one dimension or () -> () for zero-dimensional memrefs. auto map = rank ? builder.getMultiDimIdentityMap(rank) : builder.getEmptyAffineMap(); build(builder, result, resultType, memref, map, indices); }

void AffineVectorLoadOp::getCanonicalizationPatterns(RewritePatternSet &results, MLIRContext *context) { results.add<SimplifyAffineOp<AffineVectorLoadOp>>(context); }

ParseResult AffineVectorLoadOp::parse(OpAsmParser &parser, OperationState &result) { auto &builder = parser.getBuilder(); auto indexTy = builder.getIndexType();

MemRefType memrefType; VectorType resultType; OpAsmParser::UnresolvedOperand memrefInfo; AffineMapAttr mapAttr; SmallVector<OpAsmParser::UnresolvedOperand, 1> mapOperands; return failure( parser.parseOperand(memrefInfo) || parser.parseAffineMapOfSSAIds(mapOperands, mapAttr, AffineVectorLoadOp::getMapAttrStrName(), result.attributes) || parser.parseOptionalAttrDict(result.attributes) || parser.parseColonType(memrefType) || parser.parseComma() || parser.parseType(resultType) || parser.resolveOperand(memrefInfo, memrefType, result.operands) || parser.resolveOperands(mapOperands, indexTy, result.operands) || parser.addTypeToList(resultType, result.types)); }

void AffineVectorLoadOp::print(OpAsmPrinter &p) { p << " " << getMemRef() << '['; if (AffineMapAttr mapAttr = (*this)->getAttrOfType<AffineMapAttr>(getMapAttrStrName())) p.printAffineMapOfSSAIds(mapAttr, getMapOperands()); p << ']'; p.printOptionalAttrDict((*this)->getAttrs(), /*elidedAttrs=

Referenced by verifyPermutationMap(), verifyStructIndices(), and verifyStructIndices().

◆ foldCstValueToCstAttrBasis()

std::optional< SmallVector< int64_t > > foldCstValueToCstAttrBasis ( ArrayRef< OpFoldResult > mixedBasis,
MutableOperandRange mutableDynamicBasis,
ArrayRef< Attribute > dynamicBasis )
static

Given mixed basis of affine.delinearize_index/linearize_index replace constant SSA values with the constant integer value and return the new static basis. In case no such candidate for replacement exists, this utility returns std::nullopt.

Definition at line 4965 of file AffineOps.cpp.

References mlir::MutableOperandRange::erase(), and mlir::getConstantIntValue().

◆ foldLoopBounds()

LogicalResult foldLoopBounds ( AffineForOp forOp)
static

Fold the constant bounds of a loop.

Definition at line 2558 of file AffineOps.cpp.

References mlir::AffineMap::constantFold(), mlir::AffineMap::getNumResults(), mlir::m_Constant(), mlir::matchPattern(), and success().

◆ foldMinMaxOp()

template<typename T>
OpFoldResult foldMinMaxOp ( T op,
ArrayRef< Attribute > operands )
static

Fold an affine min or max operation with the given operands.

The operand list may contain nulls, which are interpreted as the operand not being a constant.

Definition at line 3633 of file AffineOps.cpp.

◆ getLargestKnownDivisor()

int64_t getLargestKnownDivisor ( AffineExpr e,
ArrayRef< Value > operands )
static

Returns the largest known divisor of e.

Exploits information from the values in operands.

Definition at line 659 of file AffineOps.cpp.

References div, mlir::affine::getForInductionVarOwner(), and mlir::AffineExpr::getLargestKnownDivisor().

Referenced by isQTimesDPlusR(), and simplifyExprAndOperands().

◆ getLowerBound() [1/2]

std::optional< int64_t > getLowerBound ( AffineExpr expr,
unsigned numDims,
unsigned numSymbols,
ArrayRef< Value > operands )
static

Determine a constant lower bound for expr if one exists while exploiting values in operands.

Note that the upper bound is an inclusive one. expr is guaranteed to be less than or equal to it.

Definition at line 798 of file AffineOps.cpp.

References mlir::getBoundForAffineExpr(), getLowerBound(), and getUpperBound().

◆ getLowerBound() [2/2]

std::optional< int64_t > getLowerBound ( Value iv)
static

Gets the constant lower bound on an iv.

Definition at line 749 of file AffineOps.cpp.

References mlir::affine::getForInductionVarOwner().

Referenced by getLowerBound(), getUpperBound(), simplifyExprAndOperands(), and simplifyMinOrMaxExprWithOperands().

◆ getTrivialConstantTripCount()

std::optional< uint64_t > getTrivialConstantTripCount ( AffineForOp forOp)
static

Returns constant trip count in trivial cases.

Definition at line 2604 of file AffineOps.cpp.

Referenced by AffineForEmptyLoopFolder(), and hasTrivialZeroTripCount().

◆ getUpperBound() [1/2]

std::optional< int64_t > getUpperBound ( AffineExpr expr,
unsigned numDims,
unsigned numSymbols,
ArrayRef< Value > operands )
static

Determine a constant upper bound for expr if one exists while exploiting values in operands.

Note that the upper bound is an inclusive one. expr is guaranteed to be less than or equal to it.

Definition at line 775 of file AffineOps.cpp.

References mlir::getBoundForAffineExpr(), getLowerBound(), and getUpperBound().

◆ getUpperBound() [2/2]

std::optional< int64_t > getUpperBound ( Value iv)
static

Gets the constant upper bound on an affine.for iv.

Definition at line 757 of file AffineOps.cpp.

References mlir::affine::getForInductionVarOwner().

Referenced by getLowerBound(), getUpperBound(), simplifyExprAndOperands(), and simplifyMinOrMaxExprWithOperands().

◆ hasTrivialZeroTripCount()

bool hasTrivialZeroTripCount ( AffineForOp op)
static

Returns true if the affine.for has zero iterations in trivial cases.

Definition at line 2694 of file AffineOps.cpp.

References getTrivialConstantTripCount().

◆ isDimOpValidSymbol()

bool isDimOpValidSymbol ( ShapedDimOpInterface dimOp,
Region * region )
static

Returns true if the result of the dim op is a valid symbol for region.

Definition at line 368 of file AffineOps.cpp.

References mlir::getConstantIntValue(), isMemRefSizeValidSymbol(), and mlir::affine::isTopLevelValue().

Referenced by mlir::affine::isValidSymbol().

◆ isMemRefSizeValidSymbol()

template<typename AnyMemRefDefOp>
bool isMemRefSizeValidSymbol ( AnyMemRefDefOp memrefDefOp,
unsigned index,
Region * region )
static

Returns true if the 'index' dimension of the memref defined by memrefDefOp is a statically shaped one or defined using a valid symbol for region.

Definition at line 349 of file AffineOps.cpp.

References mlir::affine::isValidSymbol().

Referenced by isDimOpValidSymbol().

◆ isNonNegativeBoundedBy()

bool isNonNegativeBoundedBy ( AffineExpr e,
ArrayRef< Value > operands,
int64_t k )
static

Check if e is known to be: 0 <= e < k.

Handles the simple cases of e being an affine dim expression or a constant.

Definition at line 697 of file AffineOps.cpp.

References mlir::affine::getForInductionVarOwner().

Referenced by isQTimesDPlusR(), and simplifyExprAndOperands().

◆ isQTimesDPlusR()

bool isQTimesDPlusR ( AffineExpr e,
ArrayRef< Value > operands,
int64_t & div,
AffineExpr & quotientTimesDiv,
AffineExpr & rem )
static

Check if expression e is of the form d*e_1 + e_2 where 0 <= e_2 < d.

Set div to d, quotientTimesDiv to e_1 and rem to e_2 if the expression is in that form.

Definition at line 725 of file AffineOps.cpp.

References mlir::Add, div, getLargestKnownDivisor(), isNonNegativeBoundedBy(), and rem.

Referenced by simplifyExprAndOperands().

◆ isResultTypeMatchAtomicRMWKind()

bool isResultTypeMatchAtomicRMWKind ( Type resultType,
arith::AtomicRMWKind op )
static

Definition at line 4230 of file AffineOps.cpp.

◆ isTopLevelValueOrAbove()

bool isTopLevelValueOrAbove ( Value value,
Region * region )
static

A utility function to check if a value is defined at the top level of region or is an argument of region or is defined above the region.

Definition at line 432 of file AffineOps.cpp.

References mlir::Region::getParentOp(), mlir::Operation::getParentRegion(), mlir::Value::getParentRegion(), and mlir::Operation::hasTrait().

Referenced by mlir::affine::isValidSymbol().

◆ isValidAffineIndexOperand()

bool isValidAffineIndexOperand ( Value value,
Region * region )
static

◆ legalizeDemotedDims()

template<class MapOrSet>
void legalizeDemotedDims ( MapOrSet & mapOrSet,
SmallVectorImpl< Value > & operands )
static

A valid affine dimension may appear as a symbol in affine.apply operations.

Given an application of operands to an affine map or integer set mapOrSet, this function canonicalizes symbols of mapOrSet that are valid dims, but not valid symbols into actual dims. Without such a legalization, the affine.apply will be invalid. This method is the exact inverse of canonicalizePromotedSymbols.

Definition at line 1636 of file AffineOps.cpp.

References mlir::getAffineDimExpr(), mlir::getAffineSymbolExpr(), mlir::affine::isValidDim(), and mlir::affine::isValidSymbol().

Referenced by canonicalizeMapOrSetAndOperands().

◆ makeComposedFoldedMinMax()

template<typename OpTy>
OpFoldResult makeComposedFoldedMinMax ( OpBuilder & b,
Location loc,
AffineMap map,
ArrayRef< OpFoldResult > operands )
static

◆ makeComposedMinMax()

template<typename OpTy>
OpTy makeComposedMinMax ( OpBuilder & b,
Location loc,
AffineMap map,
ArrayRef< OpFoldResult > operands )
static

◆ parseAffineMinMaxOp()

◆ parseBound()

◆ printAffineMinMaxOp()

template<typename T>
void printAffineMinMaxOp ( OpAsmPrinter & p,
T op )
static

Definition at line 3597 of file AffineOps.cpp.

References mlir::OpAsmPrinter::printOptionalAttrDict().

◆ printBound()

◆ printDimAndSymbolList()

void printDimAndSymbolList ( Operation::operand_iterator begin,
Operation::operand_iterator end,
unsigned numDims,
OpAsmPrinter & printer )
static

Prints dimension and symbol list.

Definition at line 497 of file AffineOps.cpp.

Referenced by printBound().

◆ printMinMaxBound()

void printMinMaxBound ( OpAsmPrinter & p,
AffineMapAttr mapAttr,
DenseIntElementsAttr group,
ValueRange operands,
StringRef keyword )
static

Prints a lower(upper) bound of an affine parallel loop with max(min) conditions in it.

mapAttr is a flat list of affine expressions and group identifies which of the those expressions form max/min groups. operands are the SSA values of dimensions and symbols and keyword is either "min" or "max".

Definition at line 4377 of file AffineOps.cpp.

References mlir::AffineMap::getNumDims(), mlir::AffineMap::getResult(), mlir::AffineMap::getSliceMap(), mlir::OpAsmPrinter::printAffineExprOfSSAIds(), and mlir::OpAsmPrinter::printAffineMapOfSSAIds().

◆ remainsLegalAfterInline() [1/4]

template<>
bool remainsLegalAfterInline ( AffineApplyOp op,
Region * src,
Region * dest,
const IRMapping & mapping )

Checks if an affine apply operation remains legal after inlining from src to dest.

Definition at line 128 of file AffineOps.cpp.

References mlir::affine::isValidDim(), mlir::affine::isValidSymbol(), and remainsLegalAfterInline().

◆ remainsLegalAfterInline() [2/4]

template<typename OpTy>
bool remainsLegalAfterInline ( OpTy op,
Region * src,
Region * dest,
const IRMapping & mapping )
static

Checks if an affine read or write operation remains legal after inlining from src to dest.

Definition at line 102 of file AffineOps.cpp.

References mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumSymbols(), mlir::affine::isValidDim(), mlir::affine::isValidSymbol(), and remainsLegalAfterInline().

◆ remainsLegalAfterInline() [3/4]

bool remainsLegalAfterInline ( Value value,
Region * src,
Region * dest,
const IRMapping & mapping,
function_ref< bool(Value, Region *)> legalityCheck )
static

Checks if value known to be a legal affine dimension or symbol in src region remains legal if the operation that uses it is inlined into dest with the given value mapping.

legalityCheck is either isValidDim or isValidSymbol, depending on the value being required to remain a valid dimension or symbol.

Definition at line 62 of file AffineOps.cpp.

References mlir::Value::getDefiningOp(), mlir::affine::isTopLevelValue(), mlir::IRMapping::lookup(), mlir::m_Constant(), and mlir::matchPattern().

Referenced by remainsLegalAfterInline(), remainsLegalAfterInline(), and remainsLegalAfterInline().

◆ remainsLegalAfterInline() [4/4]

bool remainsLegalAfterInline ( ValueRange values,
Region * src,
Region * dest,
const IRMapping & mapping,
function_ref< bool(Value, Region *)> legalityCheck )
static

Checks if all values known to be legal affine dimensions or symbols in src remain so if their respective users are inlined into dest.

Definition at line 91 of file AffineOps.cpp.

References remainsLegalAfterInline().

◆ replaceAffineDelinearizeIndexInverseExpression()

LogicalResult replaceAffineDelinearizeIndexInverseExpression ( AffineDelinearizeIndexOp delinOp,
Value resultToReplace,
AffineMap * map,
SmallVectorImpl< Value > & dims,
SmallVectorImpl< Value > & syms )
static

If this map contains of the expression x_1 + x_1 * C_1 + ... x_n * C_N + / ... (not necessarily in order) where the set of the x_i is the set of outputs of an affine.delinearize_index whos inverse is that expression, replace that expression with the input of that delinearize_index op.

unitDimInput is the input that was detected as the potential start to this replacement chain - if it isn't the rightmost result of the delinearization, this method fails. (This is intended to ensure we don't have redundant scans over the same expression).

While this currently only handles delinearizations with a constant basis, that isn't a fundamental limitation.

This is a utility function for replaceDimOrSym below.

Definition at line 1190 of file AffineOps.cpp.

References mlir::getAffineConstantExpr(), mlir::getAffineDimExpr(), mlir::getAffineSymbolExpr(), mlir::AffineMap::getResults(), mlir::AffineMap::isFunctionOfDim(), mlir::AffineMap::isFunctionOfSymbol(), mlir::AffineMap::replace(), shortenAddChainsContainingAll(), and success().

Referenced by replaceDimOrSym().

◆ replaceAffineMinBoundingBoxExpression()

LogicalResult replaceAffineMinBoundingBoxExpression ( AffineMinOp minOp,
AffineExpr dimOrSym,
AffineMap * map,
ValueRange dims,
ValueRange syms )
static

Assuming dimOrSym is a quantity in the apply op map map and defined by minOp = affine_min(x_1, ..., x_n).

This function checks that: 0 < affine_min(x_1, ..., x_n) and proceeds with replacing the patterns:

dimOrSym.ceildiv(x_k)
(dimOrSym + x_k - 1).floordiv(x_k)

by 1 for all k in 1, ..., n. This is possible because x / x_k <= 1.

Warning: ValueBoundsConstraintSet::computeConstantBound is needed to check minOp is positive.

Convert affine symbols and dimensions in minOp to symbols or dimensions in the apply op affine map.

Definition at line 1061 of file AffineOps.cpp.

References mlir::AffineExpr::ceilDiv(), mlir::ValueBoundsConstraintSet::compare(), mlir::getAffineConstantExpr(), mlir::getAffineDimExpr(), mlir::getAffineSymbolExpr(), mlir::getAsIndexOpFoldResult(), mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::AffineMap::getResults(), mlir::AffineMap::getSliceMap(), mlir::ValueBoundsConstraintSet::LT, mlir::AffineExpr::replace(), mlir::AffineMap::replace(), and success().

Referenced by replaceDimOrSym().

◆ replaceDimOrSym()

LogicalResult replaceDimOrSym ( AffineMap * map,
unsigned dimOrSymbolPosition,
SmallVectorImpl< Value > & dims,
SmallVectorImpl< Value > & syms,
bool replaceAffineMin )
static

Replace all occurrences of AffineExpr at position pos in map by the defining AffineApplyOp expression and operands.

When dimOrSymbolPosition < dims.size(), AffineDimExpr@[pos] is replaced. When dimOrSymbolPosition >= dims.size(), AffineSymbolExpr@[pos - dims.size()] is replaced. Mutate map,dims and syms in place as follows:

  1. dims and syms are only appended to.
  2. map dim and symbols are gradually shifted to higher positions.
  3. Old dim and sym entries are replaced by nullptr This avoids the need for any bookkeeping. If replaceAffineMin is set to true, additionally triggers more expensive replacements involving affine_min operations.

Definition at line 1275 of file AffineOps.cpp.

References mlir::affine::canonicalizeMapAndOperands(), mlir::getAffineDimExpr(), mlir::getAffineSymbolExpr(), mlir::AffineMap::getContext(), mlir::Value::getDefiningOp(), mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::AffineMap::getResult(), mlir::AffineMap::replace(), replaceAffineDelinearizeIndexInverseExpression(), replaceAffineMinBoundingBoxExpression(), mlir::AffineMap::shiftDims(), mlir::AffineMap::shiftSymbols(), and success().

Referenced by composeAffineMapAndOperands().

◆ shortenAddChainsContainingAll()

void shortenAddChainsContainingAll ( AffineExpr e,
const llvm::SmallDenseSet< AffineExpr, 4 > & exprsToRemove,
AffineExpr newVal,
DenseMap< AffineExpr, AffineExpr > & replacementsMap )
static

Recursively traverse e.

If e or one of its sub-expressions has the form e1 + e2 + ... + eK, where the e_i are a super(multi)set of exprsToRemove, place a map between e and newVal + sum({e1, e2, .. eK} - exprsToRemove) into replacementsMap. If no entries were added to replacementsMap, nothing was found.

Definition at line 1133 of file AffineOps.cpp.

References mlir::Add, lhs, rhs, and shortenAddChainsContainingAll().

Referenced by replaceAffineDelinearizeIndexInverseExpression(), and shortenAddChainsContainingAll().

◆ simplifyExprAndOperands()

◆ simplifyMapWithOperands()

void simplifyMapWithOperands ( AffineMap & map,
ArrayRef< Value > operands )
static

◆ simplifyMinOrMaxExprWithOperands()

void simplifyMinOrMaxExprWithOperands ( AffineMap & map,
ArrayRef< Value > operands,
bool isMax )
static

Simplify the expressions in map while making use of lower or upper bounds of its operands.

If isMax is true, the map is to be treated as a max of its result expressions, and min otherwise. Eg: min (d0, d1) -> (8, 4 * d0 + d1) can be simplified to (8) if the operands are respectively lower bounded by 2 and 0 (the second expression can't be lower than 8).

Definition at line 925 of file AffineOps.cpp.

References mlir::AffineMap::get(), mlir::getAffineConstantExpr(), mlir::getBoundForAffineExpr(), mlir::AffineExpr::getContext(), mlir::AffineMap::getContext(), getLowerBound(), mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::AffineMap::getResults(), and getUpperBound().

Referenced by canonicalizeLoopBounds().

◆ success()

◆ verifyAffineMinMaxOp()

template<typename T>
LogicalResult verifyAffineMinMaxOp ( T op)
static

Definition at line 3584 of file AffineOps.cpp.

References success().

◆ verifyDimAndSymbolIdentifiers()

template<typename OpTy>
LogicalResult verifyDimAndSymbolIdentifiers ( OpTy & op,
Operation::operand_range operands,
unsigned numDims )
static

Utility function to verify that a set of operands are valid dimension and symbol identifiers.

The operands should be laid out such that the dimension operands are before the symbol operands. This function returns failure if there was an invalid operand. An operation is provided to emit any necessary errors.

Definition at line 529 of file AffineOps.cpp.

References mlir::affine::getAffineScope(), mlir::affine::isValidDim(), mlir::affine::isValidSymbol(), and success().

Referenced by verifyMemoryOpIndexing().

◆ verifyMemoryOpIndexing()

template<typename AffineMemOpTy>
LogicalResult verifyMemoryOpIndexing ( AffineMemOpTy op,
AffineMapAttr mapAttr,
Operation::operand_range mapOperands,
MemRefType memrefType,
unsigned numIndexOperands )
static

Verify common indexing invariants of affine.load, affine.store, affine.vector_load and affine.vector_store.

Definition at line 3419 of file AffineOps.cpp.

References mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumInputs(), mlir::AffineMap::getNumResults(), success(), and verifyDimAndSymbolIdentifiers().