13#include "../PassDetails.h"
22#include "mlir/Transforms/DialectConversion.h"
26#define GEN_PASS_DEF_LOWERESITOPHYSICAL
27#include "circt/Dialect/ESI/ESIPasses.h.inc"
42 using OpConversionPattern::OpConversionPattern;
45 matchAndRewrite(ChannelBufferOp buffer, OpAdaptor adaptor,
46 ConversionPatternRewriter &rewriter)
const final;
53LogicalResult ChannelBufferLowering::matchAndRewrite(
54 ChannelBufferOp buffer, OpAdaptor adaptor,
55 ConversionPatternRewriter &rewriter)
const {
56 auto loc = buffer.getLoc();
58 ChannelType inputType = buffer.getInput().getType();
59 Value stageInput = buffer.getInput();
62 if (inputType.getSignaling() == ChannelSignaling::FIFO) {
64 Backedge rdEn = bb.get(rewriter.getI1Type());
65 Backedge valid = bb.get(rewriter.getI1Type());
67 auto unwrap = rewriter.create<UnwrapFIFOOp>(loc, stageInput, rdEn);
68 auto wrap = rewriter.create<WrapValidReadyOp>(loc,
unwrap.getData(), valid);
69 stageInput =
wrap.getChanOutput();
76 rewriter.create<
hw::ConstantOp>(loc, rewriter.getBoolAttr(
true))));
80 auto stages = buffer.getStagesAttr();
81 uint64_t numStages = 1;
84 numStages = stages.getValue().getLimitedValue();
85 StringAttr bufferName = buffer.getNameAttr();
87 for (uint64_t i = 0; i < numStages; ++i) {
89 auto stage = rewriter.create<PipelineStageOp>(loc, buffer.getClk(),
90 buffer.getRst(), stageInput);
92 SmallString<64> stageName(
93 {bufferName.getValue(),
"_stage", std::to_string(i)});
94 stage->setAttr(
"name", StringAttr::get(rewriter.getContext(), stageName));
99 ChannelType outputType = buffer.getOutput().getType();
100 Value output = stageInput;
102 if (outputType.getSignaling() == ChannelSignaling::FIFO) {
104 Backedge ready = bb.get(rewriter.getI1Type());
107 auto unwrap = rewriter.create<UnwrapValidReadyOp>(loc, stageInput, ready);
108 auto wrap = rewriter.create<WrapFIFOOp>(
109 loc, TypeRange{outputType, rewriter.getI1Type()},
unwrap.getRawOutput(),
115 rewriter.create<
hw::ConstantOp>(loc, rewriter.getBoolAttr(
true))));
116 output =
wrap.getChanOutput();
120 rewriter.replaceOp(buffer, output);
130 using OpConversionPattern::OpConversionPattern;
133 matchAndRewrite(FIFOOp, OpAdaptor adaptor,
134 ConversionPatternRewriter &rewriter)
const final;
139FIFOLowering::matchAndRewrite(FIFOOp op, OpAdaptor adaptor,
140 ConversionPatternRewriter &rewriter)
const {
141 auto loc = op.getLoc();
142 auto outputType = op.getType();
144 auto i1 = rewriter.getI1Type();
145 auto c1 = rewriter.create<
hw::ConstantOp>(loc, rewriter.getI1Type(),
146 rewriter.getBoolAttr(
true));
147 mlir::TypedValue<ChannelType> chanInput = op.getInput();
148 if (chanInput.getType().getDataDelay() != 0)
149 return op.emitOpError(
150 "currently only supports input channels with zero data delay");
154 Value dataNotAvailable;
155 if (chanInput.getType().getSignaling() == ChannelSignaling::ValidReady) {
156 auto unwrapValidReady =
157 rewriter.create<UnwrapValidReadyOp>(loc, chanInput, inputEn);
158 rawData = unwrapValidReady.getRawOutput();
159 dataNotAvailable = comb::createOrFoldNot(loc, unwrapValidReady.getValid(),
161 dataNotAvailable.getDefiningOp()->setAttr(
162 "sv.namehint", rewriter.getStringAttr(
"dataNotAvailable"));
163 }
else if (chanInput.getType().getSignaling() == ChannelSignaling::FIFO) {
164 auto unwrapPull = rewriter.create<UnwrapFIFOOp>(loc, chanInput, inputEn);
165 rawData = unwrapPull.getData();
166 dataNotAvailable = unwrapPull.getEmpty();
168 return rewriter.notifyMatchFailure(
169 op,
"only supports ValidReady and FIFO signaling");
173 auto seqFifo = rewriter.create<seq::FIFOOp>(
174 loc, outputType.getInner(), i1, i1, Type(), Type(), rawData, outputRdEn,
175 inputEn, op.getClk(), op.getRst(), op.getDepthAttr(),
176 rewriter.getI64IntegerAttr(outputType.getDataDelay()), IntegerAttr(),
178 auto inputNotEmpty = rewriter.create<
comb::XorOp>(loc, dataNotAvailable, c1);
179 inputNotEmpty->setAttr(
"sv.namehint",
180 rewriter.getStringAttr(
"inputNotEmpty"));
181 auto seqFifoNotFull =
182 rewriter.create<
comb::XorOp>(loc, seqFifo.getFull(), c1);
183 seqFifoNotFull->setAttr(
"sv.namehint",
184 rewriter.getStringAttr(
"seqFifoNotFull"));
186 rewriter.create<
comb::AndOp>(loc, inputNotEmpty, seqFifoNotFull));
187 static_cast<Value
>(inputEn).getDefiningOp()->setAttr(
188 "sv.namehint", rewriter.getStringAttr(
"inputEn"));
191 if (outputType.getSignaling() == ChannelSignaling::ValidReady) {
192 auto wrap = rewriter.create<WrapValidReadyOp>(
193 loc, mlir::TypeRange{outputType, i1}, seqFifo.getOutput(),
194 comb::createOrFoldNot(loc, seqFifo.getEmpty(), rewriter,
196 output =
wrap.getChanOutput();
199 static_cast<Value
>(outputRdEn)
201 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"outputRdEn"));
202 }
else if (outputType.getSignaling() == ChannelSignaling::FIFO) {
204 rewriter.create<WrapFIFOOp>(loc, mlir::TypeRange{outputType, i1},
205 seqFifo.getOutput(), seqFifo.getEmpty());
206 output =
wrap.getChanOutput();
207 outputRdEn.setValue(
wrap.getRden());
209 return rewriter.notifyMatchFailure(op,
"only supports ValidReady and FIFO");
212 rewriter.replaceOp(op, output);
220 using OpConversionPattern::OpConversionPattern;
223 matchAndRewrite(ESIPureModuleOp pureMod, OpAdaptor adaptor,
224 ConversionPatternRewriter &rewriter)
const final;
229PureModuleLowering::matchAndRewrite(ESIPureModuleOp pureMod, OpAdaptor adaptor,
230 ConversionPatternRewriter &rewriter)
const {
231 auto loc = pureMod.getLoc();
232 Block *body = &pureMod.getBody().front();
236 DenseMap<StringAttr, ESIPureModuleInputOp> inputPortNames;
238 SmallVector<hw::PortInfo> ports;
240 SmallVector<ESIPureModuleInputOp> inputs;
241 SmallVector<ESIPureModuleOutputOp> outputs;
242 SmallVector<Attribute> params;
244 for (Operation &op :
llvm::make_early_inc_range(body->getOperations())) {
245 if (
auto port = dyn_cast<ESIPureModuleInputOp>(op)) {
249 auto existingPort = inputPortNames.find(port.getNameAttr());
250 if (existingPort != inputPortNames.end()) {
251 rewriter.replaceAllUsesWith(port.getResult(),
252 existingPort->getSecond().getResult());
253 rewriter.eraseOp(port);
258 hw::PortInfo{{port.getNameAttr(), port.getResult().getType(),
259 hw::ModulePort::Direction::Input},
263 inputs.push_back(port);
264 }
else if (
auto port = dyn_cast<ESIPureModuleOutputOp>(op)) {
266 hw::PortInfo{{port.getNameAttr(), port.getValue().getType(),
267 hw::ModulePort::Direction::Output},
271 outputs.push_back(port);
272 }
else if (
auto param = dyn_cast<ESIPureModuleParamOp>(op)) {
274 ParamDeclAttr::get(param.getNameAttr(), param.getType()));
275 rewriter.eraseOp(param);
281 loc, pureMod.getNameAttr(), ports, ArrayAttr::get(getContext(), params));
282 hwMod->setDialectAttrs(pureMod->getDialectAttrs());
283 rewriter.eraseBlock(hwMod.getBodyBlock());
284 rewriter.inlineRegionBefore(*body->getParent(), hwMod.getBodyRegion(),
285 hwMod.getBodyRegion().end());
286 body = hwMod.getBodyBlock();
289 for (
auto input : inputs) {
290 BlockArgument newArg;
291 rewriter.modifyOpInPlace(hwMod, [&]() {
292 newArg = body->addArgument(input.getResult().getType(), input.getLoc());
294 rewriter.replaceAllUsesWith(input.getResult(), newArg);
295 rewriter.eraseOp(input);
299 SmallVector<Value> hwOutputOperands;
300 for (
auto output : outputs) {
301 hwOutputOperands.push_back(output.getValue());
302 rewriter.eraseOp(output);
304 rewriter.setInsertionPointToEnd(body);
305 rewriter.create<hw::OutputOp>(pureMod.getLoc(), hwOutputOperands);
308 rewriter.eraseOp(pureMod);
314struct ESIToPhysicalPass
315 :
public circt::esi::impl::LowerESIToPhysicalBase<ESIToPhysicalPass> {
316 void runOnOperation()
override;
320void ESIToPhysicalPass::runOnOperation() {
322 ConversionTarget target(getContext());
323 target.markUnknownOpDynamicallyLegal([](Operation *) {
return true; });
324 target.addIllegalOp<ChannelBufferOp, ESIPureModuleOp, FIFOOp>();
327 RewritePatternSet
patterns(&getContext());
328 patterns.insert<ChannelBufferLowering, PureModuleLowering, FIFOLowering>(
333 applyPartialConversion(getOperation(), target, std::move(
patterns))))
337std::unique_ptr<OperationPass<ModuleOp>>
339 return std::make_unique<ESIToPhysicalPass>();
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static InstancePath empty
static EvaluatorValuePtr unwrap(OMEvaluatorValue c)
Instantiate one of these and use it to build typed backedges.
Backedge is a wrapper class around a Value.
void setValue(mlir::Value)
std::unique_ptr< OperationPass< ModuleOp > > createESIPhysicalLoweringPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
This holds the name, type, direction of a module's ports.