31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/TypeSwitch.h"
48 .Case([](arith::AddFOp op) {
return ReductionKind::Sum; })
49 .Case([](arith::MulFOp op) {
return ReductionKind::Product; })
51 .Case([](arith::MaximumFOp op) {
return ReductionKind::Max; })
52 .Case([](arith::MinimumFOp op) {
return ReductionKind::Min; })
54 .Case([](arith::AddIOp op) {
return ReductionKind::Sum; })
55 .Case([](arith::OrIOp op) {
return ReductionKind::BitwiseOr; })
56 .Case([](arith::XOrIOp op) {
return ReductionKind::BitwiseXor; })
57 .Case([](arith::AndIOp op) {
return ReductionKind::BitwiseAnd; })
67 .Case([](arith::MaxUIOp op) {
return ReductionKind::Max; })
68 .Case([](arith::MinUIOp op) {
return ReductionKind::Min; })
69 .Case([](arith::MaxSIOp op) {
return ReductionKind::Max; })
70 .Case([](arith::MinSIOp op) {
return ReductionKind::Min; })
71 .Case([](arith::MulIOp op) {
return ReductionKind::Product; })
72 .Default([](
Operation *op) {
return ReductionKind::Generic; });
78 if (!reducedValue || combinerOps.size() != 1) {
82 return combinerOps[0];
88 return ReductionKind::Generic;
90 [[maybe_unused]]
Type resultElementType =
91 llvm::cast<RankedTensorType>(op->getResult(0).getType()).getElementType();
95 assert(resultElementType == reductionOp.value()->getResult(0).getType());
102 for (
const Sharding &sharding : operandShardings) {
108 for (
const Sharding &sharding : resultShardings) {
126 LinalgOp op,
int operandNumber,
Value partitionedOperand,
130 builder, gridOp.getSymName(), reductionGridAxes);
132 Value isLeadProcess = arith::CmpIOp::create(
133 builder, builder.
getI1Type(), arith::CmpIPredicate::eq,
134 processLinearIndexInReductionGroup, zero);
135 scf::IfOp ifOp = scf::IfOp::create(builder, partitionedOperand.
getType(),
136 isLeadProcess,
true,
true);
141 scf::YieldOp::create(builder, partitionedOperand);
152 matchReduction(op.getRegionOutputArgs(), operandNumber, combinerOps);
153 assert(combinerOps.size() == 1);
154 std::optional<TypedAttr> neutralEl =
157 Value init = tensor::EmptyOp::create(builder, op.getLoc(),
shape,
158 neutralEl.value().getType());
160 arith::ConstantOp::create(builder, op.getLoc(), neutralEl.value());
161 Value fill = linalg::FillOp::create(builder, op.getLoc(), constant, init)
164 scf::YieldOp::create(builder, fill);
166 return ifOp.getResult(0);
177 assert(op.getNumDpsInits() == 1 &&
"Multiple initial values not supported.");
179 auto operandIdx = op.getDpsInitOperand(0)->getOperandNumber();
180 Value partitionedInitOperand =
181 partitionMap.
lookup(op->getOperands()[operandIdx]);
183 op, 0, partitionedInitOperand, reductionGridAxes, gridOp, builder);
192 for (
auto [unshardedLinalgOpResult, resultSharding] :
193 llvm::zip_equal(unshardedOp->getResults(), resultShardings)) {
194 Value partitionedLinalgOpResult =
195 partitionMap.
lookup(unshardedLinalgOpResult);
196 Value reducedValue = shard::AllReduceOp::create(
197 builder, partitionedLinalgOpResult, resultSharding.getGrid(),
198 opReductionGridAxes, reductionKind);
199 partitionMap.
map(unshardedLinalgOpResult, reducedValue);
210 GridOp grid =
getGrid(op, operandShardings, resultShardings, symbolTable);
212 loopIteratorTypes, gridAxisAssignmentForLoopIterators);
215 reductionGridAxes, partitionMap,
221 for (
auto [unshardedOperand, partitionedOperand] :
222 llvm::zip_equal(op->getOperands(), partitionedLinalgOpOperands)) {
223 internalPartitionMap.
map(unshardedOperand, partitionedOperand);
225 partitionTriviallyShardableOperation(
226 *op, partitionedLinalgOpOperands, operandShardings, resultShardings,
227 internalPartitionMap, symbolTable, builder);
234 op, reductionGridAxes, resultShardings, partitionMap, builder);
241template <
typename Op>
242struct StructuredOpShardingInterface
243 :
public shard::ShardingInterface::ExternalModel<
244 StructuredOpShardingInterface<Op>, Op> {
246 return llvm::cast<LinalgOp>(op).getIteratorTypesArray();
249 SmallVector<AffineMap> getIndexingMaps(Operation *op)
const {
250 LinalgOp linalgOp = llvm::cast<LinalgOp>(op);
251 SmallVector<AffineMap> res = linalgOp.getIndexingMapsArray();
255 for (
int64_t i = 0; i < linalgOp.getNumDpsInits(); ++i) {
256 res.push_back(res[linalgOp.getDpsInitOperand(i)->getOperandNumber()]);
262 SmallVector<ReductionKind>
263 getReductionLoopIteratorKinds(Operation *op)
const {
264 LinalgOp linalgOp = llvm::cast<LinalgOp>(op);
265 SmallVector<utils::IteratorType> iteratorTypes =
266 linalgOp.getIteratorTypesArray();
267 unsigned reductionItersCount = llvm::accumulate(
268 iteratorTypes, 0u, [](
unsigned count, utils::IteratorType iter) {
269 return count + (iter == utils::IteratorType::reduction);
272 return SmallVector<ReductionKind>(reductionItersCount, reductionKind);
275 LogicalResult partition(Operation *op, ArrayRef<Value> partitionedOperands,
276 ArrayRef<Sharding> operandShardings,
277 ArrayRef<Sharding> resultShardings,
278 IRMapping &partitionMap,
279 SymbolTableCollection &symbolTable,
280 OpBuilder &builder)
const {
281 LinalgOp linalgOp = llvm::cast<LinalgOp>(op);
283 SmallVector<AffineMap> indexingMaps = linalgOp.getIndexingMapsArray();
284 bool allIndexingMapsAreProjectedPermutation =
285 llvm::all_of(indexingMaps, [](AffineMap map) {
286 return map.isProjectedPermutation();
288 if (!allIndexingMapsAreProjectedPermutation) {
290 return op->emitOpError()
291 <<
"supports indexing maps that are only projected permutation.";
294 SmallVector<utils::IteratorType> loopIteratorTypes =
295 linalgOp.getIteratorTypesArray();
298 loopIteratorTypes, indexingMaps);
300 loopIteratorTypes, gridAxisAssignmentForLoopIterators)) {
301 ImplicitLocOpBuilder implicitLocBuilder(op->getLoc(), builder);
303 linalgOp, partitionedOperands, operandShardings, resultShardings,
304 loopIteratorTypes, gridAxisAssignmentForLoopIterators, partitionMap,
305 symbolTable, implicitLocBuilder);
308 operandShardings, resultShardings,
309 partitionMap, symbolTable, builder);
317template <
typename OpType>
319 OpType::template attachInterface<StructuredOpShardingInterface<OpType>>(*ctx);
323template <
typename... OpTypes>
331 registry.
insert<affine::AffineDialect, arith::ArithDialect, scf::SCFDialect,
332 tensor::TensorDialect>();
340#include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc"
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
SmallVector< StringRef > getRegisteredDialectNames() const
Return the names of dialects registered in this registry with an allocator function.
This is a utility class for mapping one set of IR entities to another.
auto lookup(T from) const
Lookup a mapped value within the map.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
ImplicitLocOpBuilder maintains a 'current location', allowing use of the create<> method without spec...
Location getLoc() const
Accessors for the implied location.
MLIRContext is the top-level object for a collection of MLIR operations.
void appendDialectRegistry(const DialectRegistry ®istry)
Append the contents of the given dialect registry to the registry associated with this context.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
RAII guard to reset the insertion point of the builder when destroyed.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Operation is the basic unit of execution within MLIR.
This class represents a collection of SymbolTables.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
std::optional< TypedAttr > getNeutralElement(Operation *op)
Return the identity numeric value associated to the give op.
static std::optional< Operation * > getCombinerOp(LinalgOp op)
static void partitionLinalgOpWithShardedReduction(LinalgOp op, ArrayRef< Value > partitionedOperands, ArrayRef< Sharding > operandShardings, ArrayRef< Sharding > resultShardings, ArrayRef< utils::IteratorType > loopIteratorTypes, ArrayRef< SmallVector< GridAxis > > gridAxisAssignmentForLoopIterators, IRMapping &partitionMap, SymbolTableCollection &symbolTable, ImplicitLocOpBuilder &builder)
static ReductionKind getReductionKind(Operation *op)
shard::ShardingArray ShardingArray
static Value createDestinationPassingStyleInitOperand(LinalgOp op, int operandNumber, Value partitionedOperand, ArrayRef< GridAxis > reductionGridAxes, GridOp gridOp, ImplicitLocOpBuilder &builder)
static void createAllReduceForResultsWithoutPartialShardings(LinalgOp unshardedOp, ArrayRef< GridAxis > opReductionGridAxes, ArrayRef< Sharding > resultShardings, IRMapping &partitionMap, ImplicitLocOpBuilder &builder)
static void registerOne(MLIRContext *ctx)
static void registerAll(MLIRContext *ctx)
Variadic helper function.
shard::ReductionKind ReductionKind
static SmallVector< Value > createDestinationPassingStyleInitOperands(LinalgOp op, GridOp gridOp, ArrayRef< Value > partitionedOperands, ArrayRef< GridAxis > reductionGridAxes, IRMapping &partitionMap, ImplicitLocOpBuilder &builder)
void registerShardingInterfaceExternalModels(DialectRegistry ®istry)
static ReductionKind getReductionKindOfLinalgOp(LinalgOp op)
static GridOp getGrid(Operation *op, ArrayRef< Sharding > operandShardings, ArrayRef< Sharding > resultShardings, SymbolTableCollection &symbolTable)
bool isAtLeastOneReductionIteratorSharded(ArrayRef< utils::IteratorType > loopIteratorTypes, ArrayRef< SmallVector< GridAxis > > gridAxisAssignmentForLoopIterators)
void partitionTriviallyShardableOperation(Operation &op, ArrayRef< Value > partitionedOperands, ArrayRef< Sharding > operandShardings, ArrayRef< Sharding > resultShardings, IRMapping &partitionMap, SymbolTableCollection &symbolTable, OpBuilder &builder)
TypedValue< IndexType > createProcessLinearIndex(ImplicitLocOpBuilder &builder, StringRef grid, ArrayRef< GridAxis > gridAxes={})
SmallVector< GridAxis > getReductionGridAxes(ArrayRef< utils::IteratorType > loopIteratorTypes, ArrayRef< SmallVector< GridAxis > > gridAxisAssignmentForLoopIterators)
shard::GridOp getGrid(Operation *op, FlatSymbolRefAttr gridSymbol, SymbolTableCollection &symbolTableCollection)
ShardingArray getGridAxisAssignmentForLoopIterators(ArrayRef< Sharding > operandShardings, ArrayRef< Sharding > resultShardings, ArrayRef< utils::IteratorType > loopIteratorTypes, ArrayRef< AffineMap > indexingMaps)
SmallVector< SmallVector< GridAxis > > ShardingArray
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given tensor value.
Value matchReduction(ArrayRef< BlockArgument > iterCarriedArgs, unsigned redPos, SmallVectorImpl< Operation * > &combinerOps)
Utility to match a generic reduction given a list of iteration-carried arguments, iterCarriedArgs and...