diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td --- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td +++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td @@ -601,14 +601,14 @@ 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. diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp --- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp +++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp @@ -2641,8 +2641,6 @@ ArrayRef lbMaps, ValueRange lbArgs, ArrayRef ubMaps, ValueRange ubArgs, ArrayRef 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 @@ }) && "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 @@ // Concatenates maps defined in the same input space (same dimensions and // symbols), assumes there is at least one map. - auto concatMapsSameInput = [](ArrayRef maps, - SmallVectorImpl &groups) { + auto concatMapsSameInput = [&builder](ArrayRef maps, + SmallVectorImpl &groups) { + if (maps.empty()) + return AffineMap::get(builder.getContext()); SmallVector exprs; groups.reserve(groups.size() + maps.size()); exprs.reserve(maps.size()); @@ -2685,7 +2687,6 @@ 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 @@ 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 @@ 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::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 newOperands(getLowerBoundsOperands()); newOperands.append(ubOperands.begin(), ubOperands.end()); @@ -3062,7 +3061,7 @@ 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 @@ 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(); } diff --git a/mlir/test/Dialect/Affine/ops.mlir b/mlir/test/Dialect/Affine/ops.mlir --- a/mlir/test/Dialect/Affine/ops.mlir +++ b/mlir/test/Dialect/Affine/ops.mlir @@ -184,6 +184,17 @@ // ----- +// 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