2020-05-07 09:41:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2020-10-10 06:03:57 +08:00
|
|
|
// This is the base file for npcomp's "reference backend".
|
|
|
|
//
|
|
|
|
// The input to this backend is a layer that we call "TCP" + a mix of scalar
|
|
|
|
// ops. TCP is currently a concrete dialect, but more generally it refers to a
|
|
|
|
// layer of the compilation stack consisting of named ops on entire tensors,
|
|
|
|
// with their preconditions checked. For example, a "matmul" op that assumes
|
|
|
|
// that the contracting ("k") dimensions of both operands are equal. Earlier
|
|
|
|
// code in the compilation stack should ensure that these preconditions are met
|
|
|
|
// (such as during TCF->TCP lowering).
|
|
|
|
//
|
|
|
|
// The output of this backend is LLVM IR suitable for JITing.
|
|
|
|
//
|
|
|
|
// We expect that other backends will appear that have a similar kind of
|
|
|
|
// interface (TCP + scalar ops ---> LLVM IR / other "executable").
|
2020-05-07 09:41:54 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-10-07 07:14:37 +08:00
|
|
|
#include "npcomp/RefBackend/RefBackend.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
#include "PassDetail.h"
|
|
|
|
|
2020-12-16 04:53:12 +08:00
|
|
|
#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"
|
2020-05-22 04:09:06 +08:00
|
|
|
#include "mlir/Conversion/SCFToStandard/SCFToStandard.h"
|
2020-09-17 08:31:40 +08:00
|
|
|
#include "mlir/Conversion/ShapeToStandard/ShapeToStandard.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
|
|
|
|
#include "mlir/Dialect/Linalg/IR/LinalgTypes.h"
|
2020-05-12 09:50:51 +08:00
|
|
|
#include "mlir/Dialect/Linalg/Passes.h"
|
2020-10-27 07:53:23 +08:00
|
|
|
#include "mlir/Dialect/SCF/Passes.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
2020-10-17 04:57:24 +08:00
|
|
|
#include "mlir/Dialect/StandardOps/Transforms/Passes.h"
|
2020-12-12 06:43:38 +08:00
|
|
|
#include "mlir/Dialect/Tensor/IR/Tensor.h"
|
|
|
|
#include "mlir/Dialect/Tensor/Transforms/Passes.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
#include "mlir/Pass/Pass.h"
|
|
|
|
#include "mlir/Pass/PassRegistry.h"
|
|
|
|
#include "mlir/Transforms/DialectConversion.h"
|
2020-10-30 06:25:55 +08:00
|
|
|
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
|
2020-05-12 06:27:37 +08:00
|
|
|
#include "mlir/Transforms/Passes.h"
|
2020-11-10 07:49:22 +08:00
|
|
|
#include "npcomp/Conversion/TCFToLinalg/TCFToLinalg.h"
|
2020-11-07 09:17:28 +08:00
|
|
|
#include "npcomp/Conversion/TCFToStd/TCFToStd.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
#include "npcomp/Conversion/TCFToTCP/TCFToTCP.h"
|
2020-10-08 08:30:10 +08:00
|
|
|
#include "npcomp/Dialect/Refback/IR/RefbackOps.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
#include "npcomp/Dialect/TCP/IR/TCPDialect.h"
|
|
|
|
#include "npcomp/Dialect/TCP/IR/TCPOps.h"
|
2020-10-16 03:26:21 +08:00
|
|
|
#include "npcomp/Dialect/TCP/Transforms/Passes.h"
|
2020-05-07 09:41:54 +08:00
|
|
|
|
|
|
|
using namespace mlir;
|
|
|
|
using namespace mlir::NPCOMP;
|
|
|
|
|
2020-08-28 06:09:10 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Pass registration
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
#define GEN_PASS_REGISTRATION
|
2020-10-07 07:14:37 +08:00
|
|
|
#include "npcomp/RefBackend/Passes.h.inc"
|
2020-08-28 06:09:10 +08:00
|
|
|
} // end namespace
|
|
|
|
|
2020-10-07 07:14:37 +08:00
|
|
|
void mlir::NPCOMP::registerRefBackendPasses() {
|
2020-08-28 06:09:10 +08:00
|
|
|
::registerPasses();
|
|
|
|
|
2020-10-07 07:14:37 +08:00
|
|
|
mlir::PassPipelineRegistration<RefBackendLoweringPipelineOptions>(
|
|
|
|
"refback-lowering-pipeline", "RefBackend lowering pipeline.",
|
|
|
|
mlir::NPCOMP::createRefBackendLoweringPipeline);
|
2020-11-18 03:59:18 +08:00
|
|
|
// TODO: Move this out of RefBackend once the TCF->TCP conversions
|
|
|
|
// become more substantial.
|
|
|
|
mlir::PassPipelineRegistration<RefBackendLoweringPipelineOptions>(
|
|
|
|
"refback-tcf-to-tcp-pipeline",
|
|
|
|
"RefBackend lowering pipeline converting TCF ops to TCP-level ops (not "
|
|
|
|
"just TCP dialect).",
|
|
|
|
mlir::NPCOMP::createRefBackendTCFToTCPPipeline);
|
2020-10-10 06:03:57 +08:00
|
|
|
mlir::PassPipelineRegistration<RefBackendLoweringPipelineOptions>(
|
|
|
|
"tcf-refback-lowering-pipeline",
|
2020-11-18 03:59:18 +08:00
|
|
|
"RefBackend lowering pipeline, starting from TCF. (equivalent to "
|
|
|
|
"refback-tcf-to-tcp-pipeline + refback-lowering-pipeline)",
|
2020-10-10 06:03:57 +08:00
|
|
|
mlir::NPCOMP::createTCFRefBackendLoweringPipeline);
|
2020-05-12 09:50:51 +08:00
|
|
|
}
|
|
|
|
|
2020-05-19 03:50:16 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LowerAllocMemRefOps
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
[RefBackend] Split out RefBackend (refback) dialect from TCP.
This is the first in a patch series that is refactoring the
constellation of things variously called or associated with "E2E",
"RefE2E", "npcomprt", and "TCP" into a more cleanly layered result.
Concretely, this first patch fixes the fact that TCP was basically
acting like a dumping ground needed by the reference backend. This
splits it out, which is fairly mechanical, but touches a lot of lines of
code (basically replacing `tcp` with `refback` and `TCP` with
`RefBackend).
Now, the RefBackend dialect is that dumping ground, which
is slighly better, as it starts allowing TCP to become a nice clean
middle layer that is not related per se to the reference backend.
The previous name RefE2E or "reference e2e flow" was super confusing.
Now that we are seeing more clearly where the "backend" distinction
lies, the [RefBackend] commit tag is born :)
2020-10-07 06:44:18 +08:00
|
|
|
class LowerAllocMemRefOp : public OpRewritePattern<refback::AllocMemRefOp> {
|
2020-05-19 03:50:16 +08:00
|
|
|
public:
|
|
|
|
using OpRewritePattern::OpRewritePattern;
|
[RefBackend] Split out RefBackend (refback) dialect from TCP.
This is the first in a patch series that is refactoring the
constellation of things variously called or associated with "E2E",
"RefE2E", "npcomprt", and "TCP" into a more cleanly layered result.
Concretely, this first patch fixes the fact that TCP was basically
acting like a dumping ground needed by the reference backend. This
splits it out, which is fairly mechanical, but touches a lot of lines of
code (basically replacing `tcp` with `refback` and `TCP` with
`RefBackend).
Now, the RefBackend dialect is that dumping ground, which
is slighly better, as it starts allowing TCP to become a nice clean
middle layer that is not related per se to the reference backend.
The previous name RefE2E or "reference e2e flow" was super confusing.
Now that we are seeing more clearly where the "backend" distinction
lies, the [RefBackend] commit tag is born :)
2020-10-07 06:44:18 +08:00
|
|
|
LogicalResult matchAndRewrite(refback::AllocMemRefOp op,
|
2020-05-19 03:50:16 +08:00
|
|
|
PatternRewriter &rewriter) const override {
|
|
|
|
auto memrefType = op.getType().cast<MemRefType>();
|
|
|
|
auto shape = op.getOperand();
|
|
|
|
// std.alloc only accepts the dynamic extents as operands, so only
|
|
|
|
// collect those.
|
|
|
|
SmallVector<Value, 6> dynamicExtents;
|
|
|
|
for (int i = 0, e = memrefType.getRank(); i < e; i++) {
|
|
|
|
if (memrefType.isDynamicDim(i)) {
|
2020-11-17 05:26:13 +08:00
|
|
|
auto ci = rewriter.create<ConstantIndexOp>(op.getLoc(), i);
|
2020-12-12 06:43:38 +08:00
|
|
|
auto extent = rewriter.create<tensor::ExtractOp>(op.getLoc(), shape,
|
|
|
|
ValueRange({ci}));
|
2020-05-19 03:50:16 +08:00
|
|
|
dynamicExtents.push_back(extent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rewriter.replaceOpWithNewOp<AllocOp>(op, memrefType, dynamicExtents);
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LowerAllocMemRefOps
|
|
|
|
: public LowerAllocMemRefOpsBase<LowerAllocMemRefOps> {
|
2020-09-10 15:23:46 +08:00
|
|
|
|
|
|
|
void runOnOperation() override {
|
2020-05-19 03:50:16 +08:00
|
|
|
auto func = getOperation();
|
|
|
|
auto *context = &getContext();
|
|
|
|
OwningRewritePatternList patterns;
|
|
|
|
patterns.insert<LowerAllocMemRefOp>(context);
|
|
|
|
ConversionTarget target(*context);
|
[RefBackend] Split out RefBackend (refback) dialect from TCP.
This is the first in a patch series that is refactoring the
constellation of things variously called or associated with "E2E",
"RefE2E", "npcomprt", and "TCP" into a more cleanly layered result.
Concretely, this first patch fixes the fact that TCP was basically
acting like a dumping ground needed by the reference backend. This
splits it out, which is fairly mechanical, but touches a lot of lines of
code (basically replacing `tcp` with `refback` and `TCP` with
`RefBackend).
Now, the RefBackend dialect is that dumping ground, which
is slighly better, as it starts allowing TCP to become a nice clean
middle layer that is not related per se to the reference backend.
The previous name RefE2E or "reference e2e flow" was super confusing.
Now that we are seeing more clearly where the "backend" distinction
lies, the [RefBackend] commit tag is born :)
2020-10-07 06:44:18 +08:00
|
|
|
target.addIllegalOp<refback::AllocMemRefOp>();
|
2020-12-12 06:43:38 +08:00
|
|
|
target.addLegalOp<tensor::ExtractOp>();
|
2020-05-19 03:50:16 +08:00
|
|
|
target.addLegalOp<AllocOp>();
|
2020-08-03 13:06:12 +08:00
|
|
|
target.addLegalOp<ConstantOp>();
|
2020-10-30 06:25:55 +08:00
|
|
|
if (failed(applyPartialConversion(func, target, std::move(patterns)))) {
|
2020-05-19 03:50:16 +08:00
|
|
|
return signalPassFailure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
std::unique_ptr<OperationPass<FuncOp>>
|
|
|
|
mlir::NPCOMP::createLowerAllocMemRefOpsPass() {
|
|
|
|
return std::make_unique<LowerAllocMemRefOps>();
|
|
|
|
}
|
|
|
|
|
2020-09-26 07:02:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// RestrictedCanonicalizer
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
struct RestrictedCanonicalizer
|
|
|
|
: public RestrictedCanonicalizerBase<RestrictedCanonicalizer> {
|
|
|
|
void runOnOperation() override {
|
|
|
|
auto *context = &getContext();
|
|
|
|
|
|
|
|
// Find the dialects from their names.
|
|
|
|
DenseSet<StringRef> neededDialects;
|
|
|
|
for (const std::string &dialectName : includedDialects)
|
|
|
|
neededDialects.insert(dialectName);
|
|
|
|
DenseSet<Dialect *> dialectsToCanonicalize;
|
|
|
|
for (Dialect *dialect : context->getLoadedDialects()) {
|
|
|
|
if (neededDialects.count(dialect->getNamespace())) {
|
|
|
|
dialectsToCanonicalize.insert(dialect);
|
|
|
|
// Erase the dialect so that we can report an error below for any
|
|
|
|
// dialect names that are not loaded.
|
|
|
|
neededDialects.erase(dialect->getNamespace());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report a helpful error if a dialect is not found.
|
|
|
|
auto missingDialects = llvm::to_vector<6>(neededDialects);
|
|
|
|
if (!missingDialects.empty()) {
|
|
|
|
llvm::sort(missingDialects);
|
|
|
|
std::string buf;
|
|
|
|
llvm::raw_string_ostream os(buf);
|
|
|
|
llvm::interleaveComma(missingDialects, os);
|
|
|
|
llvm::report_fatal_error("restricted-canonicalize: unknown dialects: " +
|
|
|
|
os.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collect all canonicalization patterns from ops in the included dialects.
|
|
|
|
OwningRewritePatternList patterns;
|
|
|
|
for (AbstractOperation *op : context->getRegisteredOperations())
|
|
|
|
if (dialectsToCanonicalize.count(&op->dialect))
|
|
|
|
op->getCanonicalizationPatterns(patterns, context);
|
|
|
|
|
|
|
|
Operation *op = getOperation();
|
2020-10-30 06:25:55 +08:00
|
|
|
applyPatternsAndFoldGreedily(op->getRegions(), std::move(patterns));
|
2020-09-26 07:02:09 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
std::unique_ptr<Pass> mlir::NPCOMP::createRestrictedCanonicalizerPass() {
|
|
|
|
return std::make_unique<RestrictedCanonicalizer>();
|
|
|
|
}
|
|
|
|
|
2020-05-07 09:41:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2020-10-07 07:14:37 +08:00
|
|
|
// createRefBackendLoweringPipeline
|
2020-05-07 09:41:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-10-07 07:14:37 +08:00
|
|
|
void mlir::NPCOMP::createRefBackendLoweringPipeline(
|
|
|
|
OpPassManager &pm, const RefBackendLoweringPipelineOptions &options) {
|
2020-11-07 09:17:28 +08:00
|
|
|
|
|
|
|
// Convert all elementwise ops to linalg.
|
|
|
|
//
|
|
|
|
// Considering correctness, this lets us reuse the linalg bufferization, which
|
|
|
|
// applies uniformly to all linalg structured ops.
|
|
|
|
//
|
|
|
|
// Also, converting to linalg herevopens up a lot of optimization
|
|
|
|
// opportunities.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createConvertElementwiseToLinalgPass());
|
2020-11-07 09:17:28 +08:00
|
|
|
|
|
|
|
if (options.optimize) {
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createLinalgFusionOfTensorOpsPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createCanonicalizerPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createCSEPass());
|
2020-11-07 09:17:28 +08:00
|
|
|
}
|
|
|
|
|
2020-09-17 08:31:40 +08:00
|
|
|
// Lower shape constraints before we enter tensor->memref conversion.
|
2020-09-26 07:02:09 +08:00
|
|
|
// That is, we expand shape.cstr_* ops to eager error handling code.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createConvertShapeConstraintsPass());
|
2020-09-26 07:02:09 +08:00
|
|
|
// Run shape canonicalizations. In particular, this erases shape.assuming,
|
|
|
|
// now that we have converted shape constraints.
|
|
|
|
// TODO: This is kind of ugly. Either we use pass options or a constructor
|
|
|
|
// that takes C++ data structures. The former makes the pass usable on the
|
|
|
|
// command line (including reproducers), the latter makes the pass more
|
|
|
|
// convenient.
|
|
|
|
std::unique_ptr<Pass> shapeCanonicalizer =
|
|
|
|
createRestrictedCanonicalizerPass();
|
|
|
|
if (failed(shapeCanonicalizer->initializeOptions("included-dialects=shape")))
|
|
|
|
llvm::report_fatal_error("couldn't initialize restricted-canonicalize");
|
|
|
|
pm.addPass(std::move(shapeCanonicalizer));
|
2020-05-07 09:41:54 +08:00
|
|
|
|
2020-11-17 05:26:13 +08:00
|
|
|
// Lower shape ops to std.
|
|
|
|
pm.addPass(createConvertShapeToStandardPass());
|
|
|
|
|
2020-09-17 08:31:40 +08:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// Lower the `tensor` type to `memref`.
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// We make a conscious effort here to do this as a sequence of separate passes
|
|
|
|
// rather than a single mega dialect conversion pass.
|
2020-05-12 05:24:57 +08:00
|
|
|
//
|
2020-09-17 08:31:40 +08:00
|
|
|
// This means that intermediate steps have source/target materializations
|
2020-10-15 10:28:43 +08:00
|
|
|
// (tensor_load / tensor_to_memref) in the IR.
|
2020-09-17 08:31:40 +08:00
|
|
|
|
2020-11-17 05:26:13 +08:00
|
|
|
// Run tensor constant bufferization.
|
|
|
|
// This pass has to run on a module op, and so does the final
|
|
|
|
// FuncBufferizePass. But everything else can run in parallel on functions,
|
|
|
|
// so we try to bracket the entire bufferization pipeline with the module
|
|
|
|
// passes to allow maximum parallelism.
|
2020-11-11 07:14:02 +08:00
|
|
|
pm.addPass(createTensorConstantBufferizePass());
|
2020-11-17 05:26:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createTCPBufferizePass());
|
[RefBackend] Split out RefBackend (refback) dialect from TCP.
This is the first in a patch series that is refactoring the
constellation of things variously called or associated with "E2E",
"RefE2E", "npcomprt", and "TCP" into a more cleanly layered result.
Concretely, this first patch fixes the fact that TCP was basically
acting like a dumping ground needed by the reference backend. This
splits it out, which is fairly mechanical, but touches a lot of lines of
code (basically replacing `tcp` with `refback` and `TCP` with
`RefBackend).
Now, the RefBackend dialect is that dumping ground, which
is slighly better, as it starts allowing TCP to become a nice clean
middle layer that is not related per se to the reference backend.
The previous name RefE2E or "reference e2e flow" was super confusing.
Now that we are seeing more clearly where the "backend" distinction
lies, the [RefBackend] commit tag is born :)
2020-10-07 06:44:18 +08:00
|
|
|
// refback::AllocMemRefOp takes a shape (i.e. extent tensor) as an argument.
|
|
|
|
// We need to resolve this to std.alloc which takes individual extents.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createLowerAllocMemRefOpsPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createSCFBufferizePass());
|
2020-11-14 07:34:24 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createLinalgBufferizePass());
|
2020-12-01 10:40:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createStdBufferizePass());
|
2020-12-12 06:43:38 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createTensorBufferizePass());
|
2020-10-28 03:03:12 +08:00
|
|
|
pm.addPass(createFuncBufferizePass());
|
2020-12-01 05:55:29 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createFinalizingBufferizePass());
|
2020-05-16 07:33:01 +08:00
|
|
|
|
2020-10-28 03:03:12 +08:00
|
|
|
// TODO: Do buffer deallocation. We should be able to just drop in the
|
|
|
|
// upstream pass?
|
2020-05-07 09:41:54 +08:00
|
|
|
|
2020-09-17 08:31:40 +08:00
|
|
|
// At this point, we have lots of loose stuff floating around from lowering,
|
|
|
|
// so it's a good time to do some general cleanups.
|
2020-06-02 10:30:13 +08:00
|
|
|
if (options.optimize) {
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createCanonicalizerPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createCSEPass());
|
2020-06-02 10:30:13 +08:00
|
|
|
}
|
2020-05-12 06:27:37 +08:00
|
|
|
|
2020-05-12 09:50:51 +08:00
|
|
|
// --------------------------------------------------------------------------
|
2020-05-21 09:48:53 +08:00
|
|
|
// Preparation for converting to an LLVM module.
|
2020-05-12 09:50:51 +08:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// Now, we begin the process of lowering to LLVM's level of abstraction
|
|
|
|
// (after which LLVM will take over lowering to machine code).
|
|
|
|
|
|
|
|
// Lower linalg ops to loops.
|
|
|
|
// TODO: Do some linalg optimizations like tiling here.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createConvertLinalgToLoopsPass());
|
2020-05-12 09:50:51 +08:00
|
|
|
|
2020-07-14 07:15:42 +08:00
|
|
|
// Run a some cleanups.
|
2020-06-02 10:30:13 +08:00
|
|
|
if (options.optimize) {
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createCanonicalizerPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createCSEPass());
|
2020-06-02 10:30:13 +08:00
|
|
|
}
|
2020-05-21 09:48:53 +08:00
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// Final conversion to an LLVM module.
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
2020-12-16 04:53:12 +08:00
|
|
|
// Convert affine to std control flow in preparation for going to LLVM.
|
|
|
|
pm.addNestedPass<FuncOp>(createLowerAffinePass());
|
|
|
|
|
2020-05-21 09:48:53 +08:00
|
|
|
// Convert scf to std control flow in preparation for going to LLVM.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createLowerToCFGPass());
|
2020-05-21 09:48:53 +08:00
|
|
|
|
2020-09-17 08:31:40 +08:00
|
|
|
// Convert functions signatures and other constructs that interface with the
|
2020-10-08 08:12:52 +08:00
|
|
|
// runtime to the `refbackrt` dialect.
|
|
|
|
pm.addPass(createLowerToRefbackrtABIPass());
|
2020-09-17 08:31:40 +08:00
|
|
|
|
2020-05-21 09:48:53 +08:00
|
|
|
// Finally, convert to LLVM dialect using our custom LowerToLLVM pass
|
|
|
|
// which reuses the upstream patterns and gives us a place to add our own
|
2020-10-08 08:12:52 +08:00
|
|
|
// patterns for our own custom ops like the refbackrt ops.
|
2020-05-21 09:48:53 +08:00
|
|
|
pm.addPass(createLowerToLLVMPass());
|
2020-07-14 07:15:42 +08:00
|
|
|
|
|
|
|
// Although LLVM will clean everything up eventually, for the sake of IR
|
|
|
|
// clarity while still in MLIR, run some cleanups.
|
|
|
|
if (options.optimize) {
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createCanonicalizerPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createCSEPass());
|
2020-07-14 07:15:42 +08:00
|
|
|
}
|
2020-05-07 09:41:54 +08:00
|
|
|
}
|
2020-10-10 06:03:57 +08:00
|
|
|
|
2020-11-18 03:59:18 +08:00
|
|
|
void mlir::NPCOMP::createRefBackendTCFToTCPPipeline(
|
2020-10-10 06:03:57 +08:00
|
|
|
OpPassManager &pm, const RefBackendLoweringPipelineOptions &options) {
|
2020-11-18 03:59:18 +08:00
|
|
|
// Convert from TCF dialect to TCP-level ops.
|
2020-10-10 06:03:57 +08:00
|
|
|
//
|
|
|
|
// TCF has implicit broadcasting, and issues errors "inside the ops" in the
|
|
|
|
// case of invalid broadcasts.
|
|
|
|
//
|
2020-11-18 03:59:18 +08:00
|
|
|
// TCP-level ops do not. So we need to reify the broadcasting and error
|
|
|
|
// checking.
|
|
|
|
//
|
|
|
|
// Note that TCP-level ops includes ops outside the TCP dialect itself, such
|
|
|
|
// as std elementwise ops on tensors and linalg ops on tensors.
|
2020-11-14 07:34:24 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createConvertTCFToStdPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createConvertTCFToLinalgPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createConvertTCFToTCPPass());
|
2020-10-10 06:03:57 +08:00
|
|
|
|
2020-11-18 03:59:18 +08:00
|
|
|
if (options.optimize) {
|
|
|
|
pm.addNestedPass<FuncOp>(createCanonicalizerPass());
|
|
|
|
pm.addNestedPass<FuncOp>(createCSEPass());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mlir::NPCOMP::createTCFRefBackendLoweringPipeline(
|
|
|
|
OpPassManager &pm, const RefBackendLoweringPipelineOptions &options) {
|
|
|
|
createRefBackendTCFToTCPPipeline(pm, options);
|
2020-10-10 06:03:57 +08:00
|
|
|
createRefBackendLoweringPipeline(pm, options);
|
|
|
|
}
|