CIRCT  20.0.0git
ExportVerilog.cpp
Go to the documentation of this file.
1 //===- ExportVerilog.cpp - Verilog Emitter --------------------------------===//
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 Verilog emitter implementation.
10 //
11 // CAREFUL: This file covers the emission phase of `ExportVerilog` which mainly
12 // walks the IR and produces output. Do NOT modify the IR during this walk, as
13 // emission occurs in a highly parallel fashion. If you need to modify the IR,
14 // do so during the preparation phase which lives in `PrepareForEmission.cpp`.
15 //
16 //===----------------------------------------------------------------------===//
17 
19 #include "ExportVerilogInternals.h"
25 #include "circt/Dialect/HW/HWOps.h"
29 #include "circt/Dialect/OM/OMOps.h"
31 #include "circt/Dialect/SV/SVOps.h"
34 #include "circt/Support/LLVM.h"
36 #include "circt/Support/Path.h"
39 #include "circt/Support/Version.h"
40 #include "mlir/IR/BuiltinOps.h"
41 #include "mlir/IR/ImplicitLocOpBuilder.h"
42 #include "mlir/IR/Location.h"
43 #include "mlir/IR/Threading.h"
44 #include "mlir/Interfaces/FunctionImplementation.h"
45 #include "mlir/Pass/PassManager.h"
46 #include "mlir/Support/FileUtilities.h"
47 #include "llvm/ADT/MapVector.h"
48 #include "llvm/ADT/STLExtras.h"
49 #include "llvm/ADT/StringSet.h"
50 #include "llvm/ADT/TypeSwitch.h"
51 #include "llvm/Support/FileSystem.h"
52 #include "llvm/Support/FormattedStream.h"
53 #include "llvm/Support/Path.h"
54 #include "llvm/Support/SaveAndRestore.h"
55 #include "llvm/Support/ToolOutputFile.h"
56 #include "llvm/Support/raw_ostream.h"
57 
58 namespace circt {
59 #define GEN_PASS_DEF_EXPORTSPLITVERILOG
60 #define GEN_PASS_DEF_EXPORTVERILOG
61 #include "circt/Conversion/Passes.h.inc"
62 } // namespace circt
63 
64 using namespace circt;
65 using namespace comb;
66 using namespace hw;
67 using namespace sv;
68 using namespace ExportVerilog;
69 
70 using namespace pretty;
71 
72 #define DEBUG_TYPE "export-verilog"
73 
74 StringRef circtHeader = "circt_header.svh";
75 StringRef circtHeaderInclude = "`include \"circt_header.svh\"\n";
76 
77 namespace {
78 /// This enum keeps track of the precedence level of various binary operators,
79 /// where a lower number binds tighter.
80 enum VerilogPrecedence {
81  // Normal precedence levels.
82  Symbol, // Atomic symbol like "foo" and {a,b}
83  Selection, // () , [] , :: , ., $signed()
84  Unary, // Unary operators like ~foo
85  Multiply, // * , / , %
86  Addition, // + , -
87  Shift, // << , >>, <<<, >>>
88  Comparison, // > , >= , < , <=
89  Equality, // == , !=
90  And, // &
91  Xor, // ^ , ^~
92  Or, // |
93  AndShortCircuit, // &&
94  Conditional, // ? :
95 
96  LowestPrecedence, // Sentinel which is always the lowest precedence.
97 };
98 
99 /// This enum keeps track of whether the emitted subexpression is signed or
100 /// unsigned as seen from the Verilog language perspective.
101 enum SubExprSignResult { IsSigned, IsUnsigned };
102 
103 /// This is information precomputed about each subexpression in the tree we
104 /// are emitting as a unit.
105 struct SubExprInfo {
106  /// The precedence of this expression.
107  VerilogPrecedence precedence;
108 
109  /// The signedness of the expression.
110  SubExprSignResult signedness;
111 
112  SubExprInfo(VerilogPrecedence precedence, SubExprSignResult signedness)
113  : precedence(precedence), signedness(signedness) {}
114 };
115 
116 } // end anonymous namespace
117 
118 //===----------------------------------------------------------------------===//
119 // Helper routines
120 //===----------------------------------------------------------------------===//
121 
122 static TypedAttr getInt32Attr(MLIRContext *ctx, uint32_t value) {
123  return Builder(ctx).getI32IntegerAttr(value);
124 }
125 
126 static TypedAttr getIntAttr(MLIRContext *ctx, Type t, const APInt &value) {
127  return Builder(ctx).getIntegerAttr(t, value);
128 }
129 
130 /// Return true for nullary operations that are better emitted multiple
131 /// times as inline expression (when they have multiple uses) rather than having
132 /// a temporary wire.
133 ///
134 /// This can only handle nullary expressions, because we don't want to replicate
135 /// subtrees arbitrarily.
136 static bool isDuplicatableNullaryExpression(Operation *op) {
137  // We don't want wires that are just constants aesthetically.
138  if (isConstantExpression(op))
139  return true;
140 
141  // If this is a small verbatim expression with no side effects, duplicate it
142  // inline.
143  if (isa<VerbatimExprOp>(op)) {
144  if (op->getNumOperands() == 0 &&
145  op->getAttrOfType<StringAttr>("format_string").getValue().size() <= 32)
146  return true;
147  }
148 
149  // Always duplicate XMRs into their use site.
150  if (isa<XMRRefOp>(op))
151  return true;
152 
153  // If this is a macro reference without side effects, allow duplication.
154  if (isa<MacroRefExprOp>(op))
155  return true;
156 
157  return false;
158 }
159 
160 // Return true if the expression can be inlined even when the op has multiple
161 // uses. Be careful to add operations here since it might cause exponential
162 // emission without proper restrictions.
163 static bool isDuplicatableExpression(Operation *op) {
164  if (op->getNumOperands() == 0)
166 
167  // It is cheap to inline extract op.
168  if (isa<comb::ExtractOp, hw::StructExtractOp, hw::UnionExtractOp>(op))
169  return true;
170 
171  // We only inline array_get with a constant, port or wire index.
172  if (auto array = dyn_cast<hw::ArrayGetOp>(op)) {
173  auto *indexOp = array.getIndex().getDefiningOp();
174  if (!indexOp || isa<ConstantOp>(indexOp))
175  return true;
176  if (auto read = dyn_cast<ReadInOutOp>(indexOp)) {
177  auto *readSrc = read.getInput().getDefiningOp();
178  // A port or wire is ok to duplicate reads.
179  return !readSrc || isa<sv::WireOp, LogicOp>(readSrc);
180  }
181 
182  return false;
183  }
184 
185  return false;
186 }
187 
188 /// Return the verilog name of the operations that can define a symbol.
189 /// Legalized names are added to "hw.verilogName" so look up it when the
190 /// attribute already exists.
191 StringRef ExportVerilog::getSymOpName(Operation *symOp) {
192  // Typeswitch of operation types which can define a symbol.
193  // If legalizeNames has renamed it, then the attribute must be set.
194  if (auto attr = symOp->getAttrOfType<StringAttr>("hw.verilogName"))
195  return attr.getValue();
196  return TypeSwitch<Operation *, StringRef>(symOp)
197  .Case<HWModuleOp, HWModuleExternOp, HWModuleGeneratedOp, FuncOp>(
198  [](Operation *op) { return getVerilogModuleName(op); })
199  .Case<InterfaceOp>([&](InterfaceOp op) {
200  return getVerilogModuleNameAttr(op).getValue();
201  })
202  .Case<InterfaceSignalOp>(
203  [&](InterfaceSignalOp op) { return op.getSymName(); })
204  .Case<InterfaceModportOp>(
205  [&](InterfaceModportOp op) { return op.getSymName(); })
206  .Default([&](Operation *op) {
207  if (auto attr = op->getAttrOfType<StringAttr>("name"))
208  return attr.getValue();
209  if (auto attr = op->getAttrOfType<StringAttr>("instanceName"))
210  return attr.getValue();
211  if (auto attr = op->getAttrOfType<StringAttr>("sv.namehint"))
212  return attr.getValue();
213  if (auto attr =
214  op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()))
215  return attr.getValue();
216  return StringRef("");
217  });
218 }
219 
220 /// Emits a known-safe token that is legal when indexing into singleton arrays.
221 template <typename PPS>
222 static void emitZeroWidthIndexingValue(PPS &os) {
223  os << "/*Zero width*/ 1\'b0";
224 }
225 
226 /// Return the verilog name of the port for the module.
227 static StringRef getPortVerilogName(Operation *module, size_t portArgNum) {
228  auto hml = cast<HWModuleLike>(module);
229  return hml.getPort(portArgNum).getVerilogName();
230 }
231 
232 /// Return the verilog name of the port for the module.
233 static StringRef getInputPortVerilogName(Operation *module, size_t portArgNum) {
234  auto hml = cast<HWModuleLike>(module);
235  auto pId = hml.getHWModuleType().getPortIdForInputId(portArgNum);
236  if (auto attrs = dyn_cast_or_null<DictionaryAttr>(hml.getPortAttrs(pId)))
237  if (auto updatedName = attrs.getAs<StringAttr>("hw.verilogName"))
238  return updatedName.getValue();
239  return hml.getHWModuleType().getPortName(pId);
240 }
241 
242 /// This predicate returns true if the specified operation is considered a
243 /// potentially inlinable Verilog expression. These nodes always have a single
244 /// result, but may have side effects (e.g. `sv.verbatim.expr.se`).
245 /// MemoryEffects should be checked if a client cares.
247  // These are SV dialect expressions.
248  if (isa<ReadInOutOp, AggregateConstantOp, ArrayIndexInOutOp,
249  IndexedPartSelectInOutOp, StructFieldInOutOp, IndexedPartSelectOp,
250  ParamValueOp, XMROp, XMRRefOp, SampledOp, EnumConstantOp,
251  SystemFunctionOp, UnpackedArrayCreateOp, UnpackedOpenArrayCastOp>(op))
252  return true;
253 
254  // All HW combinational logic ops and SV expression ops are Verilog
255  // expressions.
256  return isCombinational(op) || isExpression(op);
257 }
258 
259 // NOLINTBEGIN(misc-no-recursion)
260 /// Push this type's dimension into a vector.
261 static void getTypeDims(SmallVectorImpl<Attribute> &dims, Type type,
262  Location loc) {
263  if (auto integer = hw::type_dyn_cast<IntegerType>(type)) {
264  if (integer.getWidth() != 1)
265  dims.push_back(getInt32Attr(type.getContext(), integer.getWidth()));
266  return;
267  }
268  if (auto array = hw::type_dyn_cast<ArrayType>(type)) {
269  dims.push_back(getInt32Attr(type.getContext(), array.getNumElements()));
270  getTypeDims(dims, array.getElementType(), loc);
271 
272  return;
273  }
274  if (auto intType = hw::type_dyn_cast<IntType>(type)) {
275  dims.push_back(intType.getWidth());
276  return;
277  }
278 
279  if (auto inout = hw::type_dyn_cast<InOutType>(type))
280  return getTypeDims(dims, inout.getElementType(), loc);
281  if (auto uarray = hw::type_dyn_cast<hw::UnpackedArrayType>(type))
282  return getTypeDims(dims, uarray.getElementType(), loc);
283  if (auto uarray = hw::type_dyn_cast<sv::UnpackedOpenArrayType>(type))
284  return getTypeDims(dims, uarray.getElementType(), loc);
285 
286  if (hw::type_isa<InterfaceType, StructType, EnumType>(type))
287  return;
288 
289  mlir::emitError(loc, "value has an unsupported verilog type ") << type;
290 }
291 // NOLINTEND(misc-no-recursion)
292 
293 /// True iff 'a' and 'b' have the same wire dims.
294 static bool haveMatchingDims(Type a, Type b, Location loc) {
295  SmallVector<Attribute, 4> aDims;
296  getTypeDims(aDims, a, loc);
297 
298  SmallVector<Attribute, 4> bDims;
299  getTypeDims(bDims, b, loc);
300 
301  return aDims == bDims;
302 }
303 
304 // NOLINTBEGIN(misc-no-recursion)
306  type = getCanonicalType(type);
307  if (auto intType = dyn_cast<IntegerType>(type))
308  return intType.getWidth() == 0;
309  if (auto inout = dyn_cast<hw::InOutType>(type))
310  return isZeroBitType(inout.getElementType());
311  if (auto uarray = dyn_cast<hw::UnpackedArrayType>(type))
312  return uarray.getNumElements() == 0 ||
313  isZeroBitType(uarray.getElementType());
314  if (auto array = dyn_cast<hw::ArrayType>(type))
315  return array.getNumElements() == 0 || isZeroBitType(array.getElementType());
316  if (auto structType = dyn_cast<hw::StructType>(type))
317  return llvm::all_of(structType.getElements(),
318  [](auto elem) { return isZeroBitType(elem.type); });
319  if (auto enumType = dyn_cast<hw::EnumType>(type))
320  return enumType.getFields().empty();
321  if (auto unionType = dyn_cast<hw::UnionType>(type))
322  return hw::getBitWidth(unionType) == 0;
323 
324  // We have an open type system, so assume it is ok.
325  return false;
326 }
327 // NOLINTEND(misc-no-recursion)
328 
329 /// Given a set of known nested types (those supported by this pass), strip off
330 /// leading unpacked types. This strips off portions of the type that are
331 /// printed to the right of the name in verilog.
332 // NOLINTBEGIN(misc-no-recursion)
333 static Type stripUnpackedTypes(Type type) {
334  return TypeSwitch<Type, Type>(type)
335  .Case<InOutType>([](InOutType inoutType) {
336  return stripUnpackedTypes(inoutType.getElementType());
337  })
338  .Case<UnpackedArrayType, sv::UnpackedOpenArrayType>([](auto arrayType) {
339  return stripUnpackedTypes(arrayType.getElementType());
340  })
341  .Default([](Type type) { return type; });
342 }
343 
344 /// Return true if the type has a leading unpacked type.
345 static bool hasLeadingUnpackedType(Type type) {
346  assert(isa<hw::InOutType>(type) && "inout type is expected");
347  auto elementType = cast<hw::InOutType>(type).getElementType();
349 }
350 
351 /// Return true if type has a struct type as a subtype.
352 static bool hasStructType(Type type) {
353  return TypeSwitch<Type, bool>(type)
354  .Case<InOutType, UnpackedArrayType, ArrayType>([](auto parentType) {
355  return hasStructType(parentType.getElementType());
356  })
357  .Case<StructType>([](auto) { return true; })
358  .Default([](auto) { return false; });
359 }
360 // NOLINTEND(misc-no-recursion)
361 
362 //===----------------------------------------------------------------------===//
363 // Location comparison
364 //===----------------------------------------------------------------------===//
365 
366 // NOLINTBEGIN(misc-no-recursion)
367 
368 static int compareLocs(Location lhs, Location rhs);
369 
370 // NameLoc comparator - compare names, then child locations.
371 static int compareLocsImpl(mlir::NameLoc lhs, mlir::NameLoc rhs) {
372  if (auto name = lhs.getName().compare(rhs.getName()))
373  return name;
374  return compareLocs(lhs.getChildLoc(), rhs.getChildLoc());
375 }
376 
377 // FileLineColLoc comparator.
378 static int compareLocsImpl(mlir::FileLineColLoc lhs, mlir::FileLineColLoc rhs) {
379  if (auto fn = lhs.getFilename().compare(rhs.getFilename()))
380  return fn;
381  if (lhs.getLine() != rhs.getLine())
382  return lhs.getLine() < rhs.getLine() ? -1 : 1;
383  return lhs.getColumn() < rhs.getColumn() ? -1 : 1;
384 }
385 
386 // CallSiteLoc comparator. Compare first on the callee, then on the caller.
387 static int compareLocsImpl(mlir::CallSiteLoc lhs, mlir::CallSiteLoc rhs) {
388  Location lhsCallee = lhs.getCallee();
389  Location rhsCallee = rhs.getCallee();
390  if (auto res = compareLocs(lhsCallee, rhsCallee))
391  return res;
392 
393  Location lhsCaller = lhs.getCaller();
394  Location rhsCaller = rhs.getCaller();
395  return compareLocs(lhsCaller, rhsCaller);
396 }
397 
398 template <typename TTargetLoc>
399 FailureOr<int> dispatchCompareLocations(Location lhs, Location rhs) {
400  auto lhsT = dyn_cast<TTargetLoc>(lhs);
401  auto rhsT = dyn_cast<TTargetLoc>(rhs);
402  if (lhsT && rhsT) {
403  // Both are of the target location type, compare them directly.
404  return compareLocsImpl(lhsT, rhsT);
405  }
406  if (lhsT) {
407  // lhs is TTargetLoc => it comes before rhs.
408  return -1;
409  }
410  if (rhsT) {
411  // rhs is TTargetLoc => it comes before lhs.
412  return 1;
413  }
414 
415  return failure();
416 }
417 
418 // Top-level comparator for two arbitrarily typed locations.
419 // First order comparison by location type:
420 // 1. FileLineColLoc
421 // 2. NameLoc
422 // 3. CallSiteLoc
423 // 4. Anything else...
424 // Intra-location type comparison is delegated to the corresponding
425 // compareLocsImpl() function.
426 static int compareLocs(Location lhs, Location rhs) {
427  // FileLineColLoc
428  if (auto res = dispatchCompareLocations<mlir::FileLineColLoc>(lhs, rhs);
429  succeeded(res))
430  return *res;
431 
432  // NameLoc
433  if (auto res = dispatchCompareLocations<mlir::NameLoc>(lhs, rhs);
434  succeeded(res))
435  return *res;
436 
437  // CallSiteLoc
438  if (auto res = dispatchCompareLocations<mlir::CallSiteLoc>(lhs, rhs);
439  succeeded(res))
440  return *res;
441 
442  // Anything else...
443  return 0;
444 }
445 
446 // NOLINTEND(misc-no-recursion)
447 
448 //===----------------------------------------------------------------------===//
449 // Location printing
450 //===----------------------------------------------------------------------===//
451 
452 /// Pull apart any fused locations into the location set, such that they are
453 /// uniqued. Any other location type will be added as-is.
454 static void collectAndUniqueLocations(Location loc,
455  SmallPtrSetImpl<Attribute> &locationSet) {
456  llvm::TypeSwitch<Location, void>(loc)
457  .Case<FusedLoc>([&](auto fusedLoc) {
458  for (auto subLoc : fusedLoc.getLocations())
459  collectAndUniqueLocations(subLoc, locationSet);
460  })
461  .Default([&](auto loc) { locationSet.insert(loc); });
462 }
463 
464 // Sorts a vector of locations in-place.
465 template <typename TVector>
466 static void sortLocationVector(TVector &vec) {
467  llvm::array_pod_sort(
468  vec.begin(), vec.end(), [](const auto *lhs, const auto *rhs) -> int {
469  return compareLocs(cast<Location>(*lhs), cast<Location>(*rhs));
470  });
471 }
472 
474 public:
475  // Generates location info for a single location in the specified style.
477  SmallPtrSet<Attribute, 8> locationSet;
478  locationSet.insert(loc);
479  llvm::raw_string_ostream os(output);
480  emitLocationSetInfo(os, style, locationSet);
481  }
482 
483  // Generates location info for a set of operations in the specified style.
485  const SmallPtrSetImpl<Operation *> &ops) {
486  // Multiple operations may come from the same location or may not have
487  // useful
488  // location info. Unique it now.
489  SmallPtrSet<Attribute, 8> locationSet;
490  for (auto *op : ops)
491  collectAndUniqueLocations(op->getLoc(), locationSet);
492  llvm::raw_string_ostream os(output);
493  emitLocationSetInfo(os, style, locationSet);
494  }
495 
496  StringRef strref() { return output; }
497 
498 private:
499  void emitLocationSetInfo(llvm::raw_string_ostream &os,
501  const SmallPtrSetImpl<Attribute> &locationSet) {
502  if (style == LoweringOptions::LocationInfoStyle::None)
503  return;
504  std::string resstr;
505  llvm::raw_string_ostream sstr(resstr);
506  LocationEmitter::Impl(sstr, style, locationSet);
507  if (resstr.empty() || style == LoweringOptions::LocationInfoStyle::Plain) {
508  os << resstr;
509  return;
510  }
511  assert(style == LoweringOptions::LocationInfoStyle::WrapInAtSquareBracket &&
512  "other styles must be already handled");
513  os << "@[" << resstr << "]";
514  }
515 
516  std::string output;
517 
518  struct Impl {
519 
520  // NOLINTBEGIN(misc-no-recursion)
521  Impl(llvm::raw_string_ostream &os, LoweringOptions::LocationInfoStyle style,
522  const SmallPtrSetImpl<Attribute> &locationSet)
523  : os(os), style(style) {
524  emitLocationSetInfoImpl(locationSet);
525  }
526 
527  // Emit CallSiteLocs.
528  void emitLocationInfo(mlir::CallSiteLoc loc) {
529  os << "{";
530  emitLocationInfo(loc.getCallee());
531  os << " <- ";
532  emitLocationInfo(loc.getCaller());
533  os << "}";
534  }
535 
536  // Emit NameLocs.
537  void emitLocationInfo(mlir::NameLoc loc) {
538  bool withName = !loc.getName().empty();
539  if (withName)
540  os << "'" << loc.getName().strref() << "'(";
541  emitLocationInfo(loc.getChildLoc());
542 
543  if (withName)
544  os << ")";
545  }
546 
547  // Emit FileLineColLocs.
548  void emitLocationInfo(FileLineColLoc loc) {
549  os << loc.getFilename().getValue();
550  if (auto line = loc.getLine()) {
551  os << ':' << line;
552  if (auto col = loc.getColumn())
553  os << ':' << col;
554  }
555  }
556 
557  // Generates a string representation of a set of FileLineColLocs.
558  // The entries are sorted by filename, line, col. Try to merge together
559  // entries to reduce verbosity on the column info.
560  void
561  printFileLineColSetInfo(llvm::SmallVector<FileLineColLoc, 8> locVector) {
562  // The entries are sorted by filename, line, col. Try to merge together
563  // entries to reduce verbosity on the column info.
564  StringRef lastFileName;
565  for (size_t i = 0, e = locVector.size(); i != e;) {
566  if (i != 0)
567  os << ", ";
568 
569  // Print the filename if it changed.
570  auto first = locVector[i];
571  if (first.getFilename() != lastFileName) {
572  lastFileName = first.getFilename();
573  os << lastFileName;
574  }
575 
576  // Scan for entries with the same file/line.
577  size_t end = i + 1;
578  while (end != e &&
579  first.getFilename() == locVector[end].getFilename() &&
580  first.getLine() == locVector[end].getLine())
581  ++end;
582 
583  // If we have one entry, print it normally.
584  if (end == i + 1) {
585  if (auto line = first.getLine()) {
586  os << ':' << line;
587  if (auto col = first.getColumn())
588  os << ':' << col;
589  }
590  ++i;
591  continue;
592  }
593 
594  // Otherwise print a brace enclosed list.
595  os << ':' << first.getLine() << ":{";
596  while (i != end) {
597  os << locVector[i++].getColumn();
598 
599  if (i != end)
600  os << ',';
601  }
602  os << '}';
603  }
604  }
605 
606  /// Return the location information in the specified style. This is the main
607  /// dispatch function for calling the location-specific routines.
608  void emitLocationInfo(Location loc) {
609  llvm::TypeSwitch<Location, void>(loc)
610  .Case<mlir::CallSiteLoc, mlir::NameLoc, mlir::FileLineColLoc>(
611  [&](auto loc) { emitLocationInfo(loc); })
612  .Case<mlir::FusedLoc>([&](auto loc) {
613  SmallPtrSet<Attribute, 8> locationSet;
614  collectAndUniqueLocations(loc, locationSet);
615  emitLocationSetInfoImpl(locationSet);
616  })
617  .Default([&](auto loc) {
618  // Don't print anything for unhandled locations.
619  });
620  }
621 
622  /// Emit the location information of `locationSet` to `sstr`. The emitted
623  /// string
624  /// may potentially be an empty string given the contents of the
625  /// `locationSet`.
626  void
627  emitLocationSetInfoImpl(const SmallPtrSetImpl<Attribute> &locationSet) {
628  // Fast pass some common cases.
629  switch (locationSet.size()) {
630  case 1:
631  emitLocationInfo(cast<LocationAttr>(*locationSet.begin()));
632  [[fallthrough]];
633  case 0:
634  return;
635  default:
636  break;
637  }
638 
639  // Sort the entries into distinct location printing kinds.
640  SmallVector<FileLineColLoc, 8> flcLocs;
641  SmallVector<Attribute, 8> otherLocs;
642  flcLocs.reserve(locationSet.size());
643  otherLocs.reserve(locationSet.size());
644  for (Attribute loc : locationSet) {
645  if (auto flcLoc = dyn_cast<FileLineColLoc>(loc))
646  flcLocs.push_back(flcLoc);
647  else
648  otherLocs.push_back(loc);
649  }
650 
651  // SmallPtrSet iteration is non-deterministic, so sort the location
652  // vectors to ensure deterministic output.
653  sortLocationVector(otherLocs);
654  sortLocationVector(flcLocs);
655 
656  // To detect whether something actually got emitted, we inspect the stream
657  // for size changes. This is due to the possiblity of locations which are
658  // not supposed to be emitted (e.g. `loc("")`).
659  size_t sstrSize = os.tell();
660  bool emittedAnything = false;
661  auto recheckEmittedSomething = [&]() {
662  size_t currSize = os.tell();
663  bool emittedSomethingSinceLastCheck = currSize != sstrSize;
664  emittedAnything |= emittedSomethingSinceLastCheck;
665  sstrSize = currSize;
666  return emittedSomethingSinceLastCheck;
667  };
668 
669  // First, emit the other locations through the generic location dispatch
670  // function.
671  llvm::interleave(
672  otherLocs,
673  [&](Attribute loc) { emitLocationInfo(cast<LocationAttr>(loc)); },
674  [&] {
675  if (recheckEmittedSomething()) {
676  os << ", ";
677  recheckEmittedSomething(); // reset detector to reflect the comma.
678  }
679  });
680 
681  // If we emitted anything, and we have FileLineColLocs, then emit a
682  // location-separating comma.
683  if (emittedAnything && !flcLocs.empty())
684  os << ", ";
685  // Then, emit the FileLineColLocs.
686  printFileLineColSetInfo(flcLocs);
687  }
688  llvm::raw_string_ostream &os;
690 
691  // NOLINTEND(misc-no-recursion)
692  };
693 };
694 
695 /// Most expressions are invalid to bit-select from in Verilog, but some
696 /// things are ok. Return true if it is ok to inline bitselect from the
697 /// result of this expression. It is conservatively correct to return false.
698 static bool isOkToBitSelectFrom(Value v) {
699  // Module ports are always ok to bit select from.
700  if (isa<BlockArgument>(v))
701  return true;
702 
703  // Read_inout is valid to inline for bit-select. See `select` syntax on
704  // SV spec A.8.4 (P1174).
705  if (auto read = v.getDefiningOp<ReadInOutOp>())
706  return true;
707 
708  // Aggregate access can be inlined.
709  if (isa_and_nonnull<StructExtractOp, UnionExtractOp, ArrayGetOp>(
710  v.getDefiningOp()))
711  return true;
712 
713  // Interface signal can be inlined.
714  if (v.getDefiningOp<ReadInterfaceSignalOp>())
715  return true;
716 
717  // TODO: We could handle concat and other operators here.
718  return false;
719 }
720 
721 /// Return true if we are unable to ever inline the specified operation. This
722 /// happens because not all Verilog expressions are composable, notably you
723 /// can only use bit selects like x[4:6] on simple expressions, you cannot use
724 /// expressions in the sensitivity list of always blocks, etc.
725 static bool isExpressionUnableToInline(Operation *op,
726  const LoweringOptions &options) {
727  if (auto cast = dyn_cast<BitcastOp>(op))
728  if (!haveMatchingDims(cast.getInput().getType(), cast.getResult().getType(),
729  op->getLoc())) {
730  // Even if dimentions don't match, we can inline when its user doesn't
731  // rely on the type.
732  if (op->hasOneUse() &&
733  isa<comb::ConcatOp, hw::ArrayConcatOp>(*op->getUsers().begin()))
734  return false;
735  // Bitcasts rely on the type being assigned to, so we cannot inline.
736  return true;
737  }
738 
739  // StructCreateOp needs to be assigning to a named temporary so that types
740  // are inferred properly by verilog
741  if (isa<StructCreateOp, UnionCreateOp, UnpackedArrayCreateOp>(op))
742  return true;
743 
744  // Aggregate literal syntax only works in an assignment expression, where
745  // the Verilog expression's type is determined by the LHS.
746  if (auto aggConstantOp = dyn_cast<AggregateConstantOp>(op))
747  return true;
748 
749  // Verbatim with a long string should be emitted as an out-of-line declration.
750  if (auto verbatim = dyn_cast<VerbatimExprOp>(op))
751  if (verbatim.getFormatString().size() > 32)
752  return true;
753 
754  // Scan the users of the operation to see if any of them need this to be
755  // emitted out-of-line.
756  for (auto &use : op->getUses()) {
757  auto *user = use.getOwner();
758 
759  // Verilog bit selection is required by the standard to be:
760  // "a vector, packed array, packed structure, parameter or concatenation".
761  //
762  // It cannot be an arbitrary expression, e.g. this is invalid:
763  // assign bar = {{a}, {b}, {c}, {d}}[idx];
764  //
765  // To handle these, we push the subexpression into a temporary.
767  UnionExtractOp, IndexedPartSelectOp>(user))
768  if (use.getOperandNumber() == 0 && // ignore index operands.
769  !isOkToBitSelectFrom(use.get()))
770  return true;
771 
772  // Handle option disallowing expressions in event control.
773  if (!options.allowExprInEventControl) {
774  // Check operations used for event control, anything other than
775  // a read of a wire must be out of line.
776 
777  // Helper to determine if the use will be part of "event control",
778  // based on what the operation using it is and as which operand.
779  auto usedInExprControl = [user, &use]() {
780  return TypeSwitch<Operation *, bool>(user)
781  .Case<ltl::ClockOp>([&](auto clockOp) {
782  // LTL Clock op's clock operand must be a name.
783  return clockOp.getClock() == use.get();
784  })
785  .Case<sv::AssertConcurrentOp, sv::AssumeConcurrentOp,
786  sv::CoverConcurrentOp>(
787  [&](auto op) { return op.getClock() == use.get(); })
788  .Case<sv::AssertPropertyOp, sv::AssumePropertyOp,
789  sv::CoverPropertyOp>([&](auto op) {
790  return op.getDisable() == use.get() || op.getClock() == use.get();
791  })
792  .Case<AlwaysOp, AlwaysFFOp>([](auto) {
793  // Always blocks must have a name in their sensitivity list.
794  // (all operands)
795  return true;
796  })
797  .Default([](auto) { return false; });
798  };
799 
800  if (!usedInExprControl())
801  continue;
802 
803  // Otherwise, this can only be inlined if is (already) a read of a wire.
804  auto read = dyn_cast<ReadInOutOp>(op);
805  if (!read)
806  return true;
807  if (!isa_and_nonnull<sv::WireOp, RegOp>(read.getInput().getDefiningOp()))
808  return true;
809  }
810  }
811  return false;
812 }
813 
814 enum class BlockStatementCount { Zero, One, TwoOrMore };
815 
816 /// Compute how many statements are within this block, for begin/end markers.
817 static BlockStatementCount countStatements(Block &block) {
818  unsigned numStatements = 0;
819  block.walk([&](Operation *op) {
820  if (isVerilogExpression(op) || isa<ltl::LTLDialect>(op->getDialect()))
821  return WalkResult::advance();
822  numStatements +=
823  TypeSwitch<Operation *, unsigned>(op)
824  .Case<VerbatimOp>([&](auto) {
825  // We don't know how many statements we emitted, so assume
826  // conservatively that a lot got put out. This will make sure we
827  // get a begin/end block around this.
828  return 3;
829  })
830  .Case<IfOp>([&](auto) {
831  // We count if as multiple statements to make sure it is always
832  // surrounded by a begin/end so we don't get if/else confusion in
833  // cases like this:
834  // if (cond)
835  // if (otherCond) // This should force a begin!
836  // stmt
837  // else // Goes with the outer if!
838  // thing;
839  return 2;
840  })
841  .Case<IfDefOp, IfDefProceduralOp>([&](auto) { return 3; })
842  .Case<OutputOp>([&](OutputOp oop) {
843  // Skip single-use instance outputs, they don't get statements.
844  // Keep this synchronized with visitStmt(InstanceOp,OutputOp).
845  return llvm::count_if(oop->getOperands(), [&](auto operand) {
846  Operation *op = operand.getDefiningOp();
847  return !operand.hasOneUse() || !op || !isa<HWInstanceLike>(op);
848  });
849  })
850  .Default([](auto) { return 1; });
851  if (numStatements > 1)
852  return WalkResult::interrupt();
853  return WalkResult::advance();
854  });
855  if (numStatements == 0)
857  if (numStatements == 1)
860 }
861 
862 /// Return true if this expression should be emitted inline into any statement
863 /// that uses it.
865  const LoweringOptions &options) {
866  // Never create a temporary for a dead expression.
867  if (op->getResult(0).use_empty())
868  return true;
869 
870  // Never create a temporary which is only going to be assigned to an output
871  // port, wire, or reg.
872  if (op->hasOneUse() &&
873  isa<hw::OutputOp, sv::AssignOp, sv::BPAssignOp, sv::PAssignOp>(
874  *op->getUsers().begin()))
875  return true;
876 
877  // If mux inlining is dissallowed, we cannot inline muxes.
878  if (options.disallowMuxInlining && isa<MuxOp>(op))
879  return false;
880 
881  // If this operation has multiple uses, we can't generally inline it unless
882  // the op is duplicatable.
883  if (!op->getResult(0).hasOneUse() && !isDuplicatableExpression(op))
884  return false;
885 
886  // If it isn't structurally possible to inline this expression, emit it out
887  // of line.
888  return !isExpressionUnableToInline(op, options);
889 }
890 
891 /// Find a nested IfOp in an else block that can be printed as `else if`
892 /// instead of nesting it into a new `begin` - `end` block. The block must
893 /// contain a single IfOp and optionally expressions which can be hoisted out.
894 static IfOp findNestedElseIf(Block *elseBlock) {
895  IfOp ifOp;
896  for (auto &op : *elseBlock) {
897  if (auto opIf = dyn_cast<IfOp>(op)) {
898  if (ifOp)
899  return {};
900  ifOp = opIf;
901  continue;
902  }
903  if (!isVerilogExpression(&op))
904  return {};
905  }
906  // SV attributes cannot be attached to `else if` so reject when ifOp has SV
907  // attributes.
908  if (ifOp && hasSVAttributes(ifOp))
909  return {};
910  return ifOp;
911 }
912 
913 /// Emit SystemVerilog attributes.
914 template <typename PPS>
915 static void emitSVAttributesImpl(PPS &ps, ArrayAttr attrs, bool mayBreak) {
916  enum Container { NoContainer, InComment, InAttr };
917  Container currentContainer = NoContainer;
918 
919  auto closeContainer = [&] {
920  if (currentContainer == NoContainer)
921  return;
922  if (currentContainer == InComment)
923  ps << " */";
924  else if (currentContainer == InAttr)
925  ps << " *)";
926  ps << PP::end << PP::end;
927 
928  currentContainer = NoContainer;
929  };
930 
931  bool isFirstContainer = true;
932  auto openContainer = [&](Container newContainer) {
933  assert(newContainer != NoContainer);
934  if (currentContainer == newContainer)
935  return false;
936  closeContainer();
937  // If not first container, insert break point but no space.
938  if (!isFirstContainer)
939  ps << (mayBreak ? PP::space : PP::nbsp);
940  isFirstContainer = false;
941  // fit container on one line if possible, break if needed.
942  ps << PP::ibox0;
943  if (newContainer == InComment)
944  ps << "/* ";
945  else if (newContainer == InAttr)
946  ps << "(* ";
947  currentContainer = newContainer;
948  // Pack attributes within to fit, align to current column when breaking.
949  ps << PP::ibox0;
950  return true;
951  };
952 
953  // Break containers to starting column (0), put all on same line OR
954  // put each on their own line (cbox).
955  ps.scopedBox(PP::cbox0, [&]() {
956  for (auto attr : attrs.getAsRange<SVAttributeAttr>()) {
957  if (!openContainer(attr.getEmitAsComment().getValue() ? InComment
958  : InAttr))
959  ps << "," << (mayBreak ? PP::space : PP::nbsp);
960  ps << PPExtString(attr.getName().getValue());
961  if (attr.getExpression())
962  ps << " = " << PPExtString(attr.getExpression().getValue());
963  }
964  closeContainer();
965  });
966 }
967 
968 /// Retrieve value's verilog name from IR. The name must already have been
969 /// added in pre-pass and passed through "hw.verilogName" attr.
970 StringRef getVerilogValueName(Value val) {
971  if (auto *op = val.getDefiningOp())
972  return getSymOpName(op);
973 
974  if (auto port = dyn_cast<BlockArgument>(val)) {
975  // If the value is defined by for op, use its associated verilog name.
976  if (auto forOp = dyn_cast<ForOp>(port.getParentBlock()->getParentOp()))
977  return forOp->getAttrOfType<StringAttr>("hw.verilogName");
978  return getInputPortVerilogName(port.getParentBlock()->getParentOp(),
979  port.getArgNumber());
980  }
981  assert(false && "unhandled value");
982  return {};
983 }
984 
985 //===----------------------------------------------------------------------===//
986 // VerilogEmitterState
987 //===----------------------------------------------------------------------===//
988 
989 namespace {
990 
991 /// This class maintains the mutable state that cross-cuts and is shared by the
992 /// various emitters.
993 class VerilogEmitterState {
994 public:
995  explicit VerilogEmitterState(ModuleOp designOp,
996  const SharedEmitterState &shared,
997  const LoweringOptions &options,
998  const HWSymbolCache &symbolCache,
999  const GlobalNameTable &globalNames,
1000  const FileMapping &fileMapping,
1001  llvm::formatted_raw_ostream &os,
1002  StringAttr fileName, OpLocMap &verilogLocMap)
1003  : designOp(designOp), shared(shared), options(options),
1004  symbolCache(symbolCache), globalNames(globalNames),
1005  fileMapping(fileMapping), os(os), verilogLocMap(verilogLocMap),
1006  pp(os, options.emittedLineLength), fileName(fileName) {
1007  pp.setListener(&saver);
1008  }
1009  /// This is the root mlir::ModuleOp that holds the whole design being emitted.
1010  ModuleOp designOp;
1011 
1012  const SharedEmitterState &shared;
1013 
1014  /// The emitter options which control verilog emission.
1015  const LoweringOptions &options;
1016 
1017  /// This is a cache of various information about the IR, in frozen state.
1018  const HWSymbolCache &symbolCache;
1019 
1020  /// This tracks global names where the Verilog name needs to be different than
1021  /// the IR name.
1022  const GlobalNameTable &globalNames;
1023 
1024  /// Tracks the referenceable files through their symbol.
1025  const FileMapping &fileMapping;
1026 
1027  /// The stream to emit to. Use a formatted_raw_ostream, to easily get the
1028  /// current location(line,column) on the stream. This is required to record
1029  /// the verilog output location information corresponding to any op.
1030  llvm::formatted_raw_ostream &os;
1031 
1032  bool encounteredError = false;
1033 
1034  /// Pretty printing:
1035 
1036  /// Whether a newline is expected, emitted late to provide opportunity to
1037  /// open/close boxes we don't know we need at level of individual statement.
1038  /// Every statement should set this instead of directly emitting (last)
1039  /// newline. Most statements end with emitLocationInfoAndNewLine which handles
1040  /// this.
1041  bool pendingNewline = false;
1042 
1043  /// Used to record the verilog output file location of an op.
1044  OpLocMap &verilogLocMap;
1045  /// String storage backing Tokens built from temporary strings.
1046  /// PrettyPrinter will clear this as appropriate.
1049  verilogLocMap);
1050 
1051  /// Pretty printer.
1052  PrettyPrinter pp;
1053 
1054  /// Name of the output file, used for debug information.
1055  StringAttr fileName;
1056 
1057  /// Update the location attribute of the ops with the verilog locations
1058  /// recorded in `verilogLocMap` and clear the map. `lineOffset` is added to
1059  /// all the line numbers, this is required when the modules are exported in
1060  /// parallel.
1061  void addVerilogLocToOps(unsigned int lineOffset, StringAttr fileName) {
1062  verilogLocMap.updateIRWithLoc(lineOffset, fileName,
1063  shared.designOp->getContext());
1064  verilogLocMap.clear();
1065  }
1066 
1067 private:
1068  VerilogEmitterState(const VerilogEmitterState &) = delete;
1069  void operator=(const VerilogEmitterState &) = delete;
1070 };
1071 } // namespace
1072 
1073 //===----------------------------------------------------------------------===//
1074 // EmitterBase
1075 //===----------------------------------------------------------------------===//
1076 
1077 namespace {
1078 
1079 /// The data that is unique to each callback. The operation and a flag to
1080 /// indicate if the callback is for begin or end of the operation print
1081 /// location.
1082 using CallbackDataTy = std::pair<Operation *, bool>;
1083 class EmitterBase {
1084 public:
1085  // All of the mutable state we are maintaining.
1086  VerilogEmitterState &state;
1087 
1088  /// Stream helper (pp, saver).
1090 
1091  explicit EmitterBase(VerilogEmitterState &state)
1092  : state(state),
1093  ps(state.pp, state.saver, state.options.emitVerilogLocations) {}
1094 
1095  InFlightDiagnostic emitError(Operation *op, const Twine &message) {
1096  state.encounteredError = true;
1097  return op->emitError(message);
1098  }
1099 
1100  InFlightDiagnostic emitOpError(Operation *op, const Twine &message) {
1101  state.encounteredError = true;
1102  return op->emitOpError(message);
1103  }
1104 
1105  void emitLocationImpl(llvm::StringRef location) {
1106  // Break so previous content is not impacted by following,
1107  // but use a 'neverbreak' so it always fits.
1108  ps << PP::neverbreak;
1109  if (!location.empty())
1110  ps << "\t// " << location; // (don't use tabs in normal pretty-printing)
1111  }
1112 
1113  void emitLocationInfo(Location loc) {
1114  emitLocationImpl(
1115  LocationEmitter(state.options.locationInfoStyle, loc).strref());
1116  }
1117 
1118  /// If we have location information for any of the specified operations,
1119  /// aggregate it together and print a pretty comment specifying where the
1120  /// operations came from. In any case, print a newline.
1121  void emitLocationInfoAndNewLine(const SmallPtrSetImpl<Operation *> &ops) {
1122  emitLocationImpl(
1123  LocationEmitter(state.options.locationInfoStyle, ops).strref());
1124  setPendingNewline();
1125  }
1126 
1127  template <typename PPS>
1128  void emitTextWithSubstitutions(PPS &ps, StringRef string, Operation *op,
1129  llvm::function_ref<void(Value)> operandEmitter,
1130  ArrayAttr symAttrs);
1131 
1132  /// Emit the value of a StringAttr as one or more Verilog "one-line" comments
1133  /// ("//"). Break the comment to respect the emittedLineLength and trim
1134  /// whitespace after a line break. Do nothing if the StringAttr is null or
1135  /// the value is empty.
1136  void emitComment(StringAttr comment);
1137 
1138  /// If previous emission requires a newline, emit it now.
1139  /// This gives us opportunity to open/close boxes before linebreak.
1140  void emitPendingNewlineIfNeeded() {
1141  if (state.pendingNewline) {
1142  state.pendingNewline = false;
1143  ps << PP::newline;
1144  }
1145  }
1146  void setPendingNewline() {
1147  assert(!state.pendingNewline);
1148  state.pendingNewline = true;
1149  }
1150 
1151  void startStatement() { emitPendingNewlineIfNeeded(); }
1152 
1153 private:
1154  void operator=(const EmitterBase &) = delete;
1155  EmitterBase(const EmitterBase &) = delete;
1156 };
1157 } // end anonymous namespace
1158 
1159 template <typename PPS>
1160 void EmitterBase::emitTextWithSubstitutions(
1161  PPS &ps, StringRef string, Operation *op,
1162  llvm::function_ref<void(Value)> operandEmitter, ArrayAttr symAttrs) {
1163 
1164  // Perform operand substitions as we emit the line string. We turn {{42}}
1165  // into the value of operand 42.
1166  auto namify = [&](Attribute sym, HWSymbolCache::Item item) {
1167  // CAVEAT: These accesses can reach into other modules through inner name
1168  // references, which are currently being processed. Do not add those remote
1169  // operations to this module's `names`, which is reserved for things named
1170  // *within* this module. Instead, you have to rely on those remote
1171  // operations to have been named inside the global names table. If they
1172  // haven't, take a look at name legalization first.
1173  if (auto *itemOp = item.getOp()) {
1174  if (item.hasPort()) {
1175  return getPortVerilogName(itemOp, item.getPort());
1176  }
1177  StringRef symOpName = getSymOpName(itemOp);
1178  if (!symOpName.empty())
1179  return symOpName;
1180  emitError(itemOp, "cannot get name for symbol ") << sym;
1181  } else {
1182  emitError(op, "cannot get name for symbol ") << sym;
1183  }
1184  return StringRef("<INVALID>");
1185  };
1186 
1187  // Scan 'line' for a substitution, emitting any non-substitution prefix,
1188  // then the mentioned operand, chopping the relevant text off 'line' and
1189  // returning true. This returns false if no substitution is found.
1190  unsigned numSymOps = symAttrs.size();
1191  auto emitUntilSubstitution = [&](size_t next = 0) -> bool {
1192  size_t start = 0;
1193  while (true) {
1194  next = string.find("{{", next);
1195  if (next == StringRef::npos)
1196  return false;
1197 
1198  // Check to make sure we have a number followed by }}. If not, we
1199  // ignore the {{ sequence as something that could happen in Verilog.
1200  next += 2;
1201  start = next;
1202  while (next < string.size() && isdigit(string[next]))
1203  ++next;
1204  // We need at least one digit.
1205  if (start == next) {
1206  next--;
1207  continue;
1208  }
1209  size_t operandNoLength = next - start;
1210 
1211  // Format string options follow a ':'.
1212  StringRef fmtOptsStr;
1213  if (string[next] == ':') {
1214  size_t startFmtOpts = next + 1;
1215  while (next < string.size() && string[next] != '}')
1216  ++next;
1217  fmtOptsStr = string.substr(startFmtOpts, next - startFmtOpts);
1218  }
1219 
1220  // We must have a }} right after the digits.
1221  if (!string.substr(next).starts_with("}}"))
1222  continue;
1223 
1224  // We must be able to decode the integer into an unsigned.
1225  unsigned operandNo = 0;
1226  if (string.drop_front(start)
1227  .take_front(operandNoLength)
1228  .getAsInteger(10, operandNo)) {
1229  emitError(op, "operand substitution too large");
1230  continue;
1231  }
1232  next += 2;
1233 
1234  // Emit any text before the substitution.
1235  auto before = string.take_front(start - 2);
1236  if (!before.empty())
1237  ps << PPExtString(before);
1238 
1239  // operandNo can either refer to Operands or symOps. symOps are
1240  // numbered after the operands.
1241  if (operandNo < op->getNumOperands())
1242  // Emit the operand.
1243  operandEmitter(op->getOperand(operandNo));
1244  else if ((operandNo - op->getNumOperands()) < numSymOps) {
1245  unsigned symOpNum = operandNo - op->getNumOperands();
1246  auto sym = symAttrs[symOpNum];
1247  StringRef symVerilogName;
1248  if (auto fsym = dyn_cast<FlatSymbolRefAttr>(sym)) {
1249  if (auto *symOp = state.symbolCache.getDefinition(fsym)) {
1250  if (auto globalRef = dyn_cast<HierPathOp>(symOp)) {
1251  auto namepath = globalRef.getNamepathAttr().getValue();
1252  for (auto [index, sym] : llvm::enumerate(namepath)) {
1253  // Emit the seperator string.
1254  if (index > 0)
1255  ps << (fmtOptsStr.empty() ? "." : fmtOptsStr);
1256 
1257  auto innerRef = cast<InnerRefAttr>(sym);
1258  auto ref = state.symbolCache.getInnerDefinition(
1259  innerRef.getModule(), innerRef.getName());
1260  ps << namify(innerRef, ref);
1261  }
1262  } else {
1263  symVerilogName = namify(sym, symOp);
1264  }
1265  }
1266  } else if (auto isym = dyn_cast<InnerRefAttr>(sym)) {
1267  auto symOp = state.symbolCache.getInnerDefinition(isym.getModule(),
1268  isym.getName());
1269  symVerilogName = namify(sym, symOp);
1270  }
1271  if (!symVerilogName.empty())
1272  ps << PPExtString(symVerilogName);
1273  } else {
1274  emitError(op, "operand " + llvm::utostr(operandNo) + " isn't valid");
1275  continue;
1276  }
1277  // Forget about the part we emitted.
1278  string = string.drop_front(next);
1279  return true;
1280  }
1281  };
1282 
1283  // Emit all the substitutions.
1284  while (emitUntilSubstitution())
1285  ;
1286 
1287  // Emit any text after the last substitution.
1288  if (!string.empty())
1289  ps << PPExtString(string);
1290 }
1291 
1292 void EmitterBase::emitComment(StringAttr comment) {
1293  if (!comment)
1294  return;
1295 
1296  // Set a line length for the comment. Subtract off the leading comment and
1297  // space ("// ") as well as the current indent level to simplify later
1298  // arithmetic. Ensure that this line length doesn't go below zero.
1299  auto lineLength = std::max<size_t>(state.options.emittedLineLength, 3) - 3;
1300 
1301  // Process the comment in line chunks extracted from manually specified line
1302  // breaks. This is done to preserve user-specified line breaking if used.
1303  auto ref = comment.getValue();
1304  StringRef line;
1305  while (!ref.empty()) {
1306  std::tie(line, ref) = ref.split("\n");
1307  // Emit each comment line breaking it if it exceeds the emittedLineLength.
1308  for (;;) {
1309  startStatement();
1310  ps << "// ";
1311 
1312  // Base case 1: the entire comment fits on one line.
1313  if (line.size() <= lineLength) {
1314  ps << PPExtString(line);
1315  setPendingNewline();
1316  break;
1317  }
1318 
1319  // The comment does NOT fit on one line. Use a simple algorithm to find
1320  // a position to break the line:
1321  // 1) Search backwards for whitespace and break there if you find it.
1322  // 2) If no whitespace exists in (1), search forward for whitespace
1323  // and break there.
1324  // This algorithm violates the emittedLineLength if (2) ever occurrs,
1325  // but it's dead simple.
1326  auto breakPos = line.rfind(' ', lineLength);
1327  // No whitespace exists looking backwards.
1328  if (breakPos == StringRef::npos) {
1329  breakPos = line.find(' ', lineLength);
1330  // No whitespace exists looking forward (you hit the end of the
1331  // string).
1332  if (breakPos == StringRef::npos)
1333  breakPos = line.size();
1334  }
1335 
1336  // Emit up to the break position. Trim any whitespace after the break
1337  // position. Exit if nothing is left to emit. Otherwise, update the
1338  // comment ref and continue;
1339  ps << PPExtString(line.take_front(breakPos));
1340  setPendingNewline();
1341  breakPos = line.find_first_not_of(' ', breakPos);
1342  // Base Case 2: nothing left except whitespace.
1343  if (breakPos == StringRef::npos)
1344  break;
1345 
1346  line = line.drop_front(breakPos);
1347  }
1348  }
1349 }
1350 
1351 /// Given an expression that is spilled into a temporary wire, try to synthesize
1352 /// a better name than "_T_42" based on the structure of the expression.
1353 // NOLINTBEGIN(misc-no-recursion)
1355  StringAttr result;
1356  bool addPrefixUnderScore = true;
1357 
1358  // Look through read_inout.
1359  if (auto read = expr.getDefiningOp<ReadInOutOp>())
1360  return inferStructuralNameForTemporary(read.getInput());
1361 
1362  // Module ports carry names!
1363  if (auto blockArg = dyn_cast<BlockArgument>(expr)) {
1364  auto moduleOp =
1365  cast<HWEmittableModuleLike>(blockArg.getOwner()->getParentOp());
1366  StringRef name = getPortVerilogName(moduleOp, blockArg.getArgNumber());
1367  result = StringAttr::get(expr.getContext(), name);
1368 
1369  } else if (auto *op = expr.getDefiningOp()) {
1370  // Uses of a wire, register or logic can be done inline.
1371  if (isa<sv::WireOp, RegOp, LogicOp>(op)) {
1372  StringRef name = getSymOpName(op);
1373  result = StringAttr::get(expr.getContext(), name);
1374 
1375  } else if (auto nameHint = op->getAttrOfType<StringAttr>("sv.namehint")) {
1376  // Use a dialect (sv) attribute to get a hint for the name if the op
1377  // doesn't explicitly specify it. Do this last
1378  result = nameHint;
1379 
1380  // If there is a namehint, don't add underscores to the name.
1381  addPrefixUnderScore = false;
1382  } else {
1383  TypeSwitch<Operation *>(op)
1384  // Generate a pretty name for VerbatimExpr's that look macro-like
1385  // using the same logic that generates the MLIR syntax name.
1386  .Case([&result](VerbatimExprOp verbatim) {
1387  verbatim.getAsmResultNames([&](Value, StringRef name) {
1388  result = StringAttr::get(verbatim.getContext(), name);
1389  });
1390  })
1391  .Case([&result](VerbatimExprSEOp verbatim) {
1392  verbatim.getAsmResultNames([&](Value, StringRef name) {
1393  result = StringAttr::get(verbatim.getContext(), name);
1394  });
1395  })
1396 
1397  // If this is an extract from a namable object, derive a name from it.
1398  .Case([&result](ExtractOp extract) {
1399  if (auto operandName =
1400  inferStructuralNameForTemporary(extract.getInput())) {
1401  unsigned numBits =
1402  cast<IntegerType>(extract.getType()).getWidth();
1403  if (numBits == 1)
1404  result = StringAttr::get(extract.getContext(),
1405  operandName.strref() + "_" +
1406  Twine(extract.getLowBit()));
1407  else
1408  result = StringAttr::get(
1409  extract.getContext(),
1410  operandName.strref() + "_" +
1411  Twine(extract.getLowBit() + numBits - 1) + "to" +
1412  Twine(extract.getLowBit()));
1413  }
1414  });
1415  // TODO: handle other common patterns.
1416  }
1417  }
1418 
1419  // Make sure any synthesized name starts with an _.
1420  if (!result || result.strref().empty())
1421  return {};
1422 
1423  // Make sure that all temporary names start with an underscore.
1424  if (addPrefixUnderScore && result.strref().front() != '_')
1425  result = StringAttr::get(expr.getContext(), "_" + result.strref());
1426 
1427  return result;
1428 }
1429 // NOLINTEND(misc-no-recursion)
1430 
1431 //===----------------------------------------------------------------------===//
1432 // ModuleEmitter
1433 //===----------------------------------------------------------------------===//
1434 
1435 namespace {
1436 
1437 class ModuleEmitter : public EmitterBase {
1438 public:
1439  explicit ModuleEmitter(VerilogEmitterState &state)
1440  : EmitterBase(state), currentModuleOp(nullptr),
1441  fieldNameResolver(FieldNameResolver(state.globalNames, state.options)) {
1442  }
1443  ~ModuleEmitter() {
1444  emitPendingNewlineIfNeeded();
1445  ps.eof();
1446  };
1447 
1448  void emitParameters(Operation *module, ArrayAttr params);
1449  void emitPortList(Operation *module, const ModulePortInfo &portInfo,
1450  bool emitAsTwoStateType = false);
1451 
1452  void emitHWModule(HWModuleOp module);
1453  void emitHWGeneratedModule(HWModuleGeneratedOp module);
1454  void emitFunc(FuncOp);
1455 
1456  // Statements.
1457  void emitStatement(Operation *op);
1458  void emitBind(BindOp op);
1459  void emitBindInterface(BindInterfaceOp op);
1460 
1461  void emitSVAttributes(Operation *op);
1462 
1463  /// Legalize the given field name if it is an invalid verilog name.
1464  StringRef getVerilogStructFieldName(StringAttr field) {
1465  return fieldNameResolver.getRenamedFieldName(field).getValue();
1466  }
1467 
1468  //===--------------------------------------------------------------------===//
1469  // Methods for formatting types.
1470 
1471  /// Emit a type's packed dimensions.
1472  void emitTypeDims(Type type, Location loc, raw_ostream &os);
1473 
1474  /// Print the specified packed portion of the type to the specified stream,
1475  ///
1476  /// * 'optionalAliasType' can be provided to perform any alias-aware printing
1477  /// of the inner type.
1478  /// * When `implicitIntType` is false, a "logic" is printed. This is used in
1479  /// struct fields and typedefs.
1480  /// * When `singleBitDefaultType` is false, single bit values are printed as
1481  /// `[0:0]`. This is used in parameter lists.
1482  ///
1483  /// This returns true if anything was printed.
1484  bool printPackedType(Type type, raw_ostream &os, Location loc,
1485  Type optionalAliasType = {}, bool implicitIntType = true,
1486  bool singleBitDefaultType = true,
1487  bool emitAsTwoStateType = false);
1488 
1489  /// Output the unpacked array dimensions. This is the part of the type that
1490  /// is to the right of the name.
1491  void printUnpackedTypePostfix(Type type, raw_ostream &os);
1492 
1493  //===--------------------------------------------------------------------===//
1494  // Methods for formatting parameters.
1495 
1496  /// Prints a parameter attribute expression in a Verilog compatible way to the
1497  /// specified stream. This returns the precedence of the generated string.
1498  SubExprInfo printParamValue(Attribute value, raw_ostream &os,
1499  function_ref<InFlightDiagnostic()> emitError);
1500 
1501  SubExprInfo printParamValue(Attribute value, raw_ostream &os,
1502  VerilogPrecedence parenthesizeIfLooserThan,
1503  function_ref<InFlightDiagnostic()> emitError);
1504 
1505  //===--------------------------------------------------------------------===//
1506  // Mutable state while emitting a module body.
1507 
1508  /// This is the current module being emitted for a HWModuleOp.
1509  Operation *currentModuleOp;
1510 
1511  /// This set keeps track of expressions that were emitted into their
1512  /// 'automatic logic' or 'localparam' declaration. This is only used for
1513  /// expressions in a procedural region, because we otherwise just emit wires
1514  /// on demand.
1515  SmallPtrSet<Operation *, 16> expressionsEmittedIntoDecl;
1516 
1517  /// This class keeps track of field name renamings in the module scope.
1518  FieldNameResolver fieldNameResolver;
1519 
1520  /// This keeps track of assignments folded into wire emissions
1521  SmallPtrSet<Operation *, 16> assignsInlined;
1522 };
1523 
1524 } // end anonymous namespace
1525 
1526 /// Return the word (e.g. "reg") in Verilog to declare the specified thing.
1527 /// If `stripAutomatic` is true, "automatic" is not used even for a declaration
1528 /// in a non-procedural region.
1529 static StringRef getVerilogDeclWord(Operation *op,
1530  const ModuleEmitter &emitter) {
1531  if (isa<RegOp>(op)) {
1532  // Check if the type stored in this register is a struct or array of
1533  // structs. In this case, according to spec section 6.8, the "reg" prefix
1534  // should be left off.
1535  auto elementType =
1536  cast<InOutType>(op->getResult(0).getType()).getElementType();
1537  if (isa<StructType>(elementType))
1538  return "";
1539  if (isa<UnionType>(elementType))
1540  return "";
1541  if (isa<EnumType>(elementType))
1542  return "";
1543  if (auto innerType = dyn_cast<ArrayType>(elementType)) {
1544  while (isa<ArrayType>(innerType.getElementType()))
1545  innerType = cast<ArrayType>(innerType.getElementType());
1546  if (isa<StructType>(innerType.getElementType()) ||
1547  isa<TypeAliasType>(innerType.getElementType()))
1548  return "";
1549  }
1550  if (isa<TypeAliasType>(elementType))
1551  return "";
1552 
1553  return "reg";
1554  }
1555  if (isa<sv::WireOp>(op))
1556  return "wire";
1557  if (isa<ConstantOp, AggregateConstantOp, LocalParamOp, ParamValueOp>(op))
1558  return "localparam";
1559 
1560  // Interfaces instances use the name of the declared interface.
1561  if (auto interface = dyn_cast<InterfaceInstanceOp>(op))
1562  return interface.getInterfaceType().getInterface().getValue();
1563 
1564  // If 'op' is in a module, output 'wire'. If 'op' is in a procedural block,
1565  // fall through to default.
1566  bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
1567 
1568  // If this decl is within a function, "automatic" is not needed because
1569  // "automatic" is added to its definition.
1570  bool stripAutomatic = isa_and_nonnull<FuncOp>(emitter.currentModuleOp);
1571 
1572  if (isa<LogicOp>(op)) {
1573  // If the logic op is defined in a procedural region, add 'automatic'
1574  // keyword. If the op has a struct type, 'logic' keyword is already emitted
1575  // within a struct type definition (e.g. struct packed {logic foo;}). So we
1576  // should not emit extra 'logic'.
1577  bool hasStruct = hasStructType(op->getResult(0).getType());
1578  if (isProcedural && !stripAutomatic)
1579  return hasStruct ? "automatic" : "automatic logic";
1580  return hasStruct ? "" : "logic";
1581  }
1582 
1583  if (!isProcedural)
1584  return "wire";
1585 
1586  if (stripAutomatic)
1587  return hasStructType(op->getResult(0).getType()) ? "" : "logic";
1588 
1589  // "automatic" values aren't allowed in disallowLocalVariables mode.
1590  assert(!emitter.state.options.disallowLocalVariables &&
1591  "automatic variables not allowed");
1592 
1593  // If the type contains a struct type, we have to use only "automatic" because
1594  // "automatic struct" is syntactically correct.
1595  return hasStructType(op->getResult(0).getType()) ? "automatic"
1596  : "automatic logic";
1597 }
1598 
1599 //===----------------------------------------------------------------------===//
1600 // Methods for formatting types.
1601 
1602 /// Emit a single dimension.
1603 static void emitDim(Attribute width, raw_ostream &os, Location loc,
1604  ModuleEmitter &emitter, bool downTo) {
1605  if (!width) {
1606  os << "<<invalid type>>";
1607  return;
1608  }
1609  if (auto intAttr = dyn_cast<IntegerAttr>(width)) {
1610  if (intAttr.getValue().isZero()) {
1611  os << "/*Zero Width*/";
1612  } else {
1613  os << '[';
1614  if (!downTo)
1615  os << "0:";
1616  os << (intAttr.getValue().getZExtValue() - 1);
1617  if (downTo)
1618  os << ":0";
1619  os << ']';
1620  }
1621  return;
1622  }
1623 
1624  // Otherwise it must be a parameterized dimension. Shove the "-1" into the
1625  // attribute so it gets printed in canonical form.
1626  auto typedAttr = dyn_cast<TypedAttr>(width);
1627  if (!typedAttr) {
1628  mlir::emitError(loc, "untyped dimension attribute ") << width;
1629  return;
1630  }
1631  auto negOne =
1632  getIntAttr(loc.getContext(), typedAttr.getType(),
1633  APInt(typedAttr.getType().getIntOrFloatBitWidth(), -1L, true));
1634  width = ParamExprAttr::get(PEO::Add, typedAttr, negOne);
1635  os << '[';
1636  if (!downTo)
1637  os << "0:";
1638  emitter.printParamValue(width, os, [loc]() {
1639  return mlir::emitError(loc, "invalid parameter in type");
1640  });
1641  if (downTo)
1642  os << ":0";
1643  os << ']';
1644 }
1645 
1646 /// Emit a list of packed dimensions.
1647 static void emitDims(ArrayRef<Attribute> dims, raw_ostream &os, Location loc,
1648  ModuleEmitter &emitter) {
1649  for (Attribute width : dims) {
1650  emitDim(width, os, loc, emitter, /*downTo=*/true);
1651  }
1652 }
1653 
1654 /// Emit a type's packed dimensions.
1655 void ModuleEmitter::emitTypeDims(Type type, Location loc, raw_ostream &os) {
1656  SmallVector<Attribute, 4> dims;
1657  getTypeDims(dims, type, loc);
1658  emitDims(dims, os, loc, *this);
1659 }
1660 
1661 /// Return a 2-state integer atom type name if the width matches. See Spec 6.8
1662 /// Variable declarations.
1663 static StringRef getTwoStateIntegerAtomType(size_t width) {
1664  switch (width) {
1665  case 8:
1666  return "byte";
1667  case 16:
1668  return "shortint";
1669  case 32:
1670  return "int";
1671  case 64:
1672  return "longint";
1673  default:
1674  return "";
1675  }
1676 }
1677 
1678 /// Output the basic type that consists of packed and primitive types. This is
1679 /// those to the left of the name in verilog. implicitIntType controls whether
1680 /// to print a base type for (logic) for inteters or whether the caller will
1681 /// have handled this (with logic, wire, reg, etc).
1682 /// optionalAliasType can be provided to perform any necessary alias-aware
1683 /// printing of 'type'.
1684 ///
1685 /// Returns true when anything was printed out.
1686 // NOLINTBEGIN(misc-no-recursion)
1687 static bool printPackedTypeImpl(Type type, raw_ostream &os, Location loc,
1688  SmallVectorImpl<Attribute> &dims,
1689  bool implicitIntType, bool singleBitDefaultType,
1690  ModuleEmitter &emitter,
1691  Type optionalAliasType = {},
1692  bool emitAsTwoStateType = false) {
1693  return TypeSwitch<Type, bool>(type)
1694  .Case<IntegerType>([&](IntegerType integerType) {
1695  if (emitAsTwoStateType && dims.empty()) {
1696  auto typeName = getTwoStateIntegerAtomType(integerType.getWidth());
1697  if (!typeName.empty()) {
1698  os << typeName;
1699  return true;
1700  }
1701  }
1702  if (integerType.getWidth() != 1 || !singleBitDefaultType)
1703  dims.push_back(
1704  getInt32Attr(type.getContext(), integerType.getWidth()));
1705 
1706  StringRef typeName =
1707  (emitAsTwoStateType ? "bit" : (implicitIntType ? "" : "logic"));
1708  if (!typeName.empty()) {
1709  os << typeName;
1710  if (!dims.empty())
1711  os << ' ';
1712  }
1713 
1714  emitDims(dims, os, loc, emitter);
1715  return !dims.empty() || !implicitIntType;
1716  })
1717  .Case<IntType>([&](IntType intType) {
1718  if (!implicitIntType)
1719  os << "logic ";
1720  dims.push_back(intType.getWidth());
1721  emitDims(dims, os, loc, emitter);
1722  return true;
1723  })
1724  .Case<ArrayType>([&](ArrayType arrayType) {
1725  dims.push_back(arrayType.getSizeAttr());
1726  return printPackedTypeImpl(arrayType.getElementType(), os, loc, dims,
1727  implicitIntType, singleBitDefaultType,
1728  emitter, /*optionalAliasType=*/{},
1729  emitAsTwoStateType);
1730  })
1731  .Case<InOutType>([&](InOutType inoutType) {
1732  return printPackedTypeImpl(inoutType.getElementType(), os, loc, dims,
1733  implicitIntType, singleBitDefaultType,
1734  emitter, /*optionalAliasType=*/{},
1735  emitAsTwoStateType);
1736  })
1737  .Case<EnumType>([&](EnumType enumType) {
1738  os << "enum ";
1739  if (enumType.getBitWidth() != 32)
1740  os << "bit [" << enumType.getBitWidth() - 1 << ":0] ";
1741  os << "{";
1742  Type enumPrefixType = optionalAliasType ? optionalAliasType : enumType;
1743  llvm::interleaveComma(
1744  enumType.getFields().getAsRange<StringAttr>(), os,
1745  [&](auto enumerator) {
1746  os << emitter.fieldNameResolver.getEnumFieldName(
1747  hw::EnumFieldAttr::get(loc, enumerator, enumPrefixType));
1748  });
1749  os << "}";
1750  return true;
1751  })
1752  .Case<StructType>([&](StructType structType) {
1753  if (structType.getElements().empty() || isZeroBitType(structType)) {
1754  os << "/*Zero Width*/";
1755  return true;
1756  }
1757  os << "struct packed {";
1758  for (auto &element : structType.getElements()) {
1759  if (isZeroBitType(element.type)) {
1760  os << "/*" << emitter.getVerilogStructFieldName(element.name)
1761  << ": Zero Width;*/ ";
1762  continue;
1763  }
1764  SmallVector<Attribute, 8> structDims;
1765  printPackedTypeImpl(stripUnpackedTypes(element.type), os, loc,
1766  structDims,
1767  /*implicitIntType=*/false,
1768  /*singleBitDefaultType=*/true, emitter,
1769  /*optionalAliasType=*/{}, emitAsTwoStateType);
1770  os << ' ' << emitter.getVerilogStructFieldName(element.name);
1771  emitter.printUnpackedTypePostfix(element.type, os);
1772  os << "; ";
1773  }
1774  os << '}';
1775  emitDims(dims, os, loc, emitter);
1776  return true;
1777  })
1778  .Case<UnionType>([&](UnionType unionType) {
1779  if (unionType.getElements().empty() || isZeroBitType(unionType)) {
1780  os << "/*Zero Width*/";
1781  return true;
1782  }
1783 
1784  int64_t unionWidth = hw::getBitWidth(unionType);
1785  os << "union packed {";
1786  for (auto &element : unionType.getElements()) {
1787  if (isZeroBitType(element.type)) {
1788  os << "/*" << emitter.getVerilogStructFieldName(element.name)
1789  << ": Zero Width;*/ ";
1790  continue;
1791  }
1792  int64_t elementWidth = hw::getBitWidth(element.type);
1793  bool needsPadding = elementWidth < unionWidth || element.offset > 0;
1794  if (needsPadding) {
1795  os << " struct packed {";
1796  if (element.offset) {
1797  os << (emitAsTwoStateType ? "bit" : "logic") << " ["
1798  << element.offset - 1 << ":0] "
1799  << "__pre_padding_" << element.name.getValue() << "; ";
1800  }
1801  }
1802 
1803  SmallVector<Attribute, 8> structDims;
1805  stripUnpackedTypes(element.type), os, loc, structDims,
1806  /*implicitIntType=*/false,
1807  /*singleBitDefaultType=*/true, emitter, {}, emitAsTwoStateType);
1808  os << ' ' << emitter.getVerilogStructFieldName(element.name);
1809  emitter.printUnpackedTypePostfix(element.type, os);
1810  os << ";";
1811 
1812  if (needsPadding) {
1813  if (elementWidth + (int64_t)element.offset < unionWidth) {
1814  os << " " << (emitAsTwoStateType ? "bit" : "logic") << " ["
1815  << unionWidth - (elementWidth + element.offset) - 1 << ":0] "
1816  << "__post_padding_" << element.name.getValue() << ";";
1817  }
1818  os << "} " << emitter.getVerilogStructFieldName(element.name)
1819  << ";";
1820  }
1821  }
1822  os << '}';
1823  emitDims(dims, os, loc, emitter);
1824  return true;
1825  })
1826 
1827  .Case<InterfaceType>([](InterfaceType ifaceType) { return false; })
1828  .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1829  os << "<<unexpected unpacked array>>";
1830  mlir::emitError(loc, "Unexpected unpacked array in packed type ")
1831  << arrayType;
1832  return true;
1833  })
1834  .Case<TypeAliasType>([&](TypeAliasType typeRef) {
1835  auto typedecl = typeRef.getTypeDecl(emitter.state.symbolCache);
1836  if (!typedecl) {
1837  mlir::emitError(loc, "unresolvable type reference");
1838  return false;
1839  }
1840  if (typedecl.getType() != typeRef.getInnerType()) {
1841  mlir::emitError(loc, "declared type did not match aliased type");
1842  return false;
1843  }
1844 
1845  os << typedecl.getPreferredName();
1846  emitDims(dims, os, typedecl->getLoc(), emitter);
1847  return true;
1848  })
1849  .Default([&](Type type) {
1850  os << "<<invalid type '" << type << "'>>";
1851  mlir::emitError(loc, "value has an unsupported verilog type ") << type;
1852  return true;
1853  });
1854 }
1855 // NOLINTEND(misc-no-recursion)
1856 
1857 /// Print the specified packed portion of the type to the specified stream,
1858 ///
1859 /// * When `implicitIntType` is false, a "logic" is printed. This is used in
1860 /// struct fields and typedefs.
1861 /// * When `singleBitDefaultType` is false, single bit values are printed as
1862 /// `[0:0]`. This is used in parameter lists.
1863 /// * When `emitAsTwoStateType` is true, a "bit" is printed. This is used in
1864 /// DPI function import statement.
1865 ///
1866 /// This returns true if anything was printed.
1867 bool ModuleEmitter::printPackedType(Type type, raw_ostream &os, Location loc,
1868  Type optionalAliasType,
1869  bool implicitIntType,
1870  bool singleBitDefaultType,
1871  bool emitAsTwoStateType) {
1872  SmallVector<Attribute, 8> packedDimensions;
1873  return printPackedTypeImpl(type, os, loc, packedDimensions, implicitIntType,
1874  singleBitDefaultType, *this, optionalAliasType,
1875  emitAsTwoStateType);
1876 }
1877 
1878 /// Output the unpacked array dimensions. This is the part of the type that is
1879 /// to the right of the name.
1880 // NOLINTBEGIN(misc-no-recursion)
1881 void ModuleEmitter::printUnpackedTypePostfix(Type type, raw_ostream &os) {
1882  TypeSwitch<Type, void>(type)
1883  .Case<InOutType>([&](InOutType inoutType) {
1884  printUnpackedTypePostfix(inoutType.getElementType(), os);
1885  })
1886  .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1887  auto loc = currentModuleOp ? currentModuleOp->getLoc()
1888  : state.designOp->getLoc();
1889  emitDim(arrayType.getSizeAttr(), os, loc, *this,
1890  /*downTo=*/false);
1891  printUnpackedTypePostfix(arrayType.getElementType(), os);
1892  })
1893  .Case<sv::UnpackedOpenArrayType>([&](auto arrayType) {
1894  os << "[]";
1895  printUnpackedTypePostfix(arrayType.getElementType(), os);
1896  })
1897  .Case<InterfaceType>([&](auto) {
1898  // Interface instantiations have parentheses like a module with no
1899  // ports.
1900  os << "()";
1901  });
1902 }
1903 // NOLINTEND(misc-no-recursion)
1904 
1905 //===----------------------------------------------------------------------===//
1906 // Methods for formatting parameters.
1907 
1908 /// Prints a parameter attribute expression in a Verilog compatible way to the
1909 /// specified stream. This returns the precedence of the generated string.
1910 SubExprInfo
1911 ModuleEmitter::printParamValue(Attribute value, raw_ostream &os,
1912  function_ref<InFlightDiagnostic()> emitError) {
1913  return printParamValue(value, os, VerilogPrecedence::LowestPrecedence,
1914  emitError);
1915 }
1916 
1917 /// Helper that prints a parameter constant value in a Verilog compatible way.
1918 /// This returns the precedence of the generated string.
1919 // NOLINTBEGIN(misc-no-recursion)
1920 SubExprInfo
1921 ModuleEmitter::printParamValue(Attribute value, raw_ostream &os,
1922  VerilogPrecedence parenthesizeIfLooserThan,
1923  function_ref<InFlightDiagnostic()> emitError) {
1924  if (auto intAttr = dyn_cast<IntegerAttr>(value)) {
1925  IntegerType intTy = cast<IntegerType>(intAttr.getType());
1926  APInt value = intAttr.getValue();
1927 
1928  // We omit the width specifier if the value is <= 32-bits in size, which
1929  // makes this more compatible with unknown width extmodules.
1930  if (intTy.getWidth() > 32) {
1931  // Sign comes out before any width specifier.
1932  if (value.isNegative() && (intTy.isSigned() || intTy.isSignless())) {
1933  os << '-';
1934  value = -value;
1935  }
1936  if (intTy.isSigned())
1937  os << intTy.getWidth() << "'sd";
1938  else
1939  os << intTy.getWidth() << "'d";
1940  }
1941  value.print(os, intTy.isSigned());
1942  return {Symbol, intTy.isSigned() ? IsSigned : IsUnsigned};
1943  }
1944  if (auto strAttr = dyn_cast<StringAttr>(value)) {
1945  os << '"';
1946  os.write_escaped(strAttr.getValue());
1947  os << '"';
1948  return {Symbol, IsUnsigned};
1949  }
1950  if (auto fpAttr = dyn_cast<FloatAttr>(value)) {
1951  // TODO: relying on float printing to be precise is not a good idea.
1952  os << fpAttr.getValueAsDouble();
1953  return {Symbol, IsUnsigned};
1954  }
1955  if (auto verbatimParam = dyn_cast<ParamVerbatimAttr>(value)) {
1956  os << verbatimParam.getValue().getValue();
1957  return {Symbol, IsUnsigned};
1958  }
1959  if (auto parameterRef = dyn_cast<ParamDeclRefAttr>(value)) {
1960  // Get the name of this parameter (in case it got renamed).
1961  os << state.globalNames.getParameterVerilogName(currentModuleOp,
1962  parameterRef.getName());
1963 
1964  // TODO: Should we support signed parameters?
1965  return {Symbol, IsUnsigned};
1966  }
1967 
1968  // Handle nested expressions.
1969  auto expr = dyn_cast<ParamExprAttr>(value);
1970  if (!expr) {
1971  os << "<<UNKNOWN MLIRATTR: " << value << ">>";
1972  emitError() << " = " << value;
1973  return {LowestPrecedence, IsUnsigned};
1974  }
1975 
1976  StringRef operatorStr;
1977  StringRef openStr, closeStr;
1978  VerilogPrecedence subprecedence = LowestPrecedence;
1979  VerilogPrecedence prec; // precedence of the emitted expression.
1980  std::optional<SubExprSignResult> operandSign;
1981  bool isUnary = false;
1982  bool hasOpenClose = false;
1983 
1984  switch (expr.getOpcode()) {
1985  case PEO::Add:
1986  operatorStr = " + ";
1987  subprecedence = Addition;
1988  break;
1989  case PEO::Mul:
1990  operatorStr = " * ";
1991  subprecedence = Multiply;
1992  break;
1993  case PEO::And:
1994  operatorStr = " & ";
1995  subprecedence = And;
1996  break;
1997  case PEO::Or:
1998  operatorStr = " | ";
1999  subprecedence = Or;
2000  break;
2001  case PEO::Xor:
2002  operatorStr = " ^ ";
2003  subprecedence = Xor;
2004  break;
2005  case PEO::Shl:
2006  operatorStr = " << ";
2007  subprecedence = Shift;
2008  break;
2009  case PEO::ShrU:
2010  // >> in verilog is always a logical shift even if operands are signed.
2011  operatorStr = " >> ";
2012  subprecedence = Shift;
2013  break;
2014  case PEO::ShrS:
2015  // >>> in verilog is an arithmetic shift if both operands are signed.
2016  operatorStr = " >>> ";
2017  subprecedence = Shift;
2018  operandSign = IsSigned;
2019  break;
2020  case PEO::DivU:
2021  operatorStr = " / ";
2022  subprecedence = Multiply;
2023  operandSign = IsUnsigned;
2024  break;
2025  case PEO::DivS:
2026  operatorStr = " / ";
2027  subprecedence = Multiply;
2028  operandSign = IsSigned;
2029  break;
2030  case PEO::ModU:
2031  operatorStr = " % ";
2032  subprecedence = Multiply;
2033  operandSign = IsUnsigned;
2034  break;
2035  case PEO::ModS:
2036  operatorStr = " % ";
2037  subprecedence = Multiply;
2038  operandSign = IsSigned;
2039  break;
2040  case PEO::CLog2:
2041  openStr = "$clog2(";
2042  closeStr = ")";
2043  operandSign = IsUnsigned;
2044  hasOpenClose = true;
2045  prec = Symbol;
2046  break;
2047  case PEO::StrConcat:
2048  openStr = "{";
2049  closeStr = "}";
2050  hasOpenClose = true;
2051  operatorStr = ", ";
2052  // We don't have Concat precedence, but it's lowest anyway. (SV Table 11-2).
2053  subprecedence = LowestPrecedence;
2054  prec = Symbol;
2055  break;
2056  }
2057  if (!hasOpenClose)
2058  prec = subprecedence;
2059 
2060  // unary -> one element.
2061  assert(!isUnary || llvm::hasSingleElement(expr.getOperands()));
2062  // one element -> {unary || open/close}.
2063  assert(isUnary || hasOpenClose ||
2064  !llvm::hasSingleElement(expr.getOperands()));
2065 
2066  // Emit the specified operand with a $signed() or $unsigned() wrapper around
2067  // it if context requires a specific signedness to compute the right value.
2068  // This returns true if the operand is signed.
2069  // TODO: This could try harder to omit redundant casts like the mainline
2070  // expression emitter.
2071  auto emitOperand = [&](Attribute operand) -> bool {
2072  // If surrounding with signed/unsigned, inner expr doesn't need parens.
2073  auto subprec = operandSign.has_value() ? LowestPrecedence : subprecedence;
2074  if (operandSign.has_value())
2075  os << (*operandSign == IsSigned ? "$signed(" : "$unsigned(");
2076  auto signedness =
2077  printParamValue(operand, os, subprec, emitError).signedness;
2078  if (operandSign.has_value()) {
2079  os << ')';
2080  signedness = *operandSign;
2081  }
2082  return signedness == IsSigned;
2083  };
2084 
2085  // Check outer precedence, wrap in parentheses if needed.
2086  if (prec > parenthesizeIfLooserThan)
2087  os << '(';
2088 
2089  // Emit opening portion of the operation.
2090  if (hasOpenClose)
2091  os << openStr;
2092  else if (isUnary)
2093  os << operatorStr;
2094 
2095  bool allOperandsSigned = emitOperand(expr.getOperands()[0]);
2096  for (auto op : expr.getOperands().drop_front()) {
2097  // Handle the special case of (a + b + -42) as (a + b - 42).
2098  // TODO: Also handle (a + b + x*-1).
2099  if (expr.getOpcode() == PEO::Add) {
2100  if (auto integer = dyn_cast<IntegerAttr>(op)) {
2101  const APInt &value = integer.getValue();
2102  if (value.isNegative() && !value.isMinSignedValue()) {
2103  os << " - ";
2104  allOperandsSigned &=
2105  emitOperand(IntegerAttr::get(op.getType(), -value));
2106  continue;
2107  }
2108  }
2109  }
2110 
2111  os << operatorStr;
2112  allOperandsSigned &= emitOperand(op);
2113  }
2114  if (hasOpenClose)
2115  os << closeStr;
2116  if (prec > parenthesizeIfLooserThan) {
2117  os << ')';
2118  prec = Selection;
2119  }
2120  return {prec, allOperandsSigned ? IsSigned : IsUnsigned};
2121 }
2122 // NOLINTEND(misc-no-recursion)
2123 
2124 //===----------------------------------------------------------------------===//
2125 // Expression Emission
2126 //===----------------------------------------------------------------------===//
2127 
2128 namespace {
2129 /// This builds a recursively nested expression from an SSA use-def graph. This
2130 /// uses a post-order walk, but it needs to obey precedence and signedness
2131 /// constraints that depend on the behavior of the child nodes.
2132 /// To handle this, we must buffer all output so we can insert parentheses
2133 /// and other things if we find out that it was needed later.
2134 // NOLINTBEGIN(misc-no-recursion)
2135 class ExprEmitter : public EmitterBase,
2136  public TypeOpVisitor<ExprEmitter, SubExprInfo>,
2137  public CombinationalVisitor<ExprEmitter, SubExprInfo>,
2138  public Visitor<ExprEmitter, SubExprInfo> {
2139 public:
2140  /// Create an ExprEmitter for the specified module emitter, and keeping track
2141  /// of any emitted expressions in the specified set.
2142  ExprEmitter(ModuleEmitter &emitter,
2143  SmallPtrSetImpl<Operation *> &emittedExprs)
2144  : ExprEmitter(emitter, emittedExprs, localTokens) {}
2145 
2146  ExprEmitter(ModuleEmitter &emitter,
2147  SmallPtrSetImpl<Operation *> &emittedExprs,
2148  BufferingPP::BufferVec &tokens)
2149  : EmitterBase(emitter.state), emitter(emitter),
2150  emittedExprs(emittedExprs), buffer(tokens),
2151  ps(buffer, state.saver, state.options.emitVerilogLocations) {
2152  assert(state.pp.getListener() == &state.saver);
2153  }
2154 
2155  /// Emit the specified value as an expression. If this is an inline-emitted
2156  /// expression, we emit that expression, otherwise we emit a reference to the
2157  /// already computed name.
2158  ///
2159  void emitExpression(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2160  bool isAssignmentLikeContext) {
2161  assert(localTokens.empty());
2162  // Wrap to this column.
2163  ps.scopedBox(PP::ibox0, [&]() {
2164  emitSubExpr(exp, parenthesizeIfLooserThan,
2165  /*signRequirement*/ NoRequirement,
2166  /*isSelfDeterminedUnsignedValue*/ false,
2167  isAssignmentLikeContext);
2168  });
2169  // If we are not using an external token buffer provided through the
2170  // constructor, but we're using the default `ExprEmitter`-scoped buffer,
2171  // flush it.
2172  if (&buffer.tokens == &localTokens)
2173  buffer.flush(state.pp);
2174  }
2175 
2176 private:
2177  friend class TypeOpVisitor<ExprEmitter, SubExprInfo>;
2178  friend class CombinationalVisitor<ExprEmitter, SubExprInfo>;
2179  friend class Visitor<ExprEmitter, SubExprInfo>;
2180 
2181  enum SubExprSignRequirement { NoRequirement, RequireSigned, RequireUnsigned };
2182 
2183  /// Emit the specified value `exp` as a subexpression to the stream. The
2184  /// `parenthesizeIfLooserThan` parameter indicates when parentheses should be
2185  /// added aroun the subexpression. The `signReq` flag can cause emitSubExpr
2186  /// to emit a subexpression that is guaranteed to be signed or unsigned, and
2187  /// the `isSelfDeterminedUnsignedValue` flag indicates whether the value is
2188  /// known to be have "self determined" width, allowing us to omit extensions.
2189  SubExprInfo emitSubExpr(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2190  SubExprSignRequirement signReq = NoRequirement,
2191  bool isSelfDeterminedUnsignedValue = false,
2192  bool isAssignmentLikeContext = false);
2193 
2194  /// Emit SystemVerilog attributes attached to the expression op as dialect
2195  /// attributes.
2196  void emitSVAttributes(Operation *op);
2197 
2198  SubExprInfo visitUnhandledExpr(Operation *op);
2199  SubExprInfo visitInvalidComb(Operation *op) {
2200  return dispatchTypeOpVisitor(op);
2201  }
2202  SubExprInfo visitUnhandledComb(Operation *op) {
2203  return visitUnhandledExpr(op);
2204  }
2205  SubExprInfo visitInvalidTypeOp(Operation *op) {
2206  return dispatchSVVisitor(op);
2207  }
2208  SubExprInfo visitUnhandledTypeOp(Operation *op) {
2209  return visitUnhandledExpr(op);
2210  }
2211  SubExprInfo visitUnhandledSV(Operation *op) { return visitUnhandledExpr(op); }
2212 
2213  using Visitor::visitSV;
2214 
2215  /// These are flags that control `emitBinary`.
2216  enum EmitBinaryFlags {
2217  EB_RequireSignedOperands = RequireSigned, /* 0x1*/
2218  EB_RequireUnsignedOperands = RequireUnsigned, /* 0x2*/
2219  EB_OperandSignRequirementMask = 0x3,
2220 
2221  /// This flag indicates that the RHS operand is an unsigned value that has
2222  /// "self determined" width. This means that we can omit explicit zero
2223  /// extensions from it, and don't impose a sign on it.
2224  EB_RHS_UnsignedWithSelfDeterminedWidth = 0x4,
2225 
2226  /// This flag indicates that the result should be wrapped in a $signed(x)
2227  /// expression to force the result to signed.
2228  EB_ForceResultSigned = 0x8,
2229  };
2230 
2231  /// Emit a binary expression. The "emitBinaryFlags" are a bitset from
2232  /// EmitBinaryFlags.
2233  SubExprInfo emitBinary(Operation *op, VerilogPrecedence prec,
2234  const char *syntax, unsigned emitBinaryFlags = 0);
2235 
2236  SubExprInfo emitUnary(Operation *op, const char *syntax,
2237  bool resultAlwaysUnsigned = false);
2238 
2239  /// Emit the specified value as a subexpression, wrapping in an ibox2.
2240  void emitSubExprIBox2(
2241  Value v, VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence) {
2242  ps.scopedBox(PP::ibox2,
2243  [&]() { emitSubExpr(v, parenthesizeIfLooserThan); });
2244  }
2245 
2246  /// Emit a range of values separated by commas and a breakable space.
2247  /// Each value is emitted by invoking `eachFn`.
2248  template <typename Container, typename EachFn>
2249  void interleaveComma(const Container &c, EachFn eachFn) {
2250  llvm::interleave(c, eachFn, [&]() { ps << "," << PP::space; });
2251  }
2252 
2253  /// Emit a range of values separated by commas and a breakable space.
2254  /// Each value is emitted in an ibox2.
2255  void interleaveComma(ValueRange ops) {
2256  return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
2257  }
2258 
2259  /// Emit an array-literal-like structure, separated by commas.
2260  /// Use callbacks to emit open tokens, closing tokens, and handle each value.
2261  /// If it fits, will be emitted on a single line with no space between
2262  /// list and surrounding open and close.
2263  /// Otherwise, each item is placed on its own line.
2264  /// This has property that if any element requires breaking, all elements
2265  /// are emitted on separate lines (with open/close attached to first/last).
2266  /// `{a + b, x + y, c}`
2267  /// OR
2268  /// ```
2269  /// {a + b,
2270  /// x + y,
2271  /// c}
2272  /// ```
2273  template <typename Container, typename OpenFunc, typename CloseFunc,
2274  typename EachFunc>
2275  void emitBracedList(const Container &c, OpenFunc openFn, EachFunc eachFn,
2276  CloseFunc closeFn) {
2277  openFn();
2278  ps.scopedBox(PP::cbox0, [&]() {
2279  interleaveComma(c, eachFn);
2280  closeFn();
2281  });
2282  }
2283 
2284  /// Emit braced list of values surrounded by specified open/close.
2285  template <typename OpenFunc, typename CloseFunc>
2286  void emitBracedList(ValueRange ops, OpenFunc openFn, CloseFunc closeFn) {
2287  return emitBracedList(
2288  ops, openFn, [&](Value v) { emitSubExprIBox2(v); }, closeFn);
2289  }
2290 
2291  /// Emit braced list of values surrounded by `{` and `}`.
2292  void emitBracedList(ValueRange ops) {
2293  return emitBracedList(
2294  ops, [&]() { ps << "{"; }, [&]() { ps << "}"; });
2295  }
2296 
2297  /// Print an APInt constant.
2298  SubExprInfo printConstantScalar(APInt &value, IntegerType type);
2299 
2300  /// Print a constant array.
2301  void printConstantArray(ArrayAttr elementValues, Type elementType,
2302  bool printAsPattern, Operation *op);
2303  /// Print a constant struct.
2304  void printConstantStruct(ArrayRef<hw::detail::FieldInfo> fieldInfos,
2305  ArrayAttr fieldValues, bool printAsPattern,
2306  Operation *op);
2307  /// Print an aggregate array or struct constant as the given type.
2308  void printConstantAggregate(Attribute attr, Type type, Operation *op);
2309 
2310  SubExprInfo visitSV(GetModportOp op);
2311  SubExprInfo visitSV(SystemFunctionOp op);
2312  SubExprInfo visitSV(ReadInterfaceSignalOp op);
2313  SubExprInfo visitSV(XMROp op);
2314  SubExprInfo visitSV(XMRRefOp op);
2315  SubExprInfo visitVerbatimExprOp(Operation *op, ArrayAttr symbols);
2316  SubExprInfo visitSV(VerbatimExprOp op) {
2317  return visitVerbatimExprOp(op, op.getSymbols());
2318  }
2319  SubExprInfo visitSV(VerbatimExprSEOp op) {
2320  return visitVerbatimExprOp(op, op.getSymbols());
2321  }
2322  SubExprInfo visitSV(MacroRefExprOp op);
2323  SubExprInfo visitSV(MacroRefExprSEOp op);
2324  template <typename MacroTy>
2325  SubExprInfo emitMacroCall(MacroTy op);
2326 
2327  SubExprInfo visitSV(ConstantXOp op);
2328  SubExprInfo visitSV(ConstantZOp op);
2329  SubExprInfo visitSV(ConstantStrOp op);
2330 
2331  SubExprInfo visitSV(sv::UnpackedArrayCreateOp op);
2332  SubExprInfo visitSV(sv::UnpackedOpenArrayCastOp op) {
2333  // Cast op is noop.
2334  return emitSubExpr(op->getOperand(0), LowestPrecedence);
2335  }
2336 
2337  // Noop cast operators.
2338  SubExprInfo visitSV(ReadInOutOp op) {
2339  auto result = emitSubExpr(op->getOperand(0), LowestPrecedence);
2340  emitSVAttributes(op);
2341  return result;
2342  }
2343  SubExprInfo visitSV(ArrayIndexInOutOp op);
2344  SubExprInfo visitSV(IndexedPartSelectInOutOp op);
2345  SubExprInfo visitSV(IndexedPartSelectOp op);
2346  SubExprInfo visitSV(StructFieldInOutOp op);
2347 
2348  // Sampled value functions
2349  SubExprInfo visitSV(SampledOp op);
2350 
2351  // Other
2352  using TypeOpVisitor::visitTypeOp;
2353  SubExprInfo visitTypeOp(ConstantOp op);
2354  SubExprInfo visitTypeOp(AggregateConstantOp op);
2355  SubExprInfo visitTypeOp(BitcastOp op);
2356  SubExprInfo visitTypeOp(ParamValueOp op);
2357  SubExprInfo visitTypeOp(ArraySliceOp op);
2358  SubExprInfo visitTypeOp(ArrayGetOp op);
2359  SubExprInfo visitTypeOp(ArrayCreateOp op);
2360  SubExprInfo visitTypeOp(ArrayConcatOp op);
2361  SubExprInfo visitTypeOp(StructCreateOp op);
2362  SubExprInfo visitTypeOp(StructExtractOp op);
2363  SubExprInfo visitTypeOp(StructInjectOp op);
2364  SubExprInfo visitTypeOp(UnionCreateOp op);
2365  SubExprInfo visitTypeOp(UnionExtractOp op);
2366  SubExprInfo visitTypeOp(EnumCmpOp op);
2367  SubExprInfo visitTypeOp(EnumConstantOp op);
2368 
2369  // Comb Dialect Operations
2370  using CombinationalVisitor::visitComb;
2371  SubExprInfo visitComb(MuxOp op);
2372  SubExprInfo visitComb(AddOp op) {
2373  assert(op.getNumOperands() == 2 && "prelowering should handle variadics");
2374  return emitBinary(op, Addition, "+");
2375  }
2376  SubExprInfo visitComb(SubOp op) { return emitBinary(op, Addition, "-"); }
2377  SubExprInfo visitComb(MulOp op) {
2378  assert(op.getNumOperands() == 2 && "prelowering should handle variadics");
2379  return emitBinary(op, Multiply, "*");
2380  }
2381  SubExprInfo visitComb(DivUOp op) {
2382  return emitBinary(op, Multiply, "/", EB_RequireUnsignedOperands);
2383  }
2384  SubExprInfo visitComb(DivSOp op) {
2385  return emitBinary(op, Multiply, "/",
2386  EB_RequireSignedOperands | EB_ForceResultSigned);
2387  }
2388  SubExprInfo visitComb(ModUOp op) {
2389  return emitBinary(op, Multiply, "%", EB_RequireUnsignedOperands);
2390  }
2391  SubExprInfo visitComb(ModSOp op) {
2392  return emitBinary(op, Multiply, "%",
2393  EB_RequireSignedOperands | EB_ForceResultSigned);
2394  }
2395  SubExprInfo visitComb(ShlOp op) {
2396  return emitBinary(op, Shift, "<<", EB_RHS_UnsignedWithSelfDeterminedWidth);
2397  }
2398  SubExprInfo visitComb(ShrUOp op) {
2399  // >> in Verilog is always an unsigned right shift.
2400  return emitBinary(op, Shift, ">>", EB_RHS_UnsignedWithSelfDeterminedWidth);
2401  }
2402  SubExprInfo visitComb(ShrSOp op) {
2403  // >>> is only an arithmetic shift right when both operands are signed.
2404  // Otherwise it does a logical shift.
2405  return emitBinary(op, Shift, ">>>",
2406  EB_RequireSignedOperands | EB_ForceResultSigned |
2407  EB_RHS_UnsignedWithSelfDeterminedWidth);
2408  }
2409  SubExprInfo visitComb(AndOp op) {
2410  assert(op.getNumOperands() == 2 && "prelowering should handle variadics");
2411  return emitBinary(op, And, "&");
2412  }
2413  SubExprInfo visitComb(OrOp op) {
2414  assert(op.getNumOperands() == 2 && "prelowering should handle variadics");
2415  return emitBinary(op, Or, "|");
2416  }
2417  SubExprInfo visitComb(XorOp op) {
2418  if (op.isBinaryNot())
2419  return emitUnary(op, "~");
2420  assert(op.getNumOperands() == 2 && "prelowering should handle variadics");
2421  return emitBinary(op, Xor, "^");
2422  }
2423 
2424  // SystemVerilog spec 11.8.1: "Reduction operator results are unsigned,
2425  // regardless of the operands."
2426  SubExprInfo visitComb(ParityOp op) { return emitUnary(op, "^", true); }
2427 
2428  SubExprInfo visitComb(ReplicateOp op);
2429  SubExprInfo visitComb(ConcatOp op);
2430  SubExprInfo visitComb(ExtractOp op);
2431  SubExprInfo visitComb(ICmpOp op);
2432 
2433  InFlightDiagnostic emitAssignmentPatternContextError(Operation *op) {
2434  auto d = emitOpError(op, "must be printed as assignment pattern, but is "
2435  "not printed within an assignment-like context");
2436  d.attachNote() << "this is likely a bug in PrepareForEmission, which is "
2437  "supposed to spill such expressions";
2438  return d;
2439  }
2440 
2441  SubExprInfo printStructCreate(
2442  ArrayRef<hw::detail::FieldInfo> fieldInfos,
2443  llvm::function_ref<void(const hw::detail::FieldInfo &, unsigned)> fieldFn,
2444  bool printAsPattern, Operation *op);
2445 
2446 public:
2447  ModuleEmitter &emitter;
2448 
2449 private:
2450  /// This is set (before a visit method is called) if emitSubExpr would
2451  /// prefer to get an output of a specific sign. This is a hint to cause the
2452  /// visitor to change its emission strategy, but the visit method can ignore
2453  /// it without a correctness problem.
2454  SubExprSignRequirement signPreference = NoRequirement;
2455 
2456  /// Keep track of all operations emitted within this subexpression for
2457  /// location information tracking.
2458  SmallPtrSetImpl<Operation *> &emittedExprs;
2459 
2460  /// Tokens buffered for inserting casts/parens after emitting children.
2461  SmallVector<Token> localTokens;
2462 
2463  /// Stores tokens until told to flush. Uses provided buffer (tokens).
2464  BufferingPP buffer;
2465 
2466  /// Stream to emit expressions into, will add to buffer.
2468 
2469  /// Tracks whether the expression being emitted is currently within an
2470  /// assignment-like context. Certain constructs such as `'{...}` assignment
2471  /// patterns are restricted to only appear in assignment-like contexts.
2472  /// Others, like packed struct and array constants, can be printed as either
2473  /// `{...}` concatenation or `'{...}` assignment pattern, depending on whether
2474  /// they appear within an assignment-like context or not.
2475  bool isAssignmentLikeContext = false;
2476 };
2477 } // end anonymous namespace
2478 
2479 SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
2480  const char *syntax,
2481  unsigned emitBinaryFlags) {
2482  if (hasSVAttributes(op))
2483  emitError(op, "SV attributes emission is unimplemented for the op");
2484 
2485  // It's tempting to wrap expressions in groups as we emit them,
2486  // but that can cause bad wrapping as-is:
2487  // add(a, add(b, add(c, add(d, e))))
2488  // ->
2489  // group(a + (group(b + group(c + group(d + e)))))
2490  // Which will break after 'a +' first.
2491  // TODO: Build tree capturing precedence/fixity at same level, group those!
2492  // Maybe like: https://www.tweag.io/blog/2022-02-10-ormolu-and-operators/ .
2493  // For now, only group within punctuation, such as parens + braces.
2494  if (emitBinaryFlags & EB_ForceResultSigned)
2495  ps << "$signed(" << PP::ibox0;
2496  auto operandSignReq =
2497  SubExprSignRequirement(emitBinaryFlags & EB_OperandSignRequirementMask);
2498  auto lhsInfo = emitSubExpr(op->getOperand(0), prec, operandSignReq);
2499  // Bit of a kludge: if this is a comparison, don't break on either side.
2500  auto lhsSpace = prec == VerilogPrecedence::Comparison ? PP::nbsp : PP::space;
2501  // Use non-breaking space between op and RHS so breaking is consistent.
2502  ps << lhsSpace << syntax << PP::nbsp; // PP::space;
2503 
2504  // Right associative operators are already generally variadic, we need to
2505  // handle things like: (a<4> == b<4>) == (c<3> == d<3>). When processing the
2506  // top operation of the tree, the rhs needs parens. When processing
2507  // known-reassociative operators like +, ^, etc we don't need parens.
2508  // TODO: MLIR should have general "Associative" trait.
2509  auto rhsPrec = prec;
2510  if (!isa<AddOp, MulOp, AndOp, OrOp, XorOp>(op))
2511  rhsPrec = VerilogPrecedence(prec - 1);
2512 
2513  // If the RHS operand has self-determined width and always treated as
2514  // unsigned, inform emitSubExpr of this. This is true for the shift amount in
2515  // a shift operation.
2516  bool rhsIsUnsignedValueWithSelfDeterminedWidth = false;
2517  if (emitBinaryFlags & EB_RHS_UnsignedWithSelfDeterminedWidth) {
2518  rhsIsUnsignedValueWithSelfDeterminedWidth = true;
2519  operandSignReq = NoRequirement;
2520  }
2521 
2522  auto rhsInfo = emitSubExpr(op->getOperand(1), rhsPrec, operandSignReq,
2523  rhsIsUnsignedValueWithSelfDeterminedWidth);
2524 
2525  // SystemVerilog 11.8.1 says that the result of a binary expression is signed
2526  // only if both operands are signed.
2527  SubExprSignResult signedness = IsUnsigned;
2528  if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
2529  signedness = IsSigned;
2530 
2531  if (emitBinaryFlags & EB_ForceResultSigned) {
2532  ps << PP::end << ")";
2533  signedness = IsSigned;
2534  prec = Selection;
2535  }
2536 
2537  return {prec, signedness};
2538 }
2539 
2540 SubExprInfo ExprEmitter::emitUnary(Operation *op, const char *syntax,
2541  bool resultAlwaysUnsigned) {
2542  if (hasSVAttributes(op))
2543  emitError(op, "SV attributes emission is unimplemented for the op");
2544 
2545  ps << syntax;
2546  auto signedness = emitSubExpr(op->getOperand(0), Selection).signedness;
2547  // For reduction operators "&" and "|", make precedence lowest to avoid
2548  // emitting an expression like `a & &b`, which is syntactically valid but some
2549  // tools produce LINT warnings.
2550  return {isa<ICmpOp>(op) ? LowestPrecedence : Unary,
2551  resultAlwaysUnsigned ? IsUnsigned : signedness};
2552 }
2553 
2554 /// Emit SystemVerilog attributes attached to the expression op as dialect
2555 /// attributes.
2556 void ExprEmitter::emitSVAttributes(Operation *op) {
2557  // SystemVerilog 2017 Section 5.12.
2558  auto svAttrs = getSVAttributes(op);
2559  if (!svAttrs)
2560  return;
2561 
2562  // For now, no breaks for attributes.
2563  ps << PP::nbsp;
2564  emitSVAttributesImpl(ps, svAttrs, /*mayBreak=*/false);
2565 }
2566 
2567 /// If the specified extension is a zero extended version of another value,
2568 /// return the shorter value, otherwise return null.
2569 static Value isZeroExtension(Value value) {
2570  auto concat = value.getDefiningOp<ConcatOp>();
2571  if (!concat || concat.getNumOperands() != 2)
2572  return {};
2573 
2574  auto constant = concat.getOperand(0).getDefiningOp<ConstantOp>();
2575  if (constant && constant.getValue().isZero())
2576  return concat.getOperand(1);
2577  return {};
2578 }
2579 
2580 /// Emit the specified value `exp` as a subexpression to the stream. The
2581 /// `parenthesizeIfLooserThan` parameter indicates when parentheses should be
2582 /// added aroun the subexpression. The `signReq` flag can cause emitSubExpr
2583 /// to emit a subexpression that is guaranteed to be signed or unsigned, and
2584 /// the `isSelfDeterminedUnsignedValue` flag indicates whether the value is
2585 /// known to be have "self determined" width, allowing us to omit extensions.
2586 SubExprInfo ExprEmitter::emitSubExpr(Value exp,
2587  VerilogPrecedence parenthesizeIfLooserThan,
2588  SubExprSignRequirement signRequirement,
2589  bool isSelfDeterminedUnsignedValue,
2590  bool isAssignmentLikeContext) {
2591  // If this is a self-determined unsigned value, look through any inline zero
2592  // extensions. This occurs on the RHS of a shift operation for example.
2593  if (isSelfDeterminedUnsignedValue && exp.hasOneUse()) {
2594  if (auto smaller = isZeroExtension(exp))
2595  exp = smaller;
2596  }
2597 
2598  auto *op = exp.getDefiningOp();
2599  bool shouldEmitInlineExpr = op && isVerilogExpression(op);
2600 
2601  // If this is a non-expr or shouldn't be done inline, just refer to its name.
2602  if (!shouldEmitInlineExpr) {
2603  // All wires are declared as unsigned, so if the client needed it signed,
2604  // emit a conversion.
2605  if (signRequirement == RequireSigned) {
2606  ps << "$signed(" << PPExtString(getVerilogValueName(exp)) << ")";
2607  return {Symbol, IsSigned};
2608  }
2609 
2610  ps << PPExtString(getVerilogValueName(exp));
2611  return {Symbol, IsUnsigned};
2612  }
2613 
2614  unsigned subExprStartIndex = buffer.tokens.size();
2615  if (op)
2616  ps.addCallback({op, true});
2617  auto done = llvm::make_scope_exit([&]() {
2618  if (op)
2619  ps.addCallback({op, false});
2620  });
2621 
2622  // Inform the visit method about the preferred sign we want from the result.
2623  // It may choose to ignore this, but some emitters can change behavior based
2624  // on contextual desired sign.
2625  signPreference = signRequirement;
2626 
2627  bool bitCastAdded = false;
2628  if (state.options.explicitBitcast && isa<AddOp, MulOp, SubOp>(op))
2629  if (auto inType =
2630  dyn_cast_or_null<IntegerType>(op->getResult(0).getType())) {
2631  ps.addAsString(inType.getWidth());
2632  ps << "'(" << PP::ibox0;
2633  bitCastAdded = true;
2634  }
2635  // Okay, this is an expression we should emit inline. Do this through our
2636  // visitor.
2637  llvm::SaveAndRestore restoreALC(this->isAssignmentLikeContext,
2638  isAssignmentLikeContext);
2639  auto expInfo = dispatchCombinationalVisitor(exp.getDefiningOp());
2640 
2641  // Check cases where we have to insert things before the expression now that
2642  // we know things about it.
2643  auto addPrefix = [&](StringToken &&t) {
2644  // insert {Prefix, ibox0}.
2645  buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex,
2646  BeginToken(0));
2647  buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex, t);
2648  };
2649  auto closeBoxAndParen = [&]() { ps << PP::end << ")"; };
2650  if (signRequirement == RequireSigned && expInfo.signedness == IsUnsigned) {
2651  addPrefix(StringToken("$signed("));
2652  closeBoxAndParen();
2653  expInfo.signedness = IsSigned;
2654  expInfo.precedence = Selection;
2655  } else if (signRequirement == RequireUnsigned &&
2656  expInfo.signedness == IsSigned) {
2657  addPrefix(StringToken("$unsigned("));
2658  closeBoxAndParen();
2659  expInfo.signedness = IsUnsigned;
2660  expInfo.precedence = Selection;
2661  } else if (expInfo.precedence > parenthesizeIfLooserThan) {
2662  // If this subexpression would bind looser than the expression it is bound
2663  // into, then we need to parenthesize it. Insert the parentheses
2664  // retroactively.
2665  addPrefix(StringToken("("));
2666  closeBoxAndParen();
2667  // Reset the precedence to the () level.
2668  expInfo.precedence = Selection;
2669  }
2670  if (bitCastAdded) {
2671  closeBoxAndParen();
2672  }
2673 
2674  // Remember that we emitted this.
2675  emittedExprs.insert(exp.getDefiningOp());
2676  return expInfo;
2677 }
2678 
2679 SubExprInfo ExprEmitter::visitComb(ReplicateOp op) {
2680  auto openFn = [&]() {
2681  ps << "{";
2682  ps.addAsString(op.getMultiple());
2683  ps << "{";
2684  };
2685  auto closeFn = [&]() { ps << "}}"; };
2686 
2687  // If the subexpression is an inline concat, we can emit it as part of the
2688  // replicate.
2689  if (auto concatOp = op.getOperand().getDefiningOp<ConcatOp>()) {
2690  if (op.getOperand().hasOneUse()) {
2691  emitBracedList(concatOp.getOperands(), openFn, closeFn);
2692  return {Symbol, IsUnsigned};
2693  }
2694  }
2695  emitBracedList(op.getOperand(), openFn, closeFn);
2696  return {Symbol, IsUnsigned};
2697 }
2698 
2699 SubExprInfo ExprEmitter::visitComb(ConcatOp op) {
2700  emitBracedList(op.getOperands());
2701  return {Symbol, IsUnsigned};
2702 }
2703 
2704 SubExprInfo ExprEmitter::visitTypeOp(BitcastOp op) {
2705  // NOTE: Bitcasts are emitted out-of-line with their own wire declaration when
2706  // their dimensions don't match. SystemVerilog uses the wire declaration to
2707  // know what type this value is being casted to.
2708  Type toType = op.getType();
2709  if (!haveMatchingDims(toType, op.getInput().getType(), op.getLoc())) {
2710  ps << "/*cast(bit";
2711  ps.invokeWithStringOS(
2712  [&](auto &os) { emitter.emitTypeDims(toType, op.getLoc(), os); });
2713  ps << ")*/";
2714  }
2715  return emitSubExpr(op.getInput(), LowestPrecedence);
2716 }
2717 
2718 SubExprInfo ExprEmitter::visitComb(ICmpOp op) {
2719  const char *symop[] = {"==", "!=", "<", "<=", ">", ">=", "<",
2720  "<=", ">", ">=", "===", "!==", "==?", "!=?"};
2721  SubExprSignRequirement signop[] = {
2722  // Equality
2723  NoRequirement, NoRequirement,
2724  // Signed Comparisons
2725  RequireSigned, RequireSigned, RequireSigned, RequireSigned,
2726  // Unsigned Comparisons
2727  RequireUnsigned, RequireUnsigned, RequireUnsigned, RequireUnsigned,
2728  // Weird Comparisons
2729  NoRequirement, NoRequirement, NoRequirement, NoRequirement};
2730 
2731  auto pred = static_cast<uint64_t>(op.getPredicate());
2732  assert(pred < sizeof(symop) / sizeof(symop[0]));
2733 
2734  // Lower "== -1" to Reduction And.
2735  if (op.isEqualAllOnes())
2736  return emitUnary(op, "&", true);
2737 
2738  // Lower "!= 0" to Reduction Or.
2739  if (op.isNotEqualZero())
2740  return emitUnary(op, "|", true);
2741 
2742  auto result = emitBinary(op, Comparison, symop[pred], signop[pred]);
2743 
2744  // SystemVerilog 11.8.1: "Comparison... operator results are unsigned,
2745  // regardless of the operands".
2746  result.signedness = IsUnsigned;
2747  return result;
2748 }
2749 
2750 SubExprInfo ExprEmitter::visitComb(ExtractOp op) {
2751  if (hasSVAttributes(op))
2752  emitError(op, "SV attributes emission is unimplemented for the op");
2753 
2754  unsigned loBit = op.getLowBit();
2755  unsigned hiBit = loBit + cast<IntegerType>(op.getType()).getWidth() - 1;
2756 
2757  auto x = emitSubExpr(op.getInput(), LowestPrecedence);
2758  assert((x.precedence == Symbol ||
2759  (x.precedence == Selection && isOkToBitSelectFrom(op.getInput()))) &&
2760  "should be handled by isExpressionUnableToInline");
2761 
2762  // If we're extracting the whole input, just return it. This is valid but
2763  // non-canonical IR, and we don't want to generate invalid Verilog.
2764  if (loBit == 0 &&
2765  op.getInput().getType().getIntOrFloatBitWidth() == hiBit + 1)
2766  return x;
2767 
2768  ps << "[";
2769  ps.addAsString(hiBit);
2770  if (hiBit != loBit) { // Emit x[4] instead of x[4:4].
2771  ps << ":";
2772  ps.addAsString(loBit);
2773  }
2774  ps << "]";
2775  return {Unary, IsUnsigned};
2776 }
2777 
2778 SubExprInfo ExprEmitter::visitSV(GetModportOp op) {
2779  if (hasSVAttributes(op))
2780  emitError(op, "SV attributes emission is unimplemented for the op");
2781 
2782  auto decl = op.getReferencedDecl(state.symbolCache);
2783  ps << PPExtString(getVerilogValueName(op.getIface())) << "."
2784  << PPExtString(getSymOpName(decl));
2785  return {Selection, IsUnsigned};
2786 }
2787 
2788 SubExprInfo ExprEmitter::visitSV(SystemFunctionOp op) {
2789  if (hasSVAttributes(op))
2790  emitError(op, "SV attributes emission is unimplemented for the op");
2791 
2792  ps << "$" << PPExtString(op.getFnName()) << "(";
2793  ps.scopedBox(PP::ibox0, [&]() {
2794  llvm::interleave(
2795  op.getOperands(), [&](Value v) { emitSubExpr(v, LowestPrecedence); },
2796  [&]() { ps << "," << PP::space; });
2797  ps << ")";
2798  });
2799  return {Symbol, IsUnsigned};
2800 }
2801 
2802 SubExprInfo ExprEmitter::visitSV(ReadInterfaceSignalOp op) {
2803  if (hasSVAttributes(op))
2804  emitError(op, "SV attributes emission is unimplemented for the op");
2805 
2806  auto decl = op.getReferencedDecl(state.symbolCache);
2807 
2808  ps << PPExtString(getVerilogValueName(op.getIface())) << "."
2809  << PPExtString(getSymOpName(decl));
2810  return {Selection, IsUnsigned};
2811 }
2812 
2813 SubExprInfo ExprEmitter::visitSV(XMROp op) {
2814  if (hasSVAttributes(op))
2815  emitError(op, "SV attributes emission is unimplemented for the op");
2816 
2817  if (op.getIsRooted())
2818  ps << "$root.";
2819  for (auto s : op.getPath())
2820  ps << PPExtString(cast<StringAttr>(s).getValue()) << ".";
2821  ps << PPExtString(op.getTerminal());
2822  return {Selection, IsUnsigned};
2823 }
2824 
2825 // TODO: This shares a lot of code with the getNameRemotely mtehod. Combine
2826 // these to share logic.
2827 SubExprInfo ExprEmitter::visitSV(XMRRefOp op) {
2828  if (hasSVAttributes(op))
2829  emitError(op, "SV attributes emission is unimplemented for the op");
2830 
2831  // The XMR is pointing at a GlobalRef.
2832  auto globalRef = op.getReferencedPath(&state.symbolCache);
2833  auto namepath = globalRef.getNamepathAttr().getValue();
2834  auto *module = state.symbolCache.getDefinition(
2835  cast<InnerRefAttr>(namepath.front()).getModule());
2836  ps << PPExtString(getSymOpName(module));
2837  for (auto sym : namepath) {
2838  ps << ".";
2839  auto innerRef = cast<InnerRefAttr>(sym);
2840  auto ref = state.symbolCache.getInnerDefinition(innerRef.getModule(),
2841  innerRef.getName());
2842  if (ref.hasPort()) {
2843  ps << PPExtString(getPortVerilogName(ref.getOp(), ref.getPort()));
2844  continue;
2845  }
2846  ps << PPExtString(getSymOpName(ref.getOp()));
2847  }
2848  auto leaf = op.getVerbatimSuffixAttr();
2849  if (leaf && leaf.size())
2850  ps << PPExtString(leaf);
2851  return {Selection, IsUnsigned};
2852 }
2853 
2854 SubExprInfo ExprEmitter::visitVerbatimExprOp(Operation *op, ArrayAttr symbols) {
2855  if (hasSVAttributes(op))
2856  emitError(op, "SV attributes emission is unimplemented for the op");
2857 
2858  emitTextWithSubstitutions(
2859  ps, op->getAttrOfType<StringAttr>("format_string").getValue(), op,
2860  [&](Value operand) { emitSubExpr(operand, LowestPrecedence); }, symbols);
2861 
2862  return {Unary, IsUnsigned};
2863 }
2864 
2865 template <typename MacroTy>
2866 SubExprInfo ExprEmitter::emitMacroCall(MacroTy op) {
2867  if (hasSVAttributes(op))
2868  emitError(op, "SV attributes emission is unimplemented for the op");
2869 
2870  // Use the specified name or the symbol name as appropriate.
2871  auto macroOp = op.getReferencedMacro(&state.symbolCache);
2872  assert(macroOp && "Invalid IR");
2873  StringRef name =
2874  macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
2875  ps << "`" << PPExtString(name);
2876  if (!op.getInputs().empty()) {
2877  ps << "(";
2878  llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
2879  emitExpression(val, LowestPrecedence, /*isAssignmentLikeContext=*/false);
2880  });
2881  ps << ")";
2882  }
2883  return {LowestPrecedence, IsUnsigned};
2884 }
2885 
2886 SubExprInfo ExprEmitter::visitSV(MacroRefExprOp op) {
2887  return emitMacroCall(op);
2888 }
2889 
2890 SubExprInfo ExprEmitter::visitSV(MacroRefExprSEOp op) {
2891  return emitMacroCall(op);
2892 }
2893 
2894 SubExprInfo ExprEmitter::visitSV(ConstantXOp op) {
2895  if (hasSVAttributes(op))
2896  emitError(op, "SV attributes emission is unimplemented for the op");
2897 
2898  ps.addAsString(op.getWidth());
2899  ps << "'bx";
2900  return {Unary, IsUnsigned};
2901 }
2902 
2903 SubExprInfo ExprEmitter::visitSV(ConstantStrOp op) {
2904  if (hasSVAttributes(op))
2905  emitError(op, "SV attributes emission is unimplemented for the op");
2906 
2907  ps.writeQuotedEscaped(op.getStr());
2908  return {Symbol, IsUnsigned}; // is a string unsigned? Yes! SV 5.9
2909 }
2910 
2911 SubExprInfo ExprEmitter::visitSV(ConstantZOp op) {
2912  if (hasSVAttributes(op))
2913  emitError(op, "SV attributes emission is unimplemented for the op");
2914 
2915  ps.addAsString(op.getWidth());
2916  ps << "'bz";
2917  return {Unary, IsUnsigned};
2918 }
2919 
2920 SubExprInfo ExprEmitter::printConstantScalar(APInt &value, IntegerType type) {
2921  bool isNegated = false;
2922  // If this is a negative signed number and not MININT (e.g. -128), then print
2923  // it as a negated positive number.
2924  if (signPreference == RequireSigned && value.isNegative() &&
2925  !value.isMinSignedValue()) {
2926  ps << "-";
2927  isNegated = true;
2928  }
2929 
2930  ps.addAsString(type.getWidth());
2931  ps << "'";
2932 
2933  // Emit this as a signed constant if the caller would prefer that.
2934  if (signPreference == RequireSigned)
2935  ps << "sh";
2936  else
2937  ps << "h";
2938 
2939  // Print negated if required.
2940  SmallString<32> valueStr;
2941  if (isNegated) {
2942  (-value).toStringUnsigned(valueStr, 16);
2943  } else {
2944  value.toStringUnsigned(valueStr, 16);
2945  }
2946  ps << valueStr;
2947  return {Unary, signPreference == RequireSigned ? IsSigned : IsUnsigned};
2948 }
2949 
2950 SubExprInfo ExprEmitter::visitTypeOp(ConstantOp op) {
2951  if (hasSVAttributes(op))
2952  emitError(op, "SV attributes emission is unimplemented for the op");
2953 
2954  auto value = op.getValue();
2955  // We currently only allow zero width values to be handled as special cases in
2956  // the various operations that may come across them. If we reached this point
2957  // in the emitter, the value should be considered illegal to emit.
2958  if (value.getBitWidth() == 0) {
2959  emitOpError(op, "will not emit zero width constants in the general case");
2960  ps << "<<unsupported zero width constant: "
2961  << PPExtString(op->getName().getStringRef()) << ">>";
2962  return {Unary, IsUnsigned};
2963  }
2964 
2965  return printConstantScalar(value, cast<IntegerType>(op.getType()));
2966 }
2967 
2968 void ExprEmitter::printConstantArray(ArrayAttr elementValues, Type elementType,
2969  bool printAsPattern, Operation *op) {
2970  if (printAsPattern && !isAssignmentLikeContext)
2971  emitAssignmentPatternContextError(op);
2972  StringRef openDelim = printAsPattern ? "'{" : "{";
2973 
2974  emitBracedList(
2975  elementValues, [&]() { ps << openDelim; },
2976  [&](Attribute elementValue) {
2977  printConstantAggregate(elementValue, elementType, op);
2978  },
2979  [&]() { ps << "}"; });
2980 }
2981 
2982 void ExprEmitter::printConstantStruct(
2983  ArrayRef<hw::detail::FieldInfo> fieldInfos, ArrayAttr fieldValues,
2984  bool printAsPattern, Operation *op) {
2985  if (printAsPattern && !isAssignmentLikeContext)
2986  emitAssignmentPatternContextError(op);
2987 
2988  // Only emit elements with non-zero bit width.
2989  // TODO: Ideally we should emit zero bit values as comments, e.g. `{/*a:
2990  // ZeroBit,*/ b: foo, /* c: ZeroBit*/ d: bar}`. However it's tedious to
2991  // nicely emit all edge cases hence currently we just elide zero bit
2992  // values.
2993  auto fieldRange = llvm::make_filter_range(
2994  llvm::zip(fieldInfos, fieldValues), [](const auto &fieldAndValue) {
2995  // Elide zero bit elements.
2996  return !isZeroBitType(std::get<0>(fieldAndValue).type);
2997  });
2998 
2999  if (printAsPattern) {
3000  emitBracedList(
3001  fieldRange, [&]() { ps << "'{"; },
3002  [&](const auto &fieldAndValue) {
3003  ps.scopedBox(PP::ibox2, [&]() {
3004  const auto &[field, value] = fieldAndValue;
3005  ps << PPExtString(emitter.getVerilogStructFieldName(field.name))
3006  << ":" << PP::space;
3007  printConstantAggregate(value, field.type, op);
3008  });
3009  },
3010  [&]() { ps << "}"; });
3011  } else {
3012  emitBracedList(
3013  fieldRange, [&]() { ps << "{"; },
3014  [&](const auto &fieldAndValue) {
3015  ps.scopedBox(PP::ibox2, [&]() {
3016  const auto &[field, value] = fieldAndValue;
3017  printConstantAggregate(value, field.type, op);
3018  });
3019  },
3020  [&]() { ps << "}"; });
3021  }
3022 }
3023 
3024 void ExprEmitter::printConstantAggregate(Attribute attr, Type type,
3025  Operation *op) {
3026  // Packed arrays can be printed as concatenation or pattern.
3027  if (auto arrayType = hw::type_dyn_cast<ArrayType>(type))
3028  return printConstantArray(cast<ArrayAttr>(attr), arrayType.getElementType(),
3029  isAssignmentLikeContext, op);
3030 
3031  // Unpacked arrays must be printed as pattern.
3032  if (auto arrayType = hw::type_dyn_cast<UnpackedArrayType>(type))
3033  return printConstantArray(cast<ArrayAttr>(attr), arrayType.getElementType(),
3034  true, op);
3035 
3036  // Packed structs can be printed as concatenation or pattern.
3037  if (auto structType = hw::type_dyn_cast<StructType>(type))
3038  return printConstantStruct(structType.getElements(), cast<ArrayAttr>(attr),
3039  isAssignmentLikeContext, op);
3040 
3041  if (auto intType = hw::type_dyn_cast<IntegerType>(type)) {
3042  auto value = cast<IntegerAttr>(attr).getValue();
3043  printConstantScalar(value, intType);
3044  return;
3045  }
3046 
3047  emitOpError(op, "contains constant of type ")
3048  << type << " which cannot be emitted as Verilog";
3049 }
3050 
3051 SubExprInfo ExprEmitter::visitTypeOp(AggregateConstantOp op) {
3052  if (hasSVAttributes(op))
3053  emitError(op, "SV attributes emission is unimplemented for the op");
3054 
3055  // If the constant op as a whole is zero-width, it is an error.
3056  assert(!isZeroBitType(op.getType()) &&
3057  "zero-bit types not allowed at this point");
3058 
3059  printConstantAggregate(op.getFields(), op.getType(), op);
3060  return {Symbol, IsUnsigned};
3061 }
3062 
3063 SubExprInfo ExprEmitter::visitTypeOp(ParamValueOp op) {
3064  if (hasSVAttributes(op))
3065  emitError(op, "SV attributes emission is unimplemented for the op");
3066 
3067  return ps.invokeWithStringOS([&](auto &os) {
3068  return emitter.printParamValue(op.getValue(), os, [&]() {
3069  return op->emitOpError("invalid parameter use");
3070  });
3071  });
3072 }
3073 
3074 // 11.5.1 "Vector bit-select and part-select addressing" allows a '+:' syntax
3075 // for slicing operations.
3076 SubExprInfo ExprEmitter::visitTypeOp(ArraySliceOp op) {
3077  if (hasSVAttributes(op))
3078  emitError(op, "SV attributes emission is unimplemented for the op");
3079 
3080  auto arrayPrec = emitSubExpr(op.getInput(), Selection);
3081 
3082  unsigned dstWidth = type_cast<ArrayType>(op.getType()).getNumElements();
3083  ps << "[";
3084  emitSubExpr(op.getLowIndex(), LowestPrecedence);
3085  ps << " +: ";
3086  ps.addAsString(dstWidth);
3087  ps << "]";
3088  return {Selection, arrayPrec.signedness};
3089 }
3090 
3091 SubExprInfo ExprEmitter::visitTypeOp(ArrayGetOp op) {
3092  emitSubExpr(op.getInput(), Selection);
3093  ps << "[";
3094  if (isZeroBitType(op.getIndex().getType()))
3096  else
3097  emitSubExpr(op.getIndex(), LowestPrecedence);
3098  ps << "]";
3099  emitSVAttributes(op);
3100  return {Selection, IsUnsigned};
3101 }
3102 
3103 // Syntax from: section 5.11 "Array literals".
3104 SubExprInfo ExprEmitter::visitTypeOp(ArrayCreateOp op) {
3105  if (hasSVAttributes(op))
3106  emitError(op, "SV attributes emission is unimplemented for the op");
3107 
3108  if (op.isUniform()) {
3109  ps << "{";
3110  ps.addAsString(op.getInputs().size());
3111  ps << "{";
3112  emitSubExpr(op.getUniformElement(), LowestPrecedence);
3113  ps << "}}";
3114  } else {
3115  emitBracedList(
3116  op.getInputs(), [&]() { ps << "{"; },
3117  [&](Value v) {
3118  ps << "{";
3119  emitSubExprIBox2(v);
3120  ps << "}";
3121  },
3122  [&]() { ps << "}"; });
3123  }
3124  return {Unary, IsUnsigned};
3125 }
3126 
3127 SubExprInfo ExprEmitter::visitSV(UnpackedArrayCreateOp op) {
3128  if (hasSVAttributes(op))
3129  emitError(op, "SV attributes emission is unimplemented for the op");
3130 
3131  emitBracedList(
3132  llvm::reverse(op.getInputs()), [&]() { ps << "'{"; },
3133  [&](Value v) { emitSubExprIBox2(v); }, [&]() { ps << "}"; });
3134  return {Unary, IsUnsigned};
3135 }
3136 
3137 SubExprInfo ExprEmitter::visitTypeOp(ArrayConcatOp op) {
3138  if (hasSVAttributes(op))
3139  emitError(op, "SV attributes emission is unimplemented for the op");
3140 
3141  emitBracedList(op.getOperands());
3142  return {Unary, IsUnsigned};
3143 }
3144 
3145 SubExprInfo ExprEmitter::visitSV(ArrayIndexInOutOp op) {
3146  if (hasSVAttributes(op))
3147  emitError(op, "SV attributes emission is unimplemented for the op");
3148 
3149  auto index = op.getIndex();
3150  auto arrayPrec = emitSubExpr(op.getInput(), Selection);
3151  ps << "[";
3152  if (isZeroBitType(index.getType()))
3154  else
3155  emitSubExpr(index, LowestPrecedence);
3156  ps << "]";
3157  return {Selection, arrayPrec.signedness};
3158 }
3159 
3160 SubExprInfo ExprEmitter::visitSV(IndexedPartSelectInOutOp op) {
3161  if (hasSVAttributes(op))
3162  emitError(op, "SV attributes emission is unimplemented for the op");
3163 
3164  auto prec = emitSubExpr(op.getInput(), Selection);
3165  ps << "[";
3166  emitSubExpr(op.getBase(), LowestPrecedence);
3167  if (op.getDecrement())
3168  ps << " -: ";
3169  else
3170  ps << " +: ";
3171  ps.addAsString(op.getWidth());
3172  ps << "]";
3173  return {Selection, prec.signedness};
3174 }
3175 
3176 SubExprInfo ExprEmitter::visitSV(IndexedPartSelectOp op) {
3177  if (hasSVAttributes(op))
3178  emitError(op, "SV attributes emission is unimplemented for the op");
3179 
3180  auto info = emitSubExpr(op.getInput(), LowestPrecedence);
3181  ps << "[";
3182  emitSubExpr(op.getBase(), LowestPrecedence);
3183  if (op.getDecrement())
3184  ps << " -: ";
3185  else
3186  ps << " +: ";
3187  ps.addAsString(op.getWidth());
3188  ps << "]";
3189  return info;
3190 }
3191 
3192 SubExprInfo ExprEmitter::visitSV(StructFieldInOutOp op) {
3193  if (hasSVAttributes(op))
3194  emitError(op, "SV attributes emission is unimplemented for the op");
3195 
3196  auto prec = emitSubExpr(op.getInput(), Selection);
3197  ps << "."
3198  << PPExtString(emitter.getVerilogStructFieldName(op.getFieldAttr()));
3199  return {Selection, prec.signedness};
3200 }
3201 
3202 SubExprInfo ExprEmitter::visitSV(SampledOp op) {
3203  if (hasSVAttributes(op))
3204  emitError(op, "SV attributes emission is unimplemented for the op");
3205 
3206  ps << "$sampled(";
3207  auto info = emitSubExpr(op.getExpression(), LowestPrecedence);
3208  ps << ")";
3209  return info;
3210 }
3211 
3212 SubExprInfo ExprEmitter::visitComb(MuxOp op) {
3213  // The ?: operator is right associative.
3214 
3215  // Layout:
3216  // cond ? a : b
3217  // (long
3218  // + cond) ? a : b
3219  // long
3220  // + cond
3221  // ? a : b
3222  // long
3223  // + cond
3224  // ? a
3225  // : b
3226  return ps.scopedBox(PP::cbox0, [&]() -> SubExprInfo {
3227  ps.scopedBox(PP::ibox0, [&]() {
3228  emitSubExpr(op.getCond(), VerilogPrecedence(Conditional - 1));
3229  });
3230  ps << BreakToken(1, 2);
3231  ps << "?";
3232  emitSVAttributes(op);
3233  ps << " ";
3234  auto lhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3235  return emitSubExpr(op.getTrueValue(), VerilogPrecedence(Conditional - 1));
3236  });
3237  ps << BreakToken(1, 2) << ": ";
3238 
3239  auto rhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3240  return emitSubExpr(op.getFalseValue(), Conditional);
3241  });
3242 
3243  SubExprSignResult signedness = IsUnsigned;
3244  if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
3245  signedness = IsSigned;
3246 
3247  return {Conditional, signedness};
3248  });
3249 }
3250 
3251 SubExprInfo ExprEmitter::printStructCreate(
3252  ArrayRef<hw::detail::FieldInfo> fieldInfos,
3253  llvm::function_ref<void(const hw::detail::FieldInfo &, unsigned)> fieldFn,
3254  bool printAsPattern, Operation *op) {
3255  if (printAsPattern && !isAssignmentLikeContext)
3256  emitAssignmentPatternContextError(op);
3257 
3258  // Elide zero bit elements.
3259  auto filteredFields = llvm::make_filter_range(
3260  llvm::enumerate(fieldInfos),
3261  [](const auto &field) { return !isZeroBitType(field.value().type); });
3262 
3263  if (printAsPattern) {
3264  emitBracedList(
3265  filteredFields, [&]() { ps << "'{"; },
3266  [&](const auto &field) {
3267  ps.scopedBox(PP::ibox2, [&]() {
3268  ps << PPExtString(
3269  emitter.getVerilogStructFieldName(field.value().name))
3270  << ":" << PP::space;
3271  fieldFn(field.value(), field.index());
3272  });
3273  },
3274  [&]() { ps << "}"; });
3275  } else {
3276  emitBracedList(
3277  filteredFields, [&]() { ps << "{"; },
3278  [&](const auto &field) {
3279  ps.scopedBox(PP::ibox2,
3280  [&]() { fieldFn(field.value(), field.index()); });
3281  },
3282  [&]() { ps << "}"; });
3283  }
3284 
3285  return {Selection, IsUnsigned};
3286 }
3287 
3288 SubExprInfo ExprEmitter::visitTypeOp(StructCreateOp op) {
3289  if (hasSVAttributes(op))
3290  emitError(op, "SV attributes emission is unimplemented for the op");
3291 
3292  // TODO: For unpacked structs, once we have support for them, `printAsPattern`
3293  // should be set to true.
3294  bool printAsPattern = isAssignmentLikeContext;
3295  StructType structType = op.getType();
3296  return printStructCreate(
3297  structType.getElements(),
3298  [&](const auto &field, auto index) {
3299  emitSubExpr(op.getOperand(index), Selection, NoRequirement,
3300  /*isSelfDeterminedUnsignedValue=*/false,
3301  /*isAssignmentLikeContext=*/isAssignmentLikeContext);
3302  },
3303  printAsPattern, op);
3304 }
3305 
3306 SubExprInfo ExprEmitter::visitTypeOp(StructExtractOp op) {
3307  if (hasSVAttributes(op))
3308  emitError(op, "SV attributes emission is unimplemented for the op");
3309 
3310  emitSubExpr(op.getInput(), Selection);
3311  ps << "."
3312  << PPExtString(emitter.getVerilogStructFieldName(op.getFieldNameAttr()));
3313  return {Selection, IsUnsigned};
3314 }
3315 
3316 SubExprInfo ExprEmitter::visitTypeOp(StructInjectOp op) {
3317  if (hasSVAttributes(op))
3318  emitError(op, "SV attributes emission is unimplemented for the op");
3319 
3320  // TODO: For unpacked structs, once we have support for them, `printAsPattern`
3321  // should be set to true.
3322  bool printAsPattern = isAssignmentLikeContext;
3323  StructType structType = op.getType();
3324  return printStructCreate(
3325  structType.getElements(),
3326  [&](const auto &field, auto index) {
3327  if (field.name == op.getFieldNameAttr()) {
3328  emitSubExpr(op.getNewValue(), Selection);
3329  } else {
3330  emitSubExpr(op.getInput(), Selection);
3331  ps << "."
3332  << PPExtString(emitter.getVerilogStructFieldName(field.name));
3333  }
3334  },
3335  printAsPattern, op);
3336 }
3337 
3338 SubExprInfo ExprEmitter::visitTypeOp(EnumConstantOp op) {
3339  ps << PPSaveString(emitter.fieldNameResolver.getEnumFieldName(op.getField()));
3340  return {Selection, IsUnsigned};
3341 }
3342 
3343 SubExprInfo ExprEmitter::visitTypeOp(EnumCmpOp op) {
3344  if (hasSVAttributes(op))
3345  emitError(op, "SV attributes emission is unimplemented for the op");
3346  auto result = emitBinary(op, Comparison, "==", NoRequirement);
3347  // SystemVerilog 11.8.1: "Comparison... operator results are unsigned,
3348  // regardless of the operands".
3349  result.signedness = IsUnsigned;
3350  return result;
3351 }
3352 
3353 SubExprInfo ExprEmitter::visitTypeOp(UnionCreateOp op) {
3354  if (hasSVAttributes(op))
3355  emitError(op, "SV attributes emission is unimplemented for the op");
3356 
3357  // Check if this union type has been padded.
3358  auto unionType = cast<UnionType>(getCanonicalType(op.getType()));
3359  auto unionWidth = hw::getBitWidth(unionType);
3360  auto &element = unionType.getElements()[op.getFieldIndex()];
3361  auto elementWidth = hw::getBitWidth(element.type);
3362 
3363  // If the element is 0 width, just fill the union with 0s.
3364  if (!elementWidth) {
3365  ps.addAsString(unionWidth);
3366  ps << "'h0";
3367  return {Unary, IsUnsigned};
3368  }
3369 
3370  // If the element has no padding, emit it directly.
3371  if (elementWidth == unionWidth) {
3372  emitSubExpr(op.getInput(), LowestPrecedence);
3373  return {Unary, IsUnsigned};
3374  }
3375 
3376  // Emit the value as a bitconcat, supplying 0 for the padding bits.
3377  ps << "{";
3378  ps.scopedBox(PP::ibox0, [&]() {
3379  if (auto prePadding = element.offset) {
3380  ps.addAsString(prePadding);
3381  ps << "'h0," << PP::space;
3382  }
3383  emitSubExpr(op.getInput(), Selection);
3384  if (auto postPadding = unionWidth - elementWidth - element.offset) {
3385  ps << "," << PP::space;
3386  ps.addAsString(postPadding);
3387  ps << "'h0";
3388  }
3389  ps << "}";
3390  });
3391 
3392  return {Unary, IsUnsigned};
3393 }
3394 
3395 SubExprInfo ExprEmitter::visitTypeOp(UnionExtractOp op) {
3396  if (hasSVAttributes(op))
3397  emitError(op, "SV attributes emission is unimplemented for the op");
3398  emitSubExpr(op.getInput(), Selection);
3399 
3400  // Check if this union type has been padded.
3401  auto unionType = cast<UnionType>(getCanonicalType(op.getInput().getType()));
3402  auto unionWidth = hw::getBitWidth(unionType);
3403  auto &element = unionType.getElements()[op.getFieldIndex()];
3404  auto elementWidth = hw::getBitWidth(element.type);
3405  bool needsPadding = elementWidth < unionWidth || element.offset > 0;
3406  auto verilogFieldName = emitter.getVerilogStructFieldName(element.name);
3407 
3408  // If the element needs padding then we need to get the actual element out
3409  // of an anonymous structure.
3410  if (needsPadding)
3411  ps << "." << PPExtString(verilogFieldName);
3412 
3413  // Get the correct member from the union.
3414  ps << "." << PPExtString(verilogFieldName);
3415  return {Selection, IsUnsigned};
3416 }
3417 
3418 SubExprInfo ExprEmitter::visitUnhandledExpr(Operation *op) {
3419  emitOpError(op, "cannot emit this expression to Verilog");
3420  ps << "<<unsupported expr: " << PPExtString(op->getName().getStringRef())
3421  << ">>";
3422  return {Symbol, IsUnsigned};
3423 }
3424 // NOLINTEND(misc-no-recursion)
3425 
3426 //===----------------------------------------------------------------------===//
3427 // Property Emission
3428 //===----------------------------------------------------------------------===//
3429 
3430 // NOLINTBEGIN(misc-no-recursion)
3431 
3432 namespace {
3433 /// Precedence level of various property and sequence expressions. Lower numbers
3434 /// bind tighter.
3435 ///
3436 /// See IEEE 1800-2017 section 16.12 "Declaring properties", specifically table
3437 /// 16-3 on "Sequence and property operator precedence and associativity".
3438 enum class PropertyPrecedence {
3439  Symbol, // Atomic symbol like `foo` and regular boolean expressions
3440  Repeat, // Sequence `[*]`, `[=]`, `[->]`
3441  Concat, // Sequence `##`
3442  Throughout, // Sequence `throughout`
3443  Within, // Sequence `within`
3444  Intersect, // Sequence `intersect`
3445  Unary, // Property `not`, `nexttime`-like
3446  And, // Sequence and property `and`
3447  Or, // Sequence and property `or`
3448  Iff, // Property `iff`
3449  Until, // Property `until`-like, `implies`
3450  Implication, // Property `|->`, `|=>`, `#-#`, `#=#`
3451  Qualifier, // Property `always`-like, `eventually`-like, `if`, `case`,
3452  // `accept`-like, `reject`-like
3453  Clocking, // `@(...)`, `disable iff` (not specified in the standard)
3454  Lowest, // Sentinel which is always the lowest precedence.
3455 };
3456 
3457 /// Additional information on emitted property and sequence expressions.
3458 struct EmittedProperty {
3459  /// The precedence of this expression.
3460  PropertyPrecedence precedence;
3461 };
3462 
3463 /// A helper to emit recursively nested property and sequence expressions for
3464 /// SystemVerilog assertions.
3465 class PropertyEmitter : public EmitterBase,
3466  public ltl::Visitor<PropertyEmitter, EmittedProperty> {
3467 public:
3468  /// Create a PropertyEmitter for the specified module emitter, and keeping
3469  /// track of any emitted expressions in the specified set.
3470  PropertyEmitter(ModuleEmitter &emitter,
3471  SmallPtrSetImpl<Operation *> &emittedOps)
3472  : PropertyEmitter(emitter, emittedOps, localTokens) {}
3473  PropertyEmitter(ModuleEmitter &emitter,
3474  SmallPtrSetImpl<Operation *> &emittedOps,
3475  BufferingPP::BufferVec &tokens)
3476  : EmitterBase(emitter.state), emitter(emitter), emittedOps(emittedOps),
3477  buffer(tokens),
3478  ps(buffer, state.saver, state.options.emitVerilogLocations) {
3479  assert(state.pp.getListener() == &state.saver);
3480  }
3481 
3482  void emitAssertPropertyDisable(
3483  Value property, Value disable,
3484  PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3485 
3486  void emitAssertPropertyBody(
3487  Value property, Value disable,
3488  PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3489 
3490  void emitAssertPropertyBody(
3491  Value property, sv::EventControl event, Value clock, Value disable,
3492  PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3493 
3494 private:
3495  /// Emit the specified value as an SVA property or sequence.
3496  EmittedProperty
3497  emitNestedProperty(Value property,
3498  PropertyPrecedence parenthesizeIfLooserThan);
3499  using ltl::Visitor<PropertyEmitter, EmittedProperty>::visitLTL;
3500  friend class ltl::Visitor<PropertyEmitter, EmittedProperty>;
3501 
3502  EmittedProperty visitUnhandledLTL(Operation *op);
3503  EmittedProperty visitLTL(ltl::AndOp op);
3504  EmittedProperty visitLTL(ltl::OrOp op);
3505  EmittedProperty visitLTL(ltl::IntersectOp op);
3506  EmittedProperty visitLTL(ltl::DelayOp op);
3507  EmittedProperty visitLTL(ltl::ConcatOp op);
3508  EmittedProperty visitLTL(ltl::RepeatOp op);
3509  EmittedProperty visitLTL(ltl::GoToRepeatOp op);
3510  EmittedProperty visitLTL(ltl::NonConsecutiveRepeatOp op);
3511  EmittedProperty visitLTL(ltl::NotOp op);
3512  EmittedProperty visitLTL(ltl::ImplicationOp op);
3513  EmittedProperty visitLTL(ltl::UntilOp op);
3514  EmittedProperty visitLTL(ltl::EventuallyOp op);
3515  EmittedProperty visitLTL(ltl::ClockOp op);
3516 
3517  void emitLTLConcat(ValueRange inputs);
3518 
3519 public:
3520  ModuleEmitter &emitter;
3521 
3522 private:
3523  /// Keep track of all operations emitted within this subexpression for
3524  /// location information tracking.
3525  SmallPtrSetImpl<Operation *> &emittedOps;
3526 
3527  /// Tokens buffered for inserting casts/parens after emitting children.
3528  SmallVector<Token> localTokens;
3529 
3530  /// Stores tokens until told to flush. Uses provided buffer (tokens).
3531  BufferingPP buffer;
3532 
3533  /// Stream to emit expressions into, will add to buffer.
3535 };
3536 } // end anonymous namespace
3537 
3538 // Emits a disable signal and its containing property.
3539 // This function can be called from withing another emission process in which
3540 // case we don't need to check that the local tokens are empty.
3541 void PropertyEmitter::emitAssertPropertyDisable(
3542  Value property, Value disable,
3543  PropertyPrecedence parenthesizeIfLooserThan) {
3544  // If the property is tied to a disable, emit that.
3545  if (disable) {
3546  ps << "disable iff" << PP::nbsp << "(";
3547  ps.scopedBox(PP::ibox2, [&] {
3548  emitNestedProperty(disable, PropertyPrecedence::Unary);
3549  ps << ")";
3550  });
3551  ps << PP::space;
3552  }
3553 
3554  ps.scopedBox(PP::ibox0,
3555  [&] { emitNestedProperty(property, parenthesizeIfLooserThan); });
3556 }
3557 
3558 // Emits a disable signal and its containing property.
3559 // This function can be called from withing another emission process in which
3560 // case we don't need to check that the local tokens are empty.
3561 void PropertyEmitter::emitAssertPropertyBody(
3562  Value property, Value disable,
3563  PropertyPrecedence parenthesizeIfLooserThan) {
3564  assert(localTokens.empty());
3565 
3566  emitAssertPropertyDisable(property, disable, parenthesizeIfLooserThan);
3567 
3568  // If we are not using an external token buffer provided through the
3569  // constructor, but we're using the default `PropertyEmitter`-scoped buffer,
3570  // flush it.
3571  if (&buffer.tokens == &localTokens)
3572  buffer.flush(state.pp);
3573 }
3574 
3575 void PropertyEmitter::emitAssertPropertyBody(
3576  Value property, sv::EventControl event, Value clock, Value disable,
3577  PropertyPrecedence parenthesizeIfLooserThan) {
3578  assert(localTokens.empty());
3579  // Wrap to this column.
3580  ps << "@(";
3581  ps.scopedBox(PP::ibox2, [&] {
3582  ps << PPExtString(stringifyEventControl(event)) << PP::space;
3583  emitNestedProperty(clock, PropertyPrecedence::Lowest);
3584  ps << ")";
3585  });
3586  ps << PP::space;
3587 
3588  // Emit the rest of the body
3589  emitAssertPropertyDisable(property, disable, parenthesizeIfLooserThan);
3590 
3591  // If we are not using an external token buffer provided through the
3592  // constructor, but we're using the default `PropertyEmitter`-scoped buffer,
3593  // flush it.
3594  if (&buffer.tokens == &localTokens)
3595  buffer.flush(state.pp);
3596 }
3597 
3598 EmittedProperty PropertyEmitter::emitNestedProperty(
3599  Value property, PropertyPrecedence parenthesizeIfLooserThan) {
3600  // Emit the property as a plain expression if it doesn't have a property or
3601  // sequence type, in which case it is just a boolean expression.
3602  //
3603  // We use the `LowestPrecedence` for the boolean expression such that it never
3604  // gets parenthesized. According to IEEE 1800-2017, "the operators described
3605  // in Table 11-2 have higher precedence than the sequence and property
3606  // operators". Therefore any boolean expression behaves just like a
3607  // `PropertyPrecedence::Symbol` and needs no parantheses, which is equivalent
3608  // to `VerilogPrecedence::LowestPrecedence`.
3609  if (!isa<ltl::SequenceType, ltl::PropertyType>(property.getType())) {
3610  ExprEmitter(emitter, emittedOps, buffer.tokens)
3611  .emitExpression(property, LowestPrecedence,
3612  /*isAssignmentLikeContext=*/false);
3613  return {PropertyPrecedence::Symbol};
3614  }
3615 
3616  unsigned startIndex = buffer.tokens.size();
3617  auto info = dispatchLTLVisitor(property.getDefiningOp());
3618 
3619  // If this subexpression would bind looser than the expression it is bound
3620  // into, then we need to parenthesize it. Insert the parentheses
3621  // retroactively.
3622  if (info.precedence > parenthesizeIfLooserThan) {
3623  // Insert {"(", ibox0} before the subexpression.
3624  buffer.tokens.insert(buffer.tokens.begin() + startIndex, BeginToken(0));
3625  buffer.tokens.insert(buffer.tokens.begin() + startIndex, StringToken("("));
3626  // Insert {end, ")" } after the subexpression.
3627  ps << PP::end << ")";
3628  // Reset the precedence level.
3629  info.precedence = PropertyPrecedence::Symbol;
3630  }
3631 
3632  // Remember that we emitted this.
3633  emittedOps.insert(property.getDefiningOp());
3634  return info;
3635 }
3636 
3637 EmittedProperty PropertyEmitter::visitUnhandledLTL(Operation *op) {
3638  emitOpError(op, "emission as Verilog property or sequence not supported");
3639  ps << "<<unsupported: " << PPExtString(op->getName().getStringRef()) << ">>";
3640  return {PropertyPrecedence::Symbol};
3641 }
3642 
3643 EmittedProperty PropertyEmitter::visitLTL(ltl::AndOp op) {
3644  llvm::interleave(
3645  op.getInputs(),
3646  [&](auto input) { emitNestedProperty(input, PropertyPrecedence::And); },
3647  [&]() { ps << PP::space << "and" << PP::nbsp; });
3648  return {PropertyPrecedence::And};
3649 }
3650 
3651 EmittedProperty PropertyEmitter::visitLTL(ltl::OrOp op) {
3652  llvm::interleave(
3653  op.getInputs(),
3654  [&](auto input) { emitNestedProperty(input, PropertyPrecedence::Or); },
3655  [&]() { ps << PP::space << "or" << PP::nbsp; });
3656  return {PropertyPrecedence::Or};
3657 }
3658 
3659 EmittedProperty PropertyEmitter::visitLTL(ltl::IntersectOp op) {
3660  llvm::interleave(
3661  op.getInputs(),
3662  [&](auto input) {
3663  emitNestedProperty(input, PropertyPrecedence::Intersect);
3664  },
3665  [&]() { ps << PP::space << "intersect" << PP::nbsp; });
3666  return {PropertyPrecedence::Intersect};
3667 }
3668 
3669 EmittedProperty PropertyEmitter::visitLTL(ltl::DelayOp op) {
3670  ps << "##";
3671  if (auto length = op.getLength()) {
3672  if (*length == 0) {
3673  ps.addAsString(op.getDelay());
3674  } else {
3675  ps << "[";
3676  ps.addAsString(op.getDelay());
3677  ps << ":";
3678  ps.addAsString(op.getDelay() + *length);
3679  ps << "]";
3680  }
3681  } else {
3682  if (op.getDelay() == 0) {
3683  ps << "[*]";
3684  } else if (op.getDelay() == 1) {
3685  ps << "[+]";
3686  } else {
3687  ps << "[";
3688  ps.addAsString(op.getDelay());
3689  ps << ":$]";
3690  }
3691  }
3692  ps << PP::space;
3693  emitNestedProperty(op.getInput(), PropertyPrecedence::Concat);
3694  return {PropertyPrecedence::Concat};
3695 }
3696 
3697 void PropertyEmitter::emitLTLConcat(ValueRange inputs) {
3698  bool addSeparator = false;
3699  for (auto input : inputs) {
3700  if (addSeparator) {
3701  ps << PP::space;
3702  if (!input.getDefiningOp<ltl::DelayOp>())
3703  ps << "##0" << PP::space;
3704  }
3705  addSeparator = true;
3706  emitNestedProperty(input, PropertyPrecedence::Concat);
3707  }
3708 }
3709 
3710 EmittedProperty PropertyEmitter::visitLTL(ltl::ConcatOp op) {
3711  emitLTLConcat(op.getInputs());
3712  return {PropertyPrecedence::Concat};
3713 }
3714 
3715 EmittedProperty PropertyEmitter::visitLTL(ltl::RepeatOp op) {
3716  emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3717  if (auto more = op.getMore()) {
3718  ps << "[*";
3719  ps.addAsString(op.getBase());
3720  if (*more != 0) {
3721  ps << ":";
3722  ps.addAsString(op.getBase() + *more);
3723  }
3724  ps << "]";
3725  } else {
3726  if (op.getBase() == 0) {
3727  ps << "[*]";
3728  } else if (op.getBase() == 1) {
3729  ps << "[+]";
3730  } else {
3731  ps << "[*";
3732  ps.addAsString(op.getBase());
3733  ps << ":$]";
3734  }
3735  }
3736  return {PropertyPrecedence::Repeat};
3737 }
3738 
3739 EmittedProperty PropertyEmitter::visitLTL(ltl::GoToRepeatOp op) {
3740  emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3741  // More always exists
3742  auto more = op.getMore();
3743  ps << "[->";
3744  ps.addAsString(op.getBase());
3745  if (more != 0) {
3746  ps << ":";
3747  ps.addAsString(op.getBase() + more);
3748  }
3749  ps << "]";
3750 
3751  return {PropertyPrecedence::Repeat};
3752 }
3753 
3754 EmittedProperty PropertyEmitter::visitLTL(ltl::NonConsecutiveRepeatOp op) {
3755  emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3756  // More always exists
3757  auto more = op.getMore();
3758  ps << "[=";
3759  ps.addAsString(op.getBase());
3760  if (more != 0) {
3761  ps << ":";
3762  ps.addAsString(op.getBase() + more);
3763  }
3764  ps << "]";
3765 
3766  return {PropertyPrecedence::Repeat};
3767 }
3768 
3769 EmittedProperty PropertyEmitter::visitLTL(ltl::NotOp op) {
3770  ps << "not" << PP::space;
3771  emitNestedProperty(op.getInput(), PropertyPrecedence::Unary);
3772  return {PropertyPrecedence::Unary};
3773 }
3774 
3775 /// For a value `concat(..., delay(const(true), 1, 0))`, return `...`. This is
3776 /// useful for emitting `(seq ##1 true) |-> prop` as `seq |=> prop`.
3777 static ValueRange getNonOverlappingConcatSubrange(Value value) {
3778  auto concatOp = value.getDefiningOp<ltl::ConcatOp>();
3779  if (!concatOp || concatOp.getInputs().size() < 2)
3780  return {};
3781  auto delayOp = concatOp.getInputs().back().getDefiningOp<ltl::DelayOp>();
3782  if (!delayOp || delayOp.getDelay() != 1 || delayOp.getLength() != 0)
3783  return {};
3784  auto constOp = delayOp.getInput().getDefiningOp<ConstantOp>();
3785  if (!constOp || !constOp.getValue().isOne())
3786  return {};
3787  return concatOp.getInputs().drop_back();
3788 }
3789 
3790 EmittedProperty PropertyEmitter::visitLTL(ltl::ImplicationOp op) {
3791  // Emit `(seq ##1 true) |-> prop` as `seq |=> prop`.
3792  if (auto range = getNonOverlappingConcatSubrange(op.getAntecedent());
3793  !range.empty()) {
3794  emitLTLConcat(range);
3795  ps << PP::space << "|=>" << PP::nbsp;
3796  } else {
3797  emitNestedProperty(op.getAntecedent(), PropertyPrecedence::Implication);
3798  ps << PP::space << "|->" << PP::nbsp;
3799  }
3800  emitNestedProperty(op.getConsequent(), PropertyPrecedence::Implication);
3801  return {PropertyPrecedence::Implication};
3802 }
3803 
3804 EmittedProperty PropertyEmitter::visitLTL(ltl::UntilOp op) {
3805  emitNestedProperty(op.getInput(), PropertyPrecedence::Until);
3806  ps << PP::space << "until" << PP::space;
3807  emitNestedProperty(op.getCondition(), PropertyPrecedence::Until);
3808  return {PropertyPrecedence::Until};
3809 }
3810 
3811 EmittedProperty PropertyEmitter::visitLTL(ltl::EventuallyOp op) {
3812  ps << "s_eventually" << PP::space;
3813  emitNestedProperty(op.getInput(), PropertyPrecedence::Qualifier);
3814  return {PropertyPrecedence::Qualifier};
3815 }
3816 
3817 EmittedProperty PropertyEmitter::visitLTL(ltl::ClockOp op) {
3818  ps << "@(";
3819  ps.scopedBox(PP::ibox2, [&] {
3820  ps << PPExtString(stringifyClockEdge(op.getEdge())) << PP::space;
3821  emitNestedProperty(op.getClock(), PropertyPrecedence::Lowest);
3822  ps << ")";
3823  });
3824  ps << PP::space;
3825  emitNestedProperty(op.getInput(), PropertyPrecedence::Clocking);
3826  return {PropertyPrecedence::Clocking};
3827 }
3828 
3829 // NOLINTEND(misc-no-recursion)
3830 
3831 //===----------------------------------------------------------------------===//
3832 // NameCollector
3833 //===----------------------------------------------------------------------===//
3834 
3835 namespace {
3836 class NameCollector {
3837 public:
3838  NameCollector(ModuleEmitter &moduleEmitter) : moduleEmitter(moduleEmitter) {}
3839 
3840  // Scan operations in the specified block, collecting information about
3841  // those that need to be emitted as declarations.
3842  void collectNames(Block &block);
3843 
3844  size_t getMaxDeclNameWidth() const { return maxDeclNameWidth; }
3845  size_t getMaxTypeWidth() const { return maxTypeWidth; }
3846 
3847 private:
3848  size_t maxDeclNameWidth = 0, maxTypeWidth = 0;
3849  ModuleEmitter &moduleEmitter;
3850 
3851  /// Types that are longer than `maxTypeWidthBound` are not added to the
3852  /// `maxTypeWidth` to prevent one single huge type from messing up the
3853  /// alignment of all other declarations.
3854  static constexpr size_t maxTypeWidthBound = 32;
3855 };
3856 } // namespace
3857 
3858 // NOLINTNEXTLINE(misc-no-recursion)
3859 void NameCollector::collectNames(Block &block) {
3860  // Loop over all of the results of all of the ops. Anything that defines a
3861  // value needs to be noticed.
3862  for (auto &op : block) {
3863  // Instances have an instance name to recognize but we don't need to look
3864  // at the result values since wires used by instances should be traversed
3865  // anyway.
3866  if (isa<InstanceOp, InstanceChoiceOp, InterfaceInstanceOp,
3867  FuncCallProceduralOp, FuncCallOp>(op))
3868  continue;
3869  if (isa<ltl::LTLDialect, debug::DebugDialect>(op.getDialect()))
3870  continue;
3871 
3872  if (!isVerilogExpression(&op)) {
3873  for (auto result : op.getResults()) {
3874  StringRef declName = getVerilogDeclWord(&op, moduleEmitter);
3875  maxDeclNameWidth = std::max(declName.size(), maxDeclNameWidth);
3876  SmallString<16> typeString;
3877 
3878  // Convert the port's type to a string and measure it.
3879  {
3880  llvm::raw_svector_ostream stringStream(typeString);
3881  moduleEmitter.printPackedType(stripUnpackedTypes(result.getType()),
3882  stringStream, op.getLoc());
3883  }
3884  if (typeString.size() <= maxTypeWidthBound)
3885  maxTypeWidth = std::max(typeString.size(), maxTypeWidth);
3886  }
3887  }
3888 
3889  // Recursively process any regions under the op iff this is a procedural
3890  // #ifdef region: we need to emit automatic logic values at the top of the
3891  // enclosing region.
3892  if (isa<IfDefProceduralOp, OrderedOutputOp>(op)) {
3893  for (auto &region : op.getRegions()) {
3894  if (!region.empty())
3895  collectNames(region.front());
3896  }
3897  continue;
3898  }
3899  }
3900 }
3901 
3902 //===----------------------------------------------------------------------===//
3903 // StmtEmitter
3904 //===----------------------------------------------------------------------===//
3905 
3906 namespace {
3907 /// This emits statement-related operations.
3908 // NOLINTBEGIN(misc-no-recursion)
3909 class StmtEmitter : public EmitterBase,
3910  public hw::StmtVisitor<StmtEmitter, LogicalResult>,
3911  public sv::Visitor<StmtEmitter, LogicalResult>,
3912  public verif::Visitor<StmtEmitter, LogicalResult> {
3913 public:
3914  /// Create an ExprEmitter for the specified module emitter, and keeping track
3915  /// of any emitted expressions in the specified set.
3916  StmtEmitter(ModuleEmitter &emitter, const LoweringOptions &options)
3917  : EmitterBase(emitter.state), emitter(emitter), options(options) {}
3918 
3919  void emitStatement(Operation *op);
3920  void emitStatementBlock(Block &body);
3921 
3922  /// Emit a declaration.
3923  LogicalResult emitDeclaration(Operation *op);
3924 
3925 private:
3926  void collectNamesAndCalculateDeclarationWidths(Block &block);
3927 
3928  void
3929  emitExpression(Value exp, SmallPtrSetImpl<Operation *> &emittedExprs,
3930  VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence,
3931  bool isAssignmentLikeContext = false);
3932  void emitSVAttributes(Operation *op);
3933 
3934  using hw::StmtVisitor<StmtEmitter, LogicalResult>::visitStmt;
3935  using sv::Visitor<StmtEmitter, LogicalResult>::visitSV;
3936  using verif::Visitor<StmtEmitter, LogicalResult>::visitVerif;
3937  friend class hw::StmtVisitor<StmtEmitter, LogicalResult>;
3938  friend class sv::Visitor<StmtEmitter, LogicalResult>;
3939  friend class verif::Visitor<StmtEmitter, LogicalResult>;
3940 
3941  // Visitor methods.
3942  LogicalResult visitUnhandledStmt(Operation *op) { return failure(); }
3943  LogicalResult visitInvalidStmt(Operation *op) { return failure(); }
3944  LogicalResult visitUnhandledSV(Operation *op) { return failure(); }
3945  LogicalResult visitInvalidSV(Operation *op) { return failure(); }
3946  LogicalResult visitUnhandledVerif(Operation *op) { return failure(); }
3947  LogicalResult visitInvalidVerif(Operation *op) { return failure(); }
3948 
3949  LogicalResult visitSV(sv::WireOp op) { return emitDeclaration(op); }
3950  LogicalResult visitSV(RegOp op) { return emitDeclaration(op); }
3951  LogicalResult visitSV(LogicOp op) { return emitDeclaration(op); }
3952  LogicalResult visitSV(LocalParamOp op) { return emitDeclaration(op); }
3953  template <typename Op>
3954  LogicalResult
3955  emitAssignLike(Op op, PPExtString syntax,
3956  std::optional<PPExtString> wordBeforeLHS = std::nullopt);
3957  void emitAssignLike(llvm::function_ref<void()> emitLHS,
3958  llvm::function_ref<void()> emitRHS, PPExtString syntax,
3959  PPExtString postSyntax = PPExtString(";"),
3960  std::optional<PPExtString> wordBeforeLHS = std::nullopt);
3961  LogicalResult visitSV(AssignOp op);
3962  LogicalResult visitSV(BPAssignOp op);
3963  LogicalResult visitSV(PAssignOp op);
3964  LogicalResult visitSV(ForceOp op);
3965  LogicalResult visitSV(ReleaseOp op);
3966  LogicalResult visitSV(AliasOp op);
3967  LogicalResult visitSV(InterfaceInstanceOp op);
3968  LogicalResult emitOutputLikeOp(Operation *op, const ModulePortInfo &ports);
3969  LogicalResult visitStmt(OutputOp op);
3970 
3971  LogicalResult visitStmt(InstanceOp op);
3972  LogicalResult visitStmt(InstanceChoiceOp op);
3973  void emitInstancePortList(Operation *op, ModulePortInfo &modPortInfo,
3974  ArrayRef<Value> instPortValues);
3975 
3976  LogicalResult visitStmt(TypeScopeOp op);
3977  LogicalResult visitStmt(TypedeclOp op);
3978 
3979  LogicalResult emitIfDef(Operation *op, MacroIdentAttr cond);
3980  LogicalResult visitSV(OrderedOutputOp op);
3981  LogicalResult visitSV(IfDefOp op) { return emitIfDef(op, op.getCond()); }
3982  LogicalResult visitSV(IfDefProceduralOp op) {
3983  return emitIfDef(op, op.getCond());
3984  }
3985  LogicalResult visitSV(IfOp op);
3986  LogicalResult visitSV(AlwaysOp op);
3987  LogicalResult visitSV(AlwaysCombOp op);
3988  LogicalResult visitSV(AlwaysFFOp op);
3989  LogicalResult visitSV(InitialOp op);
3990  LogicalResult visitSV(CaseOp op);
3991  LogicalResult visitSV(FWriteOp op);
3992  LogicalResult visitSV(VerbatimOp op);
3993  LogicalResult visitSV(MacroRefOp op);
3994 
3995  LogicalResult emitSimulationControlTask(Operation *op, PPExtString taskName,
3996  std::optional<unsigned> verbosity);
3997  LogicalResult visitSV(StopOp op);
3998  LogicalResult visitSV(FinishOp op);
3999  LogicalResult visitSV(ExitOp op);
4000 
4001  LogicalResult emitSeverityMessageTask(Operation *op, PPExtString taskName,
4002  std::optional<unsigned> verbosity,
4003  StringAttr message,
4004  ValueRange operands);
4005  LogicalResult visitSV(FatalOp op);
4006  LogicalResult visitSV(ErrorOp op);
4007  LogicalResult visitSV(WarningOp op);
4008  LogicalResult visitSV(InfoOp op);
4009 
4010  LogicalResult visitSV(ReadMemOp op);
4011 
4012  LogicalResult visitSV(GenerateOp op);
4013  LogicalResult visitSV(GenerateCaseOp op);
4014 
4015  LogicalResult visitSV(ForOp op);
4016 
4017  void emitAssertionLabel(Operation *op);
4018  void emitAssertionMessage(StringAttr message, ValueRange args,
4019  SmallPtrSetImpl<Operation *> &ops,
4020  bool isConcurrent);
4021  template <typename Op>
4022  LogicalResult emitImmediateAssertion(Op op, PPExtString opName);
4023  LogicalResult visitSV(AssertOp op);
4024  LogicalResult visitSV(AssumeOp op);
4025  LogicalResult visitSV(CoverOp op);
4026  template <typename Op>
4027  LogicalResult emitConcurrentAssertion(Op op, PPExtString opName);
4028  LogicalResult visitSV(AssertConcurrentOp op);
4029  LogicalResult visitSV(AssumeConcurrentOp op);
4030  LogicalResult visitSV(CoverConcurrentOp op);
4031  template <typename Op>
4032  LogicalResult emitPropertyAssertion(Op op, PPExtString opName);
4033  LogicalResult visitSV(AssertPropertyOp op);
4034  LogicalResult visitSV(AssumePropertyOp op);
4035  LogicalResult visitSV(CoverPropertyOp op);
4036 
4037  LogicalResult visitSV(BindOp op);
4038  LogicalResult visitSV(InterfaceOp op);
4039  LogicalResult visitSV(InterfaceSignalOp op);
4040  LogicalResult visitSV(InterfaceModportOp op);
4041  LogicalResult visitSV(AssignInterfaceSignalOp op);
4042  LogicalResult visitSV(MacroDefOp op);
4043 
4044  void emitBlockAsStatement(Block *block,
4045  const SmallPtrSetImpl<Operation *> &locationOps,
4046  StringRef multiLineComment = StringRef());
4047 
4048  LogicalResult visitSV(FuncDPIImportOp op);
4049  template <typename CallOp>
4050  LogicalResult emitFunctionCall(CallOp callOp);
4051  LogicalResult visitSV(FuncCallProceduralOp op);
4052  LogicalResult visitSV(FuncCallOp op);
4053  LogicalResult visitSV(ReturnOp op);
4054 
4055 public:
4056  ModuleEmitter &emitter;
4057 
4058 private:
4059  /// These keep track of the maximum length of name width and type width in the
4060  /// current statement scope.
4061  size_t maxDeclNameWidth = 0;
4062  size_t maxTypeWidth = 0;
4063 
4064  const LoweringOptions &options;
4065 };
4066 
4067 } // end anonymous namespace
4068 
4069 /// Emit the specified value as an expression. If this is an inline-emitted
4070 /// expression, we emit that expression, otherwise we emit a reference to the
4071 /// already computed name.
4072 ///
4073 void StmtEmitter::emitExpression(Value exp,
4074  SmallPtrSetImpl<Operation *> &emittedExprs,
4075  VerilogPrecedence parenthesizeIfLooserThan,
4076  bool isAssignmentLikeContext) {
4077  ExprEmitter(emitter, emittedExprs)
4078  .emitExpression(exp, parenthesizeIfLooserThan, isAssignmentLikeContext);
4079 }
4080 
4081 /// Emit SystemVerilog attributes attached to the statement op as dialect
4082 /// attributes.
4083 void StmtEmitter::emitSVAttributes(Operation *op) {
4084  // SystemVerilog 2017 Section 5.12.
4085  auto svAttrs = getSVAttributes(op);
4086  if (!svAttrs)
4087  return;
4088 
4089  startStatement(); // For attributes.
4090  emitSVAttributesImpl(ps, svAttrs, /*mayBreak=*/true);
4091  setPendingNewline();
4092 }
4093 
4094 void StmtEmitter::emitAssignLike(llvm::function_ref<void()> emitLHS,
4095  llvm::function_ref<void()> emitRHS,
4096  PPExtString syntax, PPExtString postSyntax,
4097  std::optional<PPExtString> wordBeforeLHS) {
4098  // If wraps, indent.
4099  ps.scopedBox(PP::ibox2, [&]() {
4100  if (wordBeforeLHS) {
4101  ps << *wordBeforeLHS << PP::space;
4102  }
4103  emitLHS();
4104  // Allow breaking before 'syntax' (e.g., '=') if long assignment.
4105  ps << PP::space << syntax << PP::space;
4106  // RHS is boxed to right of the syntax.
4107  ps.scopedBox(PP::ibox0, [&]() {
4108  emitRHS();
4109  ps << postSyntax;
4110  });
4111  });
4112 }
4113 
4114 template <typename Op>
4115 LogicalResult
4116 StmtEmitter::emitAssignLike(Op op, PPExtString syntax,
4117  std::optional<PPExtString> wordBeforeLHS) {
4118  SmallPtrSet<Operation *, 8> ops;
4119  ops.insert(op);
4120 
4121  startStatement();
4122  ps.addCallback({op, true});
4123  emitAssignLike([&]() { emitExpression(op.getDest(), ops); },
4124  [&]() {
4125  emitExpression(op.getSrc(), ops, LowestPrecedence,
4126  /*isAssignmentLikeContext=*/true);
4127  },
4128  syntax, PPExtString(";"), wordBeforeLHS);
4129 
4130  ps.addCallback({op, false});
4131  emitLocationInfoAndNewLine(ops);
4132  return success();
4133 }
4134 
4135 LogicalResult StmtEmitter::visitSV(AssignOp op) {
4136  // prepare assigns wires to instance outputs and function results, but these
4137  // are logically handled in the port binding list when outputing an instance.
4138  if (isa_and_nonnull<HWInstanceLike, FuncCallOp>(op.getSrc().getDefiningOp()))
4139  return success();
4140 
4141  if (emitter.assignsInlined.count(op))
4142  return success();
4143 
4144  // Emit SV attributes. See Spec 12.3.
4145  emitSVAttributes(op);
4146 
4147  return emitAssignLike(op, PPExtString("="), PPExtString("assign"));
4148 }
4149 
4150 LogicalResult StmtEmitter::visitSV(BPAssignOp op) {
4151  if (op.getSrc().getDefiningOp<FuncCallProceduralOp>())
4152  return success();
4153 
4154  // If the assign is emitted into logic declaration, we must not emit again.
4155  if (emitter.assignsInlined.count(op))
4156  return success();
4157 
4158  // Emit SV attributes. See Spec 12.3.
4159  emitSVAttributes(op);
4160 
4161  return emitAssignLike(op, PPExtString("="));
4162 }
4163 
4164 LogicalResult StmtEmitter::visitSV(PAssignOp op) {
4165  // Emit SV attributes. See Spec 12.3.
4166  emitSVAttributes(op);
4167 
4168  return emitAssignLike(op, PPExtString("<="));
4169 }
4170 
4171 LogicalResult StmtEmitter::visitSV(ForceOp op) {
4172  if (hasSVAttributes(op))
4173  emitError(op, "SV attributes emission is unimplemented for the op");
4174 
4175  return emitAssignLike(op, PPExtString("="), PPExtString("force"));
4176 }
4177 
4178 LogicalResult StmtEmitter::visitSV(ReleaseOp op) {
4179  if (hasSVAttributes(op))
4180  emitError(op, "SV attributes emission is unimplemented for the op");
4181 
4182  startStatement();
4183  SmallPtrSet<Operation *, 8> ops;
4184  ops.insert(op);
4185  ps.addCallback({op, true});
4186  ps.scopedBox(PP::ibox2, [&]() {
4187  ps << "release" << PP::space;
4188  emitExpression(op.getDest(), ops);
4189  ps << ";";
4190  });
4191  ps.addCallback({op, false});
4192  emitLocationInfoAndNewLine(ops);
4193  return success();
4194 }
4195 
4196 LogicalResult StmtEmitter::visitSV(AliasOp op) {
4197  if (hasSVAttributes(op))
4198  emitError(op, "SV attributes emission is unimplemented for the op");
4199 
4200  startStatement();
4201  SmallPtrSet<Operation *, 8> ops;
4202  ops.insert(op);
4203  ps.addCallback({op, true});
4204  ps.scopedBox(PP::ibox2, [&]() {
4205  ps << "alias" << PP::space;
4206  ps.scopedBox(PP::cbox0, [&]() { // If any breaks, all break.
4207  llvm::interleave(
4208  op.getOperands(), [&](Value v) { emitExpression(v, ops); },
4209  [&]() { ps << PP::nbsp << "=" << PP::space; });
4210  ps << ";";
4211  });
4212  });
4213  ps.addCallback({op, false});
4214  emitLocationInfoAndNewLine(ops);
4215  return success();
4216 }
4217 
4218 LogicalResult StmtEmitter::visitSV(InterfaceInstanceOp op) {
4219  auto doNotPrint = op->hasAttr("doNotPrint");
4220  if (doNotPrint && !state.options.emitBindComments)
4221  return success();
4222 
4223  if (hasSVAttributes(op))
4224  emitError(op, "SV attributes emission is unimplemented for the op");
4225 
4226  startStatement();
4227  StringRef prefix = "";
4228  ps.addCallback({op, true});
4229  if (doNotPrint) {
4230  prefix = "// ";
4231  ps << "// This interface is elsewhere emitted as a bind statement."
4232  << PP::newline;
4233  }
4234 
4235  SmallPtrSet<Operation *, 8> ops;
4236  ops.insert(op);
4237 
4238  auto *interfaceOp = op.getReferencedInterface(&state.symbolCache);
4239  assert(interfaceOp && "InterfaceInstanceOp has invalid symbol that does not "
4240  "point to an interface");
4241 
4242  auto verilogName = getSymOpName(interfaceOp);
4243  if (!prefix.empty())
4244  ps << PPExtString(prefix);
4245  ps << PPExtString(verilogName)
4246  << PP::nbsp /* don't break, may be comment line */
4247  << PPExtString(op.getName()) << "();";
4248 
4249  ps.addCallback({op, false});
4250  emitLocationInfoAndNewLine(ops);
4251 
4252  return success();
4253 }
4254 
4255 /// For OutputOp and ReturnOp we put "assign" statements at the end of the
4256 /// Verilog module or function respectively to assign outputs to intermediate
4257 /// wires.
4258 LogicalResult StmtEmitter::emitOutputLikeOp(Operation *op,
4259  const ModulePortInfo &ports) {
4260  SmallPtrSet<Operation *, 8> ops;
4261  size_t operandIndex = 0;
4262  bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
4263  for (PortInfo port : ports.getOutputs()) {
4264  auto operand = op->getOperand(operandIndex);
4265  // Outputs that are set by the output port of an instance are handled
4266  // directly when the instance is emitted.
4267  // Keep synced with countStatements() and visitStmt(InstanceOp).
4268  if (operand.hasOneUse() && operand.getDefiningOp() &&
4269  isa<InstanceOp, InstanceChoiceOp>(operand.getDefiningOp())) {
4270  ++operandIndex;
4271  continue;
4272  }
4273 
4274  ops.clear();
4275  ops.insert(op);
4276 
4277  startStatement();
4278  ps.addCallback({op, true});
4279  bool isZeroBit = isZeroBitType(port.type);
4280  ps.scopedBox(isZeroBit ? PP::neverbox : PP::ibox2, [&]() {
4281  if (isZeroBit)
4282  ps << "// Zero width: ";
4283  // Emit "assign" only in a non-procedural region.
4284  if (!isProcedural)
4285  ps << "assign" << PP::space;
4286  ps << PPExtString(port.getVerilogName());
4287  ps << PP::space << "=" << PP::space;
4288  ps.scopedBox(PP::ibox0, [&]() {
4289  // If this is a zero-width constant then don't emit it (illegal). Else,
4290  // emit the expression - even for zero width - for traceability.
4291  if (isZeroBit &&
4292  isa_and_nonnull<hw::ConstantOp>(operand.getDefiningOp()))
4293  ps << "/*Zero width*/";
4294  else
4295  emitExpression(operand, ops, LowestPrecedence,
4296  /*isAssignmentLikeContext=*/true);
4297  ps << ";";
4298  });
4299  });
4300  ps.addCallback({op, false});
4301  emitLocationInfoAndNewLine(ops);
4302 
4303  ++operandIndex;
4304  }
4305  return success();
4306 }
4307 
4308 LogicalResult StmtEmitter::visitStmt(OutputOp op) {
4309  auto parent = op->getParentOfType<PortList>();
4310  ModulePortInfo ports(parent.getPortList());
4311  return emitOutputLikeOp(op, ports);
4312 }
4313 
4314 LogicalResult StmtEmitter::visitStmt(TypeScopeOp op) {
4315  startStatement();
4316  auto typescopeDef = ("_TYPESCOPE_" + op.getSymName()).str();
4317  ps << "`ifndef " << typescopeDef << PP::newline;
4318  ps << "`define " << typescopeDef;
4319  setPendingNewline();
4320  emitStatementBlock(*op.getBodyBlock());
4321  startStatement();
4322  ps << "`endif // " << typescopeDef;
4323  setPendingNewline();
4324  return success();
4325 }
4326 
4327 LogicalResult StmtEmitter::visitStmt(TypedeclOp op) {
4328  if (hasSVAttributes(op))
4329  emitError(op, "SV attributes emission is unimplemented for the op");
4330 
4331  startStatement();
4332  auto zeroBitType = isZeroBitType(op.getType());
4333  if (zeroBitType)
4334  ps << PP::neverbox << "// ";
4335 
4336  SmallPtrSet<Operation *, 8> ops;
4337  ops.insert(op);
4338  ps.scopedBox(PP::ibox2, [&]() {
4339  ps << "typedef" << PP::space;
4340  ps.invokeWithStringOS([&](auto &os) {
4341  emitter.printPackedType(stripUnpackedTypes(op.getType()), os, op.getLoc(),
4342  op.getAliasType(), false);
4343  });
4344  ps << PP::space << PPExtString(op.getPreferredName());
4345  ps.invokeWithStringOS(
4346  [&](auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
4347  ps << ";";
4348  });
4349  if (zeroBitType)
4350  ps << PP::end;
4351  emitLocationInfoAndNewLine(ops);
4352  return success();
4353 }
4354 
4355 template <typename CallOpTy>
4356 LogicalResult StmtEmitter::emitFunctionCall(CallOpTy op) {
4357  startStatement();
4358 
4359  auto callee =
4360  dyn_cast<FuncOp>(state.symbolCache.getDefinition(op.getCalleeAttr()));
4361 
4362  SmallPtrSet<Operation *, 8> ops;
4363  ops.insert(op);
4364  assert(callee);
4365 
4366  auto explicitReturn = op.getExplicitlyReturnedValue(callee);
4367  if (explicitReturn) {
4368  assert(explicitReturn.hasOneUse());
4369  if (op->getParentOp()->template hasTrait<ProceduralRegion>()) {
4370  auto bpassignOp = cast<sv::BPAssignOp>(*explicitReturn.user_begin());
4371  emitExpression(bpassignOp.getDest(), ops);
4372  } else {
4373  auto assignOp = cast<sv::AssignOp>(*explicitReturn.user_begin());
4374  ps << "assign" << PP::nbsp;
4375  emitExpression(assignOp.getDest(), ops);
4376  }
4377  ps << PP::nbsp << "=" << PP::nbsp;
4378  }
4379 
4380  auto arguments = callee.getPortList(true);
4381 
4382  ps << PPExtString(getSymOpName(callee)) << "(";
4383 
4384  bool needsComma = false;
4385  auto printArg = [&](Value value) {
4386  if (needsComma)
4387  ps << "," << PP::space;
4388  emitExpression(value, ops);
4389  needsComma = true;
4390  };
4391 
4392  ps.scopedBox(PP::ibox0, [&] {
4393  unsigned inputIndex = 0, outputIndex = 0;
4394  for (auto arg : arguments) {
4395  if (arg.dir == hw::ModulePort::Output)
4396  printArg(
4397  op.getResults()[outputIndex++].getUsers().begin()->getOperand(0));
4398  else
4399  printArg(op.getInputs()[inputIndex++]);
4400  }
4401  });
4402 
4403  ps << ");";
4404  emitLocationInfoAndNewLine(ops);
4405  return success();
4406 }
4407 
4408 LogicalResult StmtEmitter::visitSV(FuncCallProceduralOp op) {
4409  return emitFunctionCall(op);
4410 }
4411 
4412 LogicalResult StmtEmitter::visitSV(FuncCallOp op) {
4413  return emitFunctionCall(op);
4414 }
4415 
4416 template <typename PPS>
4417 void emitFunctionSignature(ModuleEmitter &emitter, PPS &ps, FuncOp op,
4418  bool isAutomatic = false,
4419  bool emitAsTwoStateType = false) {
4420  ps << "function" << PP::nbsp;
4421  if (isAutomatic)
4422  ps << "automatic" << PP::nbsp;
4423  auto retType = op.getExplicitlyReturnedType();
4424  if (retType) {
4425  ps.invokeWithStringOS([&](auto &os) {
4426  emitter.printPackedType(retType, os, op->getLoc(), {}, false, true,
4427  emitAsTwoStateType);
4428  });
4429  } else
4430  ps << "void";
4431  ps << PP::nbsp << PPExtString(getSymOpName(op));
4432 
4433  emitter.emitPortList(
4434  op, ModulePortInfo(op.getPortList(/*excludeExplicitReturn=*/true)), true);
4435 }
4436 
4437 LogicalResult StmtEmitter::visitSV(ReturnOp op) {
4438  auto parent = op->getParentOfType<sv::FuncOp>();
4439  ModulePortInfo ports(parent.getPortList(false));
4440  return emitOutputLikeOp(op, ports);
4441 }
4442 
4443 LogicalResult StmtEmitter::visitSV(FuncDPIImportOp importOp) {
4444  startStatement();
4445 
4446  ps << "import" << PP::nbsp << "\"DPI-C\"" << PP::nbsp << "context"
4447  << PP::nbsp;
4448 
4449  // Emit a linkage name if provided.
4450  if (auto linkageName = importOp.getLinkageName())
4451  ps << *linkageName << PP::nbsp << "=" << PP::nbsp;
4452  auto op =
4453  cast<FuncOp>(state.symbolCache.getDefinition(importOp.getCalleeAttr()));
4454  assert(op.isDeclaration() && "function must be a declaration");
4455  emitFunctionSignature(emitter, ps, op, /*isAutomatic=*/false,
4456  /*emitAsTwoStateType=*/true);
4457  assert(state.pendingNewline);
4458  ps << PP::newline;
4459 
4460  return success();
4461 }
4462 
4463 LogicalResult StmtEmitter::visitSV(FWriteOp op) {
4464  if (hasSVAttributes(op))
4465  emitError(op, "SV attributes emission is unimplemented for the op");
4466 
4467  startStatement();
4468  SmallPtrSet<Operation *, 8> ops;
4469  ops.insert(op);
4470 
4471  ps.addCallback({op, true});
4472  ps << "$fwrite(";
4473  ps.scopedBox(PP::ibox0, [&]() {
4474  emitExpression(op.getFd(), ops);
4475 
4476  ps << "," << PP::space;
4477  ps.writeQuotedEscaped(op.getFormatString());
4478 
4479  // TODO: if any of these breaks, it'd be "nice" to break
4480  // after the comma, instead of:
4481  // $fwrite(5, "...", a + b,
4482  // longexpr_goes
4483  // + here, c);
4484  // (without forcing breaking between all elements, like braced list)
4485  for (auto operand : op.getSubstitutions()) {
4486  ps << "," << PP::space;
4487  emitExpression(operand, ops);
4488  }
4489  ps << ");";
4490  });
4491  ps.addCallback({op, false});
4492  emitLocationInfoAndNewLine(ops);
4493  return success();
4494 }
4495 
4496 LogicalResult StmtEmitter::visitSV(VerbatimOp op) {
4497  if (hasSVAttributes(op))
4498  emitError(op, "SV attributes emission is unimplemented for the op");
4499 
4500  startStatement();
4501  SmallPtrSet<Operation *, 8> ops;
4502  ops.insert(op);
4503  ps << PP::neverbox;
4504 
4505  // Drop an extraneous \n off the end of the string if present.
4506  StringRef string = op.getFormatString();
4507  if (string.ends_with("\n"))
4508  string = string.drop_back();
4509 
4510  // Emit each \n separated piece of the string with each piece properly
4511  // indented. The convention is to not emit the \n so
4512  // emitLocationInfoAndNewLine can do that for the last line.
4513  bool isFirst = true;
4514 
4515  // Emit each line of the string at a time.
4516  while (!string.empty()) {
4517  auto lhsRhs = string.split('\n');
4518  if (isFirst)
4519  isFirst = false;
4520  else {
4521  ps << PP::end << PP::newline << PP::neverbox;
4522  }
4523 
4524  // Emit each chunk of the line.
4525  emitTextWithSubstitutions(
4526  ps, lhsRhs.first, op,
4527  [&](Value operand) { emitExpression(operand, ops); }, op.getSymbols());
4528  string = lhsRhs.second;
4529  }
4530 
4531  ps << PP::end;
4532 
4533  emitLocationInfoAndNewLine(ops);
4534  return success();
4535 }
4536 
4537 // Emit macro as a statement.
4538 LogicalResult StmtEmitter::visitSV(MacroRefOp op) {
4539  if (hasSVAttributes(op)) {
4540  emitError(op, "SV attributes emission is unimplemented for the op");
4541  return failure();
4542  }
4543  startStatement();
4544  SmallPtrSet<Operation *, 8> ops;
4545  ops.insert(op);
4546  ps << PP::neverbox;
4547 
4548  // Use the specified name or the symbol name as appropriate.
4549  auto macroOp = op.getReferencedMacro(&state.symbolCache);
4550  assert(macroOp && "Invalid IR");
4551  StringRef name =
4552  macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
4553  ps << "`" << PPExtString(name);
4554  if (!op.getInputs().empty()) {
4555  ps << "(";
4556  llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
4557  emitExpression(val, ops, LowestPrecedence,
4558  /*isAssignmentLikeContext=*/false);
4559  });
4560  ps << ")";
4561  }
4562  ps << PP::end;
4563  emitLocationInfoAndNewLine(ops);
4564  return success();
4565 }
4566 
4567 /// Emit one of the simulation control tasks `$stop`, `$finish`, or `$exit`.
4568 LogicalResult
4569 StmtEmitter::emitSimulationControlTask(Operation *op, PPExtString taskName,
4570  std::optional<unsigned> verbosity) {
4571  if (hasSVAttributes(op))
4572  emitError(op, "SV attributes emission is unimplemented for the op");
4573 
4574  startStatement();
4575  SmallPtrSet<Operation *, 8> ops;
4576  ops.insert(op);
4577  ps.addCallback({op, true});
4578  ps << taskName;
4579  if (verbosity && *verbosity != 1) {
4580  ps << "(";
4581  ps.addAsString(*verbosity);
4582  ps << ")";
4583  }
4584  ps << ";";
4585  ps.addCallback({op, false});
4586  emitLocationInfoAndNewLine(ops);
4587  return success();
4588 }
4589 
4590 LogicalResult StmtEmitter::visitSV(StopOp op) {
4591  return emitSimulationControlTask(op, PPExtString("$stop"), op.getVerbosity());
4592 }
4593 
4594 LogicalResult StmtEmitter::visitSV(FinishOp op) {
4595  return emitSimulationControlTask(op, PPExtString("$finish"),
4596  op.getVerbosity());
4597 }
4598 
4599 LogicalResult StmtEmitter::visitSV(ExitOp op) {
4600  return emitSimulationControlTask(op, PPExtString("$exit"), {});
4601 }
4602 
4603 /// Emit one of the severity message tasks `$fatal`, `$error`, `$warning`, or
4604 /// `$info`.
4605 LogicalResult
4606 StmtEmitter::emitSeverityMessageTask(Operation *op, PPExtString taskName,
4607  std::optional<unsigned> verbosity,
4608  StringAttr message, ValueRange operands) {
4609  if (hasSVAttributes(op))
4610  emitError(op, "SV attributes emission is unimplemented for the op");
4611 
4612  startStatement();
4613  SmallPtrSet<Operation *, 8> ops;
4614  ops.insert(op);
4615  ps.addCallback({op, true});
4616  ps << taskName;
4617 
4618  // In case we have a message to print, or the operation has an optional
4619  // verbosity and that verbosity is present, print the parenthesized parameter
4620  // list.
4621  if ((verbosity && *verbosity != 1) || message) {
4622  ps << "(";
4623  ps.scopedBox(PP::ibox0, [&]() {
4624  // If the operation takes a verbosity, print it if it is set, or print the
4625  // default "1".
4626  if (verbosity)
4627  ps.addAsString(*verbosity);
4628 
4629  // Print the message and interpolation operands if present.
4630  if (message) {
4631  if (verbosity)
4632  ps << "," << PP::space;
4633  ps.writeQuotedEscaped(message.getValue());
4634  // TODO: good comma/wrapping behavior as elsewhere.
4635  for (auto operand : operands) {
4636  ps << "," << PP::space;
4637  emitExpression(operand, ops);
4638  }
4639  }
4640 
4641  ps << ")";
4642  });
4643  }
4644 
4645  ps << ";";
4646  ps.addCallback({op, false});
4647  emitLocationInfoAndNewLine(ops);
4648  return success();
4649 }
4650 
4651 LogicalResult StmtEmitter::visitSV(FatalOp op) {
4652  return emitSeverityMessageTask(op, PPExtString("$fatal"), op.getVerbosity(),
4653  op.getMessageAttr(), op.getSubstitutions());
4654 }
4655 
4656 LogicalResult StmtEmitter::visitSV(ErrorOp op) {
4657  return emitSeverityMessageTask(op, PPExtString("$error"), {},
4658  op.getMessageAttr(), op.getSubstitutions());
4659 }
4660 
4661 LogicalResult StmtEmitter::visitSV(WarningOp op) {
4662  return emitSeverityMessageTask(op, PPExtString("$warning"), {},
4663  op.getMessageAttr(), op.getSubstitutions());
4664 }
4665 
4666 LogicalResult StmtEmitter::visitSV(InfoOp op) {
4667  return emitSeverityMessageTask(op, PPExtString("$info"), {},
4668  op.getMessageAttr(), op.getSubstitutions());
4669 }
4670 
4671 LogicalResult StmtEmitter::visitSV(ReadMemOp op) {
4672  SmallPtrSet<Operation *, 8> ops({op});
4673 
4674  startStatement();
4675  ps.addCallback({op, true});
4676  ps << "$readmem";
4677  switch (op.getBaseAttr().getValue()) {
4678  case MemBaseTypeAttr::MemBaseBin:
4679  ps << "b";
4680  break;
4681  case MemBaseTypeAttr::MemBaseHex:
4682  ps << "h";
4683  break;
4684  }
4685  ps << "(";
4686  ps.scopedBox(PP::ibox0, [&]() {
4687  ps.writeQuotedEscaped(op.getFilename());
4688  ps << "," << PP::space;
4689  emitExpression(op.getDest(), ops);
4690  });
4691 
4692  ps << ");";
4693  ps.addCallback({op, false});
4694  emitLocationInfoAndNewLine(ops);
4695  return success();
4696 }
4697 
4698 LogicalResult StmtEmitter::visitSV(GenerateOp op) {
4699  emitSVAttributes(op);
4700  // TODO: location info?
4701  startStatement();
4702  ps.addCallback({op, true});
4703  ps << "generate" << PP::newline;
4704  ps << "begin: " << PPExtString(getSymOpName(op));
4705  setPendingNewline();
4706  emitStatementBlock(op.getBody().getBlocks().front());
4707  startStatement();
4708  ps << "end: " << PPExtString(getSymOpName(op)) << PP::newline;
4709  ps << "endgenerate";
4710  ps.addCallback({op, false});
4711  setPendingNewline();
4712  return success();
4713 }
4714 
4715 LogicalResult StmtEmitter::visitSV(GenerateCaseOp op) {
4716  emitSVAttributes(op);
4717  // TODO: location info?
4718  startStatement();
4719  ps.addCallback({op, true});
4720  ps << "case (";
4721  ps.invokeWithStringOS([&](auto &os) {
4722  emitter.printParamValue(
4723  op.getCond(), os, VerilogPrecedence::Selection,
4724  [&]() { return op->emitOpError("invalid case parameter"); });
4725  });
4726  ps << ")";
4727  setPendingNewline();
4728 
4729  // Ensure that all of the per-case arrays are the same length.
4730  ArrayAttr patterns = op.getCasePatterns();
4731  ArrayAttr caseNames = op.getCaseNames();
4732  MutableArrayRef<Region> regions = op.getCaseRegions();
4733  assert(patterns.size() == regions.size());
4734  assert(patterns.size() == caseNames.size());
4735 
4736  // TODO: We'll probably need to store the legalized names somewhere for
4737  // `verbose` formatting. Set up the infra for storing names recursively. Just
4738  // store this locally for now.
4739  llvm::StringMap<size_t> nextGenIds;
4740  ps.scopedBox(PP::bbox2, [&]() {
4741  // Emit each case.
4742  for (size_t i = 0, e = patterns.size(); i < e; ++i) {
4743  auto &region = regions[i];
4744  assert(region.hasOneBlock());
4745  Attribute patternAttr = patterns[i];
4746 
4747  startStatement();
4748  if (!isa<mlir::TypedAttr>(patternAttr))
4749  ps << "default";
4750  else
4751  ps.invokeWithStringOS([&](auto &os) {
4752  emitter.printParamValue(
4753  patternAttr, os, VerilogPrecedence::LowestPrecedence,
4754  [&]() { return op->emitOpError("invalid case value"); });
4755  });
4756 
4757  StringRef legalName =
4758  legalizeName(cast<StringAttr>(caseNames[i]).getValue(), nextGenIds,
4759  options.caseInsensitiveKeywords);
4760  ps << ": begin: " << PPExtString(legalName);
4761  setPendingNewline();
4762  emitStatementBlock(region.getBlocks().front());
4763  startStatement();
4764  ps << "end: " << PPExtString(legalName);
4765  setPendingNewline();
4766  }
4767  });
4768 
4769  startStatement();
4770  ps << "endcase";
4771  ps.addCallback({op, false});
4772  setPendingNewline();
4773  return success();
4774 }
4775 
4776 LogicalResult StmtEmitter::visitSV(ForOp op) {
4777  emitSVAttributes(op);
4778  llvm::SmallPtrSet<Operation *, 8> ops;
4779  ps.addCallback({op, true});
4780  startStatement();
4781  auto inductionVarName = op->getAttrOfType<StringAttr>("hw.verilogName");
4782  ps << "for (";
4783  // Emit statements on same line if possible, or put each on own line.
4784  ps.scopedBox(PP::cbox0, [&]() {
4785  // Emit initialization assignment.
4786  emitAssignLike(
4787  [&]() {
4788  ps << "logic" << PP::nbsp;
4789  ps.invokeWithStringOS([&](auto &os) {
4790  emitter.emitTypeDims(op.getInductionVar().getType(), op.getLoc(),
4791  os);
4792  });
4793  ps << PP::nbsp << PPExtString(inductionVarName);
4794  },
4795  [&]() { emitExpression(op.getLowerBound(), ops); }, PPExtString("="));
4796  // Break between statements.
4797  ps << PP::space;
4798 
4799  // Emit bounds-check statement.
4800  emitAssignLike([&]() { ps << PPExtString(inductionVarName); },
4801  [&]() { emitExpression(op.getUpperBound(), ops); },
4802  PPExtString("<"));
4803  // Break between statements.
4804  ps << PP::space;
4805 
4806  // Emit update statement and trailing syntax.
4807  emitAssignLike([&]() { ps << PPExtString(inductionVarName); },
4808  [&]() { emitExpression(op.getStep(), ops); },
4809  PPExtString("+="), PPExtString(") begin"));
4810  });
4811  // Don't break for because of newline.
4812  ps << PP::neverbreak;
4813  setPendingNewline();
4814  emitStatementBlock(op.getBody().getBlocks().front());
4815  startStatement();
4816  ps << "end";
4817  ps.addCallback({op, false});
4818  emitLocationInfoAndNewLine(ops);
4819  return success();
4820 }
4821 
4822 /// Emit the `<label>:` portion of a verification operation.
4823 void StmtEmitter::emitAssertionLabel(Operation *op) {
4824  if (auto label = op->getAttrOfType<StringAttr>("hw.verilogName"))
4825  ps << PPExtString(label) << ":" << PP::space;
4826 }
4827 
4828 /// Emit the optional ` else $error(...)` portion of an immediate or concurrent
4829 /// verification operation.
4830 void StmtEmitter::emitAssertionMessage(StringAttr message, ValueRange args,
4831  SmallPtrSetImpl<Operation *> &ops,
4832  bool isConcurrent = false) {
4833  if (!message)
4834  return;
4835  ps << PP::space << "else" << PP::nbsp << "$error(";
4836  ps.scopedBox(PP::ibox0, [&]() {
4837  ps.writeQuotedEscaped(message.getValue());
4838  // TODO: box, break/wrap behavior!
4839  for (auto arg : args) {
4840  ps << "," << PP::space;
4841  emitExpression(arg, ops);
4842  }
4843  ps << ")";
4844  });
4845 }
4846 
4847 template <typename Op>
4848 LogicalResult StmtEmitter::emitImmediateAssertion(Op op, PPExtString opName) {
4849  if (hasSVAttributes(op))
4850  emitError(op, "SV attributes emission is unimplemented for the op");
4851 
4852  startStatement();
4853  SmallPtrSet<Operation *, 8> ops;
4854  ops.insert(op);
4855  ps.addCallback({op, true});
4856  ps.scopedBox(PP::ibox2, [&]() {
4857  emitAssertionLabel(op);
4858  ps.scopedBox(PP::cbox0, [&]() {
4859  ps << opName;
4860  switch (op.getDefer()) {
4861  case DeferAssert::Immediate:
4862  break;
4863  case DeferAssert::Observed:
4864  ps << " #0 ";
4865  break;
4866  case DeferAssert::Final:
4867  ps << " final ";
4868  break;
4869  }
4870  ps << "(";
4871  ps.scopedBox(PP::ibox0, [&]() {
4872  emitExpression(op.getExpression(), ops);
4873  ps << ")";
4874  });
4875  emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops);
4876  ps << ";";
4877  });
4878  });
4879  ps.addCallback({op, false});
4880  emitLocationInfoAndNewLine(ops);
4881  return success();
4882 }
4883 
4884 LogicalResult StmtEmitter::visitSV(AssertOp op) {
4885  return emitImmediateAssertion(op, PPExtString("assert"));
4886 }
4887 
4888 LogicalResult StmtEmitter::visitSV(AssumeOp op) {
4889  return emitImmediateAssertion(op, PPExtString("assume"));
4890 }
4891 
4892 LogicalResult StmtEmitter::visitSV(CoverOp op) {
4893  return emitImmediateAssertion(op, PPExtString("cover"));
4894 }
4895 
4896 template <typename Op>
4897 LogicalResult StmtEmitter::emitConcurrentAssertion(Op op, PPExtString opName) {
4898  if (hasSVAttributes(op))
4899  emitError(op, "SV attributes emission is unimplemented for the op");
4900 
4901  startStatement();
4902  SmallPtrSet<Operation *, 8> ops;
4903  ops.insert(op);
4904  ps.addCallback({op, true});
4905  ps.scopedBox(PP::ibox2, [&]() {
4906  emitAssertionLabel(op);
4907  ps.scopedBox(PP::cbox0, [&]() {
4908  ps << opName << PP::nbsp << "property (";
4909  ps.scopedBox(PP::ibox0, [&]() {
4910  ps << "@(" << PPExtString(stringifyEventControl(op.getEvent()))
4911  << PP::nbsp;
4912  emitExpression(op.getClock(), ops);
4913  ps << ")" << PP::space;
4914  emitExpression(op.getProperty(), ops);
4915  ps << ")";
4916  });
4917  emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops,
4918  true);
4919  ps << ";";
4920  });
4921  });
4922  ps.addCallback({op, false});
4923  emitLocationInfoAndNewLine(ops);
4924  return success();
4925 }
4926 
4927 LogicalResult StmtEmitter::visitSV(AssertConcurrentOp op) {
4928  return emitConcurrentAssertion(op, PPExtString("assert"));
4929 }
4930 
4931 LogicalResult StmtEmitter::visitSV(AssumeConcurrentOp op) {
4932  return emitConcurrentAssertion(op, PPExtString("assume"));
4933 }
4934 
4935 LogicalResult StmtEmitter::visitSV(CoverConcurrentOp op) {
4936  return emitConcurrentAssertion(op, PPExtString("cover"));
4937 }
4938 
4939 // Property assertions are what gets emitted if the user want to combine
4940 // concurrent assertions with a disable signal, a clock and an ltl property.
4941 template <typename Op>
4942 LogicalResult StmtEmitter::emitPropertyAssertion(Op op, PPExtString opName) {
4943  if (hasSVAttributes(op))
4944  emitError(op, "SV attributes emission is unimplemented for the op");
4945 
4946  // If we are inside a procedural region we have the option of emitting either
4947  // an `assert` or `assert property`. If we are in a non-procedural region,
4948  // e.g., the body of a module, we have to use the concurrent form `assert
4949  // property` (which also supports plain booleans).
4950  //
4951  // See IEEE 1800-2017 section 16.14.5 "Using concurrent assertion statements
4952  // outside procedural code" and 16.14.6 "Embedding concurrent assertions in
4953  // procedural code".
4954  Operation *parent = op->getParentOp();
4955  Value property = op.getProperty();
4956  bool isTemporal = !property.getType().isSignlessInteger(1);
4957  bool isProcedural = parent->hasTrait<ProceduralRegion>();
4958  bool emitAsImmediate = !isTemporal && isProcedural;
4959 
4960  startStatement();
4961  SmallPtrSet<Operation *, 8> ops;
4962  ops.insert(op);
4963  ps.addCallback({op, true});
4964  ps.scopedBox(PP::ibox2, [&]() {
4965  // Check for a label and emit it if necessary
4966  emitAssertionLabel(op);
4967  // Emit the assertion
4968  ps.scopedBox(PP::cbox0, [&]() {
4969  if (emitAsImmediate)
4970  ps << opName << "(";
4971  else
4972  ps << opName << PP::nbsp << "property" << PP::nbsp << "(";
4973  // Event only exists if the clock exists
4974  Value clock = op.getClock();
4975  auto event = op.getEvent();
4976  if (clock)
4977  ps.scopedBox(PP::ibox2, [&]() {
4978  PropertyEmitter(emitter, ops)
4979  .emitAssertPropertyBody(property, *event, clock, op.getDisable());
4980  });
4981  else
4982  ps.scopedBox(PP::ibox2, [&]() {
4983  PropertyEmitter(emitter, ops)
4984  .emitAssertPropertyBody(property, op.getDisable());
4985  });
4986  ps << ");";
4987  });
4988  });
4989  ps.addCallback({op, false});
4990  emitLocationInfoAndNewLine(ops);
4991  return success();
4992 }
4993 
4994 LogicalResult StmtEmitter::visitSV(AssertPropertyOp op) {
4995  return emitPropertyAssertion(op, PPExtString("assert"));
4996 }
4997 
4998 LogicalResult StmtEmitter::visitSV(AssumePropertyOp op) {
4999  return emitPropertyAssertion(op, PPExtString("assume"));
5000 }
5001 
5002 LogicalResult StmtEmitter::visitSV(CoverPropertyOp op) {
5003  return emitPropertyAssertion(op, PPExtString("cover"));
5004 }
5005 
5006 LogicalResult StmtEmitter::emitIfDef(Operation *op, MacroIdentAttr cond) {
5007  if (hasSVAttributes(op))
5008  emitError(op, "SV attributes emission is unimplemented for the op");
5009 
5010  auto ident = PPExtString(cond.getName());
5011 
5012  startStatement();
5013  bool hasEmptyThen = op->getRegion(0).front().empty();
5014  if (hasEmptyThen)
5015  ps << "`ifndef " << ident;
5016  else
5017  ps << "`ifdef " << ident;
5018 
5019  SmallPtrSet<Operation *, 8> ops;
5020  ops.insert(op);
5021  emitLocationInfoAndNewLine(ops);
5022 
5023  if (!hasEmptyThen)
5024  emitStatementBlock(op->getRegion(0).front());
5025 
5026  if (!op->getRegion(1).empty()) {
5027  if (!hasEmptyThen) {
5028  startStatement();
5029  ps << "`else // " << ident;
5030  setPendingNewline();
5031  }
5032  emitStatementBlock(op->getRegion(1).front());
5033  }
5034  startStatement();
5035  ps << "`endif // ";
5036  if (hasEmptyThen)
5037  ps << "not def ";
5038  ps << ident;
5039  setPendingNewline();
5040  return success();
5041 }
5042 
5043 /// Emit the body of a control flow statement that is surrounded by begin/end
5044 /// markers if non-singular. If the control flow construct is multi-line and
5045 /// if multiLineComment is non-null, the string is included in a comment after
5046 /// the 'end' to make it easier to associate.
5047 void StmtEmitter::emitBlockAsStatement(
5048  Block *block, const SmallPtrSetImpl<Operation *> &locationOps,
5049  StringRef multiLineComment) {
5050 
5051  // Determine if we need begin/end by scanning the block.
5052  auto count = countStatements(*block);
5053  auto needsBeginEnd = count != BlockStatementCount::One;
5054  if (needsBeginEnd)
5055  ps << " begin";
5056  emitLocationInfoAndNewLine(locationOps);
5057 
5058  if (count != BlockStatementCount::Zero)
5059  emitStatementBlock(*block);
5060 
5061  if (needsBeginEnd) {
5062  startStatement();
5063  ps << "end";
5064  // Emit comment if there's an 'end', regardless of line count.
5065  if (!multiLineComment.empty())
5066  ps << " // " << multiLineComment;
5067  setPendingNewline();
5068  }
5069 }
5070 
5071 LogicalResult StmtEmitter::visitSV(OrderedOutputOp ooop) {
5072  // Emit the body.
5073  for (auto &op : ooop.getBody().front())
5074  emitStatement(&op);
5075  return success();
5076 }
5077 
5078 LogicalResult StmtEmitter::visitSV(IfOp op) {
5079  SmallPtrSet<Operation *, 8> ops;
5080 
5081  auto ifcondBox = PP::ibox2;
5082 
5083  emitSVAttributes(op);
5084  startStatement();
5085  ps.addCallback({op, true});
5086  ps << "if (" << ifcondBox;
5087 
5088  // In the loop, emit an if statement assuming the keyword introducing
5089  // it (either "if (" or "else if (") was printed already.
5090  IfOp ifOp = op;
5091  for (;;) {
5092  ops.clear();
5093  ops.insert(ifOp);
5094 
5095  // Emit the condition and the then block.
5096  emitExpression(ifOp.getCond(), ops);
5097  ps << PP::end << ")";
5098  emitBlockAsStatement(ifOp.getThenBlock(), ops);
5099 
5100  if (!ifOp.hasElse())
5101  break;
5102 
5103  startStatement();
5104  Block *elseBlock = ifOp.getElseBlock();
5105  auto nestedElseIfOp = findNestedElseIf(elseBlock);
5106  if (!nestedElseIfOp) {
5107  // The else block does not contain an if-else that can be flattened.
5108  ops.clear();
5109  ops.insert(ifOp);
5110  ps << "else";
5111  emitBlockAsStatement(elseBlock, ops);
5112  break;
5113  }
5114 
5115  // Introduce the 'else if', and iteratively continue unfolding any if-else
5116  // statements inside of it.
5117  ifOp = nestedElseIfOp;
5118  ps << "else if (" << ifcondBox;
5119  }
5120  ps.addCallback({op, false});
5121 
5122  return success();
5123 }
5124 
5125 LogicalResult StmtEmitter::visitSV(AlwaysOp op) {
5126  emitSVAttributes(op);
5127  SmallPtrSet<Operation *, 8> ops;
5128  ops.insert(op);
5129  startStatement();
5130 
5131  auto printEvent = [&](AlwaysOp::Condition cond) {
5132  ps << PPExtString(stringifyEventControl(cond.event)) << PP::nbsp;
5133  ps.scopedBox(PP::cbox0, [&]() { emitExpression(cond.value, ops); });
5134  };
5135  ps.addCallback({op, true});
5136 
5137  switch (op.getNumConditions()) {
5138  case 0:
5139  ps << "always @*";
5140  break;
5141  case 1:
5142  ps << "always @(";
5143  printEvent(op.getCondition(0));
5144  ps << ")";
5145  break;
5146  default:
5147  ps << "always @(";
5148  ps.scopedBox(PP::cbox0, [&]() {
5149  printEvent(op.getCondition(0));
5150  for (size_t i = 1, e = op.getNumConditions(); i != e; ++i) {
5151  ps << PP::space << "or" << PP::space;
5152  printEvent(op.getCondition(i));
5153  }
5154  ps << ")";
5155  });
5156  break;
5157  }
5158 
5159  // Build the comment string, leave out the signal expressions (since they
5160  // can be large).
5161  std::string comment;
5162  if (op.getNumConditions() == 0) {
5163  comment = "always @*";
5164  } else {
5165  comment = "always @(";
5166  llvm::interleave(
5167  op.getEvents(),
5168  [&](Attribute eventAttr) {
5169  auto event = sv::EventControl(cast<IntegerAttr>(eventAttr).getInt());
5170  comment += stringifyEventControl(event);
5171  },
5172  [&]() { comment += ", "; });
5173  comment += ')';
5174  }
5175 
5176  emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5177  ps.addCallback({op, false});
5178  return success();
5179 }
5180 
5181 LogicalResult StmtEmitter::visitSV(AlwaysCombOp op) {
5182  emitSVAttributes(op);
5183  SmallPtrSet<Operation *, 8> ops;
5184  ops.insert(op);
5185  startStatement();
5186 
5187  ps.addCallback({op, true});
5188  StringRef opString = "always_comb";
5189  if (state.options.noAlwaysComb)
5190  opString = "always @(*)";
5191 
5192  ps << PPExtString(opString);
5193  emitBlockAsStatement(op.getBodyBlock(), ops, opString);
5194  ps.addCallback({op, false});
5195  return success();
5196 }
5197 
5198 LogicalResult StmtEmitter::visitSV(AlwaysFFOp op) {
5199  emitSVAttributes(op);
5200 
5201  SmallPtrSet<Operation *, 8> ops;
5202  ops.insert(op);
5203  startStatement();
5204 
5205  ps.addCallback({op, true});
5206  ps << "always_ff @(";
5207  ps.scopedBox(PP::cbox0, [&]() {
5208  ps << PPExtString(stringifyEventControl(op.getClockEdge())) << PP::nbsp;
5209  emitExpression(op.getClock(), ops);
5210  if (op.getResetStyle() == ResetType::AsyncReset) {
5211  ps << PP::nbsp << "or" << PP::space
5212  << PPExtString(stringifyEventControl(*op.getResetEdge())) << PP::nbsp;
5213  emitExpression(op.getReset(), ops);
5214  }
5215  ps << ")";
5216  });
5217 
5218  // Build the comment string, leave out the signal expressions (since they
5219  // can be large).
5220  std::string comment;
5221  comment += "always_ff @(";
5222  comment += stringifyEventControl(op.getClockEdge());
5223  if (op.getResetStyle() == ResetType::AsyncReset) {
5224  comment += " or ";
5225  comment += stringifyEventControl(*op.getResetEdge());
5226  }
5227  comment += ')';
5228 
5229  if (op.getResetStyle() == ResetType::NoReset)
5230  emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5231  else {
5232  ps << " begin";
5233  emitLocationInfoAndNewLine(ops);
5234  ps.scopedBox(PP::bbox2, [&]() {
5235  startStatement();
5236  ps << "if (";
5237  // TODO: group, like normal 'if'.
5238  // Negative edge async resets need to invert the reset condition. This
5239  // is noted in the op description.
5240  if (op.getResetStyle() == ResetType::AsyncReset &&
5241  *op.getResetEdge() == sv::EventControl::AtNegEdge)
5242  ps << "!";
5243  emitExpression(op.getReset(), ops);
5244  ps << ")";
5245  emitBlockAsStatement(op.getResetBlock(), ops);
5246  startStatement();
5247  ps << "else";
5248  emitBlockAsStatement(op.getBodyBlock(), ops);
5249  });
5250 
5251  startStatement();
5252  ps << "end";
5253  ps << " // " << comment;
5254  setPendingNewline();
5255  }
5256  ps.addCallback({op, false});
5257  return success();
5258 }
5259 
5260 LogicalResult StmtEmitter::visitSV(InitialOp op) {
5261  emitSVAttributes(op);
5262  SmallPtrSet<Operation *, 8> ops;
5263  ops.insert(op);
5264  startStatement();
5265  ps.addCallback({op, true});
5266  ps << "initial";
5267  emitBlockAsStatement(op.getBodyBlock(), ops, "initial");
5268  ps.addCallback({op, false});
5269  return success();
5270 }
5271 
5272 LogicalResult StmtEmitter::visitSV(CaseOp op) {
5273  emitSVAttributes(op);
5274  SmallPtrSet<Operation *, 8> ops, emptyOps;
5275  ops.insert(op);
5276  startStatement();
5277  ps.addCallback({op, true});
5278  if (op.getValidationQualifier() !=
5279  ValidationQualifierTypeEnum::ValidationQualifierPlain)
5280  ps << PPExtString(circt::sv::stringifyValidationQualifierTypeEnum(
5281  op.getValidationQualifier()))
5282  << PP::nbsp;
5283  const char *opname = nullptr;
5284  switch (op.getCaseStyle()) {
5285  case CaseStmtType::CaseStmt:
5286  opname = "case";
5287  break;
5288  case CaseStmtType::CaseXStmt:
5289  opname = "casex";
5290  break;
5291  case CaseStmtType::CaseZStmt:
5292  opname = "casez";
5293  break;
5294  }
5295  ps << opname << " (";
5296  ps.scopedBox(PP::ibox0, [&]() {
5297  emitExpression(op.getCond(), ops);
5298  ps << ")";
5299  });
5300  emitLocationInfoAndNewLine(ops);
5301 
5302  ps.scopedBox(PP::bbox2, [&]() {
5303  for (auto &caseInfo : op.getCases()) {
5304  startStatement();
5305  auto &pattern = caseInfo.pattern;
5306 
5307  llvm::TypeSwitch<CasePattern *>(pattern.get())
5308  .Case<CaseBitPattern>([&](auto bitPattern) {
5309  // TODO: We could emit in hex if/when the size is a multiple of
5310  // 4 and there are no x's crossing nibble boundaries.
5311  ps.invokeWithStringOS([&](auto &os) {
5312  os << bitPattern->getWidth() << "'b";
5313  for (size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
5314  os << getLetter(bitPattern->getBit(e - bit - 1));
5315  });
5316  })
5317  .Case<CaseEnumPattern>([&](auto enumPattern) {
5318  ps << PPExtString(emitter.fieldNameResolver.getEnumFieldName(
5319  cast<hw::EnumFieldAttr>(enumPattern->attr())));
5320  })
5321  .Case<CaseDefaultPattern>([&](auto) { ps << "default"; })
5322  .Default([&](auto) { assert(false && "unhandled case pattern"); });
5323 
5324  ps << ":";
5325  emitBlockAsStatement(caseInfo.block, emptyOps);
5326  }
5327  });
5328 
5329  startStatement();
5330  ps << "endcase";
5331  ps.addCallback({op, false});
5332  emitLocationInfoAndNewLine(ops);
5333  return success();
5334 }
5335 
5336 LogicalResult StmtEmitter::visitStmt(InstanceOp op) {
5337  bool doNotPrint = op->hasAttr("doNotPrint");
5338  if (doNotPrint && !state.options.emitBindComments)
5339  return success();
5340 
5341  // Emit SV attributes if the op is not emitted as a bind statement.
5342  if (!doNotPrint)
5343  emitSVAttributes(op);
5344  startStatement();
5345  ps.addCallback({op, true});
5346  if (doNotPrint) {
5347  ps << PP::ibox2
5348  << "/* This instance is elsewhere emitted as a bind statement."
5349  << PP::newline;
5350  if (hasSVAttributes(op))
5351  op->emitWarning() << "is emitted as a bind statement but has SV "
5352  "attributes. The attributes will not be emitted.";
5353  }
5354 
5355  SmallPtrSet<Operation *, 8> ops;
5356  ops.insert(op);
5357 
5358  // Use the specified name or the symbol name as appropriate.
5359  auto *moduleOp =
5360  state.symbolCache.getDefinition(op.getReferencedModuleNameAttr());
5361  assert(moduleOp && "Invalid IR");
5362  ps << PPExtString(getVerilogModuleName(moduleOp));
5363 
5364  // If this is a parameterized module, then emit the parameters.
5365  if (!op.getParameters().empty()) {
5366  // All the parameters may be defaulted -- don't print out an empty list if
5367  // so.
5368  bool printed = false;
5369  for (auto params :
5370  llvm::zip(op.getParameters(),
5371  moduleOp->getAttrOfType<ArrayAttr>("parameters"))) {
5372  auto param = cast<ParamDeclAttr>(std::get<0>(params));
5373  auto modParam = cast<ParamDeclAttr>(std::get<1>(params));
5374  // Ignore values that line up with their default.
5375  if (param.getValue() == modParam.getValue())
5376  continue;
5377 
5378  // Handle # if this is the first parameter we're printing.
5379  if (!printed) {
5380  ps << " #(" << PP::bbox2 << PP::newline;
5381  printed = true;
5382  } else {
5383  ps << "," << PP::newline;
5384  }
5385  ps << ".";
5386  ps << PPExtString(
5387  state.globalNames.getParameterVerilogName(moduleOp, param.getName()));
5388  ps << "(";
5389  ps.invokeWithStringOS([&](auto &os) {
5390  emitter.printParamValue(param.getValue(), os, [&]() {
5391  return op->emitOpError("invalid instance parameter '")
5392  << param.getName().getValue() << "' value";
5393  });
5394  });
5395  ps << ")";
5396  }
5397  if (printed) {
5398  ps << PP::end << PP::newline << ")";
5399  }
5400  }
5401 
5402  ps << PP::nbsp << PPExtString(getSymOpName(op));
5403 
5404  ModulePortInfo modPortInfo(cast<PortList>(moduleOp).getPortList());
5405  SmallVector<Value> instPortValues(modPortInfo.size());
5406  op.getValues(instPortValues, modPortInfo);
5407  emitInstancePortList(op, modPortInfo, instPortValues);
5408 
5409  ps.addCallback({op, false});
5410  emitLocationInfoAndNewLine(ops);
5411  if (doNotPrint) {
5412  ps << PP::end;
5413  startStatement();
5414  ps << "*/";
5415  setPendingNewline();
5416  }
5417  return success();
5418 }
5419 
5420 LogicalResult StmtEmitter::visitStmt(InstanceChoiceOp op) {
5421  startStatement();
5422  Operation *choiceMacroDeclOp = state.symbolCache.getDefinition(
5423  op->getAttrOfType<FlatSymbolRefAttr>("hw.choiceTarget"));
5424 
5425  ps << "`" << PPExtString(getSymOpName(choiceMacroDeclOp)) << PP::nbsp
5426  << PPExtString(getSymOpName(op));
5427 
5428  Operation *defaultModuleOp =
5429  state.symbolCache.getDefinition(op.getDefaultModuleNameAttr());
5430  ModulePortInfo modPortInfo(cast<PortList>(defaultModuleOp).getPortList());
5431  SmallVector<Value> instPortValues(modPortInfo.size());
5432  op.getValues(instPortValues, modPortInfo);
5433  emitInstancePortList(op, modPortInfo, instPortValues);
5434 
5435  SmallPtrSet<Operation *, 8> ops;
5436  ops.insert(op);
5437  ps.addCallback({op, false});
5438  emitLocationInfoAndNewLine(ops);
5439 
5440  return success();
5441 }
5442 
5443 void StmtEmitter::emitInstancePortList(Operation *op,
5444  ModulePortInfo &modPortInfo,
5445  ArrayRef<Value> instPortValues) {
5446  SmallPtrSet<Operation *, 8> ops;
5447  ops.insert(op);
5448 
5449  auto containingModule = cast<HWModuleOp>(emitter.currentModuleOp);
5450  ModulePortInfo containingPortList(containingModule.getPortList());
5451 
5452  ps << " (";
5453 
5454  // Get the max port name length so we can align the '('.
5455  size_t maxNameLength = 0;
5456  for (auto &elt : modPortInfo) {
5457  maxNameLength = std::max(maxNameLength, elt.getVerilogName().size());
5458  }
5459 
5460  auto getWireForValue = [&](Value result) {
5461  return result.getUsers().begin()->getOperand(0);
5462  };
5463 
5464  // Emit the argument and result ports.
5465  bool isFirst = true; // True until we print a port.
5466  bool isZeroWidth = false;
5467 
5468  for (size_t portNum = 0, portEnd = modPortInfo.size(); portNum < portEnd;
5469  ++portNum) {
5470  auto &modPort = modPortInfo.at(portNum);
5471  isZeroWidth = isZeroBitType(modPort.type);
5472  Value portVal = instPortValues[portNum];
5473 
5474  // Decide if we should print a comma. We can't do this if we're the first
5475  // port or if all the subsequent ports are zero width.
5476  if (!isFirst) {
5477  bool shouldPrintComma = true;
5478  if (isZeroWidth) {
5479  shouldPrintComma = false;
5480  for (size_t i = portNum + 1, e = modPortInfo.size(); i != e; ++i)
5481  if (!isZeroBitType(modPortInfo.at(i).type)) {
5482  shouldPrintComma = true;
5483  break;
5484  }
5485  }
5486 
5487  if (shouldPrintComma)
5488  ps << ",";
5489  }
5490  emitLocationInfoAndNewLine(ops);
5491 
5492  // Emit the port's name.
5493  startStatement();
5494  if (!isZeroWidth) {
5495  // If this is a real port we're printing, then it isn't the first one. Any
5496  // subsequent ones will need a comma.
5497  isFirst = false;
5498  ps << " ";
5499  } else {
5500  // We comment out zero width ports, so their presence and initializer
5501  // expressions are still emitted textually.
5502  ps << "//";
5503  }
5504 
5505  ps.scopedBox(isZeroWidth ? PP::neverbox : PP::ibox2, [&]() {
5506  auto modPortName = modPort.getVerilogName();
5507  ps << "." << PPExtString(modPortName);
5508  ps.spaces(maxNameLength - modPortName.size() + 1);
5509  ps << "(";
5510  ps.scopedBox(PP::ibox0, [&]() {
5511  // Emit the value as an expression.
5512  ops.clear();
5513 
5514  // Output ports that are not connected to single use output ports were
5515  // lowered to wire.
5516  OutputOp output;
5517  if (!modPort.isOutput()) {
5518  if (isZeroWidth &&
5519  isa_and_nonnull<ConstantOp>(portVal.getDefiningOp()))
5520  ps << "/* Zero width */";
5521  else
5522  emitExpression(portVal, ops, LowestPrecedence);
5523  } else if (portVal.use_empty()) {
5524  ps << "/* unused */";
5525  } else if (portVal.hasOneUse() &&
5526  (output = dyn_cast_or_null<OutputOp>(
5527  portVal.getUses().begin()->getOwner()))) {
5528  // If this is directly using the output port of the containing module,
5529  // just specify that directly so we avoid a temporary wire.
5530  // Keep this synchronized with countStatements() and
5531  // visitStmt(OutputOp).
5532  size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
5533  ps << PPExtString(
5534  containingPortList.atOutput(outputPortNo).getVerilogName());
5535  } else {
5536  portVal = getWireForValue(portVal);
5537  emitExpression(portVal, ops);
5538  }
5539  ps << ")";
5540  });
5541  });
5542  }
5543  if (!isFirst || isZeroWidth) {
5544  emitLocationInfoAndNewLine(ops);
5545  ops.clear();
5546  startStatement();
5547  }
5548  ps << ");";
5549 }
5550 
5551 // This may be called in the top-level, not just in an hw.module. Thus we can't
5552 // use the name map to find expression names for arguments to the instance, nor
5553 // do we need to emit subexpressions. Prepare pass, which has run for all
5554 // modules prior to this, has ensured that all arguments are bound to wires,
5555 // regs, or ports, with legalized names, so we can lookup up the names through
5556 // the IR.
5557 LogicalResult StmtEmitter::visitSV(BindOp op) {
5558  emitter.emitBind(op);
5559  assert(state.pendingNewline);
5560  return success();
5561 }
5562 
5563 LogicalResult StmtEmitter::visitSV(InterfaceOp op) {
5564  emitComment(op.getCommentAttr());
5565  // Emit SV attributes.
5566  emitSVAttributes(op);
5567  // TODO: source info!
5568  startStatement();
5569  ps.addCallback({op, true});
5570  ps << "interface " << PPExtString(getSymOpName(op)) << ";";
5571  setPendingNewline();
5572  // FIXME: Don't emit the body of this as general statements, they aren't!
5573  emitStatementBlock(*op.getBodyBlock());
5574  startStatement();
5575  ps << "endinterface" << PP::newline;
5576  ps.addCallback({op, false});
5577  setPendingNewline();
5578  return success();
5579 }
5580 
5581 LogicalResult StmtEmitter::visitSV(InterfaceSignalOp op) {
5582  // Emit SV attributes.
5583  emitSVAttributes(op);
5584  startStatement();
5585  ps.addCallback({op, true});
5586  if (isZeroBitType(op.getType()))
5587  ps << PP::neverbox << "// ";
5588  ps.invokeWithStringOS([&](auto &os) {
5589  emitter.printPackedType(stripUnpackedTypes(op.getType()), os, op->getLoc(),
5590  Type(), false);
5591  });
5592  ps << PP::nbsp << PPExtString(getSymOpName(op));
5593  ps.invokeWithStringOS(
5594  [&](auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
5595  ps << ";";
5596  if (isZeroBitType(op.getType()))
5597  ps << PP::end; // Close never-break group.
5598  ps.addCallback({op, false});
5599  setPendingNewline();
5600  return success();
5601 }
5602 
5603 LogicalResult StmtEmitter::visitSV(InterfaceModportOp op) {
5604  startStatement();
5605  ps.addCallback({op, true});
5606  ps << "modport " << PPExtString(getSymOpName(op)) << "(";
5607 
5608  // TODO: revisit, better breaks/grouping.
5609  llvm::interleaveComma(op.getPorts(), ps, [&](const Attribute &portAttr) {
5610  auto port = cast<ModportStructAttr>(portAttr);
5611  ps << PPExtString(stringifyEnum(port.getDirection().getValue())) << " ";
5612  auto *signalDecl = state.symbolCache.getDefinition(port.getSignal());
5613  ps << PPExtString(getSymOpName(signalDecl));
5614  });
5615 
5616  ps << ");";
5617  ps.addCallback({op, false});
5618  setPendingNewline();
5619  return success();
5620 }
5621 
5622 LogicalResult StmtEmitter::visitSV(AssignInterfaceSignalOp op) {
5623  startStatement();
5624  ps.addCallback({op, true});
5625  SmallPtrSet<Operation *, 8> emitted;
5626  // TODO: emit like emitAssignLike does, maybe refactor.
5627  ps << "assign ";
5628  emitExpression(op.getIface(), emitted);
5629  ps << "." << PPExtString(op.getSignalName()) << " = ";
5630  emitExpression(op.getRhs(), emitted);
5631  ps << ";";
5632  ps.addCallback({op, false});
5633  setPendingNewline();
5634  return success();
5635 }
5636 
5637 LogicalResult StmtEmitter::visitSV(MacroDefOp op) {
5638  auto decl = op.getReferencedMacro(&state.symbolCache);
5639  // TODO: source info!
5640  startStatement();
5641  ps.addCallback({op, true});
5642  ps << "`define " << PPExtString(getSymOpName(decl));
5643  if (decl.getArgs()) {
5644  ps << "(";
5645  llvm::interleaveComma(*decl.getArgs(), ps, [&](const Attribute &name) {
5646  ps << cast<StringAttr>(name);
5647  });
5648  ps << ")";
5649  }
5650  if (!op.getFormatString().empty()) {
5651  ps << " ";
5652  emitTextWithSubstitutions(ps, op.getFormatString(), op, {},
5653  op.getSymbols());
5654  }
5655  ps.addCallback({op, false});
5656  setPendingNewline();
5657  return success();
5658 }
5659 
5660 void StmtEmitter::emitStatement(Operation *op) {
5661  // Expressions may either be ignored or emitted as an expression statements.
5662  if (isVerilogExpression(op))
5663  return;
5664 
5665  // Ignore LTL expressions as they are emitted as part of verification
5666  // statements. Ignore debug ops as they are emitted as part of debug info.
5667  if (isa<ltl::LTLDialect, debug::DebugDialect>(op->getDialect()))
5668  return;
5669 
5670  // Handle HW statements, SV statements.
5671  if (succeeded(dispatchStmtVisitor(op)) || succeeded(dispatchSVVisitor(op)) ||
5672  succeeded(dispatchVerifVisitor(op)))
5673  return;
5674 
5675  emitOpError(op, "emission to Verilog not supported");
5676  emitPendingNewlineIfNeeded();
5677  ps << "unknown MLIR operation " << PPExtString(op->getName().getStringRef());
5678  setPendingNewline();
5679 }
5680 
5681 /// Given an operation corresponding to a VerilogExpression, determine whether
5682 /// it is safe to emit inline into a 'localparam' or 'automatic logic' varaible
5683 /// initializer in a procedural region.
5684 ///
5685 /// We can't emit exprs inline when they refer to something else that can't be
5686 /// emitted inline, when they're in a general #ifdef region,
5687 static bool
5689  StmtEmitter &stmtEmitter) {
5690  if (!isVerilogExpression(op))
5691  return false;
5692 
5693  // If the expression exists in an #ifdef region, then bail. Emitting it
5694  // inline would cause it to be executed unconditionally, because the
5695  // declarations are outside the #ifdef.
5696  if (isa<IfDefProceduralOp>(op->getParentOp()))
5697  return false;
5698 
5699  // This expression tree can be emitted into the initializer if all leaf
5700  // references are safe to refer to from here. They are only safe if they are
5701  // defined in an enclosing scope (guaranteed to already be live by now) or if
5702  // they are defined in this block and already emitted to an inline automatic
5703  // logic variable.
5704  SmallVector<Value, 8> exprsToScan(op->getOperands());
5705 
5706  // This loop is guaranteed to terminate because we're only scanning up
5707  // single-use expressions and other things that 'isExpressionEmittedInline'
5708  // returns success for. Cycles won't get in here.
5709  while (!exprsToScan.empty()) {
5710  Operation *expr = exprsToScan.pop_back_val().getDefiningOp();
5711  if (!expr)
5712  continue; // Ports are always safe to reference.
5713 
5714  // If this is an inout op, check that its inout op has no blocking
5715  // assignment. A register or logic might be mutated by a blocking assignment
5716  // so it is not always safe to inline.
5717  if (auto readInout = dyn_cast<sv::ReadInOutOp>(expr)) {
5718  auto *defOp = readInout.getOperand().getDefiningOp();
5719 
5720  // If it is a read from an inout port, it's unsafe to inline in general.
5721  if (!defOp)
5722  return false;
5723 
5724  // If the operand is a wire, it's OK to inline the read.
5725  if (isa<sv::WireOp>(defOp))
5726  continue;
5727 
5728  // Reject struct_field_inout/array_index_inout for now because it's
5729  // necessary to consider aliasing inout operations.
5730  if (!isa<RegOp, LogicOp>(defOp))
5731  return false;
5732 
5733  // It's safe to inline if all users are read op, passign or assign.
5734  // If the op is a logic op whose single assignment is inlined into
5735  // declaration, we can inline the read.
5736  if (isa<LogicOp>(defOp) &&
5737  stmtEmitter.emitter.expressionsEmittedIntoDecl.count(defOp))
5738  continue;
5739 
5740  // Check that it's safe for all users to be inlined.
5741  if (llvm::all_of(defOp->getResult(0).getUsers(), [&](Operation *op) {
5742  return isa<ReadInOutOp, PAssignOp, AssignOp>(op);
5743  }))
5744  continue;
5745  return false;
5746  }
5747 
5748  // If this is an internal node in the expression tree, process its operands.
5749  if (isExpressionEmittedInline(expr, stmtEmitter.state.options)) {
5750  exprsToScan.append(expr->getOperands().begin(),
5751  expr->getOperands().end());
5752  continue;
5753  }
5754 
5755  // Otherwise, this isn't an inlinable expression. If it is defined outside
5756  // this block, then it is live-in.
5757  if (expr->getBlock() != op->getBlock())
5758  continue;
5759 
5760  // Otherwise, if it is defined in this block then it is only ok to reference
5761  // if it has already been emitted into an automatic logic.
5762  if (!stmtEmitter.emitter.expressionsEmittedIntoDecl.count(expr))
5763  return false;
5764  }
5765 
5766  return true;
5767 }
5768 
5769 template <class AssignTy>
5770 static AssignTy getSingleAssignAndCheckUsers(Operation *op) {
5771  AssignTy singleAssign;
5772  if (llvm::all_of(op->getUsers(), [&](Operation *user) {
5773  if (hasSVAttributes(user))
5774  return false;
5775 
5776  if (auto assign = dyn_cast<AssignTy>(user)) {
5777  if (singleAssign)
5778  return false;
5779  singleAssign = assign;
5780  return true;
5781  }
5782 
5783  return isa<ReadInOutOp>(user);
5784  }))
5785  return singleAssign;
5786  return {};
5787 }
5788 
5789 /// Return true if `op1` dominates users of `op2`.
5790 static bool checkDominanceOfUsers(Operation *op1, Operation *op2) {
5791  return llvm::all_of(op2->getUsers(), [&](Operation *user) {
5792  /// TODO: Use MLIR DominanceInfo.
5793 
5794  // If the op1 and op2 are in different blocks, conservatively return false.
5795  if (op1->getBlock() != user->getBlock())
5796  return false;
5797 
5798  if (op1 == user)
5799  return true;
5800 
5801  return op1->isBeforeInBlock(user);
5802  });
5803 }
5804 
5805 LogicalResult StmtEmitter::emitDeclaration(Operation *op) {
5806  emitSVAttributes(op);
5807  auto value = op->getResult(0);
5808  SmallPtrSet<Operation *, 8> opsForLocation;
5809  opsForLocation.insert(op);
5810  startStatement();
5811  ps.addCallback({op, true});
5812 
5813  // Emit the leading word, like 'wire', 'reg' or 'logic'.
5814  auto type = value.getType();
5815  auto word = getVerilogDeclWord(op, emitter);
5816  auto isZeroBit = isZeroBitType(type);
5817  ps.scopedBox(isZeroBit ? PP::neverbox : PP::ibox2, [&]() {
5818  unsigned targetColumn = 0;
5819  unsigned column = 0;
5820 
5821  // Emit the declaration keyword.
5822  if (maxDeclNameWidth > 0)
5823  targetColumn += maxDeclNameWidth + 1;
5824 
5825  if (isZeroBit) {
5826  ps << "// Zero width: " << PPExtString(word) << PP::space;
5827  } else if (!word.empty()) {
5828  ps << PPExtString(word);
5829  column += word.size();
5830  unsigned numSpaces = targetColumn > column ? targetColumn - column : 1;
5831  ps.spaces(numSpaces);
5832  column += numSpaces;
5833  }
5834 
5835  SmallString<8> typeString;
5836  // Convert the port's type to a string and measure it.
5837  {
5838  llvm::raw_svector_ostream stringStream(typeString);
5839  emitter.printPackedType(stripUnpackedTypes(type), stringStream,
5840  op->getLoc());
5841  }
5842  // Emit the type.
5843  if (maxTypeWidth > 0)
5844  targetColumn += maxTypeWidth + 1;
5845  unsigned numSpaces = 0;
5846  if (!typeString.empty()) {
5847  ps << typeString;
5848  column += typeString.size();
5849  ++numSpaces;
5850  }
5851  if (targetColumn > column)
5852  numSpaces = targetColumn - column;
5853  ps.spaces(numSpaces);
5854  column += numSpaces;
5855 
5856  // Emit the name.
5857  ps << PPExtString(getSymOpName(op));
5858 
5859  // Print out any array subscripts or other post-name stuff.
5860  ps.invokeWithStringOS(
5861  [&](auto &os) { emitter.printUnpackedTypePostfix(type, os); });
5862 
5863  // Print debug info.
5864  if (state.options.printDebugInfo) {
5865  if (auto innerSymOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
5866  auto innerSym = innerSymOp.getInnerSymAttr();
5867  if (innerSym && !innerSym.empty()) {
5868  ps << " /* ";
5869  ps.invokeWithStringOS([&](auto &os) { os << innerSym; });
5870  ps << " */";
5871  }
5872  }
5873  }
5874 
5875  if (auto localparam = dyn_cast<LocalParamOp>(op)) {
5876  ps << PP::space << "=" << PP::space;
5877  ps.invokeWithStringOS([&](auto &os) {
5878  emitter.printParamValue(localparam.getValue(), os, [&]() {
5879  return op->emitOpError("invalid localparam value");
5880  });
5881  });
5882  }
5883 
5884  if (auto regOp = dyn_cast<RegOp>(op)) {
5885  if (auto initValue = regOp.getInit()) {
5886  ps << PP::space << "=" << PP::space;
5887  ps.scopedBox(PP::ibox0, [&]() {
5888  emitExpression(initValue, opsForLocation, LowestPrecedence,
5889  /*isAssignmentLikeContext=*/true);
5890  });
5891  }
5892  }
5893 
5894  // Try inlining an assignment into declarations.
5895  // FIXME: Unpacked array is not inlined since several tools doesn't support
5896  // that syntax. See Issue 6363.
5897  if (isa<sv::WireOp, LogicOp>(op) &&
5898  !op->getParentOp()->hasTrait<ProceduralRegion>() &&
5899  !hasLeadingUnpackedType(op->getResult(0).getType())) {
5900  // Get a single assignments if any.
5901  if (auto singleAssign = getSingleAssignAndCheckUsers<AssignOp>(op)) {
5902  auto *source = singleAssign.getSrc().getDefiningOp();
5903  // Check that the source value is OK to inline in the current emission
5904  // point. A port or constant is fine, otherwise check that the assign is
5905  // next to the operation.
5906  if (!source || isa<ConstantOp>(source) ||
5907  op->getNextNode() == singleAssign) {
5908  ps << PP::space << "=" << PP::space;
5909  ps.scopedBox(PP::ibox0, [&]() {
5910  emitExpression(singleAssign.getSrc(), opsForLocation,
5911  LowestPrecedence,
5912  /*isAssignmentLikeContext=*/true);
5913  });
5914  emitter.assignsInlined.insert(singleAssign);
5915  }
5916  }
5917  }
5918 
5919  // Try inlining a blocking assignment to logic op declaration.
5920  // FIXME: Unpacked array is not inlined since several tools doesn't support
5921  // that syntax. See Issue 6363.
5922  if (isa<LogicOp>(op) && op->getParentOp()->hasTrait<ProceduralRegion>() &&
5923  !hasLeadingUnpackedType(op->getResult(0).getType())) {
5924  // Get a single assignment which might be possible to inline.
5925  if (auto singleAssign = getSingleAssignAndCheckUsers<BPAssignOp>(op)) {
5926  // It is necessary for the assignment to dominate users of the op.
5927  if (checkDominanceOfUsers(singleAssign, op)) {
5928  auto *source = singleAssign.getSrc().getDefiningOp();
5929  // A port or constant can be inlined at everywhere. Otherwise, check
5930  // the validity by
5931  // `isExpressionEmittedInlineIntoProceduralDeclaration`.
5932  if (!source || isa<ConstantOp>(source) ||
5934  *this)) {
5935  ps << PP::space << "=" << PP::space;
5936  ps.scopedBox(PP::ibox0, [&]() {
5937  emitExpression(singleAssign.getSrc(), opsForLocation,
5938  LowestPrecedence,
5939  /*isAssignmentLikeContext=*/true);
5940  });
5941  // Remember that the assignment and logic op are emitted into decl.
5942  emitter.assignsInlined.insert(singleAssign);
5943  emitter.expressionsEmittedIntoDecl.insert(op);
5944  }
5945  }
5946  }
5947  }
5948  ps << ";";
5949  });
5950  ps.addCallback({op, false});
5951  emitLocationInfoAndNewLine(opsForLocation);
5952  return success();
5953 }
5954 
5955 void StmtEmitter::collectNamesAndCalculateDeclarationWidths(Block &block) {
5956  // In the first pass, we fill in the symbol table, calculate the max width
5957  // of the declaration words and the max type width.
5958  NameCollector collector(emitter);
5959  collector.collectNames(block);
5960 
5961  // Record maxDeclNameWidth and maxTypeWidth in the current scope.
5962  maxDeclNameWidth = collector.getMaxDeclNameWidth();
5963  maxTypeWidth = collector.getMaxTypeWidth();
5964 }
5965 
5966 void StmtEmitter::emitStatementBlock(Block &body) {
5967  ps.scopedBox(PP::bbox2, [&]() {
5968  // Ensure decl alignment values are preserved after the block is emitted.
5969  // These values were computed for and from all declarations in the current
5970  // block (before/after this nested block), so be sure they're restored
5971  // and not overwritten by the declaration alignment within the block.
5972  llvm::SaveAndRestore<size_t> x(maxDeclNameWidth);
5973  llvm::SaveAndRestore<size_t> x2(maxTypeWidth);
5974 
5975  // Build up the symbol table for all of the values that need names in the
5976  // module. #ifdef's in procedural regions are special because local
5977  // variables are all emitted at the top of their enclosing blocks.
5978  if (!isa<IfDefProceduralOp>(body.getParentOp()))
5979  collectNamesAndCalculateDeclarationWidths(body);
5980 
5981  // Emit the body.
5982  for (auto &op : body) {
5983  emitStatement(&op);
5984  }
5985  });
5986 }
5987 // NOLINTEND(misc-no-recursion)
5988 
5989 void ModuleEmitter::emitStatement(Operation *op) {
5990  StmtEmitter(*this, state.options).emitStatement(op);
5991 }
5992 
5993 /// Emit SystemVerilog attributes attached to the expression op as dialect
5994 /// attributes.
5995 void ModuleEmitter::emitSVAttributes(Operation *op) {
5996  // SystemVerilog 2017 Section 5.12.
5997  auto svAttrs = getSVAttributes(op);
5998  if (!svAttrs)
5999  return;
6000 
6001  startStatement(); // For attributes.
6002  emitSVAttributesImpl(ps, svAttrs, /*mayBreak=*/true);
6003  setPendingNewline();
6004 }
6005 
6006 //===----------------------------------------------------------------------===//
6007 // Module Driver
6008 //===----------------------------------------------------------------------===//
6009 
6010 void ModuleEmitter::emitHWGeneratedModule(HWModuleGeneratedOp module) {
6011  auto verilogName = module.getVerilogModuleNameAttr();
6012  startStatement();
6013  ps << "// external generated module " << PPExtString(verilogName.getValue())
6014  << PP::newline;
6015  setPendingNewline();
6016 }
6017 
6018 // This may be called in the top-level, not just in an hw.module. Thus we can't
6019 // use the name map to find expression names for arguments to the instance, nor
6020 // do we need to emit subexpressions. Prepare pass, which has run for all
6021 // modules prior to this, has ensured that all arguments are bound to wires,
6022 // regs, or ports, with legalized names, so we can lookup up the names through
6023 // the IR.
6024 void ModuleEmitter::emitBind(BindOp op) {
6025  if (hasSVAttributes(op))
6026  emitError(op, "SV attributes emission is unimplemented for the op");
6027  InstanceOp inst = op.getReferencedInstance(&state.symbolCache);
6028 
6029  HWModuleOp parentMod = inst->getParentOfType<hw::HWModuleOp>();
6030  ModulePortInfo parentPortList(parentMod.getPortList());
6031  auto parentVerilogName = getVerilogModuleNameAttr(parentMod);
6032 
6033  Operation *childMod =
6034  state.symbolCache.getDefinition(inst.getReferencedModuleNameAttr());
6035  auto childVerilogName = getVerilogModuleNameAttr(childMod);
6036 
6037  startStatement();
6038  ps.addCallback({op, true});
6039  ps << "bind " << PPExtString(parentVerilogName.getValue()) << PP::nbsp
6040  << PPExtString(childVerilogName.getValue()) << PP::nbsp
6041  << PPExtString(getSymOpName(inst)) << " (";
6042  bool isFirst = true; // True until we print a port.
6043  ps.scopedBox(PP::bbox2, [&]() {
6044  auto parentPortInfo = parentMod.getPortList();
6045  ModulePortInfo childPortInfo(cast<PortList>(childMod).getPortList());
6046 
6047  // Get the max port name length so we can align the '('.
6048  size_t maxNameLength = 0;
6049  for (auto &elt : childPortInfo) {
6050  auto portName = elt.getVerilogName();
6051  elt.name = Builder(inst.getContext()).getStringAttr(portName);
6052  maxNameLength = std::max(maxNameLength, elt.getName().size());
6053  }
6054 
6055  SmallVector<Value> instPortValues(childPortInfo.size());
6056  inst.getValues(instPortValues, childPortInfo);
6057  // Emit the argument and result ports.
6058  for (auto [idx, elt] : llvm::enumerate(childPortInfo)) {
6059  // Figure out which value we are emitting.
6060  Value portVal = instPortValues[idx];
6061  bool isZeroWidth = isZeroBitType(elt.type);
6062 
6063  // Decide if we should print a comma. We can't do this if we're the
6064  // first port or if all the subsequent ports are zero width.
6065  if (!isFirst) {
6066  bool shouldPrintComma = true;
6067  if (isZeroWidth) {
6068  shouldPrintComma = false;
6069  for (size_t i = idx + 1, e = childPortInfo.size(); i != e; ++i)
6070  if (!isZeroBitType(childPortInfo.at(i).type)) {
6071  shouldPrintComma = true;
6072  break;
6073  }
6074  }
6075 
6076  if (shouldPrintComma)
6077  ps << ",";
6078  }
6079  ps << PP::newline;
6080 
6081  // Emit the port's name.
6082  if (!isZeroWidth) {
6083  // If this is a real port we're printing, then it isn't the first
6084  // one. Any subsequent ones will need a comma.
6085  isFirst = false;
6086  } else {
6087  // We comment out zero width ports, so their presence and
6088  // initializer expressions are still emitted textually.
6089  ps << PP::neverbox << "//";
6090  }
6091 
6092  ps << "." << PPExtString(elt.getName());
6093  ps.nbsp(maxNameLength - elt.getName().size());
6094  ps << " (";
6095  llvm::SmallPtrSet<Operation *, 4> ops;
6096  if (elt.isOutput()) {
6097  assert((portVal.hasOneUse() || portVal.use_empty()) &&
6098  "output port must have either single or no use");
6099  if (portVal.use_empty()) {
6100  ps << "/* unused */";
6101  } else if (auto output = dyn_cast_or_null<OutputOp>(
6102  portVal.getUses().begin()->getOwner())) {
6103  // If this is directly using the output port of the containing
6104  // module, just specify that directly.
6105  size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
6106  ps << PPExtString(
6107  parentPortList.atOutput(outputPortNo).getVerilogName());
6108  } else {
6109  portVal = portVal.getUsers().begin()->getOperand(0);
6110  ExprEmitter(*this, ops)
6111  .emitExpression(portVal, LowestPrecedence,
6112  /*isAssignmentLikeContext=*/false);
6113  }
6114  } else {
6115  ExprEmitter(*this, ops)
6116  .emitExpression(portVal, LowestPrecedence,
6117  /*isAssignmentLikeContext=*/false);
6118  }
6119 
6120  ps << ")";
6121 
6122  if (isZeroWidth)
6123  ps << PP::end; // Close never-break group.
6124  }
6125  });
6126  if (!isFirst)
6127  ps << PP::newline;
6128  ps << ");";
6129  ps.addCallback({op, false});
6130  setPendingNewline();
6131 }
6132 
6133 void ModuleEmitter::emitBindInterface(BindInterfaceOp op) {
6134  if (hasSVAttributes(op))
6135  emitError(op, "SV attributes emission is unimplemented for the op");
6136 
6137  auto instance = op.getReferencedInstance(&state.symbolCache);
6138  auto instantiator = instance->getParentOfType<HWModuleOp>().getName();
6139  auto *interface = op->getParentOfType<ModuleOp>().lookupSymbol(
6140  instance.getInterfaceType().getInterface());
6141  startStatement();
6142  ps.addCallback({op, true});
6143  ps << "bind " << PPExtString(instantiator) << PP::nbsp
6144  << PPExtString(cast<InterfaceOp>(*interface).getSymName()) << PP::nbsp
6145  << PPExtString(getSymOpName(instance)) << " (.*);" << PP::newline;
6146  ps.addCallback({op, false});
6147  setPendingNewline();
6148 }
6149 
6150 void ModuleEmitter::emitParameters(Operation *module, ArrayAttr params) {
6151  if (params.empty())
6152  return;
6153 
6154  auto printParamType = [&](Type type, Attribute defaultValue,
6155  SmallString<8> &result) {
6156  result.clear();
6157  llvm::raw_svector_ostream sstream(result);
6158 
6159  // If there is a default value like "32" then just print without type at
6160  // all.
6161  if (defaultValue) {
6162  if (auto intAttr = dyn_cast<IntegerAttr>(defaultValue))
6163  if (intAttr.getValue().getBitWidth() == 32)
6164  return;
6165  if (auto fpAttr = dyn_cast<FloatAttr>(defaultValue))
6166  if (fpAttr.getType().isF64())
6167  return;
6168  }
6169  if (isa<NoneType>(type))
6170  return;
6171 
6172  // Classic Verilog parser don't allow a type in the parameter declaration.
6173  // For compatibility with them, we omit the type when it is implicit based
6174  // on its initializer value, and print the type commented out when it is
6175  // a 32-bit "integer" parameter.
6176  if (auto intType = type_dyn_cast<IntegerType>(type))
6177  if (intType.getWidth() == 32) {
6178  sstream << "/*integer*/";
6179  return;
6180  }
6181 
6182  printPackedType(type, sstream, module->getLoc(),
6183  /*optionalAliasType=*/Type(),
6184  /*implicitIntType=*/true,
6185  // Print single-bit values as explicit `[0:0]` type.
6186  /*singleBitDefaultType=*/false);
6187  };
6188 
6189  // Determine the max width of the parameter types so things are lined up.
6190  size_t maxTypeWidth = 0;
6191  SmallString<8> scratch;
6192  for (auto param : params) {
6193  auto paramAttr = cast<ParamDeclAttr>(param);
6194  // Measure the type length by printing it to a temporary string.
6195  printParamType(paramAttr.getType(), paramAttr.getValue(), scratch);
6196  maxTypeWidth = std::max(scratch.size(), maxTypeWidth);
6197  }
6198 
6199  if (maxTypeWidth > 0) // add a space if any type exists.
6200  maxTypeWidth += 1;
6201 
6202  ps.scopedBox(PP::bbox2, [&]() {
6203  ps << PP::newline << "#(";
6204  ps.scopedBox(PP::cbox0, [&]() {
6205  llvm::interleave(
6206  params,
6207  [&](Attribute param) {
6208  auto paramAttr = cast<ParamDeclAttr>(param);
6209  auto defaultValue = paramAttr.getValue(); // may be null if absent.
6210  ps << "parameter ";
6211  printParamType(paramAttr.getType(), defaultValue, scratch);
6212  if (!scratch.empty())
6213  ps << scratch;
6214  if (scratch.size() < maxTypeWidth)
6215  ps.nbsp(maxTypeWidth - scratch.size());
6216 
6217  ps << PPExtString(state.globalNames.getParameterVerilogName(
6218  module, paramAttr.getName()));
6219 
6220  if (defaultValue) {
6221  ps << " = ";
6222  ps.invokeWithStringOS([&](auto &os) {
6223  printParamValue(defaultValue, os, [&]() {
6224  return module->emitError("parameter '")
6225  << paramAttr.getName().getValue()
6226  << "' has invalid value";
6227  });
6228  });
6229  }
6230  },
6231  [&]() { ps << "," << PP::newline; });
6232  ps << ") ";
6233  });
6234  });
6235 }
6236 
6237 void ModuleEmitter::emitPortList(Operation *module,
6238  const ModulePortInfo &portInfo,
6239  bool emitAsTwoStateType) {
6240  ps << "(";
6241  if (portInfo.size())
6242  emitLocationInfo(module->getLoc());
6243 
6244  // Determine the width of the widest type we have to print so everything
6245  // lines up nicely.
6246  bool hasOutputs = false, hasZeroWidth = false;
6247  size_t maxTypeWidth = 0, lastNonZeroPort = -1;
6248  SmallVector<SmallString<8>, 16> portTypeStrings;
6249 
6250  for (size_t i = 0, e = portInfo.size(); i < e; ++i) {
6251  auto port = portInfo.at(i);
6252  hasOutputs |= port.isOutput();
6253  hasZeroWidth |= isZeroBitType(port.type);
6254  if (!isZeroBitType(port.type))
6255  lastNonZeroPort = i;
6256 
6257  // Convert the port's type to a string and measure it.
6258  portTypeStrings.push_back({});
6259  {
6260  llvm::raw_svector_ostream stringStream(portTypeStrings.back());
6261  printPackedType(stripUnpackedTypes(port.type), stringStream,
6262  module->getLoc(), {}, true, true, emitAsTwoStateType);
6263  }
6264 
6265  maxTypeWidth = std::max(portTypeStrings.back().size(), maxTypeWidth);
6266  }
6267 
6268  if (maxTypeWidth > 0) // add a space if any type exists
6269  maxTypeWidth += 1;
6270 
6271  // Emit the port list.
6272  ps.scopedBox(PP::bbox2, [&]() {
6273  for (size_t portIdx = 0, e = portInfo.size(); portIdx != e;) {
6274  auto lastPort = e - 1;
6275 
6276  ps << PP::newline;
6277  auto portType = portInfo.at(portIdx).type;
6278 
6279  // If this is a zero width type, emit the port as a comment and create a
6280  // neverbox to ensure we don't insert a line break.
6281  bool isZeroWidth = false;
6282  if (hasZeroWidth) {
6283  isZeroWidth = isZeroBitType(portType);
6284  if (isZeroWidth)
6285  ps << PP::neverbox;
6286  ps << (isZeroWidth ? "// " : " ");
6287  }
6288 
6289  // Emit the port direction.
6290  auto thisPortDirection = portInfo.at(portIdx).dir;
6291  switch (thisPortDirection) {
6293  ps << "output ";
6294  break;
6296  ps << (hasOutputs ? "input " : "input ");
6297  break;
6299  ps << (hasOutputs ? "inout " : "inout ");
6300  break;
6301  }
6302  bool emitWireInPorts = state.options.emitWireInPorts;
6303  if (emitWireInPorts)
6304  ps << "wire ";
6305 
6306  // Emit the type.
6307  if (!portTypeStrings[portIdx].empty())
6308  ps << portTypeStrings[portIdx];
6309  if (portTypeStrings[portIdx].size() < maxTypeWidth)
6310  ps.nbsp(maxTypeWidth - portTypeStrings[portIdx].size());
6311 
6312  size_t startOfNamePos =
6313  (hasOutputs ? 7 : 6) + (emitWireInPorts ? 5 : 0) + maxTypeWidth;
6314 
6315  // Emit the name.
6316  ps << PPExtString(portInfo.at(portIdx).getVerilogName());
6317 
6318  // Emit array dimensions.
6319  ps.invokeWithStringOS(
6320  [&](auto &os) { printUnpackedTypePostfix(portType, os); });
6321 
6322  // Emit the symbol.
6323  auto innerSym = portInfo.at(portIdx).getSym();
6324  if (state.options.printDebugInfo && innerSym && !innerSym.empty()) {
6325  ps << " /* ";
6326  ps.invokeWithStringOS([&](auto &os) { os << innerSym; });
6327  ps << " */";
6328  }
6329 
6330  // Emit the comma if this is not the last real port.
6331  if (portIdx != lastNonZeroPort && portIdx != lastPort)
6332  ps << ",";
6333 
6334  // Emit the location.
6335  if (auto loc = portInfo.at(portIdx).loc)
6336  emitLocationInfo(loc);
6337 
6338  if (isZeroWidth)
6339  ps << PP::end; // Close never-break group.
6340 
6341  ++portIdx;
6342 
6343  // If we have any more ports with the same types and the same
6344  // direction, emit them in a list one per line. Optionally skip this
6345  // behavior when requested by user.
6346  if (!state.options.disallowPortDeclSharing) {
6347  while (portIdx != e && portInfo.at(portIdx).dir == thisPortDirection &&
6348  stripUnpackedTypes(portType) ==
6349  stripUnpackedTypes(portInfo.at(portIdx).type)) {
6350  auto port = portInfo.at(portIdx);
6351  // Append this to the running port decl.
6352  ps << PP::newline;
6353 
6354  bool isZeroWidth = false;
6355  if (hasZeroWidth) {
6356  isZeroWidth = isZeroBitType(portType);
6357  if (isZeroWidth)
6358  ps << PP::neverbox;
6359  ps << (isZeroWidth ? "// " : " ");
6360  }
6361 
6362  ps.nbsp(startOfNamePos);
6363 
6364  // Emit the name.
6365  StringRef name = port.getVerilogName();
6366  ps << PPExtString(name);
6367 
6368  // Emit array dimensions.
6369  ps.invokeWithStringOS(
6370  [&](auto &os) { printUnpackedTypePostfix(port.type, os); });
6371 
6372  // Emit the symbol.
6373  auto sym = port.getSym();
6374  if (state.options.printDebugInfo && sym && !sym.empty())
6375  ps << " /* inner_sym: " << PPExtString(sym.getSymName().getValue())
6376  << " */";
6377 
6378  // Emit the comma if this is not the last real port.
6379  if (portIdx != lastNonZeroPort && portIdx != lastPort)
6380  ps << ",";
6381 
6382  // Emit the location.
6383  if (auto loc = port.loc)
6384  emitLocationInfo(loc);
6385 
6386  if (isZeroWidth)
6387  ps << PP::end; // Close never-break group.
6388 
6389  ++portIdx;
6390  }
6391  }
6392  }
6393  });
6394 
6395  if (!portInfo.size()) {
6396  ps << ");";
6397  SmallPtrSet<Operation *, 8> moduleOpSet;
6398  moduleOpSet.insert(module);
6399  emitLocationInfoAndNewLine(moduleOpSet);
6400  } else {
6401  ps << PP::newline;
6402  ps << ");" << PP::newline;
6403  setPendingNewline();
6404  }
6405 }
6406 
6407 void ModuleEmitter::emitHWModule(HWModuleOp module) {
6408  currentModuleOp = module;
6409 
6410  emitComment(module.getCommentAttr());
6411  emitSVAttributes(module);
6412  startStatement();
6413  ps.addCallback({module, true});
6414  ps << "module " << PPExtString(getVerilogModuleName(module));
6415 
6416  // If we have any parameters, print them on their own line.
6417  emitParameters(module, module.getParameters());
6418 
6419  emitPortList(module, ModulePortInfo(module.getPortList()));
6420 
6421  assert(state.pendingNewline);
6422 
6423  // Emit the body of the module.
6424  StmtEmitter(*this, state.options).emitStatementBlock(*module.getBodyBlock());
6425  startStatement();
6426  ps << "endmodule";
6427  ps.addCallback({module, false});
6428  ps << PP::newline;
6429  setPendingNewline();
6430 
6431  currentModuleOp = nullptr;
6432 }
6433 
6434 void ModuleEmitter::emitFunc(FuncOp func) {
6435  // Nothing to emit for a declaration.
6436  if (func.isDeclaration())
6437  return;
6438 
6439  currentModuleOp = func;
6440  startStatement();
6441  ps.addCallback({func, true});
6442  // A function is moduled as an automatic function.
6443  emitFunctionSignature(*this, ps, func, /*isAutomatic=*/true);
6444  // Emit the body of the module.
6445  StmtEmitter(*this, state.options).emitStatementBlock(*func.getBodyBlock());
6446  startStatement();
6447  ps << "endfunction";
6448  ps << PP::newline;
6449  currentModuleOp = nullptr;
6450 }
6451 
6452 //===----------------------------------------------------------------------===//
6453 // Emitter for files & file lists.
6454 //===----------------------------------------------------------------------===//
6455 
6456 class FileEmitter : public EmitterBase {
6457 public:
6458  explicit FileEmitter(VerilogEmitterState &state) : EmitterBase(state) {}
6459 
6460  void emit(emit::FileOp op) {
6461  emit(op.getBody());
6462  ps.eof();
6463  }
6464  void emit(emit::FragmentOp op) { emit(op.getBody()); }
6465  void emit(emit::FileListOp op);
6466 
6467 private:
6468  void emit(Block *block);
6469 
6470  void emitOp(emit::RefOp op);
6471  void emitOp(emit::VerbatimOp op);
6472 };
6473 
6474 void FileEmitter::emit(Block *block) {
6475  for (Operation &op : *block) {
6476  TypeSwitch<Operation *>(&op)
6477  .Case<emit::VerbatimOp, emit::RefOp>([&](auto op) { emitOp(op); })
6478  .Case<VerbatimOp, IfDefOp, MacroDefOp, sv::FuncDPIImportOp>(
6479  [&](auto op) { ModuleEmitter(state).emitStatement(op); })
6480  .Case<BindOp>([&](auto op) { ModuleEmitter(state).emitBind(op); })
6481  .Case<BindInterfaceOp>(
6482  [&](auto op) { ModuleEmitter(state).emitBindInterface(op); })
6483  .Case<TypeScopeOp>([&](auto typedecls) {
6484  ModuleEmitter(state).emitStatement(typedecls);
6485  })
6486  .Default(
6487  [&](auto op) { emitOpError(op, "cannot be emitted to a file"); });
6488  }
6489 }
6490 
6491 void FileEmitter::emit(emit::FileListOp op) {
6492  // Find the associated file ops and write the paths on individual lines.
6493  for (auto sym : op.getFiles()) {
6494  auto fileName = cast<FlatSymbolRefAttr>(sym).getAttr();
6495 
6496  auto it = state.fileMapping.find(fileName);
6497  if (it == state.fileMapping.end()) {
6498  emitOpError(op, " references an invalid file: ") << sym;
6499  continue;
6500  }
6501 
6502  auto file = cast<emit::FileOp>(it->second);
6503  ps << PP::neverbox << PPExtString(file.getFileName()) << PP::end
6504  << PP::newline;
6505  }
6506  ps.eof();
6507 }
6508 
6509 void FileEmitter::emitOp(emit::RefOp op) {
6510  StringAttr target = op.getTargetAttr().getAttr();
6511  auto *targetOp = state.symbolCache.getDefinition(target);
6512  assert(isa<emit::Emittable>(targetOp) && "target must be emittable");
6513 
6514  TypeSwitch<Operation *>(targetOp)
6515  .Case<sv::FuncOp>([&](auto func) { ModuleEmitter(state).emitFunc(func); })
6516  .Case<hw::HWModuleOp>(
6517  [&](auto module) { ModuleEmitter(state).emitHWModule(module); })
6518  .Case<TypeScopeOp>([&](auto typedecls) {
6519  ModuleEmitter(state).emitStatement(typedecls);
6520  })
6521  .Default(
6522  [&](auto op) { emitOpError(op, "cannot be emitted to a file"); });
6523 }
6524 
6525 void FileEmitter::emitOp(emit::VerbatimOp op) {
6526  startStatement();
6527 
6528  SmallPtrSet<Operation *, 8> ops;
6529  ops.insert(op);
6530 
6531  // Emit each line of the string at a time, emitting the
6532  // location comment after the last emitted line.
6533  StringRef text = op.getText();
6534 
6535  ps << PP::neverbox;
6536  do {
6537  const auto &[lhs, rhs] = text.split('\n');
6538  if (!lhs.empty())
6539  ps << PPExtString(lhs);
6540  if (!rhs.empty())
6541  ps << PP::end << PP::newline << PP::neverbox;
6542  text = rhs;
6543  } while (!text.empty());
6544  ps << PP::end;
6545 
6546  emitLocationInfoAndNewLine(ops);
6547 }
6548 
6549 //===----------------------------------------------------------------------===//
6550 // Top level "file" emitter logic
6551 //===----------------------------------------------------------------------===//
6552 
6553 /// Organize the operations in the root MLIR module into output files to be
6554 /// generated. If `separateModules` is true, a handful of top-level
6555 /// declarations will be split into separate output files even in the absence
6556 /// of an explicit output file attribute.
6557 void SharedEmitterState::gatherFiles(bool separateModules) {
6558 
6559  /// Collect all the inner names from the specified module and add them to the
6560  /// IRCache. Declarations (named things) only exist at the top level of the
6561  /// module. Also keep track of any modules that contain bind operations.
6562  /// These are non-hierarchical references which we need to be careful about
6563  /// during emission.
6564  auto collectInstanceSymbolsAndBinds = [&](Operation *moduleOp) {
6565  moduleOp->walk([&](Operation *op) {
6566  // Populate the symbolCache with all operations that can define a symbol.
6567  if (auto name = op->getAttrOfType<InnerSymAttr>(
6569  symbolCache.addDefinition(moduleOp->getAttrOfType<StringAttr>(
6570  SymbolTable::getSymbolAttrName()),
6571  name.getSymName(), op);
6572  if (isa<BindOp>(op))
6573  modulesContainingBinds.insert(moduleOp);
6574  });
6575  };
6576 
6577  /// Collect any port marked as being referenced via symbol.
6578  auto collectPorts = [&](auto moduleOp) {
6579  auto portInfo = moduleOp.getPortList();
6580  for (auto [i, p] : llvm::enumerate(portInfo)) {
6581  if (!p.attrs || p.attrs.empty())
6582  continue;
6583  for (NamedAttribute portAttr : p.attrs) {
6584  if (auto sym = dyn_cast<InnerSymAttr>(portAttr.getValue())) {
6585  symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getSymName(),
6586  moduleOp, i);
6587  }
6588  }
6589  }
6590  };
6591 
6592  // Create a mapping identifying the files each symbol is emitted to.
6593  DenseMap<StringAttr, SmallVector<emit::FileOp>> symbolsToFiles;
6594  for (auto file : designOp.getOps<emit::FileOp>())
6595  for (auto refs : file.getOps<emit::RefOp>())
6596  symbolsToFiles[refs.getTargetAttr().getAttr()].push_back(file);
6597 
6598  SmallString<32> outputPath;
6599  for (auto &op : *designOp.getBody()) {
6600  auto info = OpFileInfo{&op, replicatedOps.size()};
6601 
6602  bool isFileOp = isa<emit::FileOp, emit::FileListOp>(&op);
6603 
6604  bool hasFileName = false;
6605  bool emitReplicatedOps = !isFileOp;
6606  bool addToFilelist = !isFileOp;
6607 
6608  outputPath.clear();
6609 
6610  // Check if the operation has an explicit `output_file` attribute set. If
6611  // it does, extract the information from the attribute.
6612  auto attr = op.getAttrOfType<hw::OutputFileAttr>("output_file");
6613  if (attr) {
6614  LLVM_DEBUG(llvm::dbgs() << "Found output_file attribute " << attr
6615  << " on " << op << "\n";);
6616  if (!attr.isDirectory())
6617  hasFileName = true;
6618  appendPossiblyAbsolutePath(outputPath, attr.getFilename().getValue());
6619  emitReplicatedOps = attr.getIncludeReplicatedOps().getValue();
6620  addToFilelist = !attr.getExcludeFromFilelist().getValue();
6621  }
6622 
6623  auto separateFile = [&](Operation *op, Twine defaultFileName = "") {
6624  // If we're emitting to a separate file and the output_file attribute
6625  // didn't specify a filename, take the default one if present or emit an
6626  // error if not.
6627  if (!hasFileName) {
6628  if (!defaultFileName.isTriviallyEmpty()) {
6629  llvm::sys::path::append(outputPath, defaultFileName);
6630  } else {
6631  op->emitError("file name unspecified");
6632  encounteredError = true;
6633  llvm::sys::path::append(outputPath, "error.out");
6634  }
6635  }
6636 
6637  auto destFile = StringAttr::get(op->getContext(), outputPath);
6638  auto &file = files[destFile];
6639  file.ops.push_back(info);
6640  file.emitReplicatedOps = emitReplicatedOps;
6641  file.addToFilelist = addToFilelist;
6642  file.isVerilog = outputPath.ends_with(".sv");
6643  };
6644 
6645  // Separate the operation into dedicated output file, or emit into the
6646  // root file, or replicate in all output files.
6647  TypeSwitch<Operation *>(&op)
6648  .Case<emit::FileOp, emit::FileListOp>([&](auto file) {
6649  // Emit file ops to their respective files.
6650  fileMapping.try_emplace(file.getSymNameAttr(), file);
6651  separateFile(file, file.getFileName());
6652  })
6653  .Case<emit::FragmentOp>([&](auto fragment) {
6654  fragmentMapping.try_emplace(fragment.getSymNameAttr(), fragment);
6655  })
6656  .Case<HWModuleOp>([&](auto mod) {
6657  // Build the IR cache.
6658  auto sym = mod.getNameAttr();
6659  symbolCache.addDefinition(sym, mod);
6660  collectPorts(mod);
6661  collectInstanceSymbolsAndBinds(mod);
6662 
6663  if (auto it = symbolsToFiles.find(sym); it != symbolsToFiles.end()) {
6664  if (it->second.size() != 1 || attr) {
6665  // This is a temporary check, present as long as both
6666  // output_file and file operations are used.
6667  op.emitError("modules can be emitted to a single file");
6668  encounteredError = true;
6669  } else {
6670  // The op is not separated into a file as it will be
6671  // pulled into the unique file operation it references.
6672  }
6673  } else {
6674  // Emit into a separate file named after the module.
6675  if (attr || separateModules)
6676  separateFile(mod, getVerilogModuleName(mod) + ".sv");
6677  else
6678  rootFile.ops.push_back(info);
6679  }
6680  })
6681  .Case<InterfaceOp>([&](InterfaceOp intf) {
6682  // Build the IR cache.
6683  symbolCache.addDefinition(intf.getNameAttr(), intf);
6684  // Populate the symbolCache with all operations that can define a
6685  // symbol.
6686  for (auto &op : *intf.getBodyBlock())
6687  if (auto symOp = dyn_cast<mlir::SymbolOpInterface>(op))
6688  if (auto name = symOp.getNameAttr())
6689  symbolCache.addDefinition(name, symOp);
6690 
6691  // Emit into a separate file named after the interface.
6692  if (attr || separateModules)
6693  separateFile(intf, intf.getSymName() + ".sv");
6694  else
6695  rootFile.ops.push_back(info);
6696  })
6697  .Case<HWModuleExternOp>([&](HWModuleExternOp op) {
6698  // Build the IR cache.
6699  symbolCache.addDefinition(op.getNameAttr(), op);
6700  collectPorts(op);
6701  // External modules are _not_ emitted.
6702  })
6703  .Case<VerbatimOp, IfDefOp, MacroDefOp, FuncDPIImportOp>(
6704  [&](Operation *op) {
6705  // Emit into a separate file using the specified file name or
6706  // replicate the operation in each outputfile.
6707  if (!attr) {
6708  replicatedOps.push_back(op);
6709  } else
6710  separateFile(op, "");
6711  })
6712  .Case<FuncOp>([&](auto op) {
6713  // Emit into a separate file using the specified file name or
6714  // replicate the operation in each outputfile.
6715  if (!attr) {
6716  replicatedOps.push_back(op);
6717  } else
6718  separateFile(op, "");
6719 
6720  symbolCache.addDefinition(op.getSymNameAttr(), op);
6721  })
6722  .Case<HWGeneratorSchemaOp>([&](HWGeneratorSchemaOp schemaOp) {
6723  symbolCache.addDefinition(schemaOp.getNameAttr(), schemaOp);
6724  })
6725  .Case<HierPathOp>([&](HierPathOp hierPathOp) {
6726  symbolCache.addDefinition(hierPathOp.getSymNameAttr(), hierPathOp);
6727  })
6728  .Case<TypeScopeOp>([&](TypeScopeOp op) {
6729  symbolCache.addDefinition(op.getNameAttr(), op);
6730  // TODO: How do we want to handle typedefs in a split output?
6731  if (!attr) {
6732  replicatedOps.push_back(op);
6733  } else
6734  separateFile(op, "");
6735  })
6736  .Case<BindOp>([&](auto op) {
6737  if (!attr) {
6738  separateFile(op, "bindfile.sv");
6739  } else {
6740  separateFile(op);
6741  }
6742  })
6743  .Case<MacroDeclOp>([&](auto op) {
6744  symbolCache.addDefinition(op.getSymNameAttr(), op);
6745  })
6746  .Case<sv::ReserveNamesOp>([](auto op) {
6747  // This op was already used in gathering used names.
6748  })
6749  .Case<om::ClassLike>([&](auto op) {
6750  symbolCache.addDefinition(op.getSymNameAttr(), op);
6751  })
6752  .Case<om::ConstantOp>([&](auto op) {
6753  // Constant ops might reference symbols, skip them.
6754  })
6755  .Default([&](auto *) {
6756  op.emitError("unknown operation (SharedEmitterState::gatherFiles)");
6757  encounteredError = true;
6758  });
6759  }
6760 
6761  // We've built the whole symbol cache. Freeze it so things can start
6762  // querying it (potentially concurrently).
6763  symbolCache.freeze();
6764 }
6765 
6766 /// Given a FileInfo, collect all the replicated and designated operations
6767 /// that go into it and append them to "thingsToEmit".
6769  EmissionList &thingsToEmit,
6770  bool emitHeader) {
6771  // Include the version string comment when the file is verilog.
6772  if (file.isVerilog && !options.omitVersionComment)
6773  thingsToEmit.emplace_back(circt::getCirctVersionComment());
6774 
6775  // If we're emitting replicated ops, keep track of where we are in the list.
6776  size_t lastReplicatedOp = 0;
6777 
6778  bool emitHeaderInclude =
6779  emitHeader && file.emitReplicatedOps && !file.isHeader;
6780 
6781  if (emitHeaderInclude)
6782  thingsToEmit.emplace_back(circtHeaderInclude);
6783 
6784  size_t numReplicatedOps =
6785  file.emitReplicatedOps && !emitHeaderInclude ? replicatedOps.size() : 0;
6786 
6787  // Emit each operation in the file preceded by the replicated ops