CIRCT  19.0.0git
MooreToCore.cpp
Go to the documentation of this file.
1 //===- MooreToCore.cpp - Moore To Core Conversion Pass --------------------===//
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 //
9 // This is the main Moore to Core Conversion Pass Implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
15 #include "circt/Dialect/HW/HWOps.h"
18 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
19 #include "mlir/Dialect/Func/IR/FuncOps.h"
20 #include "mlir/IR/BuiltinDialect.h"
21 #include "mlir/Pass/Pass.h"
22 #include "mlir/Transforms/DialectConversion.h"
23 #include "llvm/ADT/TypeSwitch.h"
24 
25 namespace circt {
26 #define GEN_PASS_DEF_CONVERTMOORETOCORE
27 #include "circt/Conversion/Passes.h.inc"
28 } // namespace circt
29 
30 using namespace mlir;
31 using namespace circt;
32 using namespace moore;
33 
34 using comb::ICmpPredicate;
35 
36 namespace {
37 
38 /// Returns the passed value if the integer width is already correct.
39 /// Zero-extends if it is too narrow.
40 /// Truncates if the integer is too wide and the truncated part is zero, if it
41 /// is not zero it returns the max value integer of target-width.
42 static Value adjustIntegerWidth(OpBuilder &builder, Value value,
43  uint32_t targetWidth, Location loc) {
44  uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
45  if (intWidth == targetWidth)
46  return value;
47 
48  if (intWidth < targetWidth) {
49  Value zeroExt = builder.create<hw::ConstantOp>(
50  loc, builder.getIntegerType(targetWidth - intWidth), 0);
51  return builder.create<comb::ConcatOp>(loc, ValueRange{zeroExt, value});
52  }
53 
54  Value hi = builder.create<comb::ExtractOp>(loc, value, targetWidth,
55  intWidth - targetWidth);
56  Value zero = builder.create<hw::ConstantOp>(
57  loc, builder.getIntegerType(intWidth - targetWidth), 0);
58  Value isZero = builder.create<comb::ICmpOp>(loc, comb::ICmpPredicate::eq, hi,
59  zero, false);
60  Value lo = builder.create<comb::ExtractOp>(loc, value, 0, targetWidth);
61  Value max = builder.create<hw::ConstantOp>(
62  loc, builder.getIntegerType(targetWidth), -1);
63  return builder.create<comb::MuxOp>(loc, isZero, lo, max, false);
64 }
65 
66 /// Get the ModulePortInfo from a SVModuleOp.
67 static hw::ModulePortInfo getModulePortInfo(const TypeConverter &typeConverter,
68  SVModuleOp op) {
69  size_t inputNum = 0;
70  size_t resultNum = 0;
71  auto moduleTy = op.getModuleType();
72  SmallVector<hw::PortInfo> inputs, outputs;
73  inputs.reserve(moduleTy.getNumInputs());
74  outputs.reserve(moduleTy.getNumOutputs());
75 
76  for (auto port : moduleTy.getPorts())
77  if (port.dir == hw::ModulePort::Direction::Output) {
78  outputs.push_back(
79  hw::PortInfo({{port.name, port.type, port.dir}, resultNum++, {}}));
80  } else {
81  // FIXME: Once we support net<...>, ref<...> type to represent type of
82  // special port like inout or ref port which is not a input or output
83  // port. It can change to generate corresponding types for direction of
84  // port or do specified operation to it. Now inout and ref port is treated
85  // as input port.
86  inputs.push_back(
87  hw::PortInfo({{port.name, port.type, port.dir}, inputNum++, {}}));
88  }
89 
90  return hw::ModulePortInfo(inputs, outputs);
91 }
92 
93 //===----------------------------------------------------------------------===//
94 // Structural Conversion
95 //===----------------------------------------------------------------------===//
96 
97 struct SVModuleOpConversion : public OpConversionPattern<SVModuleOp> {
98  using OpConversionPattern::OpConversionPattern;
99 
100  LogicalResult
101  matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
102  ConversionPatternRewriter &rewriter) const override {
103  auto outputOp = op.getOutputOp();
104  rewriter.setInsertionPoint(op);
105 
106  // Create the hw.module to replace svmoduleOp
107  auto hwModuleOp =
108  rewriter.create<hw::HWModuleOp>(op.getLoc(), op.getSymNameAttr(),
109  getModulePortInfo(*typeConverter, op));
110  rewriter.eraseBlock(hwModuleOp.getBodyBlock());
111  rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
112  hwModuleOp.getBodyRegion().end());
113 
114  // Rewrite the hw.output op
115  rewriter.setInsertionPointToEnd(hwModuleOp.getBodyBlock());
116  rewriter.replaceOpWithNewOp<hw::OutputOp>(outputOp, outputOp.getOperands());
117 
118  // Erase the original op
119  rewriter.eraseOp(op);
120  return success();
121  }
122 };
123 
124 struct InstanceOpConversion : public OpConversionPattern<InstanceOp> {
125  using OpConversionPattern::OpConversionPattern;
126 
127  LogicalResult
128  matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
129  ConversionPatternRewriter &rewriter) const override {
130  auto instName = op.getInstanceNameAttr();
131  auto moduleName = op.getModuleNameAttr();
132 
133  // Create the new hw instanceOp to replace the original one.
134  rewriter.setInsertionPoint(op);
135  auto instOp = rewriter.create<hw::InstanceOp>(
136  op.getLoc(), op.getResultTypes(), instName, moduleName, op.getInputs(),
137  op.getInputNamesAttr(), op.getOutputNamesAttr(),
138  /*Parameter*/ rewriter.getArrayAttr({}), /*InnerSymbol*/ nullptr);
139 
140  // Replace uses chain and erase the original op.
141  op.replaceAllUsesWith(instOp.getResults());
142  rewriter.eraseOp(op);
143  return success();
144  }
145 };
146 
147 //===----------------------------------------------------------------------===//
148 // Declaration Conversion
149 //===----------------------------------------------------------------------===//
150 
151 struct VariableOpConversion : public OpConversionPattern<VariableOp> {
152  using OpConversionPattern::OpConversionPattern;
153 
154  LogicalResult
155  matchAndRewrite(VariableOp op, OpAdaptor adaptor,
156  ConversionPatternRewriter &rewriter) const override {
157  Type resultType = typeConverter->convertType(op.getResult().getType());
158  Value init = adaptor.getInitial();
159  // TODO: Unsupport x/z, so the initial value is 0.
160  if (!init && cast<RefType>(op.getResult().getType()).getDomain() ==
161  Domain::FourValued)
162  return failure();
163 
164  if (!init)
165  init = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, 0);
166  rewriter.replaceOpWithNewOp<llhd::SigOp>(op, hw::InOutType::get(resultType),
167  op.getNameAttr(), init);
168  return success();
169  }
170 };
171 
172 //===----------------------------------------------------------------------===//
173 // Expression Conversion
174 //===----------------------------------------------------------------------===//
175 
176 struct ConstantOpConv : public OpConversionPattern<ConstantOp> {
177  using OpConversionPattern::OpConversionPattern;
178 
179  LogicalResult
180  matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
181  ConversionPatternRewriter &rewriter) const override {
182 
183  rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, op.getValueAttr());
184  return success();
185  }
186 };
187 
188 struct NamedConstantOpConv : public OpConversionPattern<NamedConstantOp> {
189  using OpConversionPattern::OpConversionPattern;
190 
191  LogicalResult
192  matchAndRewrite(NamedConstantOp op, OpAdaptor adaptor,
193  ConversionPatternRewriter &rewriter) const override {
194 
195  Type resultType = typeConverter->convertType(op.getResult().getType());
196  SmallString<32> symStr;
197  switch (op.getKind()) {
198  case NamedConst::Parameter:
199  symStr = "parameter";
200  break;
201  case NamedConst::LocalParameter:
202  symStr = "localparameter";
203  break;
204  case NamedConst::SpecParameter:
205  symStr = "specparameter";
206  break;
207  }
208  auto symAttr =
209  rewriter.getStringAttr(symStr + Twine("_") + adaptor.getName());
210  rewriter.replaceOpWithNewOp<hw::WireOp>(op, resultType, adaptor.getValue(),
211  op.getNameAttr(),
212  hw::InnerSymAttr::get(symAttr));
213  return success();
214  }
215 };
216 
217 struct ConcatOpConversion : public OpConversionPattern<ConcatOp> {
218  using OpConversionPattern::OpConversionPattern;
219  LogicalResult
220  matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
221  ConversionPatternRewriter &rewriter) const override {
222  rewriter.replaceOpWithNewOp<comb::ConcatOp>(op, adaptor.getValues());
223  return success();
224  }
225 };
226 
227 struct ReplicateOpConversion : public OpConversionPattern<ReplicateOp> {
228  using OpConversionPattern::OpConversionPattern;
229  LogicalResult
230  matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
231  ConversionPatternRewriter &rewriter) const override {
232  Type resultType = typeConverter->convertType(op.getResult().getType());
233 
234  rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
235  adaptor.getValue());
236  return success();
237  }
238 };
239 
240 struct ExtractOpConversion : public OpConversionPattern<ExtractOp> {
241  using OpConversionPattern::OpConversionPattern;
242 
243  LogicalResult
244  matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
245  ConversionPatternRewriter &rewriter) const override {
246  Type resultType = typeConverter->convertType(op.getResult().getType());
247  rewriter.replaceOpWithNewOp<comb::ExtractOp>(
248  op, resultType, adaptor.getInput(), adaptor.getLowBit());
249  return success();
250  }
251 };
252 
253 struct DynExtractOpConversion : public OpConversionPattern<DynExtractOp> {
254  using OpConversionPattern::OpConversionPattern;
255 
256  LogicalResult
257  matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
258  ConversionPatternRewriter &rewriter) const override {
259  Type resultType = typeConverter->convertType(op.getResult().getType());
260  auto width = typeConverter->convertType(op.getInput().getType())
261  .getIntOrFloatBitWidth();
262  Value amount =
263  adjustIntegerWidth(rewriter, adaptor.getLowBit(), width, op->getLoc());
264  Value value =
265  rewriter.create<comb::ShrUOp>(op->getLoc(), adaptor.getInput(), amount);
266 
267  rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, resultType, value, 0);
268  return success();
269  }
270 };
271 
272 struct ReduceAndOpConversion : public OpConversionPattern<ReduceAndOp> {
273  using OpConversionPattern::OpConversionPattern;
274  LogicalResult
275  matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
276  ConversionPatternRewriter &rewriter) const override {
277  Type resultType = typeConverter->convertType(op.getInput().getType());
278  Value max = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, -1);
279 
280  rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
281  adaptor.getInput(), max);
282  return success();
283  }
284 };
285 
286 struct ReduceOrOpConversion : public OpConversionPattern<ReduceOrOp> {
287  using OpConversionPattern::OpConversionPattern;
288  LogicalResult
289  matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
290  ConversionPatternRewriter &rewriter) const override {
291  Type resultType = typeConverter->convertType(op.getInput().getType());
292  Value zero = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, 0);
293 
294  rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
295  adaptor.getInput(), zero);
296  return success();
297  }
298 };
299 
300 struct ReduceXorOpConversion : public OpConversionPattern<ReduceXorOp> {
301  using OpConversionPattern::OpConversionPattern;
302  LogicalResult
303  matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
304  ConversionPatternRewriter &rewriter) const override {
305 
306  rewriter.replaceOpWithNewOp<comb::ParityOp>(op, adaptor.getInput());
307  return success();
308  }
309 };
310 
311 struct BoolCastOpConversion : public OpConversionPattern<BoolCastOp> {
312  using OpConversionPattern::OpConversionPattern;
313  LogicalResult
314  matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
315  ConversionPatternRewriter &rewriter) const override {
316  Type resultType = typeConverter->convertType(op.getInput().getType());
317  if (isa_and_nonnull<IntegerType>(resultType)) {
318  Value zero = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, 0);
319  rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
320  adaptor.getInput(), zero);
321  return success();
322  }
323  return failure();
324  }
325 };
326 
327 struct NotOpConversion : public OpConversionPattern<NotOp> {
328  using OpConversionPattern::OpConversionPattern;
329  LogicalResult
330  matchAndRewrite(NotOp op, OpAdaptor adaptor,
331  ConversionPatternRewriter &rewriter) const override {
332  Type resultType =
333  ConversionPattern::typeConverter->convertType(op.getResult().getType());
334  Value max = rewriter.create<hw::ConstantOp>(op.getLoc(), resultType, -1);
335 
336  rewriter.replaceOpWithNewOp<comb::XorOp>(op, adaptor.getInput(), max);
337  return success();
338  }
339 };
340 
341 struct NegOpConversion : public OpConversionPattern<NegOp> {
342  using OpConversionPattern::OpConversionPattern;
343  LogicalResult
344  matchAndRewrite(NegOp op, OpAdaptor adaptor,
345  ConversionPatternRewriter &rewriter) const override {
346  Type resultType =
347  ConversionPattern::typeConverter->convertType(op.getResult().getType());
348  Value zero = rewriter.create<hw::ConstantOp>(op.getLoc(), resultType, 0);
349 
350  rewriter.replaceOpWithNewOp<comb::SubOp>(op, zero, adaptor.getInput());
351  return success();
352  }
353 };
354 
355 template <typename SourceOp, typename TargetOp>
356 struct BinaryOpConversion : public OpConversionPattern<SourceOp> {
358  using OpAdaptor = typename SourceOp::Adaptor;
359 
360  LogicalResult
361  matchAndRewrite(SourceOp op, OpAdaptor adaptor,
362  ConversionPatternRewriter &rewriter) const override {
363  rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
364  adaptor.getRhs(), false);
365  return success();
366  }
367 };
368 
369 template <typename SourceOp, ICmpPredicate pred>
370 struct ICmpOpConversion : public OpConversionPattern<SourceOp> {
372  using OpAdaptor = typename SourceOp::Adaptor;
373 
374  LogicalResult
375  matchAndRewrite(SourceOp op, OpAdaptor adapter,
376  ConversionPatternRewriter &rewriter) const override {
377  Type resultType =
378  ConversionPattern::typeConverter->convertType(op.getResult().getType());
379 
380  rewriter.replaceOpWithNewOp<comb::ICmpOp>(
381  op, resultType, pred, adapter.getLhs(), adapter.getRhs());
382  return success();
383  }
384 };
385 
386 struct ConversionOpConversion : public OpConversionPattern<ConversionOp> {
387  using OpConversionPattern::OpConversionPattern;
388 
389  LogicalResult
390  matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
391  ConversionPatternRewriter &rewriter) const override {
392  Type resultType = typeConverter->convertType(op.getResult().getType());
393  Value amount =
394  adjustIntegerWidth(rewriter, adaptor.getInput(),
395  resultType.getIntOrFloatBitWidth(), op->getLoc());
396 
397  rewriter.replaceOpWithNewOp<hw::BitcastOp>(op, resultType, amount);
398  return success();
399  }
400 };
401 
402 //===----------------------------------------------------------------------===//
403 // Statement Conversion
404 //===----------------------------------------------------------------------===//
405 
406 struct HWOutputOpConversion : public OpConversionPattern<hw::OutputOp> {
407  using OpConversionPattern::OpConversionPattern;
408 
409  LogicalResult
410  matchAndRewrite(hw::OutputOp op, OpAdaptor adaptor,
411  ConversionPatternRewriter &rewriter) const override {
412  rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
413  return success();
414  }
415 };
416 
417 struct HWInstanceOpConversion : public OpConversionPattern<hw::InstanceOp> {
418  using OpConversionPattern::OpConversionPattern;
419 
420  LogicalResult
421  matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
422  ConversionPatternRewriter &rewriter) const override {
423  SmallVector<Type> convResTypes;
424  if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
425  return failure();
426 
427  rewriter.replaceOpWithNewOp<hw::InstanceOp>(
428  op, convResTypes, op.getInstanceName(), op.getModuleName(),
429  adaptor.getOperands(), op.getArgNames(),
430  op.getResultNames(), /*Parameter*/
431  rewriter.getArrayAttr({}), /*InnerSymbol*/ nullptr);
432 
433  return success();
434  }
435 };
436 
437 struct ReturnOpConversion : public OpConversionPattern<func::ReturnOp> {
438  using OpConversionPattern::OpConversionPattern;
439 
440  LogicalResult
441  matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
442  ConversionPatternRewriter &rewriter) const override {
443  rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
444  return success();
445  }
446 };
447 
448 struct CondBranchOpConversion : public OpConversionPattern<cf::CondBranchOp> {
449  using OpConversionPattern::OpConversionPattern;
450 
451  LogicalResult
452  matchAndRewrite(cf::CondBranchOp op, OpAdaptor adaptor,
453  ConversionPatternRewriter &rewriter) const override {
454  rewriter.replaceOpWithNewOp<cf::CondBranchOp>(
455  op, adaptor.getCondition(), adaptor.getTrueDestOperands(),
456  adaptor.getFalseDestOperands(), op.getTrueDest(), op.getFalseDest());
457  return success();
458  }
459 };
460 
461 struct BranchOpConversion : public OpConversionPattern<cf::BranchOp> {
462  using OpConversionPattern::OpConversionPattern;
463 
464  LogicalResult
465  matchAndRewrite(cf::BranchOp op, OpAdaptor adaptor,
466  ConversionPatternRewriter &rewriter) const override {
467  rewriter.replaceOpWithNewOp<cf::BranchOp>(op, op.getDest(),
468  adaptor.getDestOperands());
469  return success();
470  }
471 };
472 
473 struct CallOpConversion : public OpConversionPattern<func::CallOp> {
474  using OpConversionPattern::OpConversionPattern;
475 
476  LogicalResult
477  matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
478  ConversionPatternRewriter &rewriter) const override {
479  SmallVector<Type> convResTypes;
480  if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
481  return failure();
482  rewriter.replaceOpWithNewOp<func::CallOp>(
483  op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
484  return success();
485  }
486 };
487 
488 struct UnrealizedConversionCastConversion
489  : public OpConversionPattern<UnrealizedConversionCastOp> {
490  using OpConversionPattern::OpConversionPattern;
491 
492  LogicalResult
493  matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
494  ConversionPatternRewriter &rewriter) const override {
495  SmallVector<Type> convResTypes;
496  if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
497  return failure();
498 
499  // Drop the cast if the operand and result types agree after type
500  // conversion.
501  if (convResTypes == adaptor.getOperands().getTypes()) {
502  rewriter.replaceOp(op, adaptor.getOperands());
503  return success();
504  }
505 
506  rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
507  op, convResTypes, adaptor.getOperands());
508  return success();
509  }
510 };
511 
512 struct ShlOpConversion : public OpConversionPattern<ShlOp> {
513  using OpConversionPattern::OpConversionPattern;
514 
515  LogicalResult
516  matchAndRewrite(ShlOp op, OpAdaptor adaptor,
517  ConversionPatternRewriter &rewriter) const override {
518  Type resultType = typeConverter->convertType(op.getResult().getType());
519 
520  // Comb shift operations require the same bit-width for value and amount
521  Value amount =
522  adjustIntegerWidth(rewriter, adaptor.getAmount(),
523  resultType.getIntOrFloatBitWidth(), op->getLoc());
524  rewriter.replaceOpWithNewOp<comb::ShlOp>(op, resultType, adaptor.getValue(),
525  amount, false);
526  return success();
527  }
528 };
529 
530 struct ShrOpConversion : public OpConversionPattern<ShrOp> {
531  using OpConversionPattern::OpConversionPattern;
532 
533  LogicalResult
534  matchAndRewrite(ShrOp op, OpAdaptor adaptor,
535  ConversionPatternRewriter &rewriter) const override {
536  Type resultType = typeConverter->convertType(op.getResult().getType());
537 
538  // Comb shift operations require the same bit-width for value and amount
539  Value amount =
540  adjustIntegerWidth(rewriter, adaptor.getAmount(),
541  resultType.getIntOrFloatBitWidth(), op->getLoc());
542  rewriter.replaceOpWithNewOp<comb::ShrUOp>(
543  op, resultType, adaptor.getValue(), amount, false);
544  return success();
545  }
546 };
547 
548 struct AShrOpConversion : public OpConversionPattern<AShrOp> {
549  using OpConversionPattern::OpConversionPattern;
550 
551  LogicalResult
552  matchAndRewrite(AShrOp op, OpAdaptor adaptor,
553  ConversionPatternRewriter &rewriter) const override {
554  Type resultType = typeConverter->convertType(op.getResult().getType());
555 
556  // Comb shift operations require the same bit-width for value and amount
557  Value amount =
558  adjustIntegerWidth(rewriter, adaptor.getAmount(),
559  resultType.getIntOrFloatBitWidth(), op->getLoc());
560  rewriter.replaceOpWithNewOp<comb::ShrSOp>(
561  op, resultType, adaptor.getValue(), amount, false);
562  return success();
563  }
564 };
565 
566 struct ReadOpConversion : public OpConversionPattern<ReadOp> {
567  using OpConversionPattern::OpConversionPattern;
568 
569  LogicalResult
570  matchAndRewrite(ReadOp op, OpAdaptor adaptor,
571  ConversionPatternRewriter &rewriter) const override {
572  Type resultType = typeConverter->convertType(op.getResult().getType());
573  rewriter.replaceOpWithNewOp<llhd::PrbOp>(op, resultType,
574  adaptor.getInput());
575  return success();
576  }
577 };
578 
579 template <typename OpTy>
580 struct AssignOpConversion : public OpConversionPattern<OpTy> {
582  using OpAdaptor = typename OpTy::Adaptor;
583 
584  LogicalResult
585  matchAndRewrite(OpTy op, OpAdaptor adaptor,
586  ConversionPatternRewriter &rewriter) const override {
587  // TODO: When we support delay control in Moore dialect, we need to update
588  // this conversion.
589  auto timeAttr =
590  llhd::TimeAttr::get(op->getContext(), unsigned(0),
591  llvm::StringRef("ns"), unsigned(0), unsigned(0));
592  auto time = rewriter.create<llhd::ConstantTimeOp>(op->getLoc(), timeAttr);
593  rewriter.replaceOpWithNewOp<llhd::DrvOp>(op, adaptor.getDst(),
594  adaptor.getSrc(), time, Value{});
595  return success();
596  }
597 };
598 
599 } // namespace
600 
601 //===----------------------------------------------------------------------===//
602 // Conversion Infrastructure
603 //===----------------------------------------------------------------------===//
604 
605 static bool isMooreType(Type type) { return isa<UnpackedType>(type); }
606 
607 static bool hasMooreType(TypeRange types) {
608  return llvm::any_of(types, isMooreType);
609 }
610 
611 static bool hasMooreType(ValueRange values) {
612  return hasMooreType(values.getTypes());
613 }
614 
615 template <typename Op>
616 static void addGenericLegality(ConversionTarget &target) {
617  target.addDynamicallyLegalOp<Op>([](Op op) {
618  return !hasMooreType(op->getOperands()) && !hasMooreType(op->getResults());
619  });
620 }
621 
622 static void populateLegality(ConversionTarget &target) {
623  target.addIllegalDialect<MooreDialect>();
624  target.addLegalDialect<mlir::BuiltinDialect>();
625  target.addLegalDialect<hw::HWDialect>();
626  target.addLegalDialect<llhd::LLHDDialect>();
627  target.addLegalDialect<comb::CombDialect>();
628 
629  addGenericLegality<cf::CondBranchOp>(target);
630  addGenericLegality<cf::BranchOp>(target);
631  addGenericLegality<func::CallOp>(target);
632  addGenericLegality<func::ReturnOp>(target);
633  addGenericLegality<UnrealizedConversionCastOp>(target);
634 
635  target.addDynamicallyLegalOp<func::FuncOp>([](func::FuncOp op) {
636  auto argsConverted = llvm::none_of(op.getBlocks(), [](auto &block) {
637  return hasMooreType(block.getArguments());
638  });
639  auto resultsConverted = !hasMooreType(op.getResultTypes());
640  return argsConverted && resultsConverted;
641  });
642 
643  target.addDynamicallyLegalOp<hw::HWModuleOp>([](hw::HWModuleOp op) {
644  return !hasMooreType(op.getInputTypes()) &&
645  !hasMooreType(op.getOutputTypes()) &&
646  !hasMooreType(op.getBody().getArgumentTypes());
647  });
648 
649  target.addDynamicallyLegalOp<hw::InstanceOp>([](hw::InstanceOp op) {
650  return !hasMooreType(op.getInputs()) && !hasMooreType(op.getResults());
651  });
652 
653  target.addDynamicallyLegalOp<hw::OutputOp>(
654  [](hw::OutputOp op) { return !hasMooreType(op.getOutputs()); });
655 }
656 
657 static void populateTypeConversion(TypeConverter &typeConverter) {
658  typeConverter.addConversion([&](IntType type) {
659  return mlir::IntegerType::get(type.getContext(), type.getWidth());
660  });
661 
662  typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
663  if (isa<IntType, ArrayType, UnpackedArrayType>(type.getNestedType()))
664  return mlir::IntegerType::get(type.getContext(),
665  type.getBitSize().value());
666  return std::nullopt;
667  });
668 
669  // Valid target types.
670  typeConverter.addConversion([](mlir::IntegerType type) { return type; });
671  typeConverter.addTargetMaterialization(
672  [&](mlir::OpBuilder &builder, mlir::Type resultType,
673  mlir::ValueRange inputs,
674  mlir::Location loc) -> std::optional<mlir::Value> {
675  if (inputs.size() != 1)
676  return std::nullopt;
677  return inputs[0];
678  });
679 
680  typeConverter.addSourceMaterialization(
681  [&](mlir::OpBuilder &builder, mlir::Type resultType,
682  mlir::ValueRange inputs,
683  mlir::Location loc) -> std::optional<mlir::Value> {
684  if (inputs.size() != 1)
685  return std::nullopt;
686  return inputs[0];
687  });
688 }
689 
690 static void populateOpConversion(RewritePatternSet &patterns,
691  TypeConverter &typeConverter) {
692  auto *context = patterns.getContext();
693  // clang-format off
694  patterns.add<
695  // Patterns of declaration operations.
696  VariableOpConversion,
697 
698  // Patterns of miscellaneous operations.
699  ConstantOpConv, ConcatOpConversion, ReplicateOpConversion,
700  ExtractOpConversion, DynExtractOpConversion, ConversionOpConversion,
701  ReadOpConversion, NamedConstantOpConv,
702 
703  // Patterns of unary operations.
704  ReduceAndOpConversion, ReduceOrOpConversion, ReduceXorOpConversion,
705  BoolCastOpConversion, NotOpConversion, NegOpConversion,
706 
707  // Patterns of binary operations.
708  BinaryOpConversion<AddOp, comb::AddOp>,
709  BinaryOpConversion<SubOp, comb::SubOp>,
710  BinaryOpConversion<MulOp, comb::MulOp>,
711  BinaryOpConversion<DivUOp, comb::DivUOp>,
712  BinaryOpConversion<DivSOp, comb::DivSOp>,
713  BinaryOpConversion<ModUOp, comb::ModUOp>,
714  BinaryOpConversion<ModSOp, comb::ModSOp>,
715  BinaryOpConversion<AndOp, comb::AndOp>,
716  BinaryOpConversion<OrOp, comb::OrOp>,
717  BinaryOpConversion<XorOp, comb::XorOp>,
718 
719  // Patterns of relational operations.
720  ICmpOpConversion<UltOp, ICmpPredicate::ult>,
721  ICmpOpConversion<SltOp, ICmpPredicate::slt>,
722  ICmpOpConversion<UleOp, ICmpPredicate::ule>,
723  ICmpOpConversion<SleOp, ICmpPredicate::sle>,
724  ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
725  ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
726  ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
727  ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
728  ICmpOpConversion<EqOp, ICmpPredicate::eq>,
729  ICmpOpConversion<NeOp, ICmpPredicate::ne>,
730  ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
731  ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
732  ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
733  ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
734 
735  // Patterns of structural operations.
736  SVModuleOpConversion, InstanceOpConversion,
737 
738  // Patterns of shifting operations.
739  ShrOpConversion, ShlOpConversion, AShrOpConversion,
740 
741  // Patterns of assignment operations.
742  AssignOpConversion<ContinuousAssignOp>,
743 
744  // Patterns of branch operations.
745  CondBranchOpConversion, BranchOpConversion,
746 
747  // Patterns of other operations outside Moore dialect.
748  HWOutputOpConversion, HWInstanceOpConversion, ReturnOpConversion,
749  CallOpConversion, UnrealizedConversionCastConversion
750  >(typeConverter, context);
751  // clang-format on
752  mlir::populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(
753  patterns, typeConverter);
754 
756  hw::HWModuleOp::getOperationName(), patterns, typeConverter);
757 }
758 
759 //===----------------------------------------------------------------------===//
760 // Moore to Core Conversion Pass
761 //===----------------------------------------------------------------------===//
762 
763 namespace {
764 struct MooreToCorePass
765  : public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
766  void runOnOperation() override;
767 };
768 } // namespace
769 
770 /// Create a Moore to core dialects conversion pass.
771 std::unique_ptr<OperationPass<ModuleOp>> circt::createConvertMooreToCorePass() {
772  return std::make_unique<MooreToCorePass>();
773 }
774 
775 /// This is the main entrypoint for the Moore to Core conversion pass.
776 void MooreToCorePass::runOnOperation() {
777  MLIRContext &context = getContext();
778  ModuleOp module = getOperation();
779 
780  ConversionTarget target(context);
781  TypeConverter typeConverter;
782  RewritePatternSet patterns(&context);
783  populateLegality(target);
784  populateTypeConversion(typeConverter);
785  populateOpConversion(patterns, typeConverter);
786 
787  if (failed(applyFullConversion(module, target, std::move(patterns))))
788  signalPassFailure();
789 }
int32_t width
Definition: FIRRTL.cpp:36
@ Output
Definition: HW.h:35
static void populateLegality(ConversionTarget &target)
static bool hasMooreType(TypeRange types)
static void populateOpConversion(RewritePatternSet &patterns, TypeConverter &typeConverter)
static bool isMooreType(Type type)
static void addGenericLegality(ConversionTarget &target)
static void populateTypeConversion(TypeConverter &typeConverter)
def create(low_bit, result_type, input=None)
Definition: comb.py:187
def create(data_type, value)
Definition: hw.py:393
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
void populateHWModuleLikeTypeConversionPattern(StringRef moduleLikeOpName, RewritePatternSet &patterns, TypeConverter &converter)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
std::unique_ptr< OperationPass< ModuleOp > > createConvertMooreToCorePass()
Create an Moore to Comb/HW/LLHD conversion pass.