[mlir] Async: lower SCF operations into CFG inside coroutines

Reviewed By: mehdi_amini

Differential Revision: https://reviews.llvm.org/D106747
This commit is contained in:
Eugene Zhulenev
2021-07-24 06:51:15 -07:00
parent c63dbd8501
commit de7a4e53a2
4 changed files with 59 additions and 1 deletions

View File

@@ -12,8 +12,10 @@
//===----------------------------------------------------------------------===//
#include "PassDetail.h"
#include "mlir/Conversion/SCFToStandard/SCFToStandard.h"
#include "mlir/Dialect/Async/IR/Async.h"
#include "mlir/Dialect/Async/Passes.h"
#include "mlir/Dialect/SCF/SCF.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/BlockAndValueMapping.h"
#include "mlir/IR/ImplicitLocOpBuilder.h"
@@ -571,10 +573,22 @@ void AsyncToAsyncRuntimePass::runOnOperation() {
<< " functions built from async.execute operations\n";
});
// Returns true if operation is inside the coroutine.
auto isInCoroutine = [&](Operation *op) -> bool {
auto parentFunc = op->getParentOfType<FuncOp>();
return outlinedFunctions.find(parentFunc) != outlinedFunctions.end();
};
// Lower async operations to async.runtime operations.
MLIRContext *ctx = module->getContext();
RewritePatternSet asyncPatterns(ctx);
// Conversion to async runtime augments original CFG with the coroutine CFG,
// and we have to make sure that structured control flow operations with async
// operations in nested regions will be converted to branch-based control flow
// before we add the coroutine basic blocks.
populateLoopToStdConversionPatterns(asyncPatterns);
// Async lowering does not use type converter because it must preserve all
// types for async.runtime operations.
asyncPatterns.add<CreateGroupOpLowering, AddToGroupOpLowering>(ctx);
@@ -591,12 +605,22 @@ void AsyncToAsyncRuntimePass::runOnOperation() {
runtimeTarget.addIllegalOp<CreateGroupOp, AddToGroupOp>();
runtimeTarget.addIllegalOp<ExecuteOp, AwaitOp, AwaitAllOp, async::YieldOp>();
// Decide if structured control flow has to be lowered to branch-based CFG.
runtimeTarget.addDynamicallyLegalDialect<scf::SCFDialect>([&](Operation *op) {
auto walkResult = op->walk([&](Operation *nested) {
bool isAsync = isa<async::AsyncDialect>(nested->getDialect());
return isAsync && isInCoroutine(nested) ? WalkResult::interrupt()
: WalkResult::advance();
});
return !walkResult.wasInterrupted();
});
runtimeTarget.addLegalOp<BranchOp, CondBranchOp>();
// Assertions must be converted to runtime errors inside async functions.
runtimeTarget.addDynamicallyLegalOp<AssertOp>([&](AssertOp op) -> bool {
auto func = op->getParentOfType<FuncOp>();
return outlinedFunctions.find(func) == outlinedFunctions.end();
});
runtimeTarget.addLegalOp<CondBranchOp>();
if (failed(applyPartialConversion(module, runtimeTarget,
std::move(asyncPatterns)))) {