12#include "mlir/Transforms/DialectConversion.h"
15using namespace firrtl;
27 auto numOps =
op.getNumOperands();
29 if (numOps < n || numOps > m) {
30 auto err =
emitError() <<
" has " << numOps <<
" inputs instead of ";
34 err <<
" between " << n <<
" and " << m;
46 return emitError() <<
" missing output bundle";
47 if (b.getType().getNumElements() != n)
48 return emitError() <<
" has " << b.getType().getNumElements()
49 <<
" output elements instead of " << n;
55 if (
op.getParameters())
56 num =
op.getParameters().size();
57 if (num < n || num > n + c) {
58 auto d =
emitError() <<
" has " << num <<
" parameters instead of ";
62 d <<
" between " << n <<
" and " << (n + c);
69 for (
auto a :
op.getParameters()) {
70 auto param = cast<ParamDeclAttr>(a);
71 if (param.getName().getValue() == paramName) {
72 if (isa<StringAttr>(param.getValue()))
75 return emitError() <<
" has parameter '" << param.getName()
76 <<
"' which should be a string but is not";
81 return emitError() <<
" is missing parameter " << paramName;
86 for (
auto a :
op.getParameters()) {
87 auto param = cast<ParamDeclAttr>(a);
88 if (param.getName().getValue() == paramName) {
89 if (isa<IntegerAttr>(param.getValue()))
92 return emitError() <<
" has parameter '" << param.getName()
93 <<
"' which should be an integer but is not";
98 return emitError() <<
" is missing parameter " << paramName;
107class IntrinsicOpConversion final
112 IntrinsicOpConversion(TypeConverter &typeConverter, MLIRContext *context,
113 const ConversionMapTy &conversions,
114 size_t &numConversions,
115 bool allowUnknownIntrinsics =
false)
117 numConversions(numConversions),
118 allowUnknownIntrinsics(allowUnknownIntrinsics) {}
121 matchAndRewrite(GenericIntrinsicOp op, OpAdaptor adaptor,
122 ConversionPatternRewriter &rewriter)
const override {
124 auto it = conversions.find(op.getIntrinsicAttr());
125 if (it == conversions.end()) {
126 if (!allowUnknownIntrinsics)
127 return op.emitError(
"unknown intrinsic ") << op.getIntrinsicAttr();
131 auto &conv = *it->second;
132 auto result = conv.checkAndConvert(
GenericIntrinsic(op), adaptor, rewriter);
133 if (succeeded(result))
139 const ConversionMapTy &conversions;
140 size_t &numConversions;
141 const bool allowUnknownIntrinsics;
150 bool allowUnknownIntrinsics) {
152 ConversionTarget target(*
context);
154 target.markUnknownOpDynamicallyLegal([](Operation *op) {
return true; });
155 if (allowUnknownIntrinsics)
156 target.addDynamicallyLegalOp<GenericIntrinsicOp>(
157 [
this](GenericIntrinsicOp op) {
158 return !
conversions.contains(op.getIntrinsicAttr());
161 target.addIllegalOp<GenericIntrinsicOp>();
165 TypeConverter typeConverter;
166 typeConverter.addConversion([](Type type) {
return type; });
167 auto firrtlBaseTypeMaterialization =
168 [](OpBuilder &builder,
FIRRTLBaseType resultType, ValueRange inputs,
169 Location loc) -> Value {
170 if (inputs.size() != 1)
172 auto inputType = type_dyn_cast<FIRRTLBaseType>(inputs.front().getType());
180 auto w = builder.create<WireOp>(loc, resultType).getResult();
185 typeConverter.addSourceMaterialization(firrtlBaseTypeMaterialization);
187 typeConverter.addTargetMaterialization(firrtlBaseTypeMaterialization);
192 count, allowUnknownIntrinsics);
194 if (failed(mlir::applyPartialConversion(mod, target, std::move(
patterns))))
207 interface.populateIntrinsicLowerings(lowering);
218 using IntrinsicOpConverter::IntrinsicOpConverter;
227 using IntrinsicOpConverter::IntrinsicOpConverter;
236 using IntrinsicConverter::IntrinsicConverter;
244 PatternRewriter &rewriter)
override {
245 rewriter.replaceOpWithNewOp<PlusArgsTestIntrinsicOp>(
252 using IntrinsicConverter::IntrinsicConverter;
262 PatternRewriter &rewriter)
override {
264 auto newop = rewriter.create<PlusArgsValueIntrinsicOp>(
265 gi.
op.getLoc(), bty.getElementTypePreservingConst(0),
266 bty.getElementTypePreservingConst(1),
268 rewriter.replaceOpWithNewOp<BundleCreateOp>(
269 gi.
op, bty, ValueRange({newop.getFound(), newop.getResult()}));
273class CirctClockGateConverter
276 using IntrinsicOpConverter::IntrinsicOpConverter;
279 if (gi.
op.getNumOperands() == 3) {
284 if (gi.
op.getNumOperands() == 2) {
288 gi.
emitError() <<
" has " << gi.
op.getNumOperands()
289 <<
" ports instead of 3 or 4";
294class CirctClockInverterConverter
297 using IntrinsicOpConverter::IntrinsicOpConverter;
307 using IntrinsicConverter::IntrinsicConverter;
316 PatternRewriter &rewriter)
override {
318 gi.
getParamValue<IntegerAttr>(
"POW_2").getValue().getZExtValue();
320 auto pow2Attr = rewriter.getI64IntegerAttr(pow2);
322 rewriter.replaceOpWithNewOp<ClockDividerIntrinsicOp>(
323 gi.
op, adaptor.getOperands()[0], pow2Attr);
327template <
typename OpTy>
339template <
typename OpTy>
352 using IntrinsicConverter::IntrinsicConverter;
361 PatternRewriter &rewriter)
override {
362 auto getI64Attr = [&](IntegerAttr val) {
364 return IntegerAttr();
365 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
367 auto delay = getI64Attr(gi.
getParamValue<IntegerAttr>(
"delay"));
368 auto length = getI64Attr(gi.
getParamValue<IntegerAttr>(
"length"));
369 rewriter.replaceOpWithNewOp<LTLDelayIntrinsicOp>(
370 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], delay, length);
374class CirctLTLClockConverter
377 using IntrinsicOpConverter::IntrinsicOpConverter;
388 using IntrinsicConverter::IntrinsicConverter;
397 PatternRewriter &rewriter)
override {
398 auto getI64Attr = [&](IntegerAttr val) {
400 return IntegerAttr();
401 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
403 auto base = getI64Attr(gi.
getParamValue<IntegerAttr>(
"base"));
404 auto more = getI64Attr(gi.
getParamValue<IntegerAttr>(
"more"));
405 rewriter.replaceOpWithNewOp<LTLRepeatIntrinsicOp>(
406 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], base, more);
412 using IntrinsicConverter::IntrinsicConverter;
421 PatternRewriter &rewriter)
override {
422 auto getI64Attr = [&](IntegerAttr val) {
424 return IntegerAttr();
425 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
427 auto base = getI64Attr(gi.
getParamValue<IntegerAttr>(
"base"));
428 auto more = getI64Attr(gi.
getParamValue<IntegerAttr>(
"more"));
429 rewriter.replaceOpWithNewOp<LTLGoToRepeatIntrinsicOp>(
430 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], base, more);
436 using IntrinsicConverter::IntrinsicConverter;
445 PatternRewriter &rewriter)
override {
446 auto getI64Attr = [&](IntegerAttr val) {
448 return IntegerAttr();
449 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
451 auto base = getI64Attr(gi.
getParamValue<IntegerAttr>(
"base"));
452 auto more = getI64Attr(gi.
getParamValue<IntegerAttr>(
"more"));
453 rewriter.replaceOpWithNewOp<LTLNonConsecutiveRepeatIntrinsicOp>(
454 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], base, more);
461 using IntrinsicConverter::IntrinsicConverter;
470 PatternRewriter &rewriter)
override {
472 auto operands = adaptor.getOperands();
477 enable = operands[1];
479 rewriter.replaceOpWithNewOp<Op>(gi.
op, operands[0], enable, label);
484 using IntrinsicConverter::IntrinsicConverter;
492 PatternRewriter &rewriter)
override {
493 auto operands = adaptor.getOperands();
494 rewriter.replaceOpWithNewOp<Mux2CellIntrinsicOp>(gi.
op, operands[0],
495 operands[1], operands[2]);
500 using IntrinsicConverter::IntrinsicConverter;
508 PatternRewriter &rewriter)
override {
509 auto operands = adaptor.getOperands();
510 rewriter.replaceOpWithNewOp<Mux4CellIntrinsicOp>(
511 gi.
op, operands[0], operands[1], operands[2], operands[3], operands[4]);
515class CirctHasBeenResetConverter
518 using IntrinsicOpConverter::IntrinsicOpConverter;
529 using IntrinsicOpConverter::IntrinsicOpConverter;
537template <
class OpTy,
bool ifElseFatal = false>
540 using IntrinsicConverter::IntrinsicConverter;
552 PatternRewriter &rewriter)
override {
557 auto clock = adaptor.getOperands()[0];
558 auto predicate = adaptor.getOperands()[1];
559 auto enable = adaptor.getOperands()[2];
561 auto substitutions = adaptor.getOperands().drop_front(3);
562 auto name = label ? label.strref() :
"";
564 auto message = format ? format : rewriter.getStringAttr(
"");
565 auto op = rewriter.template replaceOpWithNewOp<OpTy>(
566 gi.
op, clock, predicate, enable, message, substitutions, name,
569 SmallVector<StringRef> guardStrings;
570 guards.strref().split(guardStrings,
';', -1,
572 rewriter.startOpModification(op);
573 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
574 rewriter.finalizeOpModification(op);
577 if constexpr (ifElseFatal) {
578 rewriter.startOpModification(op);
579 op->setAttr(
"format", rewriter.getStringAttr(
"ifElseFatal"));
580 rewriter.finalizeOpModification(op);
587 using IntrinsicConverter::IntrinsicConverter;
598 PatternRewriter &rewriter)
override {
602 auto clock = adaptor.getOperands()[0];
603 auto predicate = adaptor.getOperands()[1];
604 auto enable = adaptor.getOperands()[2];
606 auto name = label ? label.strref() :
"";
608 auto message = rewriter.getStringAttr(
"");
609 auto op = rewriter.replaceOpWithNewOp<CoverOp>(
610 gi.
op, clock, predicate, enable, message, ValueRange{}, name,
613 SmallVector<StringRef> guardStrings;
614 guards.strref().split(guardStrings,
';', -1,
616 rewriter.startOpModification(op);
617 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
618 rewriter.finalizeOpModification(op);
625 using IntrinsicConverter::IntrinsicConverter;
636 PatternRewriter &rewriter)
override {
641 auto predicate = adaptor.getOperands()[0];
642 auto enable = adaptor.getOperands()[1];
644 auto substitutions = adaptor.getOperands().drop_front(2);
645 auto name = label ? label.strref() :
"";
647 auto message = format ? format : rewriter.getStringAttr(
"");
648 auto op = rewriter.template replaceOpWithNewOp<UnclockedAssumeIntrinsicOp>(
649 gi.
op, predicate, enable, message, substitutions, name);
651 SmallVector<StringRef> guardStrings;
652 guards.strref().split(guardStrings,
';', -1,
654 rewriter.startOpModification(op);
655 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
656 rewriter.finalizeOpModification(op);
663 return !gi.
getParamValue<IntegerAttr>(
"isClocked").getValue().isZero();
667 using IntrinsicConverter::IntrinsicConverter;
675 auto isClocked = getIsClocked(gi);
687 PatternRewriter &rewriter)
override {
688 auto isClocked = getIsClocked(gi);
689 auto functionName = gi.
getParamValue<StringAttr>(
"functionName");
690 ArrayAttr inputNamesStrArray;
691 StringAttr outputStr = gi.
getParamValue<StringAttr>(
"outputName");
692 if (
auto inputNames = gi.
getParamValue<StringAttr>(
"inputNames")) {
693 SmallVector<StringRef> inputNamesTemporary;
694 inputNames.strref().split(inputNamesTemporary,
';', -1,
696 inputNamesStrArray = rewriter.getStrArrayAttr(inputNamesTemporary);
699 Value clock = isClocked ? adaptor.getOperands()[0] : Value();
700 Value enable = adaptor.getOperands()[
static_cast<size_t>(isClocked)];
703 adaptor.getOperands().drop_front(
static_cast<size_t>(isClocked) + 1);
705 rewriter.replaceOpWithNewOp<DPICallIntrinsicOp>(
706 gi.
op, gi.
op.getResultTypes(), functionName, inputNamesStrArray,
707 outputStr, clock, enable, inputs);
719 lowering.
add<CirctSizeofConverter>(
"circt.sizeof",
"circt_sizeof");
720 lowering.
add<CirctIsXConverter>(
"circt.isX",
"circt_isX");
721 lowering.
add<CirctPlusArgTestConverter>(
"circt.plusargs.test",
722 "circt_plusargs_test");
723 lowering.
add<CirctPlusArgValueConverter>(
"circt.plusargs.value",
724 "circt_plusargs_value");
725 lowering.
add<CirctClockGateConverter>(
"circt.clock_gate",
"circt_clock_gate");
726 lowering.
add<CirctClockInverterConverter>(
"circt.clock_inv",
728 lowering.
add<CirctClockDividerConverter>(
"circt.clock_div",
730 lowering.
add<CirctLTLBinaryConverter<LTLAndIntrinsicOp>>(
"circt.ltl.and",
732 lowering.
add<CirctLTLBinaryConverter<LTLOrIntrinsicOp>>(
"circt.ltl.or",
734 lowering.
add<CirctLTLBinaryConverter<LTLIntersectIntrinsicOp>>(
735 "circt.ltl.intersect",
"circt_ltl_intersect");
736 lowering.
add<CirctLTLBinaryConverter<LTLConcatIntrinsicOp>>(
737 "circt.ltl.concat",
"circt_ltl_concat");
738 lowering.
add<CirctLTLBinaryConverter<LTLImplicationIntrinsicOp>>(
739 "circt.ltl.implication",
"circt_ltl_implication");
740 lowering.
add<CirctLTLBinaryConverter<LTLUntilIntrinsicOp>>(
"circt.ltl.until",
742 lowering.
add<CirctLTLUnaryConverter<LTLNotIntrinsicOp>>(
"circt.ltl.not",
744 lowering.
add<CirctLTLUnaryConverter<LTLEventuallyIntrinsicOp>>(
745 "circt.ltl.eventually",
"circt_ltl_eventually");
747 lowering.
add<CirctLTLDelayConverter>(
"circt.ltl.delay",
"circt_ltl_delay");
748 lowering.
add<CirctLTLRepeatConverter>(
"circt.ltl.repeat",
"circt_ltl_repeat");
749 lowering.
add<CirctLTLGoToRepeatConverter>(
"circt.ltl.goto_repeat",
750 "circt_ltl_goto_repeat");
751 lowering.
add<CirctLTLNonConsecutiveRepeatConverter>(
752 "circt.ltl.non_consecutive_repeat",
"circt_ltl_non_consecutive_repeat");
753 lowering.
add<CirctLTLClockConverter>(
"circt.ltl.clock",
"circt_ltl_clock");
755 lowering.
add<CirctVerifConverter<VerifAssertIntrinsicOp>>(
756 "circt.verif.assert",
"circt_verif_assert");
757 lowering.
add<CirctVerifConverter<VerifAssumeIntrinsicOp>>(
758 "circt.verif.assume",
"circt_verif_assume");
759 lowering.
add<CirctVerifConverter<VerifCoverIntrinsicOp>>(
"circt.verif.cover",
760 "circt_verif_cover");
761 lowering.
add<CirctMux2CellConverter>(
"circt.mux2cell",
"circt_mux2cell");
762 lowering.
add<CirctMux4CellConverter>(
"circt.mux4cell",
"circt_mux4cell");
763 lowering.
add<CirctHasBeenResetConverter>(
"circt.has_been_reset",
764 "circt_has_been_reset");
765 lowering.
add<CirctProbeConverter>(
"circt.fpga_probe",
"circt_fpga_probe");
766 lowering.
add<CirctAssertConverter<AssertOp>>(
"circt.chisel_assert",
767 "circt_chisel_assert");
768 lowering.
add<CirctAssertConverter<AssertOp,
true>>(
769 "circt.chisel_ifelsefatal",
"circt_chisel_ifelsefatal");
770 lowering.
add<CirctAssertConverter<AssumeOp>>(
"circt.chisel_assume",
771 "circt_chisel_assume");
772 lowering.
add<CirctCoverConverter>(
"circt.chisel_cover",
"circt_chisel_cover");
773 lowering.
add<CirctUnclockedAssumeConverter>(
"circt.unclocked_assume",
774 "circt_unclocked_assume");
775 lowering.
add<CirctDPICallConverter>(
"circt.dpi_call",
"circt_dpi_call");
Base class for Intrinsic Converters.
Lowering helper which collects all intrinsic converters.
FailureOr< size_t > lower(FModuleOp mod, bool allowUnknownIntrinsics=false)
Lowers all intrinsics in a module. Returns number converted or failure.
llvm::DenseMap< StringAttr, std::unique_ptr< IntrinsicConverter > > ConversionMapTy
void add(Args... args)
Registers a converter to one or more intrinsic names.
MLIRContext * context
Reference to the MLIR context.
ConversionMapTy conversions
Mapping from intrinsic names to converters.
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const override
Helper class for checking and extracting information from the generic instrinsic op.
ParseResult sizedInput(unsigned n, int32_t size)
mlir::TypedValue< BundleType > getOutputBundle()
T getParamValue(StringRef name)
Get parameter value by name, if present, as requested type.
ParseResult typedOutput()
ParseResult hasResetInput(unsigned n)
ParseResult typedInput(unsigned n)
ParseResult hasNOutputElements(unsigned n)
InFlightDiagnostic emitError()
ParseResult namedIntParam(StringRef paramName, bool optional=false)
ParseResult namedParam(StringRef paramName, bool optional=false)
ParseResult sizedOutput(int32_t size)
ParseResult sizedOutputElement(unsigned n, StringRef name, int32_t size)
ParseResult hasNParam(unsigned n, unsigned c=0)
ParseResult hasOutputElement(unsigned n, StringRef name)
ParseResult hasNInputs(unsigned n, unsigned c=0)
ParseResult hasNoOutput()
A dialect interface to provide lowering conversions.
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const