9 #include "../PassDetails.h"
18 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
20 using namespace circt;
38 void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
39 SmallVectorImpl<Value> &newOperands,
40 ArrayRef<Backedge> newResults)
override;
41 void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
42 SmallVectorImpl<Value> &newOperands,
43 ArrayRef<Backedge> newResults)
override;
46 void buildInputSignals()
override;
47 void buildOutputSignals()
override;
50 SmallVector<hw::PortInfo, 4> newInputChannels;
51 SmallVector<hw::PortInfo, 4> newOutputChannels;
58 return llvm::TypeSwitch<Type, FailureOr<std::unique_ptr<PortConversion>>>(
60 .Case([&](esi::ChannelBundleType)
62 return {std::make_unique<BundlePort>(converter, port)};
71 void BundlePort::mapInputSignals(OpBuilder &b, Operation *inst, Value,
72 SmallVectorImpl<Value> &newOperands,
73 ArrayRef<Backedge> newResults) {
75 SmallVector<Value, 4> fromChannels(
76 llvm::map_range(newOutputChannels, [&](hw::PortInfo port) {
77 return newResults[port.argNum];
79 SmallVector<Type, 5> toChannelTypes(llvm::map_range(
80 newInputChannels, [](hw::PortInfo port) {
return port.type; }));
81 auto unpack = b.create<UnpackBundleOp>(
83 inst->getOperand(origPort.argNum), fromChannels);
86 for (
auto [idx, inPort] : llvm::enumerate(newInputChannels))
87 newOperands[inPort.argNum] = unpack.getResult(idx);
92 void BundlePort::mapOutputSignals(OpBuilder &b, Operation *inst, Value,
93 SmallVectorImpl<Value> &newOperands,
94 ArrayRef<Backedge> newResults) {
96 SmallVector<Value, 4> toChannels(
97 llvm::map_range(newOutputChannels, [&](hw::PortInfo port) {
98 return newResults[port.argNum];
100 SmallVector<Type, 5> fromChannelTypes(llvm::map_range(
101 newInputChannels, [](hw::PortInfo port) {
return port.type; }));
102 auto pack = b.create<PackBundleOp>(
103 origPort.loc, cast<ChannelBundleType>(origPort.type), toChannels);
106 for (
auto [idx, inPort] : llvm::enumerate(newInputChannels))
107 newOperands[inPort.argNum] = pack.getFromChannels()[idx];
109 inst->getResult(origPort.argNum).replaceAllUsesWith(pack.getBundle());
114 void BundlePort::buildInputSignals() {
115 auto bundleType = cast<ChannelBundleType>(origPort.type);
116 SmallVector<Value, 4> newInputValues;
117 SmallVector<BundledChannel, 4> outputChannels;
121 if (ch.direction == ChannelDirection::to) {
122 hw::PortInfo newPort;
123 newInputValues.push_back(converter.createNewInput(
124 origPort,
"_" + ch.name.getValue(), ch.type, newPort));
125 newInputChannels.push_back(newPort);
128 outputChannels.push_back(ch);
136 ImplicitLocOpBuilder b(origPort.loc, body, body->begin());
137 pack = b.create<PackBundleOp>(bundleType, newInputValues);
138 body->getArgument(origPort.argNum).replaceAllUsesWith(pack.getBundle());
143 newOutputChannels.resize(outputChannels.size());
144 for (
auto [idx, ch] : llvm::enumerate(outputChannels))
145 converter.createNewOutput(origPort,
"_" + ch.name.getValue(), ch.type,
146 pack ? pack.getFromChannels()[idx] :
nullptr,
147 newOutputChannels[idx]);
152 void BundlePort::buildOutputSignals() {
153 auto bundleType = cast<ChannelBundleType>(origPort.type);
154 SmallVector<Value, 4> unpackChannels;
155 SmallVector<BundledChannel, 4> outputChannels;
157 SmallVector<Type, 4> unpackOpResultTypes;
160 if (ch.direction == ChannelDirection::from) {
161 hw::PortInfo newPort;
162 unpackChannels.push_back(converter.createNewInput(
163 origPort,
"_" + ch.name.getValue(), ch.type, newPort));
164 newInputChannels.push_back(newPort);
167 unpackOpResultTypes.push_back(ch.type);
168 outputChannels.push_back(ch);
174 UnpackBundleOp unpack;
176 unpack = OpBuilder::atBlockTerminator(body).create<UnpackBundleOp>(
177 origPort.loc, body->getTerminator()->getOperand(origPort.argNum),
182 newOutputChannels.resize(outputChannels.size());
183 for (
auto [idx, ch] : llvm::enumerate(outputChannels))
184 converter.createNewOutput(origPort,
"_" + ch.name.getValue(), ch.type,
185 unpack ? unpack.getToChannels()[idx] :
nullptr,
186 newOutputChannels[idx]);
191 struct ESIBundlesPass :
public LowerESIBundlesBase<ESIBundlesPass> {
192 void runOnOperation()
override;
197 void ESIBundlesPass::runOnOperation() {
198 MLIRContext &
ctxt = getContext();
199 ModuleOp top = getOperation();
203 getAnalysis<circt::hw::InstanceGraph>();
204 for (
auto mod : top.getOps<HWMutableModuleLike>()) {
207 return signalPassFailure();
213 PackBundleOp::getCanonicalizationPatterns(
patterns, &
ctxt);
214 UnpackBundleOp::getCanonicalizationPatterns(
patterns, &
ctxt);
215 if (failed(mlir::applyPatternsAndFoldGreedily(getOperation(),
219 top.walk([&](PackBundleOp pack) {
220 pack.emitError(
"PackBundleOp should have been canonicalized away by now");
225 std::unique_ptr<OperationPass<ModuleOp>>
227 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.
std::unique_ptr< OperationPass< ModuleOp > > createESIBundleLoweringPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.