[MLIR] Add support for empty IVs to affine.parallel

Allow support for specifying empty IVs in an `affine.parallel`.

For example:

```
affine.parallel () = () to () {
  affine.yield
}
```

Reviewed By: bondhugula, jbruestle

Differential Revision: https://reviews.llvm.org/D102895
This commit is contained in:
Frank Laub 2021-05-21 01:52:53 +00:00
parent 002f5e158d
commit b5c3f17e70
3 changed files with 35 additions and 25 deletions

View File

@ -601,14 +601,14 @@ def AffineParallelOp : Affine_Op<"parallel",
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.yield".
parallel band, defining zero or more 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.yield".
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.

View File

@ -2641,8 +2641,6 @@ void AffineParallelOp::build(OpBuilder &builder, OperationState &result,
ArrayRef<AffineMap> lbMaps, ValueRange lbArgs,
ArrayRef<AffineMap> ubMaps, ValueRange ubArgs,
ArrayRef<int64_t> steps) {
assert(!lbMaps.empty() && "expected the lower bound map to be non-empty");
assert(!ubMaps.empty() && "expected the upper bound map to be non-empty");
assert(llvm::all_of(lbMaps,
[lbMaps](AffineMap m) {
return m.getNumDims() == lbMaps[0].getNumDims() &&
@ -2657,12 +2655,14 @@ void AffineParallelOp::build(OpBuilder &builder, OperationState &result,
}) &&
"expected all upper bounds maps to have the same number of dimensions "
"and symbols");
assert(lbMaps[0].getNumInputs() == lbArgs.size() &&
"expected lower bound maps to have as many inputs as lower bound "
"operands");
assert(ubMaps[0].getNumInputs() == ubArgs.size() &&
"expected upper bound maps to have as many inputs as upper bound "
"operands");
assert(lbMaps.empty() ||
lbMaps[0].getNumInputs() == lbArgs.size() &&
"expected lower bound maps to have as many inputs as lower bound "
"operands");
assert(ubMaps.empty() ||
ubMaps[0].getNumInputs() == ubArgs.size() &&
"expected upper bound maps to have as many inputs as upper bound "
"operands");
result.addTypes(resultTypes);
@ -2676,8 +2676,10 @@ void AffineParallelOp::build(OpBuilder &builder, OperationState &result,
// Concatenates maps defined in the same input space (same dimensions and
// symbols), assumes there is at least one map.
auto concatMapsSameInput = [](ArrayRef<AffineMap> maps,
SmallVectorImpl<int32_t> &groups) {
auto concatMapsSameInput = [&builder](ArrayRef<AffineMap> maps,
SmallVectorImpl<int32_t> &groups) {
if (maps.empty())
return AffineMap::get(builder.getContext());
SmallVector<AffineExpr> exprs;
groups.reserve(groups.size() + maps.size());
exprs.reserve(maps.size());
@ -2685,7 +2687,6 @@ void AffineParallelOp::build(OpBuilder &builder, OperationState &result,
llvm::append_range(exprs, m.getResults());
groups.push_back(m.getNumResults());
}
assert(!maps.empty() && "expected a non-empty list of maps");
return AffineMap::get(maps[0].getNumDims(), maps[0].getNumSymbols(), exprs,
maps[0].getContext());
};
@ -2696,10 +2697,10 @@ void AffineParallelOp::build(OpBuilder &builder, OperationState &result,
AffineMap ubMap = concatMapsSameInput(ubMaps, ubGroups);
result.addAttribute(getLowerBoundsMapAttrName(), AffineMapAttr::get(lbMap));
result.addAttribute(getLowerBoundsGroupsAttrName(),
builder.getI32VectorAttr(lbGroups));
builder.getI32TensorAttr(lbGroups));
result.addAttribute(getUpperBoundsMapAttrName(), AffineMapAttr::get(ubMap));
result.addAttribute(getUpperBoundsGroupsAttrName(),
builder.getI32VectorAttr(ubGroups));
builder.getI32TensorAttr(ubGroups));
result.addAttribute(getStepsAttrName(), builder.getI64ArrayAttr(steps));
result.addOperands(lbArgs);
result.addOperands(ubArgs);
@ -2790,7 +2791,6 @@ OpBuilder AffineParallelOp::getBodyBuilder() {
void AffineParallelOp::setLowerBounds(ValueRange lbOperands, AffineMap map) {
assert(lbOperands.size() == map.getNumInputs() &&
"operands to map must match number of inputs");
assert(map.getNumResults() >= 1 && "bounds map has at least one result");
auto ubOperands = getUpperBoundsOperands();
@ -2804,7 +2804,6 @@ void AffineParallelOp::setLowerBounds(ValueRange lbOperands, AffineMap map) {
void AffineParallelOp::setUpperBounds(ValueRange ubOperands, AffineMap map) {
assert(ubOperands.size() == map.getNumInputs() &&
"operands to map must match number of inputs");
assert(map.getNumResults() >= 1 && "bounds map has at least one result");
SmallVector<Value, 4> newOperands(getLowerBoundsOperands());
newOperands.append(ubOperands.begin(), ubOperands.end());
@ -3062,7 +3061,7 @@ static ParseResult parseAffineMapWithMinMax(OpAsmParser &parser,
if (succeeded(parser.parseOptionalRParen())) {
result.addAttribute(
mapName, AffineMapAttr::get(parser.getBuilder().getEmptyAffineMap()));
result.addAttribute(groupsName, parser.getBuilder().getI32VectorAttr({}));
result.addAttribute(groupsName, parser.getBuilder().getI32TensorAttr({}));
return success();
}
@ -3134,7 +3133,7 @@ static ParseResult parseAffineMapWithMinMax(OpAsmParser &parser,
dimRplacements, symRepacements, dimOperands.size(), symOperands.size());
result.addAttribute(mapName, AffineMapAttr::get(flatMap));
result.addAttribute(groupsName, builder.getI32VectorAttr(numMapsPerGroup));
result.addAttribute(groupsName, builder.getI32TensorAttr(numMapsPerGroup));
return success();
}

View File

@ -184,6 +184,17 @@ func @parallel_min_max(%a: index, %b: index, %c: index, %d: index) {
// -----
// CHECK-LABEL: @parallel_no_ivs
func @parallel_no_ivs() {
// CHECK: affine.parallel () = () to ()
affine.parallel () = () to () {
affine.yield
}
return
}
// -----
// CHECK-LABEL: func @affine_if
func @affine_if() -> f32 {
// CHECK: %[[ZERO:.*]] = constant {{.*}} : f32