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, llhd::SigType::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  auto width = typeConverter->convertType(op.getInput().getType())
248  .getIntOrFloatBitWidth();
249  Value amount =
250  adjustIntegerWidth(rewriter, adaptor.getLowBit(), width, op->getLoc());
251  Value value =
252  rewriter.create<comb::ShrUOp>(op->getLoc(), adaptor.getInput(), amount);
253 
254  rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, resultType, value, 0);
255  return success();
256  }
257 };
258 
259 struct ReduceAndOpConversion : public OpConversionPattern<ReduceAndOp> {
260  using OpConversionPattern::OpConversionPattern;
261  LogicalResult
262  matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
263  ConversionPatternRewriter &rewriter) const override {
264  Type resultType = typeConverter->convertType(op.getInput().getType());
265  Value max = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, -1);
266 
267  rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
268  adaptor.getInput(), max);
269  return success();
270  }
271 };
272 
273 struct ReduceOrOpConversion : public OpConversionPattern<ReduceOrOp> {
274  using OpConversionPattern::OpConversionPattern;
275  LogicalResult
276  matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
277  ConversionPatternRewriter &rewriter) const override {
278  Type resultType = typeConverter->convertType(op.getInput().getType());
279  Value zero = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, 0);
280 
281  rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
282  adaptor.getInput(), zero);
283  return success();
284  }
285 };
286 
287 struct ReduceXorOpConversion : public OpConversionPattern<ReduceXorOp> {
288  using OpConversionPattern::OpConversionPattern;
289  LogicalResult
290  matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
291  ConversionPatternRewriter &rewriter) const override {
292 
293  rewriter.replaceOpWithNewOp<comb::ParityOp>(op, adaptor.getInput());
294  return success();
295  }
296 };
297 
298 struct BoolCastOpConversion : public OpConversionPattern<BoolCastOp> {
299  using OpConversionPattern::OpConversionPattern;
300  LogicalResult
301  matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
302  ConversionPatternRewriter &rewriter) const override {
303  Type resultType = typeConverter->convertType(op.getInput().getType());
304  if (isa_and_nonnull<IntegerType>(resultType)) {
305  Value zero = rewriter.create<hw::ConstantOp>(op->getLoc(), resultType, 0);
306  rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
307  adaptor.getInput(), zero);
308  return success();
309  }
310  return failure();
311  }
312 };
313 
314 struct NotOpConversion : public OpConversionPattern<NotOp> {
315  using OpConversionPattern::OpConversionPattern;
316  LogicalResult
317  matchAndRewrite(NotOp op, OpAdaptor adaptor,
318  ConversionPatternRewriter &rewriter) const override {
319  Type resultType =
320  ConversionPattern::typeConverter->convertType(op.getResult().getType());
321  Value max = rewriter.create<hw::ConstantOp>(op.getLoc(), resultType, -1);
322 
323  rewriter.replaceOpWithNewOp<comb::XorOp>(op, adaptor.getInput(), max);
324  return success();
325  }
326 };
327 
328 struct NegOpConversion : public OpConversionPattern<NegOp> {
329  using OpConversionPattern::OpConversionPattern;
330  LogicalResult
331  matchAndRewrite(NegOp op, OpAdaptor adaptor,
332  ConversionPatternRewriter &rewriter) const override {
333  Type resultType =
334  ConversionPattern::typeConverter->convertType(op.getResult().getType());
335  Value zero = rewriter.create<hw::ConstantOp>(op.getLoc(), resultType, 0);
336 
337  rewriter.replaceOpWithNewOp<comb::SubOp>(op, zero, adaptor.getInput());
338  return success();
339  }
340 };
341 
342 template <typename SourceOp, typename TargetOp>
343 struct BinaryOpConversion : public OpConversionPattern<SourceOp> {
345  using OpAdaptor = typename SourceOp::Adaptor;
346 
347  LogicalResult
348  matchAndRewrite(SourceOp op, OpAdaptor adaptor,
349  ConversionPatternRewriter &rewriter) const override {
350  rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
351  adaptor.getRhs(), false);
352  return success();
353  }
354 };
355 
356 template <typename SourceOp, ICmpPredicate pred>
357 struct ICmpOpConversion : public OpConversionPattern<SourceOp> {
359  using OpAdaptor = typename SourceOp::Adaptor;
360 
361  LogicalResult
362  matchAndRewrite(SourceOp op, OpAdaptor adapter,
363  ConversionPatternRewriter &rewriter) const override {
364  Type resultType =
365  ConversionPattern::typeConverter->convertType(op.getResult().getType());
366 
367  rewriter.replaceOpWithNewOp<comb::ICmpOp>(
368  op, resultType, pred, adapter.getLhs(), adapter.getRhs());
369  return success();
370  }
371 };
372 
373 struct ConversionOpConversion : public OpConversionPattern<ConversionOp> {
374  using OpConversionPattern::OpConversionPattern;
375 
376  LogicalResult
377  matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
378  ConversionPatternRewriter &rewriter) const override {
379  Type resultType = typeConverter->convertType(op.getResult().getType());
380  Value amount =
381  adjustIntegerWidth(rewriter, adaptor.getInput(),
382  resultType.getIntOrFloatBitWidth(), op->getLoc());
383 
384  rewriter.replaceOpWithNewOp<hw::BitcastOp>(op, resultType, amount);
385  return success();
386  }
387 };
388 
389 //===----------------------------------------------------------------------===//
390 // Statement Conversion
391 //===----------------------------------------------------------------------===//
392 
393 struct HWOutputOpConversion : public OpConversionPattern<hw::OutputOp> {
394  using OpConversionPattern::OpConversionPattern;
395 
396  LogicalResult
397  matchAndRewrite(hw::OutputOp op, OpAdaptor adaptor,
398  ConversionPatternRewriter &rewriter) const override {
399  rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
400  return success();
401  }
402 };
403 
404 struct HWInstanceOpConversion : public OpConversionPattern<hw::InstanceOp> {
405  using OpConversionPattern::OpConversionPattern;
406 
407  LogicalResult
408  matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
409  ConversionPatternRewriter &rewriter) const override {
410  SmallVector<Type> convResTypes;
411  if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
412  return failure();
413 
414  rewriter.replaceOpWithNewOp<hw::InstanceOp>(
415  op, convResTypes, op.getInstanceName(), op.getModuleName(),
416  adaptor.getOperands(), op.getArgNames(),
417  op.getResultNames(), /*Parameter*/
418  rewriter.getArrayAttr({}), /*InnerSymbol*/ nullptr);
419 
420  return success();
421  }
422 };
423 
424 struct ReturnOpConversion : public OpConversionPattern<func::ReturnOp> {
425  using OpConversionPattern::OpConversionPattern;
426 
427  LogicalResult
428  matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
429  ConversionPatternRewriter &rewriter) const override {
430  rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
431  return success();
432  }
433 };
434 
435 struct CondBranchOpConversion : public OpConversionPattern<cf::CondBranchOp> {
436  using OpConversionPattern::OpConversionPattern;
437 
438  LogicalResult
439  matchAndRewrite(cf::CondBranchOp op, OpAdaptor adaptor,
440  ConversionPatternRewriter &rewriter) const override {
441  rewriter.replaceOpWithNewOp<cf::CondBranchOp>(
442  op, adaptor.getCondition(), adaptor.getTrueDestOperands(),
443  adaptor.getFalseDestOperands(), op.getTrueDest(), op.getFalseDest());
444  return success();
445  }
446 };
447 
448 struct BranchOpConversion : public OpConversionPattern<cf::BranchOp> {
449  using OpConversionPattern::OpConversionPattern;
450 
451  LogicalResult
452  matchAndRewrite(cf::BranchOp op, OpAdaptor adaptor,
453  ConversionPatternRewriter &rewriter) const override {
454  rewriter.replaceOpWithNewOp<cf::BranchOp>(op, op.getDest(),
455  adaptor.getDestOperands());
456  return success();
457  }
458 };
459 
460 struct CallOpConversion : public OpConversionPattern<func::CallOp> {
461  using OpConversionPattern::OpConversionPattern;
462 
463  LogicalResult
464  matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
465  ConversionPatternRewriter &rewriter) const override {
466  SmallVector<Type> convResTypes;
467  if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
468  return failure();
469  rewriter.replaceOpWithNewOp<func::CallOp>(
470  op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
471  return success();
472  }
473 };
474 
475 struct UnrealizedConversionCastConversion
476  : public OpConversionPattern<UnrealizedConversionCastOp> {
477  using OpConversionPattern::OpConversionPattern;
478 
479  LogicalResult
480  matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
481  ConversionPatternRewriter &rewriter) const override {
482  SmallVector<Type> convResTypes;
483  if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
484  return failure();
485 
486  // Drop the cast if the operand and result types agree after type
487  // conversion.
488  if (convResTypes == adaptor.getOperands().getTypes()) {
489  rewriter.replaceOp(op, adaptor.getOperands());
490  return success();
491  }
492 
493  rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
494  op, convResTypes, adaptor.getOperands());
495  return success();
496  }
497 };
498 
499 struct ShlOpConversion : public OpConversionPattern<ShlOp> {
500  using OpConversionPattern::OpConversionPattern;
501 
502  LogicalResult
503  matchAndRewrite(ShlOp op, OpAdaptor adaptor,
504  ConversionPatternRewriter &rewriter) const override {
505  Type resultType = typeConverter->convertType(op.getResult().getType());
506 
507  // Comb shift operations require the same bit-width for value and amount
508  Value amount =
509  adjustIntegerWidth(rewriter, adaptor.getAmount(),
510  resultType.getIntOrFloatBitWidth(), op->getLoc());
511  rewriter.replaceOpWithNewOp<comb::ShlOp>(op, resultType, adaptor.getValue(),
512  amount, false);
513  return success();
514  }
515 };
516 
517 struct ShrOpConversion : public OpConversionPattern<ShrOp> {
518  using OpConversionPattern::OpConversionPattern;
519 
520  LogicalResult
521  matchAndRewrite(ShrOp op, OpAdaptor adaptor,
522  ConversionPatternRewriter &rewriter) const override {
523  Type resultType = typeConverter->convertType(op.getResult().getType());
524 
525  // Comb shift operations require the same bit-width for value and amount
526  Value amount =
527  adjustIntegerWidth(rewriter, adaptor.getAmount(),
528  resultType.getIntOrFloatBitWidth(), op->getLoc());
529  rewriter.replaceOpWithNewOp<comb::ShrUOp>(
530  op, resultType, adaptor.getValue(), amount, false);
531  return success();
532  }
533 };
534 
535 struct AShrOpConversion : public OpConversionPattern<AShrOp> {
536  using OpConversionPattern::OpConversionPattern;
537 
538  LogicalResult
539  matchAndRewrite(AShrOp op, OpAdaptor adaptor,
540  ConversionPatternRewriter &rewriter) const override {
541  Type resultType = typeConverter->convertType(op.getResult().getType());
542 
543  // Comb shift operations require the same bit-width for value and amount
544  Value amount =
545  adjustIntegerWidth(rewriter, adaptor.getAmount(),
546  resultType.getIntOrFloatBitWidth(), op->getLoc());
547  rewriter.replaceOpWithNewOp<comb::ShrSOp>(
548  op, resultType, adaptor.getValue(), amount, false);
549  return success();
550  }
551 };
552 
553 struct ReadOpConversion : public OpConversionPattern<ReadOp> {
554  using OpConversionPattern::OpConversionPattern;
555 
556  LogicalResult
557  matchAndRewrite(ReadOp op, OpAdaptor adaptor,
558  ConversionPatternRewriter &rewriter) const override {
559  Type resultType = typeConverter->convertType(op.getResult().getType());
560  rewriter.replaceOpWithNewOp<llhd::PrbOp>(op, resultType,
561  adaptor.getInput());
562  return success();
563  }
564 };
565 
566 template <typename OpTy>
567 struct AssignOpConversion : public OpConversionPattern<OpTy> {
569  using OpAdaptor = typename OpTy::Adaptor;
570 
571  LogicalResult
572  matchAndRewrite(OpTy op, OpAdaptor adaptor,
573  ConversionPatternRewriter &rewriter) const override {
574  // TODO: When we support delay control in Moore dialect, we need to update
575  // this conversion.
576  auto timeAttr =
577  llhd::TimeAttr::get(op->getContext(), unsigned(0),
578  llvm::StringRef("ns"), unsigned(0), unsigned(0));
579  auto time = rewriter.create<llhd::ConstantTimeOp>(op->getLoc(), timeAttr);
580  rewriter.replaceOpWithNewOp<llhd::DrvOp>(op, adaptor.getDst(),
581  adaptor.getSrc(), time, Value{});
582  return success();
583  }
584 };
585 
586 } // namespace
587 
588 //===----------------------------------------------------------------------===//
589 // Conversion Infrastructure
590 //===----------------------------------------------------------------------===//
591 
592 static bool isMooreType(Type type) { return isa<UnpackedType>(type); }
593 
594 static bool hasMooreType(TypeRange types) {
595  return llvm::any_of(types, isMooreType);
596 }
597 
598 static bool hasMooreType(ValueRange values) {
599  return hasMooreType(values.getTypes());
600 }
601 
602 template <typename Op>
603 static void addGenericLegality(ConversionTarget &target) {
604  target.addDynamicallyLegalOp<Op>([](Op op) {
605  return !hasMooreType(op->getOperands()) && !hasMooreType(op->getResults());
606  });
607 }
608 
609 static void populateLegality(ConversionTarget &target) {
610  target.addIllegalDialect<MooreDialect>();
611  target.addLegalDialect<mlir::BuiltinDialect>();
612  target.addLegalDialect<hw::HWDialect>();
613  target.addLegalDialect<llhd::LLHDDialect>();
614  target.addLegalDialect<comb::CombDialect>();
615 
616  addGenericLegality<cf::CondBranchOp>(target);
617  addGenericLegality<cf::BranchOp>(target);
618  addGenericLegality<func::CallOp>(target);
619  addGenericLegality<func::ReturnOp>(target);
620  addGenericLegality<UnrealizedConversionCastOp>(target);
621 
622  target.addDynamicallyLegalOp<func::FuncOp>([](func::FuncOp op) {
623  auto argsConverted = llvm::none_of(op.getBlocks(), [](auto &block) {
624  return hasMooreType(block.getArguments());
625  });
626  auto resultsConverted = !hasMooreType(op.getResultTypes());
627  return argsConverted && resultsConverted;
628  });
629 
630  target.addDynamicallyLegalOp<hw::HWModuleOp>([](hw::HWModuleOp op) {
631  return !hasMooreType(op.getInputTypes()) &&
632  !hasMooreType(op.getOutputTypes()) &&
633  !hasMooreType(op.getBody().getArgumentTypes());
634  });
635 
636  target.addDynamicallyLegalOp<hw::InstanceOp>([](hw::InstanceOp op) {
637  return !hasMooreType(op.getInputs()) && !hasMooreType(op.getResults());
638  });
639 
640  target.addDynamicallyLegalOp<hw::OutputOp>(
641  [](hw::OutputOp op) { return !hasMooreType(op.getOutputs()); });
642 }
643 
644 static void populateTypeConversion(TypeConverter &typeConverter) {
645  typeConverter.addConversion([&](IntType type) {
646  return mlir::IntegerType::get(type.getContext(), type.getWidth());
647  });
648 
649  typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
650  if (isa<IntType, ArrayType, UnpackedArrayType>(type.getNestedType()))
651  return mlir::IntegerType::get(type.getContext(),
652  type.getBitSize().value());
653  return std::nullopt;
654  });
655 
656  // Valid target types.
657  typeConverter.addConversion([](mlir::IntegerType type) { return type; });
658  typeConverter.addTargetMaterialization(
659  [&](mlir::OpBuilder &builder, mlir::Type resultType,
660  mlir::ValueRange inputs,
661  mlir::Location loc) -> std::optional<mlir::Value> {
662  if (inputs.size() != 1)
663  return std::nullopt;
664  return inputs[0];
665  });
666 
667  typeConverter.addSourceMaterialization(
668  [&](mlir::OpBuilder &builder, mlir::Type resultType,
669  mlir::ValueRange inputs,
670  mlir::Location loc) -> std::optional<mlir::Value> {
671  if (inputs.size() != 1)
672  return std::nullopt;
673  return inputs[0];
674  });
675 }
676 
677 static void populateOpConversion(RewritePatternSet &patterns,
678  TypeConverter &typeConverter) {
679  auto *context = patterns.getContext();
680  // clang-format off
681  patterns.add<
682  // Patterns of declaration operations.
683  VariableOpConversion,
684 
685  // Patterns of miscellaneous operations.
686  ConstantOpConv, ConcatOpConversion, ReplicateOpConversion,
687  ExtractOpConversion, ConversionOpConversion, ReadOpConversion,
688  NamedConstantOpConv,
689 
690  // Patterns of unary operations.
691  ReduceAndOpConversion, ReduceOrOpConversion, ReduceXorOpConversion,
692  BoolCastOpConversion, NotOpConversion, NegOpConversion,
693 
694  // Patterns of binary operations.
695  BinaryOpConversion<AddOp, comb::AddOp>,
696  BinaryOpConversion<SubOp, comb::SubOp>,
697  BinaryOpConversion<MulOp, comb::MulOp>,
698  BinaryOpConversion<DivUOp, comb::DivUOp>,
699  BinaryOpConversion<DivSOp, comb::DivSOp>,
700  BinaryOpConversion<ModUOp, comb::ModUOp>,
701  BinaryOpConversion<ModSOp, comb::ModSOp>,
702  BinaryOpConversion<AndOp, comb::AndOp>,
703  BinaryOpConversion<OrOp, comb::OrOp>,
704  BinaryOpConversion<XorOp, comb::XorOp>,
705 
706  // Patterns of relational operations.
707  ICmpOpConversion<UltOp, ICmpPredicate::ult>,
708  ICmpOpConversion<SltOp, ICmpPredicate::slt>,
709  ICmpOpConversion<UleOp, ICmpPredicate::ule>,
710  ICmpOpConversion<SleOp, ICmpPredicate::sle>,
711  ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
712  ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
713  ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
714  ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
715  ICmpOpConversion<EqOp, ICmpPredicate::eq>,
716  ICmpOpConversion<NeOp, ICmpPredicate::ne>,
717  ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
718  ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
719  ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
720  ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
721 
722  // Patterns of structural operations.
723  SVModuleOpConversion, InstanceOpConversion,
724 
725  // Patterns of shifting operations.
726  ShrOpConversion, ShlOpConversion, AShrOpConversion,
727 
728  // Patterns of assignment operations.
729  AssignOpConversion<ContinuousAssignOp>,
730 
731  // Patterns of branch operations.
732  CondBranchOpConversion, BranchOpConversion,
733 
734  // Patterns of other operations outside Moore dialect.
735  HWOutputOpConversion, HWInstanceOpConversion, ReturnOpConversion,
736  CallOpConversion, UnrealizedConversionCastConversion
737  >(typeConverter, context);
738  // clang-format on
739  mlir::populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(
740  patterns, typeConverter);
741 
743  hw::HWModuleOp::getOperationName(), patterns, typeConverter);
744 }
745 
746 //===----------------------------------------------------------------------===//
747 // Moore to Core Conversion Pass
748 //===----------------------------------------------------------------------===//
749 
750 namespace {
751 struct MooreToCorePass
752  : public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
753  void runOnOperation() override;
754 };
755 } // namespace
756 
757 /// Create a Moore to core dialects conversion pass.
758 std::unique_ptr<OperationPass<ModuleOp>> circt::createConvertMooreToCorePass() {
759  return std::make_unique<MooreToCorePass>();
760 }
761 
762 /// This is the main entrypoint for the Moore to Core conversion pass.
763 void MooreToCorePass::runOnOperation() {
764  MLIRContext &context = getContext();
765  ModuleOp module = getOperation();
766 
767  ConversionTarget target(context);
768  TypeConverter typeConverter;
769  RewritePatternSet patterns(&context);
770  populateLegality(target);
771  populateTypeConversion(typeConverter);
772  populateOpConversion(patterns, typeConverter);
773 
774  if (failed(applyFullConversion(module, target, std::move(patterns))))
775  signalPassFailure();
776 }
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)
llvm::SmallVector< StringAttr > inputs
llvm::SmallVector< StringAttr > outputs
Builder builder
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.