The MLIR classes Type/Attribute/Operation/Op/Value support cast/dyn_cast/isa/dyn_cast_or_null functionality through llvm's doCast functionality in addition to defining methods with the same name. This change begins the migration of uses of the method to the corresponding function call as has been decided as more consistent. Note that there still exist classes that only define methods directly, such as AffineExpr, and this does not include work currently to support a functional cast/isa call. Context: * https://mlir.llvm.org/deprecation/ at "Use the free function variants for dyn_cast/cast/isa/…" * Original discussion at https://discourse.llvm.org/t/preferred-casting-style-going-forward/68443 Implementation: This follows a previous patch that updated calls `op.cast<T>()-> cast<T>(op)`. However some cases could not handle an unprefixed `cast` call due to occurrences of variables named cast, or occurring inside of class definitions which would resolve to the method. All C++ files that did not work automatically with `cast<T>()` are updated here to `llvm::cast` and similar with the intention that they can be easily updated after the methods are removed through a find-replace. See https://github.com/llvm/llvm-project/compare/main...tpopp:llvm-project:tidy-cast-check for the clang-tidy check that is used and then update printed occurrences of the function to include `llvm::` before. One can then run the following: ``` ninja -C $BUILD_DIR clang-tidy run-clang-tidy -clang-tidy-binary=$BUILD_DIR/bin/clang-tidy -checks='-*,misc-cast-functions'\ -export-fixes /tmp/cast/casts.yaml mlir/*\ -header-filter=mlir/ -fix rm -rf $BUILD_DIR/tools/mlir/**/*.inc ``` Differential Revision: https://reviews.llvm.org/D150348
127 lines
4.5 KiB
C++
127 lines
4.5 KiB
C++
//===- ValueBoundsOpInterfaceImpl.cpp - Impl. of ValueBoundsOpInterface ---===//
|
|
//
|
|
// 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/SCF/IR/ValueBoundsOpInterfaceImpl.h"
|
|
|
|
#include "mlir/Dialect/SCF/IR/SCF.h"
|
|
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
|
|
|
|
using namespace mlir;
|
|
using presburger::BoundType;
|
|
|
|
namespace mlir {
|
|
namespace scf {
|
|
namespace {
|
|
|
|
struct ForOpInterface
|
|
: public ValueBoundsOpInterface::ExternalModel<ForOpInterface, ForOp> {
|
|
|
|
/// Populate bounds of values/dimensions for iter_args/OpResults.
|
|
static void populateIterArgBounds(scf::ForOp forOp, Value value,
|
|
std::optional<int64_t> dim,
|
|
ValueBoundsConstraintSet &cstr) {
|
|
// `value` is an iter_arg or an OpResult.
|
|
int64_t iterArgIdx;
|
|
if (auto iterArg = llvm::dyn_cast<BlockArgument>(value)) {
|
|
iterArgIdx = iterArg.getArgNumber() - forOp.getNumInductionVars();
|
|
} else {
|
|
iterArgIdx = llvm::cast<OpResult>(value).getResultNumber();
|
|
}
|
|
|
|
// An EQ constraint can be added if the yielded value (dimension size)
|
|
// equals the corresponding block argument (dimension size).
|
|
assert(forOp.getLoopBody().hasOneBlock() &&
|
|
"multiple blocks not supported");
|
|
Value yieldedValue =
|
|
cast<scf::YieldOp>(forOp.getLoopBody().front().getTerminator())
|
|
.getOperand(iterArgIdx);
|
|
Value iterArg = forOp.getRegionIterArg(iterArgIdx);
|
|
Value initArg = forOp.getInitArgs()[iterArgIdx];
|
|
|
|
auto addEqBound = [&]() {
|
|
if (dim.has_value()) {
|
|
cstr.bound(value)[*dim] == cstr.getExpr(initArg, dim);
|
|
} else {
|
|
cstr.bound(value) == initArg;
|
|
}
|
|
};
|
|
|
|
if (yieldedValue == iterArg) {
|
|
addEqBound();
|
|
return;
|
|
}
|
|
|
|
// Compute EQ bound for yielded value.
|
|
AffineMap bound;
|
|
ValueDimList boundOperands;
|
|
LogicalResult status = ValueBoundsConstraintSet::computeBound(
|
|
bound, boundOperands, BoundType::EQ, yieldedValue, dim,
|
|
[&](Value v, std::optional<int64_t> d) {
|
|
// Stop when reaching a block argument of the loop body.
|
|
if (auto bbArg = llvm::dyn_cast<BlockArgument>(v))
|
|
return bbArg.getOwner()->getParentOp() == forOp;
|
|
// Stop when reaching a value that is defined outside of the loop. It
|
|
// is impossible to reach an iter_arg from there.
|
|
Operation *op = v.getDefiningOp();
|
|
return forOp.getLoopBody().findAncestorOpInRegion(*op) == nullptr;
|
|
});
|
|
if (failed(status))
|
|
return;
|
|
if (bound.getNumResults() != 1)
|
|
return;
|
|
|
|
// Check if computed bound equals the corresponding iter_arg.
|
|
Value singleValue = nullptr;
|
|
std::optional<int64_t> singleDim;
|
|
if (auto dimExpr = bound.getResult(0).dyn_cast<AffineDimExpr>()) {
|
|
int64_t idx = dimExpr.getPosition();
|
|
singleValue = boundOperands[idx].first;
|
|
singleDim = boundOperands[idx].second;
|
|
} else if (auto symExpr = bound.getResult(0).dyn_cast<AffineSymbolExpr>()) {
|
|
int64_t idx = symExpr.getPosition() + bound.getNumDims();
|
|
singleValue = boundOperands[idx].first;
|
|
singleDim = boundOperands[idx].second;
|
|
}
|
|
if (singleValue == iterArg && singleDim == dim)
|
|
addEqBound();
|
|
}
|
|
|
|
void populateBoundsForIndexValue(Operation *op, Value value,
|
|
ValueBoundsConstraintSet &cstr) const {
|
|
auto forOp = cast<ForOp>(op);
|
|
|
|
if (value == forOp.getInductionVar()) {
|
|
// TODO: Take into account step size.
|
|
cstr.bound(value) >= forOp.getLowerBound();
|
|
cstr.bound(value) < forOp.getUpperBound();
|
|
return;
|
|
}
|
|
|
|
// Handle iter_args and OpResults.
|
|
populateIterArgBounds(forOp, value, std::nullopt, cstr);
|
|
}
|
|
|
|
void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
|
|
ValueBoundsConstraintSet &cstr) const {
|
|
auto forOp = cast<ForOp>(op);
|
|
// Handle iter_args and OpResults.
|
|
populateIterArgBounds(forOp, value, dim, cstr);
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
} // namespace scf
|
|
} // namespace mlir
|
|
|
|
void mlir::scf::registerValueBoundsOpInterfaceExternalModels(
|
|
DialectRegistry ®istry) {
|
|
registry.addExtension(+[](MLIRContext *ctx, scf::SCFDialect *dialect) {
|
|
scf::ForOp::attachInterface<scf::ForOpInterface>(*ctx);
|
|
});
|
|
}
|