14#include "mlir/Dialect/SCF/IR/SCF.h"
16#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
20#define GEN_PASS_DEF_SPLITMULTIRESULTSPASS
21#include "Passes/Passes.h.inc"
30static bool allComputedByPureOps(Operation *terminator) {
31 Block *parent = terminator->getBlock();
32 DenseSet<Value> visited;
33 visited.insert_range(terminator->getOperands());
34 SmallVector<Value> frontier(terminator->getOperands());
35 while (!frontier.empty()) {
36 Value curr = frontier.pop_back_val();
37 Operation *definingOp = curr.getDefiningOp();
38 if (!definingOp || definingOp->getBlock() != parent)
41 if (!mlir::isPure(definingOp))
44 for (Value operand : definingOp->getOperands()) {
45 if (!visited.contains(operand)) {
46 visited.insert(operand);
47 frontier.push_back(operand);
54struct SplitMultiIf :
public mlir::OpRewritePattern<scf::IfOp> {
55 using OpRewritePattern::OpRewritePattern;
57 LogicalResult matchAndRewrite(scf::IfOp ifOp,
58 PatternRewriter &rewriter)
const override {
59 if (ifOp.getNumResults() < 2)
61 if (llvm::all_of(ifOp.getResults(),
62 [](OpResult res) { return res.use_empty(); })) {
66 if (llvm::any_of(ifOp.getRegions(), [](Region *region) {
67 return llvm::any_of(region->getOps(), [](Operation &op) {
68 return op.getNumRegions() != 0;
74 if (!(allComputedByPureOps(ifOp.thenYield()) &&
75 allComputedByPureOps(ifOp.elseYield()))) {
79 for (OpResult ifRes : ifOp.getResults()) {
80 auto newIf = scf::IfOp::create(rewriter, ifOp.getLoc(), ifRes.getType(),
84 OpBuilder::InsertionGuard guard(rewriter);
85 for (
auto [oldReg, newReg] :
86 llvm::zip(ifOp.getRegions(), newIf.getRegions())) {
87 for (
auto &&[oldBlk, newBlk] : llvm::zip(*oldReg, *newReg)) {
88 rewriter.setInsertionPointToStart(&newBlk);
89 for (
auto &op : oldBlk.without_terminator()) {
90 if (mlir::isPure(&op))
91 rewriter.clone(op, map);
94 rewriter, ifOp.getLoc(),
96 oldBlk.getTerminator()->getOperand(ifRes.getResultNumber())));
99 rewriter.replaceAllUsesWith(ifRes, newIf.getResult(0));
105struct SplitMultiResultsPass
106 :
public enzyme::impl::SplitMultiResultsPassBase<SplitMultiResultsPass> {
107 void runOnOperation()
override {
108 RewritePatternSet patterns(&getContext());
109 patterns.insert<SplitMultiIf>(&getContext());
111 GreedyRewriteConfig config;
112 config.setRegionSimplificationLevel(GreedySimplifyRegionLevel::Normal);
113 (void)applyPatternsGreedily(getOperation(), std::move(patterns), config);