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