-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Buffers] Simple pass for inserting a single buffer (#62)
This commit introduces an experimental pass `--handshake-placebuffers-custom` which inserts a single buffer in the IR on a channel referenced by its producer's name and result index (as such, the IR must be materialized as a pre-condition to the pass). This pass facilitates externally prototyping a custom buffer placement analysis, e.g., in Python. This also makes the results of some research artifacts (e.g., [Mapbuf](https://github.com/Nozidoali/MapBuf/tree/master)) developed in Python easily reproducible in the current Dynamatic framework. A typical workflow would be: 1. Export the `handshake_transformed.mlir` to DOT, apply some external analysis using Python to determine where to place buffers. 2. Using this pass: add all the buffers, and generate `handshake_buffered.mlir`. 3. Continue with the rest of the HLS flow. For example, we can add buffers by as follows (this is for the benchmark `fir`): ```sh dynamatic-opt handshake_transformed.mlir \ --handshake-placebuffers-custom="pred=mux1 outid=0 slots=1 type=oehb" \ --handshake-placebuffers-custom="pred=mux1 outid=0 slots=1 type=tehb" \ --handshake-placebuffers-custom="pred=mux2 outid=0 slots=1 type=oehb" \ --handshake-placebuffers-custom="pred=mux2 outid=0 slots=1 type=tehb" \ --handshake-placebuffers-custom="pred=control_merge2 outid=0 slots=1 type=oehb" \ --handshake-placebuffers-custom="pred=control_merge2 outid=0 slots=1 type=tehb" \ > "handshake_buffered.mlir" dynamatic-opt handshake_buffered.mlir --handshake-canonicalize \ > handshake_export.mlir ``` --------- Co-authored-by: Jiahui Xu <jxu@ethz.ch>
- Loading branch information
Showing
5 changed files
with
166 additions
and
1 deletion.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
experimental/include/experimental/Transforms/HandshakePlaceBuffersCustom.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
//===- HandshakePlaceBuffersCustom.h - Place buffers in DFG -----*- C++ -*-===// | ||
// | ||
// Dynamatic is 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file declares the --handshake-place-buffers-custom pass | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef EXPERIMENTAL_TRANSFORMS_BUFFERPLACEMENT_PLACEBUFFERS_CUSTOM_H | ||
#define EXPERIMENTAL_TRANSFORMS_BUFFERPLACEMENT_PLACEBUFFERS_CUSTOM_H | ||
|
||
#include "dynamatic/Support/DynamaticPass.h" | ||
#include "mlir/IR/BuiltinTypes.h" | ||
#include "llvm/ADT/StringRef.h" | ||
#include <string> | ||
|
||
namespace dynamatic { | ||
namespace experimental { | ||
namespace buffer { | ||
|
||
std::unique_ptr<dynamatic::DynamaticPass> createHandshakePlaceBuffersCustom( | ||
const std::string &pred = "", const unsigned &outid = 1, | ||
const unsigned &slots = 1, const std::string &type = "oehb"); | ||
|
||
#define GEN_PASS_DECL_HANDSHAKEPLACEBUFFERSCUSTOM | ||
#define GEN_PASS_DEF_HANDSHAKEPLACEBUFFERSCUSTOM | ||
#include "experimental/Transforms/Passes.h.inc" | ||
|
||
} // namespace buffer | ||
} // namespace experimental | ||
} // namespace dynamatic | ||
|
||
#endif // EXPERIMENTAL_TRANSFORMS_BUFFERPLACEMENT_PLACEBUFFERS_CUSTOM_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
experimental/lib/Transforms/HandshakePlaceBuffersCustom.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
//===- HandshakePlaceBuffersCustom.cpp - Place buffers in DFG ---*- C++ -*-===// | ||
// | ||
// Dynamatic is 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Buffer placement pass in Handshake functions, it takes the location (i.e., | ||
// the predecessor, and which output channel of it), type (i.e., opaque or | ||
// transparent), and slots of the buffer that should be placed. | ||
// | ||
// This pass facilitates externally prototyping a custom buffer placement | ||
// analysis, e.g., in Python. This also makes the results of some research | ||
// artifacts (e.g., Mapbuf) developed in Python easily reproducible in the | ||
// current Dynamatic framework. | ||
// | ||
// Currently, this pass only supports adding units for a IR that is already | ||
// materized (i.e., each value is produced by exactly one producer, and consumed | ||
// by exactly one consumer). For future work on unmaterialized IRs, we need to | ||
// supply the producer--consumer pair as arguments | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "dynamatic/Analysis/NameAnalysis.h" | ||
#include "dynamatic/Dialect/Handshake/HandshakeDialect.h" | ||
#include "dynamatic/Dialect/Handshake/HandshakeOps.h" | ||
#include "dynamatic/Support/Attribute.h" | ||
#include "dynamatic/Support/CFG.h" | ||
#include "dynamatic/Transforms/HandshakeMaterialize.h" | ||
#include "experimental/Transforms/HandshakePlaceBuffersCustom.h" | ||
#include "mlir/Dialect/Func/IR/FuncOps.h" | ||
#include "llvm/ADT/StringRef.h" | ||
|
||
using namespace llvm; | ||
using namespace dynamatic; | ||
using namespace dynamatic::experimental; | ||
using namespace dynamatic::experimental::buffer; | ||
|
||
namespace { | ||
|
||
struct HandshakePlaceBuffersCustomPass | ||
: public dynamatic::experimental::buffer::impl:: | ||
HandshakePlaceBuffersCustomBase<HandshakePlaceBuffersCustomPass> { | ||
|
||
/// Trivial field-by-field constructor. | ||
HandshakePlaceBuffersCustomPass(const std::string &pred, const int &outid, | ||
const int &slots, const std::string &type) { | ||
this->pred = pred; | ||
this->outid = outid; | ||
this->slots = slots; | ||
this->type = type; | ||
} | ||
|
||
/// Called on the MLIR module provided as input. | ||
void runDynamaticPass() override { | ||
mlir::ModuleOp modOp = getOperation(); | ||
MLIRContext *ctx = &getContext(); | ||
|
||
// Check if the IR is after being materialized, if not, reject the input | ||
// IR. | ||
if (failed(verifyIRMaterialized(modOp))) { | ||
modOp->emitError() << ERR_NON_MATERIALIZED_MOD; | ||
return signalPassFailure(); | ||
} | ||
|
||
OpBuilder builder(ctx); | ||
NameAnalysis &namer = getAnalysis<NameAnalysis>(); | ||
Operation *op = namer.getOp(pred); | ||
if (!op) { | ||
llvm::errs() << "No operation named \"" << pred << "\" exists\n"; | ||
return signalPassFailure(); | ||
} | ||
assert(outid <= op->getNumResults() && | ||
"The output id exceeds the number of output ports!"); | ||
Value channel = op->getResult(outid); | ||
// Set the insertion point to be before the original successor of the | ||
// channel. | ||
Operation *succ = *channel.getUsers().begin(); | ||
builder.setInsertionPoint(succ); | ||
StringAttr slotName = StringAttr::get(ctx, "slots"); | ||
StringRef bufOpType; | ||
if (type == "oehb") { | ||
// if the specified type is "oehb", then we add a Opaque buffer with | ||
// number of slots = slots. | ||
bufOpType = handshake::OEHBOp::getOperationName(); | ||
} else if (type == "tehb") { | ||
// If the specified type is "tehb", then we add a Transparent buffer | ||
// with number of slots = slots. | ||
bufOpType = handshake::TEHBOp::getOperationName(); | ||
} else { | ||
llvm::errs() << "Unknown buffer type: \"" << type << "\"!\n"; | ||
return signalPassFailure(); | ||
} | ||
NamedAttribute namedSlots(slotName, builder.getI32IntegerAttr(slots)); | ||
auto *bufOp = | ||
builder.create(channel.getLoc(), StringAttr::get(ctx, bufOpType), | ||
channel, {channel.getType()}, {namedSlots}); | ||
inheritBB(succ, bufOp); | ||
Value bufferRes = bufOp->getResult(0); | ||
succ->replaceUsesOfWith(channel, bufferRes); | ||
} | ||
}; | ||
} // namespace | ||
|
||
std::unique_ptr<dynamatic::DynamaticPass> | ||
dynamatic::experimental::buffer::createHandshakePlaceBuffersCustom( | ||
const std::string &pred, const unsigned &outid, const unsigned &slots, | ||
const std::string &type) { | ||
return std::make_unique<HandshakePlaceBuffersCustomPass>(pred, outid, slots, | ||
type); | ||
} |