Decouple affine->standard lowering from the pass

The lowering from the Affine dialect to the Standard dialect was originally
    implemented as a standalone pass.  However, it may be used by other passes
    willing to lower away some of the affine constructs as a part of their
    operation.  Decouple the transformation functions from the pass infrastructure
    and expose the entry point for the lowering.

    Also update the lowering functions to use `LogicalResult` instead of bool for
    return values.

--

PiperOrigin-RevId: 250229198
This commit is contained in:
Alex Zinenko 2019-05-28 00:49:23 -07:00 committed by Mehdi Amini
parent ffc4cf7091
commit d4c071cc69
2 changed files with 60 additions and 33 deletions

View File

@ -0,0 +1,28 @@
//===- LowerAffine.h - Convert Affine to Standard dialect -------*- C++ -*-===//
//
// Copyright 2019 The MLIR Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#ifndef MLIR_TRANSFORMS_LOWERAFFINE_H
#define MLIR_TRANSFORMS_LOWERAFFINE_H
namespace mlir {
class Function;
class LogicalResult;
LogicalResult lowerAffineConstructs(Function &function);
} // namespace mlir
#endif // MLIR_TRANSFORMS_LOWERAFFINE_H

View File

@ -20,6 +20,7 @@
//
//===----------------------------------------------------------------------===//
#include "mlir/Transforms/LowerAffine.h"
#include "mlir/AffineOps/AffineOps.h"
#include "mlir/IR/AffineExprVisitor.h"
#include "mlir/IR/Builders.h"
@ -243,10 +244,6 @@ Optional<SmallVector<Value *, 8>> static expandAffineMap(
namespace {
struct LowerAffinePass : public FunctionPass<LowerAffinePass> {
void runOnFunction() override;
bool lowerAffineFor(AffineForOp forOp);
bool lowerAffineIf(AffineIfOp ifOp);
bool lowerAffineApply(AffineApplyOp op);
};
} // end anonymous namespace
@ -319,7 +316,7 @@ static Value *buildMinMaxReductionSeq(Location loc, CmpIPredicate predicate,
// | <code after the AffineForOp> |
// +--------------------------------+
//
bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
static LogicalResult lowerAffineFor(AffineForOp forOp) {
auto loc = forOp.getLoc();
auto *forInst = forOp.getOperation();
@ -356,7 +353,7 @@ bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
auto affDim = builder.getAffineDimExpr(0);
auto stepped = expandAffineExpr(&builder, loc, affDim + affStep, iv, {});
if (!stepped)
return true;
return failure();
// We know we applied a one-dimensional map.
builder.create<BranchOp>(loc, conditionBlock, stepped);
@ -369,7 +366,7 @@ bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
auto lbValues = expandAffineMap(&builder, forInst->getLoc(),
forOp.getLowerBoundMap(), operands);
if (!lbValues)
return true;
return failure();
Value *lowerBound =
buildMinMaxReductionSeq(loc, CmpIPredicate::SGT, *lbValues, builder);
@ -378,7 +375,7 @@ bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
auto ubValues = expandAffineMap(&builder, forInst->getLoc(),
forOp.getUpperBoundMap(), operands);
if (!ubValues)
return true;
return failure();
Value *upperBound =
buildMinMaxReductionSeq(loc, CmpIPredicate::SLT, *ubValues, builder);
builder.create<BranchOp>(loc, conditionBlock, lowerBound);
@ -392,7 +389,7 @@ bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
// Ok, we're done!
forOp.erase();
return false;
return success();
}
// Convert an "if" operation into a flow of basic blocks.
@ -454,7 +451,7 @@ bool LowerAffinePass::lowerAffineFor(AffineForOp forOp) {
// | <code after the AffineIfOp> |
// +--------------------------------+
//
bool LowerAffinePass::lowerAffineIf(AffineIfOp ifOp) {
static LogicalResult lowerAffineIf(AffineIfOp ifOp) {
auto *ifInst = ifOp.getOperation();
auto loc = ifInst->getLoc();
@ -476,7 +473,7 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp ifOp) {
if (!oldThenBlocks.empty()) {
// We currently only handle one 'then' block.
if (std::next(oldThenBlocks.begin()) != oldThenBlocks.end())
return true;
return failure();
Block *oldThen = &oldThenBlocks.front();
@ -495,7 +492,7 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp ifOp) {
if (!oldElseBlocks.empty()) {
// We currently only handle one 'else' block.
if (std::next(oldElseBlocks.begin()) != oldElseBlocks.end())
return true;
return failure();
auto *oldElse = &oldElseBlocks.front();
elseBlock = new Block();
@ -541,7 +538,7 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp ifOp) {
operandsRef.take_front(numDims),
operandsRef.drop_front(numDims));
if (!affResult)
return true;
return failure();
// Compare the result of the apply and branch.
auto comparisonOp = builder.create<CmpIOp>(
@ -566,26 +563,26 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp ifOp) {
// Ok, we're done!
ifInst->erase();
return false;
return success();
}
// Convert an "affine.apply" operation into a sequence of arithmetic
// operations using the StandardOps dialect. Return true on error.
bool LowerAffinePass::lowerAffineApply(AffineApplyOp op) {
static LogicalResult lowerAffineApply(AffineApplyOp op) {
FuncBuilder builder(op.getOperation());
auto maybeExpandedMap =
expandAffineMap(&builder, op.getLoc(), op.getAffineMap(),
llvm::to_vector<8>(op.getOperands()));
if (!maybeExpandedMap)
return true;
return failure();
Value *original = op.getResult();
Value *expanded = (*maybeExpandedMap)[0];
if (!expanded)
return true;
return failure();
original->replaceAllUsesWith(expanded);
op.erase();
return false;
return success();
}
// Entry point of the function convertor.
@ -600,35 +597,37 @@ bool LowerAffinePass::lowerAffineApply(AffineApplyOp op) {
// Individual operations are simply appended to the end of the last basic block
// of the current region. The SESE invariant allows us to easily handle nested
// structures of arbitrary complexity.
//
// During the conversion, we maintain a mapping between the Values present in
// the original function and their Value images in the function under
// construction. When an Value is used, it gets replaced with the
// corresponding Value that has been defined previously. The value flow
// starts with function arguments converted to basic block arguments.
void LowerAffinePass::runOnFunction() {
LogicalResult mlir::lowerAffineConstructs(Function &function) {
SmallVector<Operation *, 8> instsToRewrite;
// Collect all the For operations as well as AffineIfOps and AffineApplyOps.
// We do this as a prepass to avoid invalidating the walker with our rewrite.
getFunction().walk([&](Operation *op) {
function.walk([&](Operation *op) {
if (isa<AffineApplyOp>(op) || isa<AffineForOp>(op) || isa<AffineIfOp>(op))
instsToRewrite.push_back(op);
});
// Rewrite all of the ifs and fors. We walked the operations in postorders,
// Rewrite all of the ifs and fors. We walked the operations in postorder,
// so we know that we will rewrite them in the reverse order.
for (auto *op : llvm::reverse(instsToRewrite)) {
if (auto ifOp = dyn_cast<AffineIfOp>(op)) {
if (lowerAffineIf(ifOp))
return signalPassFailure();
if (failed(lowerAffineIf(ifOp)))
return failure();
} else if (auto forOp = dyn_cast<AffineForOp>(op)) {
if (lowerAffineFor(forOp))
return signalPassFailure();
} else if (lowerAffineApply(cast<AffineApplyOp>(op))) {
return signalPassFailure();
if (failed(lowerAffineFor(forOp)))
return failure();
} else if (failed(lowerAffineApply(cast<AffineApplyOp>(op)))) {
return failure();
}
}
return success();
}
// Run the affine lowering as a function pass.
void LowerAffinePass::runOnFunction() {
if (failed(lowerAffineConstructs(getFunction())))
signalPassFailure();
}
/// Lowers If and For operations within a function into their lower level CFG