18#include "mlir/Dialect/Arith/IR/Arith.h"
19#include "mlir/Dialect/GPU/IR/GPUDialect.h"
20#include "mlir/Dialect/MemRef/IR/MemRef.h"
26#define GEN_PASS_DEF_FLATTENENZYMECACHESPASS
27#include "Passes/Passes.h.inc"
35Type flattenType(Type oldType, OpBuilder &builder) {
36 if (
auto memrefType = dyn_cast<MemRefType>(oldType)) {
37 return MemRefType::get({ShapedType::kDynamic},
38 flattenType(memrefType.getElementType(), builder),
39 builder.getDimIdentityMap(),
40 memrefType.getMemorySpace());
45Value createFlatAlloc(MemRefType oldType,
46 enzyme::MultidimensionalAllocInterface allocOp,
47 ImplicitLocOpBuilder &builder) {
48 auto newType = cast<MemRefType>(flattenType(oldType, builder));
52 SmallVector<Value> dynamicDims;
53 allocOp.appendDynamicDims(dynamicDims);
56 for (
unsigned dim = 0; dim < oldType.getRank(); dim++) {
58 if (oldType.getDimSize(dim) == ShapedType::kDynamic) {
59 bound = dynamicDims[opidx];
62 bound = arith::ConstantIndexOp::create(builder, oldType.getDimSize(dim));
64 if (size ==
nullptr) {
67 size = arith::MulIOp::create(builder, size, bound);
71 if (size ==
nullptr) {
72 size = arith::ConstantIndexOp::create(builder, 0);
75 return allocOp.allocate(builder, builder.getLoc(), newType, size);
78Value computeFlatIndex(ValueRange indices, ValueRange dynamicSizes,
79 ArrayRef<int64_t> oldShape,
80 ImplicitLocOpBuilder &builder) {
81 if (oldShape.size() == 0) {
82 return arith::ConstantIndexOp::create(builder, 0);
88 Value flatIndex = indices[0];
89 int64_t dynamicIndex = 0;
90 if (oldShape[0] == ShapedType::kDynamic) {
94 for (int64_t dim = 1; dim < oldShape.size(); dim++) {
96 if (oldShape[dim] == ShapedType::kDynamic) {
97 bound = dynamicSizes[dynamicIndex];
100 bound = arith::ConstantIndexOp::create(builder, oldShape[dim]);
103 flatIndex = arith::MulIOp::create(builder, flatIndex, bound);
105 flatIndex = arith::AddIOp::create(builder, flatIndex, indices[dim]);
111struct FlattenEnzymeCaches
112 :
public enzyme::impl::FlattenEnzymeCachesPassBase<FlattenEnzymeCaches> {
113 void runOnOperation()
override {
114 SetVector<enzyme::MultidimensionalAllocInterface> allocations;
115 getOperation()->walk([&allocations](enzyme::StoreOp storeOp) {
116 Operation *alloc = storeOp.getMemref().getDefiningOp();
120 MemRefType oldType = storeOp.getMemref().getType();
121 if (oldType.getRank() <= 1)
125 dyn_cast<enzyme::MultidimensionalAllocInterface>(alloc)) {
126 allocations.insert(allocOp);
130 for (
auto alloc : llvm::make_early_inc_range(allocations)) {
131 auto oldType = cast<MemRefType>(alloc->getResultTypes().front());
132 ImplicitLocOpBuilder abuilder(alloc->getLoc(), alloc);
133 Value flatAlloc = createFlatAlloc(oldType, alloc, abuilder);
134 alloc->replaceAllUsesWith(ValueRange(flatAlloc));
139 getOperation()->walk([](enzyme::StoreOp storeOp) {
140 ImplicitLocOpBuilder sbuilder(storeOp.getLoc(), storeOp);
142 computeFlatIndex(storeOp.getIndices(), storeOp.getSizes(),
143 storeOp.getStaticSizes(), sbuilder);
144 memref::StoreOp::create(sbuilder, storeOp.getValue(), storeOp.getMemref(),
150 getOperation()->walk([](enzyme::LoadOp loadOp) {
151 ImplicitLocOpBuilder lbuilder(loadOp.getLoc(), loadOp);
152 Value flatIndex = computeFlatIndex(loadOp.getIndices(), loadOp.getSizes(),
153 loadOp.getStaticSizes(), lbuilder);
155 memref::LoadOp::create(lbuilder, loadOp.getMemref(), flatIndex);
156 loadOp.replaceAllUsesWith(flatLoad.getResult());