18#include "mlir/Dialect/SCF/IR/SCF.h"
19#include "mlir/IR/Matchers.h"
20#include "mlir/Interfaces/SideEffectInterfaces.h"
21#include "mlir/Interfaces/ViewLikeInterface.h"
22#include "mlir/Transforms/RegionUtils.h"
27#define GEN_PASS_DEF_SINKCHECKPOINTVIEWSPASS
28#include "Passes/Passes.h.inc"
34using namespace enzyme;
52static bool isCheckpointed(Operation *op) {
53 auto enable = op->getAttrOfType<BoolAttr>(
"enzyme.enable_checkpointing");
54 return enable && enable.getValue();
59static bool isSinkableView(Operation *op) {
60 return op && isa<ViewLikeOpInterface>(op) && isMemoryEffectFree(op) &&
61 op->getNumResults() == 1 && op->getNumRegions() == 0;
67static void sinkViewInto(Operation *loop, Operation *view) {
68 Value result = view->getResult(0);
70 for (Region ®ion : loop->getRegions()) {
75 bool used = llvm::any_of(result.getUses(), [&](OpOperand &use) {
76 return region.isAncestor(use.getOwner()->getParentRegion());
81 OpBuilder builder(®ion.front(), region.front().begin());
82 Operation *sunk = builder.clone(*view);
83 result.replaceUsesWithIf(sunk->getResult(0), [&](OpOperand &use) {
84 return use.getOwner() != sunk &&
85 region.isAncestor(use.getOwner()->getParentRegion());
93static void sinkCapturedViews(Operation *loop) {
98 SetVector<Value> captures;
99 getUsedValuesDefinedAbove(loop->getRegions(), captures);
101 for (Value capture : captures) {
104 if (!isa<ClonableTypeInterface>(capture.getType()))
107 Operation *def = capture.getDefiningOp();
108 if (!isSinkableView(def))
111 sinkViewInto(loop, def);
118struct SinkCheckpointViewsPass
119 :
public enzyme::impl::SinkCheckpointViewsPassBase<
120 SinkCheckpointViewsPass> {
121 using SinkCheckpointViewsPassBase::SinkCheckpointViewsPassBase;
123 void runOnOperation()
override {
124 SmallVector<Operation *> loops;
125 getOperation()->walk([&](LoopLikeOpInterface loop) {
126 if (isCheckpointed(loop))
127 loops.push_back(loop);
130 for (Operation *loop : loops)
131 sinkCapturedViews(loop);