12 #include "mlir/Transforms/DialectConversion.h"
14 using namespace circt;
15 using namespace firrtl;
24 auto numOps =
op.getNumOperands();
26 if (numOps < n || numOps > m) {
27 auto err =
emitError() <<
" has " << numOps <<
" inputs instead of ";
31 err <<
" between " << n <<
" and " << m;
43 return emitError() <<
" missing output bundle";
44 if (b.getType().getNumElements() != n)
45 return emitError() <<
" has " << b.getType().getNumElements()
46 <<
" output elements instead of " << n;
52 if (
op.getParameters())
53 num =
op.getParameters().size();
54 if (num < n || num > n + c) {
55 auto d =
emitError() <<
" has " << num <<
" parameters instead of ";
59 d <<
" between " << n <<
" and " << (n + c);
66 for (
auto a :
op.getParameters()) {
67 auto param = cast<ParamDeclAttr>(a);
68 if (param.getName().getValue() == paramName) {
69 if (isa<StringAttr>(param.getValue()))
72 return emitError() <<
" has parameter '" << param.getName()
73 <<
"' which should be a string but is not";
78 return emitError() <<
" is missing parameter " << paramName;
83 for (
auto a :
op.getParameters()) {
84 auto param = cast<ParamDeclAttr>(a);
85 if (param.getName().getValue() == paramName) {
86 if (isa<IntegerAttr>(param.getValue()))
89 return emitError() <<
" has parameter '" << param.getName()
90 <<
"' which should be an integer but is not";
95 return emitError() <<
" is missing parameter " << paramName;
104 class IntrinsicOpConversion final
109 IntrinsicOpConversion(TypeConverter &typeConverter, MLIRContext *context,
110 const ConversionMapTy &conversions,
111 size_t &numConversions,
112 bool allowUnknownIntrinsics =
false)
114 numConversions(numConversions),
115 allowUnknownIntrinsics(allowUnknownIntrinsics) {}
118 matchAndRewrite(GenericIntrinsicOp op, OpAdaptor adaptor,
119 ConversionPatternRewriter &rewriter)
const override {
121 auto it = conversions.find(op.getIntrinsicAttr());
122 if (it == conversions.end()) {
123 if (!allowUnknownIntrinsics)
124 return op.emitError(
"unknown intrinsic ") << op.getIntrinsicAttr();
128 auto &conv = *it->second;
137 const ConversionMapTy &conversions;
138 size_t &numConversions;
139 const bool allowUnknownIntrinsics;
148 bool allowUnknownIntrinsics) {
150 ConversionTarget target(*
context);
152 target.markUnknownOpDynamicallyLegal([](Operation *op) {
return true; });
153 if (allowUnknownIntrinsics)
154 target.addDynamicallyLegalOp<GenericIntrinsicOp>(
155 [
this](GenericIntrinsicOp op) {
156 return !
conversions.contains(op.getIntrinsicAttr());
159 target.addIllegalOp<GenericIntrinsicOp>();
163 TypeConverter typeConverter;
164 typeConverter.addConversion([](Type type) {
return type; });
165 auto firrtlBaseTypeMaterialization =
166 [](OpBuilder &builder,
FIRRTLBaseType resultType, ValueRange inputs,
167 Location loc) -> Value {
168 if (inputs.size() != 1)
170 auto inputType = type_dyn_cast<FIRRTLBaseType>(inputs.front().getType());
178 auto w = builder.create<WireOp>(loc, resultType).getResult();
183 typeConverter.addSourceMaterialization(firrtlBaseTypeMaterialization);
185 typeConverter.addTargetMaterialization(firrtlBaseTypeMaterialization);
190 count, allowUnknownIntrinsics);
192 if (failed(mlir::applyPartialConversion(mod, target, std::move(
patterns))))
216 using IntrinsicOpConverter::IntrinsicOpConverter;
225 using IntrinsicOpConverter::IntrinsicOpConverter;
234 using IntrinsicConverter::IntrinsicConverter;
242 PatternRewriter &rewriter)
override {
243 rewriter.replaceOpWithNewOp<PlusArgsTestIntrinsicOp>(
250 using IntrinsicConverter::IntrinsicConverter;
260 PatternRewriter &rewriter)
override {
262 auto newop = rewriter.create<PlusArgsValueIntrinsicOp>(
263 gi.
op.getLoc(), bty.getElementTypePreservingConst(0),
264 bty.getElementTypePreservingConst(1),
266 rewriter.replaceOpWithNewOp<BundleCreateOp>(
267 gi.
op, bty, ValueRange({newop.getFound(), newop.getResult()}));
271 class CirctClockGateConverter
274 using IntrinsicOpConverter::IntrinsicOpConverter;
277 if (gi.
op.getNumOperands() == 3) {
282 if (gi.
op.getNumOperands() == 2) {
286 gi.
emitError() <<
" has " << gi.
op.getNumOperands()
287 <<
" ports instead of 3 or 4";
292 class CirctClockInverterConverter
295 using IntrinsicOpConverter::IntrinsicOpConverter;
305 using IntrinsicConverter::IntrinsicConverter;
314 PatternRewriter &rewriter)
override {
316 gi.
getParamValue<IntegerAttr>(
"POW_2").getValue().getZExtValue();
318 auto pow2Attr = rewriter.getI64IntegerAttr(pow2);
320 rewriter.replaceOpWithNewOp<ClockDividerIntrinsicOp>(
321 gi.
op, adaptor.getOperands()[0], pow2Attr);
325 template <
typename OpTy>
337 template <
typename OpTy>
350 using IntrinsicConverter::IntrinsicConverter;
359 PatternRewriter &rewriter)
override {
360 auto getI64Attr = [&](IntegerAttr val) {
362 return IntegerAttr();
363 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
365 auto delay = getI64Attr(gi.
getParamValue<IntegerAttr>(
"delay"));
366 auto length = getI64Attr(gi.
getParamValue<IntegerAttr>(
"length"));
367 rewriter.replaceOpWithNewOp<LTLDelayIntrinsicOp>(
368 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], delay, length);
372 class CirctLTLClockConverter
375 using IntrinsicOpConverter::IntrinsicOpConverter;
386 using IntrinsicConverter::IntrinsicConverter;
395 PatternRewriter &rewriter)
override {
396 auto getI64Attr = [&](IntegerAttr val) {
398 return IntegerAttr();
399 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
401 auto base = getI64Attr(gi.
getParamValue<IntegerAttr>(
"base"));
402 auto more = getI64Attr(gi.
getParamValue<IntegerAttr>(
"more"));
403 rewriter.replaceOpWithNewOp<LTLRepeatIntrinsicOp>(
404 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], base, more);
410 using IntrinsicConverter::IntrinsicConverter;
419 PatternRewriter &rewriter)
override {
420 auto getI64Attr = [&](IntegerAttr val) {
422 return IntegerAttr();
423 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
425 auto base = getI64Attr(gi.
getParamValue<IntegerAttr>(
"base"));
426 auto more = getI64Attr(gi.
getParamValue<IntegerAttr>(
"more"));
427 rewriter.replaceOpWithNewOp<LTLGoToRepeatIntrinsicOp>(
428 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], base, more);
434 using IntrinsicConverter::IntrinsicConverter;
443 PatternRewriter &rewriter)
override {
444 auto getI64Attr = [&](IntegerAttr val) {
446 return IntegerAttr();
447 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
449 auto base = getI64Attr(gi.
getParamValue<IntegerAttr>(
"base"));
450 auto more = getI64Attr(gi.
getParamValue<IntegerAttr>(
"more"));
451 rewriter.replaceOpWithNewOp<LTLNonConsecutiveRepeatIntrinsicOp>(
452 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], base, more);
459 using IntrinsicConverter::IntrinsicConverter;
468 PatternRewriter &rewriter)
override {
470 auto operands = adaptor.getOperands();
475 enable = operands[1];
477 rewriter.replaceOpWithNewOp<Op>(gi.
op, operands[0], enable, label);
482 using IntrinsicConverter::IntrinsicConverter;
490 PatternRewriter &rewriter)
override {
491 auto operands = adaptor.getOperands();
492 rewriter.replaceOpWithNewOp<Mux2CellIntrinsicOp>(gi.
op, operands[0],
493 operands[1], operands[2]);
498 using IntrinsicConverter::IntrinsicConverter;
506 PatternRewriter &rewriter)
override {
507 auto operands = adaptor.getOperands();
508 rewriter.replaceOpWithNewOp<Mux4CellIntrinsicOp>(
509 gi.
op, operands[0], operands[1], operands[2], operands[3], operands[4]);
513 class CirctHasBeenResetConverter
516 using IntrinsicOpConverter::IntrinsicOpConverter;
527 using IntrinsicOpConverter::IntrinsicOpConverter;
535 template <
class OpTy,
bool ifElseFatal = false>
538 using IntrinsicConverter::IntrinsicConverter;
550 PatternRewriter &rewriter)
override {
555 auto clock = adaptor.getOperands()[0];
556 auto predicate = adaptor.getOperands()[1];
557 auto enable = adaptor.getOperands()[2];
559 auto substitutions = adaptor.getOperands().drop_front(3);
560 auto name = label ? label.strref() :
"";
562 auto message = format ? format : rewriter.getStringAttr(
"");
563 auto op = rewriter.template replaceOpWithNewOp<OpTy>(
564 gi.
op, clock, predicate, enable, message, substitutions, name,
567 SmallVector<StringRef> guardStrings;
568 guards.strref().split(guardStrings,
';', -1,
570 rewriter.startOpModification(op);
571 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
572 rewriter.finalizeOpModification(op);
575 if constexpr (ifElseFatal) {
576 rewriter.startOpModification(op);
577 op->setAttr(
"format", rewriter.getStringAttr(
"ifElseFatal"));
578 rewriter.finalizeOpModification(op);
585 using IntrinsicConverter::IntrinsicConverter;
596 PatternRewriter &rewriter)
override {
600 auto clock = adaptor.getOperands()[0];
601 auto predicate = adaptor.getOperands()[1];
602 auto enable = adaptor.getOperands()[2];
604 auto name = label ? label.strref() :
"";
606 auto message = rewriter.getStringAttr(
"");
607 auto op = rewriter.replaceOpWithNewOp<CoverOp>(
608 gi.
op, clock, predicate, enable, message, ValueRange{}, name,
611 SmallVector<StringRef> guardStrings;
612 guards.strref().split(guardStrings,
';', -1,
614 rewriter.startOpModification(op);
615 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
616 rewriter.finalizeOpModification(op);
623 using IntrinsicConverter::IntrinsicConverter;
634 PatternRewriter &rewriter)
override {
639 auto predicate = adaptor.getOperands()[0];
640 auto enable = adaptor.getOperands()[1];
642 auto substitutions = adaptor.getOperands().drop_front(2);
643 auto name = label ? label.strref() :
"";
645 auto message = format ? format : rewriter.getStringAttr(
"");
646 auto op = rewriter.template replaceOpWithNewOp<UnclockedAssumeIntrinsicOp>(
647 gi.
op, predicate, enable, message, substitutions, name);
649 SmallVector<StringRef> guardStrings;
650 guards.strref().split(guardStrings,
';', -1,
652 rewriter.startOpModification(op);
653 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
654 rewriter.finalizeOpModification(op);
661 return !gi.
getParamValue<IntegerAttr>(
"isClocked").getValue().isZero();
665 using IntrinsicConverter::IntrinsicConverter;
673 auto isClocked = getIsClocked(gi);
685 PatternRewriter &rewriter)
override {
686 auto isClocked = getIsClocked(gi);
687 auto functionName = gi.
getParamValue<StringAttr>(
"functionName");
688 ArrayAttr inputNamesStrArray;
689 StringAttr outputStr = gi.
getParamValue<StringAttr>(
"outputName");
690 if (
auto inputNames = gi.
getParamValue<StringAttr>(
"inputNames")) {
691 SmallVector<StringRef> inputNamesTemporary;
692 inputNames.strref().split(inputNamesTemporary,
';', -1,
694 inputNamesStrArray = rewriter.getStrArrayAttr(inputNamesTemporary);
697 Value clock = isClocked ? adaptor.getOperands()[0] : Value();
698 Value enable = adaptor.getOperands()[
static_cast<size_t>(isClocked)];
701 adaptor.getOperands().drop_front(
static_cast<size_t>(isClocked) + 1);
703 rewriter.replaceOpWithNewOp<DPICallIntrinsicOp>(
704 gi.
op, gi.
op.getResultTypes(), functionName, inputNamesStrArray,
705 outputStr, clock, enable, inputs);
717 lowering.
add<CirctSizeofConverter>(
"circt.sizeof",
"circt_sizeof");
718 lowering.
add<CirctIsXConverter>(
"circt.isX",
"circt_isX");
719 lowering.
add<CirctPlusArgTestConverter>(
"circt.plusargs.test",
720 "circt_plusargs_test");
721 lowering.
add<CirctPlusArgValueConverter>(
"circt.plusargs.value",
722 "circt_plusargs_value");
723 lowering.
add<CirctClockGateConverter>(
"circt.clock_gate",
"circt_clock_gate");
724 lowering.
add<CirctClockInverterConverter>(
"circt.clock_inv",
726 lowering.
add<CirctClockDividerConverter>(
"circt.clock_div",
728 lowering.
add<CirctLTLBinaryConverter<LTLAndIntrinsicOp>>(
"circt.ltl.and",
730 lowering.
add<CirctLTLBinaryConverter<LTLOrIntrinsicOp>>(
"circt.ltl.or",
732 lowering.
add<CirctLTLBinaryConverter<LTLIntersectIntrinsicOp>>(
733 "circt.ltl.intersect",
"circt_ltl_intersect");
734 lowering.
add<CirctLTLBinaryConverter<LTLConcatIntrinsicOp>>(
735 "circt.ltl.concat",
"circt_ltl_concat");
736 lowering.
add<CirctLTLBinaryConverter<LTLImplicationIntrinsicOp>>(
737 "circt.ltl.implication",
"circt_ltl_implication");
738 lowering.
add<CirctLTLBinaryConverter<LTLUntilIntrinsicOp>>(
"circt.ltl.until",
740 lowering.
add<CirctLTLUnaryConverter<LTLNotIntrinsicOp>>(
"circt.ltl.not",
742 lowering.
add<CirctLTLUnaryConverter<LTLEventuallyIntrinsicOp>>(
743 "circt.ltl.eventually",
"circt_ltl_eventually");
745 lowering.
add<CirctLTLDelayConverter>(
"circt.ltl.delay",
"circt_ltl_delay");
746 lowering.
add<CirctLTLRepeatConverter>(
"circt.ltl.repeat",
"circt_ltl_repeat");
747 lowering.
add<CirctLTLGoToRepeatConverter>(
"circt.ltl.goto_repeat",
748 "circt_ltl_goto_repeat");
749 lowering.
add<CirctLTLNonConsecutiveRepeatConverter>(
750 "circt.ltl.non_consecutive_repeat",
"circt_ltl_non_consecutive_repeat");
751 lowering.
add<CirctLTLClockConverter>(
"circt.ltl.clock",
"circt_ltl_clock");
753 lowering.
add<CirctVerifConverter<VerifAssertIntrinsicOp>>(
754 "circt.verif.assert",
"circt_verif_assert");
755 lowering.
add<CirctVerifConverter<VerifAssumeIntrinsicOp>>(
756 "circt.verif.assume",
"circt_verif_assume");
757 lowering.
add<CirctVerifConverter<VerifCoverIntrinsicOp>>(
"circt.verif.cover",
758 "circt_verif_cover");
759 lowering.
add<CirctMux2CellConverter>(
"circt.mux2cell",
"circt_mux2cell");
760 lowering.
add<CirctMux4CellConverter>(
"circt.mux4cell",
"circt_mux4cell");
761 lowering.
add<CirctHasBeenResetConverter>(
"circt.has_been_reset",
762 "circt_has_been_reset");
763 lowering.
add<CirctProbeConverter>(
"circt.fpga_probe",
"circt_fpga_probe");
764 lowering.
add<CirctAssertConverter<AssertOp>>(
"circt.chisel_assert",
765 "circt_chisel_assert");
766 lowering.
add<CirctAssertConverter<AssertOp,
true>>(
767 "circt.chisel_ifelsefatal",
"circt_chisel_ifelsefatal");
768 lowering.
add<CirctAssertConverter<AssumeOp>>(
"circt.chisel_assume",
769 "circt_chisel_assume");
770 lowering.
add<CirctCoverConverter>(
"circt.chisel_cover",
"circt_chisel_cover");
771 lowering.
add<CirctUnclockedAssumeConverter>(
"circt.unclocked_assume",
772 "circt_unclocked_assume");
773 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.
virtual void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const =0
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const