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-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/Shape/IR/Shape.h"
|
|
|
|
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
2020-10-17 04:57:24 +08:00
|
|
|
#include "mlir/Dialect/StandardOps/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-10-10 06:03:57 +08:00
|
|
|
mlir::PassPipelineRegistration<RefBackendLoweringPipelineOptions>(
|
|
|
|
"tcf-refback-lowering-pipeline",
|
|
|
|
"RefBackend lowering pipeline, starting from TCF.",
|
|
|
|
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-08-03 13:06:12 +08:00
|
|
|
auto extent =
|
|
|
|
rewriter.create<shape::GetExtentOp>(op.getLoc(), shape, i);
|
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 getDependentDialects(DialectRegistry ®istry) const override {
|
|
|
|
registry.insert<shape::ShapeDialect>();
|
|
|
|
}
|
|
|
|
|
|
|
|
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-08-03 13:06:12 +08:00
|
|
|
target.addLegalOp<shape::GetExtentOp>();
|
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-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-10-16 03:26:21 +08:00
|
|
|
// Bufferize the TCP dialect.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createTCPBufferizePass());
|
2020-11-11 07:14:02 +08:00
|
|
|
pm.addPass(createTensorConstantBufferizePass());
|
[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());
|
2020-09-17 08:31:40 +08:00
|
|
|
// Lower shape ops to std.
|
|
|
|
// TODO: This should in principle be moved before tensor->memref conversion.
|
|
|
|
// But some of the tensor->memref lowerings above use shape.get_extent. For
|
|
|
|
// example, when lowering a broadcast, we need to get an extent from its shape
|
|
|
|
// operand to allocate the output.
|
|
|
|
pm.addPass(createConvertShapeToStandardPass());
|
2020-10-28 03:03:12 +08:00
|
|
|
|
|
|
|
// Run some upstream bufferization passes to finish bufferization.
|
2020-11-11 13:38:13 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createStdBufferizePass());
|
|
|
|
pm.addNestedPass<FuncOp>(createSCFBufferizePass());
|
2020-11-14 07:34:24 +08:00
|
|
|
pm.addNestedPass<FuncOp>(createLinalgBufferizePass());
|
2020-10-28 03:03:12 +08:00
|
|
|
pm.addPass(createFuncBufferizePass());
|
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.
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
void mlir::NPCOMP::createTCFRefBackendLoweringPipeline(
|
|
|
|
OpPassManager &pm, const RefBackendLoweringPipelineOptions &options) {
|
2020-11-07 09:17:28 +08:00
|
|
|
|
2020-10-10 06:03:57 +08:00
|
|
|
// Convert from TCF to TCP.
|
|
|
|
//
|
|
|
|
// TCF has implicit broadcasting, and issues errors "inside the ops" in the
|
|
|
|
// case of invalid broadcasts.
|
|
|
|
//
|
|
|
|
// TCP does not. So we need to reify the broadcasting and error checking.
|
2020-11-11 13:38:13 +08:00
|
|
|
// These all run at the module level.
|
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
|
|
|
|
|
|
|
createRefBackendLoweringPipeline(pm, options);
|
|
|
|
}
|