forked from OSchip/llvm-project
[MLIR][SCF] Inline single block ExecuteRegionOp
This commit adds a canonicalization pass which inlines any single block execute region Differential Revision: https://reviews.llvm.org/D104865
This commit is contained in:
parent
3ba090e5f6
commit
44985872b8
|
@ -111,7 +111,7 @@ def ExecuteRegionOp : SCF_Op<"execute_region"> {
|
||||||
// TODO: If the parent is a func like op (which would be the case if all other
|
// TODO: If the parent is a func like op (which would be the case if all other
|
||||||
// ops are from the std dialect), the inliner logic could be readily used to
|
// ops are from the std dialect), the inliner logic could be readily used to
|
||||||
// inline.
|
// inline.
|
||||||
let hasCanonicalizer = 0;
|
let hasCanonicalizer = 1;
|
||||||
|
|
||||||
// TODO: can fold if it returns a constant.
|
// TODO: can fold if it returns a constant.
|
||||||
// TODO: Single block execute_region ops can be readily inlined irrespective
|
// TODO: Single block execute_region ops can be readily inlined irrespective
|
||||||
|
|
|
@ -73,6 +73,19 @@ void mlir::scf::buildTerminatedBody(OpBuilder &builder, Location loc) {
|
||||||
// ExecuteRegionOp
|
// ExecuteRegionOp
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// Replaces the given op with the contents of the given single-block region,
|
||||||
|
/// using the operands of the block terminator to replace operation results.
|
||||||
|
static void replaceOpWithRegion(PatternRewriter &rewriter, Operation *op,
|
||||||
|
Region ®ion, ValueRange blockArgs = {}) {
|
||||||
|
assert(llvm::hasSingleElement(region) && "expected single-region block");
|
||||||
|
Block *block = ®ion.front();
|
||||||
|
Operation *terminator = block->getTerminator();
|
||||||
|
ValueRange results = terminator->getOperands();
|
||||||
|
rewriter.mergeBlockBefore(block, op, blockArgs);
|
||||||
|
rewriter.replaceOp(op, results);
|
||||||
|
rewriter.eraseOp(terminator);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// (ssa-id `=`)? `execute_region` `->` function-result-type `{`
|
/// (ssa-id `=`)? `execute_region` `->` function-result-type `{`
|
||||||
/// block+
|
/// block+
|
||||||
|
@ -118,6 +131,37 @@ static LogicalResult verify(ExecuteRegionOp op) {
|
||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inline an ExecuteRegionOp if it only contains one block.
|
||||||
|
// "test.foo"() : () -> ()
|
||||||
|
// %v = scf.execute_region -> i64 {
|
||||||
|
// %x = "test.val"() : () -> i64
|
||||||
|
// scf.yield %x : i64
|
||||||
|
// }
|
||||||
|
// "test.bar"(%v) : (i64) -> ()
|
||||||
|
//
|
||||||
|
// becomes
|
||||||
|
//
|
||||||
|
// "test.foo"() : () -> ()
|
||||||
|
// %x = "test.val"() : () -> i64
|
||||||
|
// "test.bar"(%v) : (i64) -> ()
|
||||||
|
//
|
||||||
|
struct SingleBlockExecuteInliner : public OpRewritePattern<ExecuteRegionOp> {
|
||||||
|
using OpRewritePattern<ExecuteRegionOp>::OpRewritePattern;
|
||||||
|
|
||||||
|
LogicalResult matchAndRewrite(ExecuteRegionOp op,
|
||||||
|
PatternRewriter &rewriter) const override {
|
||||||
|
if (op.region().getBlocks().size() != 1)
|
||||||
|
return failure();
|
||||||
|
replaceOpWithRegion(rewriter, op, op.region());
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ExecuteRegionOp::getCanonicalizationPatterns(RewritePatternSet &results,
|
||||||
|
MLIRContext *context) {
|
||||||
|
results.add<SingleBlockExecuteInliner>(context);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ForOp
|
// ForOp
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -444,19 +488,6 @@ LoopNest mlir::scf::buildLoopNest(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the given op with the contents of the given single-block region,
|
|
||||||
/// using the operands of the block terminator to replace operation results.
|
|
||||||
static void replaceOpWithRegion(PatternRewriter &rewriter, Operation *op,
|
|
||||||
Region ®ion, ValueRange blockArgs = {}) {
|
|
||||||
assert(llvm::hasSingleElement(region) && "expected single-region block");
|
|
||||||
Block *block = ®ion.front();
|
|
||||||
Operation *terminator = block->getTerminator();
|
|
||||||
ValueRange results = terminator->getOperands();
|
|
||||||
rewriter.mergeBlockBefore(block, op, blockArgs);
|
|
||||||
rewriter.replaceOp(op, results);
|
|
||||||
rewriter.eraseOp(terminator);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Fold away ForOp iter arguments when:
|
// Fold away ForOp iter arguments when:
|
||||||
// 1) The op yields the iter arguments.
|
// 1) The op yields the iter arguments.
|
||||||
|
|
|
@ -921,9 +921,30 @@ func @propagate_into_execute_region() {
|
||||||
}
|
}
|
||||||
"test.bar"(%v) : (i64) -> ()
|
"test.bar"(%v) : (i64) -> ()
|
||||||
// CHECK: %[[C2:.*]] = constant 2 : i64
|
// CHECK: %[[C2:.*]] = constant 2 : i64
|
||||||
// CHECK: scf.execute_region -> i64 {
|
// CHECK: "test.foo"
|
||||||
// CHECK-NEXT: scf.yield %[[C2]] : i64
|
// CHECK-NEXT: "test.bar"(%[[C2]]) : (i64) -> ()
|
||||||
// CHECK-NEXT: }
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
// CHECK-LABEL: func @execute_region_elim
|
||||||
|
func @execute_region_elim() {
|
||||||
|
affine.for %i = 0 to 100 {
|
||||||
|
"test.foo"() : () -> ()
|
||||||
|
%v = scf.execute_region -> i64 {
|
||||||
|
%x = "test.val"() : () -> i64
|
||||||
|
scf.yield %x : i64
|
||||||
|
}
|
||||||
|
"test.bar"(%v) : (i64) -> ()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-NEXT: affine.for %arg0 = 0 to 100 {
|
||||||
|
// CHECK-NEXT: "test.foo"() : () -> ()
|
||||||
|
// CHECK-NEXT: %[[VAL:.*]] = "test.val"() : () -> i64
|
||||||
|
// CHECK-NEXT: "test.bar"(%[[VAL]]) : (i64) -> ()
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue