Enzyme main
Loading...
Searching...
No Matches
EnzymeBatchPass.h
Go to the documentation of this file.
1#ifndef ENZYME_BATCH_PASS_H
2#define ENZYME_BATCH_PASS_H
3
4#include "Dialect/Ops.h"
6#include "PassDetails.h"
7#include "Passes/Passes.h"
8
9#include "mlir/Dialect/Func/IR/FuncOps.h"
10#include "mlir/IR/Builders.h"
11#include "mlir/Interfaces/FunctionInterfaces.h"
12
13namespace mlir {
14namespace enzyme {
15namespace batchutils {
16
18 FunctionOpInterface function;
19 SmallVector<int64_t> batchSizes;
20
21 bool operator<(const BatchCacheKey &other) const {
22 Operation *thisSymbolTable = SymbolTable::getNearestSymbolTable(function),
23 *otherSymbolTable =
24 SymbolTable::getNearestSymbolTable(other.function);
25 if (thisSymbolTable != otherSymbolTable)
26 return std::less<Operation *>()(thisSymbolTable, otherSymbolTable);
27
28 auto thisName = const_cast<FunctionOpInterface &>(function).getName(),
29 otherName =
30 const_cast<FunctionOpInterface &>(other.function).getName();
31 if (thisName != otherName)
32 return thisName < otherName;
33
34 return std::lexicographical_compare(batchSizes.begin(), batchSizes.end(),
35 other.batchSizes.begin(),
36 other.batchSizes.end());
37 }
38};
39
40mlir::TensorType applyBatchSizes(mlir::Type Ty,
41 llvm::ArrayRef<int64_t> batchSizes);
42
43FunctionOpInterface batchCloneFunction(
44 OpBuilder &builder, FunctionOpInterface F, Twine name,
45 llvm::ArrayRef<int64_t> batchSizes,
46 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache);
47
49 OpBuilder &builder, Block *blk, IRMapping &mapper,
50 llvm::ArrayRef<int64_t> batchSizes,
51 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache,
52 bool withoutTerminator);
53
55 OpBuilder &builder, Region *src, Region *dest, IRMapping &mapper,
56 llvm::ArrayRef<int64_t> batchSizes,
57 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache);
58
59LogicalResult handleCallOp(
60 func::CallOp callOp, OpBuilder &builder, IRMapping &mapper,
61 llvm::ArrayRef<int64_t> batchSizes,
62 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache);
63
64template <typename T>
65FunctionOpInterface batchOperationWithoutInsertingCallOp(
66 OpBuilder &builder, T CI, FunctionOpInterface fn,
67 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache);
68
69template <typename T>
70LogicalResult batchOperation(
71 SymbolTableCollection &symbolTable, OpBuilder &builder, T CI,
72 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache) {
73
74 auto *symbolOp = symbolTable.lookupNearestSymbolFrom(CI, CI.getFnAttr());
75 return batchOperation(builder, CI, cast<FunctionOpInterface>(symbolOp),
76 batchedFunctionCache);
77}
78
79template <typename T>
80LogicalResult batchOperation(
81 SymbolTableCollection &symbolTable, PatternRewriter &rewriter, T CI,
82 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache) {
83 auto *symbolOp = symbolTable.lookupNearestSymbolFrom(CI, CI.getFnAttr());
84 return batchOperation(rewriter, CI, cast<FunctionOpInterface>(symbolOp),
85 batchedFunctionCache);
86}
87
88template <typename T>
89LogicalResult batchOperation(
90 OpBuilder &builder, T CI, FunctionOpInterface fn,
91 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache) {
92 auto newFunc = batchOperationWithoutInsertingCallOp(builder, CI, fn,
93 batchedFunctionCache);
94
95 if (!newFunc)
96 return failure();
97
98 {
99 IRRewriter::InsertionGuard insertGuard(builder);
100 builder.setInsertionPoint(CI);
101 auto dCI = func::CallOp::create(builder, CI.getLoc(), newFunc.getName(),
102 newFunc.getResultTypes(), CI.getInputs());
103 CI.replaceAllUsesWith(dCI);
104 CI->erase();
105 }
106 return success();
107}
108
109template <typename T>
110LogicalResult batchOperation(
111 PatternRewriter &rewriter, T CI, FunctionOpInterface fn,
112 std::map<BatchCacheKey, FunctionOpInterface> &batchedFunctionCache) {
113 auto newFunc = batchOperationWithoutInsertingCallOp(rewriter, CI, fn,
114 batchedFunctionCache);
115
116 if (!newFunc)
117 return failure();
118
119 {
120 IRRewriter::InsertionGuard insertGuard(rewriter);
121 rewriter.setInsertionPoint(CI);
122 rewriter.replaceOpWithNewOp<func::CallOp>(
123 CI, newFunc.getName(), newFunc.getResultTypes(), CI.getInputs());
124 }
125 return success();
126}
127
128// instead of inserting a call op, we will inline each operation directly
129// into the caller
130inline void batchOperationInline(PatternRewriter &rewriter,
131 enzyme::BatchOp batchOp,
132 FunctionOpInterface func) {
133 auto &origRegion = func.getFunctionBody();
134 auto &origBlock = origRegion.front();
135
136 IRMapping mapper;
137 for (int i = 0; i < batchOp->getNumOperands(); i++) {
138 mapper.map(origBlock.getArguments()[i], batchOp->getOperand(i));
139 }
140
141 rewriter.setInsertionPoint(batchOp);
142 std::map<BatchCacheKey, FunctionOpInterface> batchedFunctionCache;
143 batchCloneBlock(rewriter, &origBlock, mapper, batchOp.getBatchShape(),
144 batchedFunctionCache, true);
145
146 auto origTerm = origBlock.getTerminator();
147 for (auto [i, operand] : llvm::enumerate(origTerm->getOperands())) {
148 auto mappedOperand = mapper.lookup(operand);
149 rewriter.replaceAllUsesWith(batchOp->getResult(i), mappedOperand);
150 }
151 rewriter.eraseOp(batchOp);
152 rewriter.eraseOp(func);
153}
154
155} // namespace batchutils
156} // namespace enzyme
157} // namespace mlir
158
159#endif // ENZYME_BATCH_PASS_H
FunctionOpInterface batchOperationWithoutInsertingCallOp(OpBuilder &builder, T CI, FunctionOpInterface fn, std::map< BatchCacheKey, FunctionOpInterface > &batchedFunctionCache)
LogicalResult batchOperation(SymbolTableCollection &symbolTable, OpBuilder &builder, T CI, std::map< BatchCacheKey, FunctionOpInterface > &batchedFunctionCache)
mlir::TensorType applyBatchSizes(mlir::Type Ty, llvm::ArrayRef< int64_t > batchSizes)
void batchOperationInline(PatternRewriter &rewriter, enzyme::BatchOp batchOp, FunctionOpInterface func)
FunctionOpInterface batchCloneFunction(OpBuilder &builder, FunctionOpInterface F, Twine name, llvm::ArrayRef< int64_t > batchSizes, std::map< BatchCacheKey, FunctionOpInterface > &batchedFunctionCache)
void batchCloneBlock(OpBuilder &builder, Block *blk, IRMapping &mapper, llvm::ArrayRef< int64_t > batchSizes, std::map< BatchCacheKey, FunctionOpInterface > &batchedFunctionCache, bool withoutTerminator)
LogicalResult handleCallOp(func::CallOp callOp, OpBuilder &builder, IRMapping &mapper, llvm::ArrayRef< int64_t > batchSizes, std::map< BatchCacheKey, FunctionOpInterface > &batchedFunctionCache)
void batchCloneRegion(OpBuilder &builder, Region *src, Region *dest, IRMapping &mapper, llvm::ArrayRef< int64_t > batchSizes, std::map< BatchCacheKey, FunctionOpInterface > &batchedFunctionCache)
bool operator<(const BatchCacheKey &other) const