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