13 #include "../PassDetails.h"
24 #include "mlir/Transforms/DialectConversion.h"
26 #include "llvm/ADT/StringExtras.h"
27 #include "llvm/ADT/TypeSwitch.h"
28 #include "llvm/Support/JSON.h"
30 using namespace circt;
44 using OpConversionPattern::OpConversionPattern;
47 matchAndRewrite(PipelineStageOp stage, OpAdaptor adaptor,
48 ConversionPatternRewriter &rewriter)
const final;
55 LogicalResult PipelineStageLowering::matchAndRewrite(
56 PipelineStageOp stage, OpAdaptor adaptor,
57 ConversionPatternRewriter &rewriter)
const {
58 auto loc = stage.getLoc();
59 auto chPort = stage.getInput().getType().dyn_cast<ChannelType>();
61 return rewriter.notifyMatchFailure(stage,
"stage had wrong type");
62 Operation *symTable = stage->getParentWithTrait<OpTrait::SymbolTable>();
63 auto stageModule =
builder.declareStage(symTable, stage);
67 ArrayAttr stageParams =
68 builder.getStageParameterList(rewriter.getUI32IntegerAttr(
width));
76 rewriter.create<UnwrapValidReadyOp>(loc, stage.getInput(), wrapReady);
78 StringRef pipeStageName =
"pipelineStage";
79 if (
auto name = stage->getAttrOfType<StringAttr>(
"name"))
80 pipeStageName = name.getValue();
84 llvm::SmallVector<Value> operands = {stage.getClk(), stage.getRst()};
85 operands.push_back(
unwrap.getRawOutput());
86 operands.push_back(
unwrap.getValid());
87 operands.push_back(stageReady);
88 auto stageInst = rewriter.create<InstanceOp>(loc, stageModule, pipeStageName,
89 operands, stageParams);
90 auto stageInstResults = stageInst.getResults();
94 wrapReady.
setValue(stageInstResults[0]);
96 x = stageInstResults[1];
97 xValid = stageInstResults[2];
100 auto wrap = rewriter.create<WrapValidReadyOp>(
101 loc, chPort, rewriter.getI1Type(), x, xValid);
105 rewriter.replaceOp(stage,
wrap.getChanOutput());
113 using OpConversionPattern::OpConversionPattern;
116 matchAndRewrite(NullSourceOp nullop, OpAdaptor adaptor,
117 ConversionPatternRewriter &rewriter)
const final;
121 LogicalResult NullSourceOpLowering::matchAndRewrite(
122 NullSourceOp nullop, OpAdaptor adaptor,
123 ConversionPatternRewriter &rewriter)
const {
124 auto innerType = nullop.getOut().getType().cast<ChannelType>().getInner();
125 Location loc = nullop.getLoc();
128 return rewriter.notifyMatchFailure(
129 nullop,
"NullOp lowering only supports hw types");
131 rewriter.create<
hw::ConstantOp>(nullop.getLoc(), rewriter.getI1Type(), 0);
135 auto wrap = rewriter.create<WrapValidReadyOp>(loc, typedZero, valid);
136 wrap->setAttr(
"name", rewriter.getStringAttr(
"nullsource"));
137 rewriter.replaceOp(nullop, {
wrap.getChanOutput()});
143 struct RemoveWrapUnwrap :
public ConversionPattern {
145 RemoveWrapUnwrap(MLIRContext *context)
146 : ConversionPattern(MatchAnyOpTypeTag(), 1, context) {}
149 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
150 ConversionPatternRewriter &rewriter)
const override {
151 Value valid, ready,
data;
152 WrapValidReadyOp
wrap = dyn_cast<WrapValidReadyOp>(op);
153 UnwrapValidReadyOp
unwrap = dyn_cast<UnwrapValidReadyOp>(op);
155 if (!
wrap.getChanOutput().hasOneUse() ||
156 !(
unwrap = dyn_cast<UnwrapValidReadyOp>(
157 wrap.getChanOutput().use_begin()->getOwner())))
158 return rewriter.notifyMatchFailure(
159 wrap,
"This conversion only supports wrap-unwrap back-to-back. "
160 "Could not find 'unwrap'.");
164 ready =
unwrap.getReady();
166 wrap = dyn_cast<WrapValidReadyOp>(operands[0].getDefiningOp());
168 return rewriter.notifyMatchFailure(
169 operands[0].getDefiningOp(),
170 "This conversion only supports wrap-unwrap back-to-back. "
171 "Could not find 'wrap'.");
172 valid =
wrap.getValid();
179 if (!
wrap.getChanOutput().hasOneUse())
180 return rewriter.notifyMatchFailure(
wrap, [](Diagnostic &d) {
181 d <<
"This conversion only supports wrap-unwrap back-to-back. "
182 "Wrap didn't have exactly one use.";
184 rewriter.replaceOp(
wrap, {
nullptr, ready});
194 template <
typename Op>
200 matchAndRewrite(Op op,
typename Op::Adaptor adaptor,
201 ConversionPatternRewriter &rewriter)
const final {
202 if (failed(Op::canonicalize(op, rewriter)))
203 return rewriter.notifyMatchFailure(op->getLoc(),
"canonicalizer failed");
210 struct ESItoHWPass :
public LowerESItoHWBase<ESItoHWPass> {
211 void runOnOperation()
override;
220 using OpConversionPattern::OpConversionPattern;
223 matchAndRewrite(WrapSVInterfaceOp
wrap, OpAdaptor adaptor,
224 ConversionPatternRewriter &rewriter)
const final;
229 WrapInterfaceLower::matchAndRewrite(WrapSVInterfaceOp
wrap, OpAdaptor adaptor,
230 ConversionPatternRewriter &rewriter)
const {
231 auto operands = adaptor.getOperands();
232 if (operands.size() != 1)
233 return rewriter.notifyMatchFailure(
wrap, [&operands](Diagnostic &d) {
234 d <<
"wrap.iface has 1 argument. Got " << operands.size() <<
"operands";
236 auto sinkModport = dyn_cast<GetModportOp>(operands[0].getDefiningOp());
240 dyn_cast<InterfaceInstanceOp>(sinkModport.getIface().getDefiningOp());
244 auto loc =
wrap.getLoc();
245 auto validSignal = rewriter.create<ReadInterfaceSignalOp>(
248 dataSignal = rewriter.create<ReadInterfaceSignalOp>(loc, ifaceInstance,
250 auto wrapVR = rewriter.create<WrapValidReadyOp>(loc, dataSignal, validSignal);
251 rewriter.create<AssignInterfaceSignalOp>(
253 rewriter.replaceOp(
wrap, {wrapVR.getChanOutput()});
263 using OpConversionPattern::OpConversionPattern;
266 matchAndRewrite(UnwrapSVInterfaceOp
wrap, OpAdaptor adaptor,
267 ConversionPatternRewriter &rewriter)
const final;
271 LogicalResult UnwrapInterfaceLower::matchAndRewrite(
272 UnwrapSVInterfaceOp
unwrap, OpAdaptor adaptor,
273 ConversionPatternRewriter &rewriter)
const {
274 auto operands = adaptor.getOperands();
275 if (operands.size() != 2)
276 return rewriter.notifyMatchFailure(
unwrap, [&operands](Diagnostic &d) {
277 d <<
"Unwrap.iface has 2 arguments. Got " << operands.size()
281 auto sourceModport = dyn_cast<GetModportOp>(operands[1].getDefiningOp());
285 dyn_cast<InterfaceInstanceOp>(sourceModport.getIface().getDefiningOp());
289 auto loc =
unwrap.getLoc();
290 auto readySignal = rewriter.create<ReadInterfaceSignalOp>(
293 rewriter.create<UnwrapValidReadyOp>(loc, operands[0], readySignal);
294 rewriter.create<AssignInterfaceSignalOp>(
297 rewriter.create<AssignInterfaceSignalOp>(
311 using OpConversionPattern::OpConversionPattern;
314 matchAndRewrite(CosimToHostEndpointOp, OpAdaptor adaptor,
315 ConversionPatternRewriter &rewriter)
const final;
322 LogicalResult CosimToHostLowering::matchAndRewrite(
323 CosimToHostEndpointOp ep, OpAdaptor adaptor,
324 ConversionPatternRewriter &rewriter)
const {
325 auto loc = ep.getLoc();
326 auto *ctxt = rewriter.getContext();
329 Value toHost = adaptor.getToHost();
330 Type type = toHost.getType();
334 SmallVector<Attribute, 8> params;
337 rewriter.getI32IntegerAttr(
width)));
340 auto sendReady = bb.get(rewriter.getI1Type());
341 UnwrapValidReadyOp unwrapSend =
342 rewriter.create<UnwrapValidReadyOp>(loc, toHost, sendReady);
344 loc, rewriter.getIntegerType(
width), unwrapSend.getRawOutput());
347 Operation *symTable = ep->getParentWithTrait<OpTrait::SymbolTable>();
348 HWModuleExternOp endpoint =
349 builder.declareCosimEndpointToHostModule(symTable);
355 unwrapSend.getValid(),
356 castedSendData.getResult(),
358 auto cosimEpModule = rewriter.create<InstanceOp>(
359 loc, endpoint, ep.getNameAttr(), operands,
ArrayAttr::get(ctxt, params));
360 sendReady.setValue(cosimEpModule.getResult(0));
363 rewriter.eraseOp(ep);
371 struct CosimFromHostLowering
377 using OpConversionPattern::OpConversionPattern;
380 matchAndRewrite(CosimFromHostEndpointOp, OpAdaptor adaptor,
381 ConversionPatternRewriter &rewriter)
const final;
388 LogicalResult CosimFromHostLowering::matchAndRewrite(
389 CosimFromHostEndpointOp ep, OpAdaptor adaptor,
390 ConversionPatternRewriter &rewriter)
const {
391 auto loc = ep.getLoc();
392 auto *ctxt = rewriter.getContext();
395 ChannelType type = ep.getFromHost().getType();
399 SmallVector<Attribute, 8> params;
402 rewriter.getI32IntegerAttr(
width)));
405 auto recvReady = bb.get(rewriter.getI1Type());
408 Operation *symTable = ep->getParentWithTrait<OpTrait::SymbolTable>();
409 HWModuleExternOp endpoint =
410 builder.declareCosimEndpointFromHostModule(symTable);
413 StringAttr nameAttr = ep->getAttr(
"name").dyn_cast_or_null<StringAttr>();
414 StringRef name = nameAttr ? nameAttr.getValue() :
"CosimEndpointOp";
415 Value operands[] = {adaptor.getClk(), adaptor.getRst(), recvReady};
417 auto cosimEpModule = rewriter.create<InstanceOp>(
421 Value recvDataFromCosim = cosimEpModule.getResult(1);
422 Value recvValidFromCosim = cosimEpModule.getResult(0);
423 auto castedRecvData =
424 rewriter.create<
hw::BitcastOp>(loc, type.getInner(), recvDataFromCosim);
425 WrapValidReadyOp wrapRecv = rewriter.
create<WrapValidReadyOp>(
426 loc, castedRecvData.getResult(), recvValidFromCosim);
427 recvReady.setValue(wrapRecv.getReady());
430 rewriter.replaceOp(ep, wrapRecv.getChanOutput());
437 struct CosimManifestLowering
440 using OpConversionPattern::OpConversionPattern;
443 matchAndRewrite(CompressedManifestOp, OpAdaptor adaptor,
444 ConversionPatternRewriter &rewriter)
const final;
448 LogicalResult CosimManifestLowering::matchAndRewrite(
449 CompressedManifestOp op, OpAdaptor adaptor,
450 ConversionPatternRewriter &rewriter)
const {
451 MLIRContext *ctxt = rewriter.getContext();
452 Location loc = op.getLoc();
455 Attribute params[] = {
458 {{rewriter.getStringAttr(
"compressed_manifest"),
459 rewriter.getType<hw::UnpackedArrayType>(
460 rewriter.getI8Type(),
462 rewriter.getStringAttr(
"COMPRESSED_MANIFEST_SIZE"),
463 rewriter.getI32Type())),
467 rewriter.setInsertionPointToEnd(
468 op->getParentOfType<mlir::ModuleOp>().getBody());
469 auto manifestModule = rewriter.create<HWModuleExternOp>(
470 loc, rewriter.getStringAttr(
"Cosim_Manifest"), ports,
"Cosim_Manifest",
473 rewriter.setInsertionPoint(op);
476 SmallVector<Attribute> bytes;
477 for (
char b : op.getCompressedManifest().getData())
478 bytes.push_back(rewriter.getI8IntegerAttr(b));
479 auto manifestConstant = rewriter.create<hw::AggregateConstantOp>(
481 rewriter.getArrayAttr(bytes));
483 rewriter.create<sv::LogicOp>(loc, manifestConstant.getType());
484 rewriter.create<
sv::AssignOp>(loc, manifestLogic, manifestConstant);
488 rewriter.
create<hw::InstanceOp>(
489 loc, manifestModule,
"__manifest", ArrayRef<Value>({manifest}),
490 rewriter.getArrayAttr(
491 {ParamDeclAttr::get(
"COMPRESSED_MANIFEST_SIZE",
492 rewriter.getI32IntegerAttr(bytes.size()))}));
493 rewriter.eraseOp(op);
497 void ESItoHWPass::runOnOperation() {
498 auto top = getOperation();
499 auto *ctxt = &getContext();
501 ConversionTarget noBundlesTarget(*ctxt);
502 noBundlesTarget.markUnknownOpDynamicallyLegal(
503 [](Operation *) {
return true; });
504 noBundlesTarget.addIllegalOp<PackBundleOp>();
505 noBundlesTarget.addIllegalOp<UnpackBundleOp>();
506 RewritePatternSet bundlePatterns(&getContext());
507 bundlePatterns.add<CanonicalizerOpLowering<PackBundleOp>>(&getContext());
508 bundlePatterns.add<CanonicalizerOpLowering<UnpackBundleOp>>(&getContext());
509 if (failed(applyPartialConversion(getOperation(), noBundlesTarget,
510 std::move(bundlePatterns))))
514 ConversionTarget pass1Target(*ctxt);
515 pass1Target.addLegalDialect<comb::CombDialect>();
516 pass1Target.addLegalDialect<HWDialect>();
517 pass1Target.addLegalDialect<SVDialect>();
518 pass1Target.addLegalOp<WrapValidReadyOp, UnwrapValidReadyOp>();
520 pass1Target.addIllegalOp<WrapSVInterfaceOp, UnwrapSVInterfaceOp>();
521 pass1Target.addIllegalOp<PipelineStageOp>();
522 pass1Target.addIllegalOp<CompressedManifestOp>();
526 RewritePatternSet pass1Patterns(ctxt);
527 pass1Patterns.insert<PipelineStageLowering>(esiBuilder, ctxt);
528 pass1Patterns.insert<WrapInterfaceLower>(ctxt);
529 pass1Patterns.insert<UnwrapInterfaceLower>(ctxt);
530 pass1Patterns.insert<CosimToHostLowering>(esiBuilder);
531 pass1Patterns.insert<CosimFromHostLowering>(esiBuilder);
532 pass1Patterns.insert<NullSourceOpLowering>(ctxt);
535 pass1Patterns.insert<CosimManifestLowering>(ctxt);
540 applyPartialConversion(top, pass1Target, std::move(pass1Patterns))))
543 ConversionTarget pass2Target(*ctxt);
544 pass2Target.addLegalDialect<comb::CombDialect>();
545 pass2Target.addLegalDialect<HWDialect>();
546 pass2Target.addLegalDialect<SVDialect>();
547 pass2Target.addIllegalDialect<ESIDialect>();
549 RewritePatternSet pass2Patterns(ctxt);
550 pass2Patterns.insert<CanonicalizerOpLowering<UnwrapFIFOOp>>(ctxt);
551 pass2Patterns.insert<CanonicalizerOpLowering<WrapFIFOOp>>(ctxt);
552 pass2Patterns.insert<RemoveWrapUnwrap>(ctxt);
554 applyPartialConversion(top, pass2Target, std::move(pass2Patterns))))
559 return std::make_unique<ESItoHWPass>();
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
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)
Assist the lowering steps for conversions which need to create auxiliary IR.
static constexpr char validStr[]
static constexpr char readyStr[]
static constexpr char dataStr[]
def create(data_type, value)
def create(data_type, value)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
uint64_t getWidth(Type t)
StringAttr getTypeID(Type t)
std::unique_ptr< OperationPass< ModuleOp > > createESItoHWPass()
mlir::Type innerType(mlir::Type type)
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
This holds the name, type, direction of a module's ports.