13 #include "../PassDetails.h"
22 #include "mlir/Transforms/DialectConversion.h"
26 #define GEN_PASS_DEF_LOWERESITOPHYSICAL
27 #include "circt/Dialect/ESI/ESIPasses.h.inc"
31 using namespace circt;
42 using OpConversionPattern::OpConversionPattern;
45 matchAndRewrite(ChannelBufferOp buffer, OpAdaptor adaptor,
46 ConversionPatternRewriter &rewriter)
const final;
50 LogicalResult ChannelBufferLowering::matchAndRewrite(
51 ChannelBufferOp buffer, OpAdaptor adaptor,
52 ConversionPatternRewriter &rewriter)
const {
53 auto loc = buffer.getLoc();
55 auto type = buffer.getType();
58 auto stages = buffer.getStagesAttr();
59 uint64_t numStages = 1;
62 numStages = stages.getValue().getLimitedValue();
64 Value input = buffer.getInput();
65 StringAttr bufferName = buffer.getNameAttr();
66 for (uint64_t i = 0; i < numStages; ++i) {
68 auto stage = rewriter.create<PipelineStageOp>(loc, type, buffer.getClk(),
69 buffer.getRst(), input);
71 SmallString<64> stageName(
72 {bufferName.getValue(),
"_stage", std::to_string(i)});
73 stage->setAttr(
"name",
StringAttr::get(rewriter.getContext(), stageName));
79 rewriter.replaceOp(buffer, input);
89 using OpConversionPattern::OpConversionPattern;
92 matchAndRewrite(FIFOOp, OpAdaptor adaptor,
93 ConversionPatternRewriter &rewriter)
const final;
98 FIFOLowering::matchAndRewrite(FIFOOp op, OpAdaptor adaptor,
99 ConversionPatternRewriter &rewriter)
const {
100 auto loc = op.getLoc();
101 auto outputType = op.getType();
103 auto i1 = rewriter.getI1Type();
104 auto c1 = rewriter.create<
hw::ConstantOp>(loc, rewriter.getI1Type(),
105 rewriter.getBoolAttr(
true));
106 mlir::TypedValue<ChannelType> chanInput = op.getInput();
107 if (chanInput.getType().getDataDelay() != 0)
108 return op.emitOpError(
109 "currently only supports input channels with zero data delay");
113 Value dataNotAvailable;
114 if (chanInput.getType().getSignaling() == ChannelSignaling::ValidReady) {
115 auto unwrapValidReady =
116 rewriter.create<UnwrapValidReadyOp>(loc, chanInput, inputEn);
117 rawData = unwrapValidReady.getRawOutput();
120 dataNotAvailable.getDefiningOp()->setAttr(
121 "sv.namehint", rewriter.getStringAttr(
"dataNotAvailable"));
122 }
else if (chanInput.getType().getSignaling() == ChannelSignaling::FIFO) {
123 auto unwrapPull = rewriter.create<UnwrapFIFOOp>(loc, chanInput, inputEn);
124 rawData = unwrapPull.getData();
125 dataNotAvailable = unwrapPull.getEmpty();
127 return rewriter.notifyMatchFailure(
128 op,
"only supports ValidReady and FIFO signaling");
132 auto seqFifo = rewriter.create<seq::FIFOOp>(
133 loc, outputType.getInner(), i1, i1, Type(), Type(), rawData, outputRdEn,
134 inputEn, op.getClk(), op.getRst(), op.getDepthAttr(),
135 rewriter.getI64IntegerAttr(outputType.getDataDelay()), IntegerAttr(),
137 auto inputNotEmpty = rewriter.create<
comb::XorOp>(loc, dataNotAvailable, c1);
138 inputNotEmpty->setAttr(
"sv.namehint",
139 rewriter.getStringAttr(
"inputNotEmpty"));
140 auto seqFifoNotFull =
141 rewriter.create<
comb::XorOp>(loc, seqFifo.getFull(), c1);
142 seqFifoNotFull->setAttr(
"sv.namehint",
143 rewriter.getStringAttr(
"seqFifoNotFull"));
145 rewriter.create<
comb::AndOp>(loc, inputNotEmpty, seqFifoNotFull));
146 static_cast<Value
>(inputEn).getDefiningOp()->setAttr(
147 "sv.namehint", rewriter.getStringAttr(
"inputEn"));
150 if (outputType.getSignaling() == ChannelSignaling::ValidReady) {
151 auto wrap = rewriter.create<WrapValidReadyOp>(
152 loc, mlir::TypeRange{outputType, i1}, seqFifo.getOutput(),
155 output =
wrap.getChanOutput();
158 static_cast<Value
>(outputRdEn)
160 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"outputRdEn"));
161 }
else if (outputType.getSignaling() == ChannelSignaling::FIFO) {
163 rewriter.create<WrapFIFOOp>(loc, mlir::TypeRange{outputType, i1},
164 seqFifo.getOutput(), seqFifo.getEmpty());
165 output =
wrap.getChanOutput();
166 outputRdEn.setValue(
wrap.getRden());
168 return rewriter.notifyMatchFailure(op,
"only supports ValidReady and FIFO");
171 rewriter.replaceOp(op, output);
179 using OpConversionPattern::OpConversionPattern;
182 matchAndRewrite(ESIPureModuleOp pureMod, OpAdaptor adaptor,
183 ConversionPatternRewriter &rewriter)
const final;
188 PureModuleLowering::matchAndRewrite(ESIPureModuleOp pureMod, OpAdaptor adaptor,
189 ConversionPatternRewriter &rewriter)
const {
190 auto loc = pureMod.getLoc();
191 Block *body = &pureMod.getBody().front();
195 DenseMap<StringAttr, ESIPureModuleInputOp> inputPortNames;
197 SmallVector<hw::PortInfo> ports;
199 SmallVector<ESIPureModuleInputOp> inputs;
200 SmallVector<ESIPureModuleOutputOp> outputs;
201 SmallVector<Attribute> params;
203 for (Operation &op : llvm::make_early_inc_range(body->getOperations())) {
204 if (
auto port = dyn_cast<ESIPureModuleInputOp>(op)) {
208 auto existingPort = inputPortNames.find(port.getNameAttr());
209 if (existingPort != inputPortNames.end()) {
210 rewriter.replaceAllUsesWith(port.getResult(),
211 existingPort->getSecond().getResult());
212 rewriter.eraseOp(port);
217 hw::PortInfo{{port.getNameAttr(), port.getResult().getType(),
222 inputs.push_back(port);
223 }
else if (
auto port = dyn_cast<ESIPureModuleOutputOp>(op)) {
225 hw::PortInfo{{port.getNameAttr(), port.getValue().getType(),
230 outputs.push_back(port);
231 }
else if (
auto param = dyn_cast<ESIPureModuleParamOp>(op)) {
234 rewriter.eraseOp(param);
240 loc, pureMod.getNameAttr(), ports,
ArrayAttr::get(getContext(), params));
241 hwMod->setDialectAttrs(pureMod->getDialectAttrs());
242 rewriter.eraseBlock(hwMod.getBodyBlock());
243 rewriter.inlineRegionBefore(*body->getParent(), hwMod.getBodyRegion(),
244 hwMod.getBodyRegion().end());
245 body = hwMod.getBodyBlock();
248 for (
auto input : inputs) {
249 BlockArgument newArg;
250 rewriter.modifyOpInPlace(hwMod, [&]() {
251 newArg = body->addArgument(input.getResult().getType(), input.getLoc());
253 rewriter.replaceAllUsesWith(input.getResult(), newArg);
254 rewriter.eraseOp(input);
258 SmallVector<Value> hwOutputOperands;
259 for (
auto output : outputs) {
260 hwOutputOperands.push_back(output.getValue());
261 rewriter.eraseOp(output);
263 rewriter.setInsertionPointToEnd(body);
264 rewriter.create<hw::OutputOp>(pureMod.getLoc(), hwOutputOperands);
267 rewriter.eraseOp(pureMod);
273 struct ESIToPhysicalPass
274 :
public circt::esi::impl::LowerESIToPhysicalBase<ESIToPhysicalPass> {
275 void runOnOperation()
override;
279 void ESIToPhysicalPass::runOnOperation() {
281 ConversionTarget target(getContext());
282 target.markUnknownOpDynamicallyLegal([](Operation *) {
return true; });
283 target.addIllegalOp<ChannelBufferOp, ESIPureModuleOp, FIFOOp>();
286 RewritePatternSet
patterns(&getContext());
287 patterns.insert<ChannelBufferLowering, PureModuleLowering, FIFOLowering>(
292 applyPartialConversion(getOperation(), target, std::move(
patterns))))
296 std::unique_ptr<OperationPass<ModuleOp>>
298 return std::make_unique<ESIToPhysicalPass>();
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
Instantiate one of these and use it to build typed backedges.
Backedge is a wrapper class around a Value.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
std::unique_ptr< OperationPass< ModuleOp > > createESIPhysicalLoweringPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.