2020-09-17 08:31:40 +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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "../PassDetail.h"
|
2020-10-07 07:14:37 +08:00
|
|
|
#include "npcomp/RefBackend/RefBackend.h"
|
2020-09-17 08:31:40 +08:00
|
|
|
|
|
|
|
#include "mlir/Dialect/SCF/SCF.h"
|
|
|
|
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
|
|
|
#include "mlir/Pass/Pass.h"
|
|
|
|
#include "mlir/Pass/PassRegistry.h"
|
|
|
|
#include "mlir/Transforms/DialectConversion.h"
|
2020-10-08 08:30:10 +08:00
|
|
|
#include "npcomp/Dialect/Refback/IR/RefbackOps.h"
|
2020-09-17 08:31:40 +08:00
|
|
|
|
|
|
|
using namespace mlir;
|
|
|
|
using namespace mlir::NPCOMP;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Generic "update the types according to the type converter" patterns.
|
|
|
|
//
|
|
|
|
// TODO: These should be upstreamed. There's nothing specific to memref type
|
|
|
|
// conversion about them.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// This is a type conversion similar to CallOpSignatureConversion.
|
|
|
|
class LowerIfOpTypes : public OpConversionPattern<scf::IfOp> {
|
|
|
|
public:
|
|
|
|
using OpConversionPattern::OpConversionPattern;
|
|
|
|
LogicalResult
|
|
|
|
matchAndRewrite(scf::IfOp op, ArrayRef<Value> operands,
|
|
|
|
ConversionPatternRewriter &rewriter) const override {
|
|
|
|
SmallVector<Type, 6> newResultTypes;
|
|
|
|
for (auto type : op.getResultTypes()) {
|
|
|
|
Type newType = typeConverter->convertType(type);
|
|
|
|
if (!newType)
|
|
|
|
return rewriter.notifyMatchFailure(op, "not a 1:1 type conversion");
|
|
|
|
newResultTypes.push_back(newType);
|
|
|
|
}
|
|
|
|
rewriter.updateRootInPlace(op, [&] {
|
|
|
|
for (auto t : llvm::zip(op.getResults(), newResultTypes))
|
|
|
|
std::get<0>(t).setType(std::get<1>(t));
|
|
|
|
});
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2020-09-19 05:49:04 +08:00
|
|
|
namespace {
|
|
|
|
// This is a type conversion similar to CallOpSignatureConversion.
|
|
|
|
class LowerForOpTypes : public OpConversionPattern<scf::ForOp> {
|
|
|
|
public:
|
|
|
|
using OpConversionPattern::OpConversionPattern;
|
|
|
|
LogicalResult
|
|
|
|
matchAndRewrite(scf::ForOp op, ArrayRef<Value> operands,
|
|
|
|
ConversionPatternRewriter &rewriter) const override {
|
|
|
|
SmallVector<Type, 6> newResultTypes;
|
|
|
|
for (auto type : op.getResultTypes()) {
|
|
|
|
Type newType = typeConverter->convertType(type);
|
|
|
|
if (!newType)
|
|
|
|
return rewriter.notifyMatchFailure(op, "not a 1:1 type conversion");
|
|
|
|
newResultTypes.push_back(newType);
|
|
|
|
}
|
|
|
|
rewriter.updateRootInPlace(op, [&] {
|
|
|
|
for (auto t : llvm::zip(op.getResults(), newResultTypes))
|
|
|
|
std::get<0>(t).setType(std::get<1>(t));
|
|
|
|
auto bodyArgs = op.getBody()->getArguments();
|
|
|
|
for (auto t : llvm::zip(llvm::drop_begin(bodyArgs, 1), newResultTypes))
|
|
|
|
std::get<0>(t).setType(std::get<1>(t));
|
|
|
|
});
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2020-09-17 08:31:40 +08:00
|
|
|
namespace {
|
|
|
|
// This is a type conversion similar to CallOpSignatureConversion.
|
|
|
|
class LowerSelectOpTypes : public OpConversionPattern<SelectOp> {
|
|
|
|
public:
|
|
|
|
using OpConversionPattern::OpConversionPattern;
|
|
|
|
LogicalResult
|
|
|
|
matchAndRewrite(SelectOp op, ArrayRef<Value> operands,
|
|
|
|
ConversionPatternRewriter &rewriter) const override {
|
|
|
|
SelectOp::Adaptor adaptor(operands);
|
|
|
|
rewriter.updateRootInPlace(
|
|
|
|
op, [&] { op.getResult().setType(adaptor.true_value().getType()); });
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Further lowerings.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LowerTensorToMemrefOp
|
[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
|
|
|
: public OpConversionPattern<refback::TensorToMemrefOp> {
|
2020-09-17 08:31:40 +08:00
|
|
|
public:
|
|
|
|
using OpConversionPattern::OpConversionPattern;
|
|
|
|
LogicalResult
|
[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
|
|
|
matchAndRewrite(refback::TensorToMemrefOp op, ArrayRef<Value> operands,
|
2020-09-17 08:31:40 +08:00
|
|
|
ConversionPatternRewriter &rewriter) const override {
|
[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::TensorToMemrefOp::Adaptor adaptor(operands);
|
2020-09-17 08:31:40 +08:00
|
|
|
rewriter.replaceOp(op, adaptor.tensor());
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LowerMemrefToTensorOp
|
[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
|
|
|
: public OpConversionPattern<refback::MemrefToTensorOp> {
|
2020-09-17 08:31:40 +08:00
|
|
|
public:
|
|
|
|
using OpConversionPattern::OpConversionPattern;
|
|
|
|
LogicalResult
|
[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
|
|
|
matchAndRewrite(refback::MemrefToTensorOp op, ArrayRef<Value> operands,
|
2020-09-17 08:31:40 +08:00
|
|
|
ConversionPatternRewriter &rewriter) const override {
|
[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::MemrefToTensorOp::Adaptor adaptor(operands);
|
2020-09-17 08:31:40 +08:00
|
|
|
rewriter.replaceOp(op, op.memref());
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// The pass.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LowerStructuralToMemref
|
|
|
|
: public LowerStructuralToMemrefBase<LowerStructuralToMemref> {
|
|
|
|
void runOnOperation() {
|
|
|
|
auto func = getOperation();
|
|
|
|
auto *context = &getContext();
|
|
|
|
|
|
|
|
// TODO: move these common type conversions to somewhere common.
|
|
|
|
TypeConverter typeConverter;
|
|
|
|
typeConverter.addConversion([](Type type) { return type; });
|
|
|
|
typeConverter.addConversion([](RankedTensorType type) -> Type {
|
|
|
|
return MemRefType::get(type.getShape(), type.getElementType());
|
|
|
|
});
|
|
|
|
|
|
|
|
typeConverter.addSourceMaterialization([](OpBuilder &builder,
|
|
|
|
RankedTensorType type,
|
|
|
|
ValueRange inputs, Location loc) {
|
|
|
|
assert(inputs.size() == 1);
|
|
|
|
assert(inputs[0].getType().isa<MemRefType>());
|
[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
|
|
|
return (Value)builder.create<refback::MemrefToTensorOp>(loc, type,
|
|
|
|
inputs[0]);
|
2020-09-17 08:31:40 +08:00
|
|
|
});
|
|
|
|
typeConverter.addTargetMaterialization([](OpBuilder &builder,
|
|
|
|
MemRefType type,
|
|
|
|
ValueRange inputs, Location loc) {
|
|
|
|
assert(inputs.size() == 1);
|
|
|
|
assert(inputs[0].getType().isa<RankedTensorType>());
|
[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
|
|
|
return (Value)builder.create<refback::TensorToMemrefOp>(loc, type,
|
|
|
|
inputs[0]);
|
2020-09-17 08:31:40 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
OwningRewritePatternList patterns;
|
|
|
|
|
|
|
|
ConversionTarget target(*context);
|
|
|
|
|
|
|
|
// All ops whose results are not tensor types are legal.
|
|
|
|
target.markUnknownOpDynamicallyLegal([](Operation *op) {
|
|
|
|
return llvm::all_of(op->getResultTypes(),
|
|
|
|
[](Type type) { return !type.isa<TensorType>(); });
|
|
|
|
});
|
|
|
|
|
|
|
|
populateFuncOpTypeConversionPattern(patterns, context, typeConverter);
|
|
|
|
target.addDynamicallyLegalOp<mlir::FuncOp>([&](mlir::FuncOp op) {
|
|
|
|
return typeConverter.isSignatureLegal(op.getType()) &&
|
|
|
|
typeConverter.isLegal(&op.getBody());
|
|
|
|
});
|
|
|
|
|
|
|
|
patterns.insert<LowerSelectOpTypes>(typeConverter, context);
|
|
|
|
patterns.insert<LowerIfOpTypes>(typeConverter, context);
|
2020-09-19 05:49:04 +08:00
|
|
|
patterns.insert<LowerForOpTypes>(typeConverter, context);
|
2020-09-17 08:31:40 +08:00
|
|
|
patterns.insert<LowerTensorToMemrefOp>(typeConverter, context);
|
|
|
|
patterns.insert<LowerMemrefToTensorOp>(typeConverter, 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::TensorToMemrefOp>();
|
2020-09-17 08:31:40 +08:00
|
|
|
|
|
|
|
if (failed(applyFullConversion(func, target, patterns)))
|
|
|
|
return signalPassFailure();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
std::unique_ptr<OperationPass<FuncOp>>
|
|
|
|
mlir::NPCOMP::createLowerStructuralToMemrefPass() {
|
|
|
|
return std::make_unique<LowerStructuralToMemref>();
|
|
|
|
}
|