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