9#include "../PassDetails.h"
18#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
22#define GEN_PASS_DEF_LOWERESIBUNDLES
23#include "circt/Dialect/ESI/ESIPasses.h.inc"
46 SmallVectorImpl<Value> &newOperands,
47 ArrayRef<Backedge> newResults)
override;
49 SmallVectorImpl<Value> &newOperands,
50 ArrayRef<Backedge> newResults)
override;
57 SmallVector<hw::PortInfo, 4> newInputChannels;
58 SmallVector<hw::PortInfo, 4> newOutputChannels;
64 FailureOr<std::unique_ptr<PortConversion>> build(
hw::PortInfo port)
override {
65 return llvm::TypeSwitch<Type, FailureOr<std::unique_ptr<PortConversion>>>(
67 .Case([&](esi::ChannelBundleType)
68 -> FailureOr<std::unique_ptr<PortConversion>> {
69 return {std::make_unique<BundlePort>(converter, port)};
78void BundlePort::mapInputSignals(OpBuilder &b, Operation *inst, Value,
79 SmallVectorImpl<Value> &newOperands,
80 ArrayRef<Backedge> newResults) {
82 SmallVector<Value, 4> fromChannels(
83 llvm::map_range(newOutputChannels, [&](
hw::PortInfo port) {
84 return newResults[port.
argNum];
86 SmallVector<Type, 5> toChannelTypes(llvm::map_range(
88 auto unpack = b.create<UnpackBundleOp>(
90 inst->getOperand(origPort.argNum), fromChannels);
93 for (
auto [idx, inPort] :
llvm::enumerate(newInputChannels))
94 newOperands[inPort.argNum] = unpack.getResult(idx);
99void BundlePort::mapOutputSignals(OpBuilder &b, Operation *inst, Value,
100 SmallVectorImpl<Value> &newOperands,
101 ArrayRef<Backedge> newResults) {
103 SmallVector<Value, 4> toChannels(
104 llvm::map_range(newOutputChannels, [&](
hw::PortInfo port) {
105 return newResults[port.
argNum];
107 SmallVector<Type, 5> fromChannelTypes(llvm::map_range(
109 auto pack = b.create<PackBundleOp>(
110 origPort.loc, cast<ChannelBundleType>(origPort.type), toChannels);
113 for (
auto [idx, inPort] :
llvm::enumerate(newInputChannels))
114 newOperands[inPort.argNum] = pack.getFromChannels()[idx];
116 inst->getResult(origPort.argNum).replaceAllUsesWith(pack.getBundle());
121void BundlePort::buildInputSignals() {
122 auto bundleType = cast<ChannelBundleType>(origPort.type);
123 SmallVector<Value, 4> newInputValues;
124 SmallVector<BundledChannel, 4> outputChannels;
128 if (ch.direction == ChannelDirection::to) {
130 newInputValues.push_back(converter.createNewInput(
131 origPort,
"_" + ch.name.getValue(), ch.type, newPort));
132 newInputChannels.push_back(newPort);
135 outputChannels.push_back(ch);
143 ImplicitLocOpBuilder b(origPort.loc, body, body->begin());
144 pack = b.create<PackBundleOp>(bundleType, newInputValues);
145 body->getArgument(origPort.argNum).replaceAllUsesWith(pack.getBundle());
150 newOutputChannels.resize(outputChannels.size());
151 for (
auto [idx, ch] :
llvm::enumerate(outputChannels))
152 converter.createNewOutput(origPort,
"_" + ch.name.getValue(), ch.type,
153 pack ? pack.getFromChannels()[idx] : nullptr,
154 newOutputChannels[idx]);
159void BundlePort::buildOutputSignals() {
160 auto bundleType = cast<ChannelBundleType>(origPort.type);
161 SmallVector<Value, 4> unpackChannels;
162 SmallVector<BundledChannel, 4> outputChannels;
164 SmallVector<Type, 4> unpackOpResultTypes;
167 if (ch.direction == ChannelDirection::from) {
169 unpackChannels.push_back(converter.createNewInput(
170 origPort,
"_" + ch.name.getValue(), ch.type, newPort));
171 newInputChannels.push_back(newPort);
174 unpackOpResultTypes.push_back(ch.type);
175 outputChannels.push_back(ch);
181 UnpackBundleOp unpack;
183 unpack = OpBuilder::atBlockTerminator(body).create<UnpackBundleOp>(
184 origPort.loc, body->getTerminator()->getOperand(origPort.argNum),
189 newOutputChannels.resize(outputChannels.size());
190 for (
auto [idx, ch] :
llvm::enumerate(outputChannels))
191 converter.createNewOutput(origPort,
"_" + ch.name.getValue(), ch.type,
192 unpack ? unpack.getToChannels()[idx] : nullptr,
193 newOutputChannels[idx]);
199 :
public circt::esi::impl::LowerESIBundlesBase<ESIBundlesPass> {
200 void runOnOperation()
override;
205void ESIBundlesPass::runOnOperation() {
206 MLIRContext &
ctxt = getContext();
207 ModuleOp top = getOperation();
211 getAnalysis<circt::hw::InstanceGraph>();
212 for (
auto mod : top.getOps<HWMutableModuleLike>()) {
215 return signalPassFailure();
221 PackBundleOp::getCanonicalizationPatterns(
patterns, &ctxt);
222 UnpackBundleOp::getCanonicalizationPatterns(
patterns, &ctxt);
223 if (failed(mlir::applyPatternsGreedily(getOperation(), std::move(
patterns))))
226 top.walk([&](PackBundleOp pack) {
227 pack.emitError(
"PackBundleOp should have been canonicalized away by now");
232std::unique_ptr<OperationPass<ModuleOp>>
234 return std::make_unique<ESIBundlesPass>();
HW-specific instance graph with a virtual entry node linking to all publicly visible modules.
PortConversionBuilder(PortConverterImpl &converter)
virtual FailureOr< std::unique_ptr< PortConversion > > build(hw::PortInfo port)
Base class for the port conversion of a particular port.
virtual void buildInputSignals()=0
virtual void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue, SmallVectorImpl< Value > &newOperands, ArrayRef< Backedge > newResults)=0
Update an instance port to the new port information.
virtual void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue, SmallVectorImpl< Value > &newOperands, ArrayRef< Backedge > newResults)=0
virtual void buildOutputSignals()=0
std::unique_ptr< OperationPass< ModuleOp > > createESIBundleLoweringPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
This holds the name, type, direction of a module's ports.
size_t argNum
This is the argument index or the result index depending on the direction.