[Mlir-commits] [mlir] [mlir][shard, mpi] Allowing 2d-grids and simplifying lowering shard.all_gather (PR #180243)
Rolf Morel
llvmlistbot at llvm.org
Mon Feb 9 09:48:17 PST 2026
================
@@ -635,104 +634,124 @@ struct ConvertAllGatherOp : public CommOpPattern<AllGatherOp> {
FailureOr<GridOp> gridOp = checkGrid(op, symbolTableCollection);
if (failed(gridOp))
return failure();
- ImplicitLocOpBuilder iBuilder(op.getLoc(), rewriter);
- Value input = getAsMemref(adaptor.getInput(), iBuilder);
+
+ ImplicitLocOpBuilder ib(op.getLoc(), rewriter);
+ Value input = getAsMemref(adaptor.getInput(), ib);
MemRefType inType = cast<MemRefType>(input.getType());
- if (!memref::isStaticShapeAndContiguousRowMajor(inType))
- return op.emitError(
- "Expected static shaped memref in contiguous row-major layout.");
MemRefType outType = getMemrefType(cast<ShapedType>(op.getType()));
- if (!memref::isStaticShapeAndContiguousRowMajor(outType))
- return op.emitError(
- "Expected static shaped memref in contiguous row-major layout.");
+ auto inputShape = inType.getShape();
+ auto outputShape = outType.getShape();
int64_t gatherAxis = adaptor.getGatherAxisAttr().getInt();
- auto ctx = op->getContext();
-
- // Get the right communicator
- Value comm = getComm(*gridOp, adaptor.getGridAxes(), iBuilder);
-
- Value nRanks =
- mpi::CommSizeOp::create(iBuilder, iBuilder.getI32Type(), comm)
- .getSize();
- nRanks =
- arith::IndexCastOp::create(iBuilder, iBuilder.getIndexType(), nRanks);
-
- Value tmpOutput, gatherDimSz;
- if (gatherAxis == 0) {
- tmpOutput = memref::AllocOp::create(iBuilder, outType);
- } else {
- // MPI's allgather always concatenates along the first dimension.
- // Create a memref type for the output buffer with adjusted (expanded)
- // shape.
- SmallVector<int64_t> gatherShape(1, ShapedType::kDynamic);
- llvm::append_range(gatherShape, outType.getShape());
- gatherShape[gatherAxis + 1] = ShapedType::kDynamic;
- MemRefType gatherType =
- MemRefType::get(gatherShape, outType.getElementType());
- gatherDimSz = arith::ConstantIndexOp::create(
- iBuilder, outType.getDimSize(gatherAxis));
- gatherDimSz = arith::DivSIOp::create(iBuilder, iBuilder.getIndexType(),
- gatherDimSz, nRanks);
- // Allocate output buffer
- tmpOutput =
- memref::AllocOp::create(iBuilder, gatherType, {nRanks, gatherDimSz});
+ int64_t inputDimOnAxis = inputShape[gatherAxis];
+ int64_t outputDimOnAxis = outputShape[gatherAxis];
+
+ for (size_t i = 0; i < outputShape.size(); ++i)
+ if (outputShape[i] != inputShape[i] && i != (size_t)gatherAxis)
+ return op.emitError(
+ "Result and input shapes must match along non-gather axes.");
+ if (inputDimOnAxis == 0)
+ return op.emitError("Input size along the gather axis must be non-zero.");
+ if (inputDimOnAxis == 1) {
+ assert(outputDimOnAxis == inputDimOnAxis);
+ rewriter.replaceOp(op, adaptor.getInput());
+ return success();
}
+ if (outputDimOnAxis % inputDimOnAxis != 0)
+ return op.emitError("Result size along the gather axis must be an exact "
+ "multiple of the input size along the gather axis.");
+
+ if (!memref::isStaticShapeAndContiguousRowMajor(inType) ||
+ !memref::isStaticShapeAndContiguousRowMajor(outType))
+ return op.emitError("Input/result must be statically shaped memrefs in "
+ "contiguous row-major layout.");
+
+ // Get the right communicator.
+ Value comm = getComm(*gridOp, adaptor.getGridAxes(), ib);
+ Value nRanksV =
+ mpi::CommSizeOp::create(ib, ib.getI32Type(), comm).getSize();
+ nRanksV = arith::IndexCastOp::create(ib, ib.getIndexType(), nRanksV);
+ int64_t nRanks = outputDimOnAxis / inputDimOnAxis;
+ Value nRanksC = arith::ConstantIndexOp::create(ib, nRanks);
+ Value notError =
+ arith::CmpIOp::create(ib, arith::CmpIPredicate::eq, nRanksV, nRanksC);
+ cf::AssertOp::create(ib, notError,
+ "Expected number of ranks in the communicator to "
+ "match the output size along the gather axis divided "
+ "by the input size along the gather axis.");
+
+ // mpi.allgather always concatenates along the first dimension, so
+ // get a output buffer of shape {nRanks, dim0, ...}.
+ SmallVector<int64_t> gatherShape;
+ gatherShape.emplace_back(nRanks);
+ gatherShape.append(inputShape.begin(), inputShape.end());
+ auto gatherType = MemRefType::get(gatherShape, outType.getElementType());
+ Value finalOutput = memref::AllocOp::create(ib, gatherType);
// Create the MPI AllGather operation.
- mpi::AllGatherOp::create(iBuilder, TypeRange(), input, tmpOutput, comm);
-
- // If gather-axis!=0, copy from gathered buffer to output with the right
- // layout.
- Value finalOutput = tmpOutput;
- if (gatherAxis != 0) {
- int64_t nSrcDims = cast<ShapedType>(tmpOutput.getType()).getRank();
- assert(nSrcDims == outType.getRank() + 1 &&
- "Expected gathered type to have rank one more than output type.");
-
- // Create affine map for copying from gathered buffer to output.
- SmallVector<AffineExpr> dims;
- dims.reserve(nSrcDims);
- for (unsigned i = 0; i < nSrcDims; ++i)
- dims.emplace_back(getAffineDimExpr(i, ctx));
- AffineExpr s = getAffineSymbolExpr(0, ctx);
- SmallVector<AffineExpr> results;
- results.reserve(nSrcDims);
- for (unsigned i = 0; i < nSrcDims - 1; ++i) {
- if (i == gatherAxis)
- results.emplace_back(dims[0] * s + dims[gatherAxis + 1]);
- else
- results.emplace_back(dims[i + 1]);
+ mpi::AllGatherOp::create(ib, TypeRange(), input, finalOutput, comm);
+
+ if (gatherAxis == 0) {
+ // If gather axis == 0, simply collapse the first 2 dims from {nRanks,
+ // dim0, ...} to {nRanks*dim0, ...}.
+ SmallVector<ReassociationIndices> reassociation;
+ reassociation.push_back({0, 1});
+ for (int64_t i = 2; i < (int64_t)gatherShape.size(); ++i) {
+ reassociation.push_back({i});
}
----------------
rolfmorel wrote:
```suggestion
int64_t numGatherDims = gatherShape.size();
for (int64_t i = 2; i < numGatherDims; ++i)
reassociation.push_back({i});
```
Nit: per the style guide.
https://github.com/llvm/llvm-project/pull/180243
More information about the Mlir-commits
mailing list