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