[Mlir-commits] [mlir] fdc7a16 - [MLIR][Affine] Add affine.parallel op
Frank Laub
llvmlistbot at llvm.org
Wed Feb 12 18:00:34 PST 2020
Author: Frank Laub
Date: 2020-02-12T18:00:24-08:00
New Revision: fdc7a16a8275b4ef69a17bb61c54c445ef506f90
URL: https://github.com/llvm/llvm-project/commit/fdc7a16a8275b4ef69a17bb61c54c445ef506f90
DIFF: https://github.com/llvm/llvm-project/commit/fdc7a16a8275b4ef69a17bb61c54c445ef506f90.diff
LOG: [MLIR][Affine] Add affine.parallel op
Summary:
As discussed in https://llvm.discourse.group/t/rfc-add-affine-parallel/350, this is the first in a series of patches to bring in support for the `affine.parallel` operation.
This first patch adds the IR representation along with custom printer/parser implementations.
Reviewers: bondhugula, herhut, mehdi_amini, nicolasvasilache, rriddle, earhart, jbruestle
Reviewed By: bondhugula, nicolasvasilache, rriddle, earhart, jbruestle
Subscribers: jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D74288
Added:
Modified:
mlir/include/mlir/Dialect/AffineOps/AffineOps.td
mlir/include/mlir/IR/OpImplementation.h
mlir/lib/Dialect/AffineOps/AffineOps.cpp
mlir/lib/Parser/Parser.cpp
mlir/test/AffineOps/invalid.mlir
mlir/test/AffineOps/ops.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/AffineOps/AffineOps.td b/mlir/include/mlir/Dialect/AffineOps/AffineOps.td
index 9514fdc9ea0c..4627802d5d77 100644
--- a/mlir/include/mlir/Dialect/AffineOps/AffineOps.td
+++ b/mlir/include/mlir/Dialect/AffineOps/AffineOps.td
@@ -271,6 +271,79 @@ def AffineMaxOp : AffineMinMaxOpBase<"max", [NoSideEffect]> {
}];
}
+def AffineParallelOp : Affine_Op<"parallel", [ImplicitAffineTerminator]> {
+ let summary = "multi-index parallel band operation";
+ let description = [{
+ The "affine.parallel" operation represents a hyper-rectangular affine
+ parallel band, defining multiple SSA values for its induction variables. It
+ has one region capturing the parallel band body. The induction variables are
+ represented as arguments of this region. These SSA values always have type
+ index, which is the size of the machine word. The strides, represented by
+ steps, are positive constant integers which defaults to "1" if not present.
+ The lower and upper bounds specify a half-open range: the range includes the
+ lower bound but does not include the upper bound. The body region must
+ contain exactly one block that terminates with "affine.terminator".
+
+ The lower and upper bounds of a parallel operation are represented as an
+ application of an affine mapping to a list of SSA values passed to the map.
+ The same restrictions hold for these SSA values as for all bindings of SSA
+ values to dimensions and symbols.
+
+ Note: Calling AffineParallelOp::build will create the required region and
+ block, and insert the required terminator. Parsing will also create the
+ required region, block, and terminator, even when they are missing from the
+ textual representation.
+
+ Example:
+
+ ```mlir
+ affine.parallel (%i, %j) = (0, 0) to (10, 10) step (1, 1) {
+ ...
+ }
+ ```
+ }];
+
+ let arguments = (ins
+ AffineMapAttr:$lowerBoundsMap,
+ AffineMapAttr:$upperBoundsMap,
+ I64ArrayAttr:$steps,
+ Variadic<Index>:$mapOperands);
+ let regions = (region SizedRegion<1>:$region);
+
+ let builders = [
+ OpBuilder<"Builder* builder, OperationState& result,"
+ "ArrayRef<int64_t> ranges">,
+ OpBuilder<"Builder* builder, OperationState& result, AffineMap lbMap,"
+ "ValueRange lbArgs, AffineMap ubMap, ValueRange ubArgs">,
+ OpBuilder<"Builder* builder, OperationState& result, AffineMap lbMap,"
+ "ValueRange lbArgs, AffineMap ubMap, ValueRange ubArgs,"
+ "ArrayRef<int64_t> steps">
+ ];
+
+ let extraClassDeclaration = [{
+ /// Get the number of dimensions.
+ unsigned getNumDims();
+
+ operand_range getLowerBoundsOperands();
+ operand_range getUpperBoundsOperands();
+
+ AffineValueMap getLowerBoundsValueMap();
+ AffineValueMap getUpperBoundsValueMap();
+ AffineValueMap getRangesValueMap();
+
+ /// Get ranges as constants, may fail in dynamic case.
+ Optional<SmallVector<int64_t, 8>> getConstantRanges();
+
+ Block *getBody();
+ OpBuilder getBodyBuilder();
+ void setSteps(ArrayRef<int64_t> newSteps);
+
+ static StringRef getLowerBoundsMapAttrName() { return "lowerBoundsMap"; }
+ static StringRef getUpperBoundsMapAttrName() { return "upperBoundsMap"; }
+ static StringRef getStepsAttrName() { return "steps"; }
+ }];
+}
+
def AffinePrefetchOp : Affine_Op<"prefetch"> {
let summary = "affine prefetch operation";
let description = [{
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index 47bfe69487d9..4edf17e50a52 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -105,7 +105,8 @@ class OpAsmPrinter {
if (types.begin() != types.end())
printArrowTypeList(types);
}
- template <typename TypeRange> void printArrowTypeList(TypeRange &&types) {
+ template <typename TypeRange>
+ void printArrowTypeList(TypeRange &&types) {
auto &os = getStream() << " -> ";
bool wrapped = !has_single_element(types) ||
@@ -517,7 +518,8 @@ class OpAsmParser {
virtual ParseResult
parseAffineMapOfSSAIds(SmallVectorImpl<OperandType> &operands, Attribute &map,
StringRef attrName,
- SmallVectorImpl<NamedAttribute> &attrs) = 0;
+ SmallVectorImpl<NamedAttribute> &attrs,
+ Delimiter delimiter = Delimiter::Square) = 0;
//===--------------------------------------------------------------------===//
// Region Parsing
@@ -579,7 +581,8 @@ class OpAsmParser {
virtual ParseResult parseType(Type &result) = 0;
/// Parse a type of a specific type.
- template <typename TypeT> ParseResult parseType(TypeT &result) {
+ template <typename TypeT>
+ ParseResult parseType(TypeT &result) {
llvm::SMLoc loc = getCurrentLocation();
// Parse any kind of type.
@@ -614,7 +617,8 @@ class OpAsmParser {
virtual ParseResult parseColonType(Type &result) = 0;
/// Parse a colon followed by a type of a specific kind, e.g. a FunctionType.
- template <typename TypeType> ParseResult parseColonType(TypeType &result) {
+ template <typename TypeType>
+ ParseResult parseColonType(TypeType &result) {
llvm::SMLoc loc = getCurrentLocation();
// Parse any kind of type.
diff --git a/mlir/lib/Dialect/AffineOps/AffineOps.cpp b/mlir/lib/Dialect/AffineOps/AffineOps.cpp
index 0ccbd1cf23ad..d39634e9eb5b 100644
--- a/mlir/lib/Dialect/AffineOps/AffineOps.cpp
+++ b/mlir/lib/Dialect/AffineOps/AffineOps.cpp
@@ -134,9 +134,11 @@ bool mlir::isValidDim(Value value) {
return isTopLevelValue(dimOp.getOperand());
return false;
}
- // This value has to be a block argument for a FuncOp or an affine.for.
+ // This value has to be a block argument of a FuncOp, an 'affine.for', or an
+ // 'affine.parallel'.
auto *parentOp = value.cast<BlockArgument>().getOwner()->getParentOp();
- return isa<FuncOp>(parentOp) || isa<AffineForOp>(parentOp);
+ return isa<FuncOp>(parentOp) || isa<AffineForOp>(parentOp) ||
+ isa<AffineParallelOp>(parentOp);
}
/// Returns true if the 'index' dimension of the `memref` defined by
@@ -2150,6 +2152,236 @@ LogicalResult AffinePrefetchOp::fold(ArrayRef<Attribute> cstOperands,
return foldMemRefCast(*this);
}
+//===----------------------------------------------------------------------===//
+// AffineParallelOp
+//===----------------------------------------------------------------------===//
+
+void AffineParallelOp::build(Builder *builder, OperationState &result,
+ ArrayRef<int64_t> ranges) {
+ // Default initalize empty maps.
+ auto lbMap = AffineMap::get(builder->getContext());
+ auto ubMap = AffineMap::get(builder->getContext());
+ // If there are ranges, set each to [0, N).
+ if (ranges.size()) {
+ SmallVector<AffineExpr, 8> lbExprs(ranges.size(),
+ builder->getAffineConstantExpr(0));
+ lbMap = AffineMap::get(0, 0, lbExprs);
+ SmallVector<AffineExpr, 8> ubExprs;
+ for (int64_t range : ranges)
+ ubExprs.push_back(builder->getAffineConstantExpr(range));
+ ubMap = AffineMap::get(0, 0, ubExprs);
+ }
+ build(builder, result, lbMap, {}, ubMap, {});
+}
+
+void AffineParallelOp::build(Builder *builder, OperationState &result,
+ AffineMap lbMap, ValueRange lbArgs,
+ AffineMap ubMap, ValueRange ubArgs) {
+ auto numDims = lbMap.getNumResults();
+ // Verify that the dimensionality of both maps are the same.
+ assert(numDims == ubMap.getNumResults() &&
+ "num dims and num results mismatch");
+ // Make default step sizes of 1.
+ SmallVector<int64_t, 8> steps(numDims, 1);
+ build(builder, result, lbMap, lbArgs, ubMap, ubArgs, steps);
+}
+
+void AffineParallelOp::build(Builder *builder, OperationState &result,
+ AffineMap lbMap, ValueRange lbArgs,
+ AffineMap ubMap, ValueRange ubArgs,
+ ArrayRef<int64_t> steps) {
+ auto numDims = lbMap.getNumResults();
+ // Verify that the dimensionality of the maps matches the number of steps.
+ assert(numDims == ubMap.getNumResults() &&
+ "num dims and num results mismatch");
+ assert(numDims == steps.size() && "num dims and num steps mismatch");
+ result.addAttribute(getLowerBoundsMapAttrName(), AffineMapAttr::get(lbMap));
+ result.addAttribute(getUpperBoundsMapAttrName(), AffineMapAttr::get(ubMap));
+ result.addAttribute(getStepsAttrName(), builder->getI64ArrayAttr(steps));
+ result.addOperands(lbArgs);
+ result.addOperands(ubArgs);
+ // Create a region and a block for the body.
+ auto bodyRegion = result.addRegion();
+ auto body = new Block();
+ // Add all the block arguments.
+ for (unsigned i = 0; i < numDims; ++i)
+ body->addArgument(IndexType::get(builder->getContext()));
+ bodyRegion->push_back(body);
+ ensureTerminator(*bodyRegion, *builder, result.location);
+}
+
+unsigned AffineParallelOp::getNumDims() { return steps().size(); }
+
+AffineParallelOp::operand_range AffineParallelOp::getLowerBoundsOperands() {
+ return getOperands().take_front(lowerBoundsMap().getNumInputs());
+}
+
+AffineParallelOp::operand_range AffineParallelOp::getUpperBoundsOperands() {
+ return getOperands().drop_front(lowerBoundsMap().getNumInputs());
+}
+
+AffineValueMap AffineParallelOp::getLowerBoundsValueMap() {
+ return AffineValueMap(lowerBoundsMap(), getLowerBoundsOperands());
+}
+
+AffineValueMap AffineParallelOp::getUpperBoundsValueMap() {
+ return AffineValueMap(upperBoundsMap(), getUpperBoundsOperands());
+}
+
+AffineValueMap AffineParallelOp::getRangesValueMap() {
+ AffineValueMap out;
+ AffineValueMap::
diff erence(getUpperBoundsValueMap(), getLowerBoundsValueMap(),
+ &out);
+ return out;
+}
+
+Optional<SmallVector<int64_t, 8>> AffineParallelOp::getConstantRanges() {
+ // Try to convert all the ranges to constant expressions.
+ SmallVector<int64_t, 8> out;
+ AffineValueMap rangesValueMap = getRangesValueMap();
+ out.reserve(rangesValueMap.getNumResults());
+ for (unsigned i = 0, e = rangesValueMap.getNumResults(); i < e; ++i) {
+ auto expr = rangesValueMap.getResult(i);
+ auto cst = expr.dyn_cast<AffineConstantExpr>();
+ if (!cst)
+ return llvm::None;
+ out.push_back(cst.getValue());
+ }
+ return out;
+}
+
+Block *AffineParallelOp::getBody() { return ®ion().front(); }
+
+OpBuilder AffineParallelOp::getBodyBuilder() {
+ return OpBuilder(getBody(), std::prev(getBody()->end()));
+}
+
+void AffineParallelOp::setSteps(ArrayRef<int64_t> newSteps) {
+ assert(newSteps.size() == getNumDims() && "steps & num dims mismatch");
+ setAttr(getStepsAttrName(), getBodyBuilder().getI64ArrayAttr(newSteps));
+}
+
+static LogicalResult verify(AffineParallelOp op) {
+ auto numDims = op.getNumDims();
+ if (op.lowerBoundsMap().getNumResults() != numDims ||
+ op.upperBoundsMap().getNumResults() != numDims ||
+ op.steps().size() != numDims ||
+ op.getBody()->getNumArguments() != numDims) {
+ return op.emitOpError("region argument count and num results of upper "
+ "bounds, lower bounds, and steps must all match");
+ }
+ // Verify that the bound operands are valid dimension/symbols.
+ /// Lower bounds.
+ if (failed(verifyDimAndSymbolIdentifiers(op, op.getLowerBoundsOperands(),
+ op.lowerBoundsMap().getNumDims())))
+ return failure();
+ /// Upper bounds.
+ if (failed(verifyDimAndSymbolIdentifiers(op, op.getUpperBoundsOperands(),
+ op.upperBoundsMap().getNumDims())))
+ return failure();
+ return success();
+}
+
+static void print(OpAsmPrinter &p, AffineParallelOp op) {
+ p << op.getOperationName() << " (" << op.getBody()->getArguments() << ") = (";
+ p.printAffineMapOfSSAIds(op.lowerBoundsMapAttr(),
+ op.getLowerBoundsOperands());
+ p << ") to (";
+ p.printAffineMapOfSSAIds(op.upperBoundsMapAttr(),
+ op.getUpperBoundsOperands());
+ p << ')';
+ SmallVector<int64_t, 4> steps;
+ bool elideSteps = true;
+ for (auto attr : op.steps()) {
+ auto step = attr.cast<IntegerAttr>().getInt();
+ elideSteps &= (step == 1);
+ steps.push_back(step);
+ }
+ if (!elideSteps) {
+ p << " step (";
+ interleaveComma(steps, p);
+ p << ')';
+ }
+ p.printRegion(op.region(), /*printEntryBlockArgs=*/false,
+ /*printBlockTerminators=*/false);
+ p.printOptionalAttrDict(
+ op.getAttrs(),
+ /*elidedAttrs=*/{AffineParallelOp::getLowerBoundsMapAttrName(),
+ AffineParallelOp::getUpperBoundsMapAttrName(),
+ AffineParallelOp::getStepsAttrName()});
+}
+
+//
+// operation ::= `affine.parallel` `(` ssa-ids `)` `=` `(` map-of-ssa-ids `)`
+// `to` `(` map-of-ssa-ids `)` steps? region attr-dict?
+// steps ::= `steps` `(` integer-literals `)`
+//
+static ParseResult parseAffineParallelOp(OpAsmParser &parser,
+ OperationState &result) {
+ auto &builder = parser.getBuilder();
+ auto indexType = builder.getIndexType();
+ AffineMapAttr lowerBoundsAttr, upperBoundsAttr;
+ SmallVector<OpAsmParser::OperandType, 4> ivs;
+ SmallVector<OpAsmParser::OperandType, 4> lowerBoundsMapOperands;
+ SmallVector<OpAsmParser::OperandType, 4> upperBoundsMapOperands;
+ if (parser.parseRegionArgumentList(ivs, /*requiredOperandCount=*/-1,
+ OpAsmParser::Delimiter::Paren) ||
+ parser.parseEqual() ||
+ parser.parseAffineMapOfSSAIds(
+ lowerBoundsMapOperands, lowerBoundsAttr,
+ AffineParallelOp::getLowerBoundsMapAttrName(), result.attributes,
+ OpAsmParser::Delimiter::Paren) ||
+ parser.resolveOperands(lowerBoundsMapOperands, indexType,
+ result.operands) ||
+ parser.parseKeyword("to") ||
+ parser.parseAffineMapOfSSAIds(
+ upperBoundsMapOperands, upperBoundsAttr,
+ AffineParallelOp::getUpperBoundsMapAttrName(), result.attributes,
+ OpAsmParser::Delimiter::Paren) ||
+ parser.resolveOperands(upperBoundsMapOperands, indexType,
+ result.operands))
+ return failure();
+
+ AffineMapAttr stepsMapAttr;
+ SmallVector<NamedAttribute, 1> stepsAttrs;
+ SmallVector<OpAsmParser::OperandType, 4> stepsMapOperands;
+ if (failed(parser.parseOptionalKeyword("step"))) {
+ SmallVector<int64_t, 4> steps(ivs.size(), 1);
+ result.addAttribute(AffineParallelOp::getStepsAttrName(),
+ builder.getI64ArrayAttr(steps));
+ } else {
+ if (parser.parseAffineMapOfSSAIds(stepsMapOperands, stepsMapAttr,
+ AffineParallelOp::getStepsAttrName(),
+ 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 = result.dyn_cast<AffineConstantExpr>();
+ if (!constExpr)
+ return parser.emitError(parser.getNameLoc(),
+ "steps must be constant integers");
+ steps.push_back(constExpr.getValue());
+ }
+ result.addAttribute(AffineParallelOp::getStepsAttrName(),
+ builder.getI64ArrayAttr(steps));
+ }
+
+ // Now parse the body.
+ Region *body = result.addRegion();
+ SmallVector<Type, 4> types(ivs.size(), indexType);
+ if (parser.parseRegion(*body, ivs, types) ||
+ parser.parseOptionalAttrDict(result.attributes))
+ return failure();
+
+ // Add a terminator if none was parsed.
+ AffineParallelOp::ensureTerminator(*body, builder, result.location);
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Parser/Parser.cpp b/mlir/lib/Parser/Parser.cpp
index 7d8535f3cee3..bff9ab6b81c0 100644
--- a/mlir/lib/Parser/Parser.cpp
+++ b/mlir/lib/Parser/Parser.cpp
@@ -343,7 +343,8 @@ class Parser {
/// Parse an AffineMap where the dim and symbol identifiers are SSA ids.
ParseResult
parseAffineMapOfSSAIds(AffineMap &map,
- function_ref<ParseResult(bool)> parseElement);
+ function_ref<ParseResult(bool)> parseElement,
+ OpAsmParser::Delimiter delimiter);
private:
/// The Parser is subclassed and reinstantiated. Do not add additional
@@ -2431,7 +2432,8 @@ class AffineParser : public Parser {
AffineMap parseAffineMapRange(unsigned numDims, unsigned numSymbols);
ParseResult parseAffineMapOrIntegerSetInline(AffineMap &map, IntegerSet &set);
IntegerSet parseIntegerSetConstraints(unsigned numDims, unsigned numSymbols);
- ParseResult parseAffineMapOfSSAIds(AffineMap &map);
+ ParseResult parseAffineMapOfSSAIds(AffineMap &map,
+ OpAsmParser::Delimiter delimiter);
void getDimsAndSymbolSSAIds(SmallVectorImpl<StringRef> &dimAndSymbolSSAIds,
unsigned &numDims);
@@ -2917,9 +2919,24 @@ ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map,
}
/// Parse an AffineMap where the dim and symbol identifiers are SSA ids.
-ParseResult AffineParser::parseAffineMapOfSSAIds(AffineMap &map) {
- if (parseToken(Token::l_square, "expected '['"))
- return failure();
+ParseResult
+AffineParser::parseAffineMapOfSSAIds(AffineMap &map,
+ OpAsmParser::Delimiter delimiter) {
+ Token::Kind rightToken;
+ switch (delimiter) {
+ case OpAsmParser::Delimiter::Square:
+ if (parseToken(Token::l_square, "expected '['"))
+ return failure();
+ rightToken = Token::r_square;
+ break;
+ case OpAsmParser::Delimiter::Paren:
+ if (parseToken(Token::l_paren, "expected '('"))
+ return failure();
+ rightToken = Token::r_paren;
+ break;
+ default:
+ return emitError("unexpected delimiter");
+ }
SmallVector<AffineExpr, 4> exprs;
auto parseElt = [&]() -> ParseResult {
@@ -2931,7 +2948,7 @@ ParseResult AffineParser::parseAffineMapOfSSAIds(AffineMap &map) {
// Parse a multi-dimensional affine expression (a comma-separated list of
// 1-d affine expressions); the list cannot be empty. Grammar:
// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
- if (parseCommaSeparatedListUntil(Token::r_square, parseElt,
+ if (parseCommaSeparatedListUntil(rightToken, parseElt,
/*allowEmptyList=*/true))
return failure();
// Parsed a valid affine map.
@@ -3081,9 +3098,10 @@ ParseResult Parser::parseIntegerSetReference(IntegerSet &set) {
/// parse SSA value uses encountered while parsing affine expressions.
ParseResult
Parser::parseAffineMapOfSSAIds(AffineMap &map,
- function_ref<ParseResult(bool)> parseElement) {
+ function_ref<ParseResult(bool)> parseElement,
+ OpAsmParser::Delimiter delimiter) {
return AffineParser(state, /*allowParsingSSAIds=*/true, parseElement)
- .parseAffineMapOfSSAIds(map);
+ .parseAffineMapOfSSAIds(map, delimiter);
}
//===----------------------------------------------------------------------===//
@@ -4182,10 +4200,10 @@ class CustomOpAsmParser : public OpAsmParser {
}
/// Parse an AffineMap of SSA ids.
- ParseResult
- parseAffineMapOfSSAIds(SmallVectorImpl<OperandType> &operands,
- Attribute &mapAttr, StringRef attrName,
- SmallVectorImpl<NamedAttribute> &attrs) override {
+ ParseResult parseAffineMapOfSSAIds(SmallVectorImpl<OperandType> &operands,
+ Attribute &mapAttr, StringRef attrName,
+ SmallVectorImpl<NamedAttribute> &attrs,
+ Delimiter delimiter) override {
SmallVector<OperandType, 2> dimOperands;
SmallVector<OperandType, 1> symOperands;
@@ -4201,7 +4219,7 @@ class CustomOpAsmParser : public OpAsmParser {
};
AffineMap map;
- if (parser.parseAffineMapOfSSAIds(map, parseElement))
+ if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter))
return failure();
// Add AffineMap attribute.
if (map) {
diff --git a/mlir/test/AffineOps/invalid.mlir b/mlir/test/AffineOps/invalid.mlir
index 0a9fe862eddd..d6d3e93e38c9 100644
--- a/mlir/test/AffineOps/invalid.mlir
+++ b/mlir/test/AffineOps/invalid.mlir
@@ -197,4 +197,68 @@ func @affine_max(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = affine.max affine_map<(d0) -> (d0)> ()
return
-}
\ No newline at end of file
+}
+
+// -----
+
+// CHECK-LABEL: @affine_parallel
+func @affine_parallel(%arg0 : index, %arg1 : index, %arg2 : index) {
+ // expected-error at +1 {{region argument count and num results of upper bounds, lower bounds, and steps must all match}}
+ affine.parallel (%i) = (0, 0) to (100, 100) step (10, 10) {
+ }
+}
+
+// -----
+
+// CHECK-LABEL: @affine_parallel
+func @affine_parallel(%arg0 : index, %arg1 : index, %arg2 : index) {
+ // expected-error at +1 {{region argument count and num results of upper bounds, lower bounds, and steps must all match}}
+ affine.parallel (%i, %j) = (0) to (100, 100) step (10, 10) {
+ }
+}
+
+// -----
+
+// CHECK-LABEL: @affine_parallel
+func @affine_parallel(%arg0 : index, %arg1 : index, %arg2 : index) {
+ // expected-error at +1 {{region argument count and num results of upper bounds, lower bounds, and steps must all match}}
+ affine.parallel (%i, %j) = (0, 0) to (100) step (10, 10) {
+ }
+}
+
+// -----
+
+// CHECK-LABEL: @affine_parallel
+func @affine_parallel(%arg0 : index, %arg1 : index, %arg2 : index) {
+ // expected-error at +1 {{region argument count and num results of upper bounds, lower bounds, and steps must all match}}
+ affine.parallel (%i, %j) = (0, 0) to (100, 100) step (10) {
+ }
+}
+
+// -----
+
+// CHECK-LABEL: @affine_parallel
+
+func @affine_parallel(%arg0 : index, %arg1 : index, %arg2 : index) {
+ affine.for %x = 0 to 7 {
+ %y = addi %x, %x : index
+ // expected-error at +1 {{operand cannot be used as a dimension id}}
+ affine.parallel (%i, %j) = (0, 0) to (%y, 100) step (10, 10) {
+ }
+ }
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @affine_parallel
+
+func @affine_parallel(%arg0 : index, %arg1 : index, %arg2 : index) {
+ affine.for %x = 0 to 7 {
+ %y = addi %x, %x : index
+ // expected-error at +1 {{operand cannot be used as a symbol}}
+ affine.parallel (%i, %j) = (0, 0) to (symbol(%y), 100) step (10, 10) {
+ }
+ }
+ return
+}
diff --git a/mlir/test/AffineOps/ops.mlir b/mlir/test/AffineOps/ops.mlir
index c03852423411..c48da1da4759 100644
--- a/mlir/test/AffineOps/ops.mlir
+++ b/mlir/test/AffineOps/ops.mlir
@@ -112,3 +112,17 @@ func @valid_symbols(%arg0: index, %arg1: index, %arg2: index) {
}
return
}
+
+// -----
+
+// CHECK-LABEL: @parallel
+// CHECK-SAME: (%[[N:.*]]: index)
+func @parallel(%N : index) {
+ // CHECK: affine.parallel (%[[I0:.*]], %[[J0:.*]]) = (0, 0) to (symbol(%[[N]]), 100) step (10, 10)
+ affine.parallel (%i0, %j0) = (0, 0) to (symbol(%N), 100) step (10, 10) {
+ // CHECK-NEXT: affine.parallel (%{{.*}}, %{{.*}}) = (%[[I0]], %[[J0]]) to (%[[I0]] + 10, %[[J0]] + 10)
+ affine.parallel (%i1, %j1) = (%i0, %j0) to (%i0 + 10, %j0 + 10) {
+ }
+ }
+ return
+}
More information about the Mlir-commits
mailing list