CIRCT  19.0.0git
FIRRTLIntrinsics.cpp
Go to the documentation of this file.
1 //===- FIRRTLIntrinsics.cpp - Lower Intrinsics ------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
12 #include "mlir/Transforms/DialectConversion.h"
13 
14 using namespace circt;
15 using namespace firrtl;
16 
17 //===----------------------------------------------------------------------===//
18 // GenericIntrinsic
19 //===----------------------------------------------------------------------===//
20 
21 ParseResult GenericIntrinsic::hasNInputs(unsigned n) {
22  if (op.getNumOperands() != n)
23  return emitError() << " has " << op.getNumOperands()
24  << " inputs instead of " << n;
25  return success();
26 }
27 
28 ParseResult GenericIntrinsic::hasNOutputElements(unsigned n) {
29  auto b = getOutputBundle();
30  if (!b)
31  return emitError() << " missing output bundle";
32  if (b.getType().getNumElements() != n)
33  return emitError() << " has " << b.getType().getNumElements()
34  << " output elements instead of " << n;
35  return success();
36 }
37 
38 ParseResult GenericIntrinsic::hasNParam(unsigned n, unsigned c) {
39  unsigned num = 0;
40  if (op.getParameters())
41  num = op.getParameters().size();
42  if (num < n || num > n + c) {
43  auto d = emitError() << " has " << num << " parameters instead of ";
44  if (c == 0)
45  d << n;
46  else
47  d << " between " << n << " and " << (n + c);
48  return failure();
49  }
50  return success();
51 }
52 
53 ParseResult GenericIntrinsic::namedParam(StringRef paramName, bool optional) {
54  for (auto a : op.getParameters()) {
55  auto param = cast<ParamDeclAttr>(a);
56  if (param.getName().getValue() == paramName) {
57  if (isa<StringAttr>(param.getValue()))
58  return success();
59 
60  return emitError() << " has parameter '" << param.getName()
61  << "' which should be a string but is not";
62  }
63  }
64  if (optional)
65  return success();
66  return emitError() << " is missing parameter " << paramName;
67 }
68 
69 ParseResult GenericIntrinsic::namedIntParam(StringRef paramName,
70  bool optional) {
71  for (auto a : op.getParameters()) {
72  auto param = cast<ParamDeclAttr>(a);
73  if (param.getName().getValue() == paramName) {
74  if (isa<IntegerAttr>(param.getValue()))
75  return success();
76 
77  return emitError() << " has parameter '" << param.getName()
78  << "' which should be an integer but is not";
79  }
80  }
81  if (optional)
82  return success();
83  return emitError() << " is missing parameter " << paramName;
84 }
85 
86 //===----------------------------------------------------------------------===//
87 // IntrinsicOpConversion
88 //===----------------------------------------------------------------------===//
89 
90 /// Conversion pattern adaptor dispatching via generic intrinsic name.
91 namespace {
92 class IntrinsicOpConversion final
93  : public OpConversionPattern<GenericIntrinsicOp> {
94 public:
95  using ConversionMapTy = IntrinsicLowerings::ConversionMapTy;
96 
97  IntrinsicOpConversion(TypeConverter &typeConverter, MLIRContext *context,
98  const ConversionMapTy &conversions,
99  size_t &numConversions,
100  bool allowUnknownIntrinsics = false)
101  : OpConversionPattern(typeConverter, context), conversions(conversions),
102  numConversions(numConversions),
103  allowUnknownIntrinsics(allowUnknownIntrinsics) {}
104 
105  LogicalResult
106  matchAndRewrite(GenericIntrinsicOp op, OpAdaptor adaptor,
107  ConversionPatternRewriter &rewriter) const override {
108 
109  auto it = conversions.find(op.getIntrinsicAttr());
110  if (it == conversions.end()) {
111  if (!allowUnknownIntrinsics)
112  return op.emitError("unknown intrinsic ") << op.getIntrinsicAttr();
113  return failure();
114  }
115 
116  auto &conv = *it->second;
117  if (conv.check(GenericIntrinsic(op)))
118  return failure();
119  conv.convert(GenericIntrinsic(op), adaptor, rewriter);
120  ++numConversions;
121  return success();
122  }
123 
124 private:
125  const ConversionMapTy &conversions;
126  size_t &numConversions;
127  const bool allowUnknownIntrinsics;
128 };
129 } // namespace
130 
131 //===----------------------------------------------------------------------===//
132 // IntrinsicLowerings
133 //===----------------------------------------------------------------------===//
134 
136  bool allowUnknownIntrinsics) {
137 
138  ConversionTarget target(*context);
139 
140  target.markUnknownOpDynamicallyLegal([](Operation *op) { return true; });
141  if (allowUnknownIntrinsics)
142  target.addDynamicallyLegalOp<GenericIntrinsicOp>(
143  [this](GenericIntrinsicOp op) {
144  return !conversions.contains(op.getIntrinsicAttr());
145  });
146  else
147  target.addIllegalOp<GenericIntrinsicOp>();
148 
149  // Automatically insert wires + connect for compatible FIRRTL base types.
150  // For now, this is not customizable/extendable.
151  TypeConverter typeConverter;
152  typeConverter.addConversion([](Type type) { return type; });
153  auto firrtlBaseTypeMaterialization =
154  [](OpBuilder &builder, FIRRTLBaseType resultType, ValueRange inputs,
155  Location loc) -> Value {
156  if (inputs.size() != 1)
157  return {};
158  auto inputType = type_dyn_cast<FIRRTLBaseType>(inputs.front().getType());
159  if (!inputType)
160  return {};
161 
162  if (!areTypesEquivalent(resultType, inputType) ||
163  !isTypeLarger(resultType, inputType))
164  return {};
165 
166  auto w = builder.create<WireOp>(loc, resultType).getResult();
167  emitConnect(builder, loc, w, inputs.front());
168  return w;
169  };
170  // New result doesn't match? Add wire + connect.
171  typeConverter.addSourceMaterialization(firrtlBaseTypeMaterialization);
172  // New operand doesn't match? Add wire + connect.
173  typeConverter.addTargetMaterialization(firrtlBaseTypeMaterialization);
174 
175  RewritePatternSet patterns(context);
176  size_t count = 0;
177  patterns.add<IntrinsicOpConversion>(typeConverter, context, conversions,
178  count, allowUnknownIntrinsics);
179 
180  if (failed(mlir::applyPartialConversion(mod, target, std::move(patterns))))
181  return failure();
182 
183  return count;
184 }
185 
186 //===----------------------------------------------------------------------===//
187 // IntrinsicLoweringInterfaceCollection
188 //===----------------------------------------------------------------------===//
189 
191  IntrinsicLowerings &lowering) const {
192  for (const IntrinsicLoweringDialectInterface &interface : *this)
193  interface.populateIntrinsicLowerings(lowering);
194 }
195 
196 //===----------------------------------------------------------------------===//
197 // FIRRTL intrinsic lowering converters
198 //===----------------------------------------------------------------------===//
199 
200 namespace {
201 
202 class CirctSizeofConverter : public IntrinsicOpConverter<SizeOfIntrinsicOp> {
203 public:
204  using IntrinsicOpConverter::IntrinsicOpConverter;
205 
206  bool check(GenericIntrinsic gi) override {
207  return gi.hasNInputs(1) || gi.sizedOutput<UIntType>(32) || gi.hasNParam(0);
208  }
209 };
210 
211 class CirctIsXConverter : public IntrinsicOpConverter<IsXIntrinsicOp> {
212 public:
213  using IntrinsicOpConverter::IntrinsicOpConverter;
214 
215  bool check(GenericIntrinsic gi) override {
216  return gi.hasNInputs(1) || gi.sizedOutput<UIntType>(1) || gi.hasNParam(0);
217  }
218 };
219 
220 class CirctPlusArgTestConverter : public IntrinsicConverter {
221 public:
222  using IntrinsicConverter::IntrinsicConverter;
223 
224  bool check(GenericIntrinsic gi) override {
225  return gi.hasNInputs(0) || gi.sizedOutput<UIntType>(1) ||
226  gi.namedParam("FORMAT") || gi.hasNParam(1);
227  }
228 
229  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
230  PatternRewriter &rewriter) override {
231  rewriter.replaceOpWithNewOp<PlusArgsTestIntrinsicOp>(
232  gi.op, gi.getParamValue<StringAttr>("FORMAT"));
233  }
234 };
235 
236 class CirctPlusArgValueConverter : public IntrinsicConverter {
237 public:
238  using IntrinsicConverter::IntrinsicConverter;
239 
240  bool check(GenericIntrinsic gi) override {
241  return gi.hasNOutputElements(2) ||
242  gi.sizedOutputElement<UIntType>(0, "found", 1) ||
243  gi.hasOutputElement(1, "result") || gi.namedParam("FORMAT") ||
244  gi.hasNParam(1);
245  }
246 
247  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
248  PatternRewriter &rewriter) override {
249  auto bty = gi.getOutputBundle().getType();
250  auto newop = rewriter.create<PlusArgsValueIntrinsicOp>(
251  gi.op.getLoc(), bty.getElementTypePreservingConst(0),
252  bty.getElementTypePreservingConst(1),
253  gi.getParamValue<StringAttr>("FORMAT"));
254  rewriter.replaceOpWithNewOp<BundleCreateOp>(
255  gi.op, bty, ValueRange({newop.getFound(), newop.getResult()}));
256  }
257 };
258 
259 class CirctClockGateConverter
260  : public IntrinsicOpConverter<ClockGateIntrinsicOp> {
261 public:
262  using IntrinsicOpConverter::IntrinsicOpConverter;
263 
264  bool check(GenericIntrinsic gi) override {
265  if (gi.op.getNumOperands() == 3) {
266  return gi.typedInput<ClockType>(0) || gi.sizedInput<UIntType>(1, 1) ||
267  gi.sizedInput<UIntType>(2, 1) || gi.typedOutput<ClockType>() ||
268  gi.hasNParam(0);
269  }
270  if (gi.op.getNumOperands() == 2) {
271  return gi.typedInput<ClockType>(0) || gi.sizedInput<UIntType>(1, 1) ||
272  gi.typedOutput<ClockType>() || gi.hasNParam(0);
273  }
274  gi.emitError() << " has " << gi.op.getNumOperands()
275  << " ports instead of 3 or 4";
276  return true;
277  }
278 };
279 
280 class CirctClockInverterConverter
281  : public IntrinsicOpConverter<ClockInverterIntrinsicOp> {
282 public:
283  using IntrinsicOpConverter::IntrinsicOpConverter;
284 
285  bool check(GenericIntrinsic gi) override {
286  return gi.hasNInputs(1) || gi.typedInput<ClockType>(0) ||
287  gi.typedOutput<ClockType>() || gi.hasNParam(0);
288  }
289 };
290 
291 class CirctClockDividerConverter : public IntrinsicConverter {
292 public:
293  using IntrinsicConverter::IntrinsicConverter;
294 
295  bool check(GenericIntrinsic gi) override {
296  return gi.hasNInputs(1) || gi.typedInput<ClockType>(0) ||
297  gi.typedOutput<ClockType>() || gi.namedIntParam("POW_2") ||
298  gi.hasNParam(1);
299  }
300 
301  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
302  PatternRewriter &rewriter) override {
303  auto pow2 =
304  gi.getParamValue<IntegerAttr>("POW_2").getValue().getZExtValue();
305 
306  auto pow2Attr = rewriter.getI64IntegerAttr(pow2);
307 
308  rewriter.replaceOpWithNewOp<ClockDividerIntrinsicOp>(
309  gi.op, adaptor.getOperands()[0], pow2Attr);
310  }
311 };
312 
313 template <typename OpTy>
314 class CirctLTLBinaryConverter : public IntrinsicOpConverter<OpTy> {
315 public:
317 
318  bool check(GenericIntrinsic gi) override {
319  return gi.hasNInputs(2) || gi.sizedInput<UIntType>(0, 1) ||
320  gi.sizedInput<UIntType>(1, 1) || gi.sizedOutput<UIntType>(1) ||
321  gi.hasNParam(0);
322  }
323 };
324 
325 template <typename OpTy>
326 class CirctLTLUnaryConverter : public IntrinsicOpConverter<OpTy> {
327 public:
329 
330  bool check(GenericIntrinsic gi) override {
331  return gi.hasNInputs(1) || gi.sizedInput<UIntType>(0, 1) ||
332  gi.sizedOutput<UIntType>(1) || gi.hasNParam(0);
333  }
334 };
335 
336 class CirctLTLDelayConverter : public IntrinsicConverter {
337 public:
338  using IntrinsicConverter::IntrinsicConverter;
339 
340  bool check(GenericIntrinsic gi) override {
341  return gi.hasNInputs(1) || gi.sizedInput<UIntType>(0, 1) ||
342  gi.sizedOutput<UIntType>(1) || gi.namedIntParam("delay") ||
343  gi.namedIntParam("length", true) || gi.hasNParam(1, 1);
344  }
345 
346  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
347  PatternRewriter &rewriter) override {
348  auto getI64Attr = [&](IntegerAttr val) {
349  if (!val)
350  return IntegerAttr();
351  return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
352  };
353  auto delay = getI64Attr(gi.getParamValue<IntegerAttr>("delay"));
354  auto length = getI64Attr(gi.getParamValue<IntegerAttr>("length"));
355  rewriter.replaceOpWithNewOp<LTLDelayIntrinsicOp>(
356  gi.op, gi.op.getResultTypes(), adaptor.getOperands()[0], delay, length);
357  }
358 };
359 
360 class CirctLTLClockConverter
361  : public IntrinsicOpConverter<LTLClockIntrinsicOp> {
362 public:
363  using IntrinsicOpConverter::IntrinsicOpConverter;
364 
365  bool check(GenericIntrinsic gi) override {
366  return gi.hasNInputs(2) || gi.sizedInput<UIntType>(0, 1) ||
367  gi.typedInput<ClockType>(1) || gi.sizedOutput<UIntType>(1) ||
368  gi.hasNParam(0);
369  }
370 };
371 
372 class CirctLTLRepeatConverter : public IntrinsicConverter {
373 public:
374  using IntrinsicConverter::IntrinsicConverter;
375 
376  bool check(GenericIntrinsic gi) override {
377  return gi.hasNInputs(1) || gi.sizedInput<UIntType>(0, 1) ||
378  gi.sizedOutput<UIntType>(1) || gi.namedIntParam("base") ||
379  gi.namedIntParam("more", true) || gi.hasNParam(1, 1);
380  }
381 
382  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
383  PatternRewriter &rewriter) override {
384  auto getI64Attr = [&](IntegerAttr val) {
385  if (!val)
386  return IntegerAttr();
387  return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
388  };
389  auto base = getI64Attr(gi.getParamValue<IntegerAttr>("base"));
390  auto more = getI64Attr(gi.getParamValue<IntegerAttr>("more"));
391  rewriter.replaceOpWithNewOp<LTLRepeatIntrinsicOp>(
392  gi.op, gi.op.getResultTypes(), adaptor.getOperands()[0], base, more);
393  }
394 };
395 
396 class CirctLTLGoToRepeatConverter : public IntrinsicConverter {
397 public:
398  using IntrinsicConverter::IntrinsicConverter;
399 
400  bool check(GenericIntrinsic gi) override {
401  return gi.hasNInputs(1) || gi.sizedInput<UIntType>(0, 1) ||
402  gi.sizedOutput<UIntType>(1) || gi.namedIntParam("base") ||
403  gi.namedIntParam("more") || gi.hasNParam(1, 1);
404  }
405 
406  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
407  PatternRewriter &rewriter) override {
408  auto getI64Attr = [&](IntegerAttr val) {
409  if (!val)
410  return IntegerAttr();
411  return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
412  };
413  auto base = getI64Attr(gi.getParamValue<IntegerAttr>("base"));
414  auto more = getI64Attr(gi.getParamValue<IntegerAttr>("more"));
415  rewriter.replaceOpWithNewOp<LTLGoToRepeatIntrinsicOp>(
416  gi.op, gi.op.getResultTypes(), adaptor.getOperands()[0], base, more);
417  }
418 };
419 
420 class CirctLTLNonConsecutiveRepeatConverter : public IntrinsicConverter {
421 public:
422  using IntrinsicConverter::IntrinsicConverter;
423 
424  bool check(GenericIntrinsic gi) override {
425  return gi.hasNInputs(1) || gi.sizedInput<UIntType>(0, 1) ||
426  gi.sizedOutput<UIntType>(1) || gi.namedIntParam("base") ||
427  gi.namedIntParam("more") || gi.hasNParam(1, 1);
428  }
429 
430  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
431  PatternRewriter &rewriter) override {
432  auto getI64Attr = [&](IntegerAttr val) {
433  if (!val)
434  return IntegerAttr();
435  return rewriter.getI64IntegerAttr(val.getValue().getZExtValue());
436  };
437  auto base = getI64Attr(gi.getParamValue<IntegerAttr>("base"));
438  auto more = getI64Attr(gi.getParamValue<IntegerAttr>("more"));
439  rewriter.replaceOpWithNewOp<LTLNonConsecutiveRepeatIntrinsicOp>(
440  gi.op, gi.op.getResultTypes(), adaptor.getOperands()[0], base, more);
441  }
442 };
443 
444 template <class Op>
445 class CirctVerifConverter : public IntrinsicConverter {
446 public:
447  using IntrinsicConverter::IntrinsicConverter;
448 
449  bool check(GenericIntrinsic gi) override {
450  return gi.hasNInputs(1) || gi.sizedInput<UIntType>(0, 1) ||
451  gi.namedParam("label", true) || gi.hasNParam(0, 1) ||
452  gi.hasNoOutput();
453  }
454 
455  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
456  PatternRewriter &rewriter) override {
457  auto label = gi.getParamValue<StringAttr>("label");
458 
459  rewriter.replaceOpWithNewOp<Op>(gi.op, adaptor.getOperands()[0], label);
460  }
461 };
462 
463 class CirctMux2CellConverter : public IntrinsicConverter {
464  using IntrinsicConverter::IntrinsicConverter;
465 
466  bool check(GenericIntrinsic gi) override {
467  return gi.hasNInputs(3) || gi.typedInput<UIntType>(0) || gi.hasNParam(0) ||
468  gi.hasOutput();
469  }
470 
471  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
472  PatternRewriter &rewriter) override {
473  auto operands = adaptor.getOperands();
474  rewriter.replaceOpWithNewOp<Mux2CellIntrinsicOp>(gi.op, operands[0],
475  operands[1], operands[2]);
476  }
477 };
478 
479 class CirctMux4CellConverter : public IntrinsicConverter {
480  using IntrinsicConverter::IntrinsicConverter;
481 
482  bool check(GenericIntrinsic gi) override {
483  return gi.hasNInputs(5) || gi.typedInput<UIntType>(0) || gi.hasNParam(0) ||
484  gi.hasOutput();
485  }
486 
487  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
488  PatternRewriter &rewriter) override {
489  auto operands = adaptor.getOperands();
490  rewriter.replaceOpWithNewOp<Mux4CellIntrinsicOp>(
491  gi.op, operands[0], operands[1], operands[2], operands[3], operands[4]);
492  }
493 };
494 
495 class CirctHasBeenResetConverter
496  : public IntrinsicOpConverter<HasBeenResetIntrinsicOp> {
497 public:
498  using IntrinsicOpConverter::IntrinsicOpConverter;
499 
500  bool check(GenericIntrinsic gi) override {
501  return gi.hasNInputs(2) || gi.typedInput<ClockType>(0) ||
502  gi.hasResetInput(1) || gi.sizedOutput<UIntType>(1) ||
503  gi.hasNParam(0);
504  }
505 };
506 
507 class CirctProbeConverter : public IntrinsicOpConverter<FPGAProbeIntrinsicOp> {
508 public:
509  using IntrinsicOpConverter::IntrinsicOpConverter;
510 
511  bool check(GenericIntrinsic gi) override {
512  return gi.hasNInputs(2) || gi.typedInput<ClockType>(1) || gi.hasNParam(0) ||
513  gi.hasNoOutput();
514  }
515 };
516 
517 template <class OpTy, bool ifElseFatal = false>
518 class CirctAssertConverter : public IntrinsicConverter {
519 public:
520  using IntrinsicConverter::IntrinsicConverter;
521 
522  bool check(GenericIntrinsic gi) override {
523  return gi.typedInput<ClockType>(0) || gi.sizedInput<UIntType>(1, 1) ||
524  gi.sizedInput<UIntType>(2, 1) ||
525  gi.namedParam("format", /*optional=*/true) ||
526  gi.namedParam("label", /*optional=*/true) ||
527  gi.namedParam("guards", /*optional=*/true) || gi.hasNParam(0, 3) ||
528  gi.hasNoOutput();
529  }
530 
531  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
532  PatternRewriter &rewriter) override {
533  auto format = gi.getParamValue<StringAttr>("format");
534  auto label = gi.getParamValue<StringAttr>("label");
535  auto guards = gi.getParamValue<StringAttr>("guards");
536 
537  auto clock = adaptor.getOperands()[0];
538  auto predicate = adaptor.getOperands()[1];
539  auto enable = adaptor.getOperands()[2];
540 
541  auto substitutions = adaptor.getOperands().drop_front(3);
542  auto name = label ? label.strref() : "";
543  // Message is not optional, so provide empty string if not present.
544  auto message = format ? format : rewriter.getStringAttr("");
545  auto op = rewriter.template replaceOpWithNewOp<OpTy>(
546  gi.op, clock, predicate, enable, message, substitutions, name,
547  /*isConcurrent=*/true);
548  if (guards) {
549  SmallVector<StringRef> guardStrings;
550  guards.strref().split(guardStrings, ';', /*MaxSplit=*/-1,
551  /*KeepEmpty=*/false);
552  rewriter.startOpModification(op);
553  op->setAttr("guards", rewriter.getStrArrayAttr(guardStrings));
554  rewriter.finalizeOpModification(op);
555  }
556 
557  if constexpr (ifElseFatal) {
558  rewriter.startOpModification(op);
559  op->setAttr("format", rewriter.getStringAttr("ifElseFatal"));
560  rewriter.finalizeOpModification(op);
561  }
562  }
563 };
564 
565 class CirctCoverConverter : public IntrinsicConverter {
566 public:
567  using IntrinsicConverter::IntrinsicConverter;
568 
569  bool check(GenericIntrinsic gi) override {
570  return gi.hasNInputs(3) || gi.hasNoOutput() ||
571  gi.typedInput<ClockType>(0) || gi.sizedInput<UIntType>(1, 1) ||
572  gi.sizedInput<UIntType>(2, 1) ||
573  gi.namedParam("label", /*optional=*/true) ||
574  gi.namedParam("guards", /*optional=*/true) || gi.hasNParam(0, 2);
575  }
576 
577  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
578  PatternRewriter &rewriter) override {
579  auto label = gi.getParamValue<StringAttr>("label");
580  auto guards = gi.getParamValue<StringAttr>("guards");
581 
582  auto clock = adaptor.getOperands()[0];
583  auto predicate = adaptor.getOperands()[1];
584  auto enable = adaptor.getOperands()[2];
585 
586  auto name = label ? label.strref() : "";
587  // Empty message string for cover, only 'name' / label.
588  auto message = rewriter.getStringAttr("");
589  auto op = rewriter.replaceOpWithNewOp<CoverOp>(
590  gi.op, clock, predicate, enable, message, ValueRange{}, name,
591  /*isConcurrent=*/true);
592  if (guards) {
593  SmallVector<StringRef> guardStrings;
594  guards.strref().split(guardStrings, ';', /*MaxSplit=*/-1,
595  /*KeepEmpty=*/false);
596  rewriter.startOpModification(op);
597  op->setAttr("guards", rewriter.getStrArrayAttr(guardStrings));
598  rewriter.finalizeOpModification(op);
599  }
600  }
601 };
602 
603 class CirctUnclockedAssumeConverter : public IntrinsicConverter {
604 public:
605  using IntrinsicConverter::IntrinsicConverter;
606 
607  bool check(GenericIntrinsic gi) override {
608  return gi.sizedInput<UIntType>(0, 1) || gi.sizedInput<UIntType>(1, 1) ||
609  gi.namedParam("format", /*optional=*/true) ||
610  gi.namedParam("label", /*optional=*/true) ||
611  gi.namedParam("guards", /*optional=*/true) || gi.hasNParam(0, 3) ||
612  gi.hasNoOutput();
613  }
614 
615  void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
616  PatternRewriter &rewriter) override {
617  auto format = gi.getParamValue<StringAttr>("format");
618  auto label = gi.getParamValue<StringAttr>("label");
619  auto guards = gi.getParamValue<StringAttr>("guards");
620 
621  auto predicate = adaptor.getOperands()[0];
622  auto enable = adaptor.getOperands()[1];
623 
624  auto substitutions = adaptor.getOperands().drop_front(2);
625  auto name = label ? label.strref() : "";
626  // Message is not optional, so provide empty string if not present.
627  auto message = format ? format : rewriter.getStringAttr("");
628  auto op = rewriter.template replaceOpWithNewOp<UnclockedAssumeIntrinsicOp>(
629  gi.op, predicate, enable, message, substitutions, name);
630  if (guards) {
631  SmallVector<StringRef> guardStrings;
632  guards.strref().split(guardStrings, ';', /*MaxSplit=*/-1,
633  /*KeepEmpty=*/false);
634  rewriter.startOpModification(op);
635  op->setAttr("guards", rewriter.getStrArrayAttr(guardStrings));
636  rewriter.finalizeOpModification(op);
637  }
638  }
639 };
640 
641 } // namespace
642 
643 //===----------------------------------------------------------------------===//
644 // FIRRTL intrinsic lowering dialect interface
645 //===----------------------------------------------------------------------===//
646 
648  IntrinsicLowerings &lowering) const {
649  lowering.add<CirctSizeofConverter>("circt.sizeof", "circt_sizeof");
650  lowering.add<CirctIsXConverter>("circt.isX", "circt_isX");
651  lowering.add<CirctPlusArgTestConverter>("circt.plusargs.test",
652  "circt_plusargs_test");
653  lowering.add<CirctPlusArgValueConverter>("circt.plusargs.value",
654  "circt_plusargs_value");
655  lowering.add<CirctClockGateConverter>("circt.clock_gate", "circt_clock_gate");
656  lowering.add<CirctClockInverterConverter>("circt.clock_inv",
657  "circt_clock_inv");
658  lowering.add<CirctClockDividerConverter>("circt.clock_div",
659  "circt_clock_div");
660  lowering.add<CirctLTLBinaryConverter<LTLAndIntrinsicOp>>("circt.ltl.and",
661  "circt_ltl_and");
662  lowering.add<CirctLTLBinaryConverter<LTLOrIntrinsicOp>>("circt.ltl.or",
663  "circt_ltl_or");
664  lowering.add<CirctLTLBinaryConverter<LTLIntersectIntrinsicOp>>(
665  "circt.ltl.intersect", "circt_ltl_intersect");
666  lowering.add<CirctLTLBinaryConverter<LTLConcatIntrinsicOp>>(
667  "circt.ltl.concat", "circt_ltl_concat");
668  lowering.add<CirctLTLBinaryConverter<LTLImplicationIntrinsicOp>>(
669  "circt.ltl.implication", "circt_ltl_implication");
670  lowering.add<CirctLTLBinaryConverter<LTLUntilIntrinsicOp>>("circt.ltl.until",
671  "circt_ltl_until");
672  lowering.add<CirctLTLBinaryConverter<LTLDisableIntrinsicOp>>(
673  "circt.ltl.disable", "circt_ltl_disable");
674  lowering.add<CirctLTLUnaryConverter<LTLNotIntrinsicOp>>("circt.ltl.not",
675  "circt_ltl_not");
676  lowering.add<CirctLTLUnaryConverter<LTLEventuallyIntrinsicOp>>(
677  "circt.ltl.eventually", "circt_ltl_eventually");
678 
679  lowering.add<CirctLTLDelayConverter>("circt.ltl.delay", "circt_ltl_delay");
680  lowering.add<CirctLTLRepeatConverter>("circt.ltl.repeat", "circt_ltl_repeat");
681  lowering.add<CirctLTLGoToRepeatConverter>("circt.ltl.goto_repeat",
682  "circt_ltl_goto_repeat");
683  lowering.add<CirctLTLNonConsecutiveRepeatConverter>(
684  "circt.ltl.non_consecutive_repeat", "circt_ltl_non_consecutive_repeat");
685  lowering.add<CirctLTLClockConverter>("circt.ltl.clock", "circt_ltl_clock");
686 
687  lowering.add<CirctVerifConverter<VerifAssertIntrinsicOp>>(
688  "circt.verif.assert", "circt_verif_assert");
689  lowering.add<CirctVerifConverter<VerifAssumeIntrinsicOp>>(
690  "circt.verif.assume", "circt_verif_assume");
691  lowering.add<CirctVerifConverter<VerifCoverIntrinsicOp>>("circt.verif.cover",
692  "circt_verif_cover");
693  lowering.add<CirctMux2CellConverter>("circt.mux2cell", "circt_mux2cell");
694  lowering.add<CirctMux4CellConverter>("circt.mux4cell", "circt_mux4cell");
695  lowering.add<CirctHasBeenResetConverter>("circt.has_been_reset",
696  "circt_has_been_reset");
697  lowering.add<CirctProbeConverter>("circt.fpga_probe", "circt_fpga_probe");
698  lowering.add<CirctAssertConverter<AssertOp>>("circt.chisel_assert",
699  "circt_chisel_assert");
700  lowering.add<CirctAssertConverter<AssertOp, /*ifElseFatal=*/true>>(
701  "circt.chisel_ifelsefatal", "circt_chisel_ifelsefatal");
702  lowering.add<CirctAssertConverter<AssumeOp>>("circt.chisel_assume",
703  "circt_chisel_assume");
704  lowering.add<CirctCoverConverter>("circt.chisel_cover", "circt_chisel_cover");
705  lowering.add<CirctUnclockedAssumeConverter>("circt.unclocked_assume",
706  "circt_unclocked_assume");
707 }
llvm::SmallVector< StringAttr > inputs
Builder builder
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.
Definition: FIRRTLUtils.cpp:24
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
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 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)
A dialect interface to provide lowering conversions.
virtual void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const =0
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const