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