42#include "mlir/IR/BuiltinOps.h"
43#include "mlir/IR/ImplicitLocOpBuilder.h"
44#include "mlir/IR/Location.h"
45#include "mlir/IR/Threading.h"
46#include "mlir/Interfaces/FunctionImplementation.h"
47#include "mlir/Pass/PassManager.h"
48#include "mlir/Support/FileUtilities.h"
49#include "llvm/ADT/MapVector.h"
50#include "llvm/ADT/STLExtras.h"
51#include "llvm/ADT/StringSet.h"
52#include "llvm/ADT/TypeSwitch.h"
53#include "llvm/Support/FileSystem.h"
54#include "llvm/Support/FormattedStream.h"
55#include "llvm/Support/Path.h"
56#include "llvm/Support/SaveAndRestore.h"
57#include "llvm/Support/ToolOutputFile.h"
58#include "llvm/Support/raw_ostream.h"
61#define GEN_PASS_DEF_EXPORTSPLITVERILOG
62#define GEN_PASS_DEF_EXPORTVERILOG
63#include "circt/Conversion/Passes.h.inc"
70using namespace ExportVerilog;
72using namespace pretty;
74#define DEBUG_TYPE "export-verilog"
82enum VerilogPrecedence {
103enum SubExprSignResult { IsSigned, IsUnsigned };
109 VerilogPrecedence precedence;
112 SubExprSignResult signedness;
114 SubExprInfo(VerilogPrecedence precedence, SubExprSignResult signedness)
115 : precedence(precedence), signedness(signedness) {}
125 return Builder(ctx).getI32IntegerAttr(value);
128static TypedAttr
getIntAttr(MLIRContext *ctx, Type t,
const APInt &value) {
129 return Builder(ctx).getIntegerAttr(t, value);
145 if (isa<VerbatimExprOp>(op)) {
146 if (op->getNumOperands() == 0 &&
147 op->getAttrOfType<StringAttr>(
"format_string").getValue().size() <= 32)
152 if (isa<XMRRefOp>(op))
156 if (isa<MacroRefExprOp>(op))
166 if (op->getNumOperands() == 0)
170 if (isa<comb::ExtractOp, hw::StructExtractOp, hw::UnionExtractOp>(op))
174 if (
auto array = dyn_cast<hw::ArrayGetOp>(op)) {
175 auto *indexOp = array.getIndex().getDefiningOp();
176 if (!indexOp || isa<ConstantOp>(indexOp))
178 if (
auto read = dyn_cast<ReadInOutOp>(indexOp)) {
179 auto *readSrc = read.getInput().getDefiningOp();
181 return !readSrc || isa<sv::WireOp, LogicOp>(readSrc);
196 if (
auto attr = symOp->getAttrOfType<StringAttr>(
"hw.verilogName"))
197 return attr.getValue();
198 return TypeSwitch<Operation *, StringRef>(symOp)
203 return op.getVerilogNameAttr().getValue();
205 .Case<PackageExternOp>([](PackageExternOp op) {
206 return op.getVerilogName().value_or(op.getSymName());
208 .Case<InterfaceOp>([&](InterfaceOp op) {
211 .Case<InterfaceSignalOp>(
212 [&](InterfaceSignalOp op) {
return op.getSymName(); })
213 .Case<InterfaceModportOp>(
214 [&](InterfaceModportOp op) {
return op.getSymName(); })
215 .Case<GenerateOp>([](GenerateOp op) {
return op.getSymName(); })
216 .Default([&](Operation *op) {
217 if (
auto attr = op->getAttrOfType<StringAttr>(
"name"))
218 return attr.getValue();
219 if (
auto attr = op->getAttrOfType<StringAttr>(
"instanceName"))
220 return attr.getValue();
221 if (
auto attr = op->getAttrOfType<StringAttr>(
"sv.namehint"))
222 return attr.getValue();
223 if (
auto symbol = dyn_cast<mlir::SymbolOpInterface>(op))
224 return symbol.getName();
225 return StringRef(
"");
230template <
typename PPS>
232 os <<
"/*Zero width*/ 1\'b0";
237 auto hml = cast<HWModuleLike>(module);
238 return hml.getPort(portArgNum).getVerilogName();
243 auto hml = cast<HWModuleLike>(module);
244 auto pId = hml.getHWModuleType().getPortIdForInputId(portArgNum);
245 if (
auto attrs = dyn_cast_or_null<DictionaryAttr>(hml.getPortAttrs(pId)))
246 if (
auto updatedName = attrs.getAs<StringAttr>(
"hw.verilogName"))
247 return updatedName.getValue();
248 return hml.getHWModuleType().getPortName(pId);
257 if (isa<
ReadInOutOp, AggregateConstantOp, ArrayIndexInOutOp,
258 IndexedPartSelectInOutOp, StructFieldInOutOp, IndexedPartSelectOp,
259 ParamValueOp, XMROp, XMRRefOp, SampledOp, EnumConstantOp, SFormatFOp,
260 SystemFunctionOp, STimeOp, TimeOp, UnpackedArrayCreateOp,
261 UnpackedOpenArrayCastOp, ConcatStrOp>(op))
265 if (isa<verif::ContractOp>(op))
276 SmallVectorImpl<Attribute> &dims, Type type, Location loc,
277 llvm::function_ref<mlir::InFlightDiagnostic(Location)> errorHandler) {
278 if (
auto integer = hw::type_dyn_cast<IntegerType>(type)) {
279 if (integer.getWidth() != 1)
280 dims.push_back(
getInt32Attr(type.getContext(), integer.getWidth()));
283 if (
auto array = hw::type_dyn_cast<ArrayType>(type)) {
284 dims.push_back(
getInt32Attr(type.getContext(), array.getNumElements()));
285 getTypeDims(dims, array.getElementType(), loc, errorHandler);
289 if (
auto intType = hw::type_dyn_cast<IntType>(type)) {
290 dims.push_back(intType.getWidth());
294 if (
auto inout = hw::type_dyn_cast<InOutType>(type))
295 return getTypeDims(dims, inout.getElementType(), loc, errorHandler);
296 if (
auto uarray = hw::type_dyn_cast<hw::UnpackedArrayType>(type))
297 return getTypeDims(dims, uarray.getElementType(), loc, errorHandler);
298 if (
auto uarray = hw::type_dyn_cast<sv::UnpackedOpenArrayType>(type))
299 return getTypeDims(dims, uarray.getElementType(), loc, errorHandler);
300 if (hw::type_isa<InterfaceType, StructType, EnumType, UnionType>(type))
303 errorHandler(loc) <<
"value has an unsupported verilog type " << type;
309 Type a, Type b, Location loc,
310 llvm::function_ref<mlir::InFlightDiagnostic(Location)> errorHandler) {
311 SmallVector<Attribute, 4> aDims;
314 SmallVector<Attribute, 4> bDims;
317 return aDims == bDims;
323 if (
auto intType = dyn_cast<IntegerType>(type))
324 return intType.getWidth() == 0;
325 if (
auto inout = dyn_cast<hw::InOutType>(type))
327 if (
auto var = dyn_cast<sv::VarType>(type))
329 if (
auto uarray = dyn_cast<hw::UnpackedArrayType>(type))
330 return uarray.getNumElements() == 0 ||
332 if (
auto array = dyn_cast<hw::ArrayType>(type))
333 return array.getNumElements() == 0 ||
isZeroBitType(array.getElementType());
334 if (
auto structType = dyn_cast<hw::StructType>(type))
335 return llvm::all_of(structType.getElements(),
336 [](
auto elem) { return isZeroBitType(elem.type); });
337 if (
auto enumType = dyn_cast<hw::EnumType>(type))
338 return enumType.getFields().empty();
339 if (
auto unionType = dyn_cast<hw::UnionType>(type))
340 return hw::getBitWidth(unionType) == 0;
352 return TypeSwitch<Type, Type>(type)
353 .Case<InOutType, VarType>([](
auto valueType) {
356 .Case<UnpackedArrayType, sv::UnpackedOpenArrayType>([](
auto arrayType) {
359 .Default([](Type type) {
return type; });
364 assert(isa<hw::InOutType>(type) &&
"inout type is expected");
365 auto elementType = cast<hw::InOutType>(type).getElementType();
372 return TypeSwitch<Type, bool>(type)
373 .Case<InOutType, VarType, UnpackedArrayType, ArrayType>(
374 [](
auto parentType) {
377 .Case<StructType, UnionType, EnumType, TypeAliasType>(
378 [](
auto) {
return true; })
379 .Default([](
auto) {
return false; });
393 if (
auto name = lhs.getName().compare(rhs.getName()))
395 return compareLocs(lhs.getChildLoc(), rhs.getChildLoc());
400 if (
auto fn = lhs.getFilename().compare(rhs.getFilename()))
402 if (lhs.getLine() != rhs.getLine())
403 return lhs.getLine() < rhs.getLine() ? -1 : 1;
404 return lhs.getColumn() < rhs.getColumn() ? -1 : 1;
409 Location lhsCallee = lhs.getCallee();
410 Location rhsCallee = rhs.getCallee();
414 Location lhsCaller = lhs.getCaller();
415 Location rhsCaller = rhs.getCaller();
419template <
typename TTargetLoc>
421 auto lhsT = dyn_cast<TTargetLoc>(lhs);
422 auto rhsT = dyn_cast<TTargetLoc>(rhs);
449 if (
auto res = dispatchCompareLocations<mlir::FileLineColLoc>(lhs, rhs);
454 if (
auto res = dispatchCompareLocations<mlir::NameLoc>(lhs, rhs);
459 if (
auto res = dispatchCompareLocations<mlir::CallSiteLoc>(lhs, rhs);
476 SmallPtrSetImpl<Attribute> &locationSet) {
477 llvm::TypeSwitch<Location, void>(loc)
478 .Case<FusedLoc>([&](
auto fusedLoc) {
479 for (
auto subLoc : fusedLoc.getLocations())
482 .Default([&](
auto loc) { locationSet.insert(loc); });
486template <
typename TVector>
488 llvm::array_pod_sort(
489 vec.begin(), vec.end(), [](
const auto *lhs,
const auto *rhs) ->
int {
490 return compareLocs(cast<Location>(*lhs), cast<Location>(*rhs));
498 SmallPtrSet<Attribute, 8> locationSet;
499 locationSet.insert(loc);
500 llvm::raw_string_ostream os(
output);
506 const SmallPtrSetImpl<Operation *> &ops) {
510 SmallPtrSet<Attribute, 8> locationSet;
513 llvm::raw_string_ostream os(
output);
522 const SmallPtrSetImpl<Attribute> &locationSet) {
523 if (style == LoweringOptions::LocationInfoStyle::None)
526 llvm::raw_string_ostream sstr(resstr);
528 if (resstr.empty() || style == LoweringOptions::LocationInfoStyle::Plain) {
532 assert(style == LoweringOptions::LocationInfoStyle::WrapInAtSquareBracket &&
533 "other styles must be already handled");
534 os <<
"@[" << resstr <<
"]";
543 const SmallPtrSetImpl<Attribute> &locationSet)
559 bool withName = !loc.getName().empty();
561 os <<
"'" << loc.getName().strref() <<
"'(";
570 os << loc.getFilename().getValue();
571 if (
auto line = loc.getLine()) {
573 if (
auto col = loc.getColumn())
585 StringRef lastFileName;
586 for (
size_t i = 0, e = locVector.size(); i != e;) {
591 auto first = locVector[i];
592 if (first.getFilename() != lastFileName) {
593 lastFileName = first.getFilename();
600 first.getFilename() == locVector[
end].getFilename() &&
601 first.getLine() == locVector[
end].getLine())
606 if (
auto line = first.getLine()) {
608 if (
auto col = first.getColumn())
616 os <<
':' << first.getLine() <<
":{";
618 os << locVector[i++].getColumn();
630 llvm::TypeSwitch<Location, void>(loc)
631 .Case<mlir::CallSiteLoc, mlir::NameLoc, mlir::FileLineColLoc>(
633 .Case<mlir::FusedLoc>([&](
auto loc) {
634 SmallPtrSet<Attribute, 8> locationSet;
638 .Default([&](
auto loc) {
650 switch (locationSet.size()) {
661 SmallVector<FileLineColLoc, 8> flcLocs;
662 SmallVector<Attribute, 8> otherLocs;
663 flcLocs.reserve(locationSet.size());
664 otherLocs.reserve(locationSet.size());
665 for (Attribute loc : locationSet) {
666 if (
auto flcLoc = dyn_cast<FileLineColLoc>(loc))
667 flcLocs.push_back(flcLoc);
669 otherLocs.push_back(loc);
680 size_t sstrSize =
os.tell();
681 bool emittedAnything =
false;
682 auto recheckEmittedSomething = [&]() {
683 size_t currSize =
os.tell();
684 bool emittedSomethingSinceLastCheck = currSize != sstrSize;
685 emittedAnything |= emittedSomethingSinceLastCheck;
687 return emittedSomethingSinceLastCheck;
696 if (recheckEmittedSomething()) {
698 recheckEmittedSomething();
704 if (emittedAnything && !flcLocs.empty())
709 llvm::raw_string_ostream &
os;
721 if (isa<BlockArgument>(v))
730 if (isa_and_nonnull<StructExtractOp, UnionExtractOp, ArrayGetOp>(
735 if (v.getDefiningOp<ReadInterfaceSignalOp>())
748 if (
auto cast = dyn_cast<BitcastOp>(op))
749 if (!
haveMatchingDims(cast.getInput().getType(), cast.getResult().getType(),
751 [&](Location loc) { return emitError(loc); })) {
754 if (op->hasOneUse() &&
755 isa<comb::ConcatOp, hw::ArrayConcatOp>(*op->getUsers().begin()))
763 if (isa<StructCreateOp, UnionCreateOp, UnpackedArrayCreateOp, ArrayInjectOp>(
769 if (
auto aggConstantOp = dyn_cast<AggregateConstantOp>(op))
773 if (
auto verbatim = dyn_cast<VerbatimExprOp>(op))
774 if (verbatim.getFormatString().size() > 32)
779 for (
auto &use : op->getUses()) {
780 auto *user = use.getOwner();
790 StructInjectOp, StructExplodeOp, UnionExtractOp,
791 IndexedPartSelectOp>(user))
792 if (use.getOperandNumber() == 0 &&
803 auto usedInExprControl = [user, &use]() {
804 return TypeSwitch<Operation *, bool>(user)
805 .Case<ltl::ClockOp>([&](
auto clockOp) {
807 return clockOp.getClock() == use.get();
809 .Case<sv::AssertConcurrentOp, sv::AssumeConcurrentOp,
810 sv::CoverConcurrentOp>(
811 [&](
auto op) {
return op.getClock() == use.get(); })
812 .Case<sv::AssertPropertyOp, sv::AssumePropertyOp,
813 sv::CoverPropertyOp>([&](
auto op) {
814 return op.getDisable() == use.get() || op.getClock() == use.get();
816 .Case<AlwaysOp, AlwaysFFOp>([](
auto) {
821 .Default([](
auto) {
return false; });
824 if (!usedInExprControl())
828 auto read = dyn_cast<ReadInOutOp>(op);
831 if (!isa_and_nonnull<sv::WireOp, RegOp>(read.getInput().getDefiningOp()))
842 unsigned numStatements = 0;
843 block.walk([&](Operation *op) {
845 isa_and_nonnull<ltl::LTLDialect>(op->getDialect()))
846 return WalkResult::advance();
848 TypeSwitch<Operation *, unsigned>(op)
849 .Case<VerbatimOp>([&](
auto) {
855 .Case<IfOp>([&](
auto) {
866 .Case<IfDefOp, IfDefProceduralOp>([&](
auto) {
return 3; })
867 .Case<OutputOp>([&](OutputOp oop) {
870 return llvm::count_if(oop->getOperands(), [&](
auto operand) {
871 Operation *op = operand.getDefiningOp();
872 return !operand.hasOneUse() || !op || !isa<HWInstanceLike>(op);
875 .Default([](
auto) {
return 1; });
876 if (numStatements > 1)
877 return WalkResult::interrupt();
878 return WalkResult::advance();
880 if (numStatements == 0)
882 if (numStatements == 1)
892 if (op->getResult(0).use_empty())
897 if (op->hasOneUse() &&
898 isa<hw::OutputOp, sv::AssignOp, sv::BPAssignOp, sv::PAssignOp>(
899 *op->getUsers().begin()))
921 for (
auto &op : *elseBlock) {
922 if (
auto opIf = dyn_cast<IfOp>(op)) {
939template <
typename PPS>
941 enum Container { NoContainer, InComment, InAttr };
942 Container currentContainer = NoContainer;
944 auto closeContainer = [&] {
945 if (currentContainer == NoContainer)
947 if (currentContainer == InComment)
949 else if (currentContainer == InAttr)
951 ps << PP::end << PP::end;
953 currentContainer = NoContainer;
956 bool isFirstContainer =
true;
957 auto openContainer = [&](Container newContainer) {
958 assert(newContainer != NoContainer);
959 if (currentContainer == newContainer)
963 if (!isFirstContainer)
964 ps << (mayBreak ? PP::space : PP::nbsp);
965 isFirstContainer =
false;
968 if (newContainer == InComment)
970 else if (newContainer == InAttr)
972 currentContainer = newContainer;
980 ps.scopedBox(PP::cbox0, [&]() {
981 for (
auto attr : attrs.getAsRange<SVAttributeAttr>()) {
982 if (!openContainer(attr.getEmitAsComment().getValue() ? InComment
984 ps <<
"," << (mayBreak ? PP::space : PP::nbsp);
986 if (attr.getExpression())
987 ps <<
" = " <<
PPExtString(attr.getExpression().getValue());
996 if (
auto *op = val.getDefiningOp())
999 if (
auto port = dyn_cast<BlockArgument>(val)) {
1001 auto parent = port.getParentBlock()->getParentOp();
1002 if (isa<ForOp, GenerateForOp>(parent))
1003 return parent->getAttrOfType<StringAttr>(
"hw.verilogName");
1005 port.getArgNumber());
1007 assert(
false &&
"unhandled value");
1019class VerilogEmitterState {
1021 explicit VerilogEmitterState(ModuleOp designOp,
1027 llvm::formatted_raw_ostream &os,
1028 StringAttr fileName,
OpLocMap &verilogLocMap)
1029 : designOp(designOp), shared(shared), options(options),
1030 symbolCache(symbolCache), globalNames(globalNames),
1031 fileMapping(fileMapping), os(os), verilogLocMap(verilogLocMap),
1032 pp(os, options.getEmittedLineLength().value_or(0)), fileName(fileName) {
1033 pp.setListener(&saver);
1056 llvm::formatted_raw_ostream &os;
1058 bool encounteredError =
false;
1067 bool pendingNewline =
false;
1081 StringAttr fileName;
1087 void addVerilogLocToOps(
unsigned int lineOffset, StringAttr fileName) {
1090 verilogLocMap.
clear();
1094 VerilogEmitterState(
const VerilogEmitterState &) =
delete;
1095 void operator=(
const VerilogEmitterState &) =
delete;
1108using CallbackDataTy = std::pair<Operation *, bool>;
1112 VerilogEmitterState &state;
1117 explicit EmitterBase(VerilogEmitterState &state)
1119 ps(state.pp, state.saver, state.options.emitVerilogLocations) {}
1121 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
1122 state.encounteredError =
true;
1123 return op->emitError(message);
1126 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
1127 state.encounteredError =
true;
1128 return op->emitOpError(message);
1131 InFlightDiagnostic emitError(Location loc,
const Twine &message =
"") {
1132 state.encounteredError =
true;
1133 return mlir::emitError(loc, message);
1136 void emitLocationImpl(llvm::StringRef location) {
1139 ps << PP::neverbreak;
1140 if (!location.empty())
1141 ps <<
"\t// " << location;
1144 void emitLocationInfo(Location loc) {
1152 void emitLocationInfoAndNewLine(
const SmallPtrSetImpl<Operation *> &ops) {
1155 setPendingNewline();
1158 template <
typename PPS>
1159 void emitTextWithSubstitutions(PPS &ps, StringRef
string, Operation *op,
1160 llvm::function_ref<
void(Value)> operandEmitter,
1161 ArrayAttr symAttrs);
1167 void emitComment(StringAttr comment);
1171 void emitPendingNewlineIfNeeded() {
1172 if (state.pendingNewline) {
1173 state.pendingNewline =
false;
1177 void setPendingNewline() {
1178 assert(!state.pendingNewline);
1179 state.pendingNewline =
true;
1182 void startStatement() { emitPendingNewlineIfNeeded(); }
1185 void operator=(
const EmitterBase &) =
delete;
1186 EmitterBase(
const EmitterBase &) =
delete;
1190template <
typename PPS>
1191void EmitterBase::emitTextWithSubstitutions(
1192 PPS &ps, StringRef
string, Operation *op,
1193 llvm::function_ref<
void(Value)> operandEmitter, ArrayAttr symAttrs) {
1204 if (
auto *itemOp = item.getOp()) {
1205 if (item.hasPort()) {
1209 if (!symOpName.empty())
1211 emitError(itemOp,
"cannot get name for symbol ") << sym;
1213 emitError(op,
"cannot get name for symbol ") << sym;
1215 return StringRef(
"<INVALID>");
1221 unsigned numSymOps = symAttrs.size();
1222 auto emitUntilSubstitution = [&](
size_t next = 0) ->
bool {
1225 next =
string.find(
"{{", next);
1226 if (next == StringRef::npos)
1233 while (next <
string.size() &&
isdigit(
string[next]))
1236 if (start == next) {
1240 size_t operandNoLength = next - start;
1243 StringRef fmtOptsStr;
1244 if (
string[next] ==
':') {
1245 size_t startFmtOpts = next + 1;
1246 while (next <
string.size() &&
string[next] !=
'}')
1248 fmtOptsStr =
string.substr(startFmtOpts, next - startFmtOpts);
1252 if (!
string.substr(next).starts_with(
"}}"))
1256 unsigned operandNo = 0;
1257 if (
string.drop_front(start)
1258 .take_front(operandNoLength)
1259 .getAsInteger(10, operandNo)) {
1260 emitError(op,
"operand substitution too large");
1266 auto before =
string.take_front(start - 2);
1267 if (!before.empty())
1272 if (operandNo < op->getNumOperands())
1274 operandEmitter(op->getOperand(operandNo));
1275 else if ((operandNo - op->getNumOperands()) < numSymOps) {
1276 unsigned symOpNum = operandNo - op->getNumOperands();
1277 auto sym = symAttrs[symOpNum];
1278 StringRef symVerilogName;
1279 if (
auto fsym = dyn_cast<FlatSymbolRefAttr>(sym)) {
1280 if (
auto *symOp = state.symbolCache.getDefinition(fsym)) {
1281 if (
auto globalRef = dyn_cast<HierPathOp>(symOp)) {
1282 auto namepath = globalRef.getNamepathAttr().getValue();
1283 for (
auto [index, sym] :
llvm::enumerate(namepath)) {
1286 ps << (fmtOptsStr.empty() ?
"." : fmtOptsStr);
1288 auto innerRef = cast<InnerRefAttr>(sym);
1289 auto ref = state.symbolCache.getInnerDefinition(
1290 innerRef.getModule(), innerRef.getName());
1291 ps << namify(innerRef, ref);
1294 symVerilogName = namify(sym, symOp);
1297 }
else if (
auto isym = dyn_cast<InnerRefAttr>(sym)) {
1298 auto symOp = state.symbolCache.getInnerDefinition(isym.getModule(),
1300 symVerilogName = namify(sym, symOp);
1302 if (!symVerilogName.empty())
1305 emitError(op,
"operand " + llvm::utostr(operandNo) +
" isn't valid");
1309 string =
string.drop_front(next);
1315 while (emitUntilSubstitution())
1319 if (!
string.
empty())
1323void EmitterBase::emitComment(StringAttr comment) {
1330 std::optional<size_t> lineLength = state.options.getEmittedLineLength();
1332 lineLength = std::max<size_t>(*lineLength, 3) - 3;
1336 auto ref = comment.getValue();
1338 while (!ref.empty()) {
1339 std::tie(line, ref) = ref.split(
"\n");
1346 if (!lineLength || line.size() <= lineLength) {
1348 setPendingNewline();
1359 auto breakPos = line.rfind(
' ', *lineLength);
1361 if (breakPos == StringRef::npos) {
1362 breakPos = line.find(
' ', *lineLength);
1365 if (breakPos == StringRef::npos)
1366 breakPos = line.size();
1373 setPendingNewline();
1374 breakPos = line.find_first_not_of(
' ', breakPos);
1376 if (breakPos == StringRef::npos)
1379 line = line.drop_front(breakPos);
1389 bool addPrefixUnderScore =
true;
1392 if (
auto read = expr.getDefiningOp<
ReadInOutOp>())
1396 if (
auto blockArg = dyn_cast<BlockArgument>(expr)) {
1398 cast<HWEmittableModuleLike>(blockArg.getOwner()->getParentOp());
1400 result = StringAttr::get(expr.getContext(), name);
1402 }
else if (
auto *op = expr.getDefiningOp()) {
1404 if (isa<sv::WireOp, RegOp, LogicOp>(op)) {
1406 result = StringAttr::get(expr.getContext(), name);
1408 }
else if (
auto nameHint = op->getAttrOfType<StringAttr>(
"sv.namehint")) {
1414 addPrefixUnderScore =
false;
1416 TypeSwitch<Operation *>(op)
1419 .Case([&result](VerbatimExprOp verbatim) {
1420 verbatim.getAsmResultNames([&](Value, StringRef name) {
1421 result = StringAttr::get(verbatim.getContext(), name);
1424 .Case([&result](VerbatimExprSEOp verbatim) {
1425 verbatim.getAsmResultNames([&](Value, StringRef name) {
1426 result = StringAttr::get(verbatim.getContext(), name);
1432 if (
auto operandName =
1435 cast<IntegerType>(extract.getType()).getWidth();
1437 result = StringAttr::get(extract.getContext(),
1438 operandName.strref() +
"_" +
1439 Twine(extract.getLowBit()));
1441 result = StringAttr::get(
1442 extract.getContext(),
1443 operandName.strref() +
"_" +
1444 Twine(extract.getLowBit() + numBits - 1) +
"to" +
1445 Twine(extract.getLowBit()));
1453 if (!result || result.strref().empty())
1457 if (addPrefixUnderScore && result.strref().front() !=
'_')
1458 result = StringAttr::get(expr.getContext(),
"_" + result.strref());
1470class ModuleEmitter :
public EmitterBase {
1472 explicit ModuleEmitter(VerilogEmitterState &state)
1473 : EmitterBase(state), currentModuleOp(nullptr),
1477 emitPendingNewlineIfNeeded();
1481 void emitParameters(Operation *module, ArrayAttr params);
1482 void emitPortList(Operation *module,
const ModulePortInfo &portInfo,
1483 bool emitAsTwoStateType =
false);
1486 void emitHWGeneratedModule(HWModuleGeneratedOp module);
1487 void emitFunc(FuncOp);
1490 void emitStatement(Operation *op);
1491 void emitBind(BindOp op);
1492 void emitBindInterface(BindInterfaceOp op);
1494 void emitSVAttributes(Operation *op);
1497 StringRef getVerilogStructFieldName(StringAttr field) {
1498 return fieldNameResolver.getRenamedFieldName(field).getValue();
1505 void emitTypeDims(Type type, Location loc, raw_ostream &os);
1517 bool printPackedType(Type type, raw_ostream &os, Location loc,
1518 Type optionalAliasType = {},
bool implicitIntType =
true,
1519 bool singleBitDefaultType =
true,
1520 bool emitAsTwoStateType =
false);
1524 void printUnpackedTypePostfix(Type type, raw_ostream &os);
1532 function_ref<InFlightDiagnostic()> emitError);
1535 VerilogPrecedence parenthesizeIfLooserThan,
1536 function_ref<InFlightDiagnostic()> emitError);
1542 Operation *currentModuleOp;
1543 Operation *currentPackage =
nullptr;
1549 SmallPtrSet<Operation *, 16> expressionsEmittedIntoDecl;
1555 SmallPtrSet<Operation *, 16> assignsInlined;
1566 return TypeSwitch<Type, bool>(type)
1567 .Case<UnpackedArrayType, ArrayType>(
1569 .Case<IntegerType>([](
auto) {
return false; })
1570 .Default([](
auto) {
return true; });
1577 const ModuleEmitter &emitter) {
1578 if (isa<RegOp>(op)) {
1583 cast<InOutType>(op->getResult(0).getType()).getElementType();
1586 while (
auto arrayType = hw::type_dyn_cast<UnpackedArrayType>(
elementType))
1588 while (
auto arrayType = hw::type_dyn_cast<ArrayType>(
elementType))
1591 if (isa<StructType, UnionType, EnumType, TypeAliasType>(
elementType))
1597 if (
auto var = dyn_cast<VarOp>(op)) {
1599 switch (emitter.state.options.varOpDeclStyle) {
1601 return hasExplicitType ?
"var" :
"var logic";
1603 return hasExplicitType ?
"" :
"logic";
1605 return hasExplicitType ?
"" :
"reg";
1609 if (isa<sv::WireOp>(op))
1611 if (isa<ConstantOp, AggregateConstantOp, LocalParamOp, ParamValueOp>(op))
1612 return "localparam";
1615 if (
auto interface = dyn_cast<InterfaceInstanceOp>(op))
1616 return interface.getInterfaceType().getInterface().getValue();
1624 bool stripAutomatic = isa_and_nonnull<FuncOp>(emitter.currentModuleOp);
1626 if (isa<LogicOp>(op)) {
1632 if (isProcedural && !stripAutomatic)
1633 return hasStruct ?
"automatic" :
"automatic logic";
1634 return hasStruct ?
"" :
"logic";
1641 return hasStructType(op->getResult(0).getType()) ?
"" :
"logic";
1644 assert(!emitter.state.options.disallowLocalVariables &&
1645 "automatic variables not allowed");
1649 return hasStructType(op->getResult(0).getType()) ?
"automatic"
1650 :
"automatic logic";
1657static void emitDim(Attribute width, raw_ostream &os, Location loc,
1658 ModuleEmitter &emitter,
bool downTo) {
1660 os <<
"<<invalid type>>";
1663 if (
auto intAttr = dyn_cast<IntegerAttr>(width)) {
1664 if (intAttr.getValue().isZero()) {
1665 os <<
"/*Zero Width*/";
1670 os << (intAttr.getValue().getZExtValue() - 1);
1680 auto typedAttr = dyn_cast<TypedAttr>(width);
1682 emitter.emitError(loc,
"untyped dimension attribute ") << width;
1686 getIntAttr(loc.getContext(), typedAttr.getType(),
1687 APInt(typedAttr.getType().getIntOrFloatBitWidth(), -1L,
true));
1688 width = ParamExprAttr::get(PEO::Add, typedAttr, negOne);
1692 emitter.printParamValue(width, os, [loc, &emitter]() {
1693 return emitter.emitError(loc,
"invalid parameter in type");
1701static void emitDims(ArrayRef<Attribute> dims, raw_ostream &os, Location loc,
1702 ModuleEmitter &emitter) {
1703 for (Attribute width : dims) {
1704 emitDim(width, os, loc, emitter,
true);
1709void ModuleEmitter::emitTypeDims(Type type, Location loc, raw_ostream &os) {
1710 SmallVector<Attribute, 4> dims;
1712 [&](Location loc) {
return this->emitError(loc); });
1743 SmallVectorImpl<Attribute> &dims,
1744 bool implicitIntType,
bool singleBitDefaultType,
1745 ModuleEmitter &emitter,
1746 Type optionalAliasType = {},
1747 bool emitAsTwoStateType =
false) {
1748 return TypeSwitch<Type, bool>(type)
1749 .Case<IntegerType>([&](IntegerType integerType) ->
bool {
1750 if (emitAsTwoStateType && dims.empty()) {
1752 if (!typeName.empty()) {
1757 if (integerType.getWidth() != 1 || !singleBitDefaultType)
1759 getInt32Attr(type.getContext(), integerType.getWidth()));
1761 StringRef typeName =
1762 (emitAsTwoStateType ?
"bit" : (implicitIntType ?
"" :
"logic"));
1763 if (!typeName.empty()) {
1770 return !dims.empty() || !implicitIntType;
1772 .Case<IntType>([&](IntType intType) {
1773 if (!implicitIntType)
1775 dims.push_back(intType.getWidth());
1779 .Case<ArrayType>([&](ArrayType arrayType) {
1780 dims.push_back(arrayType.getSizeAttr());
1782 implicitIntType, singleBitDefaultType,
1784 emitAsTwoStateType);
1786 .Case<InOutType>([&](InOutType inoutType) {
1788 implicitIntType, singleBitDefaultType,
1790 emitAsTwoStateType);
1792 .Case<EnumType>([&](EnumType enumType) {
1793 assert(enumType.getBitWidth().has_value() &&
1794 "enum type must have bitwidth");
1796 if (enumType.getBitWidth() != 32)
1797 os <<
"bit [" << *enumType.getBitWidth() - 1 <<
":0] ";
1799 Type enumPrefixType = optionalAliasType ? optionalAliasType : enumType;
1800 llvm::interleaveComma(
1801 enumType.getFields().getAsRange<StringAttr>(), os,
1802 [&](
auto enumerator) {
1803 os << emitter.fieldNameResolver.getEnumFieldName(
1804 hw::EnumFieldAttr::get(loc, enumerator, enumPrefixType),
1805 emitter.currentPackage);
1810 .Case<StructType>([&](StructType structType) {
1811 if (structType.getElements().empty() ||
isZeroBitType(structType)) {
1812 os <<
"/*Zero Width*/";
1815 os <<
"struct packed {";
1816 for (
auto &element : structType.getElements()) {
1818 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1819 <<
": Zero Width;*/ ";
1822 SmallVector<Attribute, 8> structDims;
1827 {}, emitAsTwoStateType);
1828 os <<
' ' << emitter.getVerilogStructFieldName(element.name);
1829 emitter.printUnpackedTypePostfix(element.type, os);
1836 .Case<UnionType>([&](UnionType unionType) {
1837 if (unionType.getElements().empty() ||
isZeroBitType(unionType)) {
1838 os <<
"/*Zero Width*/";
1842 int64_t unionWidth = hw::getBitWidth(unionType);
1844 "SV packed union must have known positive bitwidth");
1845 os <<
"union packed {";
1846 for (
auto &element : unionType.getElements()) {
1848 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1849 <<
": Zero Width;*/ ";
1852 int64_t elementWidth = hw::getBitWidth(element.type);
1855 auto elementOffset =
static_cast<int64_t
>(element.offset);
1856 bool needsPadding = elementWidth < unionWidth || elementOffset > 0;
1857 int64_t prePadding = unionWidth - (elementWidth + elementOffset);
1859 os <<
" struct packed {";
1860 if (prePadding > 0) {
1861 os << (emitAsTwoStateType ?
"bit" :
"logic") <<
" ["
1862 << prePadding - 1 <<
":0] "
1863 <<
"__pre_padding_" << element.name.getValue() <<
"; ";
1867 SmallVector<Attribute, 8> structDims;
1871 true, emitter, {}, emitAsTwoStateType);
1872 os <<
' ' << emitter.getVerilogStructFieldName(element.name);
1873 emitter.printUnpackedTypePostfix(element.type, os);
1877 if (elementOffset > 0) {
1878 os <<
" " << (emitAsTwoStateType ?
"bit" :
"logic") <<
" ["
1879 << elementOffset - 1 <<
":0] "
1880 <<
"__post_padding_" << element.name.getValue() <<
";";
1882 os <<
"} " << emitter.getVerilogStructFieldName(element.name)
1891 .Case<InterfaceType>([](InterfaceType ifaceType) {
return false; })
1892 .Case<ModportType>([&](ModportType modportType) {
1893 auto modportAttr = modportType.getModport();
1894 os << modportAttr.getRootReference().getValue() <<
"."
1895 << modportAttr.getNestedReferences().front().getValue();
1898 .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1899 os <<
"<<unexpected unpacked array>>";
1900 emitter.emitError(loc,
"Unexpected unpacked array in packed type ")
1904 .Case<TypeAliasType>([&](TypeAliasType typeRef) {
1905 auto typedecl = typeRef.getTypeDecl(emitter.state.symbolCache);
1907 emitter.emitError(loc,
"unresolvable type reference");
1910 if (typedecl.getType() != typeRef.getInnerType()) {
1911 emitter.emitError(loc,
"declared type did not match aliased type");
1915 if (
auto *package = typedecl->getParentOp();
1916 isa<PackageOp, PackageExternOp>(package)) {
1917 if (package != emitter.currentPackage)
1920 os << typedecl.getPreferredName();
1921 emitDims(dims, os, typedecl->getLoc(), emitter);
1924 .Default([&](Type type) {
1925 os <<
"<<invalid type '" << type <<
"'>>";
1926 emitter.emitError(loc,
"value has an unsupported verilog type ")
1943bool ModuleEmitter::printPackedType(Type type, raw_ostream &os, Location loc,
1944 Type optionalAliasType,
1945 bool implicitIntType,
1946 bool singleBitDefaultType,
1947 bool emitAsTwoStateType) {
1948 SmallVector<Attribute, 8> packedDimensions;
1950 singleBitDefaultType, *
this, optionalAliasType,
1951 emitAsTwoStateType);
1957void ModuleEmitter::printUnpackedTypePostfix(Type type, raw_ostream &os) {
1958 TypeSwitch<Type, void>(type)
1959 .Case<
InOutType, VarType>([&](
auto valueType) {
1960 printUnpackedTypePostfix(valueType.getElementType(), os);
1962 .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1963 auto loc = currentModuleOp ? currentModuleOp->getLoc()
1964 : state.designOp->getLoc();
1965 emitDim(arrayType.getSizeAttr(), os, loc, *
this,
1967 printUnpackedTypePostfix(arrayType.getElementType(), os);
1969 .Case<sv::UnpackedOpenArrayType>([&](
auto arrayType) {
1971 printUnpackedTypePostfix(arrayType.getElementType(), os);
1973 .Case<InterfaceType>([&](
auto) {
1987ModuleEmitter::printParamValue(Attribute value, raw_ostream &os,
1988 function_ref<InFlightDiagnostic()> emitError) {
1989 return printParamValue(value, os, VerilogPrecedence::LowestPrecedence,
1997ModuleEmitter::printParamValue(Attribute value, raw_ostream &os,
1998 VerilogPrecedence parenthesizeIfLooserThan,
1999 function_ref<InFlightDiagnostic()> emitError) {
2000 if (
auto intAttr = dyn_cast<IntegerAttr>(value)) {
2001 IntegerType intTy = cast<IntegerType>(intAttr.getType());
2002 APInt value = intAttr.getValue();
2006 if (intTy.getWidth() > 32) {
2008 if (value.isNegative() && (intTy.isSigned() || intTy.isSignless())) {
2012 if (intTy.isSigned())
2013 os << intTy.getWidth() <<
"'sd";
2015 os << intTy.getWidth() <<
"'d";
2017 value.print(os, intTy.isSigned());
2018 return {Symbol, intTy.isSigned() ? IsSigned : IsUnsigned};
2020 if (
auto strAttr = dyn_cast<StringAttr>(value)) {
2022 os.write_escaped(strAttr.getValue());
2024 return {Symbol, IsUnsigned};
2026 if (
auto fpAttr = dyn_cast<FloatAttr>(value)) {
2028 os << fpAttr.getValueAsDouble();
2029 return {Symbol, IsUnsigned};
2031 if (
auto verbatimParam = dyn_cast<ParamVerbatimAttr>(value)) {
2032 os << verbatimParam.getValue().getValue();
2033 return {Symbol, IsUnsigned};
2035 if (
auto parameterRef = dyn_cast<ParamDeclRefAttr>(value)) {
2037 os << state.globalNames.getParameterVerilogName(currentModuleOp,
2038 parameterRef.getName());
2041 return {Symbol, IsUnsigned};
2045 auto expr = dyn_cast<ParamExprAttr>(value);
2047 os <<
"<<UNKNOWN MLIRATTR: " << value <<
">>";
2048 emitError() <<
" = " << value;
2049 return {LowestPrecedence, IsUnsigned};
2052 StringRef operatorStr;
2053 StringRef openStr, closeStr;
2054 VerilogPrecedence subprecedence = LowestPrecedence;
2055 VerilogPrecedence prec;
2056 std::optional<SubExprSignResult> operandSign;
2057 bool isUnary =
false;
2058 bool hasOpenClose =
false;
2060 switch (expr.getOpcode()) {
2062 operatorStr =
" + ";
2063 subprecedence = Addition;
2066 operatorStr =
" * ";
2067 subprecedence = Multiply;
2070 operatorStr =
" & ";
2071 subprecedence = And;
2074 operatorStr =
" | ";
2078 operatorStr =
" ^ ";
2079 subprecedence = Xor;
2082 operatorStr =
" << ";
2083 subprecedence = Shift;
2087 operatorStr =
" >> ";
2088 subprecedence = Shift;
2092 operatorStr =
" >>> ";
2093 subprecedence = Shift;
2094 operandSign = IsSigned;
2097 operatorStr =
" / ";
2098 subprecedence = Multiply;
2099 operandSign = IsUnsigned;
2102 operatorStr =
" / ";
2103 subprecedence = Multiply;
2104 operandSign = IsSigned;
2107 operatorStr =
" % ";
2108 subprecedence = Multiply;
2109 operandSign = IsUnsigned;
2112 operatorStr =
" % ";
2113 subprecedence = Multiply;
2114 operandSign = IsSigned;
2117 openStr =
"$clog2(";
2119 operandSign = IsUnsigned;
2120 hasOpenClose =
true;
2123 case PEO::StrConcat:
2126 hasOpenClose =
true;
2129 subprecedence = LowestPrecedence;
2134 prec = subprecedence;
2137 assert(!isUnary || llvm::hasSingleElement(expr.getOperands()));
2139 assert(isUnary || hasOpenClose ||
2140 !llvm::hasSingleElement(expr.getOperands()));
2147 auto emitOperand = [&](Attribute operand) ->
bool {
2149 auto subprec = operandSign.has_value() ? LowestPrecedence : subprecedence;
2150 if (operandSign.has_value())
2151 os << (*operandSign == IsSigned ?
"$signed(" :
"$unsigned(");
2154 if (operandSign.has_value()) {
2156 signedness = *operandSign;
2158 return signedness == IsSigned;
2162 if (prec > parenthesizeIfLooserThan)
2171 bool allOperandsSigned = emitOperand(expr.getOperands()[0]);
2172 for (
auto op : expr.getOperands().drop_front()) {
2175 if (expr.getOpcode() == PEO::Add) {
2176 if (
auto integer = dyn_cast<IntegerAttr>(op)) {
2177 const APInt &value = integer.getValue();
2178 if (value.isNegative() && !value.isMinSignedValue()) {
2180 allOperandsSigned &=
2181 emitOperand(IntegerAttr::get(op.getType(), -value));
2188 allOperandsSigned &= emitOperand(op);
2192 if (prec > parenthesizeIfLooserThan) {
2196 return {prec, allOperandsSigned ? IsSigned : IsUnsigned};
2211class ExprEmitter :
public EmitterBase,
2213 public CombinationalVisitor<ExprEmitter, SubExprInfo>,
2218 ExprEmitter(ModuleEmitter &emitter,
2219 SmallPtrSetImpl<Operation *> &emittedExprs)
2220 : ExprEmitter(emitter, emittedExprs, localTokens) {}
2222 ExprEmitter(ModuleEmitter &emitter,
2223 SmallPtrSetImpl<Operation *> &emittedExprs,
2225 : EmitterBase(emitter.state), emitter(emitter),
2226 emittedExprs(emittedExprs), buffer(tokens),
2227 ps(buffer, state.saver, state.options.emitVerilogLocations) {
2228 assert(state.pp.getListener() == &state.saver);
2235 void emitExpression(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2236 bool isAssignmentLikeContext) {
2237 assert(localTokens.empty());
2239 ps.scopedBox(PP::ibox0, [&]() {
2242 emitSubExpr(exp, parenthesizeIfLooserThan,
2244 isAssignmentLikeContext ? RequireUnsigned : NoRequirement,
2246 isAssignmentLikeContext);
2251 if (&buffer.tokens == &localTokens)
2252 buffer.flush(state.pp);
2257 friend class CombinationalVisitor<ExprEmitter, SubExprInfo>;
2258 friend class sv::Visitor<ExprEmitter, SubExprInfo>;
2260 enum SubExprSignRequirement { NoRequirement, RequireSigned, RequireUnsigned };
2268 SubExprInfo emitSubExpr(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2269 SubExprSignRequirement signReq = NoRequirement,
2270 bool isSelfDeterminedUnsignedValue =
false,
2271 bool isAssignmentLikeContext =
false);
2275 void emitSVAttributes(Operation *op);
2277 SubExprInfo visitUnhandledExpr(Operation *op);
2278 SubExprInfo visitInvalidComb(Operation *op) {
2281 SubExprInfo visitUnhandledComb(Operation *op) {
2282 return visitUnhandledExpr(op);
2285 return dispatchSVVisitor(op);
2288 return visitUnhandledExpr(op);
2290 SubExprInfo visitUnhandledSV(Operation *op) {
return visitUnhandledExpr(op); }
2293 enum EmitBinaryFlags {
2294 EB_RequireSignedOperands = RequireSigned,
2295 EB_RequireUnsignedOperands = RequireUnsigned,
2296 EB_OperandSignRequirementMask = 0x3,
2301 EB_RHS_UnsignedWithSelfDeterminedWidth = 0x4,
2305 EB_ForceResultSigned = 0x8,
2310 SubExprInfo emitBinary(Operation *op, VerilogPrecedence prec,
2311 const char *syntax,
unsigned emitBinaryFlags = 0);
2313 SubExprInfo emitUnary(Operation *op,
const char *syntax,
2314 bool resultAlwaysUnsigned =
false);
2317 void emitSubExprIBox2(
2318 Value v, VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence) {
2319 ps.scopedBox(PP::ibox2,
2320 [&]() { emitSubExpr(v, parenthesizeIfLooserThan); });
2325 template <
typename Container,
typename EachFn>
2326 void interleaveComma(
const Container &c, EachFn eachFn) {
2327 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
2332 void interleaveComma(ValueRange ops) {
2333 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
2350 template <
typename Container,
typename OpenFunc,
typename CloseFunc,
2352 void emitBracedList(
const Container &c, OpenFunc openFn, EachFunc eachFn,
2353 CloseFunc closeFn) {
2355 ps.scopedBox(PP::cbox0, [&]() {
2356 interleaveComma(c, eachFn);
2362 template <
typename OpenFunc,
typename CloseFunc>
2363 void emitBracedList(ValueRange ops, OpenFunc openFn, CloseFunc closeFn) {
2364 return emitBracedList(
2365 ops, openFn, [&](Value v) { emitSubExprIBox2(v); }, closeFn);
2369 void emitBracedList(ValueRange ops) {
2370 return emitBracedList(
2371 ops, [&]() { ps <<
"{"; }, [&]() { ps <<
"}"; });
2375 SubExprInfo printConstantScalar(APInt &value, IntegerType type);
2378 void printConstantArray(ArrayAttr elementValues, Type
elementType,
2379 bool printAsPattern, Operation *op);
2381 void printConstantStruct(ArrayRef<hw::detail::FieldInfo> fieldInfos,
2382 ArrayAttr fieldValues,
bool printAsPattern,
2385 void printConstantAggregate(Attribute attr, Type type, Operation *op);
2387 using sv::Visitor<ExprEmitter, SubExprInfo>::visitSV;
2388 SubExprInfo visitSV(GetModportOp op);
2389 SubExprInfo visitSV(SystemFunctionOp op);
2390 SubExprInfo visitSV(ReadInterfaceSignalOp op);
2391 SubExprInfo visitSV(XMROp op);
2392 SubExprInfo visitSV(SFormatFOp op);
2393 SubExprInfo visitSV(XMRRefOp op);
2394 SubExprInfo visitVerbatimExprOp(Operation *op, ArrayAttr symbols);
2395 SubExprInfo visitSV(VerbatimExprOp op) {
2396 return visitVerbatimExprOp(op, op.getSymbols());
2398 SubExprInfo visitSV(VerbatimExprSEOp op) {
2399 return visitVerbatimExprOp(op, op.getSymbols());
2401 SubExprInfo visitSV(MacroRefExprOp op);
2402 SubExprInfo visitSV(MacroRefExprSEOp op);
2403 template <
typename MacroTy>
2404 SubExprInfo emitMacroCall(MacroTy op);
2406 SubExprInfo visitSV(ConstantXOp op);
2407 SubExprInfo visitSV(ConstantZOp op);
2408 SubExprInfo visitSV(ConstantStrOp op);
2409 SubExprInfo visitSV(ConcatStrOp op);
2411 SubExprInfo visitSV(sv::UnpackedArrayCreateOp op);
2412 SubExprInfo visitSV(sv::UnpackedOpenArrayCastOp op) {
2414 return emitSubExpr(op->getOperand(0), LowestPrecedence);
2419 auto result = emitSubExpr(op->getOperand(0), LowestPrecedence);
2420 emitSVAttributes(op);
2423 SubExprInfo visitSV(ArrayIndexInOutOp op);
2424 SubExprInfo visitSV(IndexedPartSelectInOutOp op);
2425 SubExprInfo visitSV(IndexedPartSelectOp op);
2426 SubExprInfo visitSV(StructFieldInOutOp op);
2429 SubExprInfo visitSV(SampledOp op);
2432 SubExprInfo visitSV(TimeOp op);
2433 SubExprInfo visitSV(STimeOp op);
2436 using TypeOpVisitor::visitTypeOp;
2438 SubExprInfo visitTypeOp(AggregateConstantOp op);
2440 SubExprInfo visitTypeOp(ParamValueOp op);
2447 SubExprInfo visitTypeOp(StructInjectOp op);
2448 SubExprInfo visitTypeOp(UnionCreateOp op);
2449 SubExprInfo visitTypeOp(UnionExtractOp op);
2450 SubExprInfo visitTypeOp(EnumCmpOp op);
2451 SubExprInfo visitTypeOp(EnumConstantOp op);
2454 using CombinationalVisitor::visitComb;
2455 SubExprInfo visitComb(
MuxOp op);
2456 SubExprInfo visitComb(ReverseOp op);
2457 SubExprInfo visitComb(
AddOp op) {
2458 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2459 return emitBinary(op, Addition,
"+");
2461 SubExprInfo visitComb(
SubOp op) {
return emitBinary(op, Addition,
"-"); }
2462 SubExprInfo visitComb(
MulOp op) {
2463 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2464 return emitBinary(op, Multiply,
"*");
2466 SubExprInfo visitComb(
DivUOp op) {
2467 return emitBinary(op, Multiply,
"/", EB_RequireUnsignedOperands);
2469 SubExprInfo visitComb(
DivSOp op) {
2470 return emitBinary(op, Multiply,
"/",
2471 EB_RequireSignedOperands | EB_ForceResultSigned);
2473 SubExprInfo visitComb(
ModUOp op) {
2474 return emitBinary(op, Multiply,
"%", EB_RequireUnsignedOperands);
2476 SubExprInfo visitComb(
ModSOp op) {
2477 return emitBinary(op, Multiply,
"%",
2478 EB_RequireSignedOperands | EB_ForceResultSigned);
2480 SubExprInfo visitComb(
ShlOp op) {
2481 return emitBinary(op, Shift,
"<<", EB_RHS_UnsignedWithSelfDeterminedWidth);
2483 SubExprInfo visitComb(
ShrUOp op) {
2485 return emitBinary(op, Shift,
">>", EB_RHS_UnsignedWithSelfDeterminedWidth);
2487 SubExprInfo visitComb(
ShrSOp op) {
2490 return emitBinary(op, Shift,
">>>",
2491 EB_RequireSignedOperands | EB_ForceResultSigned |
2492 EB_RHS_UnsignedWithSelfDeterminedWidth);
2494 SubExprInfo visitComb(
AndOp op) {
2495 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2496 return emitBinary(op, And,
"&");
2498 SubExprInfo visitComb(
OrOp op) {
2499 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2500 return emitBinary(op, Or,
"|");
2502 SubExprInfo visitComb(
XorOp op) {
2503 if (op.isBinaryNot())
2504 return emitUnary(op,
"~");
2505 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2506 return emitBinary(op, Xor,
"^");
2511 SubExprInfo visitComb(
ParityOp op) {
return emitUnary(op,
"^",
true); }
2513 SubExprInfo visitComb(ReplicateOp op);
2514 SubExprInfo visitComb(
ConcatOp op);
2516 SubExprInfo visitComb(ICmpOp op);
2518 InFlightDiagnostic emitAssignmentPatternContextError(Operation *op) {
2519 auto d = emitOpError(op,
"must be printed as assignment pattern, but is "
2520 "not printed within an assignment-like context");
2521 d.attachNote() <<
"this is likely a bug in PrepareForEmission, which is "
2522 "supposed to spill such expressions";
2526 SubExprInfo printStructCreate(
2527 ArrayRef<hw::detail::FieldInfo> fieldInfos,
2529 bool printAsPattern, Operation *op);
2532 ModuleEmitter &emitter;
2539 SubExprSignRequirement signPreference = NoRequirement;
2543 SmallPtrSetImpl<Operation *> &emittedExprs;
2546 SmallVector<Token> localTokens;
2560 bool isAssignmentLikeContext =
false;
2564SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
2566 unsigned emitBinaryFlags) {
2568 emitError(op,
"SV attributes emission is unimplemented for the op");
2579 if (emitBinaryFlags & EB_ForceResultSigned)
2580 ps <<
"$signed(" << PP::ibox0;
2581 auto operandSignReq =
2582 SubExprSignRequirement(emitBinaryFlags & EB_OperandSignRequirementMask);
2583 auto lhsInfo = emitSubExpr(op->getOperand(0), prec, operandSignReq);
2586 auto lhsSpace = (prec == VerilogPrecedence::Comparison ||
2587 prec == VerilogPrecedence::Equality)
2591 ps << lhsSpace << syntax << PP::nbsp;
2598 auto rhsPrec = prec;
2599 if (!isa<AddOp, MulOp, AndOp, OrOp, XorOp>(op))
2600 rhsPrec = VerilogPrecedence(prec - 1);
2605 bool rhsIsUnsignedValueWithSelfDeterminedWidth =
false;
2606 if (emitBinaryFlags & EB_RHS_UnsignedWithSelfDeterminedWidth) {
2607 rhsIsUnsignedValueWithSelfDeterminedWidth =
true;
2608 operandSignReq = NoRequirement;
2611 auto rhsInfo = emitSubExpr(op->getOperand(1), rhsPrec, operandSignReq,
2612 rhsIsUnsignedValueWithSelfDeterminedWidth);
2616 SubExprSignResult signedness = IsUnsigned;
2617 if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
2618 signedness = IsSigned;
2620 if (emitBinaryFlags & EB_ForceResultSigned) {
2621 ps << PP::end <<
")";
2622 signedness = IsSigned;
2626 return {prec, signedness};
2629SubExprInfo ExprEmitter::emitUnary(Operation *op,
const char *syntax,
2630 bool resultAlwaysUnsigned) {
2632 emitError(op,
"SV attributes emission is unimplemented for the op");
2635 auto signedness = emitSubExpr(op->getOperand(0), Selection).signedness;
2639 return {isa<ICmpOp>(op) ? LowestPrecedence : Unary,
2640 resultAlwaysUnsigned ? IsUnsigned : signedness};
2645void ExprEmitter::emitSVAttributes(Operation *op) {
2659 auto concat = value.getDefiningOp<
ConcatOp>();
2660 if (!concat || concat.getNumOperands() != 2)
2663 auto constant = concat.getOperand(0).getDefiningOp<
ConstantOp>();
2664 if (constant && constant.getValue().isZero())
2665 return concat.getOperand(1);
2675SubExprInfo ExprEmitter::emitSubExpr(Value exp,
2676 VerilogPrecedence parenthesizeIfLooserThan,
2677 SubExprSignRequirement signRequirement,
2678 bool isSelfDeterminedUnsignedValue,
2679 bool isAssignmentLikeContext) {
2681 if (
auto result = dyn_cast<OpResult>(exp))
2682 if (
auto contract = dyn_cast<verif::ContractOp>(result.getOwner()))
2683 return emitSubExpr(contract.getInputs()[result.getResultNumber()],
2684 parenthesizeIfLooserThan, signRequirement,
2685 isSelfDeterminedUnsignedValue,
2686 isAssignmentLikeContext);
2690 if (isSelfDeterminedUnsignedValue && exp.hasOneUse()) {
2695 auto *op = exp.getDefiningOp();
2699 if (!shouldEmitInlineExpr) {
2702 if (signRequirement == RequireSigned) {
2704 return {Symbol, IsSigned};
2708 return {Symbol, IsUnsigned};
2711 unsigned subExprStartIndex = buffer.tokens.size();
2713 ps.addCallback({op,
true});
2714 llvm::scope_exit done([&]() {
2716 ps.addCallback({op, false});
2722 signPreference = signRequirement;
2724 bool bitCastAdded =
false;
2725 if (state.options.explicitBitcast && isa<AddOp, MulOp, SubOp>(op))
2727 dyn_cast_or_null<IntegerType>(op->getResult(0).getType())) {
2728 ps.addAsString(inType.getWidth());
2729 ps <<
"'(" << PP::ibox0;
2730 bitCastAdded =
true;
2734 llvm::SaveAndRestore restoreALC(this->isAssignmentLikeContext,
2735 isAssignmentLikeContext);
2736 auto expInfo = dispatchCombinationalVisitor(exp.getDefiningOp());
2742 buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex,
2744 buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex, t);
2746 auto closeBoxAndParen = [&]() { ps << PP::end <<
")"; };
2747 if (signRequirement == RequireSigned && expInfo.signedness == IsUnsigned) {
2750 expInfo.signedness = IsSigned;
2751 expInfo.precedence = Selection;
2752 }
else if (signRequirement == RequireUnsigned &&
2753 expInfo.signedness == IsSigned) {
2756 expInfo.signedness = IsUnsigned;
2757 expInfo.precedence = Selection;
2758 }
else if (expInfo.precedence > parenthesizeIfLooserThan) {
2765 expInfo.precedence = Selection;
2772 emittedExprs.insert(exp.getDefiningOp());
2776SubExprInfo ExprEmitter::visitComb(ReplicateOp op) {
2777 auto openFn = [&]() {
2779 ps.addAsString(op.getMultiple());
2782 auto closeFn = [&]() { ps <<
"}}"; };
2786 if (
auto concatOp = op.getOperand().getDefiningOp<
ConcatOp>()) {
2787 if (op.getOperand().hasOneUse()) {
2788 emitBracedList(concatOp.getOperands(), openFn, closeFn);
2789 return {Symbol, IsUnsigned};
2792 emitBracedList(op.getOperand(), openFn, closeFn);
2793 return {Symbol, IsUnsigned};
2796SubExprInfo ExprEmitter::visitComb(
ConcatOp op) {
2797 emitBracedList(op.getOperands());
2798 return {Symbol, IsUnsigned};
2801SubExprInfo ExprEmitter::visitTypeOp(
BitcastOp op) {
2805 Type toType = op.getType();
2807 toType, op.getInput().getType(), op.getLoc(),
2808 [&](Location loc) { return emitter.emitError(loc,
""); })) {
2810 ps.invokeWithStringOS(
2811 [&](
auto &os) { emitter.emitTypeDims(toType, op.getLoc(), os); });
2814 return emitSubExpr(op.getInput(), LowestPrecedence);
2817SubExprInfo ExprEmitter::visitComb(ICmpOp op) {
2818 const char *symop[] = {
"==",
"!=",
"<",
"<=",
">",
">=",
"<",
2819 "<=",
">",
">=",
"===",
"!==",
"==?",
"!=?"};
2820 SubExprSignRequirement signop[] = {
2822 NoRequirement, NoRequirement,
2824 RequireSigned, RequireSigned, RequireSigned, RequireSigned,
2826 RequireUnsigned, RequireUnsigned, RequireUnsigned, RequireUnsigned,
2828 NoRequirement, NoRequirement, NoRequirement, NoRequirement};
2830 auto pred =
static_cast<uint64_t
>(op.getPredicate());
2831 assert(pred <
sizeof(symop) /
sizeof(symop[0]));
2834 if (op.isEqualAllOnes())
2835 return emitUnary(op,
"&",
true);
2838 if (op.isNotEqualZero())
2839 return emitUnary(op,
"|",
true);
2841 VerilogPrecedence precedence = Comparison;
2842 switch (op.getPredicate()) {
2843 case ICmpPredicate::eq:
2844 case ICmpPredicate::ne:
2845 case ICmpPredicate::ceq:
2846 case ICmpPredicate::cne:
2847 case ICmpPredicate::weq:
2848 case ICmpPredicate::wne:
2849 precedence = Equality;
2852 precedence = Comparison;
2855 auto result = emitBinary(op, precedence, symop[pred], signop[pred]);
2859 result.signedness = IsUnsigned;
2863SubExprInfo ExprEmitter::visitComb(
ExtractOp op) {
2865 emitError(op,
"SV attributes emission is unimplemented for the op");
2867 unsigned loBit = op.getLowBit();
2868 unsigned hiBit = loBit + cast<IntegerType>(op.getType()).getWidth() - 1;
2870 auto x = emitSubExpr(op.getInput(), LowestPrecedence);
2871 assert((x.precedence == Symbol ||
2873 "should be handled by isExpressionUnableToInline");
2878 op.getInput().getType().getIntOrFloatBitWidth() == hiBit + 1)
2882 ps.addAsString(hiBit);
2883 if (hiBit != loBit) {
2885 ps.addAsString(loBit);
2888 return {Unary, IsUnsigned};
2891SubExprInfo ExprEmitter::visitSV(GetModportOp op) {
2893 emitError(op,
"SV attributes emission is unimplemented for the op");
2895 auto decl = op.getReferencedDecl(state.symbolCache);
2898 return {Selection, IsUnsigned};
2901SubExprInfo ExprEmitter::visitSV(SystemFunctionOp op) {
2903 emitError(op,
"SV attributes emission is unimplemented for the op");
2906 ps.scopedBox(PP::ibox0, [&]() {
2908 op.getOperands(), [&](Value v) { emitSubExpr(v, LowestPrecedence); },
2909 [&]() { ps <<
"," << PP::space; });
2912 return {Symbol, IsUnsigned};
2915SubExprInfo ExprEmitter::visitSV(ReadInterfaceSignalOp op) {
2917 emitError(op,
"SV attributes emission is unimplemented for the op");
2919 auto decl = op.getReferencedDecl(state.symbolCache);
2923 return {Selection, IsUnsigned};
2926SubExprInfo ExprEmitter::visitSV(XMROp op) {
2928 emitError(op,
"SV attributes emission is unimplemented for the op");
2930 if (op.getIsRooted())
2932 for (
auto s : op.getPath())
2933 ps <<
PPExtString(cast<StringAttr>(
s).getValue()) <<
".";
2935 return {Selection, IsUnsigned};
2940SubExprInfo ExprEmitter::visitSV(XMRRefOp op) {
2942 emitError(op,
"SV attributes emission is unimplemented for the op");
2945 auto globalRef = op.getReferencedPath(&state.symbolCache);
2946 auto namepath = globalRef.getNamepathAttr().getValue();
2947 auto *
module = state.symbolCache.getDefinition(
2948 cast<InnerRefAttr>(namepath.front()).getModule());
2950 for (
auto sym : namepath) {
2952 auto innerRef = cast<InnerRefAttr>(sym);
2953 auto ref = state.symbolCache.getInnerDefinition(innerRef.getModule(),
2954 innerRef.getName());
2955 if (ref.hasPort()) {
2961 auto leaf = op.getVerbatimSuffixAttr();
2962 if (leaf && leaf.size())
2964 return {Selection, IsUnsigned};
2967SubExprInfo ExprEmitter::visitVerbatimExprOp(Operation *op, ArrayAttr symbols) {
2969 emitError(op,
"SV attributes emission is unimplemented for the op");
2971 emitTextWithSubstitutions(
2972 ps, op->getAttrOfType<StringAttr>(
"format_string").getValue(), op,
2973 [&](Value operand) { emitSubExpr(operand, LowestPrecedence); }, symbols);
2975 return {Unary, IsUnsigned};
2978template <
typename MacroTy>
2979SubExprInfo ExprEmitter::emitMacroCall(MacroTy op) {
2981 emitError(op,
"SV attributes emission is unimplemented for the op");
2984 auto macroOp = op.getReferencedMacro(&state.symbolCache);
2985 assert(macroOp &&
"Invalid IR");
2987 macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
2989 if (!op.getInputs().empty()) {
2991 llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
2992 emitExpression(val, LowestPrecedence, false);
2996 return {LowestPrecedence, IsUnsigned};
2999SubExprInfo ExprEmitter::visitSV(MacroRefExprOp op) {
3000 return emitMacroCall(op);
3003SubExprInfo ExprEmitter::visitSV(MacroRefExprSEOp op) {
3004 return emitMacroCall(op);
3007SubExprInfo ExprEmitter::visitSV(ConstantXOp op) {
3009 emitError(op,
"SV attributes emission is unimplemented for the op");
3011 ps.addAsString(op.getWidth());
3013 return {Unary, IsUnsigned};
3016SubExprInfo ExprEmitter::visitSV(ConstantStrOp op) {
3018 emitError(op,
"SV attributes emission is unimplemented for the op");
3020 ps.writeQuotedEscaped(op.getStr());
3021 return {Symbol, IsUnsigned};
3024SubExprInfo ExprEmitter::visitSV(ConcatStrOp op) {
3026 emitError(op,
"SV attributes emission is unimplemented for the op");
3030 emitBracedList(op.getInputs());
3031 return {Symbol, IsUnsigned};
3034SubExprInfo ExprEmitter::visitSV(ConstantZOp op) {
3036 emitError(op,
"SV attributes emission is unimplemented for the op");
3038 ps.addAsString(op.getWidth());
3040 return {Unary, IsUnsigned};
3043SubExprInfo ExprEmitter::printConstantScalar(APInt &value, IntegerType type) {
3044 bool isNegated =
false;
3047 if (signPreference == RequireSigned && value.isNegative() &&
3048 !value.isMinSignedValue()) {
3053 ps.addAsString(type.getWidth());
3057 if (signPreference == RequireSigned)
3063 SmallString<32> valueStr;
3065 (-value).toStringUnsigned(valueStr, 16);
3067 value.toStringUnsigned(valueStr, 16);
3070 return {Unary, signPreference == RequireSigned ? IsSigned : IsUnsigned};
3073SubExprInfo ExprEmitter::visitTypeOp(
ConstantOp op) {
3075 emitError(op,
"SV attributes emission is unimplemented for the op");
3077 auto value = op.getValue();
3081 if (value.getBitWidth() == 0) {
3082 emitOpError(op,
"will not emit zero width constants in the general case");
3083 ps <<
"<<unsupported zero width constant: "
3084 <<
PPExtString(op->getName().getStringRef()) <<
">>";
3085 return {Unary, IsUnsigned};
3088 return printConstantScalar(value, hw::type_cast<IntegerType>(op.getType()));
3091void ExprEmitter::printConstantArray(ArrayAttr elementValues, Type
elementType,
3092 bool printAsPattern, Operation *op) {
3093 if (printAsPattern && !isAssignmentLikeContext)
3094 emitAssignmentPatternContextError(op);
3095 StringRef openDelim = printAsPattern ?
"'{" :
"{";
3098 elementValues, [&]() { ps << openDelim; },
3099 [&](Attribute elementValue) {
3100 printConstantAggregate(elementValue,
elementType, op);
3102 [&]() { ps <<
"}"; });
3105void ExprEmitter::printConstantStruct(
3106 ArrayRef<hw::detail::FieldInfo> fieldInfos, ArrayAttr fieldValues,
3107 bool printAsPattern, Operation *op) {
3108 if (printAsPattern && !isAssignmentLikeContext)
3109 emitAssignmentPatternContextError(op);
3116 auto fieldRange = llvm::make_filter_range(
3117 llvm::zip(fieldInfos, fieldValues), [](
const auto &fieldAndValue) {
3122 if (printAsPattern) {
3124 fieldRange, [&]() { ps <<
"'{"; },
3125 [&](
const auto &fieldAndValue) {
3126 ps.scopedBox(PP::ibox2, [&]() {
3127 const auto &[field, value] = fieldAndValue;
3128 ps <<
PPExtString(emitter.getVerilogStructFieldName(field.name))
3129 <<
":" << PP::space;
3130 printConstantAggregate(value, field.type, op);
3133 [&]() { ps <<
"}"; });
3136 fieldRange, [&]() { ps <<
"{"; },
3137 [&](
const auto &fieldAndValue) {
3138 ps.scopedBox(PP::ibox2, [&]() {
3139 const auto &[field, value] = fieldAndValue;
3140 printConstantAggregate(value, field.type, op);
3143 [&]() { ps <<
"}"; });
3147void ExprEmitter::printConstantAggregate(Attribute attr, Type type,
3150 if (
auto arrayType = hw::type_dyn_cast<ArrayType>(type))
3151 return printConstantArray(cast<ArrayAttr>(attr), arrayType.getElementType(),
3152 isAssignmentLikeContext, op);
3155 if (
auto arrayType = hw::type_dyn_cast<UnpackedArrayType>(type))
3156 return printConstantArray(cast<ArrayAttr>(attr), arrayType.getElementType(),
3160 if (
auto structType = hw::type_dyn_cast<StructType>(type))
3161 return printConstantStruct(structType.getElements(), cast<ArrayAttr>(attr),
3162 isAssignmentLikeContext, op);
3164 if (
auto intType = hw::type_dyn_cast<IntegerType>(type)) {
3165 auto value = cast<IntegerAttr>(attr).getValue();
3166 printConstantScalar(value, intType);
3170 emitOpError(op,
"contains constant of type ")
3171 << type <<
" which cannot be emitted as Verilog";
3174SubExprInfo ExprEmitter::visitTypeOp(AggregateConstantOp op) {
3176 emitError(op,
"SV attributes emission is unimplemented for the op");
3180 "zero-bit types not allowed at this point");
3182 printConstantAggregate(op.getFields(), op.getType(), op);
3183 return {Symbol, IsUnsigned};
3186SubExprInfo ExprEmitter::visitTypeOp(ParamValueOp op) {
3188 emitError(op,
"SV attributes emission is unimplemented for the op");
3190 return ps.invokeWithStringOS([&](
auto &os) {
3191 return emitter.printParamValue(op.getValue(), os, [&]() {
3192 return op->emitOpError(
"invalid parameter use");
3201 emitError(op,
"SV attributes emission is unimplemented for the op");
3203 auto arrayPrec = emitSubExpr(op.getInput(), Selection);
3205 unsigned dstWidth = type_cast<ArrayType>(op.getType()).getNumElements();
3207 emitSubExpr(op.getLowIndex(), LowestPrecedence);
3209 ps.addAsString(dstWidth);
3211 return {Selection, arrayPrec.signedness};
3214SubExprInfo ExprEmitter::visitTypeOp(
ArrayGetOp op) {
3215 emitSubExpr(op.getInput(), Selection);
3220 emitSubExpr(op.getIndex(), LowestPrecedence);
3222 emitSVAttributes(op);
3223 return {Selection, IsUnsigned};
3229 emitError(op,
"SV attributes emission is unimplemented for the op");
3231 if (op.isUniform()) {
3233 ps.addAsString(op.getInputs().size());
3235 emitSubExpr(op.getUniformElement(), LowestPrecedence);
3239 op.getInputs(), [&]() { ps <<
"{"; },
3242 emitSubExprIBox2(v);
3245 [&]() { ps <<
"}"; });
3247 return {Unary, IsUnsigned};
3250SubExprInfo ExprEmitter::visitSV(UnpackedArrayCreateOp op) {
3252 emitError(op,
"SV attributes emission is unimplemented for the op");
3255 llvm::reverse(op.getInputs()), [&]() { ps <<
"'{"; },
3256 [&](Value v) { emitSubExprIBox2(v); }, [&]() { ps <<
"}"; });
3257 return {Unary, IsUnsigned};
3262 emitError(op,
"SV attributes emission is unimplemented for the op");
3264 emitBracedList(op.getOperands());
3265 return {Unary, IsUnsigned};
3268SubExprInfo ExprEmitter::visitSV(ArrayIndexInOutOp op) {
3270 emitError(op,
"SV attributes emission is unimplemented for the op");
3272 auto index = op.getIndex();
3273 auto arrayPrec = emitSubExpr(op.getInput(), Selection);
3278 emitSubExpr(index, LowestPrecedence);
3280 return {Selection, arrayPrec.signedness};
3283SubExprInfo ExprEmitter::visitSV(IndexedPartSelectInOutOp op) {
3285 emitError(op,
"SV attributes emission is unimplemented for the op");
3287 auto prec = emitSubExpr(op.getInput(), Selection);
3289 emitSubExpr(op.getBase(), LowestPrecedence);
3290 if (op.getDecrement())
3294 ps.addAsString(op.getWidth());
3296 return {Selection, prec.signedness};
3299SubExprInfo ExprEmitter::visitSV(IndexedPartSelectOp op) {
3301 emitError(op,
"SV attributes emission is unimplemented for the op");
3303 auto info = emitSubExpr(op.getInput(), LowestPrecedence);
3305 emitSubExpr(op.getBase(), LowestPrecedence);
3306 if (op.getDecrement())
3310 ps.addAsString(op.getWidth());
3315SubExprInfo ExprEmitter::visitSV(StructFieldInOutOp op) {
3317 emitError(op,
"SV attributes emission is unimplemented for the op");
3319 auto prec = emitSubExpr(op.getInput(), Selection);
3321 <<
PPExtString(emitter.getVerilogStructFieldName(op.getFieldAttr()));
3322 return {Selection, prec.signedness};
3325SubExprInfo ExprEmitter::visitSV(SampledOp op) {
3327 emitError(op,
"SV attributes emission is unimplemented for the op");
3330 auto info = emitSubExpr(op.getExpression(), LowestPrecedence);
3335SubExprInfo ExprEmitter::visitSV(SFormatFOp op) {
3337 emitError(op,
"SV attributes emission is unimplemented for the op");
3340 ps.scopedBox(PP::ibox0, [&]() {
3341 ps.writeQuotedEscaped(op.getFormatString());
3348 for (
auto operand : op.getSubstitutions()) {
3349 ps <<
"," << PP::space;
3350 emitSubExpr(operand, LowestPrecedence);
3354 return {Symbol, IsUnsigned};
3357SubExprInfo ExprEmitter::visitSV(TimeOp op) {
3359 emitError(op,
"SV attributes emission is unimplemented for the op");
3362 return {Symbol, IsUnsigned};
3365SubExprInfo ExprEmitter::visitSV(STimeOp op) {
3367 emitError(op,
"SV attributes emission is unimplemented for the op");
3370 return {Symbol, IsUnsigned};
3373SubExprInfo ExprEmitter::visitComb(
MuxOp op) {
3387 return ps.scopedBox(PP::cbox0, [&]() -> SubExprInfo {
3388 ps.scopedBox(PP::ibox0, [&]() {
3389 emitSubExpr(op.getCond(), VerilogPrecedence(Conditional - 1));
3393 emitSVAttributes(op);
3395 auto lhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3396 return emitSubExpr(op.getTrueValue(), VerilogPrecedence(Conditional - 1));
3400 auto rhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3401 return emitSubExpr(op.getFalseValue(), Conditional);
3404 SubExprSignResult signedness = IsUnsigned;
3405 if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
3406 signedness = IsSigned;
3408 return {Conditional, signedness};
3412SubExprInfo ExprEmitter::visitComb(ReverseOp op) {
3414 emitError(op,
"SV attributes emission is unimplemented for the op");
3417 emitSubExpr(op.getInput(), LowestPrecedence);
3420 return {Symbol, IsUnsigned};
3423SubExprInfo ExprEmitter::printStructCreate(
3424 ArrayRef<hw::detail::FieldInfo> fieldInfos,
3426 bool printAsPattern, Operation *op) {
3427 if (printAsPattern && !isAssignmentLikeContext)
3428 emitAssignmentPatternContextError(op);
3431 auto filteredFields = llvm::make_filter_range(
3432 llvm::enumerate(fieldInfos),
3433 [](
const auto &field) {
return !
isZeroBitType(field.value().type); });
3435 if (printAsPattern) {
3437 filteredFields, [&]() { ps <<
"'{"; },
3438 [&](
const auto &field) {
3439 ps.scopedBox(PP::ibox2, [&]() {
3441 emitter.getVerilogStructFieldName(field.value().name))
3442 <<
":" << PP::space;
3443 fieldFn(field.value(), field.index());
3446 [&]() { ps <<
"}"; });
3449 filteredFields, [&]() { ps <<
"{"; },
3450 [&](
const auto &field) {
3451 ps.scopedBox(PP::ibox2,
3452 [&]() { fieldFn(field.value(), field.index()); });
3454 [&]() { ps <<
"}"; });
3457 return {Selection, IsUnsigned};
3462 emitError(op,
"SV attributes emission is unimplemented for the op");
3466 bool printAsPattern = isAssignmentLikeContext;
3467 StructType structType = op.getType();
3468 return printStructCreate(
3469 structType.getElements(),
3470 [&](
const auto &field,
auto index) {
3471 emitSubExpr(op.getOperand(index), Selection, NoRequirement,
3473 isAssignmentLikeContext);
3475 printAsPattern, op);
3480 emitError(op,
"SV attributes emission is unimplemented for the op");
3482 emitSubExpr(op.getInput(), Selection);
3484 <<
PPExtString(emitter.getVerilogStructFieldName(op.getFieldNameAttr()));
3485 return {Selection, IsUnsigned};
3488SubExprInfo ExprEmitter::visitTypeOp(StructInjectOp op) {
3490 emitError(op,
"SV attributes emission is unimplemented for the op");
3494 bool printAsPattern = isAssignmentLikeContext;
3495 StructType structType = op.getType();
3496 return printStructCreate(
3497 structType.getElements(),
3498 [&](
const auto &field,
auto index) {
3499 if (field.name == op.getFieldNameAttr()) {
3500 emitSubExpr(op.getNewValue(), Selection);
3502 emitSubExpr(op.getInput(), Selection);
3504 << PPExtString(emitter.getVerilogStructFieldName(field.name));
3507 printAsPattern, op);
3510SubExprInfo ExprEmitter::visitTypeOp(EnumConstantOp op) {
3511 ps <<
PPSaveString(emitter.fieldNameResolver.getEnumFieldName(op.getField()));
3512 return {Selection, IsUnsigned};
3515SubExprInfo ExprEmitter::visitTypeOp(EnumCmpOp op) {
3517 emitError(op,
"SV attributes emission is unimplemented for the op");
3518 auto result = emitBinary(op, Comparison,
"==", NoRequirement);
3521 result.signedness = IsUnsigned;
3525SubExprInfo ExprEmitter::visitTypeOp(UnionCreateOp op) {
3527 emitError(op,
"SV attributes emission is unimplemented for the op");
3531 auto unionWidth = hw::getBitWidth(unionType);
3532 auto &element = unionType.getElements()[op.getFieldIndex()];
3533 auto elementWidth = hw::getBitWidth(element.type);
3536 if (!elementWidth) {
3537 ps.addAsString(unionWidth);
3539 return {Unary, IsUnsigned};
3543 if (elementWidth == unionWidth) {
3544 emitSubExpr(op.getInput(), LowestPrecedence);
3545 return {Unary, IsUnsigned};
3550 auto elementOffset =
static_cast<int64_t
>(element.offset);
3551 int64_t prePadding = unionWidth - elementWidth - elementOffset;
3553 ps.scopedBox(PP::ibox0, [&]() {
3554 if (prePadding > 0) {
3555 ps.addAsString(prePadding);
3556 ps <<
"'h0," << PP::space;
3558 emitSubExpr(op.getInput(), Selection);
3559 if (elementOffset > 0) {
3560 ps <<
"," << PP::space;
3561 ps.addAsString(elementOffset);
3567 return {Unary, IsUnsigned};
3570SubExprInfo ExprEmitter::visitTypeOp(UnionExtractOp op) {
3572 emitError(op,
"SV attributes emission is unimplemented for the op");
3573 emitSubExpr(op.getInput(), Selection);
3576 auto unionType = cast<UnionType>(
getCanonicalType(op.getInput().getType()));
3577 auto unionWidth = hw::getBitWidth(unionType);
3578 auto &element = unionType.getElements()[op.getFieldIndex()];
3579 auto elementWidth = hw::getBitWidth(element.type);
3580 bool needsPadding = elementWidth < unionWidth || element.offset > 0;
3581 auto verilogFieldName = emitter.getVerilogStructFieldName(element.name);
3590 return {Selection, IsUnsigned};
3593SubExprInfo ExprEmitter::visitUnhandledExpr(Operation *op) {
3594 emitOpError(op,
"cannot emit this expression to Verilog");
3595 ps <<
"<<unsupported expr: " <<
PPExtString(op->getName().getStringRef())
3597 return {Symbol, IsUnsigned};
3613enum class PropertyPrecedence {
3633struct EmittedProperty {
3635 PropertyPrecedence precedence;
3640class PropertyEmitter :
public EmitterBase,
3641 public ltl::Visitor<PropertyEmitter, EmittedProperty> {
3645 PropertyEmitter(ModuleEmitter &emitter,
3646 SmallPtrSetImpl<Operation *> &emittedOps)
3647 : PropertyEmitter(emitter, emittedOps, localTokens) {}
3648 PropertyEmitter(ModuleEmitter &emitter,
3649 SmallPtrSetImpl<Operation *> &emittedOps,
3651 : EmitterBase(emitter.state), emitter(emitter), emittedOps(emittedOps),
3653 ps(buffer, state.saver, state.options.emitVerilogLocations) {
3654 assert(state.pp.getListener() == &state.saver);
3657 void emitAssertPropertyDisable(
3658 Value property, Value disable,
3659 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3661 void emitAssertPropertyBody(
3662 Value property, Value disable,
3663 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3665 void emitAssertPropertyBody(
3666 Value property, sv::EventControl event, Value clock, Value disable,
3667 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3672 emitNestedProperty(Value property,
3673 PropertyPrecedence parenthesizeIfLooserThan);
3674 using ltl::Visitor<PropertyEmitter, EmittedProperty>::visitLTL;
3675 friend class ltl::Visitor<PropertyEmitter, EmittedProperty>;
3677 EmittedProperty visitUnhandledLTL(Operation *op);
3678 EmittedProperty visitLTL(ltl::BooleanConstantOp op);
3679 EmittedProperty visitLTL(ltl::AndOp op);
3680 EmittedProperty visitLTL(ltl::OrOp op);
3681 EmittedProperty visitLTL(ltl::IntersectOp op);
3682 EmittedProperty visitLTL(ltl::DelayOp op);
3683 EmittedProperty visitLTL(ltl::ClockedDelayOp op);
3684 EmittedProperty visitLTL(ltl::ConcatOp op);
3685 EmittedProperty visitLTL(ltl::RepeatOp op);
3686 EmittedProperty visitLTL(ltl::GoToRepeatOp op);
3687 EmittedProperty visitLTL(ltl::NonConsecutiveRepeatOp op);
3688 EmittedProperty visitLTL(ltl::NotOp op);
3689 EmittedProperty visitLTL(ltl::ImplicationOp op);
3690 EmittedProperty visitLTL(ltl::UntilOp op);
3691 EmittedProperty visitLTL(ltl::EventuallyOp op);
3692 EmittedProperty visitLTL(ltl::ClockOp op);
3693 EmittedProperty visitLTL(ltl::WeakOp op);
3694 EmittedProperty visitLTL(ltl::StrongOp op);
3696 EmittedProperty emitWeakStrongOp(StringRef mnemonic, Value input);
3697 void emitLTLDelay(int64_t delay, std::optional<int64_t> length);
3698 void emitLTLClockingEvent(ltl::ClockEdge edge, Value clock);
3699 void emitLTLConcat(ValueRange inputs);
3702 ModuleEmitter &emitter;
3707 SmallPtrSetImpl<Operation *> &emittedOps;
3710 SmallVector<Token> localTokens;
3723void PropertyEmitter::emitAssertPropertyDisable(
3724 Value property, Value disable,
3725 PropertyPrecedence parenthesizeIfLooserThan) {
3728 ps <<
"disable iff" << PP::nbsp <<
"(";
3730 emitNestedProperty(disable, PropertyPrecedence::Unary);
3736 ps.scopedBox(PP::ibox0,
3737 [&] { emitNestedProperty(property, parenthesizeIfLooserThan); });
3743void PropertyEmitter::emitAssertPropertyBody(
3744 Value property, Value disable,
3745 PropertyPrecedence parenthesizeIfLooserThan) {
3746 assert(localTokens.empty());
3748 emitAssertPropertyDisable(property, disable, parenthesizeIfLooserThan);
3753 if (&buffer.tokens == &localTokens)
3754 buffer.flush(state.pp);
3757void PropertyEmitter::emitAssertPropertyBody(
3758 Value property, sv::EventControl event, Value clock, Value disable,
3759 PropertyPrecedence parenthesizeIfLooserThan) {
3760 assert(localTokens.empty());
3763 ps.scopedBox(PP::ibox2, [&] {
3764 ps <<
PPExtString(stringifyEventControl(event)) << PP::space;
3765 emitNestedProperty(clock, PropertyPrecedence::Lowest);
3771 emitAssertPropertyDisable(property, disable, parenthesizeIfLooserThan);
3776 if (&buffer.tokens == &localTokens)
3777 buffer.flush(state.pp);
3780EmittedProperty PropertyEmitter::emitNestedProperty(
3781 Value property, PropertyPrecedence parenthesizeIfLooserThan) {
3791 if (!isa<ltl::SequenceType, ltl::PropertyType>(property.getType())) {
3792 ExprEmitter(emitter, emittedOps, buffer.tokens)
3793 .emitExpression(property, LowestPrecedence,
3795 return {PropertyPrecedence::Symbol};
3798 unsigned startIndex = buffer.tokens.size();
3799 auto info = dispatchLTLVisitor(property.getDefiningOp());
3804 if (
info.precedence > parenthesizeIfLooserThan) {
3806 buffer.tokens.insert(buffer.tokens.begin() + startIndex,
BeginToken(0));
3807 buffer.tokens.insert(buffer.tokens.begin() + startIndex,
StringToken(
"("));
3809 ps << PP::end <<
")";
3811 info.precedence = PropertyPrecedence::Symbol;
3815 emittedOps.insert(property.getDefiningOp());
3819EmittedProperty PropertyEmitter::visitUnhandledLTL(Operation *op) {
3820 emitOpError(op,
"emission as Verilog property or sequence not supported");
3821 ps <<
"<<unsupported: " <<
PPExtString(op->getName().getStringRef()) <<
">>";
3822 return {PropertyPrecedence::Symbol};
3825EmittedProperty PropertyEmitter::visitLTL(ltl::BooleanConstantOp op) {
3827 ps << (op.getValueAttr().getValue() ?
"1'h1" :
"1'h0");
3828 return {PropertyPrecedence::Symbol};
3831EmittedProperty PropertyEmitter::visitLTL(ltl::AndOp op) {
3834 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::And); },
3835 [&]() { ps << PP::space <<
"and" << PP::nbsp; });
3836 return {PropertyPrecedence::And};
3839EmittedProperty PropertyEmitter::visitLTL(ltl::OrOp op) {
3842 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::Or); },
3843 [&]() { ps << PP::space <<
"or" << PP::nbsp; });
3844 return {PropertyPrecedence::Or};
3847EmittedProperty PropertyEmitter::visitLTL(ltl::IntersectOp op) {
3851 emitNestedProperty(input, PropertyPrecedence::Intersect);
3853 [&]() { ps << PP::space <<
"intersect" << PP::nbsp; });
3854 return {PropertyPrecedence::Intersect};
3857void PropertyEmitter::emitLTLDelay(int64_t delay,
3858 std::optional<int64_t> length) {
3862 ps.addAsString(delay);
3865 ps.addAsString(delay);
3867 ps.addAsString(delay + *length);
3873 }
else if (delay == 1) {
3877 ps.addAsString(delay);
3883void PropertyEmitter::emitLTLClockingEvent(ltl::ClockEdge edge, Value clock) {
3885 ps.scopedBox(PP::ibox2, [&] {
3886 ps <<
PPExtString(stringifyClockEdge(edge)) << PP::space;
3887 emitNestedProperty(clock, PropertyPrecedence::Lowest);
3892EmittedProperty PropertyEmitter::visitLTL(ltl::DelayOp op) {
3893 emitLTLDelay(op.getDelay(), op.getLength());
3895 emitNestedProperty(op.getInput(), PropertyPrecedence::Concat);
3896 return {PropertyPrecedence::Concat};
3899EmittedProperty PropertyEmitter::visitLTL(ltl::ClockedDelayOp op) {
3900 emitLTLClockingEvent(op.getEdge(), op.getClock());
3902 emitLTLDelay(op.getDelay(), op.getLength());
3904 emitNestedProperty(op.getInput(), PropertyPrecedence::Concat);
3905 return {PropertyPrecedence::Clocking};
3908void PropertyEmitter::emitLTLConcat(ValueRange inputs) {
3909 bool addSeparator =
false;
3910 for (
auto input : inputs) {
3913 if (!input.getDefiningOp<ltl::DelayOp>())
3914 ps <<
"##0" << PP::space;
3916 addSeparator =
true;
3917 emitNestedProperty(input, PropertyPrecedence::Concat);
3921EmittedProperty PropertyEmitter::visitLTL(ltl::ConcatOp op) {
3922 emitLTLConcat(op.getInputs());
3923 return {PropertyPrecedence::Concat};
3926EmittedProperty PropertyEmitter::visitLTL(ltl::RepeatOp op) {
3927 emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3928 if (
auto more = op.getMore()) {
3930 ps.addAsString(op.getBase());
3933 ps.addAsString(op.getBase() + *more);
3937 if (op.getBase() == 0) {
3939 }
else if (op.getBase() == 1) {
3943 ps.addAsString(op.getBase());
3947 return {PropertyPrecedence::Repeat};
3950EmittedProperty PropertyEmitter::visitLTL(ltl::GoToRepeatOp op) {
3951 emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3953 auto more = op.getMore();
3955 ps.addAsString(op.getBase());
3958 ps.addAsString(op.getBase() + more);
3962 return {PropertyPrecedence::Repeat};
3965EmittedProperty PropertyEmitter::visitLTL(ltl::NonConsecutiveRepeatOp op) {
3966 emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3968 auto more = op.getMore();
3970 ps.addAsString(op.getBase());
3973 ps.addAsString(op.getBase() + more);
3977 return {PropertyPrecedence::Repeat};
3980EmittedProperty PropertyEmitter::visitLTL(ltl::NotOp op) {
3983 if (
auto ev = op.getInput().getDefiningOp<ltl::EventuallyOp>()) {
3984 ps <<
"always" << PP::space;
3985 if (
auto innerNot = ev.getInput().getDefiningOp<ltl::NotOp>()) {
3987 emitNestedProperty(innerNot.getInput(), PropertyPrecedence::Qualifier);
3990 ps <<
"not" << PP::space;
3991 emitNestedProperty(ev.getInput(), PropertyPrecedence::Unary);
3993 return {PropertyPrecedence::Qualifier};
3995 ps <<
"not" << PP::space;
3996 emitNestedProperty(op.getInput(), PropertyPrecedence::Unary);
3997 return {PropertyPrecedence::Unary};
4003 auto concatOp = value.getDefiningOp<ltl::ConcatOp>();
4004 if (!concatOp || concatOp.getInputs().size() < 2)
4006 auto delayOp = concatOp.getInputs().back().getDefiningOp<ltl::DelayOp>();
4007 if (!delayOp || delayOp.getDelay() != 1 || delayOp.getLength() != 0)
4009 auto constOp = delayOp.getInput().getDefiningOp<
ConstantOp>();
4010 if (!constOp || !constOp.getValue().isOne())
4012 return concatOp.getInputs().drop_back();
4015EmittedProperty PropertyEmitter::visitLTL(ltl::ImplicationOp op) {
4019 emitLTLConcat(range);
4020 ps << PP::space <<
"|=>" << PP::nbsp;
4022 emitNestedProperty(op.getAntecedent(), PropertyPrecedence::Implication);
4023 ps << PP::space <<
"|->" << PP::nbsp;
4025 emitNestedProperty(op.getConsequent(), PropertyPrecedence::Implication);
4026 return {PropertyPrecedence::Implication};
4029EmittedProperty PropertyEmitter::visitLTL(ltl::UntilOp op) {
4030 emitNestedProperty(op.getInput(), PropertyPrecedence::Until);
4031 ps << PP::space <<
"until" << PP::space;
4032 emitNestedProperty(op.getCondition(), PropertyPrecedence::Until);
4033 return {PropertyPrecedence::Until};
4036EmittedProperty PropertyEmitter::visitLTL(ltl::EventuallyOp op) {
4037 ps <<
"s_eventually" << PP::space;
4038 emitNestedProperty(op.getInput(), PropertyPrecedence::Qualifier);
4039 return {PropertyPrecedence::Qualifier};
4042EmittedProperty PropertyEmitter::visitLTL(ltl::ClockOp op) {
4043 emitLTLClockingEvent(op.getEdge(), op.getClock());
4045 emitNestedProperty(op.getInput(), PropertyPrecedence::Clocking);
4046 return {PropertyPrecedence::Clocking};
4050EmittedProperty PropertyEmitter::emitWeakStrongOp(StringRef mnemonic,
4052 ps << mnemonic << PP::space <<
"(";
4053 ps.scopedBox(PP::ibox2, [&] {
4054 emitNestedProperty(input, PropertyPrecedence::Unary);
4057 return {PropertyPrecedence::Lowest};
4060EmittedProperty PropertyEmitter::visitLTL(ltl::WeakOp op) {
4061 return emitWeakStrongOp(
"weak", op.getInput());
4064EmittedProperty PropertyEmitter::visitLTL(ltl::StrongOp op) {
4065 return emitWeakStrongOp(
"strong", op.getInput());
4075class NameCollector {
4077 NameCollector(ModuleEmitter &moduleEmitter) : moduleEmitter(moduleEmitter) {}
4081 void collectNames(Block &block);
4083 size_t getMaxDeclNameWidth()
const {
return maxDeclNameWidth; }
4084 size_t getMaxTypeWidth()
const {
return maxTypeWidth; }
4087 size_t maxDeclNameWidth = 0, maxTypeWidth = 0;
4088 ModuleEmitter &moduleEmitter;
4093 static constexpr size_t maxTypeWidthBound = 32;
4098void NameCollector::collectNames(Block &block) {
4101 for (
auto &op : block) {
4105 if (isa<InstanceOp, InterfaceInstanceOp, FuncCallProceduralOp, FuncCallOp>(
4108 if (isa<ltl::LTLDialect, debug::DebugDialect>(op.getDialect()))
4112 for (
auto result : op.getResults()) {
4114 maxDeclNameWidth = std::max(declName.size(), maxDeclNameWidth);
4115 SmallString<16> typeString;
4119 llvm::raw_svector_ostream stringStream(typeString);
4121 stringStream, op.getLoc());
4123 if (typeString.size() <= maxTypeWidthBound)
4124 maxTypeWidth = std::max(typeString.size(), maxTypeWidth);
4131 if (isa<IfDefProceduralOp, OrderedOutputOp>(op)) {
4132 for (
auto ®ion : op.getRegions()) {
4133 if (!region.empty())
4134 collectNames(region.front());
4148class StmtEmitter :
public EmitterBase,
4156 : EmitterBase(emitter.state), emitter(emitter), options(options) {}
4158 void emitStatement(Operation *op);
4159 void emitStatementBlock(Block &body);
4162 LogicalResult emitDeclaration(Operation *op);
4165 void collectNamesAndCalculateDeclarationWidths(Block &block);
4168 emitExpression(Value exp, SmallPtrSetImpl<Operation *> &emittedExprs,
4169 VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence,
4170 bool isAssignmentLikeContext =
false);
4171 void emitSVAttributes(Operation *op);
4174 using sv::Visitor<StmtEmitter, LogicalResult>::visitSV;
4177 friend class sv::Visitor<StmtEmitter, LogicalResult>;
4181 LogicalResult visitUnhandledStmt(Operation *op) {
return failure(); }
4182 LogicalResult visitInvalidStmt(Operation *op) {
return failure(); }
4183 LogicalResult visitUnhandledSV(Operation *op) {
return failure(); }
4184 LogicalResult visitInvalidSV(Operation *op) {
return failure(); }
4185 LogicalResult visitUnhandledVerif(Operation *op) {
return failure(); }
4186 LogicalResult visitInvalidVerif(Operation *op) {
return failure(); }
4188 LogicalResult visitSV(
sv::WireOp op) {
return emitDeclaration(op); }
4189 LogicalResult visitSV(VarOp op) {
return emitDeclaration(op); }
4190 LogicalResult visitSV(
RegOp op) {
return emitDeclaration(op); }
4191 LogicalResult visitSV(LogicOp op) {
return emitDeclaration(op); }
4192 LogicalResult visitSV(LocalParamOp op) {
return emitDeclaration(op); }
4193 template <
typename Op>
4196 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
4197 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
4198 llvm::function_ref<
void()> emitRHS,
PPExtString syntax,
4200 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
4201 LogicalResult visitSV(
AssignOp op);
4202 LogicalResult visitSV(BPAssignOp op);
4203 LogicalResult visitSV(PAssignOp op);
4204 LogicalResult visitSV(ForceOp op);
4205 LogicalResult visitSV(ReleaseOp op);
4206 LogicalResult visitSV(AliasOp op);
4207 LogicalResult visitSV(InterfaceInstanceOp op);
4208 LogicalResult emitOutputLikeOp(Operation *op,
const ModulePortInfo &ports);
4209 LogicalResult visitStmt(OutputOp op);
4211 LogicalResult visitStmt(InstanceOp op);
4212 void emitInstancePortList(Operation *op,
ModulePortInfo &modPortInfo,
4213 ArrayRef<Value> instPortValues);
4217 LogicalResult visitSV(PackageOp op);
4219 LogicalResult emitIfDef(Operation *op, MacroIdentAttr cond);
4220 LogicalResult visitSV(OrderedOutputOp op);
4221 LogicalResult visitSV(
IfDefOp op) {
return emitIfDef(op, op.getCond()); }
4222 LogicalResult visitSV(IfDefProceduralOp op) {
4223 return emitIfDef(op, op.getCond());
4225 LogicalResult visitSV(IfOp op);
4226 LogicalResult visitSV(AlwaysOp op);
4227 LogicalResult visitSV(AlwaysCombOp op);
4228 LogicalResult visitSV(AlwaysFFOp op);
4229 LogicalResult visitSV(InitialOp op);
4230 LogicalResult visitSV(CaseOp op);
4231 template <
typename OpTy,
typename EmitPrefixFn>
4233 emitFormattedWriteLikeOp(OpTy op, StringRef callee, StringRef formatString,
4234 ValueRange substitutions, EmitPrefixFn emitPrefix);
4235 LogicalResult visitSV(WriteOp op);
4236 LogicalResult visitSV(FWriteOp op);
4237 LogicalResult visitSV(FFlushOp op);
4238 LogicalResult visitSV(FCloseOp op);
4239 LogicalResult visitSV(VerbatimOp op);
4240 LogicalResult visitSV(MacroRefOp op);
4242 LogicalResult emitSimulationControlTask(Operation *op,
PPExtString taskName,
4243 std::optional<unsigned> verbosity);
4244 LogicalResult visitSV(StopOp op);
4245 LogicalResult visitSV(FinishOp op);
4246 LogicalResult visitSV(ExitOp op);
4248 LogicalResult emitSeverityMessageTask(Operation *op,
PPExtString taskName,
4249 std::optional<unsigned> verbosity,
4251 ValueRange operands);
4254 template <
typename OpTy>
4255 LogicalResult emitNonfatalMessageOp(OpTy op,
const char *taskName) {
4256 return emitSeverityMessageTask(op,
PPExtString(taskName), {},
4257 op.getMessageAttr(), op.getSubstitutions());
4261 template <
typename OpTy>
4262 LogicalResult emitFatalMessageOp(OpTy op) {
4263 return emitSeverityMessageTask(op,
PPExtString(
"$fatal"), op.getVerbosity(),
4264 op.getMessageAttr(), op.getSubstitutions());
4267 LogicalResult visitSV(FatalProceduralOp op);
4268 LogicalResult visitSV(FatalOp op);
4269 LogicalResult visitSV(ErrorProceduralOp op);
4270 LogicalResult visitSV(WarningProceduralOp op);
4271 LogicalResult visitSV(InfoProceduralOp op);
4272 LogicalResult visitSV(ErrorOp op);
4273 LogicalResult visitSV(WarningOp op);
4274 LogicalResult visitSV(InfoOp op);
4276 LogicalResult visitSV(ReadMemOp op);
4278 LogicalResult visitSV(GenerateOp op);
4279 LogicalResult visitSV(GenerateCaseOp op);
4280 LogicalResult visitSV(GenerateForOp op);
4282 LogicalResult visitSV(
ForOp op);
4284 void emitAssertionLabel(Operation *op);
4285 void emitAssertionMessage(StringAttr message, ValueRange args,
4286 SmallPtrSetImpl<Operation *> &ops,
4288 template <
typename Op>
4289 LogicalResult emitImmediateAssertion(Op op,
PPExtString opName);
4290 LogicalResult visitSV(AssertOp op);
4291 LogicalResult visitSV(AssumeOp op);
4292 LogicalResult visitSV(CoverOp op);
4293 template <
typename Op>
4294 LogicalResult emitConcurrentAssertion(Op op,
PPExtString opName);
4295 LogicalResult visitSV(AssertConcurrentOp op);
4296 LogicalResult visitSV(AssumeConcurrentOp op);
4297 LogicalResult visitSV(CoverConcurrentOp op);
4298 template <
typename Op>
4299 LogicalResult emitPropertyAssertion(Op op,
PPExtString opName);
4300 LogicalResult visitSV(AssertPropertyOp op);
4301 LogicalResult visitSV(AssumePropertyOp op);
4302 LogicalResult visitSV(CoverPropertyOp op);
4304 LogicalResult visitSV(BindOp op);
4305 LogicalResult visitSV(InterfaceOp op);
4307 LogicalResult visitSV(InterfaceSignalOp op);
4308 LogicalResult visitSV(InterfaceModportOp op);
4309 LogicalResult visitSV(AssignInterfaceSignalOp op);
4310 LogicalResult visitSV(MacroErrorOp op);
4311 LogicalResult visitSV(MacroDefOp op);
4313 void emitBlockAsStatement(Block *block,
4314 const SmallPtrSetImpl<Operation *> &locationOps,
4315 StringRef multiLineComment = StringRef());
4317 LogicalResult visitSV(FuncDPIImportOp op);
4318 template <
typename CallOp>
4319 LogicalResult emitFunctionCall(CallOp callOp);
4320 LogicalResult visitSV(FuncCallProceduralOp op);
4321 LogicalResult visitSV(FuncCallOp op);
4322 LogicalResult visitSV(ReturnOp op);
4323 LogicalResult visitSV(IncludeOp op);
4326 ModuleEmitter &emitter;
4331 size_t maxDeclNameWidth = 0;
4332 size_t maxTypeWidth = 0;
4343void StmtEmitter::emitExpression(Value exp,
4344 SmallPtrSetImpl<Operation *> &emittedExprs,
4345 VerilogPrecedence parenthesizeIfLooserThan,
4346 bool isAssignmentLikeContext) {
4347 ExprEmitter(emitter, emittedExprs)
4348 .emitExpression(exp, parenthesizeIfLooserThan, isAssignmentLikeContext);
4353void StmtEmitter::emitSVAttributes(Operation *op) {
4361 setPendingNewline();
4364void StmtEmitter::emitAssignLike(llvm::function_ref<
void()> emitLHS,
4365 llvm::function_ref<
void()> emitRHS,
4367 std::optional<PPExtString> wordBeforeLHS) {
4369 ps.scopedBox(PP::ibox2, [&]() {
4370 if (wordBeforeLHS) {
4371 ps << *wordBeforeLHS << PP::space;
4375 ps << PP::space << syntax << PP::space;
4377 ps.scopedBox(PP::ibox0, [&]() {
4384template <
typename Op>
4386StmtEmitter::emitAssignLike(Op op,
PPExtString syntax,
4387 std::optional<PPExtString> wordBeforeLHS) {
4388 SmallPtrSet<Operation *, 8> ops;
4392 ps.addCallback({op,
true});
4393 emitAssignLike([&]() { emitExpression(op.getDest(), ops); },
4395 emitExpression(op.getSrc(), ops, LowestPrecedence,
4400 ps.addCallback({op,
false});
4401 emitLocationInfoAndNewLine(ops);
4405LogicalResult StmtEmitter::visitSV(
AssignOp op) {
4408 if (isa_and_nonnull<HWInstanceLike, FuncCallOp>(op.getSrc().getDefiningOp()))
4411 if (emitter.assignsInlined.count(op))
4415 emitSVAttributes(op);
4420LogicalResult StmtEmitter::visitSV(BPAssignOp op) {
4421 if (op.getSrc().getDefiningOp<FuncCallProceduralOp>())
4425 if (emitter.assignsInlined.count(op))
4429 emitSVAttributes(op);
4434LogicalResult StmtEmitter::visitSV(PAssignOp op) {
4436 emitSVAttributes(op);
4441LogicalResult StmtEmitter::visitSV(ForceOp op) {
4443 emitError(op,
"SV attributes emission is unimplemented for the op");
4448LogicalResult StmtEmitter::visitSV(ReleaseOp op) {
4450 emitError(op,
"SV attributes emission is unimplemented for the op");
4453 SmallPtrSet<Operation *, 8> ops;
4455 ps.addCallback({op,
true});
4456 ps.scopedBox(PP::ibox2, [&]() {
4457 ps <<
"release" << PP::space;
4458 emitExpression(op.getDest(), ops);
4461 ps.addCallback({op,
false});
4462 emitLocationInfoAndNewLine(ops);
4466LogicalResult StmtEmitter::visitSV(AliasOp op) {
4468 emitError(op,
"SV attributes emission is unimplemented for the op");
4471 SmallPtrSet<Operation *, 8> ops;
4473 ps.addCallback({op,
true});
4474 ps.scopedBox(PP::ibox2, [&]() {
4475 ps <<
"alias" << PP::space;
4476 ps.scopedBox(PP::cbox0, [&]() {
4478 op.getOperands(), [&](Value v) { emitExpression(v, ops); },
4479 [&]() { ps << PP::nbsp <<
"=" << PP::space; });
4483 ps.addCallback({op,
false});
4484 emitLocationInfoAndNewLine(ops);
4488LogicalResult StmtEmitter::visitSV(InterfaceInstanceOp op) {
4489 auto doNotPrint = op.getDoNotPrint();
4490 if (doNotPrint && !state.options.emitBindComments)
4494 emitError(op,
"SV attributes emission is unimplemented for the op");
4497 StringRef prefix =
"";
4498 ps.addCallback({op,
true});
4501 ps <<
"// This interface is elsewhere emitted as a bind statement."
4505 SmallPtrSet<Operation *, 8> ops;
4508 auto *interfaceOp = op.getReferencedInterface(&state.symbolCache);
4509 assert(interfaceOp &&
"InterfaceInstanceOp has invalid symbol that does not "
4510 "point to an interface");
4513 if (!prefix.empty())
4519 ps.addCallback({op,
false});
4520 emitLocationInfoAndNewLine(ops);
4528LogicalResult StmtEmitter::emitOutputLikeOp(Operation *op,
4530 SmallPtrSet<Operation *, 8> ops;
4531 size_t operandIndex = 0;
4533 for (
PortInfo port : ports.getOutputs()) {
4534 auto operand = op->getOperand(operandIndex);
4538 if (operand.hasOneUse() && operand.getDefiningOp() &&
4539 isa<InstanceOp>(operand.getDefiningOp())) {
4548 ps.addCallback({op,
true});
4550 ps.scopedBox(isZeroBit ? PP::neverbox :
PP::
ibox2, [&]() {
4552 ps <<
"// Zero width: ";
4555 ps <<
"assign" << PP::space;
4557 ps << PP::space <<
"=" << PP::space;
4558 ps.scopedBox(PP::ibox0, [&]() {
4562 isa_and_nonnull<hw::ConstantOp>(operand.getDefiningOp()))
4563 ps <<
"/*Zero width*/";
4565 emitExpression(operand, ops, LowestPrecedence,
4570 ps.addCallback({op,
false});
4571 emitLocationInfoAndNewLine(ops);
4578LogicalResult StmtEmitter::visitStmt(OutputOp op) {
4579 auto parent = op->getParentOfType<PortList>();
4581 return emitOutputLikeOp(op, ports);
4584LogicalResult StmtEmitter::visitStmt(
TypeScopeOp op) {
4586 auto typescopeDef = (
"_TYPESCOPE_" + op.getSymName()).str();
4587 ps <<
"`ifndef " << typescopeDef << PP::newline;
4588 ps <<
"`define " << typescopeDef;
4589 setPendingNewline();
4590 emitStatementBlock(*op.getBodyBlock());
4592 ps <<
"`endif // " << typescopeDef;
4593 setPendingNewline();
4597LogicalResult StmtEmitter::visitStmt(
TypedeclOp op) {
4599 emitError(op,
"SV attributes emission is unimplemented for the op");
4604 ps << PP::neverbox <<
"// ";
4606 SmallPtrSet<Operation *, 8> ops;
4608 ps.scopedBox(PP::ibox2, [&]() {
4609 ps <<
"typedef" << PP::space;
4610 ps.invokeWithStringOS([&](
auto &os) {
4612 op.getAliasType(),
false);
4614 ps << PP::space <<
PPExtString(op.getPreferredName());
4615 ps.invokeWithStringOS(
4616 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
4621 emitLocationInfoAndNewLine(ops);
4625LogicalResult StmtEmitter::visitSV(PackageOp op) {
4626 llvm::SaveAndRestore<Operation *> package(emitter.currentPackage, op);
4628 ps.addCallback({op,
true});
4630 setPendingNewline();
4631 ps.scopedBox(PP::bbox2, [&]() { emitStatementBlock(*op.getBodyBlock()); });
4634 ps.addCallback({op,
false});
4635 setPendingNewline();
4639template <
typename CallOpTy>
4640LogicalResult StmtEmitter::emitFunctionCall(CallOpTy op) {
4644 dyn_cast<FuncOp>(state.symbolCache.getDefinition(op.getCalleeAttr()));
4646 SmallPtrSet<Operation *, 8> ops;
4650 auto explicitReturn = op.getExplicitlyReturnedValue(callee);
4651 if (explicitReturn) {
4652 assert(explicitReturn.hasOneUse());
4653 if (op->getParentOp()->template hasTrait<ProceduralRegion>()) {
4654 auto bpassignOp = cast<sv::BPAssignOp>(*explicitReturn.user_begin());
4655 emitExpression(bpassignOp.getDest(), ops);
4657 auto assignOp = cast<sv::AssignOp>(*explicitReturn.user_begin());
4658 ps <<
"assign" << PP::nbsp;
4659 emitExpression(assignOp.getDest(), ops);
4661 ps << PP::nbsp <<
"=" << PP::nbsp;
4664 auto arguments = callee.getPortList(
true);
4668 bool needsComma =
false;
4669 auto printArg = [&](Value value) {
4671 ps <<
"," << PP::space;
4672 emitExpression(value, ops);
4676 ps.scopedBox(PP::ibox0, [&] {
4677 unsigned inputIndex = 0, outputIndex = 0;
4678 for (
auto arg : arguments) {
4681 op.getResults()[outputIndex++].getUsers().begin()->getOperand(0));
4683 printArg(op.getInputs()[inputIndex++]);
4688 emitLocationInfoAndNewLine(ops);
4692LogicalResult StmtEmitter::visitSV(FuncCallProceduralOp op) {
4693 return emitFunctionCall(op);
4696LogicalResult StmtEmitter::visitSV(FuncCallOp op) {
4697 return emitFunctionCall(op);
4700template <
typename PPS>
4702 bool isAutomatic =
false,
4703 bool emitAsTwoStateType =
false) {
4704 ps <<
"function" << PP::nbsp;
4706 ps <<
"automatic" << PP::nbsp;
4707 auto retType = op.getExplicitlyReturnedType();
4709 ps.invokeWithStringOS([&](
auto &os) {
4710 emitter.printPackedType(retType, os, op->getLoc(), {},
false,
true,
4711 emitAsTwoStateType);
4717 emitter.emitPortList(
4721LogicalResult StmtEmitter::visitSV(ReturnOp op) {
4722 auto parent = op->getParentOfType<sv::FuncOp>();
4724 return emitOutputLikeOp(op, ports);
4727LogicalResult StmtEmitter::visitSV(IncludeOp op) {
4729 ps <<
"`include" << PP::nbsp;
4731 if (op.getStyle() == IncludeStyle::System)
4732 ps <<
"<" << op.getTarget() <<
">";
4734 ps <<
"\"" << op.getTarget() <<
"\"";
4736 emitLocationInfo(op.getLoc());
4737 setPendingNewline();
4741LogicalResult StmtEmitter::visitSV(FuncDPIImportOp importOp) {
4744 ps <<
"import" << PP::nbsp <<
"\"DPI-C\"" << PP::nbsp <<
"context"
4748 if (
auto linkageName = importOp.getLinkageName())
4749 ps << *linkageName << PP::nbsp <<
"=" << PP::nbsp;
4751 cast<FuncOp>(state.symbolCache.getDefinition(importOp.getCalleeAttr()));
4752 assert(op.isDeclaration() &&
"function must be a declaration");
4755 assert(state.pendingNewline);
4761LogicalResult StmtEmitter::visitSV(FFlushOp op) {
4763 emitError(op,
"SV attributes emission is unimplemented for the op");
4766 SmallPtrSet<Operation *, 8> ops;
4769 ps.addCallback({op,
true});
4771 if (
auto fd = op.getFd())
4772 ps.scopedBox(PP::ibox0, [&]() { emitExpression(op.getFd(), ops); });
4775 ps.addCallback({op,
false});
4776 emitLocationInfoAndNewLine(ops);
4780LogicalResult StmtEmitter::visitSV(FCloseOp op) {
4782 emitError(op,
"SV attributes emission is unimplemented for the op");
4785 SmallPtrSet<Operation *, 8> ops;
4788 ps.addCallback({op,
true});
4790 ps.scopedBox(PP::ibox0, [&]() { emitExpression(op.getFd(), ops); });
4792 ps.addCallback({op,
false});
4793 emitLocationInfoAndNewLine(ops);
4797template <
typename OpTy,
typename EmitPrefixFn>
4798LogicalResult StmtEmitter::emitFormattedWriteLikeOp(OpTy op, StringRef callee,
4799 StringRef formatString,
4800 ValueRange substitutions,
4801 EmitPrefixFn emitPrefix) {
4803 emitError(op,
"SV attributes emission is unimplemented for the op");
4806 SmallPtrSet<Operation *, 8> ops;
4809 ps.addCallback({op,
true});
4811 ps.scopedBox(PP::ibox0, [&]() {
4813 ps.writeQuotedEscaped(formatString);
4820 for (
auto operand : substitutions) {
4821 ps <<
"," << PP::space;
4822 emitExpression(operand, ops);
4826 ps.addCallback({op,
false});
4827 emitLocationInfoAndNewLine(ops);
4831LogicalResult StmtEmitter::visitSV(WriteOp op) {
4832 return emitFormattedWriteLikeOp(op,
"$write(", op.getFormatString(),
4833 op.getSubstitutions(),
4834 [&](SmallPtrSetImpl<Operation *> &) {});
4837LogicalResult StmtEmitter::visitSV(FWriteOp op) {
4838 return emitFormattedWriteLikeOp(op,
"$fwrite(", op.getFormatString(),
4839 op.getSubstitutions(),
4840 [&](SmallPtrSetImpl<Operation *> &ops) {
4841 emitExpression(op.getFd(), ops);
4842 ps <<
"," << PP::space;
4846LogicalResult StmtEmitter::visitSV(VerbatimOp op) {
4848 emitError(op,
"SV attributes emission is unimplemented for the op");
4851 SmallPtrSet<Operation *, 8> ops;
4856 StringRef
string = op.getFormatString();
4857 if (
string.ends_with(
"\n"))
4858 string =
string.drop_back();
4863 bool isFirst =
true;
4866 while (!
string.
empty()) {
4867 auto lhsRhs =
string.split(
'\n');
4871 ps << PP::end << PP::newline << PP::neverbox;
4875 emitTextWithSubstitutions(
4876 ps, lhsRhs.first, op,
4877 [&](Value operand) { emitExpression(operand, ops); }, op.getSymbols());
4878 string = lhsRhs.second;
4883 emitLocationInfoAndNewLine(ops);
4888LogicalResult StmtEmitter::visitSV(MacroRefOp op) {
4890 emitError(op,
"SV attributes emission is unimplemented for the op");
4894 SmallPtrSet<Operation *, 8> ops;
4899 auto macroOp = op.getReferencedMacro(&state.symbolCache);
4900 assert(macroOp &&
"Invalid IR");
4902 macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
4904 if (!op.getInputs().empty()) {
4906 llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
4907 emitExpression(val, ops, LowestPrecedence,
4913 emitLocationInfoAndNewLine(ops);
4919StmtEmitter::emitSimulationControlTask(Operation *op,
PPExtString taskName,
4920 std::optional<unsigned> verbosity) {
4922 emitError(op,
"SV attributes emission is unimplemented for the op");
4925 SmallPtrSet<Operation *, 8> ops;
4927 ps.addCallback({op,
true});
4929 if (verbosity && *verbosity != 1) {
4931 ps.addAsString(*verbosity);
4935 ps.addCallback({op,
false});
4936 emitLocationInfoAndNewLine(ops);
4940LogicalResult StmtEmitter::visitSV(StopOp op) {
4941 return emitSimulationControlTask(op,
PPExtString(
"$stop"), op.getVerbosity());
4944LogicalResult StmtEmitter::visitSV(FinishOp op) {
4945 return emitSimulationControlTask(op,
PPExtString(
"$finish"),
4949LogicalResult StmtEmitter::visitSV(ExitOp op) {
4950 return emitSimulationControlTask(op,
PPExtString(
"$exit"), {});
4956StmtEmitter::emitSeverityMessageTask(Operation *op,
PPExtString taskName,
4957 std::optional<unsigned> verbosity,
4958 StringAttr message, ValueRange operands) {
4960 emitError(op,
"SV attributes emission is unimplemented for the op");
4963 SmallPtrSet<Operation *, 8> ops;
4965 ps.addCallback({op,
true});
4971 if ((verbosity && *verbosity != 1) || message) {
4973 ps.scopedBox(PP::ibox0, [&]() {
4977 ps.addAsString(*verbosity);
4982 ps <<
"," << PP::space;
4983 ps.writeQuotedEscaped(message.getValue());
4985 for (
auto operand : operands) {
4986 ps <<
"," << PP::space;
4987 emitExpression(operand, ops);
4996 ps.addCallback({op,
false});
4997 emitLocationInfoAndNewLine(ops);
5001LogicalResult StmtEmitter::visitSV(FatalProceduralOp op) {
5002 return emitFatalMessageOp(op);
5005LogicalResult StmtEmitter::visitSV(FatalOp op) {
5006 return emitFatalMessageOp(op);
5009LogicalResult StmtEmitter::visitSV(ErrorProceduralOp op) {
5010 return emitNonfatalMessageOp(op,
"$error");
5013LogicalResult StmtEmitter::visitSV(WarningProceduralOp op) {
5014 return emitNonfatalMessageOp(op,
"$warning");
5017LogicalResult StmtEmitter::visitSV(InfoProceduralOp op) {
5018 return emitNonfatalMessageOp(op,
"$info");
5021LogicalResult StmtEmitter::visitSV(ErrorOp op) {
5022 return emitNonfatalMessageOp(op,
"$error");
5025LogicalResult StmtEmitter::visitSV(WarningOp op) {
5026 return emitNonfatalMessageOp(op,
"$warning");
5029LogicalResult StmtEmitter::visitSV(InfoOp op) {
5030 return emitNonfatalMessageOp(op,
"$info");
5033LogicalResult StmtEmitter::visitSV(ReadMemOp op) {
5034 SmallPtrSet<Operation *, 8> ops({op});
5037 ps.addCallback({op,
true});
5039 switch (op.getBaseAttr().getValue()) {
5040 case MemBaseTypeAttr::MemBaseBin:
5043 case MemBaseTypeAttr::MemBaseHex:
5048 ps.scopedBox(PP::ibox0, [&]() {
5049 ps.writeQuotedEscaped(op.getFilename());
5050 ps <<
"," << PP::space;
5051 emitExpression(op.getDest(), ops);
5055 ps.addCallback({op,
false});
5056 emitLocationInfoAndNewLine(ops);
5060LogicalResult StmtEmitter::visitSV(GenerateOp op) {
5061 emitSVAttributes(op);
5064 ps.addCallback({op,
true});
5065 ps <<
"generate" << PP::newline;
5067 setPendingNewline();
5068 emitStatementBlock(op.getBody().getBlocks().front());
5071 ps <<
"endgenerate";
5072 ps.addCallback({op,
false});
5073 setPendingNewline();
5077LogicalResult StmtEmitter::visitSV(GenerateCaseOp op) {
5078 emitSVAttributes(op);
5081 ps.addCallback({op,
true});
5083 ps.invokeWithStringOS([&](
auto &os) {
5084 emitter.printParamValue(
5085 op.getCond(), os, VerilogPrecedence::Selection,
5086 [&]() { return op->emitOpError(
"invalid case parameter"); });
5089 setPendingNewline();
5092 ArrayAttr
patterns = op.getCasePatterns();
5093 ArrayAttr caseNames = op.getCaseNames();
5094 MutableArrayRef<Region> regions = op.getCaseRegions();
5101 llvm::StringMap<size_t> nextGenIds;
5102 ps.scopedBox(PP::bbox2, [&]() {
5104 for (
size_t i = 0, e =
patterns.size(); i < e; ++i) {
5105 auto ®ion = regions[i];
5106 assert(region.hasOneBlock());
5107 Attribute patternAttr =
patterns[i];
5110 if (!isa<mlir::TypedAttr>(patternAttr))
5113 ps.invokeWithStringOS([&](
auto &os) {
5114 emitter.printParamValue(
5115 patternAttr, os, VerilogPrecedence::LowestPrecedence,
5116 [&]() {
return op->emitOpError(
"invalid case value"); });
5119 StringRef legalName =
5120 legalizeName(cast<StringAttr>(caseNames[i]).getValue(), nextGenIds,
5123 setPendingNewline();
5124 emitStatementBlock(region.getBlocks().front());
5127 setPendingNewline();
5133 ps.addCallback({op,
false});
5134 setPendingNewline();
5138LogicalResult StmtEmitter::visitSV(GenerateForOp op) {
5139 emitSVAttributes(op);
5140 llvm::SmallPtrSet<Operation *, 8> ops;
5141 ps.addCallback({op,
true});
5144 StringRef inductionVarName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
5147 ps.scopedBox(PP::cbox0, [&]() {
5149 [&]() { ps <<
"genvar" << PP::nbsp <<
PPExtString(inductionVarName); },
5151 ps.invokeWithStringOS([&](
auto &os) {
5152 emitter.printParamValue(
5153 op.getLowerBound(), os, VerilogPrecedence::LowestPrecedence,
5154 [&]() { return op->emitOpError(
"invalid lower bound"); });
5163 ps.invokeWithStringOS([&](
auto &os) {
5164 emitter.printParamValue(
5165 op.getUpperBound(), os, VerilogPrecedence::LowestPrecedence,
5166 [&]() { return op->emitOpError(
"invalid upper bound"); });
5172 ps <<
PPExtString(inductionVarName) << PP::nbsp <<
"+=" << PP::nbsp;
5173 ps.invokeWithStringOS([&](
auto &os) {
5174 emitter.printParamValue(
5175 op.getStep(), os, VerilogPrecedence::LowestPrecedence,
5176 [&]() { return op->emitOpError(
"invalid step"); });
5179 StringRef blockName = op.getGenBlockName();
5180 if (!blockName.empty())
5184 ps << PP::neverbreak;
5185 setPendingNewline();
5186 emitStatementBlock(op.getBody().getBlocks().front());
5189 if (StringRef blockName = op.getGenBlockName(); !blockName.empty())
5191 ps.addCallback({op,
false});
5192 setPendingNewline();
5196LogicalResult StmtEmitter::visitSV(
ForOp op) {
5197 emitSVAttributes(op);
5198 llvm::SmallPtrSet<Operation *, 8> ops;
5199 ps.addCallback({op,
true});
5201 auto inductionVarName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
5204 ps.scopedBox(PP::cbox0, [&]() {
5208 ps <<
"logic" << PP::nbsp;
5209 ps.invokeWithStringOS([&](
auto &os) {
5210 emitter.emitTypeDims(op.getInductionVar().getType(), op.getLoc(),
5215 [&]() { emitExpression(op.getLowerBound(), ops); },
PPExtString(
"="));
5220 emitAssignLike([&]() { ps <<
PPExtString(inductionVarName); },
5221 [&]() { emitExpression(op.getUpperBound(), ops); },
5227 emitAssignLike([&]() { ps <<
PPExtString(inductionVarName); },
5228 [&]() { emitExpression(op.getStep(), ops); },
5232 ps << PP::neverbreak;
5233 setPendingNewline();
5234 emitStatementBlock(op.getBody().getBlocks().front());
5237 ps.addCallback({op,
false});
5238 emitLocationInfoAndNewLine(ops);
5243void StmtEmitter::emitAssertionLabel(Operation *op) {
5244 if (
auto label = op->getAttrOfType<StringAttr>(
"hw.verilogName"))
5250void StmtEmitter::emitAssertionMessage(StringAttr message, ValueRange args,
5251 SmallPtrSetImpl<Operation *> &ops,
5252 bool isConcurrent =
false) {
5255 ps << PP::space <<
"else" << PP::nbsp <<
"$error(";
5256 ps.scopedBox(PP::ibox0, [&]() {
5257 ps.writeQuotedEscaped(message.getValue());
5259 for (
auto arg : args) {
5260 ps <<
"," << PP::space;
5261 emitExpression(arg, ops);
5267template <
typename Op>
5268LogicalResult StmtEmitter::emitImmediateAssertion(Op op,
PPExtString opName) {
5270 emitError(op,
"SV attributes emission is unimplemented for the op");
5273 SmallPtrSet<Operation *, 8> ops;
5275 ps.addCallback({op,
true});
5276 ps.scopedBox(PP::ibox2, [&]() {
5277 emitAssertionLabel(op);
5278 ps.scopedBox(PP::cbox0, [&]() {
5280 switch (op.getDefer()) {
5281 case DeferAssert::Immediate:
5283 case DeferAssert::Observed:
5286 case DeferAssert::Final:
5291 ps.scopedBox(PP::ibox0, [&]() {
5292 emitExpression(op.getExpression(), ops);
5295 emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops);
5299 ps.addCallback({op,
false});
5300 emitLocationInfoAndNewLine(ops);
5304LogicalResult StmtEmitter::visitSV(AssertOp op) {
5305 return emitImmediateAssertion(op,
PPExtString(
"assert"));
5308LogicalResult StmtEmitter::visitSV(AssumeOp op) {
5309 return emitImmediateAssertion(op,
PPExtString(
"assume"));
5312LogicalResult StmtEmitter::visitSV(CoverOp op) {
5313 return emitImmediateAssertion(op,
PPExtString(
"cover"));
5316template <
typename Op>
5317LogicalResult StmtEmitter::emitConcurrentAssertion(Op op,
PPExtString opName) {
5319 emitError(op,
"SV attributes emission is unimplemented for the op");
5322 SmallPtrSet<Operation *, 8> ops;
5324 ps.addCallback({op,
true});
5325 ps.scopedBox(PP::ibox2, [&]() {
5326 emitAssertionLabel(op);
5327 ps.scopedBox(PP::cbox0, [&]() {
5328 ps << opName << PP::nbsp <<
"property (";
5329 ps.scopedBox(PP::ibox0, [&]() {
5330 ps <<
"@(" <<
PPExtString(stringifyEventControl(op.getEvent()))
5332 emitExpression(op.getClock(), ops);
5333 ps <<
")" << PP::space;
5334 emitExpression(op.getProperty(), ops);
5337 emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops,
5342 ps.addCallback({op,
false});
5343 emitLocationInfoAndNewLine(ops);
5347LogicalResult StmtEmitter::visitSV(AssertConcurrentOp op) {
5348 return emitConcurrentAssertion(op,
PPExtString(
"assert"));
5351LogicalResult StmtEmitter::visitSV(AssumeConcurrentOp op) {
5352 return emitConcurrentAssertion(op,
PPExtString(
"assume"));
5355LogicalResult StmtEmitter::visitSV(CoverConcurrentOp op) {
5356 return emitConcurrentAssertion(op,
PPExtString(
"cover"));
5361template <
typename Op>
5362LogicalResult StmtEmitter::emitPropertyAssertion(Op op,
PPExtString opName) {
5364 emitError(op,
"SV attributes emission is unimplemented for the op");
5374 Operation *parent = op->getParentOp();
5375 Value
property = op.getProperty();
5376 bool isTemporal = !
property.getType().isSignlessInteger(1);
5378 bool emitAsImmediate = !isTemporal && isProcedural;
5381 SmallPtrSet<Operation *, 8> ops;
5383 ps.addCallback({op,
true});
5384 ps.scopedBox(PP::ibox2, [&]() {
5386 emitAssertionLabel(op);
5388 ps.scopedBox(PP::cbox0, [&]() {
5389 if (emitAsImmediate)
5390 ps << opName <<
"(";
5392 ps << opName << PP::nbsp <<
"property" << PP::nbsp <<
"(";
5394 Value clock = op.getClock();
5395 auto event = op.getEvent();
5397 ps.scopedBox(PP::ibox2, [&]() {
5398 PropertyEmitter(emitter, ops)
5399 .emitAssertPropertyBody(property, *event, clock, op.getDisable());
5402 ps.scopedBox(PP::ibox2, [&]() {
5403 PropertyEmitter(emitter, ops)
5404 .emitAssertPropertyBody(property, op.getDisable());
5409 ps.addCallback({op,
false});
5410 emitLocationInfoAndNewLine(ops);
5414LogicalResult StmtEmitter::visitSV(AssertPropertyOp op) {
5415 return emitPropertyAssertion(op,
PPExtString(
"assert"));
5418LogicalResult StmtEmitter::visitSV(AssumePropertyOp op) {
5419 return emitPropertyAssertion(op,
PPExtString(
"assume"));
5422LogicalResult StmtEmitter::visitSV(CoverPropertyOp op) {
5423 return emitPropertyAssertion(op,
PPExtString(
"cover"));
5426LogicalResult StmtEmitter::emitIfDef(Operation *op, MacroIdentAttr cond) {
5428 emitError(op,
"SV attributes emission is unimplemented for the op");
5431 cast<MacroDeclOp>(state.symbolCache.getDefinition(cond.getIdent()))
5432 .getMacroIdentifier());
5435 bool hasEmptyThen = op->getRegion(0).front().empty();
5437 ps <<
"`ifndef " << ident;
5439 ps <<
"`ifdef " << ident;
5441 SmallPtrSet<Operation *, 8> ops;
5443 emitLocationInfoAndNewLine(ops);
5446 emitStatementBlock(op->getRegion(0).front());
5448 if (!op->getRegion(1).empty()) {
5449 if (!hasEmptyThen) {
5451 ps <<
"`else // " << ident;
5452 setPendingNewline();
5454 emitStatementBlock(op->getRegion(1).front());
5461 setPendingNewline();
5469void StmtEmitter::emitBlockAsStatement(
5470 Block *block,
const SmallPtrSetImpl<Operation *> &locationOps,
5471 StringRef multiLineComment) {
5475 auto needsBeginEnd =
5479 emitLocationInfoAndNewLine(locationOps);
5482 emitStatementBlock(*block);
5484 if (needsBeginEnd) {
5488 if (!multiLineComment.empty())
5489 ps <<
" // " << multiLineComment;
5490 setPendingNewline();
5494LogicalResult StmtEmitter::visitSV(OrderedOutputOp ooop) {
5496 for (
auto &op : ooop.getBody().front())
5501LogicalResult StmtEmitter::visitSV(IfOp op) {
5502 SmallPtrSet<Operation *, 8> ops;
5504 auto ifcondBox = PP::ibox2;
5506 emitSVAttributes(op);
5508 ps.addCallback({op,
true});
5509 ps <<
"if (" << ifcondBox;
5519 emitExpression(ifOp.getCond(), ops);
5520 ps << PP::end <<
")";
5521 emitBlockAsStatement(ifOp.getThenBlock(), ops);
5523 if (!ifOp.hasElse())
5527 Block *elseBlock = ifOp.getElseBlock();
5529 if (!nestedElseIfOp) {
5534 emitBlockAsStatement(elseBlock, ops);
5540 ifOp = nestedElseIfOp;
5541 ps <<
"else if (" << ifcondBox;
5543 ps.addCallback({op,
false});
5548LogicalResult StmtEmitter::visitSV(AlwaysOp op) {
5549 emitSVAttributes(op);
5550 SmallPtrSet<Operation *, 8> ops;
5554 auto printEvent = [&](AlwaysOp::Condition cond) {
5555 ps <<
PPExtString(stringifyEventControl(cond.event)) << PP::nbsp;
5556 ps.scopedBox(PP::cbox0, [&]() { emitExpression(cond.value, ops); });
5558 ps.addCallback({op,
true});
5560 switch (op.getNumConditions()) {
5566 printEvent(op.getCondition(0));
5571 ps.scopedBox(PP::cbox0, [&]() {
5572 printEvent(op.getCondition(0));
5573 for (
size_t i = 1, e = op.getNumConditions(); i != e; ++i) {
5574 ps << PP::space <<
"or" << PP::space;
5575 printEvent(op.getCondition(i));
5584 std::string comment;
5585 if (op.getNumConditions() == 0) {
5586 comment =
"always @*";
5588 comment =
"always @(";
5591 [&](Attribute eventAttr) {
5592 auto event = sv::EventControl(cast<IntegerAttr>(eventAttr).getInt());
5593 comment += stringifyEventControl(event);
5595 [&]() { comment +=
", "; });
5599 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5600 ps.addCallback({op,
false});
5604LogicalResult StmtEmitter::visitSV(AlwaysCombOp op) {
5605 emitSVAttributes(op);
5606 SmallPtrSet<Operation *, 8> ops;
5610 ps.addCallback({op,
true});
5611 StringRef opString =
"always_comb";
5612 if (state.options.noAlwaysComb)
5613 opString =
"always @(*)";
5616 emitBlockAsStatement(op.getBodyBlock(), ops, opString);
5617 ps.addCallback({op,
false});
5621LogicalResult StmtEmitter::visitSV(AlwaysFFOp op) {
5622 emitSVAttributes(op);
5624 SmallPtrSet<Operation *, 8> ops;
5628 ps.addCallback({op,
true});
5629 ps <<
"always_ff @(";
5630 ps.scopedBox(PP::cbox0, [&]() {
5631 ps <<
PPExtString(stringifyEventControl(op.getClockEdge())) << PP::nbsp;
5632 emitExpression(op.getClock(), ops);
5633 if (op.getResetStyle() == ResetType::AsyncReset) {
5634 ps << PP::nbsp <<
"or" << PP::space
5635 <<
PPExtString(stringifyEventControl(*op.getResetEdge())) << PP::nbsp;
5636 emitExpression(op.getReset(), ops);
5643 std::string comment;
5644 comment +=
"always_ff @(";
5645 comment += stringifyEventControl(op.getClockEdge());
5646 if (op.getResetStyle() == ResetType::AsyncReset) {
5648 comment += stringifyEventControl(*op.getResetEdge());
5652 if (op.getResetStyle() == ResetType::NoReset)
5653 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5656 emitLocationInfoAndNewLine(ops);
5657 ps.scopedBox(PP::bbox2, [&]() {
5663 if (op.getResetStyle() == ResetType::AsyncReset &&
5664 *op.getResetEdge() == sv::EventControl::AtNegEdge)
5666 emitExpression(op.getReset(), ops);
5668 emitBlockAsStatement(op.getResetBlock(), ops);
5671 emitBlockAsStatement(op.getBodyBlock(), ops);
5676 ps <<
" // " << comment;
5677 setPendingNewline();
5679 ps.addCallback({op,
false});
5683LogicalResult StmtEmitter::visitSV(InitialOp op) {
5684 emitSVAttributes(op);
5685 SmallPtrSet<Operation *, 8> ops;
5688 ps.addCallback({op,
true});
5690 emitBlockAsStatement(op.getBodyBlock(), ops,
"initial");
5691 ps.addCallback({op,
false});
5695LogicalResult StmtEmitter::visitSV(CaseOp op) {
5696 emitSVAttributes(op);
5697 SmallPtrSet<Operation *, 8> ops, emptyOps;
5700 ps.addCallback({op,
true});
5701 if (op.getValidationQualifier() !=
5702 ValidationQualifierTypeEnum::ValidationQualifierPlain)
5703 ps <<
PPExtString(circt::sv::stringifyValidationQualifierTypeEnum(
5704 op.getValidationQualifier()))
5706 const char *opname =
nullptr;
5707 switch (op.getCaseStyle()) {
5708 case CaseStmtType::CaseStmt:
5711 case CaseStmtType::CaseXStmt:
5714 case CaseStmtType::CaseZStmt:
5718 ps << opname <<
" (";
5719 ps.scopedBox(PP::ibox0, [&]() {
5720 emitExpression(op.getCond(), ops);
5723 emitLocationInfoAndNewLine(ops);
5725 size_t caseValueIndex = 0;
5726 ps.scopedBox(PP::bbox2, [&]() {
5727 for (
auto &caseInfo : op.getCases()) {
5729 auto &
pattern = caseInfo.pattern;
5731 llvm::TypeSwitch<CasePattern *>(
pattern.get())
5732 .Case<CaseBitPattern>([&](
auto bitPattern) {
5735 ps.invokeWithStringOS([&](
auto &os) {
5736 os << bitPattern->getWidth() <<
"'b";
5737 for (
size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
5738 os <<
getLetter(bitPattern->getBit(e - bit - 1));
5741 .Case<CaseEnumPattern>([&](
auto enumPattern) {
5742 ps <<
PPExtString(emitter.fieldNameResolver.getEnumFieldName(
5743 cast<hw::EnumFieldAttr>(enumPattern->attr())));
5745 .Case<CaseExprPattern>([&](
auto) {
5746 emitExpression(op.getCaseValues()[caseValueIndex++], ops);
5748 .Case<CaseDefaultPattern>([&](
auto) { ps <<
"default"; })
5749 .Default([&](
auto) {
assert(
false &&
"unhandled case pattern"); });
5752 emitBlockAsStatement(caseInfo.block, emptyOps);
5758 ps.addCallback({op,
false});
5759 emitLocationInfoAndNewLine(ops);
5763LogicalResult StmtEmitter::visitStmt(InstanceOp op) {
5764 bool doNotPrint = op.getDoNotPrint();
5765 if (doNotPrint && !state.options.emitBindComments)
5770 emitSVAttributes(op);
5772 ps.addCallback({op,
true});
5775 <<
"/* This instance is elsewhere emitted as a bind statement."
5778 op->emitWarning() <<
"is emitted as a bind statement but has SV "
5779 "attributes. The attributes will not be emitted.";
5782 SmallPtrSet<Operation *, 8> ops;
5787 state.symbolCache.getDefinition(op.getReferencedModuleNameAttr());
5788 assert(moduleOp &&
"Invalid IR");
5792 if (!op.getParameters().empty()) {
5795 bool printed =
false;
5797 llvm::zip(op.getParameters(),
5798 moduleOp->getAttrOfType<ArrayAttr>(
"parameters"))) {
5799 auto param = cast<ParamDeclAttr>(std::get<0>(params));
5800 auto modParam = cast<ParamDeclAttr>(std::get<1>(params));
5802 if (param.getValue() == modParam.getValue())
5807 ps <<
" #(" << PP::bbox2 << PP::newline;
5810 ps <<
"," << PP::newline;
5814 state.globalNames.getParameterVerilogName(moduleOp, param.getName()));
5816 ps.invokeWithStringOS([&](
auto &os) {
5817 emitter.printParamValue(param.getValue(), os, [&]() {
5818 return op->emitOpError(
"invalid instance parameter '")
5819 << param.getName().getValue() <<
"' value";
5825 ps << PP::end << PP::newline <<
")";
5832 SmallVector<Value> instPortValues(modPortInfo.size());
5833 op.getValues(instPortValues, modPortInfo);
5834 emitInstancePortList(op, modPortInfo, instPortValues);
5836 ps.addCallback({op,
false});
5837 emitLocationInfoAndNewLine(ops);
5842 setPendingNewline();
5847void StmtEmitter::emitInstancePortList(Operation *op,
5849 ArrayRef<Value> instPortValues) {
5850 SmallPtrSet<Operation *, 8> ops;
5853 auto containingModule = cast<HWModuleOp>(emitter.currentModuleOp);
5854 ModulePortInfo containingPortList(containingModule.getPortList());
5860 size_t maxNameLength = 0;
5861 auto lineLength = state.options.getEmittedLineLength();
5862 for (
auto &elt : modPortInfo) {
5863 size_t nameLength = elt.getVerilogName().size();
5864 if (!lineLength || nameLength <= *lineLength / 3)
5865 maxNameLength = std::max(maxNameLength, nameLength);
5868 auto getWireForValue = [&](Value result) {
5869 return result.getUsers().begin()->getOperand(0);
5873 bool isFirst =
true;
5874 bool isZeroWidth =
false;
5876 for (
size_t portNum = 0, portEnd = modPortInfo.
size(); portNum < portEnd;
5878 auto &modPort = modPortInfo.
at(portNum);
5880 Value portVal = instPortValues[portNum];
5885 bool shouldPrintComma =
true;
5887 shouldPrintComma =
false;
5888 for (
size_t i = portNum + 1, e = modPortInfo.
size(); i != e; ++i)
5890 shouldPrintComma =
true;
5895 if (shouldPrintComma)
5898 emitLocationInfoAndNewLine(ops);
5913 ps.scopedBox(isZeroWidth ? PP::neverbox :
PP::
ibox2, [&]() {
5914 auto modPortName = modPort.getVerilogName();
5917 if (modPortName.size() <= maxNameLength)
5918 ps.spaces(maxNameLength - modPortName.size() + 1);
5922 ps.scopedBox(PP::ibox0, [&]() {
5929 if (!modPort.isOutput()) {
5931 isa_and_nonnull<ConstantOp>(portVal.getDefiningOp()))
5932 ps <<
"/* Zero width */";
5934 emitExpression(portVal, ops, LowestPrecedence);
5935 }
else if (portVal.use_empty()) {
5936 ps <<
"/* unused */";
5937 }
else if (portVal.hasOneUse() &&
5938 (output = dyn_cast_or_null<OutputOp>(
5939 portVal.getUses().begin()->getOwner()))) {
5944 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
5946 containingPortList.atOutput(outputPortNo).getVerilogName());
5948 portVal = getWireForValue(portVal);
5949 emitExpression(portVal, ops);
5955 if (!isFirst || isZeroWidth) {
5956 emitLocationInfoAndNewLine(ops);
5969LogicalResult StmtEmitter::visitSV(BindOp op) {
5970 emitter.emitBind(op);
5971 assert(state.pendingNewline);
5975LogicalResult StmtEmitter::visitSV(InterfaceOp op) {
5976 emitComment(op.getCommentAttr());
5978 emitSVAttributes(op);
5981 ps.addCallback({op,
true});
5983 setPendingNewline();
5985 emitStatementBlock(*op.getBodyBlock());
5987 ps <<
"endinterface" << PP::newline;
5988 ps.addCallback({op,
false});
5989 setPendingNewline();
5994 emitSVAttributes(op);
5996 ps.addCallback({op,
true});
5998 ps << op.getContent();
6000 ps.addCallback({op,
false});
6001 setPendingNewline();
6005LogicalResult StmtEmitter::visitSV(InterfaceSignalOp op) {
6007 emitSVAttributes(op);
6009 ps.addCallback({op,
true});
6011 ps << PP::neverbox <<
"// ";
6012 ps.invokeWithStringOS([&](
auto &os) {
6017 ps.invokeWithStringOS(
6018 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
6022 ps.addCallback({op,
false});
6023 setPendingNewline();
6027LogicalResult StmtEmitter::visitSV(InterfaceModportOp op) {
6029 ps.addCallback({op,
true});
6033 llvm::interleaveComma(op.getPorts(), ps, [&](
const Attribute &portAttr) {
6034 auto port = cast<ModportStructAttr>(portAttr);
6035 ps << PPExtString(stringifyEnum(port.getDirection().getValue())) <<
" ";
6036 auto *signalDecl = state.symbolCache.getDefinition(port.getSignal());
6037 ps << PPExtString(getSymOpName(signalDecl));
6041 ps.addCallback({op,
false});
6042 setPendingNewline();
6046LogicalResult StmtEmitter::visitSV(AssignInterfaceSignalOp op) {
6048 ps.addCallback({op,
true});
6049 SmallPtrSet<Operation *, 8> emitted;
6052 emitExpression(op.getIface(), emitted);
6053 ps <<
"." <<
PPExtString(op.getSignalName()) <<
" = ";
6054 emitExpression(op.getRhs(), emitted);
6056 ps.addCallback({op,
false});
6057 setPendingNewline();
6061LogicalResult StmtEmitter::visitSV(MacroErrorOp op) {
6063 ps <<
"`" << op.getMacroIdentifier();
6064 setPendingNewline();
6068LogicalResult StmtEmitter::visitSV(MacroDefOp op) {
6069 auto decl = op.getReferencedMacro(&state.symbolCache);
6072 ps.addCallback({op,
true});
6074 if (decl.getArgs()) {
6076 llvm::interleaveComma(*decl.getArgs(), ps, [&](
const Attribute &name) {
6077 ps << cast<StringAttr>(name);
6081 if (!op.getFormatString().empty()) {
6083 emitTextWithSubstitutions(ps, op.getFormatString(), op, {},
6086 ps.addCallback({op,
false});
6087 setPendingNewline();
6091void StmtEmitter::emitStatement(Operation *op) {
6098 if (isa_and_nonnull<ltl::LTLDialect, debug::DebugDialect>(op->getDialect()))
6102 if (succeeded(dispatchStmtVisitor(op)) || succeeded(dispatchSVVisitor(op)) ||
6103 succeeded(dispatchVerifVisitor(op)))
6106 emitOpError(op,
"emission to Verilog not supported");
6107 emitPendingNewlineIfNeeded();
6108 ps <<
"unknown MLIR operation " <<
PPExtString(op->getName().getStringRef());
6109 setPendingNewline();
6120 StmtEmitter &stmtEmitter) {
6127 if (isa<IfDefProceduralOp>(op->getParentOp()))
6135 SmallVector<Value, 8> exprsToScan(op->getOperands());
6140 while (!exprsToScan.empty()) {
6141 Operation *expr = exprsToScan.pop_back_val().getDefiningOp();
6148 if (
auto readInout = dyn_cast<sv::ReadInOutOp>(expr)) {
6149 auto *defOp = readInout.getOperand().getDefiningOp();
6156 if (isa<sv::WireOp>(defOp))
6161 if (!isa<RegOp, LogicOp>(defOp))
6167 if (isa<LogicOp>(defOp) &&
6168 stmtEmitter.emitter.expressionsEmittedIntoDecl.count(defOp))
6172 if (llvm::all_of(defOp->getResult(0).getUsers(), [&](Operation *op) {
6173 return isa<ReadInOutOp, PAssignOp, AssignOp>(op);
6181 exprsToScan.append(expr->getOperands().begin(),
6182 expr->getOperands().end());
6188 if (expr->getBlock() != op->getBlock())
6193 if (!stmtEmitter.emitter.expressionsEmittedIntoDecl.count(expr))
6200template <
class AssignTy>
6202 AssignTy singleAssign;
6203 if (llvm::all_of(op->getUsers(), [&](Operation *user) {
6204 if (hasSVAttributes(user))
6207 if (auto assign = dyn_cast<AssignTy>(user)) {
6210 singleAssign = assign;
6214 return isa<ReadInOutOp>(user);
6216 return singleAssign;
6222 return llvm::all_of(op2->getUsers(), [&](Operation *user) {
6226 if (op1->getBlock() != user->getBlock())
6232 return op1->isBeforeInBlock(user);
6236LogicalResult StmtEmitter::emitDeclaration(Operation *op) {
6237 emitSVAttributes(op);
6238 auto value = op->getResult(0);
6239 SmallPtrSet<Operation *, 8> opsForLocation;
6240 opsForLocation.insert(op);
6242 ps.addCallback({op,
true});
6245 auto type = value.getType();
6251 bool singleBitDefaultType = !isa<LocalParamOp>(op);
6253 ps.scopedBox(isZeroBit ? PP::neverbox :
PP::
ibox2, [&]() {
6254 unsigned targetColumn = 0;
6255 unsigned column = 0;
6258 if (maxDeclNameWidth > 0)
6259 targetColumn += maxDeclNameWidth + 1;
6262 ps <<
"// Zero width: " <<
PPExtString(word) << PP::space;
6263 }
else if (!word.empty()) {
6265 column += word.size();
6266 unsigned numSpaces = targetColumn > column ? targetColumn - column : 1;
6267 ps.spaces(numSpaces);
6268 column += numSpaces;
6271 SmallString<8> typeString;
6274 llvm::raw_svector_ostream stringStream(typeString);
6277 true, singleBitDefaultType);
6280 if (maxTypeWidth > 0)
6281 targetColumn += maxTypeWidth + 1;
6282 unsigned numSpaces = 0;
6283 if (!typeString.empty()) {
6285 column += typeString.size();
6288 if (targetColumn > column)
6289 numSpaces = targetColumn - column;
6290 ps.spaces(numSpaces);
6291 column += numSpaces;
6297 ps.invokeWithStringOS(
6298 [&](
auto &os) { emitter.printUnpackedTypePostfix(type, os); });
6301 if (state.options.printDebugInfo) {
6302 if (
auto innerSymOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
6303 auto innerSym = innerSymOp.getInnerSymAttr();
6304 if (innerSym && !innerSym.empty()) {
6306 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
6312 if (
auto localparam = dyn_cast<LocalParamOp>(op)) {
6313 ps << PP::space <<
"=" << PP::space;
6314 ps.invokeWithStringOS([&](
auto &os) {
6315 emitter.printParamValue(localparam.getValue(), os, [&]() {
6316 return op->emitOpError(
"invalid localparam value");
6321 if (
auto varOp = dyn_cast<VarOp>(op)) {
6322 if (
auto initValue = varOp.getInit()) {
6323 ps << PP::space <<
"=" << PP::space;
6324 ps.scopedBox(PP::ibox0, [&]() {
6325 emitExpression(initValue, opsForLocation, LowestPrecedence,
6331 if (
auto regOp = dyn_cast<RegOp>(op)) {
6332 if (
auto initValue = regOp.getInit()) {
6333 ps << PP::space <<
"=" << PP::space;
6334 ps.scopedBox(PP::ibox0, [&]() {
6335 emitExpression(initValue, opsForLocation, LowestPrecedence,
6344 if (!state.options.disallowDeclAssignments && isa<sv::WireOp>(op) &&
6348 if (
auto singleAssign = getSingleAssignAndCheckUsers<AssignOp>(op)) {
6349 auto *source = singleAssign.getSrc().getDefiningOp();
6353 if (!source || isa<ConstantOp>(source) ||
6354 op->getNextNode() == singleAssign) {
6355 ps << PP::space <<
"=" << PP::space;
6356 ps.scopedBox(PP::ibox0, [&]() {
6357 emitExpression(singleAssign.getSrc(), opsForLocation,
6361 emitter.assignsInlined.insert(singleAssign);
6369 if (!state.options.disallowDeclAssignments && isa<LogicOp>(op) &&
6373 if (
auto singleAssign = getSingleAssignAndCheckUsers<BPAssignOp>(op)) {
6376 auto *source = singleAssign.getSrc().getDefiningOp();
6380 if (!source || isa<ConstantOp>(source) ||
6383 ps << PP::space <<
"=" << PP::space;
6384 ps.scopedBox(PP::ibox0, [&]() {
6385 emitExpression(singleAssign.getSrc(), opsForLocation,
6390 emitter.assignsInlined.insert(singleAssign);
6391 emitter.expressionsEmittedIntoDecl.insert(op);
6398 ps.addCallback({op,
false});
6399 emitLocationInfoAndNewLine(opsForLocation);
6403void StmtEmitter::collectNamesAndCalculateDeclarationWidths(Block &block) {
6406 NameCollector collector(emitter);
6407 collector.collectNames(block);
6410 maxDeclNameWidth = collector.getMaxDeclNameWidth();
6411 maxTypeWidth = collector.getMaxTypeWidth();
6414void StmtEmitter::emitStatementBlock(Block &body) {
6415 ps.scopedBox(PP::bbox2, [&]() {
6420 llvm::SaveAndRestore<size_t> x(maxDeclNameWidth);
6421 llvm::SaveAndRestore<size_t> x2(maxTypeWidth);
6426 if (!isa<IfDefProceduralOp>(body.getParentOp()))
6427 collectNamesAndCalculateDeclarationWidths(body);
6430 for (
auto &op : body) {
6437void ModuleEmitter::emitStatement(Operation *op) {
6438 StmtEmitter(*
this, state.options).emitStatement(op);
6443void ModuleEmitter::emitSVAttributes(Operation *op) {
6451 setPendingNewline();
6458void ModuleEmitter::emitHWGeneratedModule(HWModuleGeneratedOp module) {
6459 auto verilogName =
module.getVerilogModuleNameAttr();
6461 ps <<
"// external generated module " <<
PPExtString(verilogName.getValue())
6463 setPendingNewline();
6472void ModuleEmitter::emitBind(BindOp op) {
6474 emitError(op,
"SV attributes emission is unimplemented for the op");
6475 InstanceOp inst = op.getReferencedInstance(&state.symbolCache);
6481 Operation *childMod =
6482 state.symbolCache.getDefinition(inst.getReferencedModuleNameAttr());
6486 ps.addCallback({op,
true});
6487 ps <<
"bind " <<
PPExtString(parentVerilogName.getValue()) << PP::nbsp
6488 <<
PPExtString(childVerilogName.getValue()) << PP::nbsp
6490 bool isFirst =
true;
6491 ps.scopedBox(PP::bbox2, [&]() {
6492 auto parentPortInfo = parentMod.getPortList();
6497 size_t maxNameLength = 0;
6498 auto lineLength = state.options.getEmittedLineLength();
6499 for (
auto &elt : childPortInfo) {
6500 auto portName = elt.getVerilogName();
6501 elt.name = Builder(inst.getContext()).getStringAttr(portName);
6502 size_t nameLength = elt.getName().size();
6503 if (!lineLength || nameLength <= *lineLength / 3)
6504 maxNameLength = std::max(maxNameLength, nameLength);
6507 SmallVector<Value> instPortValues(childPortInfo.size());
6508 inst.getValues(instPortValues, childPortInfo);
6510 for (
auto [idx, elt] :
llvm::enumerate(childPortInfo)) {
6512 Value portVal = instPortValues[idx];
6518 bool shouldPrintComma =
true;
6520 shouldPrintComma =
false;
6521 for (
size_t i = idx + 1, e = childPortInfo.size(); i != e; ++i)
6523 shouldPrintComma =
true;
6528 if (shouldPrintComma)
6541 ps << PP::neverbox <<
"//";
6546 if (elt.getName().size() <= maxNameLength)
6547 ps.nbsp(maxNameLength - elt.getName().size());
6549 llvm::SmallPtrSet<Operation *, 4> ops;
6550 if (elt.isOutput()) {
6551 assert((portVal.hasOneUse() || portVal.use_empty()) &&
6552 "output port must have either single or no use");
6553 if (portVal.use_empty()) {
6554 ps <<
"/* unused */";
6555 }
else if (
auto output = dyn_cast_or_null<OutputOp>(
6556 portVal.getUses().begin()->getOwner())) {
6559 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
6561 parentPortList.atOutput(outputPortNo).getVerilogName());
6563 portVal = portVal.getUsers().begin()->getOperand(0);
6564 ExprEmitter(*
this, ops)
6565 .emitExpression(portVal, LowestPrecedence,
6569 ExprEmitter(*
this, ops)
6570 .emitExpression(portVal, LowestPrecedence,
6583 ps.addCallback({op,
false});
6584 setPendingNewline();
6587void ModuleEmitter::emitBindInterface(BindInterfaceOp op) {
6589 emitError(op,
"SV attributes emission is unimplemented for the op");
6591 auto instance = op.getReferencedInstance(&state.symbolCache);
6593 auto *
interface = op->getParentOfType<ModuleOp>().lookupSymbol(
6594 instance.getInterfaceType().getInterface());
6596 ps.addCallback({op,
true});
6597 ps <<
"bind " <<
PPExtString(instantiator) << PP::nbsp
6598 <<
PPExtString(cast<InterfaceOp>(*interface).getSymName()) << PP::nbsp
6600 ps.addCallback({op,
false});
6601 setPendingNewline();
6604void ModuleEmitter::emitParameters(Operation *module, ArrayAttr params) {
6608 auto printParamType = [&](Type type, Attribute defaultValue,
6609 SmallString<8> &result) {
6611 llvm::raw_svector_ostream sstream(result);
6616 if (
auto intAttr = dyn_cast<IntegerAttr>(defaultValue))
6617 if (intAttr.getValue().getBitWidth() == 32)
6619 if (
auto fpAttr = dyn_cast<FloatAttr>(defaultValue))
6620 if (fpAttr.getType().isF64())
6623 if (isa<NoneType>(type))
6630 if (
auto intType = type_dyn_cast<IntegerType>(type))
6631 if (intType.getWidth() == 32) {
6632 sstream <<
"/*integer*/";
6636 printPackedType(type, sstream, module->getLoc(),
6644 size_t maxTypeWidth = 0;
6645 SmallString<8> scratch;
6646 for (
auto param : params) {
6647 auto paramAttr = cast<ParamDeclAttr>(param);
6649 printParamType(paramAttr.getType(), paramAttr.getValue(), scratch);
6650 maxTypeWidth = std::max(scratch.size(), maxTypeWidth);
6653 if (maxTypeWidth > 0)
6656 ps.scopedBox(PP::bbox2, [&]() {
6657 ps << PP::newline <<
"#(";
6658 ps.scopedBox(PP::cbox0, [&]() {
6661 [&](Attribute param) {
6662 auto paramAttr = cast<ParamDeclAttr>(param);
6663 auto defaultValue = paramAttr.getValue();
6665 printParamType(paramAttr.getType(), defaultValue, scratch);
6666 if (!scratch.empty())
6668 if (scratch.size() < maxTypeWidth)
6669 ps.nbsp(maxTypeWidth - scratch.size());
6671 ps <<
PPExtString(state.globalNames.getParameterVerilogName(
6672 module, paramAttr.getName()));
6676 ps.invokeWithStringOS([&](
auto &os) {
6678 return module->emitError("parameter '")
6679 << paramAttr.getName().getValue()
6680 << "' has invalid value";
6685 [&]() { ps <<
"," << PP::newline; });
6691void ModuleEmitter::emitPortList(Operation *module,
6693 bool emitAsTwoStateType) {
6695 if (portInfo.
size())
6696 emitLocationInfo(module->getLoc());
6700 bool hasOutputs =
false, hasZeroWidth =
false;
6701 size_t maxTypeWidth = 0, lastNonZeroPort = -1;
6702 SmallVector<SmallString<8>, 16> portTypeStrings;
6704 for (
size_t i = 0, e = portInfo.
size(); i < e; ++i) {
6705 auto port = portInfo.
at(i);
6709 lastNonZeroPort = i;
6712 portTypeStrings.push_back({});
6714 llvm::raw_svector_ostream stringStream(portTypeStrings.back());
6716 module->getLoc(), {},
true,
true, emitAsTwoStateType);
6719 maxTypeWidth = std::max(portTypeStrings.back().size(), maxTypeWidth);
6722 if (maxTypeWidth > 0)
6726 ps.scopedBox(PP::bbox2, [&]() {
6727 for (
size_t portIdx = 0, e = portInfo.
size(); portIdx != e;) {
6728 auto lastPort = e - 1;
6731 auto portType = portInfo.
at(portIdx).
type;
6735 bool isZeroWidth =
false;
6740 ps << (isZeroWidth ?
"// " :
" ");
6744 auto thisPortDirection = portInfo.
at(portIdx).
dir;
6745 size_t startOfNamePos = (hasOutputs ? 7 : 6) +
6746 (state.options.emitWireInPorts ? 5 : 0) +
6751 if (!isa<ModportType>(portType)) {
6752 switch (thisPortDirection) {
6753 case ModulePort::Direction::Output:
6756 case ModulePort::Direction::Input:
6757 ps << (hasOutputs ?
"input " :
"input ");
6759 case ModulePort::Direction::InOut:
6760 ps << (hasOutputs ?
"inout " :
"inout ");
6763 if (state.options.emitWireInPorts)
6765 if (!portTypeStrings[portIdx].
empty())
6766 ps << portTypeStrings[portIdx];
6767 if (portTypeStrings[portIdx].size() < maxTypeWidth)
6768 ps.nbsp(maxTypeWidth - portTypeStrings[portIdx].size());
6770 ps << portTypeStrings[portIdx];
6771 if (portTypeStrings[portIdx].size() < startOfNamePos)
6772 ps.nbsp(startOfNamePos - portTypeStrings[portIdx].size());
6779 ps.invokeWithStringOS(
6780 [&](
auto &os) { printUnpackedTypePostfix(portType, os); });
6783 auto innerSym = portInfo.
at(portIdx).
getSym();
6784 if (state.options.printDebugInfo && innerSym && !innerSym.empty()) {
6786 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
6791 if (portIdx != lastNonZeroPort && portIdx != lastPort)
6795 if (
auto loc = portInfo.
at(portIdx).
loc)
6796 emitLocationInfo(loc);
6806 if (!state.options.disallowPortDeclSharing) {
6807 while (portIdx != e && portInfo.
at(portIdx).
dir == thisPortDirection &&
6810 auto port = portInfo.
at(portIdx);
6814 bool isZeroWidth =
false;
6819 ps << (isZeroWidth ?
"// " :
" ");
6822 ps.nbsp(startOfNamePos);
6825 StringRef name = port.getVerilogName();
6829 ps.invokeWithStringOS(
6830 [&](
auto &os) { printUnpackedTypePostfix(port.type, os); });
6833 auto sym = port.getSym();
6834 if (state.options.printDebugInfo && sym && !sym.empty())
6835 ps <<
" /* inner_sym: " <<
PPExtString(sym.getSymName().getValue())
6839 if (portIdx != lastNonZeroPort && portIdx != lastPort)
6843 if (
auto loc = port.loc)
6844 emitLocationInfo(loc);
6855 if (!portInfo.
size()) {
6857 SmallPtrSet<Operation *, 8> moduleOpSet;
6858 moduleOpSet.insert(module);
6859 emitLocationInfoAndNewLine(moduleOpSet);
6862 ps <<
");" << PP::newline;
6863 setPendingNewline();
6867void ModuleEmitter::emitHWModule(
HWModuleOp module) {
6868 currentModuleOp =
module;
6870 emitComment(module.getCommentAttr());
6871 emitSVAttributes(module);
6873 ps.addCallback({module,
true});
6877 emitParameters(module, module.getParameters());
6881 assert(state.pendingNewline);
6884 StmtEmitter(*
this, state.options).emitStatementBlock(*module.getBodyBlock());
6887 ps.addCallback({module,
false});
6889 setPendingNewline();
6891 currentModuleOp =
nullptr;
6894void ModuleEmitter::emitFunc(FuncOp func) {
6896 if (func.isDeclaration())
6899 currentModuleOp = func;
6901 ps.addCallback({func,
true});
6905 StmtEmitter(*
this, state.options).emitStatementBlock(*func.getBodyBlock());
6907 ps <<
"endfunction";
6909 currentModuleOp =
nullptr;
6918 explicit FileEmitter(VerilogEmitterState &state) : EmitterBase(state) {}
6925 void emit(emit::FileListOp op);
6928 void emit(Block *block);
6930 void emitOp(emit::RefOp op);
6931 void emitOp(emit::VerbatimOp op);
6935 for (Operation &op : *block) {
6936 TypeSwitch<Operation *>(&op)
6937 .Case<emit::VerbatimOp, emit::RefOp>([&](
auto op) {
emitOp(op); })
6938 .Case<VerbatimOp, IfDefOp, MacroDefOp, sv::FuncDPIImportOp>(
6939 [&](
auto op) { ModuleEmitter(state).emitStatement(op); })
6940 .Case<BindOp>([&](
auto op) { ModuleEmitter(state).emitBind(op); })
6941 .Case<BindInterfaceOp>(
6942 [&](
auto op) { ModuleEmitter(state).emitBindInterface(op); })
6943 .Case<TypeScopeOp>([&](
auto typedecls) {
6944 ModuleEmitter(state).emitStatement(typedecls);
6947 [&](
auto op) { emitOpError(op,
"cannot be emitted to a file"); });
6953 for (
auto sym : op.getFiles()) {
6954 auto fileName = cast<FlatSymbolRefAttr>(sym).getAttr();
6956 auto it = state.fileMapping.find(fileName);
6957 if (it == state.fileMapping.end()) {
6958 emitOpError(op,
" references an invalid file: ") << sym;
6962 auto file = cast<emit::FileOp>(it->second);
6963 ps << PP::neverbox <<
PPExtString(file.getFileName()) << PP::end
6970 StringAttr target = op.getTargetAttr().getAttr();
6971 auto *targetOp = state.symbolCache.getDefinition(target);
6972 assert(isa<emit::Emittable>(targetOp) &&
"target must be emittable");
6974 TypeSwitch<Operation *>(targetOp)
6975 .Case<sv::FuncOp>([&](
auto func) { ModuleEmitter(state).emitFunc(func); })
6976 .Case<hw::HWModuleOp>(
6977 [&](
auto module) { ModuleEmitter(state).emitHWModule(module); })
6978 .Case<TypeScopeOp, PackageOp>([&](
auto typedecls) {
6979 ModuleEmitter(state).emitStatement(typedecls);
6982 [&](
auto op) { emitOpError(op,
"cannot be emitted to a file"); });
6988 SmallPtrSet<Operation *, 8> ops;
6993 StringRef text = op.getText();
6997 const auto &[lhs, rhs] = text.split(
'\n');
7001 ps << PP::end << PP::newline << PP::neverbox;
7003 }
while (!text.empty());
7006 emitLocationInfoAndNewLine(ops);
7024 auto collectInstanceSymbolsAndBinds = [&](Operation *moduleOp) {
7025 moduleOp->walk([&](Operation *op) {
7027 if (
auto name = op->getAttrOfType<InnerSymAttr>(
7030 cast<mlir::SymbolOpInterface>(moduleOp).getNameAttr(),
7031 name.getSymName(), op);
7032 if (isa<BindOp>(op))
7038 auto collectPorts = [&](
auto moduleOp) {
7039 auto portInfo = moduleOp.getPortList();
7040 for (
auto [i, p] : llvm::enumerate(portInfo)) {
7041 if (!p.attrs || p.attrs.empty())
7043 for (NamedAttribute portAttr : p.attrs) {
7044 if (
auto sym = dyn_cast<InnerSymAttr>(portAttr.getValue())) {
7053 DenseMap<StringAttr, SmallVector<emit::FileOp>> symbolsToFiles;
7054 for (
auto file :
designOp.getOps<emit::FileOp>())
7055 for (
auto refs : file.getOps<emit::RefOp>())
7056 symbolsToFiles[refs.getTargetAttr().getAttr()].push_back(file);
7058 SmallString<32> outputPath;
7059 for (
auto &op : *
designOp.getBody()) {
7062 bool isFileOp = isa<emit::FileOp, emit::FileListOp>(&op);
7064 bool hasFileName =
false;
7065 bool emitReplicatedOps = !isFileOp;
7066 bool addToFilelist = !isFileOp;
7072 auto attr = op.getAttrOfType<hw::OutputFileAttr>(
"output_file");
7074 LLVM_DEBUG(llvm::dbgs() <<
"Found output_file attribute " << attr
7075 <<
" on " << op <<
"\n";);
7076 if (!attr.isDirectory())
7079 emitReplicatedOps = attr.getIncludeReplicatedOps().getValue();
7080 addToFilelist = !attr.getExcludeFromFilelist().getValue();
7083 auto separateFile = [&](Operation *op, Twine defaultFileName =
"") {
7088 if (!defaultFileName.isTriviallyEmpty()) {
7089 llvm::sys::path::append(outputPath, defaultFileName);
7091 op->emitError(
"file name unspecified");
7093 llvm::sys::path::append(outputPath,
"error.out");
7097 auto destFile = StringAttr::get(op->getContext(), outputPath);
7098 auto &file =
files[destFile];
7099 file.ops.push_back(info);
7100 file.emitReplicatedOps = emitReplicatedOps;
7101 file.addToFilelist = addToFilelist;
7102 file.isVerilog = outputPath.ends_with(
".sv");
7107 if (!attr || attr.isDirectory()) {
7108 auto excludeFromFileListAttr =
7109 BoolAttr::get(op->getContext(), !addToFilelist);
7110 auto includeReplicatedOpsAttr =
7111 BoolAttr::get(op->getContext(), emitReplicatedOps);
7112 auto outputFileAttr = hw::OutputFileAttr::get(
7113 destFile, excludeFromFileListAttr, includeReplicatedOpsAttr);
7114 op->setAttr(
"output_file", outputFileAttr);
7120 TypeSwitch<Operation *>(&op)
7121 .Case<emit::FileOp, emit::FileListOp>([&](
auto file) {
7123 fileMapping.try_emplace(file.getSymNameAttr(), file);
7124 separateFile(file, file.getFileName());
7126 .Case<emit::FragmentOp>([&](
auto fragment) {
7129 .Case<HWModuleOp>([&](
auto mod) {
7131 auto sym = mod.getNameAttr();
7134 collectInstanceSymbolsAndBinds(mod);
7136 if (
auto it = symbolsToFiles.find(sym); it != symbolsToFiles.end()) {
7137 if (it->second.size() != 1 || attr) {
7140 op.emitError(
"modules can be emitted to a single file");
7148 if (attr || separateModules)
7154 .Case<InterfaceOp>([&](InterfaceOp intf) {
7159 for (
auto &op : *intf.getBodyBlock())
7160 if (
auto symOp = dyn_cast<mlir::SymbolOpInterface>(op))
7161 if (
auto name = symOp.getNameAttr())
7165 if (attr || separateModules)
7166 separateFile(intf, intf.getSymName() +
".sv");
7170 .Case<PackageOp>([&](PackageOp package) {
7172 auto sym = package.getSymNameAttr();
7175 if (
auto it = symbolsToFiles.find(sym); it != symbolsToFiles.end()) {
7176 if (it->second.size() != 1 || attr) {
7178 "packages can only be emitted to a single file");
7187 if (attr || separateModules)
7192 .Case<PackageExternOp>([&](PackageExternOp package) {
7197 separateFile(op, op.getOutputFile().getFilename().getValue());
7199 .Case<HWModuleExternOp, sv::SVVerbatimModuleOp>([&](
auto op) {
7205 .Case<VerbatimOp, IfDefOp, MacroDefOp, IncludeOp, FuncDPIImportOp>(
7206 [&](Operation *op) {
7212 separateFile(op,
"");
7214 .Case<FuncOp>([&](
auto op) {
7220 separateFile(op,
"");
7224 .Case<HWGeneratorSchemaOp>([&](HWGeneratorSchemaOp schemaOp) {
7227 .Case<HierPathOp>([&](HierPathOp hierPathOp) {
7236 separateFile(op,
"");
7238 .Case<BindOp>([&](
auto op) {
7240 separateFile(op,
"bindfile.sv");
7245 .Case<MacroErrorOp>([&](
auto op) {
replicatedOps.push_back(op); })
7246 .Case<MacroDeclOp>([&](
auto op) {
7249 .Case<sv::ReserveNamesOp>([](
auto op) {
7252 .Case<om::ClassLike>([&](
auto op) {
7255 .Case<om::ConstantOp>([&](
auto op) {
7258 .Default([&](
auto *) {
7259 op.emitError(
"unknown operation (SharedEmitterState::gatherFiles)");
7279 size_t lastReplicatedOp = 0;
7281 bool emitHeaderInclude =
7284 if (emitHeaderInclude)
7287 size_t numReplicatedOps =
7292 DenseSet<emit::FragmentOp> includedFragments;
7293 for (
const auto &opInfo : file.
ops) {
7294 Operation *op = opInfo.op;
7298 for (; lastReplicatedOp < std::min(opInfo.position, numReplicatedOps);
7304 if (
auto fragments =
7306 for (
auto sym : fragments.getAsRange<FlatSymbolRefAttr>()) {
7310 op->emitError(
"cannot find referenced fragment ") << sym;
7313 emit::FragmentOp fragment = it->second;
7314 if (includedFragments.insert(fragment).second) {
7315 thingsToEmit.emplace_back(it->second);
7321 thingsToEmit.emplace_back(op);
7326 for (; lastReplicatedOp < numReplicatedOps; lastReplicatedOp++)
7331 TypeSwitch<Operation *>(op)
7332 .Case<
HWModuleOp>([&](
auto op) { ModuleEmitter(state).emitHWModule(op); })
7333 .Case<HWModuleExternOp, sv::SVVerbatimModuleOp, PackageExternOp>(
7337 .Case<HWModuleGeneratedOp>(
7338 [&](
auto op) { ModuleEmitter(state).emitHWGeneratedModule(op); })
7339 .Case<HWGeneratorSchemaOp>([&](
auto op) { })
7340 .Case<BindOp>([&](
auto op) { ModuleEmitter(state).emitBind(op); })
7341 .Case<InterfaceOp, VerbatimOp, IfDefOp, sv::SVVerbatimSourceOp>(
7342 [&](
auto op) { ModuleEmitter(state).emitStatement(op); })
7343 .Case<TypeScopeOp, PackageOp>([&](
auto typedecls) {
7344 ModuleEmitter(state).emitStatement(typedecls);
7346 .Case<emit::FileOp, emit::FileListOp, emit::FragmentOp>(
7348 .Case<MacroErrorOp, MacroDefOp, FuncDPIImportOp>(
7349 [&](
auto op) { ModuleEmitter(state).emitStatement(op); })
7350 .Case<FuncOp>([&](
auto op) { ModuleEmitter(state).emitFunc(op); })
7351 .Case<IncludeOp>([&](
auto op) { ModuleEmitter(state).emitStatement(op); })
7352 .Default([&](
auto *op) {
7353 state.encounteredError =
true;
7354 op->emitError(
"unknown operation (ExportVerilog::emitOperation)");
7361 llvm::formatted_raw_ostream &os,
7362 StringAttr fileName,
bool parallelize) {
7367 parallelize &=
context->isMultithreadingEnabled();
7378 size_t lineOffset = 0;
7379 for (
auto &entry : thingsToEmit) {
7380 entry.verilogLocs.setStream(os);
7381 if (
auto *op = entry.getOperation()) {
7386 state.addVerilogLocToOps(lineOffset, fileName);
7388 os << entry.getStringData();
7393 if (state.encounteredError)
7411 SmallString<256> buffer;
7412 llvm::raw_svector_ostream tmpStream(buffer);
7413 llvm::formatted_raw_ostream rs(tmpStream);
7421 if (state.encounteredError)
7426 for (
auto &entry : thingsToEmit) {
7429 auto *op = entry.getOperation();
7431 auto lineOffset = os.getLine() + 1;
7432 os << entry.getStringData();
7436 entry.verilogLocs.updateIRWithLoc(lineOffset, fileName,
context);
7439 entry.verilogLocs.setStream(os);
7446 state.addVerilogLocToOps(0, fileName);
7447 if (state.encounteredError) {
7466 module.emitWarning()
7467 << "`emitReplicatedOpsToHeader` option is enabled but an header is "
7468 "created only at SplitExportVerilog";
7477 for (
const auto &it : emitter.
files) {
7478 list.emplace_back(
"\n// ----- 8< ----- FILE \"" + it.first.str() +
7479 "\" ----- 8< -----\n\n");
7485 std::string contents(
"\n// ----- 8< ----- FILE \"" + it.first().str() +
7486 "\" ----- 8< -----\n\n");
7487 for (
auto &name : it.second)
7488 contents += name.str() +
"\n";
7489 list.emplace_back(contents);
7492 llvm::formatted_raw_ostream rs(os);
7496 emitter.
emitOps(list, rs, StringAttr::get(module.getContext(),
""),
7503 SmallVector<HWEmittableModuleLike> modulesToPrepare;
7505 [&](HWEmittableModuleLike op) { modulesToPrepare.push_back(op); });
7506 if (failed(failableParallelForEach(
7507 module->getContext(), modulesToPrepare,
7508 [&](
auto op) { return prepareHWModule(op, options); })))
7515struct ExportVerilogPass
7516 :
public circt::impl::ExportVerilogBase<ExportVerilogPass> {
7517 ExportVerilogPass(raw_ostream &os) : os(os) {}
7518 void runOnOperation()
override {
7520 mlir::OpPassManager preparePM(
"builtin.module");
7521 preparePM.addPass(createLegalizeAnonEnums());
7522 auto &modulePM = preparePM.nestAny();
7523 modulePM.addPass(createPrepareForEmission());
7524 if (failed(runPipeline(preparePM, getOperation())))
7525 return signalPassFailure();
7528 return signalPassFailure();
7535struct ExportVerilogStreamOwnedPass :
public ExportVerilogPass {
7536 ExportVerilogStreamOwnedPass(std::unique_ptr<llvm::raw_ostream> os)
7537 : ExportVerilogPass{*os} {
7538 owned = std::move(os);
7542 std::unique_ptr<llvm::raw_ostream> owned;
7546std::unique_ptr<mlir::Pass>
7548 return std::make_unique<ExportVerilogStreamOwnedPass>(std::move(os));
7551std::unique_ptr<mlir::Pass>
7553 return std::make_unique<ExportVerilogPass>(os);
7564static std::unique_ptr<llvm::ToolOutputFile>
7568 SmallString<128> outputFilename(dirname);
7570 auto outputDir = llvm::sys::path::parent_path(outputFilename);
7573 std::error_code error = llvm::sys::fs::create_directories(outputDir);
7575 emitter.
designOp.emitError(
"cannot create output directory \"")
7576 << outputDir <<
"\": " << error.message();
7582 std::string errorMessage;
7583 auto output = mlir::openOutputFile(outputFilename, &errorMessage);
7585 emitter.
designOp.emitError(errorMessage);
7602 llvm::formatted_raw_ostream rs(output->os());
7608 StringAttr::get(fileName.getContext(), output->getFilename()),
7614 StringRef dirname) {
7625 bool insertSuccess =
7627 .insert({StringAttr::get(module.getContext(),
circtHeader),
7633 if (!insertSuccess) {
7634 module.emitError() << "tried to emit a heder to " << circtHeader
7635 << ", but the file is used as an output too.";
7641 parallelForEach(module->getContext(), emitter.
files.begin(),
7642 emitter.
files.end(), [&](
auto &it) {
7643 createSplitOutputFile(it.first, it.second, dirname,
7648 SmallString<128> filelistPath(dirname);
7649 llvm::sys::path::append(filelistPath,
"filelist.f");
7651 std::string errorMessage;
7652 auto output = mlir::openOutputFile(filelistPath, &errorMessage);
7654 module->emitError(errorMessage);
7658 for (
const auto &it : emitter.
files) {
7659 if (it.second.addToFilelist)
7660 output->os() << it.first.str() <<
"\n";
7669 for (
auto &name : it.second)
7670 output->os() << name.str() <<
"\n";
7679 SmallVector<HWEmittableModuleLike> modulesToPrepare;
7681 [&](HWEmittableModuleLike op) { modulesToPrepare.push_back(op); });
7682 if (failed(failableParallelForEach(
7683 module->getContext(), modulesToPrepare,
7684 [&](
auto op) { return prepareHWModule(op, options); })))
7692struct ExportSplitVerilogPass
7693 :
public circt::impl::ExportSplitVerilogBase<ExportSplitVerilogPass> {
7694 ExportSplitVerilogPass(StringRef directory) {
7695 directoryName = directory.str();
7697 void runOnOperation()
override {
7699 mlir::OpPassManager preparePM(
"builtin.module");
7702 modulePM.addPass(createPrepareForEmission());
7703 if (failed(runPipeline(preparePM, getOperation())))
7704 return signalPassFailure();
7707 return signalPassFailure();
7712std::unique_ptr<mlir::Pass>
7714 return std::make_unique<ExportSplitVerilogPass>(directory);
assert(baseType &&"element must be base type")
static bool hasSVAttributes(Operation *op)
static void emitOperation(VerilogEmitterState &state, Operation *op)
static LogicalResult exportVerilogImpl(ModuleOp module, llvm::raw_ostream &os)
static void emitDim(Attribute width, raw_ostream &os, Location loc, ModuleEmitter &emitter, bool downTo)
Emit a single dimension.
static int compareLocs(Location lhs, Location rhs)
static bool isDuplicatableExpression(Operation *op)
static TypedAttr getInt32Attr(MLIRContext *ctx, uint32_t value)
StringRef getVerilogValueName(Value val)
Retrieve value's verilog name from IR.
static void sortLocationVector(TVector &vec)
static bool hasStructType(Type type)
Return true if the element type is emitted as a type name or a keyword (struct, union,...
static StringRef getVerilogDeclWord(Operation *op, const ModuleEmitter &emitter)
Return the word (e.g.
static bool isOkToBitSelectFrom(Value v)
Most expressions are invalid to bit-select from in Verilog, but some things are ok.
static LogicalResult exportSplitVerilogImpl(ModuleOp module, StringRef dirname)
static int compareLocsImpl(mlir::NameLoc lhs, mlir::NameLoc rhs)
static void emitZeroWidthIndexingValue(PPS &os)
Emits a known-safe token that is legal when indexing into singleton arrays.
static bool checkDominanceOfUsers(Operation *op1, Operation *op2)
Return true if op1 dominates users of op2.
static void emitDims(ArrayRef< Attribute > dims, raw_ostream &os, Location loc, ModuleEmitter &emitter)
Emit a list of packed dimensions.
static bool isExpressionEmittedInlineIntoProceduralDeclaration(Operation *op, StmtEmitter &stmtEmitter)
Given an operation corresponding to a VerilogExpression, determine whether it is safe to emit inline ...
static StringRef getPortVerilogName(Operation *module, size_t portArgNum)
Return the verilog name of the port for the module.
static void collectAndUniqueLocations(Location loc, SmallPtrSetImpl< Attribute > &locationSet)
Pull apart any fused locations into the location set, such that they are uniqued.
static Value isZeroExtension(Value value)
If the specified extension is a zero extended version of another value, return the shorter value,...
static void createSplitOutputFile(StringAttr fileName, FileInfo &file, StringRef dirname, SharedEmitterState &emitter)
static StringRef getInputPortVerilogName(Operation *module, size_t portArgNum)
Return the verilog name of the port for the module.
static StringRef getTwoStateIntegerAtomType(size_t width)
Return a 2-state integer atom type name if the width matches.
static TypedAttr getIntAttr(MLIRContext *ctx, Type t, const APInt &value)
static BlockStatementCount countStatements(Block &block)
Compute how many statements are within this block, for begin/end markers.
static Type stripUnpackedTypes(Type type)
Given a set of known nested types (those supported by this pass), strip off leading unpacked types.
FailureOr< int > dispatchCompareLocations(Location lhs, Location rhs)
static bool haveMatchingDims(Type a, Type b, Location loc, llvm::function_ref< mlir::InFlightDiagnostic(Location)> errorHandler)
True iff 'a' and 'b' have the same wire dims.
static void getTypeDims(SmallVectorImpl< Attribute > &dims, Type type, Location loc, llvm::function_ref< mlir::InFlightDiagnostic(Location)> errorHandler)
Push this type's dimension into a vector.
static bool isExpressionUnableToInline(Operation *op, const LoweringOptions &options)
Return true if we are unable to ever inline the specified operation.
void emitFunctionSignature(ModuleEmitter &emitter, PPS &ps, FuncOp op, bool isAutomatic=false, bool emitAsTwoStateType=false)
static AssignTy getSingleAssignAndCheckUsers(Operation *op)
static bool hasLeadingUnpackedType(Type type)
Return true if the type has a leading unpacked type.
static bool printPackedTypeImpl(Type type, raw_ostream &os, Location loc, SmallVectorImpl< Attribute > &dims, bool implicitIntType, bool singleBitDefaultType, ModuleEmitter &emitter, Type optionalAliasType={}, bool emitAsTwoStateType=false)
Output the basic type that consists of packed and primitive types.
static void emitSVAttributesImpl(PPS &ps, ArrayAttr attrs, bool mayBreak)
Emit SystemVerilog attributes.
static bool hasExplicitDataType(Type type)
Returns true if type prints its own SystemVerilog data_type, so its declaration must not be prefixed ...
static bool isDuplicatableNullaryExpression(Operation *op)
Return true for nullary operations that are better emitted multiple times as inline expression (when ...
static IfOp findNestedElseIf(Block *elseBlock)
Find a nested IfOp in an else block that can be printed as else if instead of nesting it into a new b...
StringRef circtHeaderInclude
static ValueRange getNonOverlappingConcatSubrange(Value value)
For a value concat(..., delay(const(true), 1, 0)), return ....
static std::unique_ptr< Context > context
static StringRef legalizeName(StringRef name, llvm::StringMap< size_t > &nextGeneratedNameIDs)
Legalize the given name such that it only consists of valid identifier characters in Verilog and does...
static void printParamValue(OpAsmPrinter &p, Operation *, Attribute value, Type resultType)
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
RewritePatternSet pattern
static InstancePath empty
void emit(emit::FragmentOp op)
FileEmitter(VerilogEmitterState &state)
void emit(emit::FileOp op)
void emitOp(emit::RefOp op)
LocationEmitter(LoweringOptions::LocationInfoStyle style, Location loc)
void emitLocationSetInfo(llvm::raw_string_ostream &os, LoweringOptions::LocationInfoStyle style, const SmallPtrSetImpl< Attribute > &locationSet)
LocationEmitter(LoweringOptions::LocationInfoStyle style, const SmallPtrSetImpl< Operation * > &ops)
Track the output verilog line,column number information for every op.
void setStream(llvm::formatted_raw_ostream &f)
Set the output stream.
void updateIRWithLoc(unsigned lineOffset, StringAttr fileName, MLIRContext *context)
Called after the verilog has been exported and the corresponding locations are recorded in the map.
This class wraps an operation or a fixed string that should be emitted.
Operation * getOperation() const
If the value is an Operation*, return it. Otherwise return null.
OpLocMap verilogLocs
Verilog output location information for entry.
void setString(StringRef value)
This method transforms the entry from an operation to a string value.
Signals that an operation's regions are procedural.
This stores lookup tables to make manipulating and working with the IR more efficient.
void freeze()
Mark the cache as frozen, which allows it to be shared across threads.
void addDefinition(mlir::StringAttr modSymbol, mlir::StringAttr name, mlir::Operation *op, size_t port=invalidPort)
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
This helps visit TypeOp nodes.
This helps visit TypeOp nodes.
ResultType dispatchTypeOpVisitor(Operation *op, ExtraArgs... args)
ResultType visitUnhandledTypeOp(Operation *op, ExtraArgs... args)
This callback is invoked on any combinational operations that are not handled by the concrete visitor...
ResultType visitInvalidTypeOp(Operation *op, ExtraArgs... args)
This callback is invoked on any non-expression operations.
Note: Callable class must implement a callable with signature: void (Data)
Wrap the TokenStream with a helper for CallbackTokens, to record the print events on the stream.
auto scopedBox(T &&t, Callable &&c, Token close=EndToken())
Open a box, invoke the lambda, and close it after.
bool isExpressionEmittedInline(Operation *op, const LoweringOptions &options)
Return true if this expression should be emitted inline into any statement that uses it.
bool isVerilogExpression(Operation *op)
This predicate returns true if the specified operation is considered a potentially inlinable Verilog ...
GlobalNameTable legalizeGlobalNames(ModuleOp topLevel, const LoweringOptions &options)
Rewrite module names and interfaces to not conflict with each other or with Verilog keywords.
StringAttr inferStructuralNameForTemporary(Value expr)
Given an expression that is spilled into a temporary wire, try to synthesize a better name than "_T_4...
DenseMap< StringAttr, Operation * > FileMapping
Mapping from symbols to file operations.
static bool isConstantExpression(Operation *op)
Return whether an operation is a constant.
bool isZeroBitType(Type type)
Return true if this is a zero bit type, e.g.
StringRef getSymOpName(Operation *symOp)
Return the verilog name of the operations that can define a symbol.
StringRef getFragmentsAttrName()
Return the name of the fragments array attribute.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
bool isCombinational(Operation *op)
Return true if the specified operation is a combinational logic op.
StringRef getVerilogModuleName(Operation *module)
StringAttr getVerilogModuleNameAttr(Operation *module)
Returns the verilog module name attribute or symbol name of any module-like operations.
mlir::Type getCanonicalType(mlir::Type type)
Recursively remove HW type aliases from a type and its subelements.
PP
Send one of these to TokenStream to add the corresponding token.
mlir::ArrayAttr getSVAttributes(mlir::Operation *op)
Return all the SV attributes of an operation, or null if there are none.
char getLetter(CasePatternBit bit)
Return the letter for the specified pattern bit, e.g. "0", "1", "x" or "z".
circt::hw::InOutType InOutType
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createExportSplitVerilogPass(llvm::StringRef directory="./")
mlir::LogicalResult exportVerilog(mlir::ModuleOp module, llvm::raw_ostream &os)
Export a module containing HW, and SV dialect code.
mlir::LogicalResult exportSplitVerilog(mlir::ModuleOp module, llvm::StringRef dirname)
Export a module containing HW, and SV dialect code, as one file per SV module.
const char * getCirctVersionComment()
std::unique_ptr< llvm::ToolOutputFile > createOutputFile(StringRef filename, StringRef dirname, function_ref< InFlightDiagnostic()> emitError)
Creates an output file with the given filename in the specified directory.
std::unique_ptr< mlir::Pass > createExportVerilogPass()
void appendPossiblyAbsolutePath(llvm::SmallVectorImpl< char > &base, const llvm::Twine &suffix)
Append a path to an existing path, replacing it if the other path is absolute.
llvm::raw_string_ostream & os
void emitLocationInfo(Location loc)
Return the location information in the specified style.
Impl(llvm::raw_string_ostream &os, LoweringOptions::LocationInfoStyle style, const SmallPtrSetImpl< Attribute > &locationSet)
void emitLocationInfo(FileLineColLoc loc)
void emitLocationSetInfoImpl(const SmallPtrSetImpl< Attribute > &locationSet)
Emit the location information of locationSet to sstr.
void emitLocationInfo(mlir::NameLoc loc)
LoweringOptions::LocationInfoStyle style
void emitLocationInfo(mlir::CallSiteLoc loc)
void printFileLineColSetInfo(llvm::SmallVector< FileLineColLoc, 8 > locVector)
Information to control the emission of a list of operations into a file.
bool isVerilog
If true, the file is known to be (system) verilog source code.
SmallVector< OpFileInfo, 1 > ops
The operations to be emitted into a separate file, and where among the replicated per-file operations...
bool isHeader
If true, the file is a header.
bool emitReplicatedOps
Whether to emit the replicated per-file operations.
Information to control the emission of a single operation into a file.
This class tracks the top-level state for the emitters, which is built and then shared across all per...
llvm::MapVector< StringAttr, FileInfo > files
The additional files to emit, with the output file name as the key into the map.
std::vector< StringOrOpToEmit > EmissionList
FileMapping fileMapping
Tracks the referenceable files through their symbol.
hw::HWSymbolCache symbolCache
A cache of symbol -> defining ops built once and used by each of the verilog module emitters.
void collectOpsForFile(const FileInfo &fileInfo, EmissionList &thingsToEmit, bool emitHeader=false)
Given a FileInfo, collect all the replicated and designated operations that go into it and append the...
ModuleOp designOp
The MLIR module to emit.
void emitOps(EmissionList &thingsToEmit, llvm::formatted_raw_ostream &os, StringAttr fileName, bool parallelize)
Actually emit the collected list of operations and strings to the specified file.
FileInfo rootFile
The main file that collects all operations that are neither replicated per-file ops nor specifically ...
llvm::StringMap< SmallVector< StringAttr > > fileLists
The various file lists and their contents to emit.
SmallPtrSet< Operation *, 8 > modulesContainingBinds
This is a set is populated at "gather" time, containing the hw.module operations that have a sv....
const LoweringOptions & options
std::atomic< bool > encounteredError
Whether any error has been encountered during emission.
FragmentMapping fragmentMapping
Tracks referenceable files through their symbol.
void gatherFiles(bool separateModules)
Organize the operations in the root MLIR module into output files to be generated.
SmallVector< Operation *, 0 > replicatedOps
A list of operations replicated in each output file (e.g., sv.verbatim or sv.ifdef without dedicated ...
const GlobalNameTable globalNames
Information about renamed global symbols, parameters, etc.
A named and typed field of an aggregate type.
Options which control the emission from CIRCT to Verilog.
bool omitVersionComment
If true, do not emit a version comment at the top of each verilog file.
LocationInfoStyle
This option controls emitted location information style.
bool disallowMuxInlining
If true, every mux expression is spilled to a wire.
bool caseInsensitiveKeywords
If true, then unique names that collide with keywords case insensitively.
bool emitReplicatedOpsToHeader
If true, replicated ops are emitted to a header file.
bool allowExprInEventControl
If true, expressions are allowed in the sensitivity list of always statements, otherwise they are for...
This holds a decoded list of input/inout and output ports for a module or instance.
PortInfo & at(size_t idx)
This holds the name, type, direction of a module's ports.
StringRef getVerilogName() const
InnerSymAttr getSym() const
Buffer tokens for clients that need to adjust things.
SmallVectorImpl< Token > BufferVec
String wrapper to indicate string has external storage.
String wrapper to indicate string needs to be saved.