10 #include "mlir/Transforms/DialectConversion.h"
12 using namespace circt;
13 using namespace firrtl;
20 if (
op.getNumOperands() != n)
21 return emitError() <<
" has " <<
op.getNumOperands()
22 <<
" inputs instead of " << n;
29 return emitError() <<
" missing output bundle";
30 if (b.getType().getNumElements() != n)
31 return emitError() <<
" has " << b.getType().getNumElements()
32 <<
" output elements instead of " << n;
38 if (
op.getParameters())
39 num =
op.getParameters().size();
40 if (num < n || num > n + c) {
41 auto d =
emitError() <<
" has " << num <<
" parameters instead of ";
45 d <<
" between " << n <<
" and " << (n + c);
52 for (
auto a :
op.getParameters()) {
53 auto param = cast<ParamDeclAttr>(a);
54 if (param.getName().getValue().equals(paramName)) {
55 if (isa<StringAttr>(param.getValue()))
58 return emitError() <<
" has parameter '" << param.getName()
59 <<
"' which should be a string but is not";
64 return emitError() <<
" is missing parameter " << paramName;
69 for (
auto a :
op.getParameters()) {
70 auto param = cast<ParamDeclAttr>(a);
71 if (param.getName().getValue().equals(paramName)) {
72 if (isa<IntegerAttr>(param.getValue()))
75 return emitError() <<
" has parameter '" << param.getName()
76 <<
"' which should be an integer but is not";
81 return emitError() <<
" is missing parameter " << paramName;
90 class IntrinsicOpConversion final
93 using OpConversionPattern::OpConversionPattern;
97 IntrinsicOpConversion(MLIRContext *context,
98 const ConversionMapTy &conversions,
99 size_t &numConversions,
100 bool allowUnknownIntrinsics =
false)
102 numConversions(numConversions),
103 allowUnknownIntrinsics(allowUnknownIntrinsics) {}
106 matchAndRewrite(GenericIntrinsicOp op, OpAdaptor adaptor,
107 ConversionPatternRewriter &rewriter)
const override {
109 auto it = conversions.find(op.getIntrinsicAttr());
110 if (it == conversions.end()) {
111 if (!allowUnknownIntrinsics)
112 return op.emitError(
"unknown intrinsic ") << op.getIntrinsicAttr();
116 auto &conv = *it->second;
125 const ConversionMapTy &conversions;
126 size_t &numConversions;
127 const bool allowUnknownIntrinsics;
136 bool allowUnknownIntrinsics) {
138 ConversionTarget target(*
context);
140 target.markUnknownOpDynamicallyLegal([](Operation *op) {
return true; });
141 if (allowUnknownIntrinsics)
142 target.addDynamicallyLegalOp<GenericIntrinsicOp>(
143 [
this](GenericIntrinsicOp op) {
144 return !
conversions.contains(op.getIntrinsicAttr());
147 target.addIllegalOp<GenericIntrinsicOp>();
152 allowUnknownIntrinsics);
154 if (failed(mlir::applyPartialConversion(mod, target, std::move(
patterns))))
178 using IntrinsicOpConverter::IntrinsicOpConverter;
187 using IntrinsicOpConverter::IntrinsicOpConverter;
196 using IntrinsicConverter::IntrinsicConverter;
204 PatternRewriter &rewriter)
override {
205 rewriter.replaceOpWithNewOp<PlusArgsTestIntrinsicOp>(
212 using IntrinsicConverter::IntrinsicConverter;
222 PatternRewriter &rewriter)
override {
224 auto newop = rewriter.create<PlusArgsValueIntrinsicOp>(
225 gi.
op.getLoc(), bty.getElementTypePreservingConst(0),
226 bty.getElementTypePreservingConst(1),
228 rewriter.replaceOpWithNewOp<BundleCreateOp>(
229 gi.
op, bty, ValueRange({newop.getFound(), newop.getResult()}));
233 class CirctClockGateConverter
236 using IntrinsicOpConverter::IntrinsicOpConverter;
239 if (gi.
op.getNumOperands() == 3) {
244 if (gi.
op.getNumOperands() == 2) {
248 gi.
emitError() <<
" has " << gi.
op.getNumOperands()
249 <<
" ports instead of 3 or 4";
254 class CirctClockInverterConverter
257 using IntrinsicOpConverter::IntrinsicOpConverter;
267 using IntrinsicConverter::IntrinsicConverter;
276 PatternRewriter &rewriter)
override {
278 gi.
getParamValue<IntegerAttr>(
"POW_2").getValue().getZExtValue();
280 auto pow2Attr = rewriter.getI64IntegerAttr(pow2);
282 rewriter.replaceOpWithNewOp<ClockDividerIntrinsicOp>(
283 gi.
op, adaptor.getOperands()[0], pow2Attr);
287 template <
typename OpTy>
299 template <
typename OpTy>
312 using IntrinsicConverter::IntrinsicConverter;
321 PatternRewriter &rewriter)
override {
322 auto getI64Attr = [&](IntegerAttr val) {
324 return IntegerAttr();
325 return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
327 auto delay = getI64Attr(gi.
getParamValue<IntegerAttr>(
"delay"));
328 auto length = getI64Attr(gi.
getParamValue<IntegerAttr>(
"length"));
329 rewriter.replaceOpWithNewOp<LTLDelayIntrinsicOp>(
330 gi.
op, gi.
op.getResultTypes(), adaptor.getOperands()[0], delay, length);
334 class CirctLTLClockConverter
337 using IntrinsicOpConverter::IntrinsicOpConverter;
349 using IntrinsicConverter::IntrinsicConverter;
358 PatternRewriter &rewriter)
override {
361 rewriter.replaceOpWithNewOp<Op>(gi.
op, adaptor.getOperands()[0], label);
365 class CirctMux2CellConverter
367 using IntrinsicOpConverter::IntrinsicOpConverter;
375 class CirctMux4CellConverter
377 using IntrinsicOpConverter::IntrinsicOpConverter;
385 class CirctHasBeenResetConverter
388 using IntrinsicOpConverter::IntrinsicOpConverter;
399 using IntrinsicOpConverter::IntrinsicOpConverter;
407 template <
class OpTy,
bool ifElseFatal = false>
410 using IntrinsicConverter::IntrinsicConverter;
422 PatternRewriter &rewriter)
override {
427 auto clock = adaptor.getOperands()[0];
428 auto predicate = adaptor.getOperands()[1];
429 auto enable = adaptor.getOperands()[2];
431 auto substitutions = adaptor.getOperands().drop_front(3);
432 auto name = label ? label.strref() :
"";
434 auto message = format ? format : rewriter.getStringAttr(
"");
435 auto op = rewriter.template replaceOpWithNewOp<OpTy>(
436 gi.
op, clock, predicate, enable, message, substitutions, name,
439 SmallVector<StringRef> guardStrings;
440 guards.strref().split(guardStrings,
';', -1,
442 rewriter.startOpModification(op);
443 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
444 rewriter.finalizeOpModification(op);
447 if constexpr (ifElseFatal) {
448 rewriter.startOpModification(op);
449 op->setAttr(
"format", rewriter.getStringAttr(
"ifElseFatal"));
450 rewriter.finalizeOpModification(op);
457 using IntrinsicConverter::IntrinsicConverter;
468 PatternRewriter &rewriter)
override {
472 auto clock = adaptor.getOperands()[0];
473 auto predicate = adaptor.getOperands()[1];
474 auto enable = adaptor.getOperands()[2];
476 auto name = label ? label.strref() :
"";
478 auto message = rewriter.getStringAttr(
"");
479 auto op = rewriter.replaceOpWithNewOp<CoverOp>(
480 gi.
op, clock, predicate, enable, message, ValueRange{}, name,
483 SmallVector<StringRef> guardStrings;
484 guards.strref().split(guardStrings,
';', -1,
486 rewriter.startOpModification(op);
487 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
488 rewriter.finalizeOpModification(op);
495 using IntrinsicConverter::IntrinsicConverter;
506 PatternRewriter &rewriter)
override {
511 auto predicate = adaptor.getOperands()[0];
512 auto enable = adaptor.getOperands()[1];
514 auto substitutions = adaptor.getOperands().drop_front(2);
515 auto name = label ? label.strref() :
"";
517 auto message = format ? format : rewriter.getStringAttr(
"");
518 auto op = rewriter.template replaceOpWithNewOp<UnclockedAssumeIntrinsicOp>(
519 gi.
op, predicate, enable, message, substitutions, name);
521 SmallVector<StringRef> guardStrings;
522 guards.strref().split(guardStrings,
';', -1,
524 rewriter.startOpModification(op);
525 op->setAttr(
"guards", rewriter.getStrArrayAttr(guardStrings));
526 rewriter.finalizeOpModification(op);
539 lowering.
add<CirctSizeofConverter>(
"circt.sizeof",
"circt_sizeof");
540 lowering.
add<CirctIsXConverter>(
"circt.isX",
"circt_isX");
541 lowering.
add<CirctPlusArgTestConverter>(
"circt.plusargs.test",
542 "circt_plusargs_test");
543 lowering.
add<CirctPlusArgValueConverter>(
"circt.plusargs.value",
544 "circt_plusargs_value");
545 lowering.
add<CirctClockGateConverter>(
"circt.clock_gate",
"circt_clock_gate");
546 lowering.
add<CirctClockInverterConverter>(
"circt.clock_inv",
548 lowering.
add<CirctClockDividerConverter>(
"circt.clock_div",
550 lowering.
add<CirctLTLBinaryConverter<LTLAndIntrinsicOp>>(
"circt.ltl.and",
552 lowering.
add<CirctLTLBinaryConverter<LTLOrIntrinsicOp>>(
"circt.ltl.or",
554 lowering.
add<CirctLTLBinaryConverter<LTLConcatIntrinsicOp>>(
555 "circt.ltl.concat",
"circt_ltl_concat");
556 lowering.
add<CirctLTLBinaryConverter<LTLImplicationIntrinsicOp>>(
557 "circt.ltl.implication",
"circt_ltl_implication");
558 lowering.
add<CirctLTLBinaryConverter<LTLDisableIntrinsicOp>>(
559 "circt.ltl.disable",
"circt_ltl_disable");
560 lowering.
add<CirctLTLUnaryConverter<LTLNotIntrinsicOp>>(
"circt.ltl.not",
562 lowering.
add<CirctLTLUnaryConverter<LTLEventuallyIntrinsicOp>>(
563 "circt.ltl.eventually",
"circt_ltl_eventually");
565 lowering.
add<CirctLTLDelayConverter>(
"circt.ltl.delay",
"circt_ltl_delay");
566 lowering.
add<CirctLTLClockConverter>(
"circt.ltl.clock",
"circt_ltl_clock");
568 lowering.
add<CirctVerifConverter<VerifAssertIntrinsicOp>>(
569 "circt.verif.assert",
"circt_verif_assert");
570 lowering.
add<CirctVerifConverter<VerifAssumeIntrinsicOp>>(
571 "circt.verif.assume",
"circt_verif_assume");
572 lowering.
add<CirctVerifConverter<VerifCoverIntrinsicOp>>(
"circt.verif.cover",
573 "circt_verif_cover");
574 lowering.
add<CirctMux2CellConverter>(
"circt.mux2cell",
"circt_mux2cell");
575 lowering.
add<CirctMux4CellConverter>(
"circt.mux4cell",
"circt_mux4cell");
576 lowering.
add<CirctHasBeenResetConverter>(
"circt.has_been_reset",
577 "circt_has_been_reset");
578 lowering.
add<CirctProbeConverter>(
"circt.fpga_probe",
"circt_fpga_probe");
579 lowering.
add<CirctAssertConverter<AssertOp>>(
"circt.chisel_assert",
580 "circt_chisel_assert");
581 lowering.
add<CirctAssertConverter<AssertOp,
true>>(
582 "circt.chisel_ifelsefatal",
"circt_chisel_ifelsefatal");
583 lowering.
add<CirctAssertConverter<AssumeOp>>(
"circt.chisel_assume",
584 "circt_chisel_assume");
585 lowering.
add<CirctCoverConverter>(
"circt.chisel_cover",
"circt_chisel_cover");
586 lowering.
add<CirctUnclockedAssumeConverter>(
"circt.unclocked_assume",
587 "circt_unclocked_assume");
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.
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)
ParseResult hasNoOutput()
A dialect interface to provide lowering conversions.
virtual void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const =0
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const