CIRCT  20.0.0git
LowerToHW.cpp
Go to the documentation of this file.
1 //===- LowerToHW.cpp - FIRRTL to HW/SV Lowering 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 FIRRTL to HW/SV Lowering Pass Implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
26 #include "circt/Dialect/HW/HWOps.h"
30 #include "circt/Dialect/SV/SVOps.h"
36 #include "mlir/IR/BuiltinOps.h"
37 #include "mlir/IR/BuiltinTypes.h"
38 #include "mlir/IR/ImplicitLocOpBuilder.h"
39 #include "mlir/IR/Threading.h"
40 #include "mlir/Pass/Pass.h"
41 #include "llvm/ADT/StringSet.h"
42 #include "llvm/ADT/TinyPtrVector.h"
43 #include "llvm/Support/Debug.h"
44 #include "llvm/Support/FormatVariadic.h"
45 #include "llvm/Support/Mutex.h"
46 #include "llvm/Support/Parallel.h"
47 
48 #define DEBUG_TYPE "lower-to-hw"
49 
50 namespace circt {
51 #define GEN_PASS_DEF_LOWERFIRRTLTOHW
52 #include "circt/Conversion/Passes.h.inc"
53 } // namespace circt
54 
55 using namespace circt;
56 using namespace firrtl;
57 using circt::comb::ICmpPredicate;
58 
59 /// Attribute that indicates that the module hierarchy starting at the
60 /// annotated module should be dumped to a file.
61 static const char moduleHierarchyFileAttrName[] = "firrtl.moduleHierarchyFile";
62 
63 /// Return true if the specified type is a sized FIRRTL type (Int or Analog)
64 /// with zero bits.
65 static bool isZeroBitFIRRTLType(Type type) {
66  auto ftype = dyn_cast<FIRRTLBaseType>(type);
67  return ftype && ftype.getPassiveType().getBitWidthOrSentinel() == 0;
68 }
69 
70 // Return a single source value in the operands of the given attach op if
71 // exists.
72 static Value getSingleNonInstanceOperand(AttachOp op) {
73  Value singleSource;
74  for (auto operand : op.getAttached()) {
75  if (isZeroBitFIRRTLType(operand.getType()) ||
76  operand.getDefiningOp<InstanceOp>())
77  continue;
78  // If it is used by other than attach op or there is already a source
79  // value, bail out.
80  if (!operand.hasOneUse() || singleSource)
81  return {};
82  singleSource = operand;
83  }
84  return singleSource;
85 }
86 
87 /// This verifies that the target operation has been lowered to a legal
88 /// operation. This checks that the operation recursively has no FIRRTL
89 /// operations or types.
90 static LogicalResult verifyOpLegality(Operation *op) {
91  auto checkTypes = [](Operation *op) -> WalkResult {
92  // Check that this operation is not a FIRRTL op.
93  if (isa_and_nonnull<FIRRTLDialect>(op->getDialect()))
94  return op->emitError("Found unhandled FIRRTL operation '")
95  << op->getName() << "'";
96 
97  // Helper to check a TypeRange for any FIRRTL types.
98  auto checkTypeRange = [&](TypeRange types) -> LogicalResult {
99  if (llvm::any_of(types, [](Type type) {
100  return isa<FIRRTLDialect>(type.getDialect());
101  }))
102  return op->emitOpError("found unhandled FIRRTL type");
103  return success();
104  };
105 
106  // Check operand and result types.
107  if (failed(checkTypeRange(op->getOperandTypes())) ||
108  failed(checkTypeRange(op->getResultTypes())))
109  return WalkResult::interrupt();
110 
111  // Check the block argument types.
112  for (auto &region : op->getRegions())
113  for (auto &block : region)
114  if (failed(checkTypeRange(block.getArgumentTypes())))
115  return WalkResult::interrupt();
116 
117  // Continue to the next operation.
118  return WalkResult::advance();
119  };
120 
121  if (checkTypes(op).wasInterrupted() || op->walk(checkTypes).wasInterrupted())
122  return failure();
123  return success();
124 }
125 
126 /// Given two FIRRTL integer types, return the widest one.
127 static IntType getWidestIntType(Type t1, Type t2) {
128  auto t1c = type_cast<IntType>(t1), t2c = type_cast<IntType>(t2);
129  return t2c.getWidth() > t1c.getWidth() ? t2c : t1c;
130 }
131 
132 /// Cast a value to a desired target type. This will insert struct casts and
133 /// unrealized conversion casts as necessary.
134 static Value castToFIRRTLType(Value val, Type type,
135  ImplicitLocOpBuilder &builder) {
136  // Use HWStructCastOp for a bundle type.
137  if (BundleType bundle = dyn_cast<BundleType>(type))
138  val = builder.createOrFold<HWStructCastOp>(bundle.getPassiveType(), val);
139 
140  if (type != val.getType())
141  val = builder.create<mlir::UnrealizedConversionCastOp>(type, val).getResult(
142  0);
143 
144  return val;
145 }
146 
147 /// Cast from a FIRRTL type (potentially with a flip) to a standard type.
148 static Value castFromFIRRTLType(Value val, Type type,
149  ImplicitLocOpBuilder &builder) {
150 
151  if (hw::StructType structTy = dyn_cast<hw::StructType>(type)) {
152  // Strip off Flip type if needed.
153  val =
154  builder
155  .create<mlir::UnrealizedConversionCastOp>(
156  type_cast<FIRRTLBaseType>(val.getType()).getPassiveType(), val)
157  .getResult(0);
158  val = builder.createOrFold<HWStructCastOp>(type, val);
159  return val;
160  }
161 
162  val =
163  builder.create<mlir::UnrealizedConversionCastOp>(type, val).getResult(0);
164 
165  return val;
166 }
167 
168 /// Move a ExtractTestCode related annotation from annotations to an attribute.
169 static void moveVerifAnno(ModuleOp top, AnnotationSet &annos,
170  StringRef annoClass, StringRef attrBase) {
171  auto anno = annos.getAnnotation(annoClass);
172  auto ctx = top.getContext();
173  if (!anno)
174  return;
175  if (auto dir = anno.getMember<StringAttr>("directory")) {
176  SmallVector<NamedAttribute> old;
177  for (auto i : top->getAttrs())
178  old.push_back(i);
179  old.emplace_back(
180  StringAttr::get(ctx, attrBase),
181  hw::OutputFileAttr::getAsDirectory(ctx, dir.getValue(), true, true));
182  top->setAttrs(old);
183  }
184  if (auto file = anno.getMember<StringAttr>("filename")) {
185  SmallVector<NamedAttribute> old;
186  for (auto i : top->getAttrs())
187  old.push_back(i);
188  old.emplace_back(StringAttr::get(ctx, attrBase + ".bindfile"),
189  hw::OutputFileAttr::getFromFilename(
190  ctx, file.getValue(), /*excludeFromFileList=*/true));
191  top->setAttrs(old);
192  }
193 }
194 
195 static unsigned getBitWidthFromVectorSize(unsigned size) {
196  return size == 1 ? 1 : llvm::Log2_64_Ceil(size);
197 }
198 
199 // Try moving a name from an firrtl expression to a hw expression as a name
200 // hint. Dont' overwrite an existing name.
201 static void tryCopyName(Operation *dst, Operation *src) {
202  if (auto attr = src->getAttrOfType<StringAttr>("name"))
203  if (!dst->hasAttr("sv.namehint") && !dst->hasAttr("name"))
204  dst->setAttr("sv.namehint", attr);
205 }
206 
207 //===----------------------------------------------------------------------===//
208 // firrtl.module Lowering Pass
209 //===----------------------------------------------------------------------===//
210 namespace {
211 
212 struct FIRRTLModuleLowering;
213 
214 /// This is state shared across the parallel module lowering logic.
215 struct CircuitLoweringState {
216  // Flags indicating whether the circuit uses certain header fragments.
217  std::atomic<bool> usedPrintfCond{false};
218  std::atomic<bool> usedAssertVerboseCond{false};
219  std::atomic<bool> usedStopCond{false};
220 
221  CircuitLoweringState(CircuitOp circuitOp, bool enableAnnotationWarning,
222  firrtl::VerificationFlavor verificationFlavor,
223  InstanceGraph &instanceGraph, NLATable *nlaTable)
224  : circuitOp(circuitOp), instanceGraph(instanceGraph),
225  enableAnnotationWarning(enableAnnotationWarning),
226  verificationFlavor(verificationFlavor), nlaTable(nlaTable) {
227  auto *context = circuitOp.getContext();
228 
229  // Get the testbench output directory.
230  if (auto tbAnno =
231  AnnotationSet(circuitOp).getAnnotation(testBenchDirAnnoClass)) {
232  auto dirName = tbAnno.getMember<StringAttr>("dirname");
233  testBenchDirectory = hw::OutputFileAttr::getAsDirectory(
234  context, dirName.getValue(), false, true);
235  }
236 
237  for (auto &op : *circuitOp.getBodyBlock()) {
238  if (auto module = dyn_cast<FModuleLike>(op))
240  dut = module;
241  }
242 
243  // Figure out which module is the DUT and TestHarness. If there is no
244  // module marked as the DUT, the top module is the DUT. If the DUT and the
245  // test harness are the same, then there is no test harness.
246  testHarness = instanceGraph.getTopLevelModule();
247  if (!dut) {
248  dut = testHarness;
249  testHarness = nullptr;
250  } else if (dut == testHarness) {
251  testHarness = nullptr;
252  }
253 
254  // Pre-populate the dutModules member with a list of all modules that are
255  // determined to be under the DUT.
256  auto inDUT = [&](igraph::ModuleOpInterface child) {
257  auto isBind = [](igraph::InstanceRecord *instRec) {
258  auto inst = instRec->getInstance();
259  if (auto *finst = dyn_cast<InstanceOp>(&inst))
260  return finst->getLowerToBind();
261  return false;
262  };
263  if (auto parent = dyn_cast<igraph::ModuleOpInterface>(*dut))
264  return getInstanceGraph().isAncestor(child, parent, isBind);
265  return dut == child;
266  };
267  circuitOp->walk([&](FModuleLike moduleOp) {
268  if (inDUT(moduleOp))
269  dutModules.insert(moduleOp);
270  });
271  }
272 
273  Operation *getNewModule(Operation *oldModule) {
274  auto it = oldToNewModuleMap.find(oldModule);
275  return it != oldToNewModuleMap.end() ? it->second : nullptr;
276  }
277 
278  Operation *getOldModule(Operation *newModule) {
279  auto it = newToOldModuleMap.find(newModule);
280  return it != newToOldModuleMap.end() ? it->second : nullptr;
281  }
282 
283  void recordModuleMapping(Operation *oldFMod, Operation *newHWMod) {
284  oldToNewModuleMap[oldFMod] = newHWMod;
285  newToOldModuleMap[newHWMod] = oldFMod;
286  }
287 
288  // Process remaining annotations and emit warnings on unprocessed annotations
289  // still remaining in the annoSet.
290  void processRemainingAnnotations(Operation *op, const AnnotationSet &annoSet);
291 
292  CircuitOp circuitOp;
293 
294  // Safely add a BindOp to global mutable state. This will acquire a lock to
295  // do this safely.
296  void addBind(sv::BindOp op) {
297  std::lock_guard<std::mutex> lock(bindsMutex);
298  binds.push_back(op);
299  }
300 
301  /// For a given Type Alias, return the corresponding AliasType. Create and
302  /// record the AliasType, if it doesn't exist.
303  hw::TypeAliasType getTypeAlias(Type rawType, BaseTypeAliasType firAliasType,
304  Location typeLoc) {
305 
306  auto hwAlias = typeAliases.getTypedecl(firAliasType);
307  if (hwAlias)
308  return hwAlias;
309  assert(!typeAliases.isFrozen() &&
310  "type aliases cannot be generated after its frozen");
311  return typeAliases.addTypedecl(rawType, firAliasType, typeLoc);
312  }
313 
314  FModuleLike getDut() { return dut; }
315  FModuleLike getTestHarness() { return testHarness; }
316 
317  // Return true if this module is the DUT or is instantiated by the DUT.
318  // Returns false if the module is not instantiated by the DUT or is
319  // instantiated under a bind. This will accept either an old FIRRTL module or
320  // a new HW module.
321  bool isInDUT(igraph::ModuleOpInterface child) {
322  if (auto hwModule = dyn_cast<hw::HWModuleOp>(child.getOperation()))
323  child = cast<igraph::ModuleOpInterface>(getOldModule(hwModule));
324  return dutModules.contains(child);
325  }
326 
327  hw::OutputFileAttr getTestBenchDirectory() { return testBenchDirectory; }
328 
329  // Return true if this module is instantiated by the Test Harness. Returns
330  // false if the module is not instantiated by the Test Harness or if the Test
331  // Harness is not known.
332  bool isInTestHarness(igraph::ModuleOpInterface mod) { return !isInDUT(mod); }
333 
334  InstanceGraph &getInstanceGraph() { return instanceGraph; }
335 
336  /// Given a type, return the corresponding lowered type for the HW dialect.
337  /// A wrapper to the FIRRTLUtils::lowerType, required to ensure safe addition
338  /// of TypeScopeOp for all the TypeDecls.
339  Type lowerType(Type type, Location loc) {
340  return ::lowerType(type, loc,
341  [&](Type rawType, BaseTypeAliasType firrtlType,
342  Location typeLoc) -> hw::TypeAliasType {
343  return getTypeAlias(rawType, firrtlType, typeLoc);
344  });
345  }
346 
347 private:
348  friend struct FIRRTLModuleLowering;
349  friend struct FIRRTLLowering;
350  CircuitLoweringState(const CircuitLoweringState &) = delete;
351  void operator=(const CircuitLoweringState &) = delete;
352 
353  /// Mapping of FModuleOp to HWModuleOp
354  DenseMap<Operation *, Operation *> oldToNewModuleMap;
355 
356  /// Mapping of HWModuleOp to FModuleOp
357  DenseMap<Operation *, Operation *> newToOldModuleMap;
358 
359  /// Cache of module symbols. We need to test hirarchy-based properties to
360  /// lower annotaitons.
361  InstanceGraph &instanceGraph;
362 
363  /// The set of old FIRRTL modules that are instantiated under the DUT. This
364  /// is precomputed as a module being under the DUT may rely on knowledge of
365  /// properties of the instance and is not suitable for querying in the
366  /// parallel execution region of this pass when the backing instances may
367  /// already be erased.
368  DenseSet<igraph::ModuleOpInterface> dutModules;
369 
370  // Record the set of remaining annotation classes. This is used to warn only
371  // once about any annotation class.
372  StringSet<> pendingAnnotations;
373  const bool enableAnnotationWarning;
374  std::mutex annotationPrintingMtx;
375 
376  const firrtl::VerificationFlavor verificationFlavor;
377 
378  // Records any sv::BindOps that are found during the course of execution.
379  // This is unsafe to access directly and should only be used through addBind.
380  SmallVector<sv::BindOp> binds;
381 
382  // Control access to binds.
383  std::mutex bindsMutex;
384 
385  // The design-under-test (DUT), if it is found. This will be set if a
386  // "sifive.enterprise.firrtl.MarkDUTAnnotation" exists.
387  FModuleLike dut;
388 
389  // If there is a module marked as the DUT and it is not the top level module,
390  // this will be set.
391  FModuleLike testHarness;
392 
393  // If there is a testbench output directory, this will be set.
394  hw::OutputFileAttr testBenchDirectory;
395 
396  /// A mapping of instances to their forced instantiation names (if
397  /// applicable).
398  DenseMap<std::pair<Attribute, Attribute>, Attribute> instanceForceNames;
399 
400  /// The set of guard macros to emit declarations for.
401  SetVector<StringAttr> macroDeclNames;
402  std::mutex macroDeclMutex;
403 
404  void addMacroDecl(StringAttr name) {
405  std::unique_lock<std::mutex> lock(macroDeclMutex);
406  macroDeclNames.insert(name);
407  }
408 
409  /// The list of fragments on which the modules rely. Must be set outside the
410  /// parallelized module lowering since module type reads access it.
411  DenseMap<hw::HWModuleOp, SetVector<Attribute>> fragments;
412  llvm::sys::SmartMutex<true> fragmentsMutex;
413 
414  void addFragment(hw::HWModuleOp module, StringRef fragment) {
415  llvm::sys::SmartScopedLock<true> lock(fragmentsMutex);
416  fragments[module].insert(
417  FlatSymbolRefAttr::get(circuitOp.getContext(), fragment));
418  }
419 
420  /// Cached nla table analysis.
421  NLATable *nlaTable = nullptr;
422 
423  /// FIRRTL::BaseTypeAliasType is lowered to hw::TypeAliasType, which requires
424  /// TypedeclOp inside a single global TypeScopeOp. This structure
425  /// maintains a map of FIRRTL alias types to HW alias type, which is populated
426  /// in the sequential phase and accessed during the read-only phase when its
427  /// frozen.
428  /// This structure ensures that
429  /// all TypeAliases are lowered as a prepass, before lowering all the modules
430  /// in parallel. Lowering of TypeAliases must be done sequentially to ensure
431  /// deteministic TypeDecls inside the global TypeScopeOp.
432  struct RecordTypeAlias {
433 
434  RecordTypeAlias(CircuitOp c) : circuitOp(c) {}
435 
436  hw::TypeAliasType getTypedecl(BaseTypeAliasType firAlias) const {
437  auto iter = firrtlTypeToAliasTypeMap.find(firAlias);
438  if (iter != firrtlTypeToAliasTypeMap.end())
439  return iter->second;
440  return {};
441  }
442 
443  bool isFrozen() { return frozen; }
444 
445  void freeze() { frozen = true; }
446 
447  hw::TypeAliasType addTypedecl(Type rawType, BaseTypeAliasType firAlias,
448  Location typeLoc) {
449  assert(!frozen && "Record already frozen, cannot be updated");
450 
451  if (!typeScope) {
452  auto b = ImplicitLocOpBuilder::atBlockBegin(
453  circuitOp.getLoc(),
454  &circuitOp->getParentRegion()->getBlocks().back());
455  typeScope = b.create<hw::TypeScopeOp>(
456  b.getStringAttr(circuitOp.getName() + "__TYPESCOPE_"));
457  typeScope.getBodyRegion().push_back(new Block());
458  }
459  auto typeName = firAlias.getName();
460  // Get a unique typedecl name.
461  // The bundleName can conflict with other symbols, but must be unique
462  // within the TypeScopeOp.
463  typeName =
464  StringAttr::get(typeName.getContext(),
465  typeDeclNamespace.newName(typeName.getValue()));
466 
467  auto typeScopeBuilder =
468  ImplicitLocOpBuilder::atBlockEnd(typeLoc, typeScope.getBodyBlock());
469  auto typeDecl = typeScopeBuilder.create<hw::TypedeclOp>(typeLoc, typeName,
470  rawType, nullptr);
471  auto hwAlias = hw::TypeAliasType::get(
472  SymbolRefAttr::get(typeScope.getSymNameAttr(),
473  {FlatSymbolRefAttr::get(typeDecl)}),
474  rawType);
475  auto insert = firrtlTypeToAliasTypeMap.try_emplace(firAlias, hwAlias);
476  assert(insert.second && "Entry already exists, insert failed");
477  return insert.first->second;
478  }
479 
480  private:
481  bool frozen = false;
482  /// Global typescope for all the typedecls in this module.
483  hw::TypeScopeOp typeScope;
484 
485  /// Map of FIRRTL type to the lowered AliasType.
486  DenseMap<Type, hw::TypeAliasType> firrtlTypeToAliasTypeMap;
487 
488  /// Set to keep track of unique typedecl names.
489  Namespace typeDeclNamespace;
490 
491  CircuitOp circuitOp;
492  };
493 
494  RecordTypeAlias typeAliases = RecordTypeAlias(circuitOp);
495 };
496 
497 void CircuitLoweringState::processRemainingAnnotations(
498  Operation *op, const AnnotationSet &annoSet) {
499  if (!enableAnnotationWarning || annoSet.empty())
500  return;
501  std::lock_guard<std::mutex> lock(annotationPrintingMtx);
502 
503  for (auto a : annoSet) {
504  auto inserted = pendingAnnotations.insert(a.getClass());
505  if (!inserted.second)
506  continue;
507 
508  // The following annotations are okay to be silently dropped at this point.
509  // This can occur for example if an annotation marks something in the IR as
510  // not to be processed by a pass, but that pass hasn't run anyway.
511  if (a.isClass(
512  // If the class is `circt.nonlocal`, it's not really an annotation,
513  // but part of a path specifier for another annotation which is
514  // non-local. We can ignore these path specifiers since there will
515  // be a warning produced for the real annotation.
516  "circt.nonlocal",
517  // The following are either consumed by a pass running before
518  // LowerToHW, or they have no effect if the pass doesn't run at all.
519  // If the accompanying pass runs on the HW dialect, then LowerToHW
520  // should have consumed and processed these into an attribute on the
521  // output.
523  // The following are inspected (but not consumed) by FIRRTL/GCT
524  // passes that have all run by now. Since no one is responsible for
525  // consuming these, they will linger around and can be ignored.
528  // This annotation is used to mark which external modules are
529  // imported blackboxes from the BlackBoxReader pass.
531  // This annotation is used by several GrandCentral passes.
533  // The following will be handled while lowering the verification
534  // ops.
537  // The following will be handled after lowering FModule ops, since
538  // they are still needed on the circuit until after lowering
539  // FModules.
542  continue;
543 
544  mlir::emitWarning(op->getLoc(), "unprocessed annotation:'" + a.getClass() +
545  "' still remaining after LowerToHW");
546  }
547 }
548 } // end anonymous namespace
549 
550 namespace {
551 struct FIRRTLModuleLowering
552  : public circt::impl::LowerFIRRTLToHWBase<FIRRTLModuleLowering> {
553 
554  void runOnOperation() override;
555  void setEnableAnnotationWarning() { enableAnnotationWarning = true; }
556 
557  using LowerFIRRTLToHWBase<FIRRTLModuleLowering>::verificationFlavor;
558 
559 private:
560  void lowerFileHeader(CircuitOp op, CircuitLoweringState &loweringState);
561  LogicalResult lowerPorts(ArrayRef<PortInfo> firrtlPorts,
562  SmallVectorImpl<hw::PortInfo> &ports,
563  Operation *moduleOp, StringRef moduleName,
564  CircuitLoweringState &loweringState);
565  bool handleForceNameAnnos(FModuleLike oldModule, AnnotationSet &annos,
566  CircuitLoweringState &loweringState);
567  hw::HWModuleOp lowerModule(FModuleOp oldModule, Block *topLevelModule,
568  CircuitLoweringState &loweringState);
569  hw::HWModuleExternOp lowerExtModule(FExtModuleOp oldModule,
570  Block *topLevelModule,
571  CircuitLoweringState &loweringState);
572  hw::HWModuleExternOp lowerMemModule(FMemModuleOp oldModule,
573  Block *topLevelModule,
574  CircuitLoweringState &loweringState);
575 
576  LogicalResult
577  lowerModulePortsAndMoveBody(FModuleOp oldModule, hw::HWModuleOp newModule,
578  CircuitLoweringState &loweringState);
579  LogicalResult lowerModuleOperations(hw::HWModuleOp module,
580  CircuitLoweringState &loweringState);
581 };
582 
583 } // end anonymous namespace
584 
585 /// This is the pass constructor.
586 std::unique_ptr<mlir::Pass> circt::createLowerFIRRTLToHWPass(
587  bool enableAnnotationWarning,
588  firrtl::VerificationFlavor verificationFlavor) {
589  auto pass = std::make_unique<FIRRTLModuleLowering>();
590  if (enableAnnotationWarning)
591  pass->setEnableAnnotationWarning();
592  pass->verificationFlavor = verificationFlavor;
593  return pass;
594 }
595 
596 /// Run on the firrtl.circuit operation, lowering any firrtl.module operations
597 /// it contains.
598 void FIRRTLModuleLowering::runOnOperation() {
599 
600  // We run on the top level modules in the IR blob. Start by finding the
601  // firrtl.circuit within it. If there is none, then there is nothing to do.
602  auto *topLevelModule = getOperation().getBody();
603 
604  // Find the single firrtl.circuit in the module.
605  CircuitOp circuit;
606  for (auto &op : *topLevelModule) {
607  if ((circuit = dyn_cast<CircuitOp>(&op)))
608  break;
609  }
610 
611  if (!circuit)
612  return;
613 
614  auto *circuitBody = circuit.getBodyBlock();
615 
616  // Keep track of the mapping from old to new modules. The result may be null
617  // if lowering failed.
618  CircuitLoweringState state(circuit, enableAnnotationWarning,
619  verificationFlavor, getAnalysis<InstanceGraph>(),
620  &getAnalysis<NLATable>());
621 
622  SmallVector<hw::HWModuleOp, 32> modulesToProcess;
623 
624  AnnotationSet circuitAnno(circuit);
625  moveVerifAnno(getOperation(), circuitAnno, extractAssertAnnoClass,
626  "firrtl.extract.assert");
627  moveVerifAnno(getOperation(), circuitAnno, extractAssumeAnnoClass,
628  "firrtl.extract.assume");
629  moveVerifAnno(getOperation(), circuitAnno, extractCoverageAnnoClass,
630  "firrtl.extract.cover");
631  circuitAnno.removeAnnotationsWithClass(
633 
634  state.processRemainingAnnotations(circuit, circuitAnno);
635  // Iterate through each operation in the circuit body, transforming any
636  // FModule's we come across. If any module fails to lower, return early.
637  for (auto &op : make_early_inc_range(circuitBody->getOperations())) {
638  auto result =
639  TypeSwitch<Operation *, LogicalResult>(&op)
640  .Case<FModuleOp>([&](auto module) {
641  auto loweredMod = lowerModule(module, topLevelModule, state);
642  if (!loweredMod)
643  return failure();
644 
645  state.recordModuleMapping(&op, loweredMod);
646  modulesToProcess.push_back(loweredMod);
647  // Lower all the alias types.
648  module.walk([&](Operation *op) {
649  for (auto res : op->getResults()) {
650  if (auto aliasType =
651  type_dyn_cast<BaseTypeAliasType>(res.getType()))
652  state.lowerType(aliasType, op->getLoc());
653  }
654  });
655  return lowerModulePortsAndMoveBody(module, loweredMod, state);
656  })
657  .Case<FExtModuleOp>([&](auto extModule) {
658  auto loweredMod =
659  lowerExtModule(extModule, topLevelModule, state);
660  if (!loweredMod)
661  return failure();
662  state.recordModuleMapping(&op, loweredMod);
663  return success();
664  })
665  .Case<FMemModuleOp>([&](auto memModule) {
666  auto loweredMod =
667  lowerMemModule(memModule, topLevelModule, state);
668  if (!loweredMod)
669  return failure();
670  state.recordModuleMapping(&op, loweredMod);
671  return success();
672  })
673  .Default([&](Operation *op) {
674  // We don't know what this op is. If it has no illegal FIRRTL
675  // types, we can forward the operation. Otherwise, we emit an
676  // error and drop the operation from the circuit.
677  if (succeeded(verifyOpLegality(op)))
678  op->moveBefore(topLevelModule, topLevelModule->end());
679  else
680  return failure();
681  return success();
682  });
683  if (failed(result))
684  return signalPassFailure();
685  }
686  // Ensure no more TypeDecl can be added to the global TypeScope.
687  state.typeAliases.freeze();
688  // Handle the creation of the module hierarchy metadata.
689 
690  // Collect the two sets of hierarchy files from the circuit. Some of them will
691  // be rooted at the test harness, the others will be rooted at the DUT.
692  SmallVector<Attribute> dutHierarchyFiles;
693  SmallVector<Attribute> testHarnessHierarchyFiles;
694  circuitAnno.removeAnnotations([&](Annotation annotation) {
695  if (annotation.isClass(moduleHierAnnoClass)) {
696  auto file = hw::OutputFileAttr::getFromFilename(
697  &getContext(),
698  annotation.getMember<StringAttr>("filename").getValue(),
699  /*excludeFromFileList=*/true);
700  dutHierarchyFiles.push_back(file);
701  return true;
702  }
703  if (annotation.isClass(testHarnessHierAnnoClass)) {
704  auto file = hw::OutputFileAttr::getFromFilename(
705  &getContext(),
706  annotation.getMember<StringAttr>("filename").getValue(),
707  /*excludeFromFileList=*/true);
708  // If there is no testHarness, we print the hiearchy for this file
709  // starting at the DUT.
710  if (state.getTestHarness())
711  testHarnessHierarchyFiles.push_back(file);
712  else
713  dutHierarchyFiles.push_back(file);
714  return true;
715  }
716  return false;
717  });
718  // Attach the lowered form of these annotations.
719  if (!dutHierarchyFiles.empty())
720  state.getNewModule(state.getDut())
721  ->setAttr(moduleHierarchyFileAttrName,
722  ArrayAttr::get(&getContext(), dutHierarchyFiles));
723  if (!testHarnessHierarchyFiles.empty())
724  state.getNewModule(state.getTestHarness())
725  ->setAttr(moduleHierarchyFileAttrName,
726  ArrayAttr::get(&getContext(), testHarnessHierarchyFiles));
727 
728  // Finally, lower all operations.
729  auto result = mlir::failableParallelForEachN(
730  &getContext(), 0, modulesToProcess.size(), [&](auto index) {
731  return lowerModuleOperations(modulesToProcess[index], state);
732  });
733 
734  // If any module bodies failed to lower, return early.
735  if (failed(result))
736  return signalPassFailure();
737 
738  // Move binds from inside modules to outside modules.
739  for (auto bind : state.binds) {
740  bind->moveBefore(bind->getParentOfType<hw::HWModuleOp>());
741  }
742 
743  // Fix up fragment attributes.
744  for (auto &[module, fragments] : state.fragments)
745  module->setAttr(emit::getFragmentsAttrName(),
746  ArrayAttr::get(&getContext(), fragments.getArrayRef()));
747 
748  // Finally delete all the old modules.
749  for (auto oldNew : state.oldToNewModuleMap)
750  oldNew.first->erase();
751 
752  if (!state.macroDeclNames.empty()) {
753  ImplicitLocOpBuilder b(UnknownLoc::get(&getContext()), circuit);
754  for (auto name : state.macroDeclNames) {
755  b.create<sv::MacroDeclOp>(name);
756  }
757  }
758 
759  // Emit all the macros and preprocessor gunk at the start of the file.
760  lowerFileHeader(circuit, state);
761 
762  // Now that the modules are moved over, remove the Circuit.
763  circuit.erase();
764 }
765 
766 /// Emit the file header that defines a bunch of macros.
767 void FIRRTLModuleLowering::lowerFileHeader(CircuitOp op,
768  CircuitLoweringState &state) {
769  // Intentionally pass an UnknownLoc here so we don't get line number
770  // comments on the output of this boilerplate in generated Verilog.
771  ImplicitLocOpBuilder b(UnknownLoc::get(&getContext()), op);
772 
773  // Helper function to emit a "#ifdef guard" with a `define in the then and
774  // optionally in the else branch.
775  auto emitGuardedDefine = [&](StringRef guard, StringRef defName,
776  StringRef defineTrue = "",
777  StringRef defineFalse = StringRef()) {
778  if (!defineFalse.data()) {
779  assert(defineTrue.data() && "didn't define anything");
780  b.create<sv::IfDefOp>(
781  guard, [&]() { b.create<sv::MacroDefOp>(defName, defineTrue); });
782  } else {
783  b.create<sv::IfDefOp>(
784  guard,
785  [&]() {
786  if (defineTrue.data())
787  b.create<sv::MacroDefOp>(defName, defineTrue);
788  },
789  [&]() { b.create<sv::MacroDefOp>(defName, defineFalse); });
790  }
791  };
792 
793  // Helper function to emit #ifndef guard.
794  auto emitGuard = [&](const char *guard, llvm::function_ref<void(void)> body) {
795  b.create<sv::IfDefOp>(
796  guard, []() {}, body);
797  };
798 
799  if (state.usedPrintfCond) {
800  b.create<sv::MacroDeclOp>("PRINTF_COND");
801  b.create<sv::MacroDeclOp>("PRINTF_COND_");
802  b.create<emit::FragmentOp>("PRINTF_COND_FRAGMENT", [&] {
803  b.create<sv::VerbatimOp>(
804  "\n// Users can define 'PRINTF_COND' to add an extra gate to "
805  "prints.");
806  emitGuard("PRINTF_COND_", [&]() {
807  emitGuardedDefine("PRINTF_COND", "PRINTF_COND_", "(`PRINTF_COND)", "1");
808  });
809  });
810  }
811 
812  if (state.usedAssertVerboseCond) {
813  b.create<sv::MacroDeclOp>("ASSERT_VERBOSE_COND");
814  b.create<sv::MacroDeclOp>("ASSERT_VERBOSE_COND_");
815  b.create<emit::FragmentOp>("ASSERT_VERBOSE_COND_FRAGMENT", [&] {
816  b.create<sv::VerbatimOp>(
817  "\n// Users can define 'ASSERT_VERBOSE_COND' to add an extra "
818  "gate to assert error printing.");
819  emitGuard("ASSERT_VERBOSE_COND_", [&]() {
820  emitGuardedDefine("ASSERT_VERBOSE_COND", "ASSERT_VERBOSE_COND_",
821  "(`ASSERT_VERBOSE_COND)", "1");
822  });
823  });
824  }
825 
826  if (state.usedStopCond) {
827  b.create<sv::MacroDeclOp>("STOP_COND");
828  b.create<sv::MacroDeclOp>("STOP_COND_");
829  b.create<emit::FragmentOp>("STOP_COND_FRAGMENT", [&] {
830  b.create<sv::VerbatimOp>(
831  "\n// Users can define 'STOP_COND' to add an extra gate "
832  "to stop conditions.");
833  emitGuard("STOP_COND_", [&]() {
834  emitGuardedDefine("STOP_COND", "STOP_COND_", "(`STOP_COND)", "1");
835  });
836  });
837  }
838 }
839 
840 LogicalResult
841 FIRRTLModuleLowering::lowerPorts(ArrayRef<PortInfo> firrtlPorts,
842  SmallVectorImpl<hw::PortInfo> &ports,
843  Operation *moduleOp, StringRef moduleName,
844  CircuitLoweringState &loweringState) {
845  ports.reserve(firrtlPorts.size());
846  size_t numArgs = 0;
847  size_t numResults = 0;
848  for (auto e : llvm::enumerate(firrtlPorts)) {
849  PortInfo firrtlPort = e.value();
850  size_t portNo = e.index();
851  hw::PortInfo hwPort;
852  hwPort.name = firrtlPort.name;
853  hwPort.type = loweringState.lowerType(firrtlPort.type, firrtlPort.loc);
854  if (firrtlPort.sym)
855  if (firrtlPort.sym.size() > 1 ||
856  (firrtlPort.sym.size() == 1 && !firrtlPort.sym.getSymName()))
857  return emitError(firrtlPort.loc)
858  << "cannot lower aggregate port " << firrtlPort.name
859  << " with field sensitive symbols, HW dialect does not support "
860  "per field symbols yet.";
861  hwPort.setSym(firrtlPort.sym, moduleOp->getContext());
862  bool hadDontTouch = firrtlPort.annotations.removeDontTouch();
863  if (hadDontTouch && !hwPort.getSym()) {
864  if (hwPort.type.isInteger(0)) {
865  if (enableAnnotationWarning) {
866  mlir::emitWarning(firrtlPort.loc)
867  << "zero width port " << hwPort.name
868  << " has dontTouch annotation, removing anyway";
869  }
870  continue;
871  }
872 
873  hwPort.setSym(
875  moduleOp->getContext(),
876  Twine("__") + moduleName + Twine("__DONTTOUCH__") +
877  Twine(portNo) + Twine("__") + firrtlPort.name.strref())),
878  moduleOp->getContext());
879  }
880 
881  // We can't lower all types, so make sure to cleanly reject them.
882  if (!hwPort.type) {
883  moduleOp->emitError("cannot lower this port type to HW");
884  return failure();
885  }
886 
887  // If this is a zero bit port, just drop it. It doesn't matter if it is
888  // input, output, or inout. We don't want these at the HW level.
889  if (hwPort.type.isInteger(0)) {
890  auto sym = hwPort.getSym();
891  if (sym && !sym.empty()) {
892  return mlir::emitError(firrtlPort.loc)
893  << "zero width port " << hwPort.name
894  << " is referenced by name [" << sym
895  << "] (e.g. in an XMR) but must be removed";
896  }
897  continue;
898  }
899 
900  // Figure out the direction of the port.
901  if (firrtlPort.isOutput()) {
903  hwPort.argNum = numResults++;
904  } else if (firrtlPort.isInput()) {
906  hwPort.argNum = numArgs++;
907  } else {
908  // If the port is an inout bundle or contains an analog type, then it is
909  // implicitly inout.
910  hwPort.type = hw::InOutType::get(hwPort.type);
912  hwPort.argNum = numArgs++;
913  }
914  hwPort.loc = firrtlPort.loc;
915  ports.push_back(hwPort);
916  loweringState.processRemainingAnnotations(moduleOp, firrtlPort.annotations);
917  }
918  return success();
919 }
920 
921 /// Map the parameter specifier on the specified extmodule into the HWModule
922 /// representation for parameters. If `ignoreValues` is true, all the values
923 /// are dropped.
924 static ArrayAttr getHWParameters(FExtModuleOp module, bool ignoreValues) {
925  auto params = llvm::map_range(module.getParameters(), [](Attribute a) {
926  return cast<ParamDeclAttr>(a);
927  });
928  if (params.empty())
929  return {};
930 
931  Builder builder(module);
932 
933  // Map the attributes over from firrtl attributes to HW attributes
934  // directly. MLIR's DictionaryAttr always stores keys in the dictionary
935  // in sorted order which is nicely stable.
936  SmallVector<Attribute> newParams;
937  for (const ParamDeclAttr &entry : params) {
938  auto name = entry.getName();
939  auto type = entry.getType();
940  auto value = ignoreValues ? Attribute() : entry.getValue();
941  auto paramAttr =
942  hw::ParamDeclAttr::get(builder.getContext(), name, type, value);
943  newParams.push_back(paramAttr);
944  }
945  return builder.getArrayAttr(newParams);
946 }
947 
948 bool FIRRTLModuleLowering::handleForceNameAnnos(
949  FModuleLike oldModule, AnnotationSet &annos,
950  CircuitLoweringState &loweringState) {
951  bool failed = false;
952  // Remove ForceNameAnnotations by generating verilogNames on instances.
953  annos.removeAnnotations([&](Annotation anno) {
954  if (!anno.isClass(forceNameAnnoClass))
955  return false;
956 
957  auto sym = anno.getMember<FlatSymbolRefAttr>("circt.nonlocal");
958  // This must be a non-local annotation due to how the Chisel API is
959  // implemented.
960  //
961  // TODO: handle this in some sensible way based on what the SFC does with
962  // a local annotation.
963  if (!sym) {
964  auto diag = oldModule.emitOpError()
965  << "contains a '" << forceNameAnnoClass
966  << "' that is not a non-local annotation";
967  diag.attachNote() << "the erroneous annotation is '" << anno.getDict()
968  << "'\n";
969  failed = true;
970  return false;
971  }
972 
973  auto nla = loweringState.nlaTable->getNLA(sym.getAttr());
974  // The non-local anchor must exist.
975  //
976  // TODO: handle this with annotation verification.
977  if (!nla) {
978  auto diag = oldModule.emitOpError()
979  << "contains a '" << forceNameAnnoClass
980  << "' whose non-local symbol, '" << sym
981  << "' does not exist in the circuit";
982  diag.attachNote() << "the erroneous annotation is '" << anno.getDict();
983  failed = true;
984  return false;
985  }
986 
987  // Add the forced name to global state (keyed by a pseudo-inner name ref).
988  // Error out if this key is alredy in use.
989  //
990  // TODO: this error behavior can be relaxed to always overwrite with the
991  // new forced name (the bug-compatible behavior of the Chisel
992  // implementation) or fixed to duplicate modules such that the naming can
993  // be applied.
994  auto inst =
995  cast<hw::InnerRefAttr>(nla.getNamepath().getValue().take_back(2)[0]);
996  auto inserted = loweringState.instanceForceNames.insert(
997  {{inst.getModule(), inst.getName()}, anno.getMember("name")});
998  if (!inserted.second &&
999  (anno.getMember("name") != (inserted.first->second))) {
1000  auto diag = oldModule.emitError()
1001  << "contained multiple '" << forceNameAnnoClass
1002  << "' with different names: " << inserted.first->second
1003  << " was not " << anno.getMember("name");
1004  diag.attachNote() << "the erroneous annotation is '" << anno.getDict()
1005  << "'";
1006  failed = true;
1007  return false;
1008  }
1009  return true;
1010  });
1011  return failed;
1012 }
1013 
1015 FIRRTLModuleLowering::lowerExtModule(FExtModuleOp oldModule,
1016  Block *topLevelModule,
1017  CircuitLoweringState &loweringState) {
1018  // Map the ports over, lowering their types as we go.
1019  SmallVector<PortInfo> firrtlPorts = oldModule.getPorts();
1020  SmallVector<hw::PortInfo, 8> ports;
1021  if (failed(lowerPorts(firrtlPorts, ports, oldModule, oldModule.getName(),
1022  loweringState)))
1023  return {};
1024 
1025  StringRef verilogName;
1026  if (auto defName = oldModule.getDefname())
1027  verilogName = defName.value();
1028 
1029  // Build the new hw.module op.
1030  auto builder = OpBuilder::atBlockEnd(topLevelModule);
1031  auto nameAttr = builder.getStringAttr(oldModule.getName());
1032  // Map over parameters if present. Drop all values as we do so, so there are
1033  // no known default values in the extmodule. This ensures that the
1034  // hw.instance will print all the parameters when generating verilog.
1035  auto parameters = getHWParameters(oldModule, /*ignoreValues=*/true);
1036  auto newModule = builder.create<hw::HWModuleExternOp>(
1037  oldModule.getLoc(), nameAttr, ports, verilogName, parameters);
1038  SymbolTable::setSymbolVisibility(newModule,
1039  SymbolTable::getSymbolVisibility(oldModule));
1040 
1041  bool hasOutputPort =
1042  llvm::any_of(firrtlPorts, [&](auto p) { return p.isOutput(); });
1043  if (!hasOutputPort &&
1045  loweringState.isInDUT(oldModule))
1046  newModule->setAttr("firrtl.extract.cover.extra", builder.getUnitAttr());
1047 
1048  AnnotationSet annos(oldModule);
1049  if (handleForceNameAnnos(oldModule, annos, loweringState))
1050  return {};
1051 
1052  loweringState.processRemainingAnnotations(oldModule, annos);
1053  return newModule;
1054 }
1055 
1057 FIRRTLModuleLowering::lowerMemModule(FMemModuleOp oldModule,
1058  Block *topLevelModule,
1059  CircuitLoweringState &loweringState) {
1060  // Map the ports over, lowering their types as we go.
1061  SmallVector<PortInfo> firrtlPorts = oldModule.getPorts();
1062  SmallVector<hw::PortInfo, 8> ports;
1063  if (failed(lowerPorts(firrtlPorts, ports, oldModule, oldModule.getName(),
1064  loweringState)))
1065  return {};
1066 
1067  // Build the new hw.module op.
1068  auto builder = OpBuilder::atBlockEnd(topLevelModule);
1069  auto newModule = builder.create<hw::HWModuleExternOp>(
1070  oldModule.getLoc(), oldModule.getModuleNameAttr(), ports,
1071  oldModule.getModuleNameAttr());
1072  loweringState.processRemainingAnnotations(oldModule,
1073  AnnotationSet(oldModule));
1074  return newModule;
1075 }
1076 
1077 /// Run on each firrtl.module, creating a basic hw.module for the firrtl module.
1079 FIRRTLModuleLowering::lowerModule(FModuleOp oldModule, Block *topLevelModule,
1080  CircuitLoweringState &loweringState) {
1081  // Map the ports over, lowering their types as we go.
1082  SmallVector<PortInfo> firrtlPorts = oldModule.getPorts();
1083  SmallVector<hw::PortInfo, 8> ports;
1084  if (failed(lowerPorts(firrtlPorts, ports, oldModule, oldModule.getName(),
1085  loweringState)))
1086  return {};
1087 
1088  // Build the new hw.module op.
1089  auto builder = OpBuilder::atBlockEnd(topLevelModule);
1090  auto nameAttr = builder.getStringAttr(oldModule.getName());
1091  auto newModule =
1092  builder.create<hw::HWModuleOp>(oldModule.getLoc(), nameAttr, ports);
1093 
1094  if (auto comment = oldModule->getAttrOfType<StringAttr>("comment"))
1095  newModule.setCommentAttr(comment);
1096 
1097  // Copy over any attributes which are not required for FModuleOp.
1098  SmallVector<StringRef, 12> attrNames = {
1099  "annotations", "convention", "layers",
1100  "portNames", "sym_name", "portDirections",
1101  "portTypes", "portAnnotations", "portSyms",
1102  "portLocations", "parameters", SymbolTable::getVisibilityAttrName()};
1103 
1104  DenseSet<StringRef> attrSet(attrNames.begin(), attrNames.end());
1105  SmallVector<NamedAttribute> newAttrs(newModule->getAttrs());
1106  for (auto i :
1107  llvm::make_filter_range(oldModule->getAttrs(), [&](auto namedAttr) {
1108  return !attrSet.count(namedAttr.getName()) &&
1109  !newModule->getAttrDictionary().contains(namedAttr.getName());
1110  }))
1111  newAttrs.push_back(i);
1112 
1113  newModule->setAttrs(newAttrs);
1114 
1115  // If the circuit has an entry point, set all other modules private.
1116  // Otherwise, mark all modules as public.
1117  SymbolTable::setSymbolVisibility(newModule,
1118  SymbolTable::getSymbolVisibility(oldModule));
1119 
1120  // Transform module annotations
1121  AnnotationSet annos(oldModule);
1122 
1124  newModule->setAttr("firrtl.extract.cover.extra", builder.getUnitAttr());
1125 
1126  // If this is in the test harness, make sure it goes to the test directory.
1127  // Do not update output file information if it is already present.
1128  if (auto testBenchDir = loweringState.getTestBenchDirectory())
1129  if (loweringState.isInTestHarness(oldModule)) {
1130  if (!newModule->hasAttr("output_file"))
1131  newModule->setAttr("output_file", testBenchDir);
1132  newModule->setAttr("firrtl.extract.do_not_extract",
1133  builder.getUnitAttr());
1134  newModule.setCommentAttr(
1135  builder.getStringAttr("VCS coverage exclude_file"));
1136  }
1137 
1138  if (handleForceNameAnnos(oldModule, annos, loweringState))
1139  return {};
1140 
1141  loweringState.processRemainingAnnotations(oldModule, annos);
1142  return newModule;
1143 }
1144 
1145 /// Given a value of analog type, check to see the only use of it is an
1146 /// attach. If so, remove the attach and return the value being attached to
1147 /// it, converted to an HW inout type. If this isn't a situation we can
1148 /// handle, just return null.
1149 static Value tryEliminatingAttachesToAnalogValue(Value value,
1150  Operation *insertPoint) {
1151  if (!value.hasOneUse())
1152  return {};
1153 
1154  auto attach = dyn_cast<AttachOp>(*value.user_begin());
1155  if (!attach || attach.getNumOperands() != 2)
1156  return {};
1157 
1158  // Don't optimize zero bit analogs.
1159  auto loweredType = lowerType(value.getType());
1160  if (loweredType.isInteger(0))
1161  return {};
1162 
1163  // Check to see if the attached value dominates the insertion point. If
1164  // not, just fail.
1165  auto attachedValue = attach.getOperand(attach.getOperand(0) == value);
1166  auto *op = attachedValue.getDefiningOp();
1167  if (op && op->getBlock() == insertPoint->getBlock() &&
1168  !op->isBeforeInBlock(insertPoint))
1169  return {};
1170 
1171  attach.erase();
1172 
1173  ImplicitLocOpBuilder builder(insertPoint->getLoc(), insertPoint);
1174  return castFromFIRRTLType(attachedValue, hw::InOutType::get(loweredType),
1175  builder);
1176 }
1177 
1178 /// Given a value of flip type, check to see if all of the uses of it are
1179 /// connects. If so, remove the connects and return the value being connected
1180 /// to it, converted to an HW type. If this isn't a situation we can handle,
1181 /// just return null.
1182 ///
1183 /// This can happen when there are no connects to the value. The 'mergePoint'
1184 /// location is where a 'hw.merge' operation should be inserted if needed.
1185 static Value
1186 tryEliminatingConnectsToValue(Value flipValue, Operation *insertPoint,
1187  CircuitLoweringState &loweringState) {
1188  // Handle analog's separately.
1189  if (type_isa<AnalogType>(flipValue.getType()))
1190  return tryEliminatingAttachesToAnalogValue(flipValue, insertPoint);
1191 
1192  Operation *connectOp = nullptr;
1193  for (auto &use : flipValue.getUses()) {
1194  // We only know how to deal with connects where this value is the
1195  // destination.
1196  if (use.getOperandNumber() != 0)
1197  return {};
1198  if (!isa<ConnectOp, MatchingConnectOp>(use.getOwner()))
1199  return {};
1200 
1201  // We only support things with a single connect.
1202  if (connectOp)
1203  return {};
1204  connectOp = use.getOwner();
1205  }
1206 
1207  // We don't have an HW equivalent of "poison" so just don't special case
1208  // the case where there are no connects other uses of an output.
1209  if (!connectOp)
1210  return {}; // TODO: Emit an sv.constant here since it is unconnected.
1211 
1212  // Don't special case zero-bit results.
1213  auto loweredType =
1214  loweringState.lowerType(flipValue.getType(), flipValue.getLoc());
1215  if (loweredType.isInteger(0))
1216  return {};
1217 
1218  // Convert each connect into an extended version of its operand being
1219  // output.
1220  ImplicitLocOpBuilder builder(insertPoint->getLoc(), insertPoint);
1221 
1222  auto connectSrc = connectOp->getOperand(1);
1223 
1224  // Directly forward foreign types.
1225  if (!isa<FIRRTLType>(connectSrc.getType())) {
1226  connectOp->erase();
1227  return connectSrc;
1228  }
1229 
1230  // Convert fliped sources to passive sources.
1231  if (!type_cast<FIRRTLBaseType>(connectSrc.getType()).isPassive())
1232  connectSrc = builder
1233  .create<mlir::UnrealizedConversionCastOp>(
1234  type_cast<FIRRTLBaseType>(connectSrc.getType())
1235  .getPassiveType(),
1236  connectSrc)
1237  .getResult(0);
1238 
1239  // We know it must be the destination operand due to the types, but the
1240  // source may not match the destination width.
1241  auto destTy = type_cast<FIRRTLBaseType>(flipValue.getType()).getPassiveType();
1242 
1243  if (destTy != connectSrc.getType() &&
1244  (isa<BaseTypeAliasType>(connectSrc.getType()) ||
1245  isa<BaseTypeAliasType>(destTy))) {
1246  connectSrc =
1247  builder.createOrFold<BitCastOp>(flipValue.getType(), connectSrc);
1248  }
1249  if (!destTy.isGround()) {
1250  // If types are not ground type and they don't match, we give up.
1251  if (destTy != type_cast<FIRRTLType>(connectSrc.getType()))
1252  return {};
1253  } else if (destTy.getBitWidthOrSentinel() !=
1254  type_cast<FIRRTLBaseType>(connectSrc.getType())
1255  .getBitWidthOrSentinel()) {
1256  // The only type mismatchs we care about is due to integer width
1257  // differences.
1258  auto destWidth = destTy.getBitWidthOrSentinel();
1259  assert(destWidth != -1 && "must know integer widths");
1260  connectSrc = builder.createOrFold<PadPrimOp>(destTy, connectSrc, destWidth);
1261  }
1262 
1263  // Remove the connect and use its source as the value for the output.
1264  connectOp->erase();
1265 
1266  // Convert from FIRRTL type to builtin type.
1267  return castFromFIRRTLType(connectSrc, loweredType, builder);
1268 }
1269 
1270 static SmallVector<SubfieldOp> getAllFieldAccesses(Value structValue,
1271  StringRef field) {
1272  SmallVector<SubfieldOp> accesses;
1273  for (auto *op : structValue.getUsers()) {
1274  assert(isa<SubfieldOp>(op));
1275  auto fieldAccess = cast<SubfieldOp>(op);
1276  auto elemIndex =
1277  fieldAccess.getInput().getType().base().getElementIndex(field);
1278  if (elemIndex && *elemIndex == fieldAccess.getFieldIndex())
1279  accesses.push_back(fieldAccess);
1280  }
1281  return accesses;
1282 }
1283 
1284 /// Now that we have the operations for the hw.module's corresponding to the
1285 /// firrtl.module's, we can go through and move the bodies over, updating the
1286 /// ports and output op.
1287 LogicalResult FIRRTLModuleLowering::lowerModulePortsAndMoveBody(
1288  FModuleOp oldModule, hw::HWModuleOp newModule,
1289  CircuitLoweringState &loweringState) {
1290  ImplicitLocOpBuilder bodyBuilder(oldModule.getLoc(), newModule.getBody());
1291 
1292  // Use a placeholder instruction be a cursor that indicates where we want to
1293  // move the new function body to. This is important because we insert some
1294  // ops at the start of the function and some at the end, and the body is
1295  // currently empty to avoid iterator invalidation.
1296  auto cursor = bodyBuilder.create<hw::ConstantOp>(APInt(1, 1));
1297  bodyBuilder.setInsertionPoint(cursor);
1298 
1299  // Insert argument casts, and re-vector users in the old body to use them.
1300  SmallVector<PortInfo> firrtlPorts = oldModule.getPorts();
1301  assert(oldModule.getBody().getNumArguments() == firrtlPorts.size() &&
1302  "port count mismatch");
1303 
1304  SmallVector<Value, 4> outputs;
1305 
1306  // This is the terminator in the new module.
1307  auto outputOp = newModule.getBodyBlock()->getTerminator();
1308  ImplicitLocOpBuilder outputBuilder(oldModule.getLoc(), outputOp);
1309 
1310  unsigned nextHWInputArg = 0;
1311  int hwPortIndex = -1;
1312  for (auto [firrtlPortIndex, port] : llvm::enumerate(firrtlPorts)) {
1313  // Inputs and outputs are both modeled as arguments in the FIRRTL level.
1314  auto oldArg = oldModule.getBody().getArgument(firrtlPortIndex);
1315 
1316  bool isZeroWidth =
1317  type_isa<FIRRTLBaseType>(port.type) &&
1318  type_cast<FIRRTLBaseType>(port.type).getBitWidthOrSentinel() == 0;
1319  if (!isZeroWidth)
1320  ++hwPortIndex;
1321 
1322  if (!port.isOutput() && !isZeroWidth) {
1323  // Inputs and InOuts are modeled as arguments in the result, so we can
1324  // just map them over. We model zero bit outputs as inouts.
1325  Value newArg = newModule.getBody().getArgument(nextHWInputArg++);
1326 
1327  // Cast the argument to the old type, reintroducing sign information in
1328  // the hw.module body.
1329  newArg = castToFIRRTLType(newArg, oldArg.getType(), bodyBuilder);
1330  // Switch all uses of the old operands to the new ones.
1331  oldArg.replaceAllUsesWith(newArg);
1332  continue;
1333  }
1334 
1335  // We lower zero width inout and outputs to a wire that isn't connected to
1336  // anything outside the module. Inputs are lowered to zero.
1337  if (isZeroWidth && port.isInput()) {
1338  Value newArg = bodyBuilder
1339  .create<WireOp>(port.type, "." + port.getName().str() +
1340  ".0width_input")
1341  .getResult();
1342  oldArg.replaceAllUsesWith(newArg);
1343  continue;
1344  }
1345 
1346  if (auto value =
1347  tryEliminatingConnectsToValue(oldArg, outputOp, loweringState)) {
1348  // If we were able to find the value being connected to the output,
1349  // directly use it!
1350  outputs.push_back(value);
1351  assert(oldArg.use_empty() && "should have removed all uses of oldArg");
1352  continue;
1353  }
1354 
1355  // Outputs need a temporary wire so they can be connect'd to, which we
1356  // then return.
1357  auto newArg = bodyBuilder.create<WireOp>(
1358  port.type, "." + port.getName().str() + ".output");
1359 
1360  // Switch all uses of the old operands to the new ones.
1361  oldArg.replaceAllUsesWith(newArg.getResult());
1362 
1363  // Don't output zero bit results or inouts.
1364  auto resultHWType = loweringState.lowerType(port.type, port.loc);
1365  if (!resultHWType.isInteger(0)) {
1366  auto output =
1367  castFromFIRRTLType(newArg.getResult(), resultHWType, outputBuilder);
1368  outputs.push_back(output);
1369 
1370  // If output port has symbol, move it to this wire.
1371  if (auto sym = newModule.getPort(hwPortIndex).getSym()) {
1372  newArg.setInnerSymAttr(sym);
1373  newModule.setPortSymbolAttr(hwPortIndex, {});
1374  }
1375  }
1376  }
1377 
1378  // Update the hw.output terminator with the list of outputs we have.
1379  outputOp->setOperands(outputs);
1380 
1381  // Finally splice the body over, don't move the old terminator over though.
1382  auto &oldBlockInstList = oldModule.getBodyBlock()->getOperations();
1383  auto &newBlockInstList = newModule.getBodyBlock()->getOperations();
1384  newBlockInstList.splice(Block::iterator(cursor), oldBlockInstList,
1385  oldBlockInstList.begin(), oldBlockInstList.end());
1386 
1387  // We are done with our cursor op.
1388  cursor.erase();
1389 
1390  return success();
1391 }
1392 
1393 //===----------------------------------------------------------------------===//
1394 // Module Body Lowering Pass
1395 //===----------------------------------------------------------------------===//
1396 
1397 namespace {
1398 
1399 struct FIRRTLLowering : public FIRRTLVisitor<FIRRTLLowering, LogicalResult> {
1400 
1401  FIRRTLLowering(hw::HWModuleOp module, CircuitLoweringState &circuitState)
1402  : theModule(module), circuitState(circuitState),
1403  builder(module.getLoc(), module.getContext()), moduleNamespace(module),
1404  backedgeBuilder(builder, module.getLoc()) {}
1405 
1406  LogicalResult run();
1407 
1408  // Helpers.
1409  Value getOrCreateClockConstant(seq::ClockConst clock);
1410  Value getOrCreateIntConstant(const APInt &value);
1411  Value getOrCreateIntConstant(unsigned numBits, uint64_t val,
1412  bool isSigned = false) {
1413  return getOrCreateIntConstant(APInt(numBits, val, isSigned));
1414  }
1415  Attribute getOrCreateAggregateConstantAttribute(Attribute value, Type type);
1416  Value getOrCreateXConstant(unsigned numBits);
1417  Value getOrCreateZConstant(Type type);
1418  Value getPossiblyInoutLoweredValue(Value value);
1419  Value getLoweredValue(Value value);
1420  Value getLoweredNonClockValue(Value value);
1421  Value getLoweredAndExtendedValue(Value value, Type destType);
1422  Value getLoweredAndExtOrTruncValue(Value value, Type destType);
1423  Value getLoweredFmtOperand(Value operand);
1424  LogicalResult setLowering(Value orig, Value result);
1425  LogicalResult setPossiblyFoldedLowering(Value orig, Value result);
1426  template <typename ResultOpType, typename... CtorArgTypes>
1427  LogicalResult setLoweringTo(Operation *orig, CtorArgTypes... args);
1428  template <typename ResultOpType, typename... CtorArgTypes>
1429  LogicalResult setLoweringToLTL(Operation *orig, CtorArgTypes... args);
1430  Backedge createBackedge(Location loc, Type type);
1431  Backedge createBackedge(Value orig, Type type);
1432  bool updateIfBackedge(Value dest, Value src);
1433 
1434  /// Returns true if the lowered operation requires an inner symbol on it.
1435  bool requiresInnerSymbol(hw::InnerSymbolOpInterface op) {
1437  return true;
1438  if (!hasDroppableName(op))
1439  return true;
1440  if (auto forceable = dyn_cast<Forceable>(op.getOperation()))
1441  if (forceable.isForceable())
1442  return true;
1443  return false;
1444  }
1445 
1446  /// Gets the lowered InnerSymAttr of this operation. If the operation is
1447  /// DontTouched, has a non-droppable name, or is forceable, then we will
1448  /// ensure that the InnerSymAttr has a symbol with fieldID zero.
1449  hw::InnerSymAttr lowerInnerSymbol(hw::InnerSymbolOpInterface op) {
1450  auto attr = op.getInnerSymAttr();
1451  // TODO: we should be checking for symbol collisions here and renaming as
1452  // neccessary. As well, we should record the renamings in a map so that we
1453  // can update any InnerRefAttrs that we find.
1454  if (requiresInnerSymbol(op))
1455  std::tie(attr, std::ignore) = getOrAddInnerSym(
1456  op.getContext(), attr, 0,
1457  [&]() -> hw::InnerSymbolNamespace & { return moduleNamespace; });
1458  return attr;
1459  }
1460 
1461  void runWithInsertionPointAtEndOfBlock(std::function<void(void)> fn,
1462  Region &region);
1463 
1464  /// Return a read value for the specified inout value, auto-uniquing them.
1465  Value getReadValue(Value v);
1466  /// Return an `i1` value for the specified value, auto-uniqueing them.
1467  Value getNonClockValue(Value v);
1468 
1469  void addToAlwaysBlock(sv::EventControl clockEdge, Value clock,
1470  sv::ResetType resetStyle, sv::EventControl resetEdge,
1471  Value reset, std::function<void(void)> body = {},
1472  std::function<void(void)> resetBody = {});
1473  void addToAlwaysBlock(Value clock, std::function<void(void)> body = {}) {
1474  addToAlwaysBlock(sv::EventControl::AtPosEdge, clock, sv::ResetType(),
1475  sv::EventControl(), Value(), body,
1476  std::function<void(void)>());
1477  }
1478 
1479  LogicalResult emitGuards(Location loc, ArrayRef<Attribute> guards,
1480  std::function<void(void)> emit);
1481  void addToIfDefBlock(StringRef cond, std::function<void(void)> thenCtor,
1482  std::function<void(void)> elseCtor = {});
1483  void addToInitialBlock(std::function<void(void)> body);
1484  void addIfProceduralBlock(Value cond, std::function<void(void)> thenCtor,
1485  std::function<void(void)> elseCtor = {});
1486  Value getExtOrTruncAggregateValue(Value array, FIRRTLBaseType sourceType,
1487  FIRRTLBaseType destType,
1488  bool allowTruncate);
1489  Value createArrayIndexing(Value array, Value index);
1490  Value createValueWithMuxAnnotation(Operation *op, bool isMux2);
1491 
1495 
1496  // Lowering hooks.
1497  enum UnloweredOpResult { AlreadyLowered, NowLowered, LoweringFailure };
1498  UnloweredOpResult handleUnloweredOp(Operation *op);
1499  LogicalResult visitExpr(ConstantOp op);
1500  LogicalResult visitExpr(SpecialConstantOp op);
1501  LogicalResult visitExpr(SubindexOp op);
1502  LogicalResult visitExpr(SubaccessOp op);
1503  LogicalResult visitExpr(SubfieldOp op);
1504  LogicalResult visitExpr(VectorCreateOp op);
1505  LogicalResult visitExpr(BundleCreateOp op);
1506  LogicalResult visitExpr(FEnumCreateOp op);
1507  LogicalResult visitExpr(AggregateConstantOp op);
1508  LogicalResult visitExpr(IsTagOp op);
1509  LogicalResult visitExpr(SubtagOp op);
1510  LogicalResult visitUnhandledOp(Operation *op) { return failure(); }
1511  LogicalResult visitInvalidOp(Operation *op) {
1512  if (auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
1513  return visitUnrealizedConversionCast(castOp);
1514  return failure();
1515  }
1516 
1517  // Declarations.
1518  LogicalResult visitDecl(WireOp op);
1519  LogicalResult visitDecl(NodeOp op);
1520  LogicalResult visitDecl(RegOp op);
1521  LogicalResult visitDecl(RegResetOp op);
1522  LogicalResult visitDecl(MemOp op);
1523  LogicalResult visitDecl(InstanceOp op);
1524  LogicalResult visitDecl(VerbatimWireOp op);
1525 
1526  // Unary Ops.
1527  LogicalResult lowerNoopCast(Operation *op);
1528  LogicalResult visitExpr(AsSIntPrimOp op);
1529  LogicalResult visitExpr(AsUIntPrimOp op);
1530  LogicalResult visitExpr(AsClockPrimOp op);
1531  LogicalResult visitExpr(AsAsyncResetPrimOp op) { return lowerNoopCast(op); }
1532 
1533  LogicalResult visitExpr(HWStructCastOp op);
1534  LogicalResult visitExpr(BitCastOp op);
1535  LogicalResult
1536  visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
1537  LogicalResult visitExpr(CvtPrimOp op);
1538  LogicalResult visitExpr(NotPrimOp op);
1539  LogicalResult visitExpr(NegPrimOp op);
1540  LogicalResult visitExpr(PadPrimOp op);
1541  LogicalResult visitExpr(XorRPrimOp op);
1542  LogicalResult visitExpr(AndRPrimOp op);
1543  LogicalResult visitExpr(OrRPrimOp op);
1544 
1545  // Binary Ops.
1546  template <typename ResultUnsignedOpType,
1547  typename ResultSignedOpType = ResultUnsignedOpType>
1548  LogicalResult lowerBinOp(Operation *op);
1549  template <typename ResultOpType>
1550  LogicalResult lowerBinOpToVariadic(Operation *op);
1551 
1552  template <typename ResultOpType>
1553  LogicalResult lowerElementwiseLogicalOp(Operation *op);
1554 
1555  LogicalResult lowerCmpOp(Operation *op, ICmpPredicate signedOp,
1556  ICmpPredicate unsignedOp);
1557  template <typename SignedOp, typename UnsignedOp>
1558  LogicalResult lowerDivLikeOp(Operation *op);
1559 
1560  LogicalResult visitExpr(CatPrimOp op);
1561 
1562  LogicalResult visitExpr(AndPrimOp op) {
1563  return lowerBinOpToVariadic<comb::AndOp>(op);
1564  }
1565  LogicalResult visitExpr(OrPrimOp op) {
1566  return lowerBinOpToVariadic<comb::OrOp>(op);
1567  }
1568  LogicalResult visitExpr(XorPrimOp op) {
1569  return lowerBinOpToVariadic<comb::XorOp>(op);
1570  }
1571  LogicalResult visitExpr(ElementwiseOrPrimOp op) {
1572  return lowerElementwiseLogicalOp<comb::OrOp>(op);
1573  }
1574  LogicalResult visitExpr(ElementwiseAndPrimOp op) {
1575  return lowerElementwiseLogicalOp<comb::AndOp>(op);
1576  }
1577  LogicalResult visitExpr(ElementwiseXorPrimOp op) {
1578  return lowerElementwiseLogicalOp<comb::XorOp>(op);
1579  }
1580  LogicalResult visitExpr(AddPrimOp op) {
1581  return lowerBinOpToVariadic<comb::AddOp>(op);
1582  }
1583  LogicalResult visitExpr(EQPrimOp op) {
1584  return lowerCmpOp(op, ICmpPredicate::eq, ICmpPredicate::eq);
1585  }
1586  LogicalResult visitExpr(NEQPrimOp op) {
1587  return lowerCmpOp(op, ICmpPredicate::ne, ICmpPredicate::ne);
1588  }
1589  LogicalResult visitExpr(LTPrimOp op) {
1590  return lowerCmpOp(op, ICmpPredicate::slt, ICmpPredicate::ult);
1591  }
1592  LogicalResult visitExpr(LEQPrimOp op) {
1593  return lowerCmpOp(op, ICmpPredicate::sle, ICmpPredicate::ule);
1594  }
1595  LogicalResult visitExpr(GTPrimOp op) {
1596  return lowerCmpOp(op, ICmpPredicate::sgt, ICmpPredicate::ugt);
1597  }
1598  LogicalResult visitExpr(GEQPrimOp op) {
1599  return lowerCmpOp(op, ICmpPredicate::sge, ICmpPredicate::uge);
1600  }
1601 
1602  LogicalResult visitExpr(SubPrimOp op) { return lowerBinOp<comb::SubOp>(op); }
1603  LogicalResult visitExpr(MulPrimOp op) {
1604  return lowerBinOpToVariadic<comb::MulOp>(op);
1605  }
1606  LogicalResult visitExpr(DivPrimOp op) {
1607  return lowerDivLikeOp<comb::DivSOp, comb::DivUOp>(op);
1608  }
1609  LogicalResult visitExpr(RemPrimOp op) {
1610  return lowerDivLikeOp<comb::ModSOp, comb::ModUOp>(op);
1611  }
1612 
1613  // Intrinsic Operations
1614  LogicalResult visitExpr(IsXIntrinsicOp op);
1615  LogicalResult visitExpr(PlusArgsTestIntrinsicOp op);
1616  LogicalResult visitExpr(PlusArgsValueIntrinsicOp op);
1617  LogicalResult visitStmt(FPGAProbeIntrinsicOp op);
1618  LogicalResult visitExpr(ClockInverterIntrinsicOp op);
1619  LogicalResult visitExpr(ClockDividerIntrinsicOp op);
1620  LogicalResult visitExpr(SizeOfIntrinsicOp op);
1621  LogicalResult visitExpr(ClockGateIntrinsicOp op);
1622  LogicalResult visitExpr(LTLAndIntrinsicOp op);
1623  LogicalResult visitExpr(LTLOrIntrinsicOp op);
1624  LogicalResult visitExpr(LTLIntersectIntrinsicOp op);
1625  LogicalResult visitExpr(LTLDelayIntrinsicOp op);
1626  LogicalResult visitExpr(LTLConcatIntrinsicOp op);
1627  LogicalResult visitExpr(LTLRepeatIntrinsicOp op);
1628  LogicalResult visitExpr(LTLGoToRepeatIntrinsicOp op);
1629  LogicalResult visitExpr(LTLNonConsecutiveRepeatIntrinsicOp op);
1630  LogicalResult visitExpr(LTLNotIntrinsicOp op);
1631  LogicalResult visitExpr(LTLImplicationIntrinsicOp op);
1632  LogicalResult visitExpr(LTLUntilIntrinsicOp op);
1633  LogicalResult visitExpr(LTLEventuallyIntrinsicOp op);
1634  LogicalResult visitExpr(LTLClockIntrinsicOp op);
1635 
1636  template <typename TargetOp, typename IntrinsicOp>
1637  LogicalResult lowerVerifIntrinsicOp(IntrinsicOp op);
1638  LogicalResult visitStmt(VerifAssertIntrinsicOp op);
1639  LogicalResult visitStmt(VerifAssumeIntrinsicOp op);
1640  LogicalResult visitStmt(VerifCoverIntrinsicOp op);
1641  LogicalResult visitExpr(HasBeenResetIntrinsicOp op);
1642  LogicalResult visitStmt(UnclockedAssumeIntrinsicOp op);
1643 
1644  // Other Operations
1645  LogicalResult visitExpr(BitsPrimOp op);
1646  LogicalResult visitExpr(InvalidValueOp op);
1647  LogicalResult visitExpr(HeadPrimOp op);
1648  LogicalResult visitExpr(ShlPrimOp op);
1649  LogicalResult visitExpr(ShrPrimOp op);
1650  LogicalResult visitExpr(DShlPrimOp op) {
1651  return lowerDivLikeOp<comb::ShlOp, comb::ShlOp>(op);
1652  }
1653  LogicalResult visitExpr(DShrPrimOp op) {
1654  return lowerDivLikeOp<comb::ShrSOp, comb::ShrUOp>(op);
1655  }
1656  LogicalResult visitExpr(DShlwPrimOp op) {
1657  return lowerDivLikeOp<comb::ShlOp, comb::ShlOp>(op);
1658  }
1659  LogicalResult visitExpr(TailPrimOp op);
1660  LogicalResult visitExpr(MuxPrimOp op);
1661  LogicalResult visitExpr(Mux2CellIntrinsicOp op);
1662  LogicalResult visitExpr(Mux4CellIntrinsicOp op);
1663  LogicalResult visitExpr(MultibitMuxOp op);
1664  LogicalResult visitExpr(VerbatimExprOp op);
1665  LogicalResult visitExpr(XMRRefOp op);
1666  LogicalResult visitExpr(XMRDerefOp op);
1667 
1668  // Statements
1669  LogicalResult lowerVerificationStatement(
1670  Operation *op, StringRef labelPrefix, Value clock, Value predicate,
1671  Value enable, StringAttr messageAttr, ValueRange operands,
1672  StringAttr nameAttr, bool isConcurrent, EventControl eventControl);
1673 
1674  LogicalResult visitStmt(SkipOp op);
1675 
1676  FailureOr<bool> lowerConnect(Value dest, Value srcVal);
1677  LogicalResult visitStmt(ConnectOp op);
1678  LogicalResult visitStmt(MatchingConnectOp op);
1679  LogicalResult visitStmt(ForceOp op);
1680  LogicalResult visitStmt(PrintFOp op);
1681  LogicalResult visitStmt(StopOp op);
1682  LogicalResult visitStmt(AssertOp op);
1683  LogicalResult visitStmt(AssumeOp op);
1684  LogicalResult visitStmt(CoverOp op);
1685  LogicalResult visitStmt(AttachOp op);
1686  LogicalResult visitStmt(RefForceOp op);
1687  LogicalResult visitStmt(RefForceInitialOp op);
1688  LogicalResult visitStmt(RefReleaseOp op);
1689  LogicalResult visitStmt(RefReleaseInitialOp op);
1690 
1691  FailureOr<Value> lowerSubindex(SubindexOp op, Value input);
1692  FailureOr<Value> lowerSubaccess(SubaccessOp op, Value input);
1693  FailureOr<Value> lowerSubfield(SubfieldOp op, Value input);
1694 
1695  LogicalResult fixupLTLOps();
1696 
1697  Type lowerType(Type type) {
1698  return circuitState.lowerType(type, builder.getLoc());
1699  }
1700 
1701 private:
1702  /// The module we're lowering into.
1703  hw::HWModuleOp theModule;
1704 
1705  /// Global state.
1706  CircuitLoweringState &circuitState;
1707 
1708  /// This builder is set to the right location for each visit call.
1709  ImplicitLocOpBuilder builder;
1710 
1711  /// Each value lowered (e.g. operation result) is kept track in this map.
1712  /// The key should have a FIRRTL type, the result will have an HW dialect
1713  /// type.
1714  DenseMap<Value, Value> valueMapping;
1715 
1716  /// Mapping from clock values to corresponding non-clock values converted
1717  /// via a deduped `seq.from_clock` op.
1718  DenseMap<Value, Value> fromClockMapping;
1719 
1720  /// This keeps track of constants that we have created so we can reuse them.
1721  /// This is populated by the getOrCreateIntConstant method.
1722  DenseMap<Attribute, Value> hwConstantMap;
1723  DenseMap<std::pair<Attribute, Type>, Attribute> hwAggregateConstantMap;
1724 
1725  /// This keeps track of constant X that we have created so we can reuse them.
1726  /// This is populated by the getOrCreateXConstant method.
1727  DenseMap<unsigned, Value> hwConstantXMap;
1728  DenseMap<Type, Value> hwConstantZMap;
1729 
1730  /// We auto-unique "ReadInOut" ops from wires and regs, enabling
1731  /// optimizations and CSEs of the read values to be more obvious. This
1732  /// caches a known ReadInOutOp for the given value and is managed by
1733  /// `getReadValue(v)`.
1734  DenseMap<Value, Value> readInOutCreated;
1735 
1736  // We auto-unique graph-level blocks to reduce the amount of generated
1737  // code and ensure that side effects are properly ordered in FIRRTL.
1738  using AlwaysKeyType = std::tuple<Block *, sv::EventControl, Value,
1739  sv::ResetType, sv::EventControl, Value>;
1741  alwaysBlocks;
1744 
1745  /// A namespace that can be used to generate new symbol names that are unique
1746  /// within this module.
1747  hw::InnerSymbolNamespace moduleNamespace;
1748 
1749  /// A backedge builder to directly materialize values during the lowering
1750  /// without requiring temporary wires.
1751  BackedgeBuilder backedgeBuilder;
1752  /// Currently unresolved backedges. More precisely, a mapping from the
1753  /// backedge value to the value it will be replaced with. We use a MapVector
1754  /// so that a combinational cycles of backedges, the one backedge that gets
1755  /// replaced with an undriven wire is consistent.
1756  llvm::MapVector<Value, Value> backedges;
1757 
1758  /// A collection of values generated by the lowering process that may have
1759  /// become obsolete through subsequent parts of the lowering. This covers the
1760  /// values of wires that may be overridden by subsequent connects; or
1761  /// subaccesses that appear only as destination of a connect, and thus gets
1762  /// obsoleted by the connect directly updating the wire or register.
1763  DenseSet<Operation *> maybeUnusedValues;
1764 
1765  void maybeUnused(Operation *op) { maybeUnusedValues.insert(op); }
1766  void maybeUnused(Value value) {
1767  if (auto *op = value.getDefiningOp())
1768  maybeUnused(op);
1769  }
1770 
1771  /// A worklist of LTL operations that don't have their final type yet. The
1772  /// FIRRTL intrinsics for LTL ops all use `uint<1>` types, but the actual LTL
1773  /// ops themselves have more precise `!ltl.sequence` and `!ltl.property`
1774  /// types. After all LTL ops have been lowered, this worklist is used to
1775  /// compute their actual types (re-inferring return types) and push the
1776  /// updated types to their users. This also drops any `hw.wire`s in between
1777  /// the LTL ops, which were necessary to go from the def-before-use FIRRTL
1778  /// dialect to the graph-like HW dialect.
1779  SetVector<Operation *> ltlOpFixupWorklist;
1780 };
1781 } // end anonymous namespace
1782 
1783 LogicalResult FIRRTLModuleLowering::lowerModuleOperations(
1784  hw::HWModuleOp module, CircuitLoweringState &loweringState) {
1785  return FIRRTLLowering(module, loweringState).run();
1786 }
1787 
1788 // This is the main entrypoint for the lowering pass.
1789 LogicalResult FIRRTLLowering::run() {
1790  // FIRRTL FModule is a single block because FIRRTL ops are a DAG. Walk
1791  // through each operation, lowering each in turn if we can, introducing
1792  // casts if we cannot.
1793  auto &body = theModule.getBody();
1794 
1795  SmallVector<Operation *, 16> opsToRemove;
1796 
1797  // Iterate through each operation in the module body, attempting to lower
1798  // each of them. We maintain 'builder' for each invocation.
1799  for (auto &op : body.front().getOperations()) {
1800  builder.setInsertionPoint(&op);
1801  builder.setLoc(op.getLoc());
1802  auto done = succeeded(dispatchVisitor(&op));
1803  circuitState.processRemainingAnnotations(&op, AnnotationSet(&op));
1804  if (done)
1805  opsToRemove.push_back(&op);
1806  else {
1807  switch (handleUnloweredOp(&op)) {
1808  case AlreadyLowered:
1809  break; // Something like hw.output, which is already lowered.
1810  case NowLowered: // Something handleUnloweredOp removed.
1811  opsToRemove.push_back(&op);
1812  break;
1813  case LoweringFailure:
1814  backedgeBuilder.abandon();
1815  return failure();
1816  }
1817  }
1818  }
1819 
1820  // Replace all backedges with uses of their regular values. We process them
1821  // after the module body since the lowering table is too hard to keep up to
1822  // date. Multiple operations may be lowered to the same backedge when values
1823  // are folded, which means we would have to scan the entire lowering table to
1824  // safely replace a backedge.
1825  for (auto &[backedge, value] : backedges) {
1826  SmallVector<Location> driverLocs;
1827  // In the case where we have backedges connected to other backedges, we have
1828  // to find the value that actually drives the group.
1829  while (true) {
1830  // If we find the original backedge we have some undriven logic or
1831  // a combinatorial loop. Bail out and provide information on the nodes.
1832  if (backedge == value) {
1833  Location edgeLoc = backedge.getLoc();
1834  if (driverLocs.empty()) {
1835  mlir::emitError(edgeLoc, "sink does not have a driver");
1836  } else {
1837  auto diag = mlir::emitError(edgeLoc, "sink in combinational loop");
1838  for (auto loc : driverLocs)
1839  diag.attachNote(loc) << "through driver here";
1840  }
1841  backedgeBuilder.abandon();
1842  return failure();
1843  }
1844  // If the value is not another backedge, we have found the driver.
1845  auto it = backedges.find(value);
1846  if (it == backedges.end())
1847  break;
1848  // Find what is driving the next backedge.
1849  driverLocs.push_back(value.getLoc());
1850  value = it->second;
1851  }
1852  if (auto *defOp = backedge.getDefiningOp())
1853  maybeUnusedValues.erase(defOp);
1854  backedge.replaceAllUsesWith(value);
1855  }
1856 
1857  // Now that all of the operations that can be lowered are, remove th
1858  // original values. We know that any lowered operations will be dead (if
1859  // removed in reverse order) at this point - any users of them from
1860  // unremapped operations will be changed to use the newly lowered ops.
1861  hw::ConstantOp zeroI0;
1862  while (!opsToRemove.empty()) {
1863  auto *op = opsToRemove.pop_back_val();
1864 
1865  // We remove zero-width values when lowering FIRRTL ops. We can't remove
1866  // such a value if it escapes to a foreign op. In that case, create an
1867  // `hw.constant 0 : i0` to pass along.
1868  for (auto result : op->getResults()) {
1869  if (!isZeroBitFIRRTLType(result.getType()))
1870  continue;
1871  if (!zeroI0) {
1872  auto builder = OpBuilder::atBlockBegin(&body.front());
1873  zeroI0 = builder.create<hw::ConstantOp>(op->getLoc(),
1874  builder.getIntegerType(0), 0);
1875  maybeUnusedValues.insert(zeroI0);
1876  }
1877  result.replaceAllUsesWith(zeroI0);
1878  }
1879 
1880  if (!op->use_empty()) {
1881  auto d = op->emitOpError(
1882  "still has uses; should remove ops in reverse order of visitation");
1883  SmallPtrSet<Operation *, 2> visited;
1884  for (auto *user : op->getUsers())
1885  if (visited.insert(user).second)
1886  d.attachNote(user->getLoc())
1887  << "used by " << user->getName() << " op";
1888  return d;
1889  }
1890  maybeUnusedValues.erase(op);
1891  op->erase();
1892  }
1893 
1894  // Prune operations that may have become unused throughout the lowering.
1895  while (!maybeUnusedValues.empty()) {
1896  auto it = maybeUnusedValues.begin();
1897  auto *op = *it;
1898  maybeUnusedValues.erase(it);
1899  if (!isOpTriviallyDead(op))
1900  continue;
1901  for (auto operand : op->getOperands())
1902  if (auto *defOp = operand.getDefiningOp())
1903  maybeUnusedValues.insert(defOp);
1904  op->erase();
1905  }
1906 
1907  // Determine the actual types of lowered LTL operations and remove any
1908  // intermediate wires among them.
1909  if (failed(fixupLTLOps()))
1910  return failure();
1911 
1912  return backedgeBuilder.clearOrEmitError();
1913 }
1914 
1915 //===----------------------------------------------------------------------===//
1916 // Helpers
1917 //===----------------------------------------------------------------------===//
1918 
1919 /// Create uniqued constant clocks.
1920 Value FIRRTLLowering::getOrCreateClockConstant(seq::ClockConst clock) {
1921  auto attr = seq::ClockConstAttr::get(theModule.getContext(), clock);
1922 
1923  auto &entry = hwConstantMap[attr];
1924  if (entry)
1925  return entry;
1926 
1927  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
1928  entry = entryBuilder.create<seq::ConstClockOp>(builder.getLoc(), attr);
1929  return entry;
1930 }
1931 
1932 /// Check to see if we've already lowered the specified constant. If so,
1933 /// return it. Otherwise create it and put it in the entry block for reuse.
1934 Value FIRRTLLowering::getOrCreateIntConstant(const APInt &value) {
1935  auto attr = builder.getIntegerAttr(
1936  builder.getIntegerType(value.getBitWidth()), value);
1937 
1938  auto &entry = hwConstantMap[attr];
1939  if (entry)
1940  return entry;
1941 
1942  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
1943  entry = entryBuilder.create<hw::ConstantOp>(builder.getLoc(), attr);
1944  return entry;
1945 }
1946 
1947 /// Check to see if we've already created the specified aggregate constant
1948 /// attribute. If so, return it. Otherwise create it.
1949 Attribute FIRRTLLowering::getOrCreateAggregateConstantAttribute(Attribute value,
1950  Type type) {
1951  // Base case.
1952  if (hw::type_isa<IntegerType>(type))
1953  return builder.getIntegerAttr(type, cast<IntegerAttr>(value).getValue());
1954 
1955  auto cache = hwAggregateConstantMap.lookup({value, type});
1956  if (cache)
1957  return cache;
1958 
1959  // Recursively construct elements.
1960  SmallVector<Attribute> values;
1961  for (auto e : llvm::enumerate(cast<ArrayAttr>(value))) {
1962  Type subType;
1963  if (auto array = hw::type_dyn_cast<hw::ArrayType>(type))
1964  subType = array.getElementType();
1965  else if (auto structType = hw::type_dyn_cast<hw::StructType>(type))
1966  subType = structType.getElements()[e.index()].type;
1967  else
1968  assert(false && "type must be either array or struct");
1969 
1970  values.push_back(getOrCreateAggregateConstantAttribute(e.value(), subType));
1971  }
1972 
1973  // FIRRTL and HW have a different operand ordering for arrays.
1974  if (hw::type_isa<hw::ArrayType>(type))
1975  std::reverse(values.begin(), values.end());
1976 
1977  auto &entry = hwAggregateConstantMap[{value, type}];
1978  entry = builder.getArrayAttr(values);
1979  return entry;
1980 }
1981 
1982 /// Zero bit operands end up looking like failures from getLoweredValue. This
1983 /// helper function invokes the closure specified if the operand was actually
1984 /// zero bit, or returns failure() if it was some other kind of failure.
1985 static LogicalResult handleZeroBit(Value failedOperand,
1986  std::function<LogicalResult()> fn) {
1987  assert(failedOperand && "Should be called on the failed operand");
1988  if (!isZeroBitFIRRTLType(failedOperand.getType()))
1989  return failure();
1990  return fn();
1991 }
1992 
1993 /// Check to see if we've already lowered the specified constant. If so,
1994 /// return it. Otherwise create it and put it in the entry block for reuse.
1995 Value FIRRTLLowering::getOrCreateXConstant(unsigned numBits) {
1996 
1997  auto &entry = hwConstantXMap[numBits];
1998  if (entry)
1999  return entry;
2000 
2001  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
2002  entry = entryBuilder.create<sv::ConstantXOp>(
2003  builder.getLoc(), entryBuilder.getIntegerType(numBits));
2004  return entry;
2005 }
2006 
2007 Value FIRRTLLowering::getOrCreateZConstant(Type type) {
2008  auto &entry = hwConstantZMap[type];
2009  if (!entry) {
2010  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
2011  entry = entryBuilder.create<sv::ConstantZOp>(builder.getLoc(), type);
2012  }
2013  return entry;
2014 }
2015 
2016 /// Return the lowered HW value corresponding to the specified original value.
2017 /// This returns a null value for FIRRTL values that haven't be lowered, e.g.
2018 /// unknown width integers. This returns hw::inout type values if present, it
2019 /// does not implicitly read from them.
2020 Value FIRRTLLowering::getPossiblyInoutLoweredValue(Value value) {
2021  // Block arguments are considered lowered.
2022  if (isa<BlockArgument>(value))
2023  return value;
2024 
2025  // If we lowered this value, then return the lowered value, otherwise fail.
2026  if (auto lowering = valueMapping.lookup(value)) {
2027  assert(!isa<FIRRTLType>(lowering.getType()) &&
2028  "Lowered value should be a non-FIRRTL value");
2029  return lowering;
2030  }
2031  return Value();
2032 }
2033 
2034 /// Return the lowered value corresponding to the specified original value.
2035 /// This returns a null value for FIRRTL values that cannot be lowered, e.g.
2036 /// unknown width integers.
2037 Value FIRRTLLowering::getLoweredValue(Value value) {
2038  auto result = getPossiblyInoutLoweredValue(value);
2039  if (!result)
2040  return result;
2041 
2042  // If we got an inout value, implicitly read it. FIRRTL allows direct use
2043  // of wires and other things that lower to inout type.
2044  if (isa<hw::InOutType>(result.getType()))
2045  return getReadValue(result);
2046 
2047  return result;
2048 }
2049 
2050 /// Return the lowered value, converting `seq.clock` to `i1.
2051 Value FIRRTLLowering::getLoweredNonClockValue(Value value) {
2052  auto result = getLoweredValue(value);
2053  if (!result)
2054  return result;
2055 
2056  if (hw::type_isa<seq::ClockType>(result.getType()))
2057  return getNonClockValue(result);
2058 
2059  return result;
2060 }
2061 
2062 /// Return the lowered aggregate value whose type is converted into
2063 /// `destType`. We have to care about the extension/truncation/signedness of
2064 /// each element.
2065 Value FIRRTLLowering::getExtOrTruncAggregateValue(Value array,
2066  FIRRTLBaseType sourceType,
2067  FIRRTLBaseType destType,
2068  bool allowTruncate) {
2069  SmallVector<Value> resultBuffer;
2070 
2071  // Helper function to cast each element of array to dest type.
2072  auto cast = [&](Value value, FIRRTLBaseType sourceType,
2073  FIRRTLBaseType destType) {
2074  auto srcWidth = firrtl::type_cast<IntType>(sourceType).getWidthOrSentinel();
2075  auto destWidth = firrtl::type_cast<IntType>(destType).getWidthOrSentinel();
2076  auto resultType = builder.getIntegerType(destWidth);
2077 
2078  if (srcWidth == destWidth)
2079  return value;
2080 
2081  if (srcWidth > destWidth) {
2082  if (allowTruncate)
2083  return builder.createOrFold<comb::ExtractOp>(resultType, value, 0);
2084 
2085  builder.emitError("operand should not be a truncation");
2086  return Value();
2087  }
2088 
2089  if (firrtl::type_cast<IntType>(sourceType).isSigned())
2090  return comb::createOrFoldSExt(value, resultType, builder);
2091  auto zero = getOrCreateIntConstant(destWidth - srcWidth, 0);
2092  return builder.createOrFold<comb::ConcatOp>(zero, value);
2093  };
2094 
2095  // This recursive function constructs the output array.
2096  std::function<LogicalResult(Value, FIRRTLBaseType, FIRRTLBaseType)> recurse =
2097  [&](Value src, FIRRTLBaseType srcType,
2098  FIRRTLBaseType destType) -> LogicalResult {
2099  return TypeSwitch<FIRRTLBaseType, LogicalResult>(srcType)
2100  .Case<FVectorType>([&](auto srcVectorType) {
2101  auto destVectorType = firrtl::type_cast<FVectorType>(destType);
2102  unsigned size = resultBuffer.size();
2103  unsigned indexWidth =
2104  getBitWidthFromVectorSize(srcVectorType.getNumElements());
2105  for (size_t i = 0, e = std::min(srcVectorType.getNumElements(),
2106  destVectorType.getNumElements());
2107  i != e; ++i) {
2108  auto iIdx = getOrCreateIntConstant(indexWidth, i);
2109  auto arrayIndex = builder.create<hw::ArrayGetOp>(src, iIdx);
2110  if (failed(recurse(arrayIndex, srcVectorType.getElementType(),
2111  destVectorType.getElementType())))
2112  return failure();
2113  }
2114  SmallVector<Value> temp(resultBuffer.begin() + size,
2115  resultBuffer.end());
2116  auto array = builder.createOrFold<hw::ArrayCreateOp>(temp);
2117  resultBuffer.resize(size);
2118  resultBuffer.push_back(array);
2119  return success();
2120  })
2121  .Case<BundleType>([&](BundleType srcStructType) {
2122  auto destStructType = firrtl::type_cast<BundleType>(destType);
2123  unsigned size = resultBuffer.size();
2124 
2125  // TODO: We don't support partial connects for bundles for now.
2126  if (destStructType.getNumElements() != srcStructType.getNumElements())
2127  return failure();
2128 
2129  for (auto elem : llvm::enumerate(destStructType)) {
2130  auto structExtract =
2131  builder.create<hw::StructExtractOp>(src, elem.value().name);
2132  if (failed(recurse(structExtract,
2133  srcStructType.getElementType(elem.index()),
2134  destStructType.getElementType(elem.index()))))
2135  return failure();
2136  }
2137  SmallVector<Value> temp(resultBuffer.begin() + size,
2138  resultBuffer.end());
2139  auto newStruct = builder.createOrFold<hw::StructCreateOp>(
2140  lowerType(destStructType), temp);
2141  resultBuffer.resize(size);
2142  resultBuffer.push_back(newStruct);
2143  return success();
2144  })
2145  .Case<IntType>([&](auto) {
2146  if (auto result = cast(src, srcType, destType)) {
2147  resultBuffer.push_back(result);
2148  return success();
2149  }
2150  return failure();
2151  })
2152  .Default([&](auto) { return failure(); });
2153  };
2154 
2155  if (failed(recurse(array, sourceType, destType)))
2156  return Value();
2157 
2158  assert(resultBuffer.size() == 1 &&
2159  "resultBuffer must only contain a result array if `success` is true");
2160  return resultBuffer[0];
2161 }
2162 
2163 /// Return the lowered value corresponding to the specified original value and
2164 /// then extend it to match the width of destType if needed.
2165 ///
2166 /// This returns a null value for FIRRTL values that cannot be lowered, e.g.
2167 /// unknown width integers.
2168 Value FIRRTLLowering::getLoweredAndExtendedValue(Value value, Type destType) {
2169  assert(type_isa<FIRRTLBaseType>(value.getType()) &&
2170  type_isa<FIRRTLBaseType>(destType) &&
2171  "input/output value should be FIRRTL");
2172 
2173  // We only know how to extend integer types with known width.
2174  auto destWidth = type_cast<FIRRTLBaseType>(destType).getBitWidthOrSentinel();
2175  if (destWidth == -1)
2176  return {};
2177 
2178  auto result = getLoweredValue(value);
2179  if (!result) {
2180  // If this was a zero bit operand being extended, then produce a zero of
2181  // the right result type. If it is just a failure, fail.
2182  if (!isZeroBitFIRRTLType(value.getType()))
2183  return {};
2184  // Zero bit results have to be returned as null. The caller can handle
2185  // this if they want to.
2186  if (destWidth == 0)
2187  return {};
2188  // Otherwise, FIRRTL semantics is that an extension from a zero bit value
2189  // always produces a zero value in the destination width.
2190  return getOrCreateIntConstant(destWidth, 0);
2191  }
2192 
2193  if (destWidth ==
2194  cast<FIRRTLBaseType>(value.getType()).getBitWidthOrSentinel()) {
2195  // Lookup the lowered type of dest.
2196  auto loweredDstType = lowerType(destType);
2197  if (result.getType() != loweredDstType &&
2198  (isa<hw::TypeAliasType>(result.getType()) ||
2199  isa<hw::TypeAliasType>(loweredDstType))) {
2200  return builder.createOrFold<hw::BitcastOp>(loweredDstType, result);
2201  }
2202  }
2203  // Aggregates values
2204  if (isa<hw::ArrayType, hw::StructType>(result.getType())) {
2205  // Types already match.
2206  if (destType == value.getType())
2207  return result;
2208 
2209  return getExtOrTruncAggregateValue(
2210  result, type_cast<FIRRTLBaseType>(value.getType()),
2211  type_cast<FIRRTLBaseType>(destType),
2212  /* allowTruncate */ false);
2213  }
2214 
2215  if (isa<seq::ClockType>(result.getType())) {
2216  // Types already match.
2217  if (destType == value.getType())
2218  return result;
2219  builder.emitError("cannot use clock type as an integer");
2220  return {};
2221  }
2222 
2223  auto intResultType = dyn_cast<IntegerType>(result.getType());
2224  if (!intResultType) {
2225  builder.emitError("operand of type ")
2226  << result.getType() << " cannot be used as an integer";
2227  return {};
2228  }
2229 
2230  auto srcWidth = intResultType.getWidth();
2231  if (srcWidth == unsigned(destWidth))
2232  return result;
2233 
2234  if (srcWidth > unsigned(destWidth)) {
2235  builder.emitError("operand should not be a truncation");
2236  return {};
2237  }
2238 
2239  auto resultType = builder.getIntegerType(destWidth);
2240 
2241  // Extension follows the sign of the source value, not the destination.
2242  auto valueFIRType =
2243  type_cast<FIRRTLBaseType>(value.getType()).getPassiveType();
2244  if (type_cast<IntType>(valueFIRType).isSigned())
2245  return comb::createOrFoldSExt(result, resultType, builder);
2246 
2247  auto zero = getOrCreateIntConstant(destWidth - srcWidth, 0);
2248  return builder.createOrFold<comb::ConcatOp>(zero, result);
2249 }
2250 
2251 /// Return the lowered value corresponding to the specified original value and
2252 /// then extended or truncated to match the width of destType if needed.
2253 ///
2254 /// This returns a null value for FIRRTL values that cannot be lowered, e.g.
2255 /// unknown width integers.
2256 Value FIRRTLLowering::getLoweredAndExtOrTruncValue(Value value, Type destType) {
2257  assert(type_isa<FIRRTLBaseType>(value.getType()) &&
2258  type_isa<FIRRTLBaseType>(destType) &&
2259  "input/output value should be FIRRTL");
2260 
2261  // We only know how to adjust integer types with known width.
2262  auto destWidth = type_cast<FIRRTLBaseType>(destType).getBitWidthOrSentinel();
2263  if (destWidth == -1)
2264  return {};
2265 
2266  auto result = getLoweredValue(value);
2267  if (!result) {
2268  // If this was a zero bit operand being extended, then produce a zero of
2269  // the right result type. If it is just a failure, fail.
2270  if (!isZeroBitFIRRTLType(value.getType()))
2271  return {};
2272  // Zero bit results have to be returned as null. The caller can handle
2273  // this if they want to.
2274  if (destWidth == 0)
2275  return {};
2276  // Otherwise, FIRRTL semantics is that an extension from a zero bit value
2277  // always produces a zero value in the destination width.
2278  return getOrCreateIntConstant(destWidth, 0);
2279  }
2280 
2281  // Aggregates values
2282  if (isa<hw::ArrayType, hw::StructType>(result.getType())) {
2283  // Types already match.
2284  if (destType == value.getType())
2285  return result;
2286 
2287  return getExtOrTruncAggregateValue(
2288  result, type_cast<FIRRTLBaseType>(value.getType()),
2289  type_cast<FIRRTLBaseType>(destType),
2290  /* allowTruncate */ true);
2291  }
2292 
2293  auto srcWidth = type_cast<IntegerType>(result.getType()).getWidth();
2294  if (srcWidth == unsigned(destWidth))
2295  return result;
2296 
2297  if (destWidth == 0)
2298  return {};
2299 
2300  if (srcWidth > unsigned(destWidth)) {
2301  auto resultType = builder.getIntegerType(destWidth);
2302  return builder.createOrFold<comb::ExtractOp>(resultType, result, 0);
2303  }
2304 
2305  auto resultType = builder.getIntegerType(destWidth);
2306 
2307  // Extension follows the sign of the source value, not the destination.
2308  auto valueFIRType =
2309  type_cast<FIRRTLBaseType>(value.getType()).getPassiveType();
2310  if (type_cast<IntType>(valueFIRType).isSigned())
2311  return comb::createOrFoldSExt(result, resultType, builder);
2312 
2313  auto zero = getOrCreateIntConstant(destWidth - srcWidth, 0);
2314  return builder.createOrFold<comb::ConcatOp>(zero, result);
2315 }
2316 
2317 /// Return a lowered version of 'operand' suitable for use with substitution /
2318 /// format strings. Zero bit operands are rewritten as one bit zeros and signed
2319 /// integers are wrapped in $signed().
2320 Value FIRRTLLowering::getLoweredFmtOperand(Value operand) {
2321  auto loweredValue = getLoweredValue(operand);
2322  if (!loweredValue) {
2323  // If this is a zero bit operand, just pass a one bit zero.
2324  if (!isZeroBitFIRRTLType(operand.getType()))
2325  return nullptr;
2326  loweredValue = getOrCreateIntConstant(1, 0);
2327  }
2328 
2329  // If the operand was an SInt, we want to give the user the option to print
2330  // it as signed decimal and have to wrap it in $signed().
2331  if (auto intTy = firrtl::type_cast<IntType>(operand.getType()))
2332  if (intTy.isSigned())
2333  loweredValue = builder.create<sv::SystemFunctionOp>(
2334  loweredValue.getType(), "signed", loweredValue);
2335 
2336  return loweredValue;
2337 }
2338 
2339 /// Set the lowered value of 'orig' to 'result', remembering this in a map.
2340 /// This always returns success() to make it more convenient in lowering code.
2341 ///
2342 /// Note that result may be null here if we're lowering orig to a zero-bit
2343 /// value.
2344 ///
2345 LogicalResult FIRRTLLowering::setLowering(Value orig, Value result) {
2346  if (auto origType = dyn_cast<FIRRTLType>(orig.getType())) {
2347  assert((!result || !type_isa<FIRRTLType>(result.getType())) &&
2348  "Lowering didn't turn a FIRRTL value into a non-FIRRTL value");
2349 
2350 #ifndef NDEBUG
2351  auto baseType = getBaseType(origType);
2352  auto srcWidth = baseType.getPassiveType().getBitWidthOrSentinel();
2353 
2354  // Caller should pass null value iff this was a zero bit value.
2355  if (srcWidth != -1) {
2356  if (result)
2357  assert((srcWidth != 0) &&
2358  "Lowering produced value for zero width source");
2359  else
2360  assert((srcWidth == 0) &&
2361  "Lowering produced null value but source wasn't zero width");
2362  }
2363 #endif
2364  } else {
2365  assert(result && "Lowering of foreign type produced null value");
2366  }
2367 
2368  auto &slot = valueMapping[orig];
2369  assert(!slot && "value lowered multiple times");
2370  slot = result;
2371  return success();
2372 }
2373 
2374 /// Set the lowering for a value to the specified result. This came from a
2375 /// possible folding, so check to see if we need to handle a constant.
2376 LogicalResult FIRRTLLowering::setPossiblyFoldedLowering(Value orig,
2377  Value result) {
2378  // If this is a constant, check to see if we have it in our unique mapping:
2379  // it could have come from folding an operation.
2380  if (auto cst = dyn_cast_or_null<hw::ConstantOp>(result.getDefiningOp())) {
2381  auto &entry = hwConstantMap[cst.getValueAttr()];
2382  if (entry == cst) {
2383  // We're already using an entry in the constant map, nothing to do.
2384  } else if (entry) {
2385  // We already had this constant, reuse the one we have instead of the
2386  // one we just folded.
2387  result = entry;
2388  cst->erase();
2389  } else {
2390  // This is a new constant. Remember it!
2391  entry = cst;
2392  cst->moveBefore(&theModule.getBodyBlock()->front());
2393  }
2394  }
2395 
2396  return setLowering(orig, result);
2397 }
2398 
2399 /// Create a new operation with type ResultOpType and arguments CtorArgTypes,
2400 /// then call setLowering with its result.
2401 template <typename ResultOpType, typename... CtorArgTypes>
2402 LogicalResult FIRRTLLowering::setLoweringTo(Operation *orig,
2403  CtorArgTypes... args) {
2404  auto result = builder.createOrFold<ResultOpType>(args...);
2405  if (auto *op = result.getDefiningOp())
2406  tryCopyName(op, orig);
2407  return setPossiblyFoldedLowering(orig->getResult(0), result);
2408 }
2409 
2410 /// Create a new LTL operation with type ResultOpType and arguments
2411 /// CtorArgTypes, then call setLowering with its result. Also add the operation
2412 /// to the worklist of LTL ops that need to have their types fixed-up after the
2413 /// lowering.
2414 template <typename ResultOpType, typename... CtorArgTypes>
2415 LogicalResult FIRRTLLowering::setLoweringToLTL(Operation *orig,
2416  CtorArgTypes... args) {
2417  auto result = builder.createOrFold<ResultOpType>(args...);
2418  if (auto *op = result.getDefiningOp())
2419  ltlOpFixupWorklist.insert(op);
2420  return setPossiblyFoldedLowering(orig->getResult(0), result);
2421 }
2422 
2423 /// Creates a backedge of the specified result type. A backedge represents a
2424 /// placeholder to be filled in later by a lowered value. If the backedge is not
2425 /// updated with a real value by the end of the pass, it will be replaced with
2426 /// an undriven wire. Backedges are allowed to be updated to other backedges.
2427 /// If a chain of backedges forms a combinational loop, they will be replaced
2428 /// with an undriven wire.
2429 Backedge FIRRTLLowering::createBackedge(Location loc, Type type) {
2430  auto backedge = backedgeBuilder.get(type, loc);
2431  backedges.insert({backedge, backedge});
2432  return backedge;
2433 }
2434 
2435 /// Sets the lowering for a value to a backedge of the specified result type.
2436 /// This is useful for lowering types which cannot pass through a wire, or to
2437 /// directly materialize values in operations that violate the SSA dominance
2438 /// constraint.
2439 Backedge FIRRTLLowering::createBackedge(Value orig, Type type) {
2440  auto backedge = createBackedge(orig.getLoc(), type);
2441  (void)setLowering(orig, backedge);
2442  return backedge;
2443 }
2444 
2445 /// If the `from` value is in fact a backedge, record that the backedge will
2446 /// be replaced by the value. Return true if the destination is a backedge.
2447 bool FIRRTLLowering::updateIfBackedge(Value dest, Value src) {
2448  auto backedgeIt = backedges.find(dest);
2449  if (backedgeIt == backedges.end())
2450  return false;
2451  backedgeIt->second = src;
2452  return true;
2453 }
2454 
2455 /// Switch the insertion point of the current builder to the end of the
2456 /// specified block and run the closure. This correctly handles the case
2457 /// where the closure is null, but the caller needs to make sure the block
2458 /// exists.
2459 void FIRRTLLowering::runWithInsertionPointAtEndOfBlock(
2460  std::function<void(void)> fn, Region &region) {
2461  if (!fn)
2462  return;
2463 
2464  auto oldIP = builder.saveInsertionPoint();
2465 
2466  builder.setInsertionPointToEnd(&region.front());
2467  fn();
2468  builder.restoreInsertionPoint(oldIP);
2469 }
2470 
2471 /// Return a read value for the specified inout operation, auto-uniquing them.
2472 Value FIRRTLLowering::getReadValue(Value v) {
2473  Value result = readInOutCreated.lookup(v);
2474  if (result)
2475  return result;
2476 
2477  // Make sure to put the read value at the correct scope so it dominates all
2478  // future uses.
2479  auto oldIP = builder.saveInsertionPoint();
2480  if (auto *vOp = v.getDefiningOp()) {
2481  builder.setInsertionPointAfter(vOp);
2482  } else {
2483  // For reads of ports, just set the insertion point at the top of the
2484  // module.
2485  builder.setInsertionPoint(&theModule.getBodyBlock()->front());
2486  }
2487 
2488  // Instead of creating `ReadInOutOp` for `ArrayIndexInOutOp`, create
2489  // `ArrayGetOp` for root arrays.
2490  if (auto arrayIndexInout = v.getDefiningOp<sv::ArrayIndexInOutOp>()) {
2491  result = getReadValue(arrayIndexInout.getInput());
2492  result = builder.createOrFold<hw::ArrayGetOp>(result,
2493  arrayIndexInout.getIndex());
2494  } else {
2495  // Otherwise, create a read inout operation.
2496  result = builder.createOrFold<sv::ReadInOutOp>(v);
2497  }
2498  builder.restoreInsertionPoint(oldIP);
2499  readInOutCreated.insert({v, result});
2500  return result;
2501 }
2502 
2503 Value FIRRTLLowering::getNonClockValue(Value v) {
2504  auto it = fromClockMapping.try_emplace(v, Value{});
2505  if (it.second) {
2506  ImplicitLocOpBuilder builder(v.getLoc(), v.getContext());
2507  builder.setInsertionPointAfterValue(v);
2508  it.first->second = builder.create<seq::FromClockOp>(v);
2509  }
2510  return it.first->second;
2511 }
2512 
2513 void FIRRTLLowering::addToAlwaysBlock(sv::EventControl clockEdge, Value clock,
2514  sv::ResetType resetStyle,
2515  sv::EventControl resetEdge, Value reset,
2516  std::function<void(void)> body,
2517  std::function<void(void)> resetBody) {
2518  AlwaysKeyType key{builder.getBlock(), clockEdge, clock,
2519  resetStyle, resetEdge, reset};
2520  sv::AlwaysOp alwaysOp;
2521  sv::IfOp insideIfOp;
2522  std::tie(alwaysOp, insideIfOp) = alwaysBlocks.lookup(key);
2523 
2524  if (!alwaysOp) {
2525  if (reset) {
2526  assert(resetStyle != sv::ResetType::NoReset);
2527  // Here, we want to create the folloing structure with sv.always and
2528  // sv.if. If `reset` is async, we need to add `reset` to a sensitivity
2529  // list.
2530  //
2531  // sv.always @(clockEdge or reset) {
2532  // sv.if (reset) {
2533  // resetBody
2534  // } else {
2535  // body
2536  // }
2537  // }
2538 
2539  auto createIfOp = [&]() {
2540  // It is weird but intended. Here we want to create an empty sv.if
2541  // with an else block.
2542  insideIfOp = builder.create<sv::IfOp>(
2543  reset, []() {}, []() {});
2544  };
2545  if (resetStyle == sv::ResetType::AsyncReset) {
2546  sv::EventControl events[] = {clockEdge, resetEdge};
2547  Value clocks[] = {clock, reset};
2548 
2549  alwaysOp = builder.create<sv::AlwaysOp>(events, clocks, [&]() {
2550  if (resetEdge == sv::EventControl::AtNegEdge)
2551  llvm_unreachable("negative edge for reset is not expected");
2552  createIfOp();
2553  });
2554  } else {
2555  alwaysOp = builder.create<sv::AlwaysOp>(clockEdge, clock, createIfOp);
2556  }
2557  } else {
2558  assert(!resetBody);
2559  alwaysOp = builder.create<sv::AlwaysOp>(clockEdge, clock);
2560  insideIfOp = nullptr;
2561  }
2562  alwaysBlocks[key] = {alwaysOp, insideIfOp};
2563  }
2564 
2565  if (reset) {
2566  assert(insideIfOp && "reset body must be initialized before");
2567  runWithInsertionPointAtEndOfBlock(resetBody, insideIfOp.getThenRegion());
2568  runWithInsertionPointAtEndOfBlock(body, insideIfOp.getElseRegion());
2569  } else {
2570  runWithInsertionPointAtEndOfBlock(body, alwaysOp.getBody());
2571  }
2572 
2573  // Move the earlier always block(s) down to where the last would have been
2574  // inserted. This ensures that any values used by the always blocks are
2575  // defined ahead of the uses, which leads to better generated Verilog.
2576  alwaysOp->moveBefore(builder.getInsertionBlock(),
2577  builder.getInsertionPoint());
2578 }
2579 
2580 LogicalResult FIRRTLLowering::emitGuards(Location loc,
2581  ArrayRef<Attribute> guards,
2582  std::function<void(void)> emit) {
2583  if (guards.empty()) {
2584  emit();
2585  return success();
2586  }
2587  auto guard = dyn_cast<StringAttr>(guards[0]);
2588  if (!guard)
2589  return mlir::emitError(loc,
2590  "elements in `guards` array must be `StringAttr`");
2591 
2592  // Record the guard macro to emit a declaration for it.
2593  circuitState.addMacroDecl(builder.getStringAttr(guard.getValue()));
2594  LogicalResult result = LogicalResult::failure();
2595  addToIfDefBlock(guard.getValue(), [&]() {
2596  result = emitGuards(loc, guards.drop_front(), emit);
2597  });
2598  return result;
2599 }
2600 
2601 void FIRRTLLowering::addToIfDefBlock(StringRef cond,
2602  std::function<void(void)> thenCtor,
2603  std::function<void(void)> elseCtor) {
2604  auto condAttr = builder.getStringAttr(cond);
2605  auto op = ifdefBlocks.lookup({builder.getBlock(), condAttr});
2606  if (op) {
2607  runWithInsertionPointAtEndOfBlock(thenCtor, op.getThenRegion());
2608  runWithInsertionPointAtEndOfBlock(elseCtor, op.getElseRegion());
2609 
2610  // Move the earlier #ifdef block(s) down to where the last would have been
2611  // inserted. This ensures that any values used by the #ifdef blocks are
2612  // defined ahead of the uses, which leads to better generated Verilog.
2613  op->moveBefore(builder.getInsertionBlock(), builder.getInsertionPoint());
2614  } else {
2615  ifdefBlocks[{builder.getBlock(), condAttr}] =
2616  builder.create<sv::IfDefOp>(condAttr, thenCtor, elseCtor);
2617  }
2618 }
2619 
2620 void FIRRTLLowering::addToInitialBlock(std::function<void(void)> body) {
2621  auto op = initialBlocks.lookup(builder.getBlock());
2622  if (op) {
2623  runWithInsertionPointAtEndOfBlock(body, op.getBody());
2624 
2625  // Move the earlier initial block(s) down to where the last would have
2626  // been inserted. This ensures that any values used by the initial blocks
2627  // are defined ahead of the uses, which leads to better generated Verilog.
2628  op->moveBefore(builder.getInsertionBlock(), builder.getInsertionPoint());
2629  } else {
2630  initialBlocks[builder.getBlock()] = builder.create<sv::InitialOp>(body);
2631  }
2632 }
2633 
2634 void FIRRTLLowering::addIfProceduralBlock(Value cond,
2635  std::function<void(void)> thenCtor,
2636  std::function<void(void)> elseCtor) {
2637  // Check to see if we already have an if on this condition immediately
2638  // before the insertion point. If so, extend it.
2639  auto insertIt = builder.getInsertionPoint();
2640  if (insertIt != builder.getBlock()->begin())
2641  if (auto ifOp = dyn_cast<sv::IfOp>(*--insertIt)) {
2642  if (ifOp.getCond() == cond) {
2643  runWithInsertionPointAtEndOfBlock(thenCtor, ifOp.getThenRegion());
2644  runWithInsertionPointAtEndOfBlock(elseCtor, ifOp.getElseRegion());
2645  return;
2646  }
2647  }
2648 
2649  builder.create<sv::IfOp>(cond, thenCtor, elseCtor);
2650 }
2651 
2652 //===----------------------------------------------------------------------===//
2653 // Special Operations
2654 //===----------------------------------------------------------------------===//
2655 
2656 /// Handle the case where an operation wasn't lowered. When this happens, the
2657 /// operands should just be unlowered non-FIRRTL values. If the operand was
2658 /// not lowered then leave it alone, otherwise we have a problem with
2659 /// lowering.
2660 ///
2661 FIRRTLLowering::UnloweredOpResult
2662 FIRRTLLowering::handleUnloweredOp(Operation *op) {
2663  // Simply pass through non-FIRRTL operations and consider them already
2664  // lowered. This allows us to handled partially lowered inputs, and also allow
2665  // other FIRRTL operations to spawn additional already-lowered operations,
2666  // like `hw.output`.
2667  if (!isa<FIRRTLDialect>(op->getDialect())) {
2668  for (auto &operand : op->getOpOperands())
2669  if (auto lowered = getPossiblyInoutLoweredValue(operand.get()))
2670  operand.set(lowered);
2671  for (auto result : op->getResults())
2672  (void)setLowering(result, result);
2673  return AlreadyLowered;
2674  }
2675 
2676  // Ok, at least one operand got lowered, so this operation is using a FIRRTL
2677  // value, but wasn't itself lowered. This is because the lowering is
2678  // incomplete. This is either a bug or incomplete implementation.
2679  //
2680  // There is one aspect of incompleteness we intentionally expect: we allow
2681  // primitive operations that produce a zero bit result to be ignored by the
2682  // lowering logic. They don't have side effects, and handling this corner
2683  // case just complicates each of the lowering hooks. Instead, we just handle
2684  // them all right here.
2685  if (op->getNumResults() == 1) {
2686  auto resultType = op->getResult(0).getType();
2687  if (type_isa<FIRRTLBaseType>(resultType) &&
2688  isZeroBitFIRRTLType(resultType) &&
2689  (isExpression(op) || isa<mlir::UnrealizedConversionCastOp>(op))) {
2690  // Zero bit values lower to the null Value.
2691  (void)setLowering(op->getResult(0), Value());
2692  return NowLowered;
2693  }
2694  }
2695  op->emitOpError("LowerToHW couldn't handle this operation");
2696  return LoweringFailure;
2697 }
2698 
2699 LogicalResult FIRRTLLowering::visitExpr(ConstantOp op) {
2700  // Zero width values must be lowered to nothing.
2701  if (isZeroBitFIRRTLType(op.getType()))
2702  return setLowering(op, Value());
2703 
2704  return setLowering(op, getOrCreateIntConstant(op.getValue()));
2705 }
2706 
2707 LogicalResult FIRRTLLowering::visitExpr(SpecialConstantOp op) {
2708  Value cst;
2709  if (isa<ClockType>(op.getType())) {
2710  cst = getOrCreateClockConstant(op.getValue() ? seq::ClockConst::High
2711  : seq::ClockConst::Low);
2712  } else {
2713  cst = getOrCreateIntConstant(APInt(/*bitWidth*/ 1, op.getValue()));
2714  }
2715  return setLowering(op, cst);
2716 }
2717 
2718 FailureOr<Value> FIRRTLLowering::lowerSubindex(SubindexOp op, Value input) {
2719  auto iIdx = getOrCreateIntConstant(
2721  firrtl::type_cast<FVectorType>(op.getInput().getType())
2722  .getNumElements()),
2723  op.getIndex());
2724 
2725  // If the input has an inout type, we need to lower to ArrayIndexInOutOp;
2726  // otherwise hw::ArrayGetOp.
2727  Value result;
2728  if (isa<sv::InOutType>(input.getType()))
2729  result = builder.createOrFold<sv::ArrayIndexInOutOp>(input, iIdx);
2730  else
2731  result = builder.createOrFold<hw::ArrayGetOp>(input, iIdx);
2732  if (auto *definingOp = result.getDefiningOp())
2733  tryCopyName(definingOp, op);
2734  return result;
2735 }
2736 
2737 FailureOr<Value> FIRRTLLowering::lowerSubaccess(SubaccessOp op, Value input) {
2738  Value valueIdx = getLoweredAndExtOrTruncValue(
2739  op.getIndex(),
2740  UIntType::get(op->getContext(),
2742  firrtl::type_cast<FVectorType>(op.getInput().getType())
2743  .getNumElements())));
2744  if (!valueIdx) {
2745  op->emitError() << "input lowering failed";
2746  return failure();
2747  }
2748 
2749  // If the input has an inout type, we need to lower to ArrayIndexInOutOp;
2750  // otherwise, lower the op to array indexing.
2751  Value result;
2752  if (isa<sv::InOutType>(input.getType()))
2753  result = builder.createOrFold<sv::ArrayIndexInOutOp>(input, valueIdx);
2754  else
2755  result = createArrayIndexing(input, valueIdx);
2756  if (auto *definingOp = result.getDefiningOp())
2757  tryCopyName(definingOp, op);
2758  return result;
2759 }
2760 
2761 FailureOr<Value> FIRRTLLowering::lowerSubfield(SubfieldOp op, Value input) {
2762  auto resultType = lowerType(op->getResult(0).getType());
2763  if (!resultType || !input) {
2764  op->emitError() << "subfield type lowering failed";
2765  return failure();
2766  }
2767 
2768  // If the input has an inout type, we need to lower to StructFieldInOutOp;
2769  // otherwise, StructExtractOp.
2770  auto field = firrtl::type_cast<BundleType>(op.getInput().getType())
2771  .getElementName(op.getFieldIndex());
2772  Value result;
2773  if (isa<sv::InOutType>(input.getType()))
2774  result = builder.createOrFold<sv::StructFieldInOutOp>(input, field);
2775  else
2776  result = builder.createOrFold<hw::StructExtractOp>(input, field);
2777  if (auto *definingOp = result.getDefiningOp())
2778  tryCopyName(definingOp, op);
2779  return result;
2780 }
2781 
2782 LogicalResult FIRRTLLowering::visitExpr(SubindexOp op) {
2783  if (isZeroBitFIRRTLType(op.getType()))
2784  return setLowering(op, Value());
2785 
2786  auto input = getPossiblyInoutLoweredValue(op.getInput());
2787  if (!input)
2788  return op.emitError() << "input lowering failed";
2789 
2790  auto result = lowerSubindex(op, input);
2791  if (failed(result))
2792  return failure();
2793  return setLowering(op, *result);
2794 }
2795 
2796 LogicalResult FIRRTLLowering::visitExpr(SubaccessOp op) {
2797  if (isZeroBitFIRRTLType(op.getType()))
2798  return setLowering(op, Value());
2799 
2800  auto input = getPossiblyInoutLoweredValue(op.getInput());
2801  if (!input)
2802  return op.emitError() << "input lowering failed";
2803 
2804  auto result = lowerSubaccess(op, input);
2805  if (failed(result))
2806  return failure();
2807  return setLowering(op, *result);
2808 }
2809 
2810 LogicalResult FIRRTLLowering::visitExpr(SubfieldOp op) {
2811  // firrtl.mem lowering lowers some SubfieldOps. Zero-width can leave
2812  // invalid subfield accesses
2813  if (getLoweredValue(op) || !op.getInput())
2814  return success();
2815 
2816  if (isZeroBitFIRRTLType(op.getType()))
2817  return setLowering(op, Value());
2818 
2819  auto input = getPossiblyInoutLoweredValue(op.getInput());
2820  if (!input)
2821  return op.emitError() << "input lowering failed";
2822 
2823  auto result = lowerSubfield(op, input);
2824  if (failed(result))
2825  return failure();
2826  return setLowering(op, *result);
2827 }
2828 
2829 LogicalResult FIRRTLLowering::visitExpr(VectorCreateOp op) {
2830  auto resultType = lowerType(op.getResult().getType());
2831  SmallVector<Value> operands;
2832  // NOTE: The operand order must be inverted.
2833  for (auto oper : llvm::reverse(op.getOperands())) {
2834  auto val = getLoweredValue(oper);
2835  if (!val)
2836  return failure();
2837  operands.push_back(val);
2838  }
2839  return setLoweringTo<hw::ArrayCreateOp>(op, resultType, operands);
2840 }
2841 
2842 LogicalResult FIRRTLLowering::visitExpr(BundleCreateOp op) {
2843  auto resultType = lowerType(op.getResult().getType());
2844  SmallVector<Value> operands;
2845  for (auto oper : op.getOperands()) {
2846  auto val = getLoweredValue(oper);
2847  if (!val)
2848  return failure();
2849  operands.push_back(val);
2850  }
2851  return setLoweringTo<hw::StructCreateOp>(op, resultType, operands);
2852 }
2853 
2854 LogicalResult FIRRTLLowering::visitExpr(FEnumCreateOp op) {
2855  // Zero width values must be lowered to nothing.
2856  if (isZeroBitFIRRTLType(op.getType()))
2857  return setLowering(op, Value());
2858 
2859  auto input = getLoweredValue(op.getInput());
2860  auto tagName = op.getFieldNameAttr();
2861  auto type = lowerType(op.getType());
2862 
2863  if (auto structType = dyn_cast<hw::StructType>(type)) {
2864  auto enumType = structType.getFieldType("tag");
2865  auto enumAttr = hw::EnumFieldAttr::get(op.getLoc(), tagName, enumType);
2866  auto enumOp = builder.create<hw::EnumConstantOp>(enumAttr);
2867  auto unionType = structType.getFieldType("body");
2868  auto unionOp = builder.create<hw::UnionCreateOp>(unionType, tagName, input);
2869  SmallVector<Value> operands = {enumOp.getResult(), unionOp.getResult()};
2870  return setLoweringTo<hw::StructCreateOp>(op, structType, operands);
2871  }
2872 
2873  return setLoweringTo<hw::EnumConstantOp>(
2874  op, hw::EnumFieldAttr::get(op.getLoc(), tagName, type));
2875 }
2876 
2877 LogicalResult FIRRTLLowering::visitExpr(AggregateConstantOp op) {
2878  auto resultType = lowerType(op.getResult().getType());
2879  auto attr =
2880  getOrCreateAggregateConstantAttribute(op.getFieldsAttr(), resultType);
2881 
2882  return setLoweringTo<hw::AggregateConstantOp>(op, resultType,
2883  cast<ArrayAttr>(attr));
2884 }
2885 
2886 LogicalResult FIRRTLLowering::visitExpr(IsTagOp op) {
2887  auto tagName = op.getFieldNameAttr();
2888  auto lhs = getLoweredValue(op.getInput());
2889  if (isa<hw::StructType>(lhs.getType()))
2890  lhs = builder.create<hw::StructExtractOp>(lhs, "tag");
2891  auto enumField = hw::EnumFieldAttr::get(op.getLoc(), tagName, lhs.getType());
2892  auto rhs = builder.create<hw::EnumConstantOp>(enumField);
2893  return setLoweringTo<hw::EnumCmpOp>(op, lhs, rhs);
2894 }
2895 
2896 LogicalResult FIRRTLLowering::visitExpr(SubtagOp op) {
2897  // Zero width values must be lowered to nothing.
2898  if (isZeroBitFIRRTLType(op.getType()))
2899  return setLowering(op, Value());
2900 
2901  auto tagName = op.getFieldNameAttr();
2902  auto input = getLoweredValue(op.getInput());
2903  auto field = builder.create<hw::StructExtractOp>(input, "body");
2904  return setLoweringTo<hw::UnionExtractOp>(op, field, tagName);
2905 }
2906 
2907 //===----------------------------------------------------------------------===//
2908 // Declarations
2909 //===----------------------------------------------------------------------===//
2910 
2911 LogicalResult FIRRTLLowering::visitDecl(WireOp op) {
2912  auto origResultType = op.getResult().getType();
2913 
2914  // Foreign types lower to a backedge that needs to be resolved by a later
2915  // connect op.
2916  if (!type_isa<FIRRTLType>(origResultType)) {
2917  createBackedge(op.getResult(), origResultType);
2918  return success();
2919  }
2920 
2921  auto resultType = lowerType(origResultType);
2922  if (!resultType)
2923  return failure();
2924 
2925  if (resultType.isInteger(0)) {
2926  if (op.getInnerSym())
2927  return op.emitError("zero width wire is referenced by name [")
2928  << *op.getInnerSym() << "] (e.g. in an XMR) but must be removed";
2929  return setLowering(op.getResult(), Value());
2930  }
2931 
2932  // Name attr is required on sv.wire but optional on firrtl.wire.
2933  auto innerSym = lowerInnerSymbol(op);
2934  auto name = op.getNameAttr();
2935  // This is not a temporary wire created by the compiler, so attach a symbol
2936  // name.
2937  auto wire = builder.create<hw::WireOp>(
2938  op.getLoc(), getOrCreateZConstant(resultType), name, innerSym);
2939 
2940  if (auto svAttrs = sv::getSVAttributes(op))
2941  sv::setSVAttributes(wire, svAttrs);
2942 
2943  return setLowering(op.getResult(), wire);
2944 }
2945 
2946 LogicalResult FIRRTLLowering::visitDecl(VerbatimWireOp op) {
2947  auto resultTy = lowerType(op.getType());
2948  if (!resultTy)
2949  return failure();
2950  resultTy = sv::InOutType::get(op.getContext(), resultTy);
2951 
2952  SmallVector<Value, 4> operands;
2953  operands.reserve(op.getSubstitutions().size());
2954  for (auto operand : op.getSubstitutions()) {
2955  auto lowered = getLoweredValue(operand);
2956  if (!lowered)
2957  return failure();
2958  operands.push_back(lowered);
2959  }
2960 
2961  ArrayAttr symbols = op.getSymbolsAttr();
2962  if (!symbols)
2963  symbols = ArrayAttr::get(op.getContext(), {});
2964 
2965  return setLoweringTo<sv::VerbatimExprSEOp>(op, resultTy, op.getTextAttr(),
2966  operands, symbols);
2967 }
2968 
2969 LogicalResult FIRRTLLowering::visitDecl(NodeOp op) {
2970  auto operand = getLoweredValue(op.getInput());
2971  if (!operand)
2972  return handleZeroBit(op.getInput(), [&]() -> LogicalResult {
2973  if (op.getInnerSym())
2974  return op.emitError("zero width node is referenced by name [")
2975  << *op.getInnerSym()
2976  << "] (e.g. in an XMR) but must be "
2977  "removed";
2978  return setLowering(op.getResult(), Value());
2979  });
2980 
2981  // Node operations are logical noops, but may carry annotations or be
2982  // referred to through an inner name. If a don't touch is present, ensure
2983  // that we have a symbol name so we can keep the node as a wire.
2984  auto name = op.getNameAttr();
2985  auto innerSym = lowerInnerSymbol(op);
2986 
2987  if (innerSym)
2988  operand = builder.create<hw::WireOp>(operand, name, innerSym);
2989 
2990  // Move SV attributes.
2991  if (auto svAttrs = sv::getSVAttributes(op)) {
2992  if (!innerSym)
2993  operand = builder.create<hw::WireOp>(operand, name);
2994  sv::setSVAttributes(operand.getDefiningOp(), svAttrs);
2995  }
2996 
2997  return setLowering(op.getResult(), operand);
2998 }
2999 
3000 LogicalResult FIRRTLLowering::visitDecl(RegOp op) {
3001  auto resultType = lowerType(op.getResult().getType());
3002  if (!resultType)
3003  return failure();
3004  if (resultType.isInteger(0))
3005  return setLowering(op.getResult(), Value());
3006 
3007  Value clockVal = getLoweredValue(op.getClockVal());
3008  if (!clockVal)
3009  return failure();
3010 
3011  // Create a reg op, wiring itself to its input.
3012  auto innerSym = lowerInnerSymbol(op);
3013  Backedge inputEdge = backedgeBuilder.get(resultType);
3014  auto reg = builder.create<seq::FirRegOp>(inputEdge, clockVal,
3015  op.getNameAttr(), innerSym);
3016 
3017  // Pass along the start and end random initialization bits for this register.
3018  if (auto randomRegister = op->getAttr("firrtl.random_init_register"))
3019  reg->setAttr("firrtl.random_init_register", randomRegister);
3020  if (auto randomStart = op->getAttr("firrtl.random_init_start"))
3021  reg->setAttr("firrtl.random_init_start", randomStart);
3022  if (auto randomEnd = op->getAttr("firrtl.random_init_end"))
3023  reg->setAttr("firrtl.random_init_end", randomEnd);
3024 
3025  // Move SV attributes.
3026  if (auto svAttrs = sv::getSVAttributes(op))
3027  sv::setSVAttributes(reg, svAttrs);
3028 
3029  inputEdge.setValue(reg);
3030  (void)setLowering(op.getResult(), reg);
3031  return success();
3032 }
3033 
3034 LogicalResult FIRRTLLowering::visitDecl(RegResetOp op) {
3035  auto resultType = lowerType(op.getResult().getType());
3036  if (!resultType)
3037  return failure();
3038  if (resultType.isInteger(0))
3039  return setLowering(op.getResult(), Value());
3040 
3041  Value clockVal = getLoweredValue(op.getClockVal());
3042  Value resetSignal = getLoweredValue(op.getResetSignal());
3043  // Reset values may be narrower than the register. Extend appropriately.
3044  Value resetValue = getLoweredAndExtOrTruncValue(
3045  op.getResetValue(), type_cast<FIRRTLBaseType>(op.getResult().getType()));
3046 
3047  if (!clockVal || !resetSignal || !resetValue)
3048  return failure();
3049 
3050  // Create a reg op, wiring itself to its input.
3051  auto innerSym = lowerInnerSymbol(op);
3052  bool isAsync = type_isa<AsyncResetType>(op.getResetSignal().getType());
3053  Backedge inputEdge = backedgeBuilder.get(resultType);
3054  auto reg =
3055  builder.create<seq::FirRegOp>(inputEdge, clockVal, op.getNameAttr(),
3056  resetSignal, resetValue, innerSym, isAsync);
3057 
3058  // Pass along the start and end random initialization bits for this register.
3059  if (auto randomRegister = op->getAttr("firrtl.random_init_register"))
3060  reg->setAttr("firrtl.random_init_register", randomRegister);
3061  if (auto randomStart = op->getAttr("firrtl.random_init_start"))
3062  reg->setAttr("firrtl.random_init_start", randomStart);
3063  if (auto randomEnd = op->getAttr("firrtl.random_init_end"))
3064  reg->setAttr("firrtl.random_init_end", randomEnd);
3065 
3066  // Move SV attributes.
3067  if (auto svAttrs = sv::getSVAttributes(op))
3068  sv::setSVAttributes(reg, svAttrs);
3069 
3070  inputEdge.setValue(reg);
3071  (void)setLowering(op.getResult(), reg);
3072 
3073  return success();
3074 }
3075 
3076 LogicalResult FIRRTLLowering::visitDecl(MemOp op) {
3077  // TODO: Remove this restriction and preserve aggregates in
3078  // memories.
3079  if (type_isa<BundleType>(op.getDataType()))
3080  return op.emitOpError(
3081  "should have already been lowered from a ground type to an aggregate "
3082  "type using the LowerTypes pass. Use "
3083  "'firtool --lower-types' or 'circt-opt "
3084  "--pass-pipeline='firrtl.circuit(firrtl-lower-types)' "
3085  "to run this.");
3086 
3087  FirMemory memSummary = op.getSummary();
3088 
3089  // Create the memory declaration.
3090  auto memType = seq::FirMemType::get(
3091  op.getContext(), memSummary.depth, memSummary.dataWidth,
3092  memSummary.isMasked ? std::optional<uint32_t>(memSummary.maskBits)
3093  : std::optional<uint32_t>());
3094 
3095  seq::FirMemInitAttr memInit;
3096  if (auto init = op.getInitAttr())
3097  memInit = seq::FirMemInitAttr::get(init.getContext(), init.getFilename(),
3098  init.getIsBinary(), init.getIsInline());
3099 
3100  auto memDecl = builder.create<seq::FirMemOp>(
3101  memType, memSummary.readLatency, memSummary.writeLatency,
3102  memSummary.readUnderWrite, memSummary.writeUnderWrite, op.getNameAttr(),
3103  op.getInnerSymAttr(), memInit, op.getPrefixAttr(), Attribute{});
3104 
3105  // If the module is outside the DUT, set the appropriate output directory for
3106  // the memory.
3107  if (!circuitState.isInDUT(theModule))
3108  if (auto testBenchDir = circuitState.getTestBenchDirectory())
3109  memDecl.setOutputFileAttr(testBenchDir);
3110 
3111  // Memories return multiple structs, one for each port, which means we
3112  // have two layers of type to split apart.
3113  for (size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3114 
3115  auto addOutput = [&](StringRef field, size_t width, Value value) {
3116  for (auto &a : getAllFieldAccesses(op.getResult(i), field)) {
3117  if (width > 0)
3118  (void)setLowering(a, value);
3119  else
3120  a->eraseOperand(0);
3121  }
3122  };
3123 
3124  auto addInput = [&](StringRef field, Value backedge) {
3125  for (auto a : getAllFieldAccesses(op.getResult(i), field)) {
3126  if (cast<FIRRTLBaseType>(a.getType())
3127  .getPassiveType()
3128  .getBitWidthOrSentinel() > 0)
3129  (void)setLowering(a, backedge);
3130  else
3131  a->eraseOperand(0);
3132  }
3133  };
3134 
3135  auto addInputPort = [&](StringRef field, size_t width) -> Value {
3136  // If the memory is 0-width, do not materialize any connections to it.
3137  // However, `seq.firmem` now requires a 1-bit input, so materialize
3138  // a dummy x value to provide it with.
3139  Value backedge, portValue;
3140  if (width == 0) {
3141  portValue = getOrCreateXConstant(1);
3142  } else {
3143  auto portType = IntegerType::get(op.getContext(), width);
3144  backedge = portValue = createBackedge(builder.getLoc(), portType);
3145  }
3146  addInput(field, backedge);
3147  return portValue;
3148  };
3149 
3150  auto addClock = [&](StringRef field) -> Value {
3151  Type clockTy = seq::ClockType::get(op.getContext());
3152  Value portValue = createBackedge(builder.getLoc(), clockTy);
3153  addInput(field, portValue);
3154  return portValue;
3155  };
3156 
3157  auto memportKind = op.getPortKind(i);
3158  if (memportKind == MemOp::PortKind::Read) {
3159  auto addr = addInputPort("addr", op.getAddrBits());
3160  auto en = addInputPort("en", 1);
3161  auto clk = addClock("clk");
3162  auto data = builder.create<seq::FirMemReadOp>(memDecl, addr, clk, en);
3163  addOutput("data", memSummary.dataWidth, data);
3164  } else if (memportKind == MemOp::PortKind::ReadWrite) {
3165  auto addr = addInputPort("addr", op.getAddrBits());
3166  auto en = addInputPort("en", 1);
3167  auto clk = addClock("clk");
3168  // If maskBits =1, then And the mask field with enable, and update the
3169  // enable. Else keep mask port.
3170  auto mode = addInputPort("wmode", 1);
3171  if (!memSummary.isMasked)
3172  mode = builder.createOrFold<comb::AndOp>(mode, addInputPort("wmask", 1),
3173  true);
3174  auto wdata = addInputPort("wdata", memSummary.dataWidth);
3175  // Ignore mask port, if maskBits =1
3176  Value mask;
3177  if (memSummary.isMasked)
3178  mask = addInputPort("wmask", memSummary.maskBits);
3179  auto rdata = builder.create<seq::FirMemReadWriteOp>(
3180  memDecl, addr, clk, en, wdata, mode, mask);
3181  addOutput("rdata", memSummary.dataWidth, rdata);
3182  } else {
3183  auto addr = addInputPort("addr", op.getAddrBits());
3184  // If maskBits =1, then And the mask field with enable, and update the
3185  // enable. Else keep mask port.
3186  auto en = addInputPort("en", 1);
3187  if (!memSummary.isMasked)
3188  en = builder.createOrFold<comb::AndOp>(en, addInputPort("mask", 1),
3189  true);
3190  auto clk = addClock("clk");
3191  auto data = addInputPort("data", memSummary.dataWidth);
3192  // Ignore mask port, if maskBits =1
3193  Value mask;
3194  if (memSummary.isMasked)
3195  mask = addInputPort("mask", memSummary.maskBits);
3196  builder.create<seq::FirMemWriteOp>(memDecl, addr, clk, en, data, mask);
3197  }
3198  }
3199 
3200  return success();
3201 }
3202 
3203 LogicalResult FIRRTLLowering::visitDecl(InstanceOp oldInstance) {
3204  Operation *oldModule =
3205  oldInstance.getReferencedModule(circuitState.getInstanceGraph());
3206 
3207  auto newModule = circuitState.getNewModule(oldModule);
3208  if (!newModule) {
3209  oldInstance->emitOpError("could not find module [")
3210  << oldInstance.getModuleName() << "] referenced by instance";
3211  return failure();
3212  }
3213 
3214  // If this is a referenced to a parameterized extmodule, then bring the
3215  // parameters over to this instance.
3216  ArrayAttr parameters;
3217  if (auto oldExtModule = dyn_cast<FExtModuleOp>(oldModule))
3218  parameters = getHWParameters(oldExtModule, /*ignoreValues=*/false);
3219 
3220  // Decode information about the input and output ports on the referenced
3221  // module.
3222  SmallVector<PortInfo, 8> portInfo = cast<FModuleLike>(oldModule).getPorts();
3223 
3224  // Build an index from the name attribute to an index into portInfo, so we
3225  // can do efficient lookups.
3226  llvm::SmallDenseMap<Attribute, unsigned> portIndicesByName;
3227  for (unsigned portIdx = 0, e = portInfo.size(); portIdx != e; ++portIdx)
3228  portIndicesByName[portInfo[portIdx].name] = portIdx;
3229 
3230  // Ok, get ready to create the new instance operation. We need to prepare
3231  // input operands.
3232  SmallVector<Value, 8> operands;
3233  for (size_t portIndex = 0, e = portInfo.size(); portIndex != e; ++portIndex) {
3234  auto &port = portInfo[portIndex];
3235  auto portType = lowerType(port.type);
3236  if (!portType) {
3237  oldInstance->emitOpError("could not lower type of port ") << port.name;
3238  return failure();
3239  }
3240 
3241  // Drop zero bit input/inout ports.
3242  if (portType.isInteger(0))
3243  continue;
3244 
3245  // We wire outputs up after creating the instance.
3246  if (port.isOutput())
3247  continue;
3248 
3249  auto portResult = oldInstance.getResult(portIndex);
3250  assert(portResult && "invalid IR, couldn't find port");
3251 
3252  // Replace the input port with a backedge. If it turns out that this port
3253  // is never driven, an uninitialized wire will be materialized at the end.
3254  if (port.isInput()) {
3255  operands.push_back(createBackedge(portResult, portType));
3256  continue;
3257  }
3258 
3259  // If the result has an analog type and is used only by attach op, try
3260  // eliminating a temporary wire by directly using an attached value.
3261  if (type_isa<AnalogType>(portResult.getType()) && portResult.hasOneUse()) {
3262  if (auto attach = dyn_cast<AttachOp>(*portResult.getUsers().begin())) {
3263  if (auto source = getSingleNonInstanceOperand(attach)) {
3264  auto loweredResult = getPossiblyInoutLoweredValue(source);
3265  operands.push_back(loweredResult);
3266  (void)setLowering(portResult, loweredResult);
3267  continue;
3268  }
3269  }
3270  }
3271 
3272  // Create a wire for each inout operand, so there is something to connect
3273  // to. The instance becomes the sole driver of this wire.
3274  auto wire = builder.create<sv::WireOp>(
3275  portType, "." + port.getName().str() + ".wire");
3276 
3277  // Know that the argument FIRRTL value is equal to this wire, allowing
3278  // connects to it to be lowered.
3279  (void)setLowering(portResult, wire);
3280 
3281  operands.push_back(wire);
3282  }
3283 
3284  // If this instance is destined to be lowered to a bind, generate a symbol
3285  // for it and generate a bind op. Enter the bind into global
3286  // CircuitLoweringState so that this can be moved outside of module once
3287  // we're guaranteed to not be a parallel context.
3288  auto innerSym = oldInstance.getInnerSymAttr();
3289  if (oldInstance.getLowerToBind()) {
3290  if (!innerSym)
3291  std::tie(innerSym, std::ignore) = getOrAddInnerSym(
3292  oldInstance.getContext(), oldInstance.getInnerSymAttr(), 0,
3293  [&]() -> hw::InnerSymbolNamespace & { return moduleNamespace; });
3294 
3295  auto bindOp = builder.create<sv::BindOp>(theModule.getNameAttr(),
3296  innerSym.getSymName());
3297  // If the lowered op already had output file information, then use that.
3298  // Otherwise, generate some default bind information.
3299  if (auto outputFile = oldInstance->getAttr("output_file"))
3300  bindOp->setAttr("output_file", outputFile);
3301  // Add the bind to the circuit state. This will be moved outside of the
3302  // encapsulating module after all modules have been processed in parallel.
3303  circuitState.addBind(bindOp);
3304  }
3305 
3306  // Create the new hw.instance operation.
3307  auto newInstance = builder.create<hw::InstanceOp>(
3308  newModule, oldInstance.getNameAttr(), operands, parameters, innerSym);
3309 
3310  if (oldInstance.getLowerToBind())
3311  newInstance->setAttr("doNotPrint", builder.getBoolAttr(true));
3312 
3313  if (newInstance.getInnerSymAttr())
3314  if (auto forceName = circuitState.instanceForceNames.lookup(
3315  {cast<hw::HWModuleOp>(newInstance->getParentOp()).getNameAttr(),
3316  newInstance.getInnerNameAttr()}))
3317  newInstance->setAttr("hw.verilogName", forceName);
3318 
3319  // Now that we have the new hw.instance, we need to remap all of the users
3320  // of the outputs/results to the values returned by the instance.
3321  unsigned resultNo = 0;
3322  for (size_t portIndex = 0, e = portInfo.size(); portIndex != e; ++portIndex) {
3323  auto &port = portInfo[portIndex];
3324  if (!port.isOutput() || isZeroBitFIRRTLType(port.type))
3325  continue;
3326 
3327  Value resultVal = newInstance.getResult(resultNo);
3328 
3329  auto oldPortResult = oldInstance.getResult(portIndex);
3330  (void)setLowering(oldPortResult, resultVal);
3331  ++resultNo;
3332  }
3333  return success();
3334 }
3335 
3336 //===----------------------------------------------------------------------===//
3337 // Unary Operations
3338 //===----------------------------------------------------------------------===//
3339 
3340 // Lower a cast that is a noop at the HW level.
3341 LogicalResult FIRRTLLowering::lowerNoopCast(Operation *op) {
3342  auto operand = getPossiblyInoutLoweredValue(op->getOperand(0));
3343  if (!operand)
3344  return failure();
3345 
3346  // Noop cast.
3347  return setLowering(op->getResult(0), operand);
3348 }
3349 
3350 LogicalResult FIRRTLLowering::visitExpr(AsSIntPrimOp op) {
3351  if (isa<ClockType>(op.getInput().getType()))
3352  return setLowering(op->getResult(0),
3353  getLoweredNonClockValue(op.getInput()));
3354  return lowerNoopCast(op);
3355 }
3356 
3357 LogicalResult FIRRTLLowering::visitExpr(AsUIntPrimOp op) {
3358  if (isa<ClockType>(op.getInput().getType()))
3359  return setLowering(op->getResult(0),
3360  getLoweredNonClockValue(op.getInput()));
3361  return lowerNoopCast(op);
3362 }
3363 
3364 LogicalResult FIRRTLLowering::visitExpr(AsClockPrimOp op) {
3365  return setLoweringTo<seq::ToClockOp>(op, getLoweredValue(op.getInput()));
3366 }
3367 
3368 LogicalResult FIRRTLLowering::visitUnrealizedConversionCast(
3369  mlir::UnrealizedConversionCastOp op) {
3370  // General lowering for non-unary casts.
3371  if (op.getNumOperands() != 1 || op.getNumResults() != 1)
3372  return failure();
3373 
3374  auto operand = op.getOperand(0);
3375  auto result = op.getResult(0);
3376 
3377  // FIRRTL -> FIRRTL
3378  if (type_isa<FIRRTLType>(operand.getType()) &&
3379  type_isa<FIRRTLType>(result.getType()))
3380  return lowerNoopCast(op);
3381 
3382  // other -> FIRRTL
3383  // other -> other
3384  if (!type_isa<FIRRTLType>(operand.getType())) {
3385  if (type_isa<FIRRTLType>(result.getType()))
3386  return setLowering(result, getPossiblyInoutLoweredValue(operand));
3387  return failure(); // general foreign op lowering for other -> other
3388  }
3389 
3390  // FIRRTL -> other
3391  // Otherwise must be a conversion from FIRRTL type to standard type.
3392  auto lowered_result = getLoweredValue(operand);
3393  if (!lowered_result) {
3394  // If this is a conversion from a zero bit HW type to firrtl value, then
3395  // we want to successfully lower this to a null Value.
3396  if (operand.getType().isSignlessInteger(0)) {
3397  return setLowering(result, Value());
3398  }
3399  return failure();
3400  }
3401 
3402  // We lower builtin.unrealized_conversion_cast converting from a firrtl type
3403  // to a standard type into the lowered operand.
3404  result.replaceAllUsesWith(lowered_result);
3405  return success();
3406 }
3407 
3408 LogicalResult FIRRTLLowering::visitExpr(HWStructCastOp op) {
3409  // Conversions from hw struct types to FIRRTL types are lowered as the
3410  // input operand.
3411  if (auto opStructType = dyn_cast<hw::StructType>(op.getOperand().getType()))
3412  return setLowering(op, op.getOperand());
3413 
3414  // Otherwise must be a conversion from FIRRTL bundle type to hw struct
3415  // type.
3416  auto result = getLoweredValue(op.getOperand());
3417  if (!result)
3418  return failure();
3419 
3420  // We lower firrtl.stdStructCast converting from a firrtl bundle to an hw
3421  // struct type into the lowered operand.
3422  op.replaceAllUsesWith(result);
3423  return success();
3424 }
3425 
3426 LogicalResult FIRRTLLowering::visitExpr(BitCastOp op) {
3427  auto operand = getLoweredValue(op.getOperand());
3428  if (!operand)
3429  return failure();
3430  auto resultType = lowerType(op.getType());
3431  if (!resultType)
3432  return failure();
3433 
3434  return setLoweringTo<hw::BitcastOp>(op, resultType, operand);
3435 }
3436 
3437 LogicalResult FIRRTLLowering::visitExpr(CvtPrimOp op) {
3438  auto operand = getLoweredValue(op.getOperand());
3439  if (!operand) {
3440  return handleZeroBit(op.getOperand(), [&]() {
3441  // Unsigned zero bit to Signed is 1b0.
3442  if (type_cast<IntType>(op.getOperand().getType()).isUnsigned())
3443  return setLowering(op, getOrCreateIntConstant(1, 0));
3444  // Signed->Signed is a zero bit value.
3445  return setLowering(op, Value());
3446  });
3447  }
3448 
3449  // Signed to signed is a noop.
3450  if (type_cast<IntType>(op.getOperand().getType()).isSigned())
3451  return setLowering(op, operand);
3452 
3453  // Otherwise prepend a zero bit.
3454  auto zero = getOrCreateIntConstant(1, 0);
3455  return setLoweringTo<comb::ConcatOp>(op, zero, operand);
3456 }
3457 
3458 LogicalResult FIRRTLLowering::visitExpr(NotPrimOp op) {
3459  auto operand = getLoweredValue(op.getInput());
3460  if (!operand)
3461  return failure();
3462  // ~x ---> x ^ 0xFF
3463  auto allOnes = getOrCreateIntConstant(
3464  APInt::getAllOnes(operand.getType().getIntOrFloatBitWidth()));
3465  return setLoweringTo<comb::XorOp>(op, operand, allOnes, true);
3466 }
3467 
3468 LogicalResult FIRRTLLowering::visitExpr(NegPrimOp op) {
3469  // FIRRTL negate always adds a bit.
3470  // -x ---> 0-sext(x) or 0-zext(x)
3471  auto operand = getLoweredAndExtendedValue(op.getInput(), op.getType());
3472  if (!operand)
3473  return failure();
3474 
3475  auto resultType = lowerType(op.getType());
3476 
3477  auto zero = getOrCreateIntConstant(resultType.getIntOrFloatBitWidth(), 0);
3478  return setLoweringTo<comb::SubOp>(op, zero, operand, true);
3479 }
3480 
3481 // Pad is a noop or extension operation.
3482 LogicalResult FIRRTLLowering::visitExpr(PadPrimOp op) {
3483  auto operand = getLoweredAndExtendedValue(op.getInput(), op.getType());
3484  if (!operand)
3485  return failure();
3486  return setLowering(op, operand);
3487 }
3488 
3489 LogicalResult FIRRTLLowering::visitExpr(XorRPrimOp op) {
3490  auto operand = getLoweredValue(op.getInput());
3491  if (!operand) {
3492  return handleZeroBit(op.getInput(), [&]() {
3493  return setLowering(op, getOrCreateIntConstant(1, 0));
3494  });
3495  return failure();
3496  }
3497 
3498  return setLoweringTo<comb::ParityOp>(op, builder.getIntegerType(1), operand,
3499  true);
3500 }
3501 
3502 LogicalResult FIRRTLLowering::visitExpr(AndRPrimOp op) {
3503  auto operand = getLoweredValue(op.getInput());
3504  if (!operand) {
3505  return handleZeroBit(op.getInput(), [&]() {
3506  return setLowering(op, getOrCreateIntConstant(1, 1));
3507  });
3508  }
3509 
3510  // Lower AndR to == -1
3511  return setLoweringTo<comb::ICmpOp>(
3512  op, ICmpPredicate::eq, operand,
3513  getOrCreateIntConstant(
3514  APInt::getAllOnes(operand.getType().getIntOrFloatBitWidth())),
3515  true);
3516 }
3517 
3518 LogicalResult FIRRTLLowering::visitExpr(OrRPrimOp op) {
3519  auto operand = getLoweredValue(op.getInput());
3520  if (!operand) {
3521  return handleZeroBit(op.getInput(), [&]() {
3522  return setLowering(op, getOrCreateIntConstant(1, 0));
3523  });
3524  return failure();
3525  }
3526 
3527  // Lower OrR to != 0
3528  return setLoweringTo<comb::ICmpOp>(
3529  op, ICmpPredicate::ne, operand,
3530  getOrCreateIntConstant(operand.getType().getIntOrFloatBitWidth(), 0),
3531  true);
3532 }
3533 
3534 //===----------------------------------------------------------------------===//
3535 // Binary Operations
3536 //===----------------------------------------------------------------------===//
3537 
3538 template <typename ResultOpType>
3539 LogicalResult FIRRTLLowering::lowerBinOpToVariadic(Operation *op) {
3540  auto resultType = op->getResult(0).getType();
3541  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3542  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3543  if (!lhs || !rhs)
3544  return failure();
3545 
3546  return setLoweringTo<ResultOpType>(op, lhs, rhs, true);
3547 }
3548 
3549 /// Element-wise logical operations can be lowered into bitcast and normal comb
3550 /// operations. Eventually we might want to introduce elementwise operations
3551 /// into HW/SV level as well.
3552 template <typename ResultOpType>
3553 LogicalResult FIRRTLLowering::lowerElementwiseLogicalOp(Operation *op) {
3554  auto resultType = op->getResult(0).getType();
3555  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3556  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3557 
3558  if (!lhs || !rhs)
3559  return failure();
3560  auto bitwidth = firrtl::getBitWidth(type_cast<FIRRTLBaseType>(resultType));
3561 
3562  if (!bitwidth)
3563  return failure();
3564 
3565  // TODO: Introduce elementwise operations to HW dialect instead of abusing
3566  // bitcast operations.
3567  auto intType = builder.getIntegerType(*bitwidth);
3568  auto retType = lhs.getType();
3569  lhs = builder.createOrFold<hw::BitcastOp>(intType, lhs);
3570  rhs = builder.createOrFold<hw::BitcastOp>(intType, rhs);
3571  auto result = builder.createOrFold<ResultOpType>(lhs, rhs, /*twoState=*/true);
3572  return setLoweringTo<hw::BitcastOp>(op, retType, result);
3573 }
3574 
3575 /// lowerBinOp extends each operand to the destination type, then performs the
3576 /// specified binary operator.
3577 template <typename ResultUnsignedOpType, typename ResultSignedOpType>
3578 LogicalResult FIRRTLLowering::lowerBinOp(Operation *op) {
3579  // Extend the two operands to match the destination type.
3580  auto resultType = op->getResult(0).getType();
3581  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3582  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3583  if (!lhs || !rhs)
3584  return failure();
3585 
3586  // Emit the result operation.
3587  if (type_cast<IntType>(resultType).isSigned())
3588  return setLoweringTo<ResultSignedOpType>(op, lhs, rhs, true);
3589  return setLoweringTo<ResultUnsignedOpType>(op, lhs, rhs, true);
3590 }
3591 
3592 /// lowerCmpOp extends each operand to the longest type, then performs the
3593 /// specified binary operator.
3594 LogicalResult FIRRTLLowering::lowerCmpOp(Operation *op, ICmpPredicate signedOp,
3595  ICmpPredicate unsignedOp) {
3596  // Extend the two operands to match the longest type.
3597  auto lhsIntType = type_cast<IntType>(op->getOperand(0).getType());
3598  auto rhsIntType = type_cast<IntType>(op->getOperand(1).getType());
3599  if (!lhsIntType.hasWidth() || !rhsIntType.hasWidth())
3600  return failure();
3601 
3602  auto cmpType = getWidestIntType(lhsIntType, rhsIntType);
3603  if (cmpType.getWidth() == 0) // Handle 0-width inputs by promoting to 1 bit.
3604  cmpType = UIntType::get(builder.getContext(), 1);
3605  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), cmpType);
3606  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), cmpType);
3607  if (!lhs || !rhs)
3608  return failure();
3609 
3610  // Emit the result operation.
3611  Type resultType = builder.getIntegerType(1);
3612  return setLoweringTo<comb::ICmpOp>(
3613  op, resultType, lhsIntType.isSigned() ? signedOp : unsignedOp, lhs, rhs,
3614  true);
3615 }
3616 
3617 /// Lower a divide or dynamic shift, where the operation has to be performed
3618 /// in the widest type of the result and two inputs then truncated down.
3619 template <typename SignedOp, typename UnsignedOp>
3620 LogicalResult FIRRTLLowering::lowerDivLikeOp(Operation *op) {
3621  // hw has equal types for these, firrtl doesn't. The type of the firrtl
3622  // RHS may be wider than the LHS, and we cannot truncate off the high bits
3623  // (because an overlarge amount is supposed to shift in sign or zero bits).
3624  auto opType = type_cast<IntType>(op->getResult(0).getType());
3625  if (opType.getWidth() == 0)
3626  return setLowering(op->getResult(0), Value());
3627 
3628  auto resultType = getWidestIntType(opType, op->getOperand(1).getType());
3629  resultType = getWidestIntType(resultType, op->getOperand(0).getType());
3630  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3631  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3632  if (!lhs || !rhs)
3633  return failure();
3634 
3635  Value result;
3636  if (opType.isSigned())
3637  result = builder.createOrFold<SignedOp>(lhs, rhs, true);
3638  else
3639  result = builder.createOrFold<UnsignedOp>(lhs, rhs, true);
3640 
3641  if (auto *definingOp = result.getDefiningOp())
3642  tryCopyName(definingOp, op);
3643 
3644  if (resultType == opType)
3645  return setLowering(op->getResult(0), result);
3646  return setLoweringTo<comb::ExtractOp>(op, lowerType(opType), result, 0);
3647 }
3648 
3649 LogicalResult FIRRTLLowering::visitExpr(CatPrimOp op) {
3650  auto lhs = getLoweredValue(op.getLhs());
3651  auto rhs = getLoweredValue(op.getRhs());
3652  if (!lhs) {
3653  return handleZeroBit(op.getLhs(), [&]() {
3654  if (rhs) // cat(0bit, x) --> x
3655  return setLowering(op, rhs);
3656  // cat(0bit, 0bit) --> 0bit
3657  return handleZeroBit(op.getRhs(),
3658  [&]() { return setLowering(op, Value()); });
3659  });
3660  }
3661 
3662  if (!rhs) // cat(x, 0bit) --> x
3663  return handleZeroBit(op.getRhs(), [&]() { return setLowering(op, lhs); });
3664 
3665  return setLoweringTo<comb::ConcatOp>(op, lhs, rhs);
3666 }
3667 
3668 //===----------------------------------------------------------------------===//
3669 // Verif Operations
3670 //===----------------------------------------------------------------------===//
3671 
3672 LogicalResult FIRRTLLowering::visitExpr(IsXIntrinsicOp op) {
3673  auto input = getLoweredNonClockValue(op.getArg());
3674  if (!input)
3675  return failure();
3676 
3677  if (!isa<IntType>(input.getType())) {
3678  auto srcType = op.getArg().getType();
3679  auto bitwidth = firrtl::getBitWidth(type_cast<FIRRTLBaseType>(srcType));
3680  assert(bitwidth && "Unknown width");
3681  auto intType = builder.getIntegerType(*bitwidth);
3682  input = builder.createOrFold<hw::BitcastOp>(intType, input);
3683  }
3684 
3685  return setLoweringTo<comb::ICmpOp>(
3686  op, ICmpPredicate::ceq, input,
3687  getOrCreateXConstant(input.getType().getIntOrFloatBitWidth()), true);
3688 }
3689 
3690 LogicalResult FIRRTLLowering::visitStmt(FPGAProbeIntrinsicOp op) {
3691  auto operand = getLoweredValue(op.getInput());
3692  builder.create<hw::WireOp>(operand);
3693  return success();
3694 }
3695 
3696 LogicalResult FIRRTLLowering::visitExpr(PlusArgsTestIntrinsicOp op) {
3697  return setLoweringTo<sim::PlusArgsTestOp>(op, builder.getIntegerType(1),
3698  op.getFormatStringAttr());
3699 }
3700 
3701 LogicalResult FIRRTLLowering::visitExpr(PlusArgsValueIntrinsicOp op) {
3702  auto type = lowerType(op.getResult().getType());
3703  if (!type)
3704  return failure();
3705 
3706  auto valueOp = builder.create<sim::PlusArgsValueOp>(
3707  builder.getIntegerType(1), type, op.getFormatStringAttr());
3708  if (failed(setLowering(op.getResult(), valueOp.getResult())))
3709  return failure();
3710  if (failed(setLowering(op.getFound(), valueOp.getFound())))
3711  return failure();
3712  return success();
3713 }
3714 
3715 LogicalResult FIRRTLLowering::visitExpr(SizeOfIntrinsicOp op) {
3716  op.emitError("SizeOf should have been resolved.");
3717  return failure();
3718 }
3719 
3720 LogicalResult FIRRTLLowering::visitExpr(ClockGateIntrinsicOp op) {
3721  Value testEnable;
3722  if (op.getTestEnable())
3723  testEnable = getLoweredValue(op.getTestEnable());
3724  return setLoweringTo<seq::ClockGateOp>(
3725  op, getLoweredValue(op.getInput()), getLoweredValue(op.getEnable()),
3726  testEnable, /*inner_sym=*/hw::InnerSymAttr{});
3727 }
3728 
3729 LogicalResult FIRRTLLowering::visitExpr(ClockInverterIntrinsicOp op) {
3730  auto operand = getLoweredValue(op.getInput());
3731  return setLoweringTo<seq::ClockInverterOp>(op, operand);
3732 }
3733 
3734 LogicalResult FIRRTLLowering::visitExpr(ClockDividerIntrinsicOp op) {
3735  auto operand = getLoweredValue(op.getInput());
3736  return setLoweringTo<seq::ClockDividerOp>(op, operand, op.getPow2());
3737 }
3738 
3739 LogicalResult FIRRTLLowering::visitExpr(LTLAndIntrinsicOp op) {
3740  return setLoweringToLTL<ltl::AndOp>(
3741  op,
3742  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3743 }
3744 
3745 LogicalResult FIRRTLLowering::visitExpr(LTLOrIntrinsicOp op) {
3746  return setLoweringToLTL<ltl::OrOp>(
3747  op,
3748  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3749 }
3750 
3751 LogicalResult FIRRTLLowering::visitExpr(LTLIntersectIntrinsicOp op) {
3752  return setLoweringToLTL<ltl::IntersectOp>(
3753  op,
3754  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3755 }
3756 
3757 LogicalResult FIRRTLLowering::visitExpr(LTLDelayIntrinsicOp op) {
3758  return setLoweringToLTL<ltl::DelayOp>(op, getLoweredValue(op.getInput()),
3759  op.getDelayAttr(), op.getLengthAttr());
3760 }
3761 
3762 LogicalResult FIRRTLLowering::visitExpr(LTLConcatIntrinsicOp op) {
3763  return setLoweringToLTL<ltl::ConcatOp>(
3764  op,
3765  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3766 }
3767 
3768 LogicalResult FIRRTLLowering::visitExpr(LTLRepeatIntrinsicOp op) {
3769  return setLoweringToLTL<ltl::RepeatOp>(op, getLoweredValue(op.getInput()),
3770  op.getBaseAttr(), op.getMoreAttr());
3771 }
3772 
3773 LogicalResult FIRRTLLowering::visitExpr(LTLGoToRepeatIntrinsicOp op) {
3774  return setLoweringToLTL<ltl::GoToRepeatOp>(
3775  op, getLoweredValue(op.getInput()), op.getBaseAttr(), op.getMoreAttr());
3776 }
3777 
3778 LogicalResult FIRRTLLowering::visitExpr(LTLNonConsecutiveRepeatIntrinsicOp op) {
3779  return setLoweringToLTL<ltl::NonConsecutiveRepeatOp>(
3780  op, getLoweredValue(op.getInput()), op.getBaseAttr(), op.getMoreAttr());
3781 }
3782 
3783 LogicalResult FIRRTLLowering::visitExpr(LTLNotIntrinsicOp op) {
3784  return setLoweringToLTL<ltl::NotOp>(op, getLoweredValue(op.getInput()));
3785 }
3786 
3787 LogicalResult FIRRTLLowering::visitExpr(LTLImplicationIntrinsicOp op) {
3788  return setLoweringToLTL<ltl::ImplicationOp>(
3789  op,
3790  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3791 }
3792 
3793 LogicalResult FIRRTLLowering::visitExpr(LTLUntilIntrinsicOp op) {
3794  return setLoweringToLTL<ltl::UntilOp>(
3795  op,
3796  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3797 }
3798 
3799 LogicalResult FIRRTLLowering::visitExpr(LTLEventuallyIntrinsicOp op) {
3800  return setLoweringToLTL<ltl::EventuallyOp>(op,
3801  getLoweredValue(op.getInput()));
3802 }
3803 
3804 LogicalResult FIRRTLLowering::visitExpr(LTLClockIntrinsicOp op) {
3805  return setLoweringToLTL<ltl::ClockOp>(op, getLoweredValue(op.getInput()),
3806  ltl::ClockEdge::Pos,
3807  getLoweredNonClockValue(op.getClock()));
3808 }
3809 
3810 template <typename TargetOp, typename IntrinsicOp>
3811 LogicalResult FIRRTLLowering::lowerVerifIntrinsicOp(IntrinsicOp op) {
3812  auto property = getLoweredValue(op.getProperty());
3813  auto enable = op.getEnable() ? getLoweredValue(op.getEnable()) : Value();
3814  builder.create<TargetOp>(property, enable, op.getLabelAttr());
3815  return success();
3816 }
3817 
3818 LogicalResult FIRRTLLowering::visitStmt(VerifAssertIntrinsicOp op) {
3819  return lowerVerifIntrinsicOp<verif::AssertOp>(op);
3820 }
3821 
3822 LogicalResult FIRRTLLowering::visitStmt(VerifAssumeIntrinsicOp op) {
3823  return lowerVerifIntrinsicOp<verif::AssumeOp>(op);
3824 }
3825 
3826 LogicalResult FIRRTLLowering::visitStmt(VerifCoverIntrinsicOp op) {
3827  return lowerVerifIntrinsicOp<verif::CoverOp>(op);
3828 }
3829 
3830 LogicalResult FIRRTLLowering::visitExpr(HasBeenResetIntrinsicOp op) {
3831  auto clock = getLoweredNonClockValue(op.getClock());
3832  auto reset = getLoweredValue(op.getReset());
3833  if (!clock || !reset)
3834  return failure();
3835  auto resetType = op.getReset().getType();
3836  auto uintResetType = dyn_cast<UIntType>(resetType);
3837  auto isSync = uintResetType && uintResetType.getWidth() == 1;
3838  auto isAsync = isa<AsyncResetType>(resetType);
3839  if (!isAsync && !isSync) {
3840  auto d = op.emitError("uninferred reset passed to 'has_been_reset'; "
3841  "requires sync or async reset");
3842  d.attachNote() << "reset is of type " << resetType
3843  << ", should be '!firrtl.uint<1>' or '!firrtl.asyncreset'";
3844  return failure();
3845  }
3846  return setLoweringTo<verif::HasBeenResetOp>(op, clock, reset, isAsync);
3847 }
3848 
3849 //===----------------------------------------------------------------------===//
3850 // Other Operations
3851 //===----------------------------------------------------------------------===//
3852 
3853 LogicalResult FIRRTLLowering::visitExpr(BitsPrimOp op) {
3854  auto input = getLoweredValue(op.getInput());
3855  if (!input)
3856  return failure();
3857 
3858  Type resultType = builder.getIntegerType(op.getHi() - op.getLo() + 1);
3859  return setLoweringTo<comb::ExtractOp>(op, resultType, input, op.getLo());
3860 }
3861 
3862 LogicalResult FIRRTLLowering::visitExpr(InvalidValueOp op) {
3863  auto resultTy = lowerType(op.getType());
3864  if (!resultTy)
3865  return failure();
3866 
3867  // Values of analog type always need to be lowered to something with inout
3868  // type. We do that by lowering to a wire and return that. As with the
3869  // SFC, we do not connect anything to this, because it is bidirectional.
3870  if (type_isa<AnalogType>(op.getType()))
3871  // This is a locally visible, private wire created by the compiler, so do
3872  // not attach a symbol name.
3873  return setLoweringTo<sv::WireOp>(op, resultTy, ".invalid_analog");
3874 
3875  // We don't allow aggregate values which contain values of analog types.
3876  if (type_cast<FIRRTLBaseType>(op.getType()).containsAnalog())
3877  return failure();
3878 
3879  // We lower invalid to 0. TODO: the FIRRTL spec mentions something about
3880  // lowering it to a random value, we should see if this is what we need to
3881  // do.
3882  if (auto bitwidth =
3883  firrtl::getBitWidth(type_cast<FIRRTLBaseType>(op.getType()))) {
3884  if (*bitwidth == 0) // Let the caller handle zero width values.
3885  return failure();
3886 
3887  auto constant = getOrCreateIntConstant(*bitwidth, 0);
3888  // If the result is an aggregate value, we have to bitcast the constant.
3889  if (!type_isa<IntegerType>(resultTy))
3890  constant = builder.create<hw::BitcastOp>(resultTy, constant);
3891  return setLowering(op, constant);
3892  }
3893 
3894  // Invalid for bundles isn't supported.
3895  op.emitOpError("unsupported type");
3896  return failure();
3897 }
3898 
3899 LogicalResult FIRRTLLowering::visitExpr(HeadPrimOp op) {
3900  auto input = getLoweredValue(op.getInput());
3901  if (!input)
3902  return failure();
3903  auto inWidth = type_cast<IntegerType>(input.getType()).getWidth();
3904  if (op.getAmount() == 0)
3905  return setLowering(op, Value());
3906  Type resultType = builder.getIntegerType(op.getAmount());
3907  return setLoweringTo<comb::ExtractOp>(op, resultType, input,
3908  inWidth - op.getAmount());
3909 }
3910 
3911 LogicalResult FIRRTLLowering::visitExpr(ShlPrimOp op) {
3912  auto input = getLoweredValue(op.getInput());
3913  if (!input) {
3914  return handleZeroBit(op.getInput(), [&]() {
3915  if (op.getAmount() == 0)
3916  return failure();
3917  return setLowering(op, getOrCreateIntConstant(op.getAmount(), 0));
3918  });
3919  }
3920 
3921  // Handle the degenerate case.
3922  if (op.getAmount() == 0)
3923  return setLowering(op, input);
3924 
3925  auto zero = getOrCreateIntConstant(op.getAmount(), 0);
3926  return setLoweringTo<comb::ConcatOp>(op, input, zero);
3927 }
3928 
3929 LogicalResult FIRRTLLowering::visitExpr(ShrPrimOp op) {
3930  auto input = getLoweredValue(op.getInput());
3931  if (!input)
3932  return failure();
3933 
3934  // Handle the special degenerate cases.
3935  auto inWidth = type_cast<IntegerType>(input.getType()).getWidth();
3936  auto shiftAmount = op.getAmount();
3937  if (shiftAmount >= inWidth) {
3938  // Unsigned shift by full width returns a single-bit zero.
3939  if (type_cast<IntType>(op.getInput().getType()).isUnsigned())
3940  return setLowering(op, {});
3941 
3942  // Signed shift by full width is equivalent to extracting the sign bit.
3943  shiftAmount = inWidth - 1;
3944  }
3945 
3946  Type resultType = builder.getIntegerType(inWidth - shiftAmount);
3947  return setLoweringTo<comb::ExtractOp>(op, resultType, input, shiftAmount);
3948 }
3949 
3950 LogicalResult FIRRTLLowering::visitExpr(TailPrimOp op) {
3951  auto input = getLoweredValue(op.getInput());
3952  if (!input)
3953  return failure();
3954 
3955  auto inWidth = type_cast<IntegerType>(input.getType()).getWidth();
3956  if (inWidth == op.getAmount())
3957  return setLowering(op, Value());
3958  Type resultType = builder.getIntegerType(inWidth - op.getAmount());
3959  return setLoweringTo<comb::ExtractOp>(op, resultType, input, 0);
3960 }
3961 
3962 LogicalResult FIRRTLLowering::visitExpr(MuxPrimOp op) {
3963  auto cond = getLoweredValue(op.getSel());
3964  auto ifTrue = getLoweredAndExtendedValue(op.getHigh(), op.getType());
3965  auto ifFalse = getLoweredAndExtendedValue(op.getLow(), op.getType());
3966  if (!cond || !ifTrue || !ifFalse)
3967  return failure();
3968 
3969  if (isa<ClockType>(op.getType()))
3970  return setLoweringTo<seq::ClockMuxOp>(op, cond, ifTrue, ifFalse);
3971  return setLoweringTo<comb::MuxOp>(op, ifTrue.getType(), cond, ifTrue, ifFalse,
3972  true);
3973 }
3974 
3975 LogicalResult FIRRTLLowering::visitExpr(Mux2CellIntrinsicOp op) {
3976  auto cond = getLoweredValue(op.getSel());
3977  auto ifTrue = getLoweredAndExtendedValue(op.getHigh(), op.getType());
3978  auto ifFalse = getLoweredAndExtendedValue(op.getLow(), op.getType());
3979  if (!cond || !ifTrue || !ifFalse)
3980  return failure();
3981 
3982  auto val = builder.create<comb::MuxOp>(ifTrue.getType(), cond, ifTrue,
3983  ifFalse, true);
3984  return setLowering(op, createValueWithMuxAnnotation(val, true));
3985 }
3986 
3987 LogicalResult FIRRTLLowering::visitExpr(Mux4CellIntrinsicOp op) {
3988  auto sel = getLoweredValue(op.getSel());
3989  auto v3 = getLoweredAndExtendedValue(op.getV3(), op.getType());
3990  auto v2 = getLoweredAndExtendedValue(op.getV2(), op.getType());
3991  auto v1 = getLoweredAndExtendedValue(op.getV1(), op.getType());
3992  auto v0 = getLoweredAndExtendedValue(op.getV0(), op.getType());
3993  if (!sel || !v3 || !v2 || !v1 || !v0)
3994  return failure();
3995  Value array[] = {v3, v2, v1, v0};
3996  auto create = builder.create<hw::ArrayCreateOp>(array);
3997  auto val = builder.create<hw::ArrayGetOp>(create, sel);
3998  return setLowering(op, createValueWithMuxAnnotation(val, false));
3999 }
4000 
4001 // Construct a value with vendor specific pragmas to utilize MUX cells.
4002 // Specifically we annotate pragmas in the following form.
4003 //
4004 // For an array indexing:
4005 // ```
4006 // wire GEN;
4007 // /* synopsys infer_mux_override */
4008 // assign GEN = array[index] /* cadence map_to_mux */;
4009 // ```
4010 //
4011 // For a mux:
4012 // ```
4013 // wire GEN;
4014 // /* synopsys infer_mux_override */
4015 // assign GEN = sel ? /* cadence map_to_mux */ high : low;
4016 // ```
4017 Value FIRRTLLowering::createValueWithMuxAnnotation(Operation *op, bool isMux2) {
4018  assert(op->getNumResults() == 1 && "only expect a single result");
4019  auto val = op->getResult(0);
4020  auto valWire = builder.create<sv::WireOp>(val.getType());
4021  // Use SV attributes to annotate pragmas.
4023  op, sv::SVAttributeAttr::get(builder.getContext(), "cadence map_to_mux",
4024  /*emitAsComment=*/true));
4025 
4026  // For operands, create temporary wires with optimization blockers(inner
4027  // symbols) so that the AST structure will never be destoyed in the later
4028  // pipeline.
4029  {
4030  OpBuilder::InsertionGuard guard(builder);
4031  builder.setInsertionPoint(op);
4032  StringRef namehint = isMux2 ? "mux2cell_in" : "mux4cell_in";
4033  for (auto [idx, operand] : llvm::enumerate(op->getOperands())) {
4034  auto [innerSym, _] = getOrAddInnerSym(
4035  op->getContext(), /*attr=*/nullptr, 0,
4036  [&]() -> hw::InnerSymbolNamespace & { return moduleNamespace; });
4037  auto wire =
4038  builder.create<hw::WireOp>(operand, namehint + Twine(idx), innerSym);
4039  op->setOperand(idx, wire);
4040  }
4041  }
4042 
4043  auto assignOp = builder.create<sv::AssignOp>(valWire, val);
4044  sv::setSVAttributes(assignOp,
4045  sv::SVAttributeAttr::get(builder.getContext(),
4046  "synopsys infer_mux_override",
4047  /*emitAsComment=*/true));
4048  return builder.create<sv::ReadInOutOp>(valWire);
4049 }
4050 
4051 Value FIRRTLLowering::createArrayIndexing(Value array, Value index) {
4052 
4053  auto size = hw::type_cast<hw::ArrayType>(array.getType()).getNumElements();
4054  // Extend to power of 2. FIRRTL semantics say out-of-bounds access result in
4055  // an indeterminate value. Existing chisel code depends on this behavior
4056  // being "return index 0". Ideally, we would tail extend the array to improve
4057  // optimization.
4058  if (!llvm::isPowerOf2_64(size)) {
4059  auto extElem = getOrCreateIntConstant(APInt(llvm::Log2_64_Ceil(size), 0));
4060  auto extValue = builder.create<hw::ArrayGetOp>(array, extElem);
4061  SmallVector<Value> temp(llvm::NextPowerOf2(size) - size, extValue);
4062  auto ext = builder.create<hw::ArrayCreateOp>(temp);
4063  Value temp2[] = {ext.getResult(), array};
4064  array = builder.create<hw::ArrayConcatOp>(temp2);
4065  }
4066 
4067  Value inBoundsRead = builder.create<hw::ArrayGetOp>(array, index);
4068 
4069  return inBoundsRead;
4070 }
4071 
4072 LogicalResult FIRRTLLowering::visitExpr(MultibitMuxOp op) {
4073  // Lower and resize to the index width.
4074  auto index = getLoweredAndExtOrTruncValue(
4075  op.getIndex(),
4076  UIntType::get(op.getContext(),
4077  getBitWidthFromVectorSize(op.getInputs().size())));
4078 
4079  if (!index)
4080  return failure();
4081  SmallVector<Value> loweredInputs;
4082  loweredInputs.reserve(op.getInputs().size());
4083  for (auto input : op.getInputs()) {
4084  auto lowered = getLoweredAndExtendedValue(input, op.getType());
4085  if (!lowered)
4086  return failure();
4087  loweredInputs.push_back(lowered);
4088  }
4089 
4090  Value array = builder.create<hw::ArrayCreateOp>(loweredInputs);
4091  return setLowering(op, createArrayIndexing(array, index));
4092 }
4093 
4094 LogicalResult FIRRTLLowering::visitExpr(VerbatimExprOp op) {
4095  auto resultTy = lowerType(op.getType());
4096  if (!resultTy)
4097  return failure();
4098 
4099  SmallVector<Value, 4> operands;
4100  operands.reserve(op.getSubstitutions().size());
4101  for (auto operand : op.getSubstitutions()) {
4102  auto lowered = getLoweredValue(operand);
4103  if (!lowered)
4104  return failure();
4105  operands.push_back(lowered);
4106  }
4107 
4108  ArrayAttr symbols = op.getSymbolsAttr();
4109  if (!symbols)
4110  symbols = ArrayAttr::get(op.getContext(), {});
4111 
4112  return setLoweringTo<sv::VerbatimExprOp>(op, resultTy, op.getTextAttr(),
4113  operands, symbols);
4114 }
4115 
4116 LogicalResult FIRRTLLowering::visitExpr(XMRRefOp op) {
4117  // This XMR is accessed solely by FIRRTL statements that mutate the probe.
4118  // To avoid the use of clock wires, create an `i1` wire and ensure that
4119  // all connections are also of the `i1` type.
4120  Type baseType = op.getType().getType();
4121 
4122  Type xmrType;
4123  if (isa<ClockType>(baseType))
4124  xmrType = builder.getIntegerType(1);
4125  else
4126  xmrType = lowerType(baseType);
4127 
4128  return setLoweringTo<sv::XMRRefOp>(op, sv::InOutType::get(xmrType),
4129  op.getRef(), op.getVerbatimSuffixAttr());
4130 }
4131 
4132 LogicalResult FIRRTLLowering::visitExpr(XMRDerefOp op) {
4133  // When an XMR targets a clock wire, replace it with an `i1` wire, but
4134  // introduce a clock-typed read op into the design afterwards.
4135  Type xmrType;
4136  if (isa<ClockType>(op.getType()))
4137  xmrType = builder.getIntegerType(1);
4138  else
4139  xmrType = lowerType(op.getType());
4140 
4141  auto xmr = builder.create<sv::XMRRefOp>(
4142  sv::InOutType::get(xmrType), op.getRef(), op.getVerbatimSuffixAttr());
4143  auto readXmr = getReadValue(xmr);
4144  if (!isa<ClockType>(op.getType()))
4145  return setLowering(op, readXmr);
4146  return setLoweringTo<seq::ToClockOp>(op, readXmr);
4147 }
4148 
4149 //===----------------------------------------------------------------------===//
4150 // Statements
4151 //===----------------------------------------------------------------------===//
4152 
4153 LogicalResult FIRRTLLowering::visitStmt(SkipOp op) {
4154  // Nothing! We could emit an comment as a verbatim op if there were a
4155  // reason to.
4156  return success();
4157 }
4158 
4159 /// Resolve a connection to `destVal`, an `hw::WireOp` or `seq::FirRegOp`, by
4160 /// updating the input operand to be `srcVal`. Returns true if the update was
4161 /// made and the connection can be considered lowered. Returns false if the
4162 /// destination isn't a wire or register with an input operand to be updated.
4163 /// Returns failure if the destination is a subaccess operation. These should be
4164 /// transposed to the right-hand-side by a pre-pass.
4165 FailureOr<bool> FIRRTLLowering::lowerConnect(Value destVal, Value srcVal) {
4166  auto srcType = srcVal.getType();
4167  auto dstType = destVal.getType();
4168  if (srcType != dstType &&
4169  (isa<hw::TypeAliasType>(srcType) || isa<hw::TypeAliasType>(dstType))) {
4170  srcVal = builder.create<hw::BitcastOp>(destVal.getType(), srcVal);
4171  }
4172  return TypeSwitch<Operation *, FailureOr<bool>>(destVal.getDefiningOp())
4173  .Case<hw::WireOp>([&](auto op) {
4174  maybeUnused(op.getInput());
4175  op.getInputMutable().assign(srcVal);
4176  return true;
4177  })
4178  .Case<seq::FirRegOp>([&](auto op) {
4179  maybeUnused(op.getNext());
4180  op.getNextMutable().assign(srcVal);
4181  return true;
4182  })
4183  .Case<hw::StructExtractOp, hw::ArrayGetOp>([](auto op) {
4184  // NOTE: msvc thinks `return op.emitOpError(...);` is ambiguous. So
4185  // return `failure()` separately.
4186  op.emitOpError("used as connect destination");
4187  return failure();
4188  })
4189  .Default([](auto) { return false; });
4190 }
4191 
4192 LogicalResult FIRRTLLowering::visitStmt(ConnectOp op) {
4193  auto dest = op.getDest();
4194  // The source can be a smaller integer, extend it as appropriate if so.
4195  auto destType = type_cast<FIRRTLBaseType>(dest.getType()).getPassiveType();
4196  auto srcVal = getLoweredAndExtendedValue(op.getSrc(), destType);
4197  if (!srcVal)
4198  return handleZeroBit(op.getSrc(), []() { return success(); });
4199 
4200  auto destVal = getPossiblyInoutLoweredValue(dest);
4201  if (!destVal)
4202  return failure();
4203 
4204  auto result = lowerConnect(destVal, srcVal);
4205  if (failed(result))
4206  return failure();
4207  if (*result)
4208  return success();
4209 
4210  // If this connect is driving a value that is currently a backedge, record
4211  // that the source is the value of the backedge.
4212  if (updateIfBackedge(destVal, srcVal))
4213  return success();
4214 
4215  if (!isa<hw::InOutType>(destVal.getType()))
4216  return op.emitError("destination isn't an inout type");
4217 
4218  builder.create<sv::AssignOp>(destVal, srcVal);
4219  return success();
4220 }
4221 
4222 LogicalResult FIRRTLLowering::visitStmt(MatchingConnectOp op) {
4223  auto dest = op.getDest();
4224  auto srcVal = getLoweredValue(op.getSrc());
4225  if (!srcVal)
4226  return handleZeroBit(op.getSrc(), []() { return success(); });
4227 
4228  auto destVal = getPossiblyInoutLoweredValue(dest);
4229  if (!destVal)
4230  return failure();
4231 
4232  auto result = lowerConnect(destVal, srcVal);
4233  if (failed(result))
4234  return failure();
4235  if (*result)
4236  return success();
4237 
4238  // If this connect is driving a value that is currently a backedge, record
4239  // that the source is the value of the backedge.
4240  if (updateIfBackedge(destVal, srcVal))
4241  return success();
4242 
4243  if (!isa<hw::InOutType>(destVal.getType()))
4244  return op.emitError("destination isn't an inout type");
4245 
4246  builder.create<sv::AssignOp>(destVal, srcVal);
4247  return success();
4248 }
4249 
4250 LogicalResult FIRRTLLowering::visitStmt(ForceOp op) {
4251  auto srcVal = getLoweredValue(op.getSrc());
4252  if (!srcVal)
4253  return failure();
4254 
4255  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4256  if (!destVal)
4257  return failure();
4258 
4259  if (!isa<hw::InOutType>(destVal.getType()))
4260  return op.emitError("destination isn't an inout type");
4261 
4262  // #ifndef SYNTHESIS
4263  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4264  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4265  addToInitialBlock([&]() { builder.create<sv::ForceOp>(destVal, srcVal); });
4266  });
4267  return success();
4268 }
4269 
4270 LogicalResult FIRRTLLowering::visitStmt(RefForceOp op) {
4271  auto src = getLoweredNonClockValue(op.getSrc());
4272  auto clock = getLoweredNonClockValue(op.getClock());
4273  auto pred = getLoweredValue(op.getPredicate());
4274  if (!src || !clock || !pred)
4275  return failure();
4276 
4277  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4278  if (!destVal)
4279  return failure();
4280 
4281  // #ifndef SYNTHESIS
4282  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4283  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4284  addToAlwaysBlock(clock, [&]() {
4285  addIfProceduralBlock(
4286  pred, [&]() { builder.create<sv::ForceOp>(destVal, src); });
4287  });
4288  });
4289  return success();
4290 }
4291 LogicalResult FIRRTLLowering::visitStmt(RefForceInitialOp op) {
4292  auto src = getLoweredNonClockValue(op.getSrc());
4293  auto pred = getLoweredValue(op.getPredicate());
4294  if (!src || !pred)
4295  return failure();
4296 
4297  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4298  if (!destVal)
4299  return failure();
4300 
4301  // #ifndef SYNTHESIS
4302  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4303  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4304  addToInitialBlock([&]() {
4305  addIfProceduralBlock(
4306  pred, [&]() { builder.create<sv::ForceOp>(destVal, src); });
4307  });
4308  });
4309  return success();
4310 }
4311 LogicalResult FIRRTLLowering::visitStmt(RefReleaseOp op) {
4312  auto clock = getLoweredNonClockValue(op.getClock());
4313  auto pred = getLoweredValue(op.getPredicate());
4314  if (!clock || !pred)
4315  return failure();
4316 
4317  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4318  if (!destVal)
4319  return failure();
4320 
4321  // #ifndef SYNTHESIS
4322  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4323  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4324  addToAlwaysBlock(clock, [&]() {
4325  addIfProceduralBlock(pred,
4326  [&]() { builder.create<sv::ReleaseOp>(destVal); });
4327  });
4328  });
4329  return success();
4330 }
4331 LogicalResult FIRRTLLowering::visitStmt(RefReleaseInitialOp op) {
4332  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4333  auto pred = getLoweredValue(op.getPredicate());
4334  if (!destVal || !pred)
4335  return failure();
4336 
4337  // #ifndef SYNTHESIS
4338  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4339  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4340  addToInitialBlock([&]() {
4341  addIfProceduralBlock(pred,
4342  [&]() { builder.create<sv::ReleaseOp>(destVal); });
4343  });
4344  });
4345  return success();
4346 }
4347 
4348 // Printf is a macro op that lowers to an sv.ifdef.procedural, an sv.if,
4349 // and an sv.fwrite all nested together.
4350 LogicalResult FIRRTLLowering::visitStmt(PrintFOp op) {
4351  auto clock = getLoweredNonClockValue(op.getClock());
4352  auto cond = getLoweredValue(op.getCond());
4353  if (!clock || !cond)
4354  return failure();
4355 
4356  SmallVector<Value, 4> operands;
4357  operands.reserve(op.getSubstitutions().size());
4358  for (auto operand : op.getSubstitutions()) {
4359  Value loweredValue = getLoweredFmtOperand(operand);
4360  if (!loweredValue)
4361  return failure();
4362  operands.push_back(loweredValue);
4363  }
4364 
4365  // Emit an "#ifndef SYNTHESIS" guard into the always block.
4366  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4367  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4368  addToAlwaysBlock(clock, [&]() {
4369  circuitState.usedPrintfCond = true;
4370  circuitState.addFragment(theModule, "PRINTF_COND_FRAGMENT");
4371 
4372  // Emit an "sv.if '`PRINTF_COND_ & cond' into the #ifndef.
4373  Value ifCond =
4374  builder.create<sv::MacroRefExprOp>(cond.getType(), "PRINTF_COND_");
4375  ifCond = builder.createOrFold<comb::AndOp>(ifCond, cond, true);
4376 
4377  addIfProceduralBlock(ifCond, [&]() {
4378  // Emit the sv.fwrite, writing to stderr by default.
4379  Value fdStderr = builder.create<hw::ConstantOp>(APInt(32, 0x80000002));
4380  builder.create<sv::FWriteOp>(fdStderr, op.getFormatString(), operands);
4381  });
4382  });
4383  });
4384 
4385  return success();
4386 }
4387 
4388 // Stop lowers into a nested series of behavioral statements plus $fatal
4389 // or $finish.
4390 LogicalResult FIRRTLLowering::visitStmt(StopOp op) {
4391  auto clock = getLoweredValue(op.getClock());
4392  auto cond = getLoweredValue(op.getCond());
4393  if (!clock || !cond)
4394  return failure();
4395 
4396  circuitState.usedStopCond = true;
4397  circuitState.addFragment(theModule, "STOP_COND_FRAGMENT");
4398 
4399  Value stopCond =
4400  builder.create<sv::MacroRefExprOp>(cond.getType(), "STOP_COND_");
4401  Value exitCond = builder.createOrFold<comb::AndOp>(stopCond, cond, true);
4402 
4403  if (op.getExitCode())
4404  builder.create<sim::FatalOp>(clock, exitCond);
4405  else
4406  builder.create<sim::FinishOp>(clock, exitCond);
4407 
4408  return success();
4409 }
4410 
4411 /// Helper function to build an immediate assert operation based on the
4412 /// original FIRRTL operation name. This reduces code duplication in
4413 /// `lowerVerificationStatement`.
4414 template <typename... Args>
4415 static Operation *buildImmediateVerifOp(ImplicitLocOpBuilder &builder,
4416  StringRef opName, Args &&...args) {
4417  if (opName == "assert")
4418  return builder.create<sv::AssertOp>(std::forward<Args>(args)...);
4419  if (opName == "assume")
4420  return builder.create<sv::AssumeOp>(std::forward<Args>(args)...);
4421  if (opName == "cover")
4422  return builder.create<sv::CoverOp>(std::forward<Args>(args)...);
4423  llvm_unreachable("unknown verification op");
4424 }
4425 
4426 /// Helper function to build a concurrent assert operation based on the
4427 /// original FIRRTL operation name. This reduces code duplication in
4428 /// `lowerVerificationStatement`.
4429 template <typename... Args>
4430 static Operation *buildConcurrentVerifOp(ImplicitLocOpBuilder &builder,
4431  StringRef opName, Args &&...args) {
4432  if (opName == "assert")
4433  return builder.create<sv::AssertConcurrentOp>(std::forward<Args>(args)...);
4434  if (opName == "assume")
4435  return builder.create<sv::AssumeConcurrentOp>(std::forward<Args>(args)...);
4436  if (opName == "cover")
4437  return builder.create<sv::CoverConcurrentOp>(std::forward<Args>(args)...);
4438  llvm_unreachable("unknown verification op");
4439 }
4440 
4441 /// Template for lowering verification statements from type A to
4442 /// type B.
4443 ///
4444 /// For example, lowering the "foo" op to the "bar" op would start
4445 /// with:
4446 ///
4447 /// foo(clock, condition, enable, "message")
4448 ///
4449 /// This becomes a Verilog clocking block with the "bar" op guarded
4450 /// by an if enable:
4451 ///
4452 /// always @(posedge clock) begin
4453 /// if (enable) begin
4454 /// bar(condition);
4455 /// end
4456 /// end
4457 /// The above can also be reduced into a concurrent verification statement
4458 /// sv.assert.concurrent posedge %clock (condition && enable)
4459 LogicalResult FIRRTLLowering::lowerVerificationStatement(
4460  Operation *op, StringRef labelPrefix, Value opClock, Value opPredicate,
4461  Value opEnable, StringAttr opMessageAttr, ValueRange opOperands,
4462  StringAttr opNameAttr, bool isConcurrent, EventControl opEventControl) {
4463  StringRef opName = op->getName().stripDialect();
4464 
4465  // The attribute holding the compile guards
4466  ArrayRef<Attribute> guards{};
4467  if (auto guardsAttr = op->template getAttrOfType<ArrayAttr>("guards"))
4468  guards = guardsAttr.getValue();
4469 
4470  auto isCover = isa<CoverOp>(op);
4471  auto clock = getLoweredNonClockValue(opClock);
4472  auto enable = getLoweredValue(opEnable);
4473  auto predicate = getLoweredValue(opPredicate);
4474  if (!clock || !enable || !predicate)
4475  return failure();
4476 
4477  StringAttr label;
4478  if (opNameAttr && !opNameAttr.getValue().empty())
4479  label = opNameAttr;
4480  StringAttr prefixedLabel;
4481  if (label)
4482  prefixedLabel =
4483  StringAttr::get(builder.getContext(), labelPrefix + label.getValue());
4484 
4485  StringAttr message;
4486  SmallVector<Value> messageOps;
4487  VerificationFlavor flavor = circuitState.verificationFlavor;
4488 
4489  // For non-assertion, rollback to per-op configuration.
4490  if (flavor == VerificationFlavor::IfElseFatal && !isa<AssertOp>(op))
4491  flavor = VerificationFlavor::None;
4492 
4493  if (flavor == VerificationFlavor::None) {
4494  // TODO: This should *not* be part of the op, but rather a lowering
4495  // option that the user of this pass can choose.
4496 
4497  auto format = op->getAttrOfType<StringAttr>("format");
4498  // if-else-fatal iff concurrent and the format is specified.
4499  if (isConcurrent && format && format.getValue() == "ifElseFatal") {
4500  if (!isa<AssertOp>(op))
4501  return op->emitError()
4502  << "ifElseFatal format cannot be used for non-assertions";
4503  flavor = VerificationFlavor::IfElseFatal;
4504  } else if (isConcurrent)
4505  flavor = VerificationFlavor::SVA;
4506  else
4507  flavor = VerificationFlavor::Immediate;
4508  }
4509 
4510  if (!isCover && opMessageAttr && !opMessageAttr.getValue().empty()) {
4511  message = opMessageAttr;
4512  for (auto operand : opOperands) {
4513  auto loweredValue = getLoweredFmtOperand(operand);
4514  if (!loweredValue)
4515  return failure();
4516 
4517  // For SVA assert/assume statements, wrap any message ops in $sampled() to
4518  // guarantee that these will print with the same value as when the
4519  // assertion triggers. (See SystemVerilog 2017 spec section 16.9.3 for
4520  // more information.)
4521  if (flavor == VerificationFlavor::SVA)
4522  loweredValue = builder.create<sv::SampledOp>(loweredValue);
4523  messageOps.push_back(loweredValue);
4524  }
4525  }
4526 
4527  auto emit = [&]() {
4528  switch (flavor) {
4529  case VerificationFlavor::Immediate: {
4530  // Handle the purely procedural flavor of the operation.
4531  auto deferImmediate = circt::sv::DeferAssertAttr::get(
4532  builder.getContext(), circt::sv::DeferAssert::Immediate);
4533  addToAlwaysBlock(clock, [&]() {
4534  addIfProceduralBlock(enable, [&]() {
4535  buildImmediateVerifOp(builder, opName, predicate, deferImmediate,
4536  prefixedLabel, message, messageOps);
4537  });
4538  });
4539  return;
4540  }
4541  case VerificationFlavor::IfElseFatal: {
4542  assert(isa<AssertOp>(op) && "only assert is expected");
4543  // Handle the `ifElseFatal` format, which does not emit an SVA but
4544  // rather a process that uses $error and $fatal to perform the checks.
4545  auto boolType = IntegerType::get(builder.getContext(), 1);
4546  predicate = comb::createOrFoldNot(predicate, builder, /*twoState=*/true);
4547  predicate = builder.createOrFold<comb::AndOp>(enable, predicate, true);
4548 
4549  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4550  addToIfDefBlock("SYNTHESIS", {}, [&]() {
4551  addToAlwaysBlock(clock, [&]() {
4552  addIfProceduralBlock(predicate, [&]() {
4553  circuitState.usedStopCond = true;
4554  circuitState.addFragment(theModule, "STOP_COND_FRAGMENT");
4555 
4556  circuitState.usedAssertVerboseCond = true;
4557  circuitState.addFragment(theModule, "ASSERT_VERBOSE_COND_FRAGMENT");
4558 
4559  addIfProceduralBlock(
4560  builder.create<sv::MacroRefExprOp>(boolType,
4561  "ASSERT_VERBOSE_COND_"),
4562  [&]() { builder.create<sv::ErrorOp>(message, messageOps); });
4563  addIfProceduralBlock(
4564  builder.create<sv::MacroRefExprOp>(boolType, "STOP_COND_"),
4565  [&]() { builder.create<sv::FatalOp>(); });
4566  });
4567  });
4568  });
4569  return;
4570  }
4571  case VerificationFlavor::SVA: {
4572  // Formulate the `enable -> predicate` as `!enable | predicate`.
4573  // Except for covers, combine them: enable & predicate
4574  if (!isCover) {
4575  auto notEnable =
4576  comb::createOrFoldNot(enable, builder, /*twoState=*/true);
4577  predicate =
4578  builder.createOrFold<comb::OrOp>(notEnable, predicate, true);
4579  } else {
4580  predicate = builder.createOrFold<comb::AndOp>(enable, predicate, true);
4581  }
4582 
4583  // Handle the regular SVA case.
4584  sv::EventControl event;
4585  switch (opEventControl) {
4586  case EventControl::AtPosEdge:
4587  event = circt::sv::EventControl::AtPosEdge;
4588  break;
4589  case EventControl::AtEdge:
4590  event = circt::sv::EventControl::AtEdge;
4591  break;
4592  case EventControl::AtNegEdge:
4593  event = circt::sv::EventControl::AtNegEdge;
4594  break;
4595  }
4596 
4598  builder, opName,
4599  circt::sv::EventControlAttr::get(builder.getContext(), event), clock,
4600  predicate, prefixedLabel, message, messageOps);
4601  return;
4602  }
4603  case VerificationFlavor::None:
4604  llvm_unreachable(
4605  "flavor `None` must be converted into one of concreate flavors");
4606  }
4607  };
4608 
4609  // Wrap the verification statement up in the optional preprocessor
4610  // guards. This is a bit awkward since we want to translate an array of
4611  // guards into a recursive call to `addToIfDefBlock`.
4612  return emitGuards(op->getLoc(), guards, emit);
4613 }
4614 
4615 // Lower an assert to SystemVerilog.
4616 LogicalResult FIRRTLLowering::visitStmt(AssertOp op) {
4617  return lowerVerificationStatement(
4618  op, "assert__", op.getClock(), op.getPredicate(), op.getEnable(),
4619  op.getMessageAttr(), op.getSubstitutions(), op.getNameAttr(),
4620  op.getIsConcurrent(), op.getEventControl());
4621 }
4622 
4623 // Lower an assume to SystemVerilog.
4624 LogicalResult FIRRTLLowering::visitStmt(AssumeOp op) {
4625  return lowerVerificationStatement(
4626  op, "assume__", op.getClock(), op.getPredicate(), op.getEnable(),
4627  op.getMessageAttr(), op.getSubstitutions(), op.getNameAttr(),
4628  op.getIsConcurrent(), op.getEventControl());
4629 }
4630 
4631 // Lower a cover to SystemVerilog.
4632 LogicalResult FIRRTLLowering::visitStmt(CoverOp op) {
4633  return lowerVerificationStatement(
4634  op, "cover__", op.getClock(), op.getPredicate(), op.getEnable(),
4635  op.getMessageAttr(), op.getSubstitutions(), op.getNameAttr(),
4636  op.getIsConcurrent(), op.getEventControl());
4637 }
4638 
4639 // Lower an UNR only assume to a specific style of SV assume.
4640 LogicalResult FIRRTLLowering::visitStmt(UnclockedAssumeIntrinsicOp op) {
4641  // TODO : Need to figure out if there is a cleaner way to get the string which
4642  // indicates the assert is UNR only. Or better - not rely on this at all -
4643  // ideally there should have been some other attribute which indicated that
4644  // this assert for UNR only.
4645  auto guardsAttr = op->getAttrOfType<mlir::ArrayAttr>("guards");
4646  ArrayRef<Attribute> guards =
4647  guardsAttr ? guardsAttr.getValue() : ArrayRef<Attribute>();
4648 
4649  auto label = op.getNameAttr();
4650  StringAttr assumeLabel;
4651  if (label && !label.empty())
4652  assumeLabel =
4653  StringAttr::get(builder.getContext(), "assume__" + label.getValue());
4654  auto predicate = getLoweredValue(op.getPredicate());
4655  auto enable = getLoweredValue(op.getEnable());
4656  auto notEnable = comb::createOrFoldNot(enable, builder, /*twoState=*/true);
4657  predicate = builder.createOrFold<comb::OrOp>(notEnable, predicate, true);
4658 
4659  SmallVector<Value> messageOps;
4660  for (auto operand : op.getSubstitutions()) {
4661  auto loweredValue = getLoweredValue(operand);
4662  if (!loweredValue) {
4663  // If this is a zero bit operand, just pass a one bit zero.
4664  if (!isZeroBitFIRRTLType(operand.getType()))
4665  return failure();
4666  loweredValue = getOrCreateIntConstant(1, 0);
4667  }
4668  messageOps.push_back(loweredValue);
4669  }
4670  return emitGuards(op.getLoc(), guards, [&]() {
4671  builder.create<sv::AlwaysOp>(
4672  ArrayRef(sv::EventControl::AtEdge), ArrayRef(predicate), [&]() {
4673  if (op.getMessageAttr().getValue().empty())
4674  buildImmediateVerifOp(
4675  builder, "assume", predicate,
4676  circt::sv::DeferAssertAttr::get(
4677  builder.getContext(), circt::sv::DeferAssert::Immediate),
4678  assumeLabel);
4679  else
4680  buildImmediateVerifOp(
4681  builder, "assume", predicate,
4682  circt::sv::DeferAssertAttr::get(
4683  builder.getContext(), circt::sv::DeferAssert::Immediate),
4684  assumeLabel, op.getMessageAttr(), messageOps);
4685  });
4686  });
4687 }
4688 
4689 LogicalResult FIRRTLLowering::visitStmt(AttachOp op) {
4690  // Don't emit anything for a zero or one operand attach.
4691  if (op.getAttached().size() < 2)
4692  return success();
4693 
4694  SmallVector<Value, 4> inoutValues;
4695  for (auto v : op.getAttached()) {
4696  inoutValues.push_back(getPossiblyInoutLoweredValue(v));
4697  if (!inoutValues.back()) {
4698  // Ignore zero bit values.
4699  if (!isZeroBitFIRRTLType(v.getType()))
4700  return failure();
4701  inoutValues.pop_back();
4702  continue;
4703  }
4704 
4705  if (!isa<hw::InOutType>(inoutValues.back().getType()))
4706  return op.emitError("operand isn't an inout type");
4707  }
4708 
4709  if (inoutValues.size() < 2)
4710  return success();
4711 
4712  // If the op has a single source value, the value is used as a lowering result
4713  // of other values. Therefore we can delete the attach op here.
4715  return success();
4716 
4717  // If all operands of the attach are internal to this module (none of them
4718  // are ports), then they can all be replaced with a single wire, and we can
4719  // delete the attach op.
4720  bool isAttachInternalOnly =
4721  llvm::none_of(inoutValues, [](auto v) { return isa<BlockArgument>(v); });
4722 
4723  if (isAttachInternalOnly) {
4724  auto v0 = inoutValues.front();
4725  for (auto v : inoutValues) {
4726  if (v == v0)
4727  continue;
4728  v.replaceAllUsesWith(v0);
4729  }
4730  return success();
4731  }
4732 
4733  // If the attach operands contain a port, then we can't do anything to
4734  // simplify the attach operation.
4735  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4736  circuitState.addMacroDecl(builder.getStringAttr("VERILATOR"));
4737  addToIfDefBlock(
4738  "SYNTHESIS",
4739  // If we're doing synthesis, we emit an all-pairs assign complex.
4740  [&]() {
4741  SmallVector<Value, 4> values;
4742  for (size_t i = 0, e = inoutValues.size(); i != e; ++i)
4743  values.push_back(getReadValue(inoutValues[i]));
4744 
4745  for (size_t i1 = 0, e = inoutValues.size(); i1 != e; ++i1) {
4746  for (size_t i2 = 0; i2 != e; ++i2)
4747  if (i1 != i2)
4748  builder.create<sv::AssignOp>(inoutValues[i1], values[i2]);
4749  }
4750  },
4751  // In the non-synthesis case, we emit a SystemVerilog alias
4752  // statement.
4753  [&]() {
4754  builder.create<sv::IfDefOp>(
4755  "VERILATOR",
4756  [&]() {
4757  builder.create<sv::VerbatimOp>(
4758  "`error \"Verilator does not support alias and thus "
4759  "cannot "
4760  "arbitrarily connect bidirectional wires and ports\"");
4761  },
4762  [&]() { builder.create<sv::AliasOp>(inoutValues); });
4763  });
4764 
4765  return success();
4766 }
4767 
4768 LogicalResult FIRRTLLowering::fixupLTLOps() {
4769  if (ltlOpFixupWorklist.empty())
4770  return success();
4771  LLVM_DEBUG(llvm::dbgs() << "Fixing up " << ltlOpFixupWorklist.size()
4772  << " LTL ops\n");
4773 
4774  // Add wire users into the worklist.
4775  for (unsigned i = 0, e = ltlOpFixupWorklist.size(); i != e; ++i)
4776  for (auto *user : ltlOpFixupWorklist[i]->getUsers())
4777  if (isa<hw::WireOp>(user))
4778  ltlOpFixupWorklist.insert(user);
4779 
4780  // Re-infer LTL op types and remove wires.
4781  while (!ltlOpFixupWorklist.empty()) {
4782  auto *op = ltlOpFixupWorklist.pop_back_val();
4783 
4784  // Update the operation's return type by re-running type inference.
4785  if (auto opIntf = dyn_cast_or_null<mlir::InferTypeOpInterface>(op)) {
4786  LLVM_DEBUG(llvm::dbgs() << "- Update " << *op << "\n");
4787  SmallVector<Type, 2> types;
4788  auto result = opIntf.inferReturnTypes(
4789  op->getContext(), op->getLoc(), op->getOperands(),
4790  op->getAttrDictionary(), op->getPropertiesStorage(), op->getRegions(),
4791  types);
4792  if (failed(result))
4793  return failure();
4794  assert(types.size() == op->getNumResults());
4795 
4796  // Update the result types and add the dependent ops into the worklist if
4797  // the type changed.
4798  for (auto [result, type] : llvm::zip(op->getResults(), types)) {
4799  if (result.getType() == type)
4800  continue;
4801  LLVM_DEBUG(llvm::dbgs()
4802  << " - Result #" << result.getResultNumber() << " from "
4803  << result.getType() << " to " << type << "\n");
4804  result.setType(type);
4805  for (auto *user : result.getUsers())
4806  if (user != op)
4807  ltlOpFixupWorklist.insert(user);
4808  }
4809  }
4810 
4811  // Remove LTL-typed wires.
4812  if (auto wireOp = dyn_cast<hw::WireOp>(op)) {
4813  if (isa<ltl::SequenceType, ltl::PropertyType>(wireOp.getType())) {
4814  wireOp.replaceAllUsesWith(wireOp.getInput());
4815  LLVM_DEBUG(llvm::dbgs() << "- Remove " << wireOp << "\n");
4816  if (wireOp.use_empty())
4817  wireOp.erase();
4818  }
4819  continue;
4820  }
4821 
4822  // Ensure that the operation has no users outside of LTL operations.
4823  SmallPtrSet<Operation *, 4> usersReported;
4824  for (auto *user : op->getUsers()) {
4825  if (!usersReported.insert(user).second)
4826  continue;
4827  if (isa<ltl::LTLDialect, verif::VerifDialect>(user->getDialect()))
4828  continue;
4829  if (isa<hw::WireOp>(user))
4830  continue;
4831  auto d = op->emitError(
4832  "verification operation used in a non-verification context");
4833  d.attachNote(user->getLoc())
4834  << "leaking outside verification context here";
4835  return d;
4836  }
4837  }
4838 
4839  return success();
4840 }
assert(baseType &&"element must be base type")
static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options, mlir::raw_indented_ostream &stream)
Emit the SMT operations in the given 'solver' to the 'stream'.
int32_t width
Definition: FIRRTL.cpp:36
@ Input
Definition: HW.h:35
@ Output
Definition: HW.h:35
@ InOut
Definition: HW.h:35
static unsigned getBitWidthFromVectorSize(unsigned size)
Definition: LowerToHW.cpp:195
static void moveVerifAnno(ModuleOp top, AnnotationSet &annos, StringRef annoClass, StringRef attrBase)
Move a ExtractTestCode related annotation from annotations to an attribute.
Definition: LowerToHW.cpp:169
static Operation * buildImmediateVerifOp(ImplicitLocOpBuilder &builder, StringRef opName, Args &&...args)
Helper function to build an immediate assert operation based on the original FIRRTL operation name.
Definition: LowerToHW.cpp:4415
static LogicalResult handleZeroBit(Value failedOperand, std::function< LogicalResult()> fn)
Zero bit operands end up looking like failures from getLoweredValue.
Definition: LowerToHW.cpp:1985
static Value castToFIRRTLType(Value val, Type type, ImplicitLocOpBuilder &builder)
Cast a value to a desired target type.
Definition: LowerToHW.cpp:134
static Operation * buildConcurrentVerifOp(ImplicitLocOpBuilder &builder, StringRef opName, Args &&...args)
Helper function to build a concurrent assert operation based on the original FIRRTL operation name.
Definition: LowerToHW.cpp:4430
static ArrayAttr getHWParameters(FExtModuleOp module, bool ignoreValues)
Map the parameter specifier on the specified extmodule into the HWModule representation for parameter...
Definition: LowerToHW.cpp:924
static bool isZeroBitFIRRTLType(Type type)
Return true if the specified type is a sized FIRRTL type (Int or Analog) with zero bits.
Definition: LowerToHW.cpp:65
static Value tryEliminatingAttachesToAnalogValue(Value value, Operation *insertPoint)
Given a value of analog type, check to see the only use of it is an attach.
Definition: LowerToHW.cpp:1149
static const char moduleHierarchyFileAttrName[]
Attribute that indicates that the module hierarchy starting at the annotated module should be dumped ...
Definition: LowerToHW.cpp:61
static SmallVector< SubfieldOp > getAllFieldAccesses(Value structValue, StringRef field)
Definition: LowerToHW.cpp:1270
static void tryCopyName(Operation *dst, Operation *src)
Definition: LowerToHW.cpp:201
static LogicalResult verifyOpLegality(Operation *op)
This verifies that the target operation has been lowered to a legal operation.
Definition: LowerToHW.cpp:90
static Value castFromFIRRTLType(Value val, Type type, ImplicitLocOpBuilder &builder)
Cast from a FIRRTL type (potentially with a flip) to a standard type.
Definition: LowerToHW.cpp:148
static Value tryEliminatingConnectsToValue(Value flipValue, Operation *insertPoint, CircuitLoweringState &loweringState)
Given a value of flip type, check to see if all of the uses of it are connects.
Definition: LowerToHW.cpp:1186
static Value getSingleNonInstanceOperand(AttachOp op)
Definition: LowerToHW.cpp:72
static IntType getWidestIntType(Type t1, Type t2)
Given two FIRRTL integer types, return the widest one.
Definition: LowerToHW.cpp:127
std::shared_ptr< calyx::CalyxLoweringState > loweringState
Instantiate one of these and use it to build typed backedges.
void abandon()
Abandon the backedges, suppressing any diagnostics if they are still active upon destruction of the b...
Backedge get(mlir::Type resultType, mlir::LocationAttr optionalLoc={})
Create a typed backedge.
mlir::LogicalResult clearOrEmitError()
Clear the backedges, erasing any remaining cursor ops.
Backedge is a wrapper class around a Value.
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:30
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
bool removeAnnotation(Annotation anno)
Remove an annotation from this annotation set.
Annotation getAnnotation(StringRef className) const
If this annotation set has an annotation with the specified class name, return it.
This class provides a read-only projection of an annotation.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
FIRRTLVisitor allows you to visit all of the expr/stmt/decls with one class declaration.
This graph tracks modules and where they are instantiated.
FModuleLike getTopLevelModule()
Get the module corresponding to the top-level module of a circuit.
This is the common base class between SIntType and UIntType.
Definition: FIRRTLTypes.h:296
This table tracks nlas and what modules participate in them.
Definition: NLATable.h:29
This is an edge in the InstanceGraph.
Definition: InstanceGraph.h:55
def create(*sub_arrays)
Definition: hw.py:464
def create(elements)
Definition: hw.py:443
def create(array_value, idx)
Definition: hw.py:410
def create(data_type, value)
Definition: hw.py:393
Definition: sv.py:15
Definition: sv.py:35
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
Definition: CombOps.cpp:48
Value createOrFoldSExt(Location loc, Value value, Type destTy, OpBuilder &builder)
Create a sign extension operation from a value of integer type to an equal or larger integer type.
Definition: CombOps.cpp:25
StringRef getFragmentsAttrName()
Return the name of the fragments array attribute.
Definition: EmitOps.h:32
constexpr const char * extractCoverageAnnoClass
constexpr const char * elaborationArtefactsDirectoryAnnoClass
FIRRTLBaseType getBaseType(Type type)
If it is a base type, return it as is.
Definition: FIRRTLUtils.h:222
constexpr const char * extractGrandCentralClass
constexpr const char * blackBoxAnnoClass
constexpr const char * dontObfuscateModuleAnnoClass
constexpr const char * metadataDirectoryAttrName
constexpr const char * testBenchDirAnnoClass
std::pair< hw::InnerSymAttr, StringAttr > getOrAddInnerSym(MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID, llvm::function_ref< hw::InnerSymbolNamespace &()> getNamespace)
Ensure that the the InnerSymAttr has a symbol on the field specified.
constexpr const char * dutAnnoClass
constexpr const char * forceNameAnnoClass
constexpr const char * noDedupAnnoClass
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool hasDroppableName(Operation *op)
Return true if the name is droppable.
constexpr const char * extractAssertAnnoClass
constexpr const char * verifBlackBoxAnnoClass
constexpr const char * blackBoxTargetDirAnnoClass
Type lowerType(Type type, std::optional< Location > loc={}, llvm::function_ref< hw::TypeAliasType(Type, BaseTypeAliasType, Location)> getTypeDeclFn={})
Given a type, return the corresponding lowered type for the HW dialect.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
Definition: FIRRTLOps.cpp:4018
constexpr const char * extractAssumeAnnoClass
constexpr const char * testHarnessHierAnnoClass
constexpr const char * moduleHierAnnoClass
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
mlir::ArrayAttr getSVAttributes(mlir::Operation *op)
Return all the SV attributes of an operation, or null if there are none.
void setSVAttributes(mlir::Operation *op, mlir::ArrayAttr attrs)
Set the SV attributes of an operation.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
std::unique_ptr< mlir::Pass > createLowerFIRRTLToHWPass(bool enableAnnotationWarning=false, firrtl::VerificationFlavor assertionFlavor=firrtl::VerificationFlavor::None)
This is the pass constructor.
Definition: LowerToHW.cpp:586
Definition: emit.py:1
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
Definition: codegen.py:121
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition: seq.py:21
This holds the name and type that describes the module's ports.
bool isOutput() const
Return true if this is a simple output-only port.
bool isInput() const
Return true if this is a simple input-only port.