CIRCT  19.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  ::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, ::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  LogicalResult visitExpr(LTLDisableIntrinsicOp op);
1636  LogicalResult visitStmt(VerifAssertIntrinsicOp op);
1637  LogicalResult visitStmt(VerifAssumeIntrinsicOp op);
1638  LogicalResult visitStmt(VerifCoverIntrinsicOp op);
1639  LogicalResult visitExpr(HasBeenResetIntrinsicOp op);
1640  LogicalResult visitStmt(UnclockedAssumeIntrinsicOp op);
1641 
1642  // Other Operations
1643  LogicalResult visitExpr(BitsPrimOp op);
1644  LogicalResult visitExpr(InvalidValueOp op);
1645  LogicalResult visitExpr(HeadPrimOp op);
1646  LogicalResult visitExpr(ShlPrimOp op);
1647  LogicalResult visitExpr(ShrPrimOp op);
1648  LogicalResult visitExpr(DShlPrimOp op) {
1649  return lowerDivLikeOp<comb::ShlOp, comb::ShlOp>(op);
1650  }
1651  LogicalResult visitExpr(DShrPrimOp op) {
1652  return lowerDivLikeOp<comb::ShrSOp, comb::ShrUOp>(op);
1653  }
1654  LogicalResult visitExpr(DShlwPrimOp op) {
1655  return lowerDivLikeOp<comb::ShlOp, comb::ShlOp>(op);
1656  }
1657  LogicalResult visitExpr(TailPrimOp op);
1658  LogicalResult visitExpr(MuxPrimOp op);
1659  LogicalResult visitExpr(Mux2CellIntrinsicOp op);
1660  LogicalResult visitExpr(Mux4CellIntrinsicOp op);
1661  LogicalResult visitExpr(MultibitMuxOp op);
1662  LogicalResult visitExpr(VerbatimExprOp op);
1663  LogicalResult visitExpr(XMRRefOp op);
1664  LogicalResult visitExpr(XMRDerefOp op);
1665 
1666  // Statements
1667  LogicalResult lowerVerificationStatement(
1668  Operation *op, StringRef labelPrefix, Value clock, Value predicate,
1669  Value enable, StringAttr messageAttr, ValueRange operands,
1670  StringAttr nameAttr, bool isConcurrent, EventControl eventControl);
1671 
1672  LogicalResult visitStmt(SkipOp op);
1673 
1674  FailureOr<bool> lowerConnect(Value dest, Value srcVal);
1675  LogicalResult visitStmt(ConnectOp op);
1676  LogicalResult visitStmt(MatchingConnectOp op);
1677  LogicalResult visitStmt(ForceOp op);
1678  LogicalResult visitStmt(PrintFOp op);
1679  LogicalResult visitStmt(StopOp op);
1680  LogicalResult visitStmt(AssertOp op);
1681  LogicalResult visitStmt(AssumeOp op);
1682  LogicalResult visitStmt(CoverOp op);
1683  LogicalResult visitStmt(AttachOp op);
1684  LogicalResult visitStmt(RefForceOp op);
1685  LogicalResult visitStmt(RefForceInitialOp op);
1686  LogicalResult visitStmt(RefReleaseOp op);
1687  LogicalResult visitStmt(RefReleaseInitialOp op);
1688 
1689  FailureOr<Value> lowerSubindex(SubindexOp op, Value input);
1690  FailureOr<Value> lowerSubaccess(SubaccessOp op, Value input);
1691  FailureOr<Value> lowerSubfield(SubfieldOp op, Value input);
1692 
1693  LogicalResult fixupLTLOps();
1694 
1695  Type lowerType(Type type) {
1696  return circuitState.lowerType(type, builder.getLoc());
1697  }
1698 
1699 private:
1700  /// The module we're lowering into.
1701  hw::HWModuleOp theModule;
1702 
1703  /// Global state.
1704  CircuitLoweringState &circuitState;
1705 
1706  /// This builder is set to the right location for each visit call.
1707  ImplicitLocOpBuilder builder;
1708 
1709  /// Each value lowered (e.g. operation result) is kept track in this map.
1710  /// The key should have a FIRRTL type, the result will have an HW dialect
1711  /// type.
1712  DenseMap<Value, Value> valueMapping;
1713 
1714  /// Mapping from clock values to corresponding non-clock values converted
1715  /// via a deduped `seq.from_clock` op.
1716  DenseMap<Value, Value> fromClockMapping;
1717 
1718  /// This keeps track of constants that we have created so we can reuse them.
1719  /// This is populated by the getOrCreateIntConstant method.
1720  DenseMap<Attribute, Value> hwConstantMap;
1721  DenseMap<std::pair<Attribute, Type>, Attribute> hwAggregateConstantMap;
1722 
1723  /// This keeps track of constant X that we have created so we can reuse them.
1724  /// This is populated by the getOrCreateXConstant method.
1725  DenseMap<unsigned, Value> hwConstantXMap;
1726  DenseMap<Type, Value> hwConstantZMap;
1727 
1728  /// We auto-unique "ReadInOut" ops from wires and regs, enabling
1729  /// optimizations and CSEs of the read values to be more obvious. This
1730  /// caches a known ReadInOutOp for the given value and is managed by
1731  /// `getReadValue(v)`.
1732  DenseMap<Value, Value> readInOutCreated;
1733 
1734  // We auto-unique graph-level blocks to reduce the amount of generated
1735  // code and ensure that side effects are properly ordered in FIRRTL.
1736  using AlwaysKeyType = std::tuple<Block *, sv::EventControl, Value,
1737  ::ResetType, sv::EventControl, Value>;
1739  alwaysBlocks;
1742 
1743  /// A namespace that can be used to generate new symbol names that are unique
1744  /// within this module.
1745  hw::InnerSymbolNamespace moduleNamespace;
1746 
1747  /// A backedge builder to directly materialize values during the lowering
1748  /// without requiring temporary wires.
1749  BackedgeBuilder backedgeBuilder;
1750  /// Currently unresolved backedges. More precisely, a mapping from the
1751  /// backedge value to the value it will be replaced with. We use a MapVector
1752  /// so that a combinational cycles of backedges, the one backedge that gets
1753  /// replaced with an undriven wire is consistent.
1754  llvm::MapVector<Value, Value> backedges;
1755 
1756  /// A collection of values generated by the lowering process that may have
1757  /// become obsolete through subsequent parts of the lowering. This covers the
1758  /// values of wires that may be overridden by subsequent connects; or
1759  /// subaccesses that appear only as destination of a connect, and thus gets
1760  /// obsoleted by the connect directly updating the wire or register.
1761  DenseSet<Operation *> maybeUnusedValues;
1762 
1763  void maybeUnused(Operation *op) { maybeUnusedValues.insert(op); }
1764  void maybeUnused(Value value) {
1765  if (auto *op = value.getDefiningOp())
1766  maybeUnused(op);
1767  }
1768 
1769  /// A worklist of LTL operations that don't have their final type yet. The
1770  /// FIRRTL intrinsics for LTL ops all use `uint<1>` types, but the actual LTL
1771  /// ops themselves have more precise `!ltl.sequence` and `!ltl.property`
1772  /// types. After all LTL ops have been lowered, this worklist is used to
1773  /// compute their actual types (re-inferring return types) and push the
1774  /// updated types to their users. This also drops any `hw.wire`s in between
1775  /// the LTL ops, which were necessary to go from the def-before-use FIRRTL
1776  /// dialect to the graph-like HW dialect.
1777  SetVector<Operation *> ltlOpFixupWorklist;
1778 };
1779 } // end anonymous namespace
1780 
1781 LogicalResult FIRRTLModuleLowering::lowerModuleOperations(
1782  hw::HWModuleOp module, CircuitLoweringState &loweringState) {
1783  return FIRRTLLowering(module, loweringState).run();
1784 }
1785 
1786 // This is the main entrypoint for the lowering pass.
1787 LogicalResult FIRRTLLowering::run() {
1788  // FIRRTL FModule is a single block because FIRRTL ops are a DAG. Walk
1789  // through each operation, lowering each in turn if we can, introducing
1790  // casts if we cannot.
1791  auto &body = theModule.getBody();
1792 
1793  SmallVector<Operation *, 16> opsToRemove;
1794 
1795  // Iterate through each operation in the module body, attempting to lower
1796  // each of them. We maintain 'builder' for each invocation.
1797  for (auto &op : body.front().getOperations()) {
1798  builder.setInsertionPoint(&op);
1799  builder.setLoc(op.getLoc());
1800  auto done = succeeded(dispatchVisitor(&op));
1801  circuitState.processRemainingAnnotations(&op, AnnotationSet(&op));
1802  if (done)
1803  opsToRemove.push_back(&op);
1804  else {
1805  switch (handleUnloweredOp(&op)) {
1806  case AlreadyLowered:
1807  break; // Something like hw.output, which is already lowered.
1808  case NowLowered: // Something handleUnloweredOp removed.
1809  opsToRemove.push_back(&op);
1810  break;
1811  case LoweringFailure:
1812  backedgeBuilder.abandon();
1813  return failure();
1814  }
1815  }
1816  }
1817 
1818  // Replace all backedges with uses of their regular values. We process them
1819  // after the module body since the lowering table is too hard to keep up to
1820  // date. Multiple operations may be lowered to the same backedge when values
1821  // are folded, which means we would have to scan the entire lowering table to
1822  // safely replace a backedge.
1823  for (auto &[backedge, value] : backedges) {
1824  SmallVector<Location> driverLocs;
1825  // In the case where we have backedges connected to other backedges, we have
1826  // to find the value that actually drives the group.
1827  while (true) {
1828  // If we find the original backedge we have some undriven logic or
1829  // a combinatorial loop. Bail out and provide information on the nodes.
1830  if (backedge == value) {
1831  Location edgeLoc = backedge.getLoc();
1832  if (driverLocs.empty()) {
1833  mlir::emitError(edgeLoc, "sink does not have a driver");
1834  } else {
1835  auto diag = mlir::emitError(edgeLoc, "sink in combinational loop");
1836  for (auto loc : driverLocs)
1837  diag.attachNote(loc) << "through driver here";
1838  }
1839  backedgeBuilder.abandon();
1840  return failure();
1841  }
1842  // If the value is not another backedge, we have found the driver.
1843  auto it = backedges.find(value);
1844  if (it == backedges.end())
1845  break;
1846  // Find what is driving the next backedge.
1847  driverLocs.push_back(value.getLoc());
1848  value = it->second;
1849  }
1850  if (auto *defOp = backedge.getDefiningOp())
1851  maybeUnusedValues.erase(defOp);
1852  backedge.replaceAllUsesWith(value);
1853  }
1854 
1855  // Now that all of the operations that can be lowered are, remove th
1856  // original values. We know that any lowered operations will be dead (if
1857  // removed in reverse order) at this point - any users of them from
1858  // unremapped operations will be changed to use the newly lowered ops.
1859  hw::ConstantOp zeroI0;
1860  while (!opsToRemove.empty()) {
1861  auto *op = opsToRemove.pop_back_val();
1862 
1863  // We remove zero-width values when lowering FIRRTL ops. We can't remove
1864  // such a value if it escapes to a foreign op. In that case, create an
1865  // `hw.constant 0 : i0` to pass along.
1866  for (auto result : op->getResults()) {
1867  if (!isZeroBitFIRRTLType(result.getType()))
1868  continue;
1869  if (!zeroI0) {
1870  auto builder = OpBuilder::atBlockBegin(&body.front());
1871  zeroI0 = builder.create<hw::ConstantOp>(op->getLoc(),
1872  builder.getIntegerType(0), 0);
1873  maybeUnusedValues.insert(zeroI0);
1874  }
1875  result.replaceAllUsesWith(zeroI0);
1876  }
1877 
1878  if (!op->use_empty()) {
1879  auto d = op->emitOpError(
1880  "still has uses; should remove ops in reverse order of visitation");
1881  SmallPtrSet<Operation *, 2> visited;
1882  for (auto *user : op->getUsers())
1883  if (visited.insert(user).second)
1884  d.attachNote(user->getLoc())
1885  << "used by " << user->getName() << " op";
1886  return d;
1887  }
1888  maybeUnusedValues.erase(op);
1889  op->erase();
1890  }
1891 
1892  // Prune operations that may have become unused throughout the lowering.
1893  while (!maybeUnusedValues.empty()) {
1894  auto it = maybeUnusedValues.begin();
1895  auto *op = *it;
1896  maybeUnusedValues.erase(it);
1897  if (!isOpTriviallyDead(op))
1898  continue;
1899  for (auto operand : op->getOperands())
1900  if (auto *defOp = operand.getDefiningOp())
1901  maybeUnusedValues.insert(defOp);
1902  op->erase();
1903  }
1904 
1905  // Determine the actual types of lowered LTL operations and remove any
1906  // intermediate wires among them.
1907  if (failed(fixupLTLOps()))
1908  return failure();
1909 
1910  return backedgeBuilder.clearOrEmitError();
1911 }
1912 
1913 //===----------------------------------------------------------------------===//
1914 // Helpers
1915 //===----------------------------------------------------------------------===//
1916 
1917 /// Create uniqued constant clocks.
1918 Value FIRRTLLowering::getOrCreateClockConstant(seq::ClockConst clock) {
1919  auto attr = seq::ClockConstAttr::get(theModule.getContext(), clock);
1920 
1921  auto &entry = hwConstantMap[attr];
1922  if (entry)
1923  return entry;
1924 
1925  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
1926  entry = entryBuilder.create<seq::ConstClockOp>(builder.getLoc(), attr);
1927  return entry;
1928 }
1929 
1930 /// Check to see if we've already lowered the specified constant. If so,
1931 /// return it. Otherwise create it and put it in the entry block for reuse.
1932 Value FIRRTLLowering::getOrCreateIntConstant(const APInt &value) {
1933  auto attr = builder.getIntegerAttr(
1934  builder.getIntegerType(value.getBitWidth()), value);
1935 
1936  auto &entry = hwConstantMap[attr];
1937  if (entry)
1938  return entry;
1939 
1940  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
1941  entry = entryBuilder.create<hw::ConstantOp>(builder.getLoc(), attr);
1942  return entry;
1943 }
1944 
1945 /// Check to see if we've already created the specified aggregate constant
1946 /// attribute. If so, return it. Otherwise create it.
1947 Attribute FIRRTLLowering::getOrCreateAggregateConstantAttribute(Attribute value,
1948  Type type) {
1949  // Base case.
1950  if (hw::type_isa<IntegerType>(type))
1951  return builder.getIntegerAttr(type, cast<IntegerAttr>(value).getValue());
1952 
1953  auto cache = hwAggregateConstantMap.lookup({value, type});
1954  if (cache)
1955  return cache;
1956 
1957  // Recursively construct elements.
1958  SmallVector<Attribute> values;
1959  for (auto e : llvm::enumerate(cast<ArrayAttr>(value))) {
1960  Type subType;
1961  if (auto array = hw::type_dyn_cast<hw::ArrayType>(type))
1962  subType = array.getElementType();
1963  else if (auto structType = hw::type_dyn_cast<hw::StructType>(type))
1964  subType = structType.getElements()[e.index()].type;
1965  else
1966  assert(false && "type must be either array or struct");
1967 
1968  values.push_back(getOrCreateAggregateConstantAttribute(e.value(), subType));
1969  }
1970 
1971  // FIRRTL and HW have a different operand ordering for arrays.
1972  if (hw::type_isa<hw::ArrayType>(type))
1973  std::reverse(values.begin(), values.end());
1974 
1975  auto &entry = hwAggregateConstantMap[{value, type}];
1976  entry = builder.getArrayAttr(values);
1977  return entry;
1978 }
1979 
1980 /// Zero bit operands end up looking like failures from getLoweredValue. This
1981 /// helper function invokes the closure specified if the operand was actually
1982 /// zero bit, or returns failure() if it was some other kind of failure.
1983 static LogicalResult handleZeroBit(Value failedOperand,
1984  std::function<LogicalResult()> fn) {
1985  assert(failedOperand && "Should be called on the failed operand");
1986  if (!isZeroBitFIRRTLType(failedOperand.getType()))
1987  return failure();
1988  return fn();
1989 }
1990 
1991 /// Check to see if we've already lowered the specified constant. If so,
1992 /// return it. Otherwise create it and put it in the entry block for reuse.
1993 Value FIRRTLLowering::getOrCreateXConstant(unsigned numBits) {
1994 
1995  auto &entry = hwConstantXMap[numBits];
1996  if (entry)
1997  return entry;
1998 
1999  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
2000  entry = entryBuilder.create<sv::ConstantXOp>(
2001  builder.getLoc(), entryBuilder.getIntegerType(numBits));
2002  return entry;
2003 }
2004 
2005 Value FIRRTLLowering::getOrCreateZConstant(Type type) {
2006  auto &entry = hwConstantZMap[type];
2007  if (!entry) {
2008  OpBuilder entryBuilder(&theModule.getBodyBlock()->front());
2009  entry = entryBuilder.create<sv::ConstantZOp>(builder.getLoc(), type);
2010  }
2011  return entry;
2012 }
2013 
2014 /// Return the lowered HW value corresponding to the specified original value.
2015 /// This returns a null value for FIRRTL values that haven't be lowered, e.g.
2016 /// unknown width integers. This returns hw::inout type values if present, it
2017 /// does not implicitly read from them.
2018 Value FIRRTLLowering::getPossiblyInoutLoweredValue(Value value) {
2019  // Block arguments are considered lowered.
2020  if (isa<BlockArgument>(value))
2021  return value;
2022 
2023  // If we lowered this value, then return the lowered value, otherwise fail.
2024  if (auto lowering = valueMapping.lookup(value)) {
2025  assert(!isa<FIRRTLType>(lowering.getType()) &&
2026  "Lowered value should be a non-FIRRTL value");
2027  return lowering;
2028  }
2029  return Value();
2030 }
2031 
2032 /// Return the lowered value corresponding to the specified original value.
2033 /// This returns a null value for FIRRTL values that cannot be lowered, e.g.
2034 /// unknown width integers.
2035 Value FIRRTLLowering::getLoweredValue(Value value) {
2036  auto result = getPossiblyInoutLoweredValue(value);
2037  if (!result)
2038  return result;
2039 
2040  // If we got an inout value, implicitly read it. FIRRTL allows direct use
2041  // of wires and other things that lower to inout type.
2042  if (isa<hw::InOutType>(result.getType()))
2043  return getReadValue(result);
2044 
2045  return result;
2046 }
2047 
2048 /// Return the lowered value, converting `seq.clock` to `i1.
2049 Value FIRRTLLowering::getLoweredNonClockValue(Value value) {
2050  auto result = getLoweredValue(value);
2051  if (!result)
2052  return result;
2053 
2054  if (hw::type_isa<seq::ClockType>(result.getType()))
2055  return getNonClockValue(result);
2056 
2057  return result;
2058 }
2059 
2060 /// Return the lowered aggregate value whose type is converted into
2061 /// `destType`. We have to care about the extension/truncation/signedness of
2062 /// each element.
2063 Value FIRRTLLowering::getExtOrTruncAggregateValue(Value array,
2064  FIRRTLBaseType sourceType,
2065  FIRRTLBaseType destType,
2066  bool allowTruncate) {
2067  SmallVector<Value> resultBuffer;
2068 
2069  // Helper function to cast each element of array to dest type.
2070  auto cast = [&](Value value, FIRRTLBaseType sourceType,
2071  FIRRTLBaseType destType) {
2072  auto srcWidth = firrtl::type_cast<IntType>(sourceType).getWidthOrSentinel();
2073  auto destWidth = firrtl::type_cast<IntType>(destType).getWidthOrSentinel();
2074  auto resultType = builder.getIntegerType(destWidth);
2075 
2076  if (srcWidth == destWidth)
2077  return value;
2078 
2079  if (srcWidth > destWidth) {
2080  if (allowTruncate)
2081  return builder.createOrFold<comb::ExtractOp>(resultType, value, 0);
2082 
2083  builder.emitError("operand should not be a truncation");
2084  return Value();
2085  }
2086 
2087  if (firrtl::type_cast<IntType>(sourceType).isSigned())
2088  return comb::createOrFoldSExt(value, resultType, builder);
2089  auto zero = getOrCreateIntConstant(destWidth - srcWidth, 0);
2090  return builder.createOrFold<comb::ConcatOp>(zero, value);
2091  };
2092 
2093  // This recursive function constructs the output array.
2094  std::function<LogicalResult(Value, FIRRTLBaseType, FIRRTLBaseType)> recurse =
2095  [&](Value src, FIRRTLBaseType srcType,
2096  FIRRTLBaseType destType) -> LogicalResult {
2097  return TypeSwitch<FIRRTLBaseType, LogicalResult>(srcType)
2098  .Case<FVectorType>([&](auto srcVectorType) {
2099  auto destVectorType = firrtl::type_cast<FVectorType>(destType);
2100  unsigned size = resultBuffer.size();
2101  unsigned indexWidth =
2102  getBitWidthFromVectorSize(srcVectorType.getNumElements());
2103  for (size_t i = 0, e = std::min(srcVectorType.getNumElements(),
2104  destVectorType.getNumElements());
2105  i != e; ++i) {
2106  auto iIdx = getOrCreateIntConstant(indexWidth, i);
2107  auto arrayIndex = builder.create<hw::ArrayGetOp>(src, iIdx);
2108  if (failed(recurse(arrayIndex, srcVectorType.getElementType(),
2109  destVectorType.getElementType())))
2110  return failure();
2111  }
2112  SmallVector<Value> temp(resultBuffer.begin() + size,
2113  resultBuffer.end());
2114  auto array = builder.createOrFold<hw::ArrayCreateOp>(temp);
2115  resultBuffer.resize(size);
2116  resultBuffer.push_back(array);
2117  return success();
2118  })
2119  .Case<BundleType>([&](BundleType srcStructType) {
2120  auto destStructType = firrtl::type_cast<BundleType>(destType);
2121  unsigned size = resultBuffer.size();
2122 
2123  // TODO: We don't support partial connects for bundles for now.
2124  if (destStructType.getNumElements() != srcStructType.getNumElements())
2125  return failure();
2126 
2127  for (auto elem : llvm::enumerate(destStructType)) {
2128  auto structExtract =
2129  builder.create<hw::StructExtractOp>(src, elem.value().name);
2130  if (failed(recurse(structExtract,
2131  srcStructType.getElementType(elem.index()),
2132  destStructType.getElementType(elem.index()))))
2133  return failure();
2134  }
2135  SmallVector<Value> temp(resultBuffer.begin() + size,
2136  resultBuffer.end());
2137  auto newStruct = builder.createOrFold<hw::StructCreateOp>(
2138  lowerType(destStructType), temp);
2139  resultBuffer.resize(size);
2140  resultBuffer.push_back(newStruct);
2141  return success();
2142  })
2143  .Case<IntType>([&](auto) {
2144  if (auto result = cast(src, srcType, destType)) {
2145  resultBuffer.push_back(result);
2146  return success();
2147  }
2148  return failure();
2149  })
2150  .Default([&](auto) { return failure(); });
2151  };
2152 
2153  if (failed(recurse(array, sourceType, destType)))
2154  return Value();
2155 
2156  assert(resultBuffer.size() == 1 &&
2157  "resultBuffer must only contain a result array if `success` is true");
2158  return resultBuffer[0];
2159 }
2160 
2161 /// Return the lowered value corresponding to the specified original value and
2162 /// then extend it to match the width of destType if needed.
2163 ///
2164 /// This returns a null value for FIRRTL values that cannot be lowered, e.g.
2165 /// unknown width integers.
2166 Value FIRRTLLowering::getLoweredAndExtendedValue(Value value, Type destType) {
2167  assert(type_isa<FIRRTLBaseType>(value.getType()) &&
2168  type_isa<FIRRTLBaseType>(destType) &&
2169  "input/output value should be FIRRTL");
2170 
2171  // We only know how to extend integer types with known width.
2172  auto destWidth = type_cast<FIRRTLBaseType>(destType).getBitWidthOrSentinel();
2173  if (destWidth == -1)
2174  return {};
2175 
2176  auto result = getLoweredValue(value);
2177  if (!result) {
2178  // If this was a zero bit operand being extended, then produce a zero of
2179  // the right result type. If it is just a failure, fail.
2180  if (!isZeroBitFIRRTLType(value.getType()))
2181  return {};
2182  // Zero bit results have to be returned as null. The caller can handle
2183  // this if they want to.
2184  if (destWidth == 0)
2185  return {};
2186  // Otherwise, FIRRTL semantics is that an extension from a zero bit value
2187  // always produces a zero value in the destination width.
2188  return getOrCreateIntConstant(destWidth, 0);
2189  }
2190 
2191  if (destWidth ==
2192  cast<FIRRTLBaseType>(value.getType()).getBitWidthOrSentinel()) {
2193  // Lookup the lowered type of dest.
2194  auto loweredDstType = lowerType(destType);
2195  if (result.getType() != loweredDstType &&
2196  (isa<hw::TypeAliasType>(result.getType()) ||
2197  isa<hw::TypeAliasType>(loweredDstType))) {
2198  return builder.createOrFold<hw::BitcastOp>(loweredDstType, result);
2199  }
2200  }
2201  // Aggregates values
2202  if (isa<hw::ArrayType, hw::StructType>(result.getType())) {
2203  // Types already match.
2204  if (destType == value.getType())
2205  return result;
2206 
2207  return getExtOrTruncAggregateValue(
2208  result, type_cast<FIRRTLBaseType>(value.getType()),
2209  type_cast<FIRRTLBaseType>(destType),
2210  /* allowTruncate */ false);
2211  }
2212 
2213  if (isa<seq::ClockType>(result.getType())) {
2214  // Types already match.
2215  if (destType == value.getType())
2216  return result;
2217  builder.emitError("cannot use clock type as an integer");
2218  return {};
2219  }
2220 
2221  auto intResultType = dyn_cast<IntegerType>(result.getType());
2222  if (!intResultType) {
2223  builder.emitError("operand of type ")
2224  << result.getType() << " cannot be used as an integer";
2225  return {};
2226  }
2227 
2228  auto srcWidth = intResultType.getWidth();
2229  if (srcWidth == unsigned(destWidth))
2230  return result;
2231 
2232  if (srcWidth > unsigned(destWidth)) {
2233  builder.emitError("operand should not be a truncation");
2234  return {};
2235  }
2236 
2237  auto resultType = builder.getIntegerType(destWidth);
2238 
2239  // Extension follows the sign of the source value, not the destination.
2240  auto valueFIRType =
2241  type_cast<FIRRTLBaseType>(value.getType()).getPassiveType();
2242  if (type_cast<IntType>(valueFIRType).isSigned())
2243  return comb::createOrFoldSExt(result, resultType, builder);
2244 
2245  auto zero = getOrCreateIntConstant(destWidth - srcWidth, 0);
2246  return builder.createOrFold<comb::ConcatOp>(zero, result);
2247 }
2248 
2249 /// Return the lowered value corresponding to the specified original value and
2250 /// then extended or truncated to match the width of destType if needed.
2251 ///
2252 /// This returns a null value for FIRRTL values that cannot be lowered, e.g.
2253 /// unknown width integers.
2254 Value FIRRTLLowering::getLoweredAndExtOrTruncValue(Value value, Type destType) {
2255  assert(type_isa<FIRRTLBaseType>(value.getType()) &&
2256  type_isa<FIRRTLBaseType>(destType) &&
2257  "input/output value should be FIRRTL");
2258 
2259  // We only know how to adjust integer types with known width.
2260  auto destWidth = type_cast<FIRRTLBaseType>(destType).getBitWidthOrSentinel();
2261  if (destWidth == -1)
2262  return {};
2263 
2264  auto result = getLoweredValue(value);
2265  if (!result) {
2266  // If this was a zero bit operand being extended, then produce a zero of
2267  // the right result type. If it is just a failure, fail.
2268  if (!isZeroBitFIRRTLType(value.getType()))
2269  return {};
2270  // Zero bit results have to be returned as null. The caller can handle
2271  // this if they want to.
2272  if (destWidth == 0)
2273  return {};
2274  // Otherwise, FIRRTL semantics is that an extension from a zero bit value
2275  // always produces a zero value in the destination width.
2276  return getOrCreateIntConstant(destWidth, 0);
2277  }
2278 
2279  // Aggregates values
2280  if (isa<hw::ArrayType, hw::StructType>(result.getType())) {
2281  // Types already match.
2282  if (destType == value.getType())
2283  return result;
2284 
2285  return getExtOrTruncAggregateValue(
2286  result, type_cast<FIRRTLBaseType>(value.getType()),
2287  type_cast<FIRRTLBaseType>(destType),
2288  /* allowTruncate */ true);
2289  }
2290 
2291  auto srcWidth = type_cast<IntegerType>(result.getType()).getWidth();
2292  if (srcWidth == unsigned(destWidth))
2293  return result;
2294 
2295  if (destWidth == 0)
2296  return {};
2297 
2298  if (srcWidth > unsigned(destWidth)) {
2299  auto resultType = builder.getIntegerType(destWidth);
2300  return builder.createOrFold<comb::ExtractOp>(resultType, result, 0);
2301  }
2302 
2303  auto resultType = builder.getIntegerType(destWidth);
2304 
2305  // Extension follows the sign of the source value, not the destination.
2306  auto valueFIRType =
2307  type_cast<FIRRTLBaseType>(value.getType()).getPassiveType();
2308  if (type_cast<IntType>(valueFIRType).isSigned())
2309  return comb::createOrFoldSExt(result, resultType, builder);
2310 
2311  auto zero = getOrCreateIntConstant(destWidth - srcWidth, 0);
2312  return builder.createOrFold<comb::ConcatOp>(zero, result);
2313 }
2314 
2315 /// Return a lowered version of 'operand' suitable for use with substitution /
2316 /// format strings. Zero bit operands are rewritten as one bit zeros and signed
2317 /// integers are wrapped in $signed().
2318 Value FIRRTLLowering::getLoweredFmtOperand(Value operand) {
2319  auto loweredValue = getLoweredValue(operand);
2320  if (!loweredValue) {
2321  // If this is a zero bit operand, just pass a one bit zero.
2322  if (!isZeroBitFIRRTLType(operand.getType()))
2323  return nullptr;
2324  loweredValue = getOrCreateIntConstant(1, 0);
2325  }
2326 
2327  // If the operand was an SInt, we want to give the user the option to print
2328  // it as signed decimal and have to wrap it in $signed().
2329  if (auto intTy = firrtl::type_cast<IntType>(operand.getType()))
2330  if (intTy.isSigned())
2331  loweredValue = builder.create<sv::SystemFunctionOp>(
2332  loweredValue.getType(), "signed", loweredValue);
2333 
2334  return loweredValue;
2335 }
2336 
2337 /// Set the lowered value of 'orig' to 'result', remembering this in a map.
2338 /// This always returns success() to make it more convenient in lowering code.
2339 ///
2340 /// Note that result may be null here if we're lowering orig to a zero-bit
2341 /// value.
2342 ///
2343 LogicalResult FIRRTLLowering::setLowering(Value orig, Value result) {
2344  if (auto origType = dyn_cast<FIRRTLType>(orig.getType())) {
2345  assert((!result || !type_isa<FIRRTLType>(result.getType())) &&
2346  "Lowering didn't turn a FIRRTL value into a non-FIRRTL value");
2347 
2348 #ifndef NDEBUG
2349  auto baseType = getBaseType(origType);
2350  auto srcWidth = baseType.getPassiveType().getBitWidthOrSentinel();
2351 
2352  // Caller should pass null value iff this was a zero bit value.
2353  if (srcWidth != -1) {
2354  if (result)
2355  assert((srcWidth != 0) &&
2356  "Lowering produced value for zero width source");
2357  else
2358  assert((srcWidth == 0) &&
2359  "Lowering produced null value but source wasn't zero width");
2360  }
2361 #endif
2362  } else {
2363  assert(result && "Lowering of foreign type produced null value");
2364  }
2365 
2366  auto &slot = valueMapping[orig];
2367  assert(!slot && "value lowered multiple times");
2368  slot = result;
2369  return success();
2370 }
2371 
2372 /// Set the lowering for a value to the specified result. This came from a
2373 /// possible folding, so check to see if we need to handle a constant.
2374 LogicalResult FIRRTLLowering::setPossiblyFoldedLowering(Value orig,
2375  Value result) {
2376  // If this is a constant, check to see if we have it in our unique mapping:
2377  // it could have come from folding an operation.
2378  if (auto cst = dyn_cast_or_null<hw::ConstantOp>(result.getDefiningOp())) {
2379  auto &entry = hwConstantMap[cst.getValueAttr()];
2380  if (entry == cst) {
2381  // We're already using an entry in the constant map, nothing to do.
2382  } else if (entry) {
2383  // We already had this constant, reuse the one we have instead of the
2384  // one we just folded.
2385  result = entry;
2386  cst->erase();
2387  } else {
2388  // This is a new constant. Remember it!
2389  entry = cst;
2390  cst->moveBefore(&theModule.getBodyBlock()->front());
2391  }
2392  }
2393 
2394  return setLowering(orig, result);
2395 }
2396 
2397 /// Create a new operation with type ResultOpType and arguments CtorArgTypes,
2398 /// then call setLowering with its result.
2399 template <typename ResultOpType, typename... CtorArgTypes>
2400 LogicalResult FIRRTLLowering::setLoweringTo(Operation *orig,
2401  CtorArgTypes... args) {
2402  auto result = builder.createOrFold<ResultOpType>(args...);
2403  if (auto *op = result.getDefiningOp())
2404  tryCopyName(op, orig);
2405  return setPossiblyFoldedLowering(orig->getResult(0), result);
2406 }
2407 
2408 /// Create a new LTL operation with type ResultOpType and arguments
2409 /// CtorArgTypes, then call setLowering with its result. Also add the operation
2410 /// to the worklist of LTL ops that need to have their types fixed-up after the
2411 /// lowering.
2412 template <typename ResultOpType, typename... CtorArgTypes>
2413 LogicalResult FIRRTLLowering::setLoweringToLTL(Operation *orig,
2414  CtorArgTypes... args) {
2415  auto result = builder.createOrFold<ResultOpType>(args...);
2416  if (auto *op = result.getDefiningOp())
2417  ltlOpFixupWorklist.insert(op);
2418  return setPossiblyFoldedLowering(orig->getResult(0), result);
2419 }
2420 
2421 /// Creates a backedge of the specified result type. A backedge represents a
2422 /// placeholder to be filled in later by a lowered value. If the backedge is not
2423 /// updated with a real value by the end of the pass, it will be replaced with
2424 /// an undriven wire. Backedges are allowed to be updated to other backedges.
2425 /// If a chain of backedges forms a combinational loop, they will be replaced
2426 /// with an undriven wire.
2427 Backedge FIRRTLLowering::createBackedge(Location loc, Type type) {
2428  auto backedge = backedgeBuilder.get(type, loc);
2429  backedges.insert({backedge, backedge});
2430  return backedge;
2431 }
2432 
2433 /// Sets the lowering for a value to a backedge of the specified result type.
2434 /// This is useful for lowering types which cannot pass through a wire, or to
2435 /// directly materialize values in operations that violate the SSA dominance
2436 /// constraint.
2437 Backedge FIRRTLLowering::createBackedge(Value orig, Type type) {
2438  auto backedge = createBackedge(orig.getLoc(), type);
2439  (void)setLowering(orig, backedge);
2440  return backedge;
2441 }
2442 
2443 /// If the `from` value is in fact a backedge, record that the backedge will
2444 /// be replaced by the value. Return true if the destination is a backedge.
2445 bool FIRRTLLowering::updateIfBackedge(Value dest, Value src) {
2446  auto backedgeIt = backedges.find(dest);
2447  if (backedgeIt == backedges.end())
2448  return false;
2449  backedgeIt->second = src;
2450  return true;
2451 }
2452 
2453 /// Switch the insertion point of the current builder to the end of the
2454 /// specified block and run the closure. This correctly handles the case
2455 /// where the closure is null, but the caller needs to make sure the block
2456 /// exists.
2457 void FIRRTLLowering::runWithInsertionPointAtEndOfBlock(
2458  std::function<void(void)> fn, Region &region) {
2459  if (!fn)
2460  return;
2461 
2462  auto oldIP = builder.saveInsertionPoint();
2463 
2464  builder.setInsertionPointToEnd(&region.front());
2465  fn();
2466  builder.restoreInsertionPoint(oldIP);
2467 }
2468 
2469 /// Return a read value for the specified inout operation, auto-uniquing them.
2470 Value FIRRTLLowering::getReadValue(Value v) {
2471  Value result = readInOutCreated.lookup(v);
2472  if (result)
2473  return result;
2474 
2475  // Make sure to put the read value at the correct scope so it dominates all
2476  // future uses.
2477  auto oldIP = builder.saveInsertionPoint();
2478  if (auto *vOp = v.getDefiningOp()) {
2479  builder.setInsertionPointAfter(vOp);
2480  } else {
2481  // For reads of ports, just set the insertion point at the top of the
2482  // module.
2483  builder.setInsertionPoint(&theModule.getBodyBlock()->front());
2484  }
2485 
2486  // Instead of creating `ReadInOutOp` for `ArrayIndexInOutOp`, create
2487  // `ArrayGetOp` for root arrays.
2488  if (auto arrayIndexInout = v.getDefiningOp<sv::ArrayIndexInOutOp>()) {
2489  result = getReadValue(arrayIndexInout.getInput());
2490  result = builder.createOrFold<hw::ArrayGetOp>(result,
2491  arrayIndexInout.getIndex());
2492  } else {
2493  // Otherwise, create a read inout operation.
2494  result = builder.createOrFold<sv::ReadInOutOp>(v);
2495  }
2496  builder.restoreInsertionPoint(oldIP);
2497  readInOutCreated.insert({v, result});
2498  return result;
2499 }
2500 
2501 Value FIRRTLLowering::getNonClockValue(Value v) {
2502  auto it = fromClockMapping.try_emplace(v, Value{});
2503  if (it.second) {
2504  ImplicitLocOpBuilder builder(v.getLoc(), v.getContext());
2505  builder.setInsertionPointAfterValue(v);
2506  it.first->second = builder.create<seq::FromClockOp>(v);
2507  }
2508  return it.first->second;
2509 }
2510 
2511 void FIRRTLLowering::addToAlwaysBlock(sv::EventControl clockEdge, Value clock,
2512  ::ResetType resetStyle,
2513  sv::EventControl resetEdge, Value reset,
2514  std::function<void(void)> body,
2515  std::function<void(void)> resetBody) {
2516  AlwaysKeyType key{builder.getBlock(), clockEdge, clock,
2517  resetStyle, resetEdge, reset};
2518  sv::AlwaysOp alwaysOp;
2519  sv::IfOp insideIfOp;
2520  std::tie(alwaysOp, insideIfOp) = alwaysBlocks.lookup(key);
2521 
2522  if (!alwaysOp) {
2523  if (reset) {
2524  assert(resetStyle != ::ResetType::NoReset);
2525  // Here, we want to create the folloing structure with sv.always and
2526  // sv.if. If `reset` is async, we need to add `reset` to a sensitivity
2527  // list.
2528  //
2529  // sv.always @(clockEdge or reset) {
2530  // sv.if (reset) {
2531  // resetBody
2532  // } else {
2533  // body
2534  // }
2535  // }
2536 
2537  auto createIfOp = [&]() {
2538  // It is weird but intended. Here we want to create an empty sv.if
2539  // with an else block.
2540  insideIfOp = builder.create<sv::IfOp>(
2541  reset, []() {}, []() {});
2542  };
2543  if (resetStyle == ::ResetType::AsyncReset) {
2544  sv::EventControl events[] = {clockEdge, resetEdge};
2545  Value clocks[] = {clock, reset};
2546 
2547  alwaysOp = builder.create<sv::AlwaysOp>(events, clocks, [&]() {
2548  if (resetEdge == sv::EventControl::AtNegEdge)
2549  llvm_unreachable("negative edge for reset is not expected");
2550  createIfOp();
2551  });
2552  } else {
2553  alwaysOp = builder.create<sv::AlwaysOp>(clockEdge, clock, createIfOp);
2554  }
2555  } else {
2556  assert(!resetBody);
2557  alwaysOp = builder.create<sv::AlwaysOp>(clockEdge, clock);
2558  insideIfOp = nullptr;
2559  }
2560  alwaysBlocks[key] = {alwaysOp, insideIfOp};
2561  }
2562 
2563  if (reset) {
2564  assert(insideIfOp && "reset body must be initialized before");
2565  runWithInsertionPointAtEndOfBlock(resetBody, insideIfOp.getThenRegion());
2566  runWithInsertionPointAtEndOfBlock(body, insideIfOp.getElseRegion());
2567  } else {
2568  runWithInsertionPointAtEndOfBlock(body, alwaysOp.getBody());
2569  }
2570 
2571  // Move the earlier always block(s) down to where the last would have been
2572  // inserted. This ensures that any values used by the always blocks are
2573  // defined ahead of the uses, which leads to better generated Verilog.
2574  alwaysOp->moveBefore(builder.getInsertionBlock(),
2575  builder.getInsertionPoint());
2576 }
2577 
2578 LogicalResult FIRRTLLowering::emitGuards(Location loc,
2579  ArrayRef<Attribute> guards,
2580  std::function<void(void)> emit) {
2581  if (guards.empty()) {
2582  emit();
2583  return success();
2584  }
2585  auto guard = dyn_cast<StringAttr>(guards[0]);
2586  if (!guard)
2587  return mlir::emitError(loc,
2588  "elements in `guards` array must be `StringAttr`");
2589 
2590  // Record the guard macro to emit a declaration for it.
2591  circuitState.addMacroDecl(builder.getStringAttr(guard.getValue()));
2592  LogicalResult result = LogicalResult::failure();
2593  addToIfDefBlock(guard.getValue(), [&]() {
2594  result = emitGuards(loc, guards.drop_front(), emit);
2595  });
2596  return result;
2597 }
2598 
2599 void FIRRTLLowering::addToIfDefBlock(StringRef cond,
2600  std::function<void(void)> thenCtor,
2601  std::function<void(void)> elseCtor) {
2602  auto condAttr = builder.getStringAttr(cond);
2603  auto op = ifdefBlocks.lookup({builder.getBlock(), condAttr});
2604  if (op) {
2605  runWithInsertionPointAtEndOfBlock(thenCtor, op.getThenRegion());
2606  runWithInsertionPointAtEndOfBlock(elseCtor, op.getElseRegion());
2607 
2608  // Move the earlier #ifdef block(s) down to where the last would have been
2609  // inserted. This ensures that any values used by the #ifdef blocks are
2610  // defined ahead of the uses, which leads to better generated Verilog.
2611  op->moveBefore(builder.getInsertionBlock(), builder.getInsertionPoint());
2612  } else {
2613  ifdefBlocks[{builder.getBlock(), condAttr}] =
2614  builder.create<sv::IfDefOp>(condAttr, thenCtor, elseCtor);
2615  }
2616 }
2617 
2618 void FIRRTLLowering::addToInitialBlock(std::function<void(void)> body) {
2619  auto op = initialBlocks.lookup(builder.getBlock());
2620  if (op) {
2621  runWithInsertionPointAtEndOfBlock(body, op.getBody());
2622 
2623  // Move the earlier initial block(s) down to where the last would have
2624  // been inserted. This ensures that any values used by the initial blocks
2625  // are defined ahead of the uses, which leads to better generated Verilog.
2626  op->moveBefore(builder.getInsertionBlock(), builder.getInsertionPoint());
2627  } else {
2628  initialBlocks[builder.getBlock()] = builder.create<sv::InitialOp>(body);
2629  }
2630 }
2631 
2632 void FIRRTLLowering::addIfProceduralBlock(Value cond,
2633  std::function<void(void)> thenCtor,
2634  std::function<void(void)> elseCtor) {
2635  // Check to see if we already have an if on this condition immediately
2636  // before the insertion point. If so, extend it.
2637  auto insertIt = builder.getInsertionPoint();
2638  if (insertIt != builder.getBlock()->begin())
2639  if (auto ifOp = dyn_cast<sv::IfOp>(*--insertIt)) {
2640  if (ifOp.getCond() == cond) {
2641  runWithInsertionPointAtEndOfBlock(thenCtor, ifOp.getThenRegion());
2642  runWithInsertionPointAtEndOfBlock(elseCtor, ifOp.getElseRegion());
2643  return;
2644  }
2645  }
2646 
2647  builder.create<sv::IfOp>(cond, thenCtor, elseCtor);
2648 }
2649 
2650 //===----------------------------------------------------------------------===//
2651 // Special Operations
2652 //===----------------------------------------------------------------------===//
2653 
2654 /// Handle the case where an operation wasn't lowered. When this happens, the
2655 /// operands should just be unlowered non-FIRRTL values. If the operand was
2656 /// not lowered then leave it alone, otherwise we have a problem with
2657 /// lowering.
2658 ///
2659 FIRRTLLowering::UnloweredOpResult
2660 FIRRTLLowering::handleUnloweredOp(Operation *op) {
2661  // Simply pass through non-FIRRTL operations and consider them already
2662  // lowered. This allows us to handled partially lowered inputs, and also allow
2663  // other FIRRTL operations to spawn additional already-lowered operations,
2664  // like `hw.output`.
2665  if (!isa<FIRRTLDialect>(op->getDialect())) {
2666  for (auto &operand : op->getOpOperands())
2667  if (auto lowered = getPossiblyInoutLoweredValue(operand.get()))
2668  operand.set(lowered);
2669  for (auto result : op->getResults())
2670  (void)setLowering(result, result);
2671  return AlreadyLowered;
2672  }
2673 
2674  // Ok, at least one operand got lowered, so this operation is using a FIRRTL
2675  // value, but wasn't itself lowered. This is because the lowering is
2676  // incomplete. This is either a bug or incomplete implementation.
2677  //
2678  // There is one aspect of incompleteness we intentionally expect: we allow
2679  // primitive operations that produce a zero bit result to be ignored by the
2680  // lowering logic. They don't have side effects, and handling this corner
2681  // case just complicates each of the lowering hooks. Instead, we just handle
2682  // them all right here.
2683  if (op->getNumResults() == 1) {
2684  auto resultType = op->getResult(0).getType();
2685  if (type_isa<FIRRTLBaseType>(resultType) &&
2686  isZeroBitFIRRTLType(resultType) &&
2687  (isExpression(op) || isa<mlir::UnrealizedConversionCastOp>(op))) {
2688  // Zero bit values lower to the null Value.
2689  (void)setLowering(op->getResult(0), Value());
2690  return NowLowered;
2691  }
2692  }
2693  op->emitOpError("LowerToHW couldn't handle this operation");
2694  return LoweringFailure;
2695 }
2696 
2697 LogicalResult FIRRTLLowering::visitExpr(ConstantOp op) {
2698  // Zero width values must be lowered to nothing.
2699  if (isZeroBitFIRRTLType(op.getType()))
2700  return setLowering(op, Value());
2701 
2702  return setLowering(op, getOrCreateIntConstant(op.getValue()));
2703 }
2704 
2705 LogicalResult FIRRTLLowering::visitExpr(SpecialConstantOp op) {
2706  Value cst;
2707  if (isa<ClockType>(op.getType())) {
2708  cst = getOrCreateClockConstant(op.getValue() ? seq::ClockConst::High
2709  : seq::ClockConst::Low);
2710  } else {
2711  cst = getOrCreateIntConstant(APInt(/*bitWidth*/ 1, op.getValue()));
2712  }
2713  return setLowering(op, cst);
2714 }
2715 
2716 FailureOr<Value> FIRRTLLowering::lowerSubindex(SubindexOp op, Value input) {
2717  auto iIdx = getOrCreateIntConstant(
2719  firrtl::type_cast<FVectorType>(op.getInput().getType())
2720  .getNumElements()),
2721  op.getIndex());
2722 
2723  // If the input has an inout type, we need to lower to ArrayIndexInOutOp;
2724  // otherwise hw::ArrayGetOp.
2725  Value result;
2726  if (isa<sv::InOutType>(input.getType()))
2727  result = builder.createOrFold<sv::ArrayIndexInOutOp>(input, iIdx);
2728  else
2729  result = builder.createOrFold<hw::ArrayGetOp>(input, iIdx);
2730  tryCopyName(result.getDefiningOp(), op);
2731  return result;
2732 }
2733 
2734 FailureOr<Value> FIRRTLLowering::lowerSubaccess(SubaccessOp op, Value input) {
2735  Value valueIdx = getLoweredAndExtOrTruncValue(
2736  op.getIndex(),
2737  UIntType::get(op->getContext(),
2739  firrtl::type_cast<FVectorType>(op.getInput().getType())
2740  .getNumElements())));
2741  if (!valueIdx) {
2742  op->emitError() << "input lowering failed";
2743  return failure();
2744  }
2745 
2746  // If the input has an inout type, we need to lower to ArrayIndexInOutOp;
2747  // otherwise, lower the op to array indexing.
2748  Value result;
2749  if (isa<sv::InOutType>(input.getType()))
2750  result = builder.createOrFold<sv::ArrayIndexInOutOp>(input, valueIdx);
2751  else
2752  result = createArrayIndexing(input, valueIdx);
2753  tryCopyName(result.getDefiningOp(), op);
2754  return result;
2755 }
2756 
2757 FailureOr<Value> FIRRTLLowering::lowerSubfield(SubfieldOp op, Value input) {
2758  auto resultType = lowerType(op->getResult(0).getType());
2759  if (!resultType || !input) {
2760  op->emitError() << "subfield type lowering failed";
2761  return failure();
2762  }
2763 
2764  // If the input has an inout type, we need to lower to StructFieldInOutOp;
2765  // otherwise, StructExtractOp.
2766  auto field = firrtl::type_cast<BundleType>(op.getInput().getType())
2767  .getElementName(op.getFieldIndex());
2768  Value result;
2769  if (isa<sv::InOutType>(input.getType()))
2770  result = builder.createOrFold<sv::StructFieldInOutOp>(input, field);
2771  else
2772  result = builder.createOrFold<hw::StructExtractOp>(input, field);
2773  tryCopyName(result.getDefiningOp(), op);
2774  return result;
2775 }
2776 
2777 LogicalResult FIRRTLLowering::visitExpr(SubindexOp op) {
2778  if (isZeroBitFIRRTLType(op.getType()))
2779  return setLowering(op, Value());
2780 
2781  auto input = getPossiblyInoutLoweredValue(op.getInput());
2782  if (!input)
2783  return op.emitError() << "input lowering failed";
2784 
2785  auto result = lowerSubindex(op, input);
2786  if (failed(result))
2787  return failure();
2788  return setLowering(op, *result);
2789 }
2790 
2791 LogicalResult FIRRTLLowering::visitExpr(SubaccessOp op) {
2792  if (isZeroBitFIRRTLType(op.getType()))
2793  return setLowering(op, Value());
2794 
2795  auto input = getPossiblyInoutLoweredValue(op.getInput());
2796  if (!input)
2797  return op.emitError() << "input lowering failed";
2798 
2799  auto result = lowerSubaccess(op, input);
2800  if (failed(result))
2801  return failure();
2802  return setLowering(op, *result);
2803 }
2804 
2805 LogicalResult FIRRTLLowering::visitExpr(SubfieldOp op) {
2806  // firrtl.mem lowering lowers some SubfieldOps. Zero-width can leave
2807  // invalid subfield accesses
2808  if (getLoweredValue(op) || !op.getInput())
2809  return success();
2810 
2811  if (isZeroBitFIRRTLType(op.getType()))
2812  return setLowering(op, Value());
2813 
2814  auto input = getPossiblyInoutLoweredValue(op.getInput());
2815  if (!input)
2816  return op.emitError() << "input lowering failed";
2817 
2818  auto result = lowerSubfield(op, input);
2819  if (failed(result))
2820  return failure();
2821  return setLowering(op, *result);
2822 }
2823 
2824 LogicalResult FIRRTLLowering::visitExpr(VectorCreateOp op) {
2825  auto resultType = lowerType(op.getResult().getType());
2826  SmallVector<Value> operands;
2827  // NOTE: The operand order must be inverted.
2828  for (auto oper : llvm::reverse(op.getOperands())) {
2829  auto val = getLoweredValue(oper);
2830  if (!val)
2831  return failure();
2832  operands.push_back(val);
2833  }
2834  return setLoweringTo<hw::ArrayCreateOp>(op, resultType, operands);
2835 }
2836 
2837 LogicalResult FIRRTLLowering::visitExpr(BundleCreateOp op) {
2838  auto resultType = lowerType(op.getResult().getType());
2839  SmallVector<Value> operands;
2840  for (auto oper : op.getOperands()) {
2841  auto val = getLoweredValue(oper);
2842  if (!val)
2843  return failure();
2844  operands.push_back(val);
2845  }
2846  return setLoweringTo<hw::StructCreateOp>(op, resultType, operands);
2847 }
2848 
2849 LogicalResult FIRRTLLowering::visitExpr(FEnumCreateOp op) {
2850  // Zero width values must be lowered to nothing.
2851  if (isZeroBitFIRRTLType(op.getType()))
2852  return setLowering(op, Value());
2853 
2854  auto input = getLoweredValue(op.getInput());
2855  auto tagName = op.getFieldNameAttr();
2856  auto type = lowerType(op.getType());
2857 
2858  if (auto structType = dyn_cast<hw::StructType>(type)) {
2859  auto enumType = structType.getFieldType("tag");
2860  auto enumAttr = hw::EnumFieldAttr::get(op.getLoc(), tagName, enumType);
2861  auto enumOp = builder.create<hw::EnumConstantOp>(enumAttr);
2862  auto unionType = structType.getFieldType("body");
2863  auto unionOp = builder.create<hw::UnionCreateOp>(unionType, tagName, input);
2864  SmallVector<Value> operands = {enumOp.getResult(), unionOp.getResult()};
2865  return setLoweringTo<hw::StructCreateOp>(op, structType, operands);
2866  }
2867 
2868  return setLoweringTo<hw::EnumConstantOp>(
2869  op, hw::EnumFieldAttr::get(op.getLoc(), tagName, type));
2870 }
2871 
2872 LogicalResult FIRRTLLowering::visitExpr(AggregateConstantOp op) {
2873  auto resultType = lowerType(op.getResult().getType());
2874  auto attr =
2875  getOrCreateAggregateConstantAttribute(op.getFieldsAttr(), resultType);
2876 
2877  return setLoweringTo<hw::AggregateConstantOp>(op, resultType,
2878  cast<ArrayAttr>(attr));
2879 }
2880 
2881 LogicalResult FIRRTLLowering::visitExpr(IsTagOp op) {
2882  auto tagName = op.getFieldNameAttr();
2883  auto lhs = getLoweredValue(op.getInput());
2884  if (isa<hw::StructType>(lhs.getType()))
2885  lhs = builder.create<hw::StructExtractOp>(lhs, "tag");
2886  auto enumField = hw::EnumFieldAttr::get(op.getLoc(), tagName, lhs.getType());
2887  auto rhs = builder.create<hw::EnumConstantOp>(enumField);
2888  return setLoweringTo<hw::EnumCmpOp>(op, lhs, rhs);
2889 }
2890 
2891 LogicalResult FIRRTLLowering::visitExpr(SubtagOp op) {
2892  // Zero width values must be lowered to nothing.
2893  if (isZeroBitFIRRTLType(op.getType()))
2894  return setLowering(op, Value());
2895 
2896  auto tagName = op.getFieldNameAttr();
2897  auto input = getLoweredValue(op.getInput());
2898  auto field = builder.create<hw::StructExtractOp>(input, "body");
2899  return setLoweringTo<hw::UnionExtractOp>(op, field, tagName);
2900 }
2901 
2902 //===----------------------------------------------------------------------===//
2903 // Declarations
2904 //===----------------------------------------------------------------------===//
2905 
2906 LogicalResult FIRRTLLowering::visitDecl(WireOp op) {
2907  auto origResultType = op.getResult().getType();
2908 
2909  // Foreign types lower to a backedge that needs to be resolved by a later
2910  // connect op.
2911  if (!type_isa<FIRRTLType>(origResultType)) {
2912  createBackedge(op.getResult(), origResultType);
2913  return success();
2914  }
2915 
2916  auto resultType = lowerType(origResultType);
2917  if (!resultType)
2918  return failure();
2919 
2920  if (resultType.isInteger(0))
2921  return setLowering(op.getResult(), Value());
2922 
2923  // Name attr is required on sv.wire but optional on firrtl.wire.
2924  auto innerSym = lowerInnerSymbol(op);
2925  auto name = op.getNameAttr();
2926  // This is not a temporary wire created by the compiler, so attach a symbol
2927  // name.
2928  auto wire = builder.create<hw::WireOp>(
2929  op.getLoc(), getOrCreateZConstant(resultType), name, innerSym);
2930 
2931  if (auto svAttrs = sv::getSVAttributes(op))
2932  sv::setSVAttributes(wire, svAttrs);
2933 
2934  return setLowering(op.getResult(), wire);
2935 }
2936 
2937 LogicalResult FIRRTLLowering::visitDecl(VerbatimWireOp op) {
2938  auto resultTy = lowerType(op.getType());
2939  if (!resultTy)
2940  return failure();
2941  resultTy = sv::InOutType::get(op.getContext(), resultTy);
2942 
2943  SmallVector<Value, 4> operands;
2944  operands.reserve(op.getSubstitutions().size());
2945  for (auto operand : op.getSubstitutions()) {
2946  auto lowered = getLoweredValue(operand);
2947  if (!lowered)
2948  return failure();
2949  operands.push_back(lowered);
2950  }
2951 
2952  ArrayAttr symbols = op.getSymbolsAttr();
2953  if (!symbols)
2954  symbols = ArrayAttr::get(op.getContext(), {});
2955 
2956  return setLoweringTo<sv::VerbatimExprSEOp>(op, resultTy, op.getTextAttr(),
2957  operands, symbols);
2958 }
2959 
2960 LogicalResult FIRRTLLowering::visitDecl(NodeOp op) {
2961  auto operand = getLoweredValue(op.getInput());
2962  if (!operand)
2963  return handleZeroBit(
2964  op.getInput(), [&]() { return setLowering(op.getResult(), Value()); });
2965 
2966  // Node operations are logical noops, but may carry annotations or be
2967  // referred to through an inner name. If a don't touch is present, ensure
2968  // that we have a symbol name so we can keep the node as a wire.
2969  auto name = op.getNameAttr();
2970  auto innerSym = lowerInnerSymbol(op);
2971 
2972  if (innerSym)
2973  operand = builder.create<hw::WireOp>(operand, name, innerSym);
2974 
2975  // Move SV attributes.
2976  if (auto svAttrs = sv::getSVAttributes(op)) {
2977  if (!innerSym)
2978  operand = builder.create<hw::WireOp>(operand, name);
2979  sv::setSVAttributes(operand.getDefiningOp(), svAttrs);
2980  }
2981 
2982  return setLowering(op.getResult(), operand);
2983 }
2984 
2985 LogicalResult FIRRTLLowering::visitDecl(RegOp op) {
2986  auto resultType = lowerType(op.getResult().getType());
2987  if (!resultType)
2988  return failure();
2989  if (resultType.isInteger(0))
2990  return setLowering(op.getResult(), Value());
2991 
2992  Value clockVal = getLoweredValue(op.getClockVal());
2993  if (!clockVal)
2994  return failure();
2995 
2996  // Create a reg op, wiring itself to its input.
2997  auto innerSym = lowerInnerSymbol(op);
2998  Backedge inputEdge = backedgeBuilder.get(resultType);
2999  auto reg = builder.create<seq::FirRegOp>(inputEdge, clockVal,
3000  op.getNameAttr(), innerSym);
3001 
3002  // Pass along the start and end random initialization bits for this register.
3003  if (auto randomRegister = op->getAttr("firrtl.random_init_register"))
3004  reg->setAttr("firrtl.random_init_register", randomRegister);
3005  if (auto randomStart = op->getAttr("firrtl.random_init_start"))
3006  reg->setAttr("firrtl.random_init_start", randomStart);
3007  if (auto randomEnd = op->getAttr("firrtl.random_init_end"))
3008  reg->setAttr("firrtl.random_init_end", randomEnd);
3009 
3010  // Move SV attributes.
3011  if (auto svAttrs = sv::getSVAttributes(op))
3012  sv::setSVAttributes(reg, svAttrs);
3013 
3014  inputEdge.setValue(reg);
3015  (void)setLowering(op.getResult(), reg);
3016  return success();
3017 }
3018 
3019 LogicalResult FIRRTLLowering::visitDecl(RegResetOp op) {
3020  auto resultType = lowerType(op.getResult().getType());
3021  if (!resultType)
3022  return failure();
3023  if (resultType.isInteger(0))
3024  return setLowering(op.getResult(), Value());
3025 
3026  Value clockVal = getLoweredValue(op.getClockVal());
3027  Value resetSignal = getLoweredValue(op.getResetSignal());
3028  // Reset values may be narrower than the register. Extend appropriately.
3029  Value resetValue = getLoweredAndExtOrTruncValue(
3030  op.getResetValue(), type_cast<FIRRTLBaseType>(op.getResult().getType()));
3031 
3032  if (!clockVal || !resetSignal || !resetValue)
3033  return failure();
3034 
3035  // Create a reg op, wiring itself to its input.
3036  auto innerSym = lowerInnerSymbol(op);
3037  bool isAsync = type_isa<AsyncResetType>(op.getResetSignal().getType());
3038  Backedge inputEdge = backedgeBuilder.get(resultType);
3039  auto reg =
3040  builder.create<seq::FirRegOp>(inputEdge, clockVal, op.getNameAttr(),
3041  resetSignal, resetValue, innerSym, isAsync);
3042 
3043  // Pass along the start and end random initialization bits for this register.
3044  if (auto randomRegister = op->getAttr("firrtl.random_init_register"))
3045  reg->setAttr("firrtl.random_init_register", randomRegister);
3046  if (auto randomStart = op->getAttr("firrtl.random_init_start"))
3047  reg->setAttr("firrtl.random_init_start", randomStart);
3048  if (auto randomEnd = op->getAttr("firrtl.random_init_end"))
3049  reg->setAttr("firrtl.random_init_end", randomEnd);
3050 
3051  // Move SV attributes.
3052  if (auto svAttrs = sv::getSVAttributes(op))
3053  sv::setSVAttributes(reg, svAttrs);
3054 
3055  inputEdge.setValue(reg);
3056  (void)setLowering(op.getResult(), reg);
3057 
3058  return success();
3059 }
3060 
3061 LogicalResult FIRRTLLowering::visitDecl(MemOp op) {
3062  // TODO: Remove this restriction and preserve aggregates in
3063  // memories.
3064  if (type_isa<BundleType>(op.getDataType()))
3065  return op.emitOpError(
3066  "should have already been lowered from a ground type to an aggregate "
3067  "type using the LowerTypes pass. Use "
3068  "'firtool --lower-types' or 'circt-opt "
3069  "--pass-pipeline='firrtl.circuit(firrtl-lower-types)' "
3070  "to run this.");
3071 
3072  FirMemory memSummary = op.getSummary();
3073 
3074  // Create the memory declaration.
3075  auto memType = seq::FirMemType::get(
3076  op.getContext(), memSummary.depth, memSummary.dataWidth,
3077  memSummary.isMasked ? std::optional<uint32_t>(memSummary.maskBits)
3078  : std::optional<uint32_t>());
3079 
3080  seq::FirMemInitAttr memInit;
3081  if (auto init = op.getInitAttr())
3082  memInit = seq::FirMemInitAttr::get(init.getContext(), init.getFilename(),
3083  init.getIsBinary(), init.getIsInline());
3084 
3085  auto memDecl = builder.create<seq::FirMemOp>(
3086  memType, memSummary.readLatency, memSummary.writeLatency,
3087  memSummary.readUnderWrite, memSummary.writeUnderWrite, op.getNameAttr(),
3088  op.getInnerSymAttr(), memInit, op.getPrefixAttr(), Attribute{});
3089 
3090  // If the module is outside the DUT, set the appropriate output directory for
3091  // the memory.
3092  if (!circuitState.isInDUT(theModule))
3093  if (auto testBenchDir = circuitState.getTestBenchDirectory())
3094  memDecl.setOutputFileAttr(testBenchDir);
3095 
3096  // Memories return multiple structs, one for each port, which means we
3097  // have two layers of type to split apart.
3098  for (size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3099 
3100  auto addOutput = [&](StringRef field, size_t width, Value value) {
3101  for (auto &a : getAllFieldAccesses(op.getResult(i), field)) {
3102  if (width > 0)
3103  (void)setLowering(a, value);
3104  else
3105  a->eraseOperand(0);
3106  }
3107  };
3108 
3109  auto addInput = [&](StringRef field, Value backedge) {
3110  for (auto a : getAllFieldAccesses(op.getResult(i), field)) {
3111  if (cast<FIRRTLBaseType>(a.getType())
3112  .getPassiveType()
3113  .getBitWidthOrSentinel() > 0)
3114  (void)setLowering(a, backedge);
3115  else
3116  a->eraseOperand(0);
3117  }
3118  };
3119 
3120  auto addInputPort = [&](StringRef field, size_t width) -> Value {
3121  // If the memory is 0-width, do not materialize any connections to it.
3122  // However, `seq.firmem` now requires a 1-bit input, so materialize
3123  // a dummy x value to provide it with.
3124  Value backedge, portValue;
3125  if (width == 0) {
3126  portValue = getOrCreateXConstant(1);
3127  } else {
3128  auto portType = IntegerType::get(op.getContext(), width);
3129  backedge = portValue = createBackedge(builder.getLoc(), portType);
3130  }
3131  addInput(field, backedge);
3132  return portValue;
3133  };
3134 
3135  auto addClock = [&](StringRef field) -> Value {
3136  Type clockTy = seq::ClockType::get(op.getContext());
3137  Value portValue = createBackedge(builder.getLoc(), clockTy);
3138  addInput(field, portValue);
3139  return portValue;
3140  };
3141 
3142  auto memportKind = op.getPortKind(i);
3143  if (memportKind == MemOp::PortKind::Read) {
3144  auto addr = addInputPort("addr", op.getAddrBits());
3145  auto en = addInputPort("en", 1);
3146  auto clk = addClock("clk");
3147  auto data = builder.create<seq::FirMemReadOp>(memDecl, addr, clk, en);
3148  addOutput("data", memSummary.dataWidth, data);
3149  } else if (memportKind == MemOp::PortKind::ReadWrite) {
3150  auto addr = addInputPort("addr", op.getAddrBits());
3151  auto en = addInputPort("en", 1);
3152  auto clk = addClock("clk");
3153  // If maskBits =1, then And the mask field with enable, and update the
3154  // enable. Else keep mask port.
3155  auto mode = addInputPort("wmode", 1);
3156  if (!memSummary.isMasked)
3157  mode = builder.createOrFold<comb::AndOp>(mode, addInputPort("wmask", 1),
3158  true);
3159  auto wdata = addInputPort("wdata", memSummary.dataWidth);
3160  // Ignore mask port, if maskBits =1
3161  Value mask;
3162  if (memSummary.isMasked)
3163  mask = addInputPort("wmask", memSummary.maskBits);
3164  auto rdata = builder.create<seq::FirMemReadWriteOp>(
3165  memDecl, addr, clk, en, wdata, mode, mask);
3166  addOutput("rdata", memSummary.dataWidth, rdata);
3167  } else {
3168  auto addr = addInputPort("addr", op.getAddrBits());
3169  // If maskBits =1, then And the mask field with enable, and update the
3170  // enable. Else keep mask port.
3171  auto en = addInputPort("en", 1);
3172  if (!memSummary.isMasked)
3173  en = builder.createOrFold<comb::AndOp>(en, addInputPort("mask", 1),
3174  true);
3175  auto clk = addClock("clk");
3176  auto data = addInputPort("data", memSummary.dataWidth);
3177  // Ignore mask port, if maskBits =1
3178  Value mask;
3179  if (memSummary.isMasked)
3180  mask = addInputPort("mask", memSummary.maskBits);
3181  builder.create<seq::FirMemWriteOp>(memDecl, addr, clk, en, data, mask);
3182  }
3183  }
3184 
3185  return success();
3186 }
3187 
3188 LogicalResult FIRRTLLowering::visitDecl(InstanceOp oldInstance) {
3189  Operation *oldModule =
3190  oldInstance.getReferencedModule(circuitState.getInstanceGraph());
3191 
3192  auto newModule = circuitState.getNewModule(oldModule);
3193  if (!newModule) {
3194  oldInstance->emitOpError("could not find module [")
3195  << oldInstance.getModuleName() << "] referenced by instance";
3196  return failure();
3197  }
3198 
3199  // If this is a referenced to a parameterized extmodule, then bring the
3200  // parameters over to this instance.
3201  ArrayAttr parameters;
3202  if (auto oldExtModule = dyn_cast<FExtModuleOp>(oldModule))
3203  parameters = getHWParameters(oldExtModule, /*ignoreValues=*/false);
3204 
3205  // Decode information about the input and output ports on the referenced
3206  // module.
3207  SmallVector<PortInfo, 8> portInfo = cast<FModuleLike>(oldModule).getPorts();
3208 
3209  // Build an index from the name attribute to an index into portInfo, so we
3210  // can do efficient lookups.
3211  llvm::SmallDenseMap<Attribute, unsigned> portIndicesByName;
3212  for (unsigned portIdx = 0, e = portInfo.size(); portIdx != e; ++portIdx)
3213  portIndicesByName[portInfo[portIdx].name] = portIdx;
3214 
3215  // Ok, get ready to create the new instance operation. We need to prepare
3216  // input operands.
3217  SmallVector<Value, 8> operands;
3218  for (size_t portIndex = 0, e = portInfo.size(); portIndex != e; ++portIndex) {
3219  auto &port = portInfo[portIndex];
3220  auto portType = lowerType(port.type);
3221  if (!portType) {
3222  oldInstance->emitOpError("could not lower type of port ") << port.name;
3223  return failure();
3224  }
3225 
3226  // Drop zero bit input/inout ports.
3227  if (portType.isInteger(0))
3228  continue;
3229 
3230  // We wire outputs up after creating the instance.
3231  if (port.isOutput())
3232  continue;
3233 
3234  auto portResult = oldInstance.getResult(portIndex);
3235  assert(portResult && "invalid IR, couldn't find port");
3236 
3237  // Replace the input port with a backedge. If it turns out that this port
3238  // is never driven, an uninitialized wire will be materialized at the end.
3239  if (port.isInput()) {
3240  operands.push_back(createBackedge(portResult, portType));
3241  continue;
3242  }
3243 
3244  // If the result has an analog type and is used only by attach op, try
3245  // eliminating a temporary wire by directly using an attached value.
3246  if (type_isa<AnalogType>(portResult.getType()) && portResult.hasOneUse()) {
3247  if (auto attach = dyn_cast<AttachOp>(*portResult.getUsers().begin())) {
3248  if (auto source = getSingleNonInstanceOperand(attach)) {
3249  auto loweredResult = getPossiblyInoutLoweredValue(source);
3250  operands.push_back(loweredResult);
3251  (void)setLowering(portResult, loweredResult);
3252  continue;
3253  }
3254  }
3255  }
3256 
3257  // Create a wire for each inout operand, so there is something to connect
3258  // to. The instance becomes the sole driver of this wire.
3259  auto wire = builder.create<sv::WireOp>(
3260  portType, "." + port.getName().str() + ".wire");
3261 
3262  // Know that the argument FIRRTL value is equal to this wire, allowing
3263  // connects to it to be lowered.
3264  (void)setLowering(portResult, wire);
3265 
3266  operands.push_back(wire);
3267  }
3268 
3269  // If this instance is destined to be lowered to a bind, generate a symbol
3270  // for it and generate a bind op. Enter the bind into global
3271  // CircuitLoweringState so that this can be moved outside of module once
3272  // we're guaranteed to not be a parallel context.
3273  auto innerSym = oldInstance.getInnerSymAttr();
3274  if (oldInstance.getLowerToBind()) {
3275  if (!innerSym)
3276  std::tie(innerSym, std::ignore) = getOrAddInnerSym(
3277  oldInstance.getContext(), oldInstance.getInnerSymAttr(), 0,
3278  [&]() -> hw::InnerSymbolNamespace & { return moduleNamespace; });
3279 
3280  auto bindOp = builder.create<sv::BindOp>(theModule.getNameAttr(),
3281  innerSym.getSymName());
3282  // If the lowered op already had output file information, then use that.
3283  // Otherwise, generate some default bind information.
3284  if (auto outputFile = oldInstance->getAttr("output_file"))
3285  bindOp->setAttr("output_file", outputFile);
3286  // Add the bind to the circuit state. This will be moved outside of the
3287  // encapsulating module after all modules have been processed in parallel.
3288  circuitState.addBind(bindOp);
3289  }
3290 
3291  // Create the new hw.instance operation.
3292  auto newInstance = builder.create<hw::InstanceOp>(
3293  newModule, oldInstance.getNameAttr(), operands, parameters, innerSym);
3294 
3295  if (oldInstance.getLowerToBind())
3296  newInstance->setAttr("doNotPrint", builder.getBoolAttr(true));
3297 
3298  if (newInstance.getInnerSymAttr())
3299  if (auto forceName = circuitState.instanceForceNames.lookup(
3300  {cast<hw::HWModuleOp>(newInstance->getParentOp()).getNameAttr(),
3301  newInstance.getInnerNameAttr()}))
3302  newInstance->setAttr("hw.verilogName", forceName);
3303 
3304  // Now that we have the new hw.instance, we need to remap all of the users
3305  // of the outputs/results to the values returned by the instance.
3306  unsigned resultNo = 0;
3307  for (size_t portIndex = 0, e = portInfo.size(); portIndex != e; ++portIndex) {
3308  auto &port = portInfo[portIndex];
3309  if (!port.isOutput() || isZeroBitFIRRTLType(port.type))
3310  continue;
3311 
3312  Value resultVal = newInstance.getResult(resultNo);
3313 
3314  auto oldPortResult = oldInstance.getResult(portIndex);
3315  (void)setLowering(oldPortResult, resultVal);
3316  ++resultNo;
3317  }
3318  return success();
3319 }
3320 
3321 //===----------------------------------------------------------------------===//
3322 // Unary Operations
3323 //===----------------------------------------------------------------------===//
3324 
3325 // Lower a cast that is a noop at the HW level.
3326 LogicalResult FIRRTLLowering::lowerNoopCast(Operation *op) {
3327  auto operand = getPossiblyInoutLoweredValue(op->getOperand(0));
3328  if (!operand)
3329  return failure();
3330 
3331  // Noop cast.
3332  return setLowering(op->getResult(0), operand);
3333 }
3334 
3335 LogicalResult FIRRTLLowering::visitExpr(AsSIntPrimOp op) {
3336  if (isa<ClockType>(op.getInput().getType()))
3337  return setLowering(op->getResult(0),
3338  getLoweredNonClockValue(op.getInput()));
3339  return lowerNoopCast(op);
3340 }
3341 
3342 LogicalResult FIRRTLLowering::visitExpr(AsUIntPrimOp op) {
3343  if (isa<ClockType>(op.getInput().getType()))
3344  return setLowering(op->getResult(0),
3345  getLoweredNonClockValue(op.getInput()));
3346  return lowerNoopCast(op);
3347 }
3348 
3349 LogicalResult FIRRTLLowering::visitExpr(AsClockPrimOp op) {
3350  return setLoweringTo<seq::ToClockOp>(op, getLoweredValue(op.getInput()));
3351 }
3352 
3353 LogicalResult FIRRTLLowering::visitUnrealizedConversionCast(
3354  mlir::UnrealizedConversionCastOp op) {
3355  // General lowering for non-unary casts.
3356  if (op.getNumOperands() != 1 || op.getNumResults() != 1)
3357  return failure();
3358 
3359  auto operand = op.getOperand(0);
3360  auto result = op.getResult(0);
3361 
3362  // FIRRTL -> FIRRTL
3363  if (type_isa<FIRRTLType>(operand.getType()) &&
3364  type_isa<FIRRTLType>(result.getType()))
3365  return lowerNoopCast(op);
3366 
3367  // other -> FIRRTL
3368  // other -> other
3369  if (!type_isa<FIRRTLType>(operand.getType())) {
3370  if (type_isa<FIRRTLType>(result.getType()))
3371  return setLowering(result, getPossiblyInoutLoweredValue(operand));
3372  return failure(); // general foreign op lowering for other -> other
3373  }
3374 
3375  // FIRRTL -> other
3376  // Otherwise must be a conversion from FIRRTL type to standard type.
3377  auto lowered_result = getLoweredValue(operand);
3378  if (!lowered_result) {
3379  // If this is a conversion from a zero bit HW type to firrtl value, then
3380  // we want to successfully lower this to a null Value.
3381  if (operand.getType().isSignlessInteger(0)) {
3382  return setLowering(result, Value());
3383  }
3384  return failure();
3385  }
3386 
3387  // We lower builtin.unrealized_conversion_cast converting from a firrtl type
3388  // to a standard type into the lowered operand.
3389  result.replaceAllUsesWith(lowered_result);
3390  return success();
3391 }
3392 
3393 LogicalResult FIRRTLLowering::visitExpr(HWStructCastOp op) {
3394  // Conversions from hw struct types to FIRRTL types are lowered as the
3395  // input operand.
3396  if (auto opStructType = dyn_cast<hw::StructType>(op.getOperand().getType()))
3397  return setLowering(op, op.getOperand());
3398 
3399  // Otherwise must be a conversion from FIRRTL bundle type to hw struct
3400  // type.
3401  auto result = getLoweredValue(op.getOperand());
3402  if (!result)
3403  return failure();
3404 
3405  // We lower firrtl.stdStructCast converting from a firrtl bundle to an hw
3406  // struct type into the lowered operand.
3407  op.replaceAllUsesWith(result);
3408  return success();
3409 }
3410 
3411 LogicalResult FIRRTLLowering::visitExpr(BitCastOp op) {
3412  auto operand = getLoweredValue(op.getOperand());
3413  if (!operand)
3414  return failure();
3415  auto resultType = lowerType(op.getType());
3416  if (!resultType)
3417  return failure();
3418 
3419  return setLoweringTo<hw::BitcastOp>(op, resultType, operand);
3420 }
3421 
3422 LogicalResult FIRRTLLowering::visitExpr(CvtPrimOp op) {
3423  auto operand = getLoweredValue(op.getOperand());
3424  if (!operand) {
3425  return handleZeroBit(op.getOperand(), [&]() {
3426  // Unsigned zero bit to Signed is 1b0.
3427  if (type_cast<IntType>(op.getOperand().getType()).isUnsigned())
3428  return setLowering(op, getOrCreateIntConstant(1, 0));
3429  // Signed->Signed is a zero bit value.
3430  return setLowering(op, Value());
3431  });
3432  }
3433 
3434  // Signed to signed is a noop.
3435  if (type_cast<IntType>(op.getOperand().getType()).isSigned())
3436  return setLowering(op, operand);
3437 
3438  // Otherwise prepend a zero bit.
3439  auto zero = getOrCreateIntConstant(1, 0);
3440  return setLoweringTo<comb::ConcatOp>(op, zero, operand);
3441 }
3442 
3443 LogicalResult FIRRTLLowering::visitExpr(NotPrimOp op) {
3444  auto operand = getLoweredValue(op.getInput());
3445  if (!operand)
3446  return failure();
3447  // ~x ---> x ^ 0xFF
3448  auto allOnes = getOrCreateIntConstant(
3449  APInt::getAllOnes(operand.getType().getIntOrFloatBitWidth()));
3450  return setLoweringTo<comb::XorOp>(op, operand, allOnes, true);
3451 }
3452 
3453 LogicalResult FIRRTLLowering::visitExpr(NegPrimOp op) {
3454  // FIRRTL negate always adds a bit.
3455  // -x ---> 0-sext(x) or 0-zext(x)
3456  auto operand = getLoweredAndExtendedValue(op.getInput(), op.getType());
3457  if (!operand)
3458  return failure();
3459 
3460  auto resultType = lowerType(op.getType());
3461 
3462  auto zero = getOrCreateIntConstant(resultType.getIntOrFloatBitWidth(), 0);
3463  return setLoweringTo<comb::SubOp>(op, zero, operand, true);
3464 }
3465 
3466 // Pad is a noop or extension operation.
3467 LogicalResult FIRRTLLowering::visitExpr(PadPrimOp op) {
3468  auto operand = getLoweredAndExtendedValue(op.getInput(), op.getType());
3469  if (!operand)
3470  return failure();
3471  return setLowering(op, operand);
3472 }
3473 
3474 LogicalResult FIRRTLLowering::visitExpr(XorRPrimOp op) {
3475  auto operand = getLoweredValue(op.getInput());
3476  if (!operand) {
3477  return handleZeroBit(op.getInput(), [&]() {
3478  return setLowering(op, getOrCreateIntConstant(1, 0));
3479  });
3480  return failure();
3481  }
3482 
3483  return setLoweringTo<comb::ParityOp>(op, builder.getIntegerType(1), operand,
3484  true);
3485 }
3486 
3487 LogicalResult FIRRTLLowering::visitExpr(AndRPrimOp op) {
3488  auto operand = getLoweredValue(op.getInput());
3489  if (!operand) {
3490  return handleZeroBit(op.getInput(), [&]() {
3491  return setLowering(op, getOrCreateIntConstant(1, 1));
3492  });
3493  }
3494 
3495  // Lower AndR to == -1
3496  return setLoweringTo<comb::ICmpOp>(
3497  op, ICmpPredicate::eq, operand,
3498  getOrCreateIntConstant(
3499  APInt::getAllOnes(operand.getType().getIntOrFloatBitWidth())),
3500  true);
3501 }
3502 
3503 LogicalResult FIRRTLLowering::visitExpr(OrRPrimOp op) {
3504  auto operand = getLoweredValue(op.getInput());
3505  if (!operand) {
3506  return handleZeroBit(op.getInput(), [&]() {
3507  return setLowering(op, getOrCreateIntConstant(1, 0));
3508  });
3509  return failure();
3510  }
3511 
3512  // Lower OrR to != 0
3513  return setLoweringTo<comb::ICmpOp>(
3514  op, ICmpPredicate::ne, operand,
3515  getOrCreateIntConstant(operand.getType().getIntOrFloatBitWidth(), 0),
3516  true);
3517 }
3518 
3519 //===----------------------------------------------------------------------===//
3520 // Binary Operations
3521 //===----------------------------------------------------------------------===//
3522 
3523 template <typename ResultOpType>
3524 LogicalResult FIRRTLLowering::lowerBinOpToVariadic(Operation *op) {
3525  auto resultType = op->getResult(0).getType();
3526  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3527  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3528  if (!lhs || !rhs)
3529  return failure();
3530 
3531  return setLoweringTo<ResultOpType>(op, lhs, rhs, true);
3532 }
3533 
3534 /// Element-wise logical operations can be lowered into bitcast and normal comb
3535 /// operations. Eventually we might want to introduce elementwise operations
3536 /// into HW/SV level as well.
3537 template <typename ResultOpType>
3538 LogicalResult FIRRTLLowering::lowerElementwiseLogicalOp(Operation *op) {
3539  auto resultType = op->getResult(0).getType();
3540  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3541  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3542 
3543  if (!lhs || !rhs)
3544  return failure();
3545  auto bitwidth = firrtl::getBitWidth(type_cast<FIRRTLBaseType>(resultType));
3546 
3547  if (!bitwidth)
3548  return failure();
3549 
3550  // TODO: Introduce elementwise operations to HW dialect instead of abusing
3551  // bitcast operations.
3552  auto intType = builder.getIntegerType(*bitwidth);
3553  auto retType = lhs.getType();
3554  lhs = builder.createOrFold<hw::BitcastOp>(intType, lhs);
3555  rhs = builder.createOrFold<hw::BitcastOp>(intType, rhs);
3556  auto result = builder.createOrFold<ResultOpType>(lhs, rhs, /*twoState=*/true);
3557  return setLoweringTo<hw::BitcastOp>(op, retType, result);
3558 }
3559 
3560 /// lowerBinOp extends each operand to the destination type, then performs the
3561 /// specified binary operator.
3562 template <typename ResultUnsignedOpType, typename ResultSignedOpType>
3563 LogicalResult FIRRTLLowering::lowerBinOp(Operation *op) {
3564  // Extend the two operands to match the destination type.
3565  auto resultType = op->getResult(0).getType();
3566  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3567  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3568  if (!lhs || !rhs)
3569  return failure();
3570 
3571  // Emit the result operation.
3572  if (type_cast<IntType>(resultType).isSigned())
3573  return setLoweringTo<ResultSignedOpType>(op, lhs, rhs, true);
3574  return setLoweringTo<ResultUnsignedOpType>(op, lhs, rhs, true);
3575 }
3576 
3577 /// lowerCmpOp extends each operand to the longest type, then performs the
3578 /// specified binary operator.
3579 LogicalResult FIRRTLLowering::lowerCmpOp(Operation *op, ICmpPredicate signedOp,
3580  ICmpPredicate unsignedOp) {
3581  // Extend the two operands to match the longest type.
3582  auto lhsIntType = type_cast<IntType>(op->getOperand(0).getType());
3583  auto rhsIntType = type_cast<IntType>(op->getOperand(1).getType());
3584  if (!lhsIntType.hasWidth() || !rhsIntType.hasWidth())
3585  return failure();
3586 
3587  auto cmpType = getWidestIntType(lhsIntType, rhsIntType);
3588  if (cmpType.getWidth() == 0) // Handle 0-width inputs by promoting to 1 bit.
3589  cmpType = UIntType::get(builder.getContext(), 1);
3590  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), cmpType);
3591  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), cmpType);
3592  if (!lhs || !rhs)
3593  return failure();
3594 
3595  // Emit the result operation.
3596  Type resultType = builder.getIntegerType(1);
3597  return setLoweringTo<comb::ICmpOp>(
3598  op, resultType, lhsIntType.isSigned() ? signedOp : unsignedOp, lhs, rhs,
3599  true);
3600 }
3601 
3602 /// Lower a divide or dynamic shift, where the operation has to be performed
3603 /// in the widest type of the result and two inputs then truncated down.
3604 template <typename SignedOp, typename UnsignedOp>
3605 LogicalResult FIRRTLLowering::lowerDivLikeOp(Operation *op) {
3606  // hw has equal types for these, firrtl doesn't. The type of the firrtl
3607  // RHS may be wider than the LHS, and we cannot truncate off the high bits
3608  // (because an overlarge amount is supposed to shift in sign or zero bits).
3609  auto opType = type_cast<IntType>(op->getResult(0).getType());
3610  if (opType.getWidth() == 0)
3611  return setLowering(op->getResult(0), Value());
3612 
3613  auto resultType = getWidestIntType(opType, op->getOperand(1).getType());
3614  resultType = getWidestIntType(resultType, op->getOperand(0).getType());
3615  auto lhs = getLoweredAndExtendedValue(op->getOperand(0), resultType);
3616  auto rhs = getLoweredAndExtendedValue(op->getOperand(1), resultType);
3617  if (!lhs || !rhs)
3618  return failure();
3619 
3620  Value result;
3621  if (opType.isSigned())
3622  result = builder.createOrFold<SignedOp>(lhs, rhs, true);
3623  else
3624  result = builder.createOrFold<UnsignedOp>(lhs, rhs, true);
3625 
3626  tryCopyName(result.getDefiningOp(), op);
3627 
3628  if (resultType == opType)
3629  return setLowering(op->getResult(0), result);
3630  return setLoweringTo<comb::ExtractOp>(op, lowerType(opType), result, 0);
3631 }
3632 
3633 LogicalResult FIRRTLLowering::visitExpr(CatPrimOp op) {
3634  auto lhs = getLoweredValue(op.getLhs());
3635  auto rhs = getLoweredValue(op.getRhs());
3636  if (!lhs) {
3637  return handleZeroBit(op.getLhs(), [&]() {
3638  if (rhs) // cat(0bit, x) --> x
3639  return setLowering(op, rhs);
3640  // cat(0bit, 0bit) --> 0bit
3641  return handleZeroBit(op.getRhs(),
3642  [&]() { return setLowering(op, Value()); });
3643  });
3644  }
3645 
3646  if (!rhs) // cat(x, 0bit) --> x
3647  return handleZeroBit(op.getRhs(), [&]() { return setLowering(op, lhs); });
3648 
3649  return setLoweringTo<comb::ConcatOp>(op, lhs, rhs);
3650 }
3651 
3652 //===----------------------------------------------------------------------===//
3653 // Verif Operations
3654 //===----------------------------------------------------------------------===//
3655 
3656 LogicalResult FIRRTLLowering::visitExpr(IsXIntrinsicOp op) {
3657  auto input = getLoweredNonClockValue(op.getArg());
3658  if (!input)
3659  return failure();
3660 
3661  if (!isa<IntType>(input.getType())) {
3662  auto srcType = op.getArg().getType();
3663  auto bitwidth = firrtl::getBitWidth(type_cast<FIRRTLBaseType>(srcType));
3664  assert(bitwidth && "Unknown width");
3665  auto intType = builder.getIntegerType(*bitwidth);
3666  input = builder.createOrFold<hw::BitcastOp>(intType, input);
3667  }
3668 
3669  return setLoweringTo<comb::ICmpOp>(
3670  op, ICmpPredicate::ceq, input,
3671  getOrCreateXConstant(input.getType().getIntOrFloatBitWidth()), true);
3672 }
3673 
3674 LogicalResult FIRRTLLowering::visitStmt(FPGAProbeIntrinsicOp op) {
3675  auto operand = getLoweredValue(op.getInput());
3676  builder.create<hw::WireOp>(operand);
3677  return success();
3678 }
3679 
3680 LogicalResult FIRRTLLowering::visitExpr(PlusArgsTestIntrinsicOp op) {
3681  return setLoweringTo<sim::PlusArgsTestOp>(op, builder.getIntegerType(1),
3682  op.getFormatStringAttr());
3683 }
3684 
3685 LogicalResult FIRRTLLowering::visitExpr(PlusArgsValueIntrinsicOp op) {
3686  auto type = lowerType(op.getResult().getType());
3687  if (!type)
3688  return failure();
3689 
3690  auto valueOp = builder.create<sim::PlusArgsValueOp>(
3691  builder.getIntegerType(1), type, op.getFormatStringAttr());
3692  if (failed(setLowering(op.getResult(), valueOp.getResult())))
3693  return failure();
3694  if (failed(setLowering(op.getFound(), valueOp.getFound())))
3695  return failure();
3696  return success();
3697 }
3698 
3699 LogicalResult FIRRTLLowering::visitExpr(SizeOfIntrinsicOp op) {
3700  op.emitError("SizeOf should have been resolved.");
3701  return failure();
3702 }
3703 
3704 LogicalResult FIRRTLLowering::visitExpr(ClockGateIntrinsicOp op) {
3705  Value testEnable;
3706  if (op.getTestEnable())
3707  testEnable = getLoweredValue(op.getTestEnable());
3708  return setLoweringTo<seq::ClockGateOp>(
3709  op, getLoweredValue(op.getInput()), getLoweredValue(op.getEnable()),
3710  testEnable, /*inner_sym=*/hw::InnerSymAttr{});
3711 }
3712 
3713 LogicalResult FIRRTLLowering::visitExpr(ClockInverterIntrinsicOp op) {
3714  auto operand = getLoweredValue(op.getInput());
3715  return setLoweringTo<seq::ClockInverterOp>(op, operand);
3716 }
3717 
3718 LogicalResult FIRRTLLowering::visitExpr(ClockDividerIntrinsicOp op) {
3719  auto operand = getLoweredValue(op.getInput());
3720  return setLoweringTo<seq::ClockDividerOp>(op, operand, op.getPow2());
3721 }
3722 
3723 LogicalResult FIRRTLLowering::visitExpr(LTLAndIntrinsicOp op) {
3724  return setLoweringToLTL<ltl::AndOp>(
3725  op,
3726  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3727 }
3728 
3729 LogicalResult FIRRTLLowering::visitExpr(LTLOrIntrinsicOp op) {
3730  return setLoweringToLTL<ltl::OrOp>(
3731  op,
3732  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3733 }
3734 
3735 LogicalResult FIRRTLLowering::visitExpr(LTLIntersectIntrinsicOp op) {
3736  return setLoweringToLTL<ltl::IntersectOp>(
3737  op,
3738  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3739 }
3740 
3741 LogicalResult FIRRTLLowering::visitExpr(LTLDelayIntrinsicOp op) {
3742  return setLoweringToLTL<ltl::DelayOp>(op, getLoweredValue(op.getInput()),
3743  op.getDelayAttr(), op.getLengthAttr());
3744 }
3745 
3746 LogicalResult FIRRTLLowering::visitExpr(LTLConcatIntrinsicOp op) {
3747  return setLoweringToLTL<ltl::ConcatOp>(
3748  op,
3749  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3750 }
3751 
3752 LogicalResult FIRRTLLowering::visitExpr(LTLRepeatIntrinsicOp op) {
3753  return setLoweringToLTL<ltl::RepeatOp>(op, getLoweredValue(op.getInput()),
3754  op.getBaseAttr(), op.getMoreAttr());
3755 }
3756 
3757 LogicalResult FIRRTLLowering::visitExpr(LTLGoToRepeatIntrinsicOp op) {
3758  return setLoweringToLTL<ltl::GoToRepeatOp>(
3759  op, getLoweredValue(op.getInput()), op.getBaseAttr(), op.getMoreAttr());
3760 }
3761 
3762 LogicalResult FIRRTLLowering::visitExpr(LTLNonConsecutiveRepeatIntrinsicOp op) {
3763  return setLoweringToLTL<ltl::NonConsecutiveRepeatOp>(
3764  op, getLoweredValue(op.getInput()), op.getBaseAttr(), op.getMoreAttr());
3765 }
3766 
3767 LogicalResult FIRRTLLowering::visitExpr(LTLNotIntrinsicOp op) {
3768  return setLoweringToLTL<ltl::NotOp>(op, getLoweredValue(op.getInput()));
3769 }
3770 
3771 LogicalResult FIRRTLLowering::visitExpr(LTLImplicationIntrinsicOp op) {
3772  return setLoweringToLTL<ltl::ImplicationOp>(
3773  op,
3774  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3775 }
3776 
3777 LogicalResult FIRRTLLowering::visitExpr(LTLUntilIntrinsicOp op) {
3778  return setLoweringToLTL<ltl::UntilOp>(
3779  op,
3780  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3781 }
3782 
3783 LogicalResult FIRRTLLowering::visitExpr(LTLEventuallyIntrinsicOp op) {
3784  return setLoweringToLTL<ltl::EventuallyOp>(op,
3785  getLoweredValue(op.getInput()));
3786 }
3787 
3788 LogicalResult FIRRTLLowering::visitExpr(LTLClockIntrinsicOp op) {
3789  return setLoweringToLTL<ltl::ClockOp>(op, getLoweredValue(op.getInput()),
3790  ltl::ClockEdge::Pos,
3791  getLoweredNonClockValue(op.getClock()));
3792 }
3793 
3794 LogicalResult FIRRTLLowering::visitExpr(LTLDisableIntrinsicOp op) {
3795  return setLoweringToLTL<ltl::DisableOp>(
3796  op,
3797  ValueRange{getLoweredValue(op.getLhs()), getLoweredValue(op.getRhs())});
3798 }
3799 
3800 LogicalResult FIRRTLLowering::visitStmt(VerifAssertIntrinsicOp op) {
3801  builder.create<verif::AssertOp>(getLoweredValue(op.getProperty()),
3802  op.getLabelAttr());
3803  return success();
3804 }
3805 
3806 LogicalResult FIRRTLLowering::visitStmt(VerifAssumeIntrinsicOp op) {
3807  builder.create<verif::AssumeOp>(getLoweredValue(op.getProperty()),
3808  op.getLabelAttr());
3809  return success();
3810 }
3811 
3812 LogicalResult FIRRTLLowering::visitStmt(VerifCoverIntrinsicOp op) {
3813  builder.create<verif::CoverOp>(getLoweredValue(op.getProperty()),
3814  op.getLabelAttr());
3815  return success();
3816 }
3817 
3818 LogicalResult FIRRTLLowering::visitExpr(HasBeenResetIntrinsicOp op) {
3819  auto clock = getLoweredNonClockValue(op.getClock());
3820  auto reset = getLoweredValue(op.getReset());
3821  if (!clock || !reset)
3822  return failure();
3823  auto resetType = op.getReset().getType();
3824  auto uintResetType = dyn_cast<UIntType>(resetType);
3825  auto isSync = uintResetType && uintResetType.getWidth() == 1;
3826  auto isAsync = isa<AsyncResetType>(resetType);
3827  if (!isAsync && !isSync) {
3828  auto d = op.emitError("uninferred reset passed to 'has_been_reset'; "
3829  "requires sync or async reset");
3830  d.attachNote() << "reset is of type " << resetType
3831  << ", should be '!firrtl.uint<1>' or '!firrtl.asyncreset'";
3832  return failure();
3833  }
3834  return setLoweringTo<verif::HasBeenResetOp>(op, clock, reset, isAsync);
3835 }
3836 
3837 //===----------------------------------------------------------------------===//
3838 // Other Operations
3839 //===----------------------------------------------------------------------===//
3840 
3841 LogicalResult FIRRTLLowering::visitExpr(BitsPrimOp op) {
3842  auto input = getLoweredValue(op.getInput());
3843  if (!input)
3844  return failure();
3845 
3846  Type resultType = builder.getIntegerType(op.getHi() - op.getLo() + 1);
3847  return setLoweringTo<comb::ExtractOp>(op, resultType, input, op.getLo());
3848 }
3849 
3850 LogicalResult FIRRTLLowering::visitExpr(InvalidValueOp op) {
3851  auto resultTy = lowerType(op.getType());
3852  if (!resultTy)
3853  return failure();
3854 
3855  // Values of analog type always need to be lowered to something with inout
3856  // type. We do that by lowering to a wire and return that. As with the
3857  // SFC, we do not connect anything to this, because it is bidirectional.
3858  if (type_isa<AnalogType>(op.getType()))
3859  // This is a locally visible, private wire created by the compiler, so do
3860  // not attach a symbol name.
3861  return setLoweringTo<sv::WireOp>(op, resultTy, ".invalid_analog");
3862 
3863  // We don't allow aggregate values which contain values of analog types.
3864  if (type_cast<FIRRTLBaseType>(op.getType()).containsAnalog())
3865  return failure();
3866 
3867  // We lower invalid to 0. TODO: the FIRRTL spec mentions something about
3868  // lowering it to a random value, we should see if this is what we need to
3869  // do.
3870  if (auto bitwidth =
3871  firrtl::getBitWidth(type_cast<FIRRTLBaseType>(op.getType()))) {
3872  if (*bitwidth == 0) // Let the caller handle zero width values.
3873  return failure();
3874 
3875  auto constant = getOrCreateIntConstant(*bitwidth, 0);
3876  // If the result is an aggregate value, we have to bitcast the constant.
3877  if (!type_isa<IntegerType>(resultTy))
3878  constant = builder.create<hw::BitcastOp>(resultTy, constant);
3879  return setLowering(op, constant);
3880  }
3881 
3882  // Invalid for bundles isn't supported.
3883  op.emitOpError("unsupported type");
3884  return failure();
3885 }
3886 
3887 LogicalResult FIRRTLLowering::visitExpr(HeadPrimOp op) {
3888  auto input = getLoweredValue(op.getInput());
3889  if (!input)
3890  return failure();
3891  auto inWidth = type_cast<IntegerType>(input.getType()).getWidth();
3892  if (op.getAmount() == 0)
3893  return setLowering(op, Value());
3894  Type resultType = builder.getIntegerType(op.getAmount());
3895  return setLoweringTo<comb::ExtractOp>(op, resultType, input,
3896  inWidth - op.getAmount());
3897 }
3898 
3899 LogicalResult FIRRTLLowering::visitExpr(ShlPrimOp op) {
3900  auto input = getLoweredValue(op.getInput());
3901  if (!input) {
3902  return handleZeroBit(op.getInput(), [&]() {
3903  if (op.getAmount() == 0)
3904  return failure();
3905  return setLowering(op, getOrCreateIntConstant(op.getAmount(), 0));
3906  });
3907  }
3908 
3909  // Handle the degenerate case.
3910  if (op.getAmount() == 0)
3911  return setLowering(op, input);
3912 
3913  auto zero = getOrCreateIntConstant(op.getAmount(), 0);
3914  return setLoweringTo<comb::ConcatOp>(op, input, zero);
3915 }
3916 
3917 LogicalResult FIRRTLLowering::visitExpr(ShrPrimOp op) {
3918  auto input = getLoweredValue(op.getInput());
3919  if (!input)
3920  return failure();
3921 
3922  // Handle the special degenerate cases.
3923  auto inWidth = type_cast<IntegerType>(input.getType()).getWidth();
3924  auto shiftAmount = op.getAmount();
3925  if (shiftAmount >= inWidth) {
3926  // Unsigned shift by full width returns a single-bit zero.
3927  if (type_cast<IntType>(op.getInput().getType()).isUnsigned())
3928  return setLowering(op, {});
3929 
3930  // Signed shift by full width is equivalent to extracting the sign bit.
3931  shiftAmount = inWidth - 1;
3932  }
3933 
3934  Type resultType = builder.getIntegerType(inWidth - shiftAmount);
3935  return setLoweringTo<comb::ExtractOp>(op, resultType, input, shiftAmount);
3936 }
3937 
3938 LogicalResult FIRRTLLowering::visitExpr(TailPrimOp op) {
3939  auto input = getLoweredValue(op.getInput());
3940  if (!input)
3941  return failure();
3942 
3943  auto inWidth = type_cast<IntegerType>(input.getType()).getWidth();
3944  if (inWidth == op.getAmount())
3945  return setLowering(op, Value());
3946  Type resultType = builder.getIntegerType(inWidth - op.getAmount());
3947  return setLoweringTo<comb::ExtractOp>(op, resultType, input, 0);
3948 }
3949 
3950 LogicalResult FIRRTLLowering::visitExpr(MuxPrimOp op) {
3951  auto cond = getLoweredValue(op.getSel());
3952  auto ifTrue = getLoweredAndExtendedValue(op.getHigh(), op.getType());
3953  auto ifFalse = getLoweredAndExtendedValue(op.getLow(), op.getType());
3954  if (!cond || !ifTrue || !ifFalse)
3955  return failure();
3956 
3957  if (isa<ClockType>(op.getType()))
3958  return setLoweringTo<seq::ClockMuxOp>(op, cond, ifTrue, ifFalse);
3959  return setLoweringTo<comb::MuxOp>(op, ifTrue.getType(), cond, ifTrue, ifFalse,
3960  true);
3961 }
3962 
3963 LogicalResult FIRRTLLowering::visitExpr(Mux2CellIntrinsicOp op) {
3964  auto cond = getLoweredValue(op.getSel());
3965  auto ifTrue = getLoweredAndExtendedValue(op.getHigh(), op.getType());
3966  auto ifFalse = getLoweredAndExtendedValue(op.getLow(), op.getType());
3967  if (!cond || !ifTrue || !ifFalse)
3968  return failure();
3969 
3970  auto val = builder.create<comb::MuxOp>(ifTrue.getType(), cond, ifTrue,
3971  ifFalse, true);
3972  return setLowering(op, createValueWithMuxAnnotation(val, true));
3973 }
3974 
3975 LogicalResult FIRRTLLowering::visitExpr(Mux4CellIntrinsicOp op) {
3976  auto sel = getLoweredValue(op.getSel());
3977  auto v3 = getLoweredAndExtendedValue(op.getV3(), op.getType());
3978  auto v2 = getLoweredAndExtendedValue(op.getV2(), op.getType());
3979  auto v1 = getLoweredAndExtendedValue(op.getV1(), op.getType());
3980  auto v0 = getLoweredAndExtendedValue(op.getV0(), op.getType());
3981  if (!sel || !v3 || !v2 || !v1 || !v0)
3982  return failure();
3983  Value array[] = {v3, v2, v1, v0};
3984  auto create = builder.create<hw::ArrayCreateOp>(array);
3985  auto val = builder.create<hw::ArrayGetOp>(create, sel);
3986  return setLowering(op, createValueWithMuxAnnotation(val, false));
3987 }
3988 
3989 // Construct a value with vendor specific pragmas to utilize MUX cells.
3990 // Specifically we annotate pragmas in the following form.
3991 //
3992 // For an array indexing:
3993 // ```
3994 // wire GEN;
3995 // /* synopsys infer_mux_override */
3996 // assign GEN = array[index] /* cadence map_to_mux */;
3997 // ```
3998 //
3999 // For a mux:
4000 // ```
4001 // wire GEN;
4002 // /* synopsys infer_mux_override */
4003 // assign GEN = sel ? /* cadence map_to_mux */ high : low;
4004 // ```
4005 Value FIRRTLLowering::createValueWithMuxAnnotation(Operation *op, bool isMux2) {
4006  assert(op->getNumResults() == 1 && "only expect a single result");
4007  auto val = op->getResult(0);
4008  auto valWire = builder.create<sv::WireOp>(val.getType());
4009  // Use SV attributes to annotate pragmas.
4011  op, sv::SVAttributeAttr::get(builder.getContext(), "cadence map_to_mux",
4012  /*emitAsComment=*/true));
4013 
4014  // For operands, create temporary wires with optimization blockers(inner
4015  // symbols) so that the AST structure will never be destoyed in the later
4016  // pipeline.
4017  {
4018  OpBuilder::InsertionGuard guard(builder);
4019  builder.setInsertionPoint(op);
4020  StringRef namehint = isMux2 ? "mux2cell_in" : "mux4cell_in";
4021  for (auto [idx, operand] : llvm::enumerate(op->getOperands())) {
4022  auto [innerSym, _] = getOrAddInnerSym(
4023  op->getContext(), /*attr=*/nullptr, 0,
4024  [&]() -> hw::InnerSymbolNamespace & { return moduleNamespace; });
4025  auto wire =
4026  builder.create<hw::WireOp>(operand, namehint + Twine(idx), innerSym);
4027  op->setOperand(idx, wire);
4028  }
4029  }
4030 
4031  auto assignOp = builder.create<sv::AssignOp>(valWire, val);
4032  sv::setSVAttributes(assignOp,
4033  sv::SVAttributeAttr::get(builder.getContext(),
4034  "synopsys infer_mux_override",
4035  /*emitAsComment=*/true));
4036  return builder.create<sv::ReadInOutOp>(valWire);
4037 }
4038 
4039 Value FIRRTLLowering::createArrayIndexing(Value array, Value index) {
4040 
4041  auto size = hw::type_cast<hw::ArrayType>(array.getType()).getNumElements();
4042  // Extend to power of 2. FIRRTL semantics say out-of-bounds access result in
4043  // an indeterminate value. Existing chisel code depends on this behavior
4044  // being "return index 0". Ideally, we would tail extend the array to improve
4045  // optimization.
4046  if (!llvm::isPowerOf2_64(size)) {
4047  auto extElem = getOrCreateIntConstant(APInt(llvm::Log2_64_Ceil(size), 0));
4048  auto extValue = builder.create<hw::ArrayGetOp>(array, extElem);
4049  SmallVector<Value> temp(llvm::NextPowerOf2(size) - size, extValue);
4050  auto ext = builder.create<hw::ArrayCreateOp>(temp);
4051  Value temp2[] = {ext.getResult(), array};
4052  array = builder.create<hw::ArrayConcatOp>(temp2);
4053  }
4054 
4055  Value inBoundsRead = builder.create<hw::ArrayGetOp>(array, index);
4056 
4057  return inBoundsRead;
4058 }
4059 
4060 LogicalResult FIRRTLLowering::visitExpr(MultibitMuxOp op) {
4061  // Lower and resize to the index width.
4062  auto index = getLoweredAndExtOrTruncValue(
4063  op.getIndex(),
4064  UIntType::get(op.getContext(),
4065  getBitWidthFromVectorSize(op.getInputs().size())));
4066 
4067  if (!index)
4068  return failure();
4069  SmallVector<Value> loweredInputs;
4070  loweredInputs.reserve(op.getInputs().size());
4071  for (auto input : op.getInputs()) {
4072  auto lowered = getLoweredAndExtendedValue(input, op.getType());
4073  if (!lowered)
4074  return failure();
4075  loweredInputs.push_back(lowered);
4076  }
4077 
4078  Value array = builder.create<hw::ArrayCreateOp>(loweredInputs);
4079  return setLowering(op, createArrayIndexing(array, index));
4080 }
4081 
4082 LogicalResult FIRRTLLowering::visitExpr(VerbatimExprOp op) {
4083  auto resultTy = lowerType(op.getType());
4084  if (!resultTy)
4085  return failure();
4086 
4087  SmallVector<Value, 4> operands;
4088  operands.reserve(op.getSubstitutions().size());
4089  for (auto operand : op.getSubstitutions()) {
4090  auto lowered = getLoweredValue(operand);
4091  if (!lowered)
4092  return failure();
4093  operands.push_back(lowered);
4094  }
4095 
4096  ArrayAttr symbols = op.getSymbolsAttr();
4097  if (!symbols)
4098  symbols = ArrayAttr::get(op.getContext(), {});
4099 
4100  return setLoweringTo<sv::VerbatimExprOp>(op, resultTy, op.getTextAttr(),
4101  operands, symbols);
4102 }
4103 
4104 LogicalResult FIRRTLLowering::visitExpr(XMRRefOp op) {
4105  // This XMR is accessed solely by FIRRTL statements that mutate the probe.
4106  // To avoid the use of clock wires, create an `i1` wire and ensure that
4107  // all connections are also of the `i1` type.
4108  Type baseType = op.getType().getType();
4109 
4110  Type xmrType;
4111  if (isa<ClockType>(baseType))
4112  xmrType = builder.getIntegerType(1);
4113  else
4114  xmrType = lowerType(baseType);
4115 
4116  return setLoweringTo<sv::XMRRefOp>(op, sv::InOutType::get(xmrType),
4117  op.getRef(), op.getVerbatimSuffixAttr());
4118 }
4119 
4120 LogicalResult FIRRTLLowering::visitExpr(XMRDerefOp op) {
4121  // When an XMR targets a clock wire, replace it with an `i1` wire, but
4122  // introduce a clock-typed read op into the design afterwards.
4123  Type xmrType;
4124  if (isa<ClockType>(op.getType()))
4125  xmrType = builder.getIntegerType(1);
4126  else
4127  xmrType = lowerType(op.getType());
4128 
4129  auto xmr = builder.create<sv::XMRRefOp>(
4130  sv::InOutType::get(xmrType), op.getRef(), op.getVerbatimSuffixAttr());
4131  auto readXmr = getReadValue(xmr);
4132  if (!isa<ClockType>(op.getType()))
4133  return setLowering(op, readXmr);
4134  return setLoweringTo<seq::ToClockOp>(op, readXmr);
4135 }
4136 
4137 //===----------------------------------------------------------------------===//
4138 // Statements
4139 //===----------------------------------------------------------------------===//
4140 
4141 LogicalResult FIRRTLLowering::visitStmt(SkipOp op) {
4142  // Nothing! We could emit an comment as a verbatim op if there were a
4143  // reason to.
4144  return success();
4145 }
4146 
4147 /// Resolve a connection to `destVal`, an `hw::WireOp` or `seq::FirRegOp`, by
4148 /// updating the input operand to be `srcVal`. Returns true if the update was
4149 /// made and the connection can be considered lowered. Returns false if the
4150 /// destination isn't a wire or register with an input operand to be updated.
4151 /// Returns failure if the destination is a subaccess operation. These should be
4152 /// transposed to the right-hand-side by a pre-pass.
4153 FailureOr<bool> FIRRTLLowering::lowerConnect(Value destVal, Value srcVal) {
4154  auto srcType = srcVal.getType();
4155  auto dstType = destVal.getType();
4156  if (srcType != dstType &&
4157  (isa<hw::TypeAliasType>(srcType) || isa<hw::TypeAliasType>(dstType))) {
4158  srcVal = builder.create<hw::BitcastOp>(destVal.getType(), srcVal);
4159  }
4160  return TypeSwitch<Operation *, FailureOr<bool>>(destVal.getDefiningOp())
4161  .Case<hw::WireOp>([&](auto op) {
4162  maybeUnused(op.getInput());
4163  op.getInputMutable().assign(srcVal);
4164  return true;
4165  })
4166  .Case<seq::FirRegOp>([&](auto op) {
4167  maybeUnused(op.getNext());
4168  op.getNextMutable().assign(srcVal);
4169  return true;
4170  })
4171  .Case<hw::StructExtractOp, hw::ArrayGetOp>([](auto op) {
4172  // NOTE: msvc thinks `return op.emitOpError(...);` is ambiguous. So
4173  // return `failure()` separately.
4174  op.emitOpError("used as connect destination");
4175  return failure();
4176  })
4177  .Default([](auto) { return false; });
4178 }
4179 
4180 LogicalResult FIRRTLLowering::visitStmt(ConnectOp op) {
4181  auto dest = op.getDest();
4182  // The source can be a smaller integer, extend it as appropriate if so.
4183  auto destType = type_cast<FIRRTLBaseType>(dest.getType()).getPassiveType();
4184  auto srcVal = getLoweredAndExtendedValue(op.getSrc(), destType);
4185  if (!srcVal)
4186  return handleZeroBit(op.getSrc(), []() { return success(); });
4187 
4188  auto destVal = getPossiblyInoutLoweredValue(dest);
4189  if (!destVal)
4190  return failure();
4191 
4192  auto result = lowerConnect(destVal, srcVal);
4193  if (failed(result))
4194  return failure();
4195  if (*result)
4196  return success();
4197 
4198  // If this connect is driving a value that is currently a backedge, record
4199  // that the source is the value of the backedge.
4200  if (updateIfBackedge(destVal, srcVal))
4201  return success();
4202 
4203  if (!isa<hw::InOutType>(destVal.getType()))
4204  return op.emitError("destination isn't an inout type");
4205 
4206  builder.create<sv::AssignOp>(destVal, srcVal);
4207  return success();
4208 }
4209 
4210 LogicalResult FIRRTLLowering::visitStmt(MatchingConnectOp op) {
4211  auto dest = op.getDest();
4212  auto srcVal = getLoweredValue(op.getSrc());
4213  if (!srcVal)
4214  return handleZeroBit(op.getSrc(), []() { return success(); });
4215 
4216  auto destVal = getPossiblyInoutLoweredValue(dest);
4217  if (!destVal)
4218  return failure();
4219 
4220  auto result = lowerConnect(destVal, srcVal);
4221  if (failed(result))
4222  return failure();
4223  if (*result)
4224  return success();
4225 
4226  // If this connect is driving a value that is currently a backedge, record
4227  // that the source is the value of the backedge.
4228  if (updateIfBackedge(destVal, srcVal))
4229  return success();
4230 
4231  if (!isa<hw::InOutType>(destVal.getType()))
4232  return op.emitError("destination isn't an inout type");
4233 
4234  builder.create<sv::AssignOp>(destVal, srcVal);
4235  return success();
4236 }
4237 
4238 LogicalResult FIRRTLLowering::visitStmt(ForceOp op) {
4239  auto srcVal = getLoweredValue(op.getSrc());
4240  if (!srcVal)
4241  return failure();
4242 
4243  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4244  if (!destVal)
4245  return failure();
4246 
4247  if (!isa<hw::InOutType>(destVal.getType()))
4248  return op.emitError("destination isn't an inout type");
4249 
4250  // #ifndef SYNTHESIS
4251  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4252  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4253  addToInitialBlock([&]() { builder.create<sv::ForceOp>(destVal, srcVal); });
4254  });
4255  return success();
4256 }
4257 
4258 LogicalResult FIRRTLLowering::visitStmt(RefForceOp op) {
4259  auto src = getLoweredNonClockValue(op.getSrc());
4260  auto clock = getLoweredNonClockValue(op.getClock());
4261  auto pred = getLoweredValue(op.getPredicate());
4262  if (!src || !clock || !pred)
4263  return failure();
4264 
4265  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4266  if (!destVal)
4267  return failure();
4268 
4269  // #ifndef SYNTHESIS
4270  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4271  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4272  addToAlwaysBlock(clock, [&]() {
4273  addIfProceduralBlock(
4274  pred, [&]() { builder.create<sv::ForceOp>(destVal, src); });
4275  });
4276  });
4277  return success();
4278 }
4279 LogicalResult FIRRTLLowering::visitStmt(RefForceInitialOp op) {
4280  auto src = getLoweredNonClockValue(op.getSrc());
4281  auto pred = getLoweredValue(op.getPredicate());
4282  if (!src || !pred)
4283  return failure();
4284 
4285  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4286  if (!destVal)
4287  return failure();
4288 
4289  // #ifndef SYNTHESIS
4290  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4291  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4292  addToInitialBlock([&]() {
4293  addIfProceduralBlock(
4294  pred, [&]() { builder.create<sv::ForceOp>(destVal, src); });
4295  });
4296  });
4297  return success();
4298 }
4299 LogicalResult FIRRTLLowering::visitStmt(RefReleaseOp op) {
4300  auto clock = getLoweredNonClockValue(op.getClock());
4301  auto pred = getLoweredValue(op.getPredicate());
4302  if (!clock || !pred)
4303  return failure();
4304 
4305  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4306  if (!destVal)
4307  return failure();
4308 
4309  // #ifndef SYNTHESIS
4310  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4311  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4312  addToAlwaysBlock(clock, [&]() {
4313  addIfProceduralBlock(pred,
4314  [&]() { builder.create<sv::ReleaseOp>(destVal); });
4315  });
4316  });
4317  return success();
4318 }
4319 LogicalResult FIRRTLLowering::visitStmt(RefReleaseInitialOp op) {
4320  auto destVal = getPossiblyInoutLoweredValue(op.getDest());
4321  auto pred = getLoweredValue(op.getPredicate());
4322  if (!destVal || !pred)
4323  return failure();
4324 
4325  // #ifndef SYNTHESIS
4326  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4327  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4328  addToInitialBlock([&]() {
4329  addIfProceduralBlock(pred,
4330  [&]() { builder.create<sv::ReleaseOp>(destVal); });
4331  });
4332  });
4333  return success();
4334 }
4335 
4336 // Printf is a macro op that lowers to an sv.ifdef.procedural, an sv.if,
4337 // and an sv.fwrite all nested together.
4338 LogicalResult FIRRTLLowering::visitStmt(PrintFOp op) {
4339  auto clock = getLoweredNonClockValue(op.getClock());
4340  auto cond = getLoweredValue(op.getCond());
4341  if (!clock || !cond)
4342  return failure();
4343 
4344  SmallVector<Value, 4> operands;
4345  operands.reserve(op.getSubstitutions().size());
4346  for (auto operand : op.getSubstitutions()) {
4347  Value loweredValue = getLoweredFmtOperand(operand);
4348  if (!loweredValue)
4349  return failure();
4350  operands.push_back(loweredValue);
4351  }
4352 
4353  // Emit an "#ifndef SYNTHESIS" guard into the always block.
4354  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4355  addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
4356  addToAlwaysBlock(clock, [&]() {
4357  circuitState.usedPrintfCond = true;
4358  circuitState.addFragment(theModule, "PRINTF_COND_FRAGMENT");
4359 
4360  // Emit an "sv.if '`PRINTF_COND_ & cond' into the #ifndef.
4361  Value ifCond =
4362  builder.create<sv::MacroRefExprOp>(cond.getType(), "PRINTF_COND_");
4363  ifCond = builder.createOrFold<comb::AndOp>(ifCond, cond, true);
4364 
4365  addIfProceduralBlock(ifCond, [&]() {
4366  // Emit the sv.fwrite, writing to stderr by default.
4367  Value fdStderr = builder.create<hw::ConstantOp>(APInt(32, 0x80000002));
4368  builder.create<sv::FWriteOp>(fdStderr, op.getFormatString(), operands);
4369  });
4370  });
4371  });
4372 
4373  return success();
4374 }
4375 
4376 // Stop lowers into a nested series of behavioral statements plus $fatal
4377 // or $finish.
4378 LogicalResult FIRRTLLowering::visitStmt(StopOp op) {
4379  auto clock = getLoweredValue(op.getClock());
4380  auto cond = getLoweredValue(op.getCond());
4381  if (!clock || !cond)
4382  return failure();
4383 
4384  circuitState.usedStopCond = true;
4385  circuitState.addFragment(theModule, "STOP_COND_FRAGMENT");
4386 
4387  Value stopCond =
4388  builder.create<sv::MacroRefExprOp>(cond.getType(), "STOP_COND_");
4389  Value exitCond = builder.createOrFold<comb::AndOp>(stopCond, cond, true);
4390 
4391  if (op.getExitCode())
4392  builder.create<sim::FatalOp>(clock, exitCond);
4393  else
4394  builder.create<sim::FinishOp>(clock, exitCond);
4395 
4396  return success();
4397 }
4398 
4399 /// Helper function to build an immediate assert operation based on the
4400 /// original FIRRTL operation name. This reduces code duplication in
4401 /// `lowerVerificationStatement`.
4402 template <typename... Args>
4403 static Operation *buildImmediateVerifOp(ImplicitLocOpBuilder &builder,
4404  StringRef opName, Args &&...args) {
4405  if (opName == "assert")
4406  return builder.create<sv::AssertOp>(std::forward<Args>(args)...);
4407  if (opName == "assume")
4408  return builder.create<sv::AssumeOp>(std::forward<Args>(args)...);
4409  if (opName == "cover")
4410  return builder.create<sv::CoverOp>(std::forward<Args>(args)...);
4411  llvm_unreachable("unknown verification op");
4412 }
4413 
4414 /// Helper function to build a concurrent assert operation based on the
4415 /// original FIRRTL operation name. This reduces code duplication in
4416 /// `lowerVerificationStatement`.
4417 template <typename... Args>
4418 static Operation *buildConcurrentVerifOp(ImplicitLocOpBuilder &builder,
4419  StringRef opName, Args &&...args) {
4420  if (opName == "assert")
4421  return builder.create<sv::AssertConcurrentOp>(std::forward<Args>(args)...);
4422  if (opName == "assume")
4423  return builder.create<sv::AssumeConcurrentOp>(std::forward<Args>(args)...);
4424  if (opName == "cover")
4425  return builder.create<sv::CoverConcurrentOp>(std::forward<Args>(args)...);
4426  llvm_unreachable("unknown verification op");
4427 }
4428 
4429 /// Template for lowering verification statements from type A to
4430 /// type B.
4431 ///
4432 /// For example, lowering the "foo" op to the "bar" op would start
4433 /// with:
4434 ///
4435 /// foo(clock, condition, enable, "message")
4436 ///
4437 /// This becomes a Verilog clocking block with the "bar" op guarded
4438 /// by an if enable:
4439 ///
4440 /// always @(posedge clock) begin
4441 /// if (enable) begin
4442 /// bar(condition);
4443 /// end
4444 /// end
4445 /// The above can also be reduced into a concurrent verification statement
4446 /// sv.assert.concurrent posedge %clock (condition && enable)
4447 LogicalResult FIRRTLLowering::lowerVerificationStatement(
4448  Operation *op, StringRef labelPrefix, Value opClock, Value opPredicate,
4449  Value opEnable, StringAttr opMessageAttr, ValueRange opOperands,
4450  StringAttr opNameAttr, bool isConcurrent, EventControl opEventControl) {
4451  StringRef opName = op->getName().stripDialect();
4452 
4453  // The attribute holding the compile guards
4454  ArrayRef<Attribute> guards{};
4455  if (auto guardsAttr = op->template getAttrOfType<ArrayAttr>("guards"))
4456  guards = guardsAttr.getValue();
4457 
4458  auto isCover = isa<CoverOp>(op);
4459  auto clock = getLoweredNonClockValue(opClock);
4460  auto enable = getLoweredValue(opEnable);
4461  auto predicate = getLoweredValue(opPredicate);
4462  if (!clock || !enable || !predicate)
4463  return failure();
4464 
4465  StringAttr label;
4466  if (opNameAttr && !opNameAttr.getValue().empty())
4467  label = opNameAttr;
4468  StringAttr prefixedLabel;
4469  if (label)
4470  prefixedLabel =
4471  StringAttr::get(builder.getContext(), labelPrefix + label.getValue());
4472 
4473  StringAttr message;
4474  SmallVector<Value> messageOps;
4475  VerificationFlavor flavor = circuitState.verificationFlavor;
4476 
4477  // For non-assertion, rollback to per-op configuration.
4478  if (flavor == VerificationFlavor::IfElseFatal && !isa<AssertOp>(op))
4479  flavor = VerificationFlavor::None;
4480 
4481  if (flavor == VerificationFlavor::None) {
4482  // TODO: This should *not* be part of the op, but rather a lowering
4483  // option that the user of this pass can choose.
4484 
4485  auto format = op->getAttrOfType<StringAttr>("format");
4486  // if-else-fatal iff concurrent and the format is specified.
4487  if (isConcurrent && format && format.getValue() == "ifElseFatal") {
4488  if (!isa<AssertOp>(op))
4489  return op->emitError()
4490  << "ifElseFatal format cannot be used for non-assertions";
4491  flavor = VerificationFlavor::IfElseFatal;
4492  } else if (isConcurrent)
4493  flavor = VerificationFlavor::SVA;
4494  else
4495  flavor = VerificationFlavor::Immediate;
4496  }
4497 
4498  if (!isCover && opMessageAttr && !opMessageAttr.getValue().empty()) {
4499  message = opMessageAttr;
4500  for (auto operand : opOperands) {
4501  auto loweredValue = getLoweredFmtOperand(operand);
4502  if (!loweredValue)
4503  return failure();
4504 
4505  // For SVA assert/assume statements, wrap any message ops in $sampled() to
4506  // guarantee that these will print with the same value as when the
4507  // assertion triggers. (See SystemVerilog 2017 spec section 16.9.3 for
4508  // more information.)
4509  if (flavor == VerificationFlavor::SVA)
4510  loweredValue = builder.create<sv::SampledOp>(loweredValue);
4511  messageOps.push_back(loweredValue);
4512  }
4513  }
4514 
4515  auto emit = [&]() {
4516  switch (flavor) {
4517  case VerificationFlavor::Immediate: {
4518  // Handle the purely procedural flavor of the operation.
4519  auto deferImmediate = circt::sv::DeferAssertAttr::get(
4520  builder.getContext(), circt::sv::DeferAssert::Immediate);
4521  addToAlwaysBlock(clock, [&]() {
4522  addIfProceduralBlock(enable, [&]() {
4523  buildImmediateVerifOp(builder, opName, predicate, deferImmediate,
4524  prefixedLabel, message, messageOps);
4525  });
4526  });
4527  return;
4528  }
4529  case VerificationFlavor::IfElseFatal: {
4530  assert(isa<AssertOp>(op) && "only assert is expected");
4531  // Handle the `ifElseFatal` format, which does not emit an SVA but
4532  // rather a process that uses $error and $fatal to perform the checks.
4533  auto boolType = IntegerType::get(builder.getContext(), 1);
4534  predicate = comb::createOrFoldNot(predicate, builder, /*twoState=*/true);
4535  predicate = builder.createOrFold<comb::AndOp>(enable, predicate, true);
4536 
4537  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4538  addToIfDefBlock("SYNTHESIS", {}, [&]() {
4539  addToAlwaysBlock(clock, [&]() {
4540  addIfProceduralBlock(predicate, [&]() {
4541  circuitState.usedStopCond = true;
4542  circuitState.addFragment(theModule, "STOP_COND_FRAGMENT");
4543 
4544  circuitState.usedAssertVerboseCond = true;
4545  circuitState.addFragment(theModule, "ASSERT_VERBOSE_COND_FRAGMENT");
4546 
4547  addIfProceduralBlock(
4548  builder.create<sv::MacroRefExprOp>(boolType,
4549  "ASSERT_VERBOSE_COND_"),
4550  [&]() { builder.create<sv::ErrorOp>(message, messageOps); });
4551  addIfProceduralBlock(
4552  builder.create<sv::MacroRefExprOp>(boolType, "STOP_COND_"),
4553  [&]() { builder.create<sv::FatalOp>(); });
4554  });
4555  });
4556  });
4557  return;
4558  }
4559  case VerificationFlavor::SVA: {
4560  // Formulate the `enable -> predicate` as `!enable | predicate`.
4561  // Except for covers, combine them: enable & predicate
4562  if (!isCover) {
4563  auto notEnable =
4564  comb::createOrFoldNot(enable, builder, /*twoState=*/true);
4565  predicate =
4566  builder.createOrFold<comb::OrOp>(notEnable, predicate, true);
4567  } else {
4568  predicate = builder.createOrFold<comb::AndOp>(enable, predicate, true);
4569  }
4570 
4571  // Handle the regular SVA case.
4572  sv::EventControl event;
4573  switch (opEventControl) {
4574  case EventControl::AtPosEdge:
4575  event = circt::sv::EventControl::AtPosEdge;
4576  break;
4577  case EventControl::AtEdge:
4578  event = circt::sv::EventControl::AtEdge;
4579  break;
4580  case EventControl::AtNegEdge:
4581  event = circt::sv::EventControl::AtNegEdge;
4582  break;
4583  }
4584 
4586  builder, opName,
4587  circt::sv::EventControlAttr::get(builder.getContext(), event), clock,
4588  predicate, prefixedLabel, message, messageOps);
4589  return;
4590  }
4591  case VerificationFlavor::None:
4592  llvm_unreachable(
4593  "flavor `None` must be converted into one of concreate flavors");
4594  }
4595  };
4596 
4597  // Wrap the verification statement up in the optional preprocessor
4598  // guards. This is a bit awkward since we want to translate an array of
4599  // guards into a recursive call to `addToIfDefBlock`.
4600  return emitGuards(op->getLoc(), guards, emit);
4601 }
4602 
4603 // Lower an assert to SystemVerilog.
4604 LogicalResult FIRRTLLowering::visitStmt(AssertOp op) {
4605  return lowerVerificationStatement(
4606  op, "assert__", op.getClock(), op.getPredicate(), op.getEnable(),
4607  op.getMessageAttr(), op.getSubstitutions(), op.getNameAttr(),
4608  op.getIsConcurrent(), op.getEventControl());
4609 }
4610 
4611 // Lower an assume to SystemVerilog.
4612 LogicalResult FIRRTLLowering::visitStmt(AssumeOp op) {
4613  return lowerVerificationStatement(
4614  op, "assume__", op.getClock(), op.getPredicate(), op.getEnable(),
4615  op.getMessageAttr(), op.getSubstitutions(), op.getNameAttr(),
4616  op.getIsConcurrent(), op.getEventControl());
4617 }
4618 
4619 // Lower a cover to SystemVerilog.
4620 LogicalResult FIRRTLLowering::visitStmt(CoverOp op) {
4621  return lowerVerificationStatement(
4622  op, "cover__", op.getClock(), op.getPredicate(), op.getEnable(),
4623  op.getMessageAttr(), op.getSubstitutions(), op.getNameAttr(),
4624  op.getIsConcurrent(), op.getEventControl());
4625 }
4626 
4627 // Lower an UNR only assume to a specific style of SV assume.
4628 LogicalResult FIRRTLLowering::visitStmt(UnclockedAssumeIntrinsicOp op) {
4629  // TODO : Need to figure out if there is a cleaner way to get the string which
4630  // indicates the assert is UNR only. Or better - not rely on this at all -
4631  // ideally there should have been some other attribute which indicated that
4632  // this assert for UNR only.
4633  auto guardsAttr = op->getAttrOfType<mlir::ArrayAttr>("guards");
4634  ArrayRef<Attribute> guards =
4635  guardsAttr ? guardsAttr.getValue() : ArrayRef<Attribute>();
4636 
4637  auto label = op.getNameAttr();
4638  StringAttr assumeLabel;
4639  if (label && !label.empty())
4640  assumeLabel =
4641  StringAttr::get(builder.getContext(), "assume__" + label.getValue());
4642  auto predicate = getLoweredValue(op.getPredicate());
4643  auto enable = getLoweredValue(op.getEnable());
4644  auto notEnable = comb::createOrFoldNot(enable, builder, /*twoState=*/true);
4645  predicate = builder.createOrFold<comb::OrOp>(notEnable, predicate, true);
4646 
4647  SmallVector<Value> messageOps;
4648  for (auto operand : op.getSubstitutions()) {
4649  auto loweredValue = getLoweredValue(operand);
4650  if (!loweredValue) {
4651  // If this is a zero bit operand, just pass a one bit zero.
4652  if (!isZeroBitFIRRTLType(operand.getType()))
4653  return failure();
4654  loweredValue = getOrCreateIntConstant(1, 0);
4655  }
4656  messageOps.push_back(loweredValue);
4657  }
4658  return emitGuards(op.getLoc(), guards, [&]() {
4659  builder.create<sv::AlwaysOp>(
4660  ArrayRef(sv::EventControl::AtEdge), ArrayRef(predicate), [&]() {
4661  if (op.getMessageAttr().getValue().empty())
4662  buildImmediateVerifOp(
4663  builder, "assume", predicate,
4664  circt::sv::DeferAssertAttr::get(
4665  builder.getContext(), circt::sv::DeferAssert::Immediate),
4666  assumeLabel);
4667  else
4668  buildImmediateVerifOp(
4669  builder, "assume", predicate,
4670  circt::sv::DeferAssertAttr::get(
4671  builder.getContext(), circt::sv::DeferAssert::Immediate),
4672  assumeLabel, op.getMessageAttr(), messageOps);
4673  });
4674  });
4675 }
4676 
4677 LogicalResult FIRRTLLowering::visitStmt(AttachOp op) {
4678  // Don't emit anything for a zero or one operand attach.
4679  if (op.getAttached().size() < 2)
4680  return success();
4681 
4682  SmallVector<Value, 4> inoutValues;
4683  for (auto v : op.getAttached()) {
4684  inoutValues.push_back(getPossiblyInoutLoweredValue(v));
4685  if (!inoutValues.back()) {
4686  // Ignore zero bit values.
4687  if (!isZeroBitFIRRTLType(v.getType()))
4688  return failure();
4689  inoutValues.pop_back();
4690  continue;
4691  }
4692 
4693  if (!isa<hw::InOutType>(inoutValues.back().getType()))
4694  return op.emitError("operand isn't an inout type");
4695  }
4696 
4697  if (inoutValues.size() < 2)
4698  return success();
4699 
4700  // If the op has a single source value, the value is used as a lowering result
4701  // of other values. Therefore we can delete the attach op here.
4703  return success();
4704 
4705  // If all operands of the attach are internal to this module (none of them
4706  // are ports), then they can all be replaced with a single wire, and we can
4707  // delete the attach op.
4708  bool isAttachInternalOnly =
4709  llvm::none_of(inoutValues, [](auto v) { return isa<BlockArgument>(v); });
4710 
4711  if (isAttachInternalOnly) {
4712  auto v0 = inoutValues.front();
4713  for (auto v : inoutValues) {
4714  if (v == v0)
4715  continue;
4716  v.replaceAllUsesWith(v0);
4717  }
4718  return success();
4719  }
4720 
4721  // If the attach operands contain a port, then we can't do anything to
4722  // simplify the attach operation.
4723  circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
4724  circuitState.addMacroDecl(builder.getStringAttr("VERILATOR"));
4725  addToIfDefBlock(
4726  "SYNTHESIS",
4727  // If we're doing synthesis, we emit an all-pairs assign complex.
4728  [&]() {
4729  SmallVector<Value, 4> values;
4730  for (size_t i = 0, e = inoutValues.size(); i != e; ++i)
4731  values.push_back(getReadValue(inoutValues[i]));
4732 
4733  for (size_t i1 = 0, e = inoutValues.size(); i1 != e; ++i1) {
4734  for (size_t i2 = 0; i2 != e; ++i2)
4735  if (i1 != i2)
4736  builder.create<sv::AssignOp>(inoutValues[i1], values[i2]);
4737  }
4738  },
4739  // In the non-synthesis case, we emit a SystemVerilog alias
4740  // statement.
4741  [&]() {
4742  builder.create<sv::IfDefOp>(
4743  "VERILATOR",
4744  [&]() {
4745  builder.create<sv::VerbatimOp>(
4746  "`error \"Verilator does not support alias and thus "
4747  "cannot "
4748  "arbitrarily connect bidirectional wires and ports\"");
4749  },
4750  [&]() { builder.create<sv::AliasOp>(inoutValues); });
4751  });
4752 
4753  return success();
4754 }
4755 
4756 LogicalResult FIRRTLLowering::fixupLTLOps() {
4757  if (ltlOpFixupWorklist.empty())
4758  return success();
4759  LLVM_DEBUG(llvm::dbgs() << "Fixing up " << ltlOpFixupWorklist.size()
4760  << " LTL ops\n");
4761 
4762  // Add wire users into the worklist.
4763  for (unsigned i = 0, e = ltlOpFixupWorklist.size(); i != e; ++i)
4764  for (auto *user : ltlOpFixupWorklist[i]->getUsers())
4765  if (isa<hw::WireOp>(user))
4766  ltlOpFixupWorklist.insert(user);
4767 
4768  // Re-infer LTL op types and remove wires.
4769  while (!ltlOpFixupWorklist.empty()) {
4770  auto *op = ltlOpFixupWorklist.pop_back_val();
4771 
4772  // Update the operation's return type by re-running type inference.
4773  if (auto opIntf = dyn_cast_or_null<mlir::InferTypeOpInterface>(op)) {
4774  LLVM_DEBUG(llvm::dbgs() << "- Update " << *op << "\n");
4775  SmallVector<Type, 2> types;
4776  auto result = opIntf.inferReturnTypes(
4777  op->getContext(), op->getLoc(), op->getOperands(),
4778  op->getAttrDictionary(), op->getPropertiesStorage(), op->getRegions(),
4779  types);
4780  if (failed(result))
4781  return failure();
4782  assert(types.size() == op->getNumResults());
4783 
4784  // Update the result types and add the dependent ops into the worklist if
4785  // the type changed.
4786  for (auto [result, type] : llvm::zip(op->getResults(), types)) {
4787  if (result.getType() == type)
4788  continue;
4789  LLVM_DEBUG(llvm::dbgs()
4790  << " - Result #" << result.getResultNumber() << " from "
4791  << result.getType() << " to " << type << "\n");
4792  result.setType(type);
4793  for (auto *user : result.getUsers())
4794  if (user != op)
4795  ltlOpFixupWorklist.insert(user);
4796  }
4797  }
4798 
4799  // Remove LTL-typed wires.
4800  if (auto wireOp = dyn_cast<hw::WireOp>(op)) {
4801  if (isa<ltl::SequenceType, ltl::PropertyType>(wireOp.getType())) {
4802  wireOp.replaceAllUsesWith(wireOp.getInput());
4803  LLVM_DEBUG(llvm::dbgs() << "- Remove " << wireOp << "\n");
4804  if (wireOp.use_empty())
4805  wireOp.erase();
4806  }
4807  continue;
4808  }
4809 
4810  // Ensure that the operation has no users outside of LTL operations.
4811  SmallPtrSet<Operation *, 4> usersReported;
4812  for (auto *user : op->getUsers()) {
4813  if (!usersReported.insert(user).second)
4814  continue;
4815  if (isa<ltl::LTLDialect, verif::VerifDialect>(user->getDialect()))
4816  continue;
4817  if (isa<hw::WireOp>(user))
4818  continue;
4819  auto d = op->emitError(
4820  "verification operation used in a non-verification context");
4821  d.attachNote(user->getLoc())
4822  << "leaking outside verification context here";
4823  return d;
4824  }
4825  }
4826 
4827  return success();
4828 }
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:4403
static LogicalResult handleZeroBit(Value failedOperand, std::function< LogicalResult()> fn)
Zero bit operands end up looking like failures from getLoweredValue.
Definition: LowerToHW.cpp:1983
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:4418
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
llvm::SmallVector< StringAttr > outputs
Builder builder
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:294
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
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:54
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:3929
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
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition: seq.py:20
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.