Skip to content

Commit d1b9215

Browse files
committed
WIP DusDusPadPad
1 parent 1e6afb9 commit d1b9215

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

src/enzyme_ad/jax/Passes/EnzymeHLOOpt.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
#include "llvm/ADT/MapVector.h"
5656
#include <cstddef>
57+
#include <cstdint>
5758
#include <iterator>
5859
#include <mlir/IR/BuiltinAttributes.h>
5960
#include <mlir/IR/Value.h>
@@ -16832,6 +16833,180 @@ struct DUSDUSToDUSPad
1683216833
}
1683316834
};
1683416835

16836+
struct DUSDUSSubsuming
16837+
: public ChceckOpRewritePattern<stablehlo::DynamicUpdateSliceOp,
16838+
DUSDUSSubsuming> {
16839+
using CheckedOpRewritePattern::CheckedOpRewritePattern;
16840+
16841+
std::tuple<Value, SmallVector<int64_t>, SmallVector<int64_t>>
16842+
getPaddingAmount(Value value) {
16843+
if (auto pad = value.getDefiningOp<stablehlo::PadOp>()) {
16844+
auto [nested, nestedLow, nestedHigh] = getPaddingAmount(pad.getOperand());
16845+
if (!nested)
16846+
return std::make_tuple(pad.getOperand(),
16847+
llvm::to_vector(pad.getEdgePaddingLow()),
16848+
llvm::to_vector(pad.getEdgePaddingHigh()));
16849+
16850+
for (auto [i, v] : llvm::enumerate(pad.getEdgePaddingLow())) {
16851+
nestedLow[i] += v;
16852+
}
16853+
for (auto [i, v] : llvm::enumerate(pad.getEdgePaddingHigh())) {
16854+
nestedHigh[i] += v;
16855+
}
16856+
return std::make_tuple(nested, nestedLow, nestedHigh);
16857+
}
16858+
if (auto extend = value.getDefiningOp<enzymexla::ExtendOp>()) {
16859+
auto rank =
16860+
cast<RankedTensorType>(extend.getOperand().getType()).getRank();
16861+
SmallVector<int64_t> low(rank, 0);
16862+
SmallVector<int64_t> high(rank, 0);
16863+
low[extend.getDimension()] = extend.getLow();
16864+
high[extend.getDimension()] = extend.getHigh();
16865+
16866+
auto [nested, nestedLow, nestedHigh] =
16867+
getPaddingAmount(extend.getOperand());
16868+
if (!nested)
16869+
return std::make_tuple(extend.getOperand(), low, high);
16870+
16871+
for (auto [i, v] : llvm::enumerate(low)) {
16872+
nestedLow[i] += v;
16873+
}
16874+
for (auto [i, v] : llvm::enumerate(high)) {
16875+
nestedHigh[i] += v;
16876+
}
16877+
return std::make_tuple(nested, nestedLow, nestedHigh);
16878+
}
16879+
return std::make_tuple(Value(), SmallVector<int64_t>(),
16880+
SmallVector<int64_t>());
16881+
}
16882+
16883+
LogicalResult matchAndRewriteImpl(stablehlo::DynamicUpdateSliceOp dus,
16884+
PatternRewriter &rewriter) const {
16885+
auto dus2 =
16886+
dus.getOperand().getDefiningOp<stablehlo::DynamicUpdateSliceOp>();
16887+
16888+
if (!dus2)
16889+
return failure();
16890+
16891+
auto pad2 = dus2.getUpdate().getDefiningOp<stablehlo::PadOp>();
16892+
if (!pad2)
16893+
return failure();
16894+
16895+
// TODO: potentially relax this
16896+
auto pad = dus.getUpdate().getDefiningOp<stablehlo::PadOp>();
16897+
if (!pad)
16898+
return failure();
16899+
16900+
if (pad.getPaddingValue() != pad2.getPaddingValue())
16901+
return failure();
16902+
16903+
if (!llvm::all_of(pad.getInteriorPadding(),
16904+
[](int64_t v) { return v == 0; }))
16905+
return failure();
16906+
if (!llvm::all_of(pad2.getInteriorPadding(),
16907+
[](int64_t v) { return v == 0; }))
16908+
return failure();
16909+
16910+
// Only applies if we can analyze sizes.
16911+
SmallVector<int64_t> starts, extents, starts2, extents2;
16912+
auto extractDUSStartAndExtents = [](stablehlo::DynamicUpdateSliceOp dus,
16913+
SmallVectorImpl<int64_t> starts,
16914+
SmallVectorImpl<int64_t> extents) {
16915+
for (auto [s, e] : llvm::zip_equal(
16916+
dus.getStartIndices(), dus.getUpdate().getType().getShape())) {
16917+
DenseIntElementsAttr startattr;
16918+
if (!matchPattern(s, m_Constant(&startattr)))
16919+
return failure();
16920+
int64_t ival = (*startattr.begin()).getSExtValue();
16921+
starts.push_back(ival);
16922+
extents.push_back(e);
16923+
return success();
16924+
}
16925+
};
16926+
if (failed(dus, starts, extents))
16927+
return failure();
16928+
if (failed(dus2, starts2, extents2))
16929+
return failure();
16930+
16931+
// The update of dus should be a padded version of dus2's update,
16932+
// and the interfering reads should not be accessing that padding.
16933+
auto [source, low, high] = getPaddingAmount(dus.getUpdate());
16934+
auto [source2, low2, high2] = getPaddingAmount(dus2.getUpdate());
16935+
if (source != source2 || !source || !source2)
16936+
return failure();
16937+
16938+
// // Find the non-subsumed part and check whether it comes from a pad. The
16939+
// // tuple is (dimension, start, extent) of the non-subsummed part.
16940+
// SmallVecor<std::tuple<unsigned, int64_t, int64_t>> nonSubsummed;
16941+
// for (auto [dim, s, e, s2, e2] :
16942+
// llvm::enumerate(starts, extents, starts2, extents2)) {
16943+
// if (s <= s2 && s + e >= s2 + e2) {
16944+
// // dus subsumes dus2 in this dimension, we are okay with this
16945+
// continue;
16946+
// }
16947+
16948+
// if (s2 < s && pad2.getEdgePaddingLow()[dim] >= (s - s2)) {
16949+
// nonSubsummed.emplace_back(dim, s2, s - s2);
16950+
// continue;
16951+
// }
16952+
// if (s2 + e2 > s + e &&
16953+
// pad2.getEdgePaddingHigh()[dim] >= (s2 + e2 - (s + e))) {
16954+
// nonSubsummed.emplace_back(dim, s + e, s2 + e2 - (s + e));
16955+
// continue;
16956+
// }
16957+
16958+
// return failure();
16959+
// }
16960+
16961+
// The pair is (start, extent).
16962+
SmallVector<std::pair<int64_t, int64_t>> forwardedToDus2;
16963+
for (auto [l2, h2, start, extent] :
16964+
llvm::zip_equal(low2, high2, start2, extents2))
16965+
forwardedToDus2.emplace_back(start2 + low2, extent - low2 - high2);
16966+
}
16967+
16968+
DominanceInfo domInfo;
16969+
for (Operation *user : dus2.getResult().getUsers()) {
16970+
if (user == dus)
16971+
continue;
16972+
auto slice = dyn_cast<stablehlo::SliceOp>(user);
16973+
if (!slice)
16974+
return failure();
16975+
16976+
if (!domInfo.dominates(user, dus))
16977+
continue;
16978+
16979+
// Find the if there is a part of the slice that is not reading from the
16980+
// forwarded or the padding.
16981+
for (auto &&[dim, sliceStart, sliceLimit, forwardedPair :
16982+
llvm::enumerate(slice.getStartIndices(), slice.getLimitInidices(), forwardedToDus)) {
16983+
auto [forwardedStart, forwardedExtent] = forwardedPair;
16984+
if (sliceStart < forwardedStart) {
16985+
if ((forwardedStart - sliceStart) <= pad2.getEdgePaddingLow()[dim])
16986+
continue;
16987+
}
16988+
if (sliceLimit >= forwardedStart + forwardedExtent) {
16989+
if ((sliceLimit - (forwardedStart + forwardedExtent)) <=
16990+
pad2.getEdgePaddingHigh()[dim])
16991+
continue;
16992+
}
16993+
return failure();
16994+
}
16995+
16996+
// Find if there is any user of the slice that cannot be moved.
16997+
for (Operation *sliceUser : slice.getResult().getUsers()) {
16998+
if (domInfo.dominates(sliceUser, dus))
16999+
return failure();
17000+
}
17001+
17002+
// TODO: otherwise this slice should be fine to move after the dus, but we
17003+
// need to make sure the padding is sufficient.
17004+
}
17005+
17006+
return success();
17007+
}
17008+
}
17009+
1683517010
struct SinkDUS : public CheckedOpRewritePattern<stablehlo::WhileOp, SinkDUS> {
1683617011
using CheckedOpRewritePattern::CheckedOpRewritePattern;
1683717012

0 commit comments

Comments
 (0)