[Mlir-commits] [mlir] [mlir][mesh] Add endomorphism simplification for all-reduce (PR #73150)
Mehdi Amini
llvmlistbot at llvm.org
Wed Dec 6 20:52:33 PST 2023
================
@@ -0,0 +1,163 @@
+//===- RegionUtils.h - Region-related transformation utilities --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_TRANSFORMS_SIMPLIFY_ENDOMORPHISM_H_
+#define MLIR_TRANSFORMS_SIMPLIFY_ENDOMORPHISM_H_
+
+#include "mlir/IR/IRMapping.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/Value.h"
+#include "mlir/Support/LLVM.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
+#include <iterator>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+#include "mlir/Dialect/Mesh/IR/MeshOps.h"
+#include "mlir/Support/LogicalResult.h"
+
+namespace mlir {
+
+// If `f` is an endomorphism with respect to the algebraic structure induced by
+// function `g`, transforms `g(f(x1), f(x2) ..., f(xn))` into
+// `f(g(x1, x2, ..., xn))`.
+// `g` is the algebraic operation and `f` is the endomorphism.
+//
+// Functors:
+// ---------
+// `GetEndomorphismOpOperandFn`: `(Operation*) -> OpOperand*`
+// Returns the operand relevant to the endomorphism.
+// There may be other operands that are not relevant.
+//
+// `GetEndomorphismOpResultFn`: `(Operation*) -> OpResult`
+// Returns the result relevant to the endomorphism.
+//
+// `GetAlgebraicOpOperandsFn`: `(Operation*, SmallVector<OpOperand*>&) -> void`
+// Populates into the vector the operands relevant to the endomorphism.
+//
+// `GetAlgebraicOpResultFn`: `(Operation*) -> OpResult`
+// Return the result relevant to the endomorphism.
+//
+// `IsEndomorphismOpFn`: `(Operation*, std::optional<Operation*>) -> bool`
+// Check if the operation is an endomorphism of the required type.
+// Additionally if the optional is present checks if the operations are
+// compatible endomorphisms.
+//
+// `IsAlgebraicOpFn`: `(Operation*) -> bool`
+// Check if the operation is an operation of the algebraic structure.
+template <typename GetEndomorphismOpOperandFn,
+ typename GetEndomorphismOpResultFn, typename GetAlgebraicOpOperandsFn,
+ typename GetAlgebraicOpResultFn, typename IsEndomorphismOpFn,
+ typename IsAlgebraicOpFn>
+struct EndomorphismSimplification : RewritePattern {
+ template <typename GetEndomorphismOpOperandFnArg,
+ typename GetEndomorphismOpResultFnArg,
+ typename GetAlgebraicOpOperandsFnArg,
+ typename GetAlgebraicOpResultFnArg, typename IsEndomorphismOpFnArg,
+ typename IsAlgebraicOpFnArg, typename... RewritePatternArgs>
+ EndomorphismSimplification(
+ GetEndomorphismOpOperandFnArg &&getEndomorphismOpOperand,
+ GetEndomorphismOpResultFnArg &&getEndomorphismOpResult,
+ GetAlgebraicOpOperandsFnArg &&getAlgebraicOpOperands,
+ GetAlgebraicOpResultFnArg &&getAlgebraicOpResult,
+ IsEndomorphismOpFnArg &&isEndomorphismOp,
+ IsAlgebraicOpFnArg &&isAlgebraicOp, RewritePatternArgs &&...args)
+ : RewritePattern(std::forward<RewritePatternArgs>(args)...),
+ getEndomorphismOpOperand(std::forward<GetEndomorphismOpOperandFnArg>(
+ getEndomorphismOpOperand)),
+ getEndomorphismOpResult(std::forward<GetEndomorphismOpResultFnArg>(
+ getEndomorphismOpResult)),
+ getAlgebraicOpOperands(
+ std::forward<GetAlgebraicOpOperandsFnArg>(getAlgebraicOpOperands)),
+ getAlgebraicOpResult(
+ std::forward<GetAlgebraicOpResultFnArg>(getAlgebraicOpResult)),
+ isEndomorphismOp(std::forward<IsEndomorphismOpFnArg>(isEndomorphismOp)),
+ isAlgebraicOp(std::forward<IsAlgebraicOpFnArg>(isAlgebraicOp)) {}
+
+ LogicalResult matchAndRewrite(Operation *op,
+ PatternRewriter &rewriter) const override {
+ if (failed(matchOp(op, algebraicOpOperands))) {
+ return failure();
+ }
+ return rewriteOp(op, algebraicOpOperands, rewriter);
+ }
+
+private:
+ LogicalResult matchOp(Operation *algebraicOp,
+ SmallVector<OpOperand *> &algebraicOpOperands) const {
+ if (!isAlgebraicOp(algebraicOp)) {
+ return failure();
+ }
+ algebraicOpOperands.clear();
+ getAlgebraicOpOperands(algebraicOp, algebraicOpOperands);
+ if (algebraicOpOperands.empty()) {
+ return failure();
+ }
+
+ Operation *firstEndomorphismOp =
+ algebraicOpOperands.front()->get().getDefiningOp();
+ if (!firstEndomorphismOp ||
+ !isEndomorphismOp(firstEndomorphismOp, std::nullopt)) {
+ return failure();
+ }
+ OpResult firstEndomorphismOpResult =
+ getEndomorphismOpResult(firstEndomorphismOp);
+ if (getEndomorphismOpResult(firstEndomorphismOp) !=
+ algebraicOpOperands.front()->get()) {
+ return failure();
+ }
+
+ for (auto operand : algebraicOpOperands) {
+ Operation *endomorphismOp = operand->get().getDefiningOp();
+ if (!endomorphismOp ||
+ !isEndomorphismOp(endomorphismOp, firstEndomorphismOp)) {
+ return failure();
+ }
+ }
+ return success();
+ }
+
+ LogicalResult rewriteOp(Operation *algebraicOp,
+ const SmallVector<OpOperand *> &algebraicOpOperands,
+ PatternRewriter &rewriter) const {
+ irMapping.clear();
+ for (auto operand : algebraicOpOperands) {
+ Operation *endomorphismOp = operand->get().getDefiningOp();
+ irMapping.map(operand->get(),
+ getEndomorphismOpOperand(endomorphismOp)->get());
+ }
+ Operation *newAlgebraicOp = rewriter.clone(*algebraicOp, irMapping);
+
+ irMapping.clear();
+ assert(!algebraicOpOperands.empty());
+ Operation *firstEndomorphismOp =
+ algebraicOpOperands[0]->get().getDefiningOp();
+ irMapping.map(getEndomorphismOpOperand(firstEndomorphismOp)->get(),
+ getAlgebraicOpResult(newAlgebraicOp));
+ Operation *newEndomorphismOp =
+ rewriter.clone(*firstEndomorphismOp, irMapping);
+ rewriter.replaceAllUsesWith(getAlgebraicOpResult(algebraicOp),
+ getEndomorphismOpResult(newEndomorphismOp));
+ return success();
+ }
+
+ GetEndomorphismOpOperandFn getEndomorphismOpOperand;
+ GetEndomorphismOpResultFn getEndomorphismOpResult;
+ GetAlgebraicOpOperandsFn getAlgebraicOpOperands;
+ GetAlgebraicOpResultFn getAlgebraicOpResult;
+ IsEndomorphismOpFn isEndomorphismOp;
+ IsAlgebraicOpFn isAlgebraicOp;
+ mutable SmallVector<OpOperand *> algebraicOpOperands;
+ mutable IRMapping irMapping;
----------------
joker-eph wrote:
No threading issue in patterns.
https://github.com/llvm/llvm-project/pull/73150
More information about the Mlir-commits
mailing list