16#include "mlir/Dialect/Arith/IR/Arith.h"
17#include "mlir/Dialect/SCF/IR/SCF.h"
18#include "mlir/IR/Matchers.h"
22#define GEN_PASS_DEF_LOWERBINOMIALPROGRESSPASS
23#include "Passes/Passes.h.inc"
65 int64_t t = 0, beta = 1;
68 beta = beta * (s + t) / t;
70 int64_t lo = n - beta * s / (s + t);
71 int64_t hi = beta * t / (s + t);
76 int64_t m = (lo + hi) / 2;
77 int64_t cap = n - (s - 1);
83static void lowerBinomialProgress(enzyme::BinomialProgressOp op) {
86 if (isa<TensorType>(op.getType()))
89 OpBuilder builder(op);
90 Location loc = op.getLoc();
91 Value n = op.getNumSteps();
92 Value s = op.getBudget();
93 Type idxTy = op.getType();
94 auto constOfType = [&](int64_t v) -> Value {
95 return arith::ConstantOp::create(builder, loc,
96 builder.getIntegerAttr(idxTy, v));
100 llvm::APInt nCst, sCst;
101 if (matchPattern(n, m_ConstantInt(&nCst)) &&
102 matchPattern(s, m_ConstantInt(&sCst)) && nCst.getSExtValue() > 0 &&
103 sCst.getSExtValue() > 0) {
106 op.getResult().replaceAllUsesWith(c);
111 Value zero = constOfType(0);
112 Value one = constOfType(1);
117 arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::sle, n, one);
119 arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::sle, s, one);
120 Value cond = arith::OrIOp::create(builder, loc, nSmall, sSmall);
122 auto ifOp = scf::IfOp::create(builder, loc, TypeRange{idxTy}, cond,
126 OpBuilder::InsertionGuard guard(builder);
127 builder.setInsertionPointToStart(ifOp.thenBlock());
130 scf::YieldOp::create(builder, loc, ValueRange{n});
134 OpBuilder::InsertionGuard guard(builder);
135 builder.setInsertionPointToStart(ifOp.elseBlock());
138 auto whileOp = scf::WhileOp::create(builder, loc, TypeRange{idxTy, idxTy},
139 ValueRange{zero, one});
143 Block *before = builder.createBlock(&whileOp.getBefore(), {},
144 TypeRange{idxTy, idxTy}, {loc, loc});
145 builder.setInsertionPointToEnd(before);
146 Value beta = before->getArgument(1);
147 Value lt = arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::slt,
149 scf::ConditionOp::create(builder, loc, lt, before->getArguments());
155 Block *after = builder.createBlock(&whileOp.getAfter(), {},
156 TypeRange{idxTy, idxTy}, {loc, loc});
157 builder.setInsertionPointToEnd(after);
158 Value t = after->getArgument(0);
159 Value beta = after->getArgument(1);
160 Value t2 = arith::AddIOp::create(builder, loc, t, one);
161 Value sPlusT = arith::AddIOp::create(builder, loc, s, t2);
162 Value num = arith::MulIOp::create(builder, loc, beta, sPlusT);
163 Value beta2 = arith::DivUIOp::create(builder, loc, num, t2);
164 scf::YieldOp::create(builder, loc, ValueRange{t2, beta2});
167 builder.setInsertionPointAfter(whileOp);
168 Value t = whileOp.getResult(0);
169 Value beta = whileOp.getResult(1);
177 Value sPlusT = arith::AddIOp::create(builder, loc, s, t);
178 Value loNum = arith::MulIOp::create(builder, loc, beta, s);
179 Value loRaw = arith::SubIOp::create(
180 builder, loc, n, arith::DivUIOp::create(builder, loc, loNum, sPlusT));
181 Value hiNum = arith::MulIOp::create(builder, loc, beta, t);
182 Value hiRaw = arith::DivUIOp::create(builder, loc, hiNum, sPlusT);
184 Value nm1 = arith::SubIOp::create(builder, loc, n, one);
185 Value lo = arith::MaxSIOp::create(builder, loc, loRaw, one);
186 Value hi = arith::MinSIOp::create(builder, loc, hiRaw, nm1);
187 Value two = constOfType(2);
188 Value sum = arith::AddIOp::create(builder, loc, lo, hi);
189 Value mid = arith::DivUIOp::create(builder, loc, sum, two);
195 Value sm1 = arith::SubIOp::create(builder, loc, s, one);
196 Value cap = arith::SubIOp::create(builder, loc, n, sm1);
197 Value capped = arith::MinSIOp::create(builder, loc, mid, cap);
198 Value res = arith::MaxSIOp::create(builder, loc, capped, one);
199 scf::YieldOp::create(builder, loc, ValueRange{res});
202 op.getResult().replaceAllUsesWith(ifOp.getResult(0));
206struct LowerBinomialProgressPass
207 :
public enzyme::impl::LowerBinomialProgressPassBase<
208 LowerBinomialProgressPass> {
209 void runOnOperation()
override {
210 SmallVector<enzyme::BinomialProgressOp> ops;
211 getOperation()->walk(
212 [&](enzyme::BinomialProgressOp op) { ops.push_back(op); });
214 lowerBinomialProgress(op);
static int64_t binomialProgress(int64_t n, int64_t s)