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