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