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