blob: 9fd27d328694e0a7cdadfcb2f8c92ed4b450e68e [file] [log] [blame]
//===- IndependenceTransforms.cpp - Make ops independent of values --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Tensor/Transforms/Transforms.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Affine/Transforms/Transforms.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
using namespace mlir;
using namespace mlir::tensor;
/// Make the given OpFoldResult independent of all independencies.
static FailureOr<OpFoldResult> makeIndependent(OpBuilder &b, Location loc,
OpFoldResult ofr,
ValueRange independencies) {
if (isa<Attribute>(ofr))
return ofr;
Value value = cast<Value>(ofr);
AffineMap boundMap;
ValueDimList mapOperands;
if (failed(ValueBoundsConstraintSet::computeIndependentBound(
boundMap, mapOperands, presburger::BoundType::UB, value,
independencies,
/*closedUB=*/true)))
return failure();
return mlir::affine::materializeComputedBound(b, loc, boundMap, mapOperands);
}
FailureOr<Value> tensor::buildIndependentOp(OpBuilder &b, tensor::PadOp padOp,
ValueRange independencies) {
OpBuilder::InsertionGuard g(b);
b.setInsertionPoint(padOp);
Location loc = padOp.getLoc();
// Non-constant padding not supported.
Value constantPadding = padOp.getConstantPaddingValue();
if (!constantPadding)
return failure();
SmallVector<OpFoldResult> newMixedLow, newMixedHigh;
for (OpFoldResult ofr : padOp.getMixedLowPad()) {
auto ub = makeIndependent(b, loc, ofr, independencies);
if (failed(ub))
return failure();
newMixedLow.push_back(*ub);
}
for (OpFoldResult ofr : padOp.getMixedHighPad()) {
auto ub = makeIndependent(b, loc, ofr, independencies);
if (failed(ub))
return failure();
newMixedHigh.push_back(*ub);
}
// Return existing tensor::PadOp if nothing has changed.
if (llvm::equal(padOp.getMixedLowPad(), newMixedLow) &&
llvm::equal(padOp.getMixedHighPad(), newMixedHigh))
return padOp.getResult();
// Create a new tensor::PadOp.
auto newPadOp =
PadOp::create(b, loc, padOp.getResultType(), padOp.getSource(),
newMixedLow, newMixedHigh, constantPadding,
padOp.getNofold(), /*attrs=*/ArrayRef<NamedAttribute>{});
// Create a tensor::ExtractSliceOp.
// Reify the result sizes of the old tensor::PadOp.
ReifiedRankedShapedTypeDims reifiedSizes;
ReifyRankedShapedTypeOpInterface reifyShapedTypeInterface =
dyn_cast<ReifyRankedShapedTypeOpInterface>(padOp.getOperation());
if (failed(reifyShapedTypeInterface.reifyResultShapes(b, reifiedSizes)))
return failure();
SmallVector<OpFoldResult> offsets, sizes, strides;
for (int64_t i = 0, e = padOp.getResultType().getRank(); i < e; ++i) {
// offset = ub(low_padding) - low_padding
OpFoldResult prevLow = padOp.getMixedLowPad()[i];
if (isa<Attribute>(prevLow)) {
offsets.push_back(b.getIndexAttr(0));
} else {
offsets.push_back(
affine::AffineApplyOp::create(
b, loc, b.getAffineDimExpr(0) - b.getAffineDimExpr(1),
std::initializer_list<Value>{cast<Value>(newMixedLow[i]),
cast<Value>(prevLow)})
.getResult());
}
// size = reified result size
if (!padOp.getResultType().isDynamicDim(i)) {
sizes.push_back(b.getIndexAttr(padOp.getResultType().getDimSize(i)));
} else {
sizes.push_back(reifiedSizes[0][i]);
}
// stride = 1
strides.push_back(b.getIndexAttr(1));
}
return ExtractSliceOp::create(b, loc, newPadOp, offsets, sizes, strides)
.getResult();
}
FailureOr<Value> tensor::buildIndependentOp(OpBuilder &b,
tensor::EmptyOp emptyOp,
ValueRange independencies) {
OpBuilder::InsertionGuard g(b);
b.setInsertionPoint(emptyOp);
Location loc = emptyOp.getLoc();
SmallVector<OpFoldResult> newSizes;
for (OpFoldResult ofr : emptyOp.getMixedSizes()) {
auto ub = makeIndependent(b, loc, ofr, independencies);
if (failed(ub))
return failure();
newSizes.push_back(*ub);
}
// Return existing tensor::EmptyOp if nothing has changed.
if (llvm::equal(emptyOp.getMixedSizes(), newSizes))
return emptyOp.getResult();
// Create a new tensor::EmptyOp.
Value newEmptyOp =
EmptyOp::create(b, loc, newSizes, emptyOp.getType().getElementType());
// Create a tensor::ExtractSliceOp.
SmallVector<OpFoldResult> offsets(newSizes.size(), b.getIndexAttr(0));
SmallVector<OpFoldResult> strides(newSizes.size(), b.getIndexAttr(1));
return ExtractSliceOp::create(b, loc, newEmptyOp, offsets,
emptyOp.getMixedSizes(), strides)
.getResult();
}