Skip to content

[mlir][loops] Add getters for multi dim loop variables in LoopLikeOpInterface #94516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 7, 2024
4 changes: 2 additions & 2 deletions mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ def AffineForOp : Affine_Op<"for",
[AttrSizedOperandSegments, AutomaticAllocationScope,
ImplicitAffineTerminator, ConditionallySpeculatable,
RecursiveMemoryEffects, DeclareOpInterfaceMethods<LoopLikeOpInterface,
["getSingleInductionVar", "getSingleLowerBound", "getSingleStep",
"getSingleUpperBound", "getYieldedValuesMutable",
["getInductionVars", "getMixedLowerBound", "getMixedStep",
"getMixedUpperBound", "getYieldedValuesMutable",
"replaceWithAdditionalYields"]>,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>]> {
Expand Down
37 changes: 6 additions & 31 deletions mlir/include/mlir/Dialect/SCF/IR/SCFOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ def ExecuteRegionOp : SCF_Op<"execute_region", [
def ForOp : SCF_Op<"for",
[AutomaticAllocationScope, DeclareOpInterfaceMethods<LoopLikeOpInterface,
["getInitsMutable", "getLoopResults", "getRegionIterArgs",
"getSingleInductionVar", "getSingleLowerBound", "getSingleStep",
"getSingleUpperBound", "getYieldedValuesMutable",
"getInductionVars", "getMixedLowerBound", "getMixedStep",
"getMixedUpperBound", "getYieldedValuesMutable",
"promoteIfSingleIteration", "replaceWithAdditionalYields",
"yieldTiledValuesAndReplace"]>,
AllTypesMatch<["lowerBound", "upperBound", "step"]>,
Expand Down Expand Up @@ -301,8 +301,8 @@ def ForallOp : SCF_Op<"forall", [
AttrSizedOperandSegments,
AutomaticAllocationScope,
DeclareOpInterfaceMethods<LoopLikeOpInterface,
["getInitsMutable", "getRegionIterArgs", "getSingleInductionVar",
"getSingleLowerBound", "getSingleUpperBound", "getSingleStep",
["getInitsMutable", "getRegionIterArgs", "getInductionVars",
"getMixedLowerBound", "getMixedUpperBound", "getMixedStep",
"promoteIfSingleIteration", "yieldTiledValuesAndReplace"]>,
RecursiveMemoryEffects,
SingleBlockImplicitTerminator<"scf::InParallelOp">,
Expand Down Expand Up @@ -510,24 +510,6 @@ def ForallOp : SCF_Op<"forall", [
];

let extraClassDeclaration = [{
// Get lower bounds as OpFoldResult.
SmallVector<OpFoldResult> getMixedLowerBound() {
Builder b(getOperation()->getContext());
return getMixedValues(getStaticLowerBound(), getDynamicLowerBound(), b);
}

// Get upper bounds as OpFoldResult.
SmallVector<OpFoldResult> getMixedUpperBound() {
Builder b(getOperation()->getContext());
return getMixedValues(getStaticUpperBound(), getDynamicUpperBound(), b);
}

// Get steps as OpFoldResult.
SmallVector<OpFoldResult> getMixedStep() {
Builder b(getOperation()->getContext());
return getMixedValues(getStaticStep(), getDynamicStep(), b);
}

/// Get lower bounds as values.
SmallVector<Value> getLowerBound(OpBuilder &b) {
return getValueOrCreateConstantIndexOp(b, getLoc(), getMixedLowerBound());
Expand Down Expand Up @@ -584,10 +566,6 @@ def ForallOp : SCF_Op<"forall", [
getNumDynamicControlOperands() + getRank());
}

::mlir::ValueRange getInductionVars() {
return getBody()->getArguments().take_front(getRank());
}

::mlir::Value getInductionVar(int64_t idx) {
return getInductionVars()[idx];
}
Expand Down Expand Up @@ -765,8 +743,8 @@ def IfOp : SCF_Op<"if", [DeclareOpInterfaceMethods<RegionBranchOpInterface, [
def ParallelOp : SCF_Op<"parallel",
[AutomaticAllocationScope,
AttrSizedOperandSegments,
DeclareOpInterfaceMethods<LoopLikeOpInterface, ["getSingleInductionVar",
"getSingleLowerBound", "getSingleUpperBound", "getSingleStep"]>,
DeclareOpInterfaceMethods<LoopLikeOpInterface, ["getInductionVars",
"getMixedLowerBound", "getMixedUpperBound", "getMixedStep"]>,
RecursiveMemoryEffects,
DeclareOpInterfaceMethods<RegionBranchOpInterface>,
SingleBlockImplicitTerminator<"scf::ReduceOp">,
Expand Down Expand Up @@ -846,9 +824,6 @@ def ParallelOp : SCF_Op<"parallel",
];

let extraClassDeclaration = [{
ValueRange getInductionVars() {
return getBody()->getArguments();
}
unsigned getNumLoops() { return getStep().size(); }
unsigned getNumReductions() { return getInitVals().size(); }
}];
Expand Down
69 changes: 49 additions & 20 deletions mlir/include/mlir/Interfaces/LoopLikeInterface.td
Original file line number Diff line number Diff line change
Expand Up @@ -93,51 +93,47 @@ def LoopLikeOpInterface : OpInterface<"LoopLikeOpInterface"> {
}]
>,
InterfaceMethod<[{
If there is a single induction variable return it, otherwise return
std::nullopt.
Return all induction variables.
}],
/*retTy=*/"::std::optional<::mlir::Value>",
/*methodName=*/"getSingleInductionVar",
/*retTy=*/"::mlir::ValueRange",
/*methodName=*/"getInductionVars",
/*args=*/(ins),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return std::nullopt;
return {};
}]
>,
InterfaceMethod<[{
Return the single lower bound value or attribute if it exists, otherwise
return std::nullopt.
Return all lower bounds.
}],
/*retTy=*/"::std::optional<::mlir::OpFoldResult>",
/*methodName=*/"getSingleLowerBound",
/*retTy=*/"::llvm::SmallVector<::mlir::OpFoldResult>",
/*methodName=*/"getMixedLowerBound",
/*args=*/(ins),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return std::nullopt;
return {};
}]
>,
InterfaceMethod<[{
Return the single step value or attribute if it exists, otherwise
return std::nullopt.
Return all steps.
}],
/*retTy=*/"::std::optional<::mlir::OpFoldResult>",
/*methodName=*/"getSingleStep",
/*retTy=*/"::llvm::SmallVector<::mlir::OpFoldResult>",
/*methodName=*/"getMixedStep",
/*args=*/(ins),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return std::nullopt;
return {};
}]
>,
InterfaceMethod<[{
Return the single upper bound value or attribute if it exists, otherwise
return std::nullopt.
Return all upper bounds.
}],
/*retTy=*/"::std::optional<::mlir::OpFoldResult>",
/*methodName=*/"getSingleUpperBound",
/*retTy=*/"::llvm::SmallVector<::mlir::OpFoldResult>",
/*methodName=*/"getMixedUpperBound",
/*args=*/(ins),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return std::nullopt;
return {};
}]
>,
InterfaceMethod<[{
Expand Down Expand Up @@ -235,6 +231,39 @@ def LoopLikeOpInterface : OpInterface<"LoopLikeOpInterface"> {
}];

let extraSharedClassDeclaration = [{
/// If there is a single induction variable return it, otherwise return
/// std::nullopt.
::std::optional<::mlir::Value> getSingleInductionVar() {
auto inductionVars = this->getInductionVars();
if (inductionVars.size() == 1)
return inductionVars[0];
return std::nullopt;
}
/// Return the single lower bound value or attribute if it exists, otherwise
/// return std::nullopt.
::std::optional<::mlir::OpFoldResult> getSingleLowerBound() {
auto lowerBounds = this->getMixedLowerBound();
if (lowerBounds.size() == 1)
return lowerBounds[0];
return std::nullopt;
}
/// Return the single step value or attribute if it exists, otherwise
/// return std::nullopt.
::std::optional<::mlir::OpFoldResult> getSingleStep() {
auto steps = this->getMixedStep();
if (steps.size() == 1)
return steps[0];
return std::nullopt;
}
/// Return the single upper bound value or attribute if it exists, otherwise
/// return std::nullopt.
::std::optional<::mlir::OpFoldResult> getSingleUpperBound() {
auto upperBounds = this->getMixedUpperBound();
if (upperBounds.size() == 1)
return upperBounds[0];
return std::nullopt;
}

/// Append the specified additional "init" operands: replace this loop with
/// a new loop that has the additional init operands. The loop body of this
/// loop is moved over to the new loop.
Expand Down
20 changes: 9 additions & 11 deletions mlir/lib/Dialect/Affine/IR/AffineOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2454,27 +2454,25 @@ bool AffineForOp::matchingBoundOperandList() {

SmallVector<Region *> AffineForOp::getLoopRegions() { return {&getRegion()}; }

std::optional<Value> AffineForOp::getSingleInductionVar() {
return getInductionVar();
}
ValueRange AffineForOp::getInductionVars() { return {getInductionVar()}; }

std::optional<OpFoldResult> AffineForOp::getSingleLowerBound() {
SmallVector<OpFoldResult> AffineForOp::getMixedLowerBound() {
if (!hasConstantLowerBound())
return std::nullopt;
return {};
OpBuilder b(getContext());
return OpFoldResult(b.getI64IntegerAttr(getConstantLowerBound()));
return {OpFoldResult(b.getI64IntegerAttr(getConstantLowerBound()))};
}

std::optional<OpFoldResult> AffineForOp::getSingleStep() {
SmallVector<OpFoldResult> AffineForOp::getMixedStep() {
OpBuilder b(getContext());
return OpFoldResult(b.getI64IntegerAttr(getStepAsInt()));
return {OpFoldResult(b.getI64IntegerAttr(getStepAsInt()))};
}

std::optional<OpFoldResult> AffineForOp::getSingleUpperBound() {
SmallVector<OpFoldResult> AffineForOp::getMixedUpperBound() {
if (!hasConstantUpperBound())
return std::nullopt;
return {};
OpBuilder b(getContext());
return OpFoldResult(b.getI64IntegerAttr(getConstantUpperBound()));
return {OpFoldResult(b.getI64IntegerAttr(getConstantUpperBound()))};
}

FailureOr<LoopLikeOpInterface> AffineForOp::replaceWithAdditionalYields(
Expand Down
70 changes: 27 additions & 43 deletions mlir/lib/Dialect/SCF/IR/SCF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,20 +378,18 @@ LogicalResult ForOp::verifyRegions() {
return success();
}

std::optional<Value> ForOp::getSingleInductionVar() {
return getInductionVar();
}
ValueRange ForOp::getInductionVars() { return {getInductionVar()}; }

std::optional<OpFoldResult> ForOp::getSingleLowerBound() {
return OpFoldResult(getLowerBound());
SmallVector<OpFoldResult> ForOp::getMixedLowerBound() {
return {OpFoldResult(getLowerBound())};
}

std::optional<OpFoldResult> ForOp::getSingleStep() {
return OpFoldResult(getStep());
SmallVector<OpFoldResult> ForOp::getMixedStep() {
return {OpFoldResult(getStep())};
}

std::optional<OpFoldResult> ForOp::getSingleUpperBound() {
return OpFoldResult(getUpperBound());
SmallVector<OpFoldResult> ForOp::getMixedUpperBound() {
return {OpFoldResult(getUpperBound())};
}

std::optional<ResultRange> ForOp::getLoopResults() { return getResults(); }
Expand Down Expand Up @@ -1428,28 +1426,26 @@ SmallVector<Operation *> ForallOp::getCombiningOps(BlockArgument bbArg) {
return storeOps;
}

std::optional<Value> ForallOp::getSingleInductionVar() {
if (getRank() != 1)
return std::nullopt;
return getInductionVar(0);
ValueRange ForallOp::getInductionVars() {
return getBody()->getArguments().take_front(getRank());
}

std::optional<OpFoldResult> ForallOp::getSingleLowerBound() {
if (getRank() != 1)
return std::nullopt;
return getMixedLowerBound()[0];
// Get lower bounds as OpFoldResult.
SmallVector<OpFoldResult> ForallOp::getMixedLowerBound() {
Builder b(getOperation()->getContext());
return getMixedValues(getStaticLowerBound(), getDynamicLowerBound(), b);
}

std::optional<OpFoldResult> ForallOp::getSingleUpperBound() {
if (getRank() != 1)
return std::nullopt;
return getMixedUpperBound()[0];
// Get upper bounds as OpFoldResult.
SmallVector<OpFoldResult> ForallOp::getMixedUpperBound() {
Builder b(getOperation()->getContext());
return getMixedValues(getStaticUpperBound(), getDynamicUpperBound(), b);
}

std::optional<OpFoldResult> ForallOp::getSingleStep() {
if (getRank() != 1)
return std::nullopt;
return getMixedStep()[0];
// Get steps as OpFoldResult.
SmallVector<OpFoldResult> ForallOp::getMixedStep() {
Builder b(getOperation()->getContext());
return getMixedValues(getStaticStep(), getDynamicStep(), b);
}

ForallOp mlir::scf::getForallOpThreadIndexOwner(Value val) {
Expand Down Expand Up @@ -3008,29 +3004,17 @@ void ParallelOp::print(OpAsmPrinter &p) {

SmallVector<Region *> ParallelOp::getLoopRegions() { return {&getRegion()}; }

std::optional<Value> ParallelOp::getSingleInductionVar() {
if (getNumLoops() != 1)
return std::nullopt;
return getBody()->getArgument(0);
}
ValueRange ParallelOp::getInductionVars() { return getBody()->getArguments(); }

std::optional<OpFoldResult> ParallelOp::getSingleLowerBound() {
if (getNumLoops() != 1)
return std::nullopt;
return getLowerBound()[0];
SmallVector<OpFoldResult> ParallelOp::getMixedLowerBound() {
return getLowerBound();
}

std::optional<OpFoldResult> ParallelOp::getSingleUpperBound() {
if (getNumLoops() != 1)
return std::nullopt;
return getUpperBound()[0];
SmallVector<OpFoldResult> ParallelOp::getMixedUpperBound() {
return getUpperBound();
}

std::optional<OpFoldResult> ParallelOp::getSingleStep() {
if (getNumLoops() != 1)
return std::nullopt;
return getStep()[0];
}
SmallVector<OpFoldResult> ParallelOp::getMixedStep() { return getStep(); }

ParallelOp mlir::scf::getParallelForInductionVarOwner(Value val) {
auto ivArg = llvm::dyn_cast<BlockArgument>(val);
Expand Down
8 changes: 8 additions & 0 deletions mlir/unittests/Dialect/SCF/LoopLikeSCFOpsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class SCFLoopLikeTest : public ::testing::Test {
std::optional<OpFoldResult> maybeIndVar =
loopLikeOp.getSingleInductionVar();
EXPECT_TRUE(maybeIndVar.has_value());
EXPECT_EQ(loopLikeOp.getInductionVars().size(), 1u);
EXPECT_EQ(loopLikeOp.getMixedLowerBound().size(), 1u);
EXPECT_EQ(loopLikeOp.getMixedStep().size(), 1u);
EXPECT_EQ(loopLikeOp.getMixedLowerBound().size(), 1u);
}

void checkMultidimensional(LoopLikeOpInterface loopLikeOp) {
Expand All @@ -48,6 +52,10 @@ class SCFLoopLikeTest : public ::testing::Test {
std::optional<OpFoldResult> maybeIndVar =
loopLikeOp.getSingleInductionVar();
EXPECT_FALSE(maybeIndVar.has_value());
EXPECT_EQ(loopLikeOp.getInductionVars().size(), 2u);
EXPECT_EQ(loopLikeOp.getMixedLowerBound().size(), 2u);
EXPECT_EQ(loopLikeOp.getMixedStep().size(), 2u);
EXPECT_EQ(loopLikeOp.getMixedLowerBound().size(), 2u);
}

MLIRContext context;
Expand Down