9 #include "../PassDetails.h"
18 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
22 #define GEN_PASS_DEF_LOWERESIBUNDLES
23 #include "circt/Dialect/ESI/ESIPasses.h.inc"
27 using namespace circt;
45 void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
46 SmallVectorImpl<Value> &newOperands,
47 ArrayRef<Backedge> newResults)
override;
48 void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
49 SmallVectorImpl<Value> &newOperands,
50 ArrayRef<Backedge> newResults)
override;
53 void buildInputSignals()
override;
54 void buildOutputSignals()
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)};
78 void 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(
87 newInputChannels, [](hw::PortInfo port) {
return port.type; }));
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);
99 void 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(
108 newInputChannels, [](hw::PortInfo port) {
return port.type; }));
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());
121 void 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) {
129 hw::PortInfo newPort;
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]);
159 void 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) {
168 hw::PortInfo newPort;
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]);
198 struct ESIBundlesPass
199 :
public circt::esi::impl::LowerESIBundlesBase<ESIBundlesPass> {
200 void runOnOperation()
override;
205 void 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::applyPatternsAndFoldGreedily(getOperation(),
227 top.walk([&](PackBundleOp pack) {
228 pack.emitError(
"PackBundleOp should have been canonicalized away by now");
233 std::unique_ptr<OperationPass<ModuleOp>>
235 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.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)