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/Linalg/IR/LinalgOps.h"
|
|
|
|
#include "mlir/Dialect/Linalg/IR/LinalgTypes.h"
|
|
|
|
#include "mlir/Dialect/SCF/SCF.h"
|
|
|
|
#include "mlir/Dialect/Shape/IR/Shape.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/RefbackDialect.h"
|
|
|
|
#include "npcomp/Dialect/Refback/IR/RefbackOps.h"
|
2020-09-17 08:31:40 +08:00
|
|
|
|
|
|
|
using namespace mlir;
|
|
|
|
using namespace mlir::NPCOMP;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// LowerConstantTensorsToMemref
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// This class creates global ops for all tensor-valued constants in the program.
|
|
|
|
// It creates them with pretty names and makes sure that duplicate globals
|
|
|
|
// aren't created.
|
|
|
|
class GlobalCreator {
|
|
|
|
public:
|
|
|
|
explicit GlobalCreator(ModuleOp module);
|
[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::GlobalOp getGlobalFor(Attribute attr) {
|
2020-09-17 08:31:40 +08:00
|
|
|
assert(globals.find(attr) != globals.end() && "unknown constant attr");
|
|
|
|
return globals[attr];
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
[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
|
|
|
DenseMap<Attribute, refback::GlobalOp> globals;
|
2020-09-17 08:31:40 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
GlobalCreator::GlobalCreator(ModuleOp module) {
|
|
|
|
// Create a builder without an insertion point. We will insert using the
|
|
|
|
// symbol table to guarantee unique names.
|
|
|
|
OpBuilder globalBuilder(module.getContext());
|
|
|
|
SymbolTable symbolTable(module);
|
|
|
|
module.walk([&](ConstantOp op) {
|
|
|
|
// We only want tensor constants for now.
|
|
|
|
auto type = op.getType().dyn_cast<RankedTensorType>();
|
|
|
|
if (!type)
|
|
|
|
return;
|
|
|
|
// If we already have a global for this constant value, no need to do
|
|
|
|
// anything else.
|
|
|
|
auto it = globals.find(op.getValue());
|
|
|
|
if (it != globals.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create a pretty name.
|
|
|
|
SmallString<64> buf;
|
|
|
|
llvm::raw_svector_ostream os(buf);
|
|
|
|
interleave(type.getShape(), os, "x");
|
|
|
|
os << "x" << type.getElementType();
|
|
|
|
|
[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
|
|
|
auto global = globalBuilder.create<refback::GlobalOp>(
|
2020-09-17 08:31:40 +08:00
|
|
|
op.getLoc(), (Twine("__constant_") + os.str()).str(),
|
|
|
|
op.getValue().cast<ElementsAttr>());
|
|
|
|
symbolTable.insert(global);
|
|
|
|
// The symbol table inserts at the end of the module, but globals are a bit
|
|
|
|
// nicer if they are at the beginning.
|
|
|
|
global.getOperation()->moveBefore(&module.front());
|
|
|
|
globals[op.getValue()] = global;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LowerConstantTensorsToMemref
|
|
|
|
: public LowerConstantTensorsToMemrefBase<LowerConstantTensorsToMemref> {
|
2020-09-22 05:48:44 +08:00
|
|
|
void getDependentDialects(DialectRegistry ®istry) const override {
|
2020-10-08 08:30:10 +08:00
|
|
|
registry.insert<refback::RefbackDialect>();
|
2020-09-22 05:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-09-29 03:03:54 +08:00
|
|
|
void runOnOperation() override {
|
2020-09-17 08:31:40 +08:00
|
|
|
auto module = getOperation();
|
|
|
|
GlobalCreator globals(module);
|
|
|
|
|
|
|
|
// With the global traversal factored into GlobalCreator, this could in
|
|
|
|
// principle be done with a pattern.
|
|
|
|
module.walk([&](ConstantOp op) {
|
|
|
|
auto type = op.getType().dyn_cast<RankedTensorType>();
|
|
|
|
if (!type)
|
|
|
|
return;
|
|
|
|
auto global = globals.getGlobalFor(op.getValue());
|
|
|
|
OpBuilder builder(op);
|
|
|
|
auto memrefType = MemRefType::get(type.getShape(), type.getElementType());
|
[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
|
|
|
auto memref = builder.create<refback::GetGlobalMemrefOp>(
|
2020-09-17 08:31:40 +08:00
|
|
|
op.getLoc(), memrefType, global.getName());
|
|
|
|
Value tensor =
|
[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
|
|
|
builder.create<refback::MemrefToTensorOp>(op.getLoc(), type, memref);
|
2020-09-17 08:31:40 +08:00
|
|
|
op.replaceAllUsesWith(tensor);
|
|
|
|
op.erase();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
std::unique_ptr<OperationPass<ModuleOp>>
|
|
|
|
mlir::NPCOMP::createLowerConstantTensorsToMemrefPass() {
|
|
|
|
return std::make_unique<LowerConstantTensorsToMemref>();
|
|
|
|
}
|