40 #include "mlir/IR/BuiltinOps.h"
41 #include "mlir/IR/ImplicitLocOpBuilder.h"
42 #include "mlir/IR/Location.h"
43 #include "mlir/IR/Threading.h"
44 #include "mlir/Interfaces/FunctionImplementation.h"
45 #include "mlir/Pass/PassManager.h"
46 #include "mlir/Support/FileUtilities.h"
47 #include "llvm/ADT/MapVector.h"
48 #include "llvm/ADT/STLExtras.h"
49 #include "llvm/ADT/StringSet.h"
50 #include "llvm/ADT/TypeSwitch.h"
51 #include "llvm/Support/FileSystem.h"
52 #include "llvm/Support/FormattedStream.h"
53 #include "llvm/Support/Path.h"
54 #include "llvm/Support/SaveAndRestore.h"
55 #include "llvm/Support/ToolOutputFile.h"
56 #include "llvm/Support/raw_ostream.h"
59 #define GEN_PASS_DEF_EXPORTSPLITVERILOG
60 #define GEN_PASS_DEF_EXPORTVERILOG
61 #include "circt/Conversion/Passes.h.inc"
64 using namespace circt;
68 using namespace ExportVerilog;
70 using namespace pretty;
72 #define DEBUG_TYPE "export-verilog"
80 enum VerilogPrecedence {
101 enum SubExprSignResult { IsSigned, IsUnsigned };
107 VerilogPrecedence precedence;
110 SubExprSignResult signedness;
112 SubExprInfo(VerilogPrecedence precedence, SubExprSignResult signedness)
113 : precedence(precedence), signedness(signedness) {}
123 return Builder(ctx).getI32IntegerAttr(value);
126 static TypedAttr
getIntAttr(MLIRContext *ctx, Type t,
const APInt &value) {
127 return Builder(ctx).getIntegerAttr(t, value);
143 if (isa<VerbatimExprOp>(op)) {
144 if (op->getNumOperands() == 0 &&
145 op->getAttrOfType<StringAttr>(
"format_string").getValue().size() <= 32)
150 if (isa<XMRRefOp>(op))
154 if (isa<MacroRefExprOp>(op))
164 if (op->getNumOperands() == 0)
168 if (isa<comb::ExtractOp, hw::StructExtractOp, hw::UnionExtractOp>(op))
172 if (
auto array = dyn_cast<hw::ArrayGetOp>(op)) {
173 auto *indexOp = array.getIndex().getDefiningOp();
174 if (!indexOp || isa<ConstantOp>(indexOp))
176 if (
auto read = dyn_cast<ReadInOutOp>(indexOp)) {
177 auto *readSrc = read.getInput().getDefiningOp();
179 return !readSrc || isa<sv::WireOp, LogicOp>(readSrc);
194 if (
auto attr = symOp->getAttrOfType<StringAttr>(
"hw.verilogName"))
195 return attr.getValue();
196 return TypeSwitch<Operation *, StringRef>(symOp)
199 .Case<InterfaceOp>([&](InterfaceOp op) {
202 .Case<InterfaceSignalOp>(
203 [&](InterfaceSignalOp op) {
return op.getSymName(); })
204 .Case<InterfaceModportOp>(
205 [&](InterfaceModportOp op) {
return op.getSymName(); })
206 .Default([&](Operation *op) {
207 if (
auto attr = op->getAttrOfType<StringAttr>(
"name"))
208 return attr.getValue();
209 if (
auto attr = op->getAttrOfType<StringAttr>(
"instanceName"))
210 return attr.getValue();
211 if (
auto attr = op->getAttrOfType<StringAttr>(
"sv.namehint"))
212 return attr.getValue();
214 op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()))
215 return attr.getValue();
216 return StringRef(
"");
221 template <
typename PPS>
223 os <<
"/*Zero width*/ 1\'b0";
228 auto hml = cast<HWModuleLike>(module);
229 return hml.getPort(portArgNum).getVerilogName();
234 auto hml = cast<HWModuleLike>(module);
235 auto pId = hml.getHWModuleType().getPortIdForInputId(portArgNum);
236 if (
auto attrs = dyn_cast_or_null<DictionaryAttr>(hml.getPortAttrs(pId)))
237 if (
auto updatedName = attrs.getAs<StringAttr>(
"hw.verilogName"))
238 return updatedName.getValue();
239 return hml.getHWModuleType().getPortName(pId);
248 if (isa<
ReadInOutOp, AggregateConstantOp, ArrayIndexInOutOp,
249 IndexedPartSelectInOutOp, StructFieldInOutOp, IndexedPartSelectOp,
250 ParamValueOp, XMROp, XMRRefOp, SampledOp, EnumConstantOp,
251 SystemFunctionOp, UnpackedArrayCreateOp, UnpackedOpenArrayCastOp>(op))
261 static void getTypeDims(SmallVectorImpl<Attribute> &dims, Type type,
263 if (
auto integer = hw::type_dyn_cast<IntegerType>(type)) {
264 if (integer.getWidth() != 1)
265 dims.push_back(
getInt32Attr(type.getContext(), integer.getWidth()));
268 if (
auto array = hw::type_dyn_cast<ArrayType>(type)) {
269 dims.push_back(
getInt32Attr(type.getContext(), array.getNumElements()));
274 if (
auto intType = hw::type_dyn_cast<IntType>(type)) {
275 dims.push_back(intType.getWidth());
279 if (
auto inout = hw::type_dyn_cast<InOutType>(type))
280 return getTypeDims(dims, inout.getElementType(), loc);
281 if (
auto uarray = hw::type_dyn_cast<hw::UnpackedArrayType>(type))
282 return getTypeDims(dims, uarray.getElementType(), loc);
283 if (
auto uarray = hw::type_dyn_cast<sv::UnpackedOpenArrayType>(type))
284 return getTypeDims(dims, uarray.getElementType(), loc);
286 if (hw::type_isa<InterfaceType, StructType, EnumType>(type))
289 mlir::emitError(loc,
"value has an unsupported verilog type ") << type;
295 SmallVector<Attribute, 4> aDims;
298 SmallVector<Attribute, 4> bDims;
301 return aDims == bDims;
307 if (
auto intType = dyn_cast<IntegerType>(type))
308 return intType.getWidth() == 0;
309 if (
auto inout = dyn_cast<hw::InOutType>(type))
311 if (
auto uarray = dyn_cast<hw::UnpackedArrayType>(type))
312 return uarray.getNumElements() == 0 ||
314 if (
auto array = dyn_cast<hw::ArrayType>(type))
315 return array.getNumElements() == 0 ||
isZeroBitType(array.getElementType());
316 if (
auto structType = dyn_cast<hw::StructType>(type))
317 return llvm::all_of(structType.getElements(),
318 [](
auto elem) { return isZeroBitType(elem.type); });
319 if (
auto enumType = dyn_cast<hw::EnumType>(type))
320 return enumType.getFields().empty();
321 if (
auto unionType = dyn_cast<hw::UnionType>(type))
334 return TypeSwitch<Type, Type>(type)
338 .Case<UnpackedArrayType, sv::UnpackedOpenArrayType>([](
auto arrayType) {
341 .Default([](Type type) {
return type; });
346 assert(isa<hw::InOutType>(type) &&
"inout type is expected");
347 auto elementType = cast<hw::InOutType>(type).getElementType();
353 return TypeSwitch<Type, bool>(type)
354 .Case<
InOutType, UnpackedArrayType, ArrayType>([](
auto parentType) {
357 .Case<StructType>([](
auto) {
return true; })
358 .Default([](
auto) {
return false; });
368 static int compareLocs(Location lhs, Location rhs);
372 if (
auto name = lhs.getName().compare(rhs.getName()))
374 return compareLocs(lhs.getChildLoc(), rhs.getChildLoc());
379 if (
auto fn = lhs.getFilename().compare(rhs.getFilename()))
381 if (lhs.getLine() != rhs.getLine())
382 return lhs.getLine() < rhs.getLine() ? -1 : 1;
383 return lhs.getColumn() < rhs.getColumn() ? -1 : 1;
388 Location lhsCallee = lhs.getCallee();
389 Location rhsCallee = rhs.getCallee();
393 Location lhsCaller = lhs.getCaller();
394 Location rhsCaller = rhs.getCaller();
398 template <
typename TTargetLoc>
400 auto lhsT = dyn_cast<TTargetLoc>(lhs);
401 auto rhsT = dyn_cast<TTargetLoc>(rhs);
428 if (
auto res = dispatchCompareLocations<mlir::FileLineColLoc>(lhs, rhs);
433 if (
auto res = dispatchCompareLocations<mlir::NameLoc>(lhs, rhs);
438 if (
auto res = dispatchCompareLocations<mlir::CallSiteLoc>(lhs, rhs);
455 SmallPtrSetImpl<Attribute> &locationSet) {
456 llvm::TypeSwitch<Location, void>(loc)
457 .Case<FusedLoc>([&](
auto fusedLoc) {
458 for (
auto subLoc : fusedLoc.getLocations())
461 .Default([&](
auto loc) { locationSet.insert(loc); });
465 template <
typename TVector>
467 llvm::array_pod_sort(
468 vec.begin(), vec.end(), [](
const auto *lhs,
const auto *rhs) ->
int {
469 return compareLocs(cast<Location>(*lhs), cast<Location>(*rhs));
477 SmallPtrSet<Attribute, 8> locationSet;
478 locationSet.insert(loc);
479 llvm::raw_string_ostream os(output);
480 emitLocationSetInfo(os, style, locationSet);
485 const SmallPtrSetImpl<Operation *> &ops) {
489 SmallPtrSet<Attribute, 8> locationSet;
492 llvm::raw_string_ostream os(output);
493 emitLocationSetInfo(os, style, locationSet);
501 const SmallPtrSetImpl<Attribute> &locationSet) {
502 if (style == LoweringOptions::LocationInfoStyle::None)
505 llvm::raw_string_ostream sstr(resstr);
507 if (resstr.empty() || style == LoweringOptions::LocationInfoStyle::Plain) {
511 assert(style == LoweringOptions::LocationInfoStyle::WrapInAtSquareBracket &&
512 "other styles must be already handled");
513 os <<
"@[" << resstr <<
"]";
522 const SmallPtrSetImpl<Attribute> &locationSet)
523 : os(os), style(style) {
524 emitLocationSetInfoImpl(locationSet);
530 emitLocationInfo(loc.getCallee());
532 emitLocationInfo(loc.getCaller());
538 bool withName = !loc.getName().empty();
540 os <<
"'" << loc.getName().strref() <<
"'(";
541 emitLocationInfo(loc.getChildLoc());
549 os << loc.getFilename().getValue();
550 if (
auto line = loc.getLine()) {
552 if (
auto col = loc.getColumn())
564 StringRef lastFileName;
565 for (
size_t i = 0, e = locVector.size(); i != e;) {
570 auto first = locVector[i];
571 if (first.getFilename() != lastFileName) {
572 lastFileName = first.getFilename();
579 first.getFilename() == locVector[
end].getFilename() &&
580 first.getLine() == locVector[
end].getLine())
585 if (
auto line = first.getLine()) {
587 if (
auto col = first.getColumn())
595 os <<
':' << first.getLine() <<
":{";
597 os << locVector[i++].getColumn();
609 llvm::TypeSwitch<Location, void>(loc)
610 .Case<mlir::CallSiteLoc, mlir::NameLoc, mlir::FileLineColLoc>(
611 [&](
auto loc) { emitLocationInfo(loc); })
612 .Case<mlir::FusedLoc>([&](
auto loc) {
613 SmallPtrSet<Attribute, 8> locationSet;
615 emitLocationSetInfoImpl(locationSet);
617 .Default([&](
auto loc) {
629 switch (locationSet.size()) {
631 emitLocationInfo(cast<LocationAttr>(*locationSet.begin()));
640 SmallVector<FileLineColLoc, 8> flcLocs;
641 SmallVector<Attribute, 8> otherLocs;
642 flcLocs.reserve(locationSet.size());
643 otherLocs.reserve(locationSet.size());
644 for (Attribute loc : locationSet) {
645 if (
auto flcLoc = dyn_cast<FileLineColLoc>(loc))
646 flcLocs.push_back(flcLoc);
648 otherLocs.push_back(loc);
659 size_t sstrSize = os.tell();
660 bool emittedAnything =
false;
661 auto recheckEmittedSomething = [&]() {
662 size_t currSize = os.tell();
663 bool emittedSomethingSinceLastCheck = currSize != sstrSize;
664 emittedAnything |= emittedSomethingSinceLastCheck;
666 return emittedSomethingSinceLastCheck;
673 [&](Attribute loc) { emitLocationInfo(cast<LocationAttr>(loc)); },
675 if (recheckEmittedSomething()) {
677 recheckEmittedSomething();
683 if (emittedAnything && !flcLocs.empty())
686 printFileLineColSetInfo(flcLocs);
688 llvm::raw_string_ostream &
os;
700 if (isa<BlockArgument>(v))
709 if (isa_and_nonnull<StructExtractOp, UnionExtractOp, ArrayGetOp>(
714 if (v.getDefiningOp<ReadInterfaceSignalOp>())
727 if (
auto cast = dyn_cast<BitcastOp>(op))
728 if (!
haveMatchingDims(cast.getInput().getType(), cast.getResult().getType(),
732 if (op->hasOneUse() &&
733 isa<comb::ConcatOp, hw::ArrayConcatOp>(*op->getUsers().begin()))
741 if (isa<StructCreateOp, UnionCreateOp, UnpackedArrayCreateOp>(op))
746 if (
auto aggConstantOp = dyn_cast<AggregateConstantOp>(op))
750 if (
auto verbatim = dyn_cast<VerbatimExprOp>(op))
751 if (verbatim.getFormatString().size() > 32)
756 for (
auto &use : op->getUses()) {
757 auto *user = use.getOwner();
767 UnionExtractOp, IndexedPartSelectOp>(user))
768 if (use.getOperandNumber() == 0 &&
779 auto usedInExprControl = [user, &use]() {
780 return TypeSwitch<Operation *, bool>(user)
781 .Case<ltl::ClockOp>([&](
auto clockOp) {
783 return clockOp.getClock() == use.get();
785 .Case<sv::AssertConcurrentOp, sv::AssumeConcurrentOp,
786 sv::CoverConcurrentOp>(
787 [&](
auto op) {
return op.getClock() == use.get(); })
788 .Case<sv::AssertPropertyOp, sv::AssumePropertyOp,
789 sv::CoverPropertyOp>([&](
auto op) {
790 return op.getDisable() == use.get() || op.getClock() == use.get();
792 .Case<AlwaysOp, AlwaysFFOp>([](
auto) {
797 .Default([](
auto) {
return false; });
800 if (!usedInExprControl())
804 auto read = dyn_cast<ReadInOutOp>(op);
807 if (!isa_and_nonnull<sv::WireOp, RegOp>(read.getInput().getDefiningOp()))
818 unsigned numStatements = 0;
819 block.walk([&](Operation *op) {
821 return WalkResult::advance();
823 TypeSwitch<Operation *, unsigned>(op)
824 .Case<VerbatimOp>([&](
auto) {
830 .Case<IfOp>([&](
auto) {
841 .Case<
IfDefOp, IfDefProceduralOp>([&](
auto) { return 3; })
842 .Case<OutputOp>([&](OutputOp oop) {
845 return llvm::count_if(oop->getOperands(), [&](auto operand) {
846 Operation *op = operand.getDefiningOp();
847 return !operand.hasOneUse() || !op || !isa<HWInstanceLike>(op);
850 .Default([](
auto) {
return 1; });
851 if (numStatements > 1)
852 return WalkResult::interrupt();
853 return WalkResult::advance();
855 if (numStatements == 0)
857 if (numStatements == 1)
867 if (op->getResult(0).use_empty())
872 if (op->hasOneUse() &&
873 isa<hw::OutputOp, sv::AssignOp, sv::BPAssignOp, sv::PAssignOp>(
874 *op->getUsers().begin()))
896 for (
auto &op : *elseBlock) {
897 if (
auto opIf = dyn_cast<IfOp>(op)) {
914 template <
typename PPS>
916 enum Container { NoContainer, InComment, InAttr };
917 Container currentContainer = NoContainer;
919 auto closeContainer = [&] {
920 if (currentContainer == NoContainer)
922 if (currentContainer == InComment)
924 else if (currentContainer == InAttr)
926 ps << PP::end << PP::end;
928 currentContainer = NoContainer;
931 bool isFirstContainer =
true;
932 auto openContainer = [&](Container newContainer) {
933 assert(newContainer != NoContainer);
934 if (currentContainer == newContainer)
938 if (!isFirstContainer)
939 ps << (mayBreak ? PP::space : PP::nbsp);
940 isFirstContainer =
false;
943 if (newContainer == InComment)
945 else if (newContainer == InAttr)
947 currentContainer = newContainer;
955 ps.scopedBox(PP::cbox0, [&]() {
956 for (
auto attr : attrs.getAsRange<SVAttributeAttr>()) {
957 if (!openContainer(attr.getEmitAsComment().getValue() ? InComment
959 ps <<
"," << (mayBreak ? PP::space : PP::nbsp);
961 if (attr.getExpression())
962 ps <<
" = " <<
PPExtString(attr.getExpression().getValue());
971 if (
auto *op = val.getDefiningOp())
974 if (
auto port = dyn_cast<BlockArgument>(val)) {
976 if (
auto forOp = dyn_cast<ForOp>(port.getParentBlock()->getParentOp()))
977 return forOp->getAttrOfType<StringAttr>(
"hw.verilogName");
979 port.getArgNumber());
981 assert(
false &&
"unhandled value");
993 class VerilogEmitterState {
995 explicit VerilogEmitterState(ModuleOp designOp,
1001 llvm::formatted_raw_ostream &os,
1002 StringAttr fileName,
OpLocMap &verilogLocMap)
1003 : designOp(designOp), shared(shared), options(options),
1004 symbolCache(symbolCache), globalNames(globalNames),
1005 fileMapping(fileMapping), os(os), verilogLocMap(verilogLocMap),
1006 pp(os, options.emittedLineLength), fileName(fileName) {
1007 pp.setListener(&saver);
1030 llvm::formatted_raw_ostream &os;
1032 bool encounteredError =
false;
1041 bool pendingNewline =
false;
1055 StringAttr fileName;
1061 void addVerilogLocToOps(
unsigned int lineOffset, StringAttr fileName) {
1064 verilogLocMap.
clear();
1068 VerilogEmitterState(
const VerilogEmitterState &) =
delete;
1069 void operator=(
const VerilogEmitterState &) =
delete;
1082 using CallbackDataTy = std::pair<Operation *, bool>;
1086 VerilogEmitterState &state;
1091 explicit EmitterBase(VerilogEmitterState &state)
1093 ps(state.pp, state.saver, state.options.emitVerilogLocations) {}
1095 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
1096 state.encounteredError =
true;
1097 return op->emitError(message);
1100 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
1101 state.encounteredError =
true;
1102 return op->emitOpError(message);
1105 void emitLocationImpl(llvm::StringRef location) {
1108 ps << PP::neverbreak;
1109 if (!location.empty())
1110 ps <<
"\t// " << location;
1113 void emitLocationInfo(Location loc) {
1121 void emitLocationInfoAndNewLine(
const SmallPtrSetImpl<Operation *> &ops) {
1124 setPendingNewline();
1127 template <
typename PPS>
1128 void emitTextWithSubstitutions(PPS &ps, StringRef
string, Operation *op,
1129 llvm::function_ref<
void(Value)> operandEmitter,
1130 ArrayAttr symAttrs);
1136 void emitComment(StringAttr comment);
1140 void emitPendingNewlineIfNeeded() {
1141 if (state.pendingNewline) {
1142 state.pendingNewline =
false;
1146 void setPendingNewline() {
1147 assert(!state.pendingNewline);
1148 state.pendingNewline =
true;
1151 void startStatement() { emitPendingNewlineIfNeeded(); }
1154 void operator=(
const EmitterBase &) =
delete;
1155 EmitterBase(
const EmitterBase &) =
delete;
1159 template <
typename PPS>
1160 void EmitterBase::emitTextWithSubstitutions(
1161 PPS &ps, StringRef
string, Operation *op,
1162 llvm::function_ref<
void(Value)> operandEmitter, ArrayAttr symAttrs) {
1173 if (
auto *itemOp = item.getOp()) {
1174 if (item.hasPort()) {
1178 if (!symOpName.empty())
1180 emitError(itemOp,
"cannot get name for symbol ") << sym;
1182 emitError(op,
"cannot get name for symbol ") << sym;
1184 return StringRef(
"<INVALID>");
1190 unsigned numSymOps = symAttrs.size();
1191 auto emitUntilSubstitution = [&](
size_t next = 0) ->
bool {
1194 next =
string.find(
"{{", next);
1195 if (next == StringRef::npos)
1202 while (next <
string.size() &&
isdigit(
string[next]))
1205 if (start == next) {
1209 size_t operandNoLength = next - start;
1212 StringRef fmtOptsStr;
1213 if (
string[next] ==
':') {
1214 size_t startFmtOpts = next + 1;
1215 while (next <
string.size() &&
string[next] !=
'}')
1217 fmtOptsStr =
string.substr(startFmtOpts, next - startFmtOpts);
1221 if (!
string.substr(next).starts_with(
"}}"))
1225 unsigned operandNo = 0;
1226 if (
string.drop_front(start)
1227 .take_front(operandNoLength)
1228 .getAsInteger(10, operandNo)) {
1229 emitError(op,
"operand substitution too large");
1235 auto before =
string.take_front(start - 2);
1236 if (!before.empty())
1241 if (operandNo < op->getNumOperands())
1243 operandEmitter(op->getOperand(operandNo));
1244 else if ((operandNo - op->getNumOperands()) < numSymOps) {
1245 unsigned symOpNum = operandNo - op->getNumOperands();
1246 auto sym = symAttrs[symOpNum];
1247 StringRef symVerilogName;
1248 if (
auto fsym = dyn_cast<FlatSymbolRefAttr>(sym)) {
1249 if (
auto *symOp = state.symbolCache.getDefinition(fsym)) {
1250 if (
auto globalRef = dyn_cast<HierPathOp>(symOp)) {
1251 auto namepath = globalRef.getNamepathAttr().getValue();
1252 for (
auto [index, sym] : llvm::enumerate(namepath)) {
1255 ps << (fmtOptsStr.empty() ?
"." : fmtOptsStr);
1257 auto innerRef = cast<InnerRefAttr>(sym);
1258 auto ref = state.symbolCache.getInnerDefinition(
1259 innerRef.getModule(), innerRef.getName());
1260 ps << namify(innerRef, ref);
1263 symVerilogName = namify(sym, symOp);
1266 }
else if (
auto isym = dyn_cast<InnerRefAttr>(sym)) {
1267 auto symOp = state.symbolCache.getInnerDefinition(isym.getModule(),
1269 symVerilogName = namify(sym, symOp);
1271 if (!symVerilogName.empty())
1274 emitError(op,
"operand " + llvm::utostr(operandNo) +
" isn't valid");
1278 string =
string.drop_front(next);
1284 while (emitUntilSubstitution())
1288 if (!
string.
empty())
1292 void EmitterBase::emitComment(StringAttr comment) {
1299 auto lineLength = std::max<size_t>(state.options.emittedLineLength, 3) - 3;
1303 auto ref = comment.getValue();
1305 while (!ref.empty()) {
1306 std::tie(line, ref) = ref.split(
"\n");
1313 if (line.size() <= lineLength) {
1315 setPendingNewline();
1326 auto breakPos = line.rfind(
' ', lineLength);
1328 if (breakPos == StringRef::npos) {
1329 breakPos = line.find(
' ', lineLength);
1332 if (breakPos == StringRef::npos)
1333 breakPos = line.size();
1340 setPendingNewline();
1341 breakPos = line.find_first_not_of(
' ', breakPos);
1343 if (breakPos == StringRef::npos)
1346 line = line.drop_front(breakPos);
1356 bool addPrefixUnderScore =
true;
1359 if (
auto read = expr.getDefiningOp<
ReadInOutOp>())
1363 if (
auto blockArg = dyn_cast<BlockArgument>(expr)) {
1365 cast<HWEmittableModuleLike>(blockArg.getOwner()->getParentOp());
1369 }
else if (
auto *op = expr.getDefiningOp()) {
1371 if (isa<sv::WireOp, RegOp, LogicOp>(op)) {
1375 }
else if (
auto nameHint = op->getAttrOfType<StringAttr>(
"sv.namehint")) {
1381 addPrefixUnderScore =
false;
1383 TypeSwitch<Operation *>(op)
1386 .Case([&result](VerbatimExprOp verbatim) {
1387 verbatim.getAsmResultNames([&](Value, StringRef name) {
1391 .Case([&result](VerbatimExprSEOp verbatim) {
1392 verbatim.getAsmResultNames([&](Value, StringRef name) {
1399 if (
auto operandName =
1402 cast<IntegerType>(extract.getType()).getWidth();
1405 operandName.strref() +
"_" +
1406 Twine(extract.getLowBit()));
1409 extract.getContext(),
1410 operandName.strref() +
"_" +
1411 Twine(extract.getLowBit() + numBits - 1) +
"to" +
1412 Twine(extract.getLowBit()));
1420 if (!result || result.strref().empty())
1424 if (addPrefixUnderScore && result.strref().front() !=
'_')
1437 class ModuleEmitter :
public EmitterBase {
1439 explicit ModuleEmitter(VerilogEmitterState &state)
1440 : EmitterBase(state), currentModuleOp(nullptr),
1444 emitPendingNewlineIfNeeded();
1448 void emitParameters(Operation *module, ArrayAttr params);
1449 void emitPortList(Operation *module,
const ModulePortInfo &portInfo,
1450 bool emitAsTwoStateType =
false);
1453 void emitHWGeneratedModule(HWModuleGeneratedOp module);
1454 void emitFunc(FuncOp);
1457 void emitStatement(Operation *op);
1458 void emitBind(BindOp op);
1459 void emitBindInterface(BindInterfaceOp op);
1461 void emitSVAttributes(Operation *op);
1464 StringRef getVerilogStructFieldName(StringAttr field) {
1465 return fieldNameResolver.getRenamedFieldName(field).getValue();
1472 void emitTypeDims(Type type, Location loc, raw_ostream &os);
1484 bool printPackedType(Type type, raw_ostream &os, Location loc,
1485 Type optionalAliasType = {},
bool implicitIntType =
true,
1486 bool singleBitDefaultType =
true,
1487 bool emitAsTwoStateType =
false);
1491 void printUnpackedTypePostfix(Type type, raw_ostream &os);
1499 function_ref<InFlightDiagnostic()> emitError);
1502 VerilogPrecedence parenthesizeIfLooserThan,
1503 function_ref<InFlightDiagnostic()> emitError);
1509 Operation *currentModuleOp;
1515 SmallPtrSet<Operation *, 16> expressionsEmittedIntoDecl;
1521 SmallPtrSet<Operation *, 16> assignsInlined;
1530 const ModuleEmitter &emitter) {
1531 if (isa<RegOp>(op)) {
1536 cast<InOutType>(op->getResult(0).getType()).getElementType();
1544 while (isa<ArrayType>(
innerType.getElementType()))
1546 if (isa<StructType>(
innerType.getElementType()) ||
1547 isa<TypeAliasType>(
innerType.getElementType()))
1555 if (isa<sv::WireOp>(op))
1557 if (isa<ConstantOp, AggregateConstantOp, LocalParamOp, ParamValueOp>(op))
1558 return "localparam";
1561 if (
auto interface = dyn_cast<InterfaceInstanceOp>(op))
1562 return interface.getInterfaceType().getInterface().getValue();
1566 bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
1570 bool stripAutomatic = isa_and_nonnull<FuncOp>(emitter.currentModuleOp);
1572 if (isa<LogicOp>(op)) {
1578 if (isProcedural && !stripAutomatic)
1579 return hasStruct ?
"automatic" :
"automatic logic";
1580 return hasStruct ?
"" :
"logic";
1587 return hasStructType(op->getResult(0).getType()) ?
"" :
"logic";
1590 assert(!emitter.state.options.disallowLocalVariables &&
1591 "automatic variables not allowed");
1595 return hasStructType(op->getResult(0).getType()) ?
"automatic"
1596 :
"automatic logic";
1604 ModuleEmitter &emitter,
bool downTo) {
1606 os <<
"<<invalid type>>";
1609 if (
auto intAttr = dyn_cast<IntegerAttr>(
width)) {
1610 if (intAttr.getValue().isZero()) {
1611 os <<
"/*Zero Width*/";
1616 os << (intAttr.getValue().getZExtValue() - 1);
1626 auto typedAttr = dyn_cast<TypedAttr>(
width);
1628 mlir::emitError(loc,
"untyped dimension attribute ") <<
width;
1632 getIntAttr(loc.getContext(), typedAttr.getType(),
1633 APInt(typedAttr.getType().getIntOrFloatBitWidth(), -1L,
true));
1638 emitter.printParamValue(
width, os, [loc]() {
1639 return mlir::emitError(loc,
"invalid parameter in type");
1647 static void emitDims(ArrayRef<Attribute> dims, raw_ostream &os, Location loc,
1648 ModuleEmitter &emitter) {
1649 for (Attribute
width : dims) {
1655 void ModuleEmitter::emitTypeDims(Type type, Location loc, raw_ostream &os) {
1656 SmallVector<Attribute, 4> dims;
1688 SmallVectorImpl<Attribute> &dims,
1689 bool implicitIntType,
bool singleBitDefaultType,
1690 ModuleEmitter &emitter,
1691 Type optionalAliasType = {},
1692 bool emitAsTwoStateType =
false) {
1693 return TypeSwitch<Type, bool>(type)
1694 .Case<IntegerType>([&](IntegerType integerType) {
1695 if (emitAsTwoStateType && dims.empty()) {
1697 if (!typeName.empty()) {
1702 if (integerType.getWidth() != 1 || !singleBitDefaultType)
1704 getInt32Attr(type.getContext(), integerType.getWidth()));
1706 StringRef typeName =
1707 (emitAsTwoStateType ?
"bit" : (implicitIntType ?
"" :
"logic"));
1708 if (!typeName.empty()) {
1715 return !dims.empty() || !implicitIntType;
1717 .Case<IntType>([&](IntType intType) {
1718 if (!implicitIntType)
1720 dims.push_back(intType.getWidth());
1724 .Case<ArrayType>([&](ArrayType arrayType) {
1725 dims.push_back(arrayType.getSizeAttr());
1727 implicitIntType, singleBitDefaultType,
1729 emitAsTwoStateType);
1731 .Case<InOutType>([&](
InOutType inoutType) {
1733 implicitIntType, singleBitDefaultType,
1735 emitAsTwoStateType);
1737 .Case<EnumType>([&](EnumType enumType) {
1739 if (enumType.getBitWidth() != 32)
1740 os <<
"bit [" << enumType.getBitWidth() - 1 <<
":0] ";
1742 Type enumPrefixType = optionalAliasType ? optionalAliasType : enumType;
1743 llvm::interleaveComma(
1744 enumType.getFields().getAsRange<StringAttr>(), os,
1745 [&](
auto enumerator) {
1746 os << emitter.fieldNameResolver.getEnumFieldName(
1747 hw::EnumFieldAttr::get(loc, enumerator, enumPrefixType));
1752 .Case<StructType>([&](StructType structType) {
1753 if (structType.getElements().empty() ||
isZeroBitType(structType)) {
1754 os <<
"/*Zero Width*/";
1757 os <<
"struct packed {";
1758 for (
auto &element : structType.getElements()) {
1760 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1761 <<
": Zero Width;*/ ";
1764 SmallVector<Attribute, 8> structDims;
1769 {}, emitAsTwoStateType);
1770 os <<
' ' << emitter.getVerilogStructFieldName(element.name);
1771 emitter.printUnpackedTypePostfix(element.type, os);
1778 .Case<UnionType>([&](UnionType unionType) {
1779 if (unionType.getElements().empty() ||
isZeroBitType(unionType)) {
1780 os <<
"/*Zero Width*/";
1785 os <<
"union packed {";
1786 for (
auto &element : unionType.getElements()) {
1788 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1789 <<
": Zero Width;*/ ";
1793 bool needsPadding = elementWidth < unionWidth || element.offset > 0;
1795 os <<
" struct packed {";
1796 if (element.offset) {
1797 os << (emitAsTwoStateType ?
"bit" :
"logic") <<
" ["
1798 << element.offset - 1 <<
":0] "
1799 <<
"__pre_padding_" << element.name.getValue() <<
"; ";
1803 SmallVector<Attribute, 8> structDims;
1807 true, emitter, {}, emitAsTwoStateType);
1808 os <<
' ' << emitter.getVerilogStructFieldName(element.name);
1809 emitter.printUnpackedTypePostfix(element.type, os);
1813 if (elementWidth + (int64_t)element.offset < unionWidth) {
1814 os <<
" " << (emitAsTwoStateType ?
"bit" :
"logic") <<
" ["
1815 << unionWidth - (elementWidth + element.offset) - 1 <<
":0] "
1816 <<
"__post_padding_" << element.name.getValue() <<
";";
1818 os <<
"} " << emitter.getVerilogStructFieldName(element.name)
1827 .Case<InterfaceType>([](InterfaceType ifaceType) {
return false; })
1828 .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1829 os <<
"<<unexpected unpacked array>>";
1830 mlir::emitError(loc,
"Unexpected unpacked array in packed type ")
1834 .Case<TypeAliasType>([&](TypeAliasType typeRef) {
1835 auto typedecl = typeRef.getTypeDecl(emitter.state.symbolCache);
1837 mlir::emitError(loc,
"unresolvable type reference");
1840 if (typedecl.getType() != typeRef.getInnerType()) {
1841 mlir::emitError(loc,
"declared type did not match aliased type");
1845 os << typedecl.getPreferredName();
1846 emitDims(dims, os, typedecl->getLoc(), emitter);
1849 .Default([&](Type type) {
1850 os <<
"<<invalid type '" << type <<
"'>>";
1851 mlir::emitError(loc,
"value has an unsupported verilog type ") << type;
1867 bool ModuleEmitter::printPackedType(Type type, raw_ostream &os, Location loc,
1868 Type optionalAliasType,
1869 bool implicitIntType,
1870 bool singleBitDefaultType,
1871 bool emitAsTwoStateType) {
1872 SmallVector<Attribute, 8> packedDimensions;
1874 singleBitDefaultType, *
this, optionalAliasType,
1875 emitAsTwoStateType);
1881 void ModuleEmitter::printUnpackedTypePostfix(Type type, raw_ostream &os) {
1882 TypeSwitch<Type, void>(type)
1884 printUnpackedTypePostfix(inoutType.getElementType(), os);
1886 .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1887 auto loc = currentModuleOp ? currentModuleOp->getLoc()
1888 : state.designOp->getLoc();
1889 emitDim(arrayType.getSizeAttr(), os, loc, *
this,
1891 printUnpackedTypePostfix(arrayType.getElementType(), os);
1893 .Case<sv::UnpackedOpenArrayType>([&](
auto arrayType) {
1895 printUnpackedTypePostfix(arrayType.getElementType(), os);
1897 .Case<InterfaceType>([&](
auto) {
1912 function_ref<InFlightDiagnostic()> emitError) {
1913 return printParamValue(value, os, VerilogPrecedence::LowestPrecedence,
1922 VerilogPrecedence parenthesizeIfLooserThan,
1923 function_ref<InFlightDiagnostic()> emitError) {
1924 if (
auto intAttr = dyn_cast<IntegerAttr>(value)) {
1925 IntegerType intTy = cast<IntegerType>(intAttr.getType());
1926 APInt value = intAttr.getValue();
1930 if (intTy.getWidth() > 32) {
1932 if (value.isNegative() && (intTy.isSigned() || intTy.isSignless())) {
1936 if (intTy.isSigned())
1937 os << intTy.getWidth() <<
"'sd";
1939 os << intTy.getWidth() <<
"'d";
1941 value.print(os, intTy.isSigned());
1942 return {Symbol, intTy.isSigned() ? IsSigned : IsUnsigned};
1944 if (
auto strAttr = dyn_cast<StringAttr>(value)) {
1946 os.write_escaped(strAttr.getValue());
1948 return {Symbol, IsUnsigned};
1950 if (
auto fpAttr = dyn_cast<FloatAttr>(value)) {
1952 os << fpAttr.getValueAsDouble();
1953 return {Symbol, IsUnsigned};
1955 if (
auto verbatimParam = dyn_cast<ParamVerbatimAttr>(value)) {
1956 os << verbatimParam.getValue().getValue();
1957 return {Symbol, IsUnsigned};
1959 if (
auto parameterRef = dyn_cast<ParamDeclRefAttr>(value)) {
1961 os << state.globalNames.getParameterVerilogName(currentModuleOp,
1962 parameterRef.getName());
1965 return {Symbol, IsUnsigned};
1969 auto expr = dyn_cast<ParamExprAttr>(value);
1971 os <<
"<<UNKNOWN MLIRATTR: " << value <<
">>";
1972 emitError() <<
" = " << value;
1973 return {LowestPrecedence, IsUnsigned};
1976 StringRef operatorStr;
1977 StringRef openStr, closeStr;
1978 VerilogPrecedence subprecedence = LowestPrecedence;
1979 VerilogPrecedence prec;
1980 std::optional<SubExprSignResult> operandSign;
1981 bool isUnary =
false;
1982 bool hasOpenClose =
false;
1984 switch (expr.getOpcode()) {
1986 operatorStr =
" + ";
1987 subprecedence = Addition;
1990 operatorStr =
" * ";
1991 subprecedence = Multiply;
1994 operatorStr =
" & ";
1995 subprecedence = And;
1998 operatorStr =
" | ";
2002 operatorStr =
" ^ ";
2003 subprecedence = Xor;
2006 operatorStr =
" << ";
2007 subprecedence = Shift;
2011 operatorStr =
" >> ";
2012 subprecedence = Shift;
2016 operatorStr =
" >>> ";
2017 subprecedence = Shift;
2018 operandSign = IsSigned;
2021 operatorStr =
" / ";
2022 subprecedence = Multiply;
2023 operandSign = IsUnsigned;
2026 operatorStr =
" / ";
2027 subprecedence = Multiply;
2028 operandSign = IsSigned;
2031 operatorStr =
" % ";
2032 subprecedence = Multiply;
2033 operandSign = IsUnsigned;
2036 operatorStr =
" % ";
2037 subprecedence = Multiply;
2038 operandSign = IsSigned;
2041 openStr =
"$clog2(";
2043 operandSign = IsUnsigned;
2044 hasOpenClose =
true;
2047 case PEO::StrConcat:
2050 hasOpenClose =
true;
2053 subprecedence = LowestPrecedence;
2058 prec = subprecedence;
2061 assert(!isUnary || llvm::hasSingleElement(expr.getOperands()));
2063 assert(isUnary || hasOpenClose ||
2064 !llvm::hasSingleElement(expr.getOperands()));
2071 auto emitOperand = [&](Attribute operand) ->
bool {
2073 auto subprec = operandSign.has_value() ? LowestPrecedence : subprecedence;
2074 if (operandSign.has_value())
2075 os << (*operandSign == IsSigned ?
"$signed(" :
"$unsigned(");
2078 if (operandSign.has_value()) {
2080 signedness = *operandSign;
2082 return signedness == IsSigned;
2086 if (prec > parenthesizeIfLooserThan)
2095 bool allOperandsSigned = emitOperand(expr.getOperands()[0]);
2096 for (
auto op : expr.getOperands().drop_front()) {
2099 if (expr.getOpcode() == PEO::Add) {
2100 if (
auto integer = dyn_cast<IntegerAttr>(op)) {
2101 const APInt &value = integer.getValue();
2102 if (value.isNegative() && !value.isMinSignedValue()) {
2104 allOperandsSigned &=
2112 allOperandsSigned &= emitOperand(op);
2116 if (prec > parenthesizeIfLooserThan) {
2120 return {prec, allOperandsSigned ? IsSigned : IsUnsigned};
2135 class ExprEmitter :
public EmitterBase,
2137 public CombinationalVisitor<ExprEmitter, SubExprInfo>,
2138 public Visitor<ExprEmitter, SubExprInfo> {
2142 ExprEmitter(ModuleEmitter &emitter,
2143 SmallPtrSetImpl<Operation *> &emittedExprs)
2144 : ExprEmitter(emitter, emittedExprs, localTokens) {}
2146 ExprEmitter(ModuleEmitter &emitter,
2147 SmallPtrSetImpl<Operation *> &emittedExprs,
2149 : EmitterBase(emitter.state), emitter(emitter),
2150 emittedExprs(emittedExprs), buffer(tokens),
2151 ps(buffer, state.saver, state.options.emitVerilogLocations) {
2152 assert(state.pp.getListener() == &state.saver);
2159 void emitExpression(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2160 bool isAssignmentLikeContext) {
2161 assert(localTokens.empty());
2163 ps.scopedBox(PP::ibox0, [&]() {
2164 emitSubExpr(exp, parenthesizeIfLooserThan,
2167 isAssignmentLikeContext);
2172 if (&buffer.tokens == &localTokens)
2173 buffer.flush(state.pp);
2178 friend class CombinationalVisitor<ExprEmitter, SubExprInfo>;
2179 friend class Visitor<ExprEmitter, SubExprInfo>;
2181 enum SubExprSignRequirement { NoRequirement, RequireSigned, RequireUnsigned };
2189 SubExprInfo emitSubExpr(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2190 SubExprSignRequirement signReq = NoRequirement,
2191 bool isSelfDeterminedUnsignedValue =
false,
2192 bool isAssignmentLikeContext =
false);
2196 void emitSVAttributes(Operation *op);
2198 SubExprInfo visitUnhandledExpr(Operation *op);
2199 SubExprInfo visitInvalidComb(Operation *op) {
2200 return dispatchTypeOpVisitor(op);
2202 SubExprInfo visitUnhandledComb(Operation *op) {
2203 return visitUnhandledExpr(op);
2205 SubExprInfo visitInvalidTypeOp(Operation *op) {
2206 return dispatchSVVisitor(op);
2208 SubExprInfo visitUnhandledTypeOp(Operation *op) {
2209 return visitUnhandledExpr(op);
2211 SubExprInfo visitUnhandledSV(Operation *op) {
return visitUnhandledExpr(op); }
2213 using Visitor::visitSV;
2216 enum EmitBinaryFlags {
2217 EB_RequireSignedOperands = RequireSigned,
2218 EB_RequireUnsignedOperands = RequireUnsigned,
2219 EB_OperandSignRequirementMask = 0x3,
2224 EB_RHS_UnsignedWithSelfDeterminedWidth = 0x4,
2228 EB_ForceResultSigned = 0x8,
2233 SubExprInfo emitBinary(Operation *op, VerilogPrecedence prec,
2234 const char *syntax,
unsigned emitBinaryFlags = 0);
2236 SubExprInfo emitUnary(Operation *op,
const char *syntax,
2237 bool resultAlwaysUnsigned =
false);
2240 void emitSubExprIBox2(
2241 Value v, VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence) {
2242 ps.scopedBox(PP::ibox2,
2243 [&]() { emitSubExpr(v, parenthesizeIfLooserThan); });
2248 template <
typename Container,
typename EachFn>
2249 void interleaveComma(
const Container &c, EachFn eachFn) {
2250 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
2255 void interleaveComma(ValueRange ops) {
2256 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
2273 template <
typename Container,
typename OpenFunc,
typename CloseFunc,
2275 void emitBracedList(
const Container &c, OpenFunc openFn, EachFunc eachFn,
2276 CloseFunc closeFn) {
2278 ps.scopedBox(PP::cbox0, [&]() {
2279 interleaveComma(c, eachFn);
2285 template <
typename OpenFunc,
typename CloseFunc>
2286 void emitBracedList(ValueRange ops, OpenFunc openFn, CloseFunc closeFn) {
2287 return emitBracedList(
2288 ops, openFn, [&](Value v) { emitSubExprIBox2(v); }, closeFn);
2292 void emitBracedList(ValueRange ops) {
2293 return emitBracedList(
2294 ops, [&]() { ps <<
"{"; }, [&]() { ps <<
"}"; });
2298 SubExprInfo printConstantScalar(APInt &value, IntegerType type);
2301 void printConstantArray(ArrayAttr elementValues, Type
elementType,
2302 bool printAsPattern, Operation *op);
2304 void printConstantStruct(ArrayRef<hw::detail::FieldInfo> fieldInfos,
2305 ArrayAttr fieldValues,
bool printAsPattern,
2308 void printConstantAggregate(Attribute attr, Type type, Operation *op);
2310 SubExprInfo visitSV(GetModportOp op);
2311 SubExprInfo visitSV(SystemFunctionOp op);
2312 SubExprInfo visitSV(ReadInterfaceSignalOp op);
2313 SubExprInfo visitSV(XMROp op);
2314 SubExprInfo visitSV(XMRRefOp op);
2315 SubExprInfo visitVerbatimExprOp(Operation *op, ArrayAttr symbols);
2316 SubExprInfo visitSV(VerbatimExprOp op) {
2317 return visitVerbatimExprOp(op, op.getSymbols());
2319 SubExprInfo visitSV(VerbatimExprSEOp op) {
2320 return visitVerbatimExprOp(op, op.getSymbols());
2322 SubExprInfo visitSV(MacroRefExprOp op);
2323 SubExprInfo visitSV(MacroRefExprSEOp op);
2324 template <
typename MacroTy>
2325 SubExprInfo emitMacroCall(MacroTy op);
2327 SubExprInfo visitSV(ConstantXOp op);
2328 SubExprInfo visitSV(ConstantZOp op);
2329 SubExprInfo visitSV(ConstantStrOp op);
2331 SubExprInfo visitSV(sv::UnpackedArrayCreateOp op);
2332 SubExprInfo visitSV(sv::UnpackedOpenArrayCastOp op) {
2334 return emitSubExpr(op->getOperand(0), LowestPrecedence);
2339 auto result = emitSubExpr(op->getOperand(0), LowestPrecedence);
2340 emitSVAttributes(op);
2343 SubExprInfo visitSV(ArrayIndexInOutOp op);
2344 SubExprInfo visitSV(IndexedPartSelectInOutOp op);
2345 SubExprInfo visitSV(IndexedPartSelectOp op);
2346 SubExprInfo visitSV(StructFieldInOutOp op);
2349 SubExprInfo visitSV(SampledOp op);
2352 using TypeOpVisitor::visitTypeOp;
2354 SubExprInfo visitTypeOp(AggregateConstantOp op);
2356 SubExprInfo visitTypeOp(ParamValueOp op);
2363 SubExprInfo visitTypeOp(StructInjectOp op);
2364 SubExprInfo visitTypeOp(UnionCreateOp op);
2365 SubExprInfo visitTypeOp(UnionExtractOp op);
2366 SubExprInfo visitTypeOp(EnumCmpOp op);
2367 SubExprInfo visitTypeOp(EnumConstantOp op);
2370 using CombinationalVisitor::visitComb;
2371 SubExprInfo visitComb(
MuxOp op);
2372 SubExprInfo visitComb(
AddOp op) {
2373 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2374 return emitBinary(op, Addition,
"+");
2376 SubExprInfo visitComb(
SubOp op) {
return emitBinary(op, Addition,
"-"); }
2377 SubExprInfo visitComb(
MulOp op) {
2378 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2379 return emitBinary(op, Multiply,
"*");
2381 SubExprInfo visitComb(
DivUOp op) {
2382 return emitBinary(op, Multiply,
"/", EB_RequireUnsignedOperands);
2384 SubExprInfo visitComb(
DivSOp op) {
2385 return emitBinary(op, Multiply,
"/",
2386 EB_RequireSignedOperands | EB_ForceResultSigned);
2388 SubExprInfo visitComb(
ModUOp op) {
2389 return emitBinary(op, Multiply,
"%", EB_RequireUnsignedOperands);
2391 SubExprInfo visitComb(
ModSOp op) {
2392 return emitBinary(op, Multiply,
"%",
2393 EB_RequireSignedOperands | EB_ForceResultSigned);
2395 SubExprInfo visitComb(
ShlOp op) {
2396 return emitBinary(op, Shift,
"<<", EB_RHS_UnsignedWithSelfDeterminedWidth);
2398 SubExprInfo visitComb(
ShrUOp op) {
2400 return emitBinary(op, Shift,
">>", EB_RHS_UnsignedWithSelfDeterminedWidth);
2402 SubExprInfo visitComb(
ShrSOp op) {
2405 return emitBinary(op, Shift,
">>>",
2406 EB_RequireSignedOperands | EB_ForceResultSigned |
2407 EB_RHS_UnsignedWithSelfDeterminedWidth);
2409 SubExprInfo visitComb(
AndOp op) {
2410 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2411 return emitBinary(op, And,
"&");
2413 SubExprInfo visitComb(
OrOp op) {
2414 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2415 return emitBinary(op, Or,
"|");
2417 SubExprInfo visitComb(
XorOp op) {
2418 if (op.isBinaryNot())
2419 return emitUnary(op,
"~");
2420 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2421 return emitBinary(op, Xor,
"^");
2426 SubExprInfo visitComb(
ParityOp op) {
return emitUnary(op,
"^",
true); }
2428 SubExprInfo visitComb(ReplicateOp op);
2429 SubExprInfo visitComb(
ConcatOp op);
2431 SubExprInfo visitComb(ICmpOp op);
2433 InFlightDiagnostic emitAssignmentPatternContextError(Operation *op) {
2434 auto d = emitOpError(op,
"must be printed as assignment pattern, but is "
2435 "not printed within an assignment-like context");
2436 d.attachNote() <<
"this is likely a bug in PrepareForEmission, which is "
2437 "supposed to spill such expressions";
2441 SubExprInfo printStructCreate(
2442 ArrayRef<hw::detail::FieldInfo> fieldInfos,
2444 bool printAsPattern, Operation *op);
2447 ModuleEmitter &emitter;
2454 SubExprSignRequirement signPreference = NoRequirement;
2458 SmallPtrSetImpl<Operation *> &emittedExprs;
2461 SmallVector<Token> localTokens;
2475 bool isAssignmentLikeContext =
false;
2479 SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
2481 unsigned emitBinaryFlags) {
2483 emitError(op,
"SV attributes emission is unimplemented for the op");
2494 if (emitBinaryFlags & EB_ForceResultSigned)
2495 ps <<
"$signed(" << PP::ibox0;
2496 auto operandSignReq =
2497 SubExprSignRequirement(emitBinaryFlags & EB_OperandSignRequirementMask);
2498 auto lhsInfo = emitSubExpr(op->getOperand(0), prec, operandSignReq);
2500 auto lhsSpace = prec == VerilogPrecedence::Comparison ? PP::nbsp : PP::space;
2502 ps << lhsSpace << syntax << PP::nbsp;
2509 auto rhsPrec = prec;
2510 if (!isa<AddOp, MulOp, AndOp, OrOp, XorOp>(op))
2511 rhsPrec = VerilogPrecedence(prec - 1);
2516 bool rhsIsUnsignedValueWithSelfDeterminedWidth =
false;
2517 if (emitBinaryFlags & EB_RHS_UnsignedWithSelfDeterminedWidth) {
2518 rhsIsUnsignedValueWithSelfDeterminedWidth =
true;
2519 operandSignReq = NoRequirement;
2522 auto rhsInfo = emitSubExpr(op->getOperand(1), rhsPrec, operandSignReq,
2523 rhsIsUnsignedValueWithSelfDeterminedWidth);
2527 SubExprSignResult signedness = IsUnsigned;
2528 if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
2529 signedness = IsSigned;
2531 if (emitBinaryFlags & EB_ForceResultSigned) {
2532 ps << PP::end <<
")";
2533 signedness = IsSigned;
2537 return {prec, signedness};
2540 SubExprInfo ExprEmitter::emitUnary(Operation *op,
const char *syntax,
2541 bool resultAlwaysUnsigned) {
2543 emitError(op,
"SV attributes emission is unimplemented for the op");
2546 auto signedness = emitSubExpr(op->getOperand(0), Selection).signedness;
2550 return {isa<ICmpOp>(op) ? LowestPrecedence : Unary,
2551 resultAlwaysUnsigned ? IsUnsigned : signedness};
2556 void ExprEmitter::emitSVAttributes(Operation *op) {
2575 if (constant && constant.getValue().isZero())
2576 return concat.getOperand(1);
2586 SubExprInfo ExprEmitter::emitSubExpr(Value exp,
2587 VerilogPrecedence parenthesizeIfLooserThan,
2588 SubExprSignRequirement signRequirement,
2589 bool isSelfDeterminedUnsignedValue,
2590 bool isAssignmentLikeContext) {
2593 if (isSelfDeterminedUnsignedValue && exp.hasOneUse()) {
2598 auto *op = exp.getDefiningOp();
2602 if (!shouldEmitInlineExpr) {
2605 if (signRequirement == RequireSigned) {
2607 return {Symbol, IsSigned};
2611 return {Symbol, IsUnsigned};
2614 unsigned subExprStartIndex = buffer.tokens.size();
2616 ps.addCallback({op,
true});
2617 auto done = llvm::make_scope_exit([&]() {
2619 ps.addCallback({op, false});
2625 signPreference = signRequirement;
2627 bool bitCastAdded =
false;
2628 if (state.options.explicitBitcast && isa<AddOp, MulOp, SubOp>(op))
2630 dyn_cast_or_null<IntegerType>(op->getResult(0).getType())) {
2631 ps.addAsString(inType.getWidth());
2632 ps <<
"'(" << PP::ibox0;
2633 bitCastAdded =
true;
2637 llvm::SaveAndRestore restoreALC(this->isAssignmentLikeContext,
2638 isAssignmentLikeContext);
2639 auto expInfo = dispatchCombinationalVisitor(exp.getDefiningOp());
2645 buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex,
2647 buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex, t);
2649 auto closeBoxAndParen = [&]() { ps << PP::end <<
")"; };
2650 if (signRequirement == RequireSigned && expInfo.signedness == IsUnsigned) {
2653 expInfo.signedness = IsSigned;
2654 expInfo.precedence = Selection;
2655 }
else if (signRequirement == RequireUnsigned &&
2656 expInfo.signedness == IsSigned) {
2659 expInfo.signedness = IsUnsigned;
2660 expInfo.precedence = Selection;
2661 }
else if (expInfo.precedence > parenthesizeIfLooserThan) {
2668 expInfo.precedence = Selection;
2675 emittedExprs.insert(exp.getDefiningOp());
2679 SubExprInfo ExprEmitter::visitComb(ReplicateOp op) {
2680 auto openFn = [&]() {
2682 ps.addAsString(op.getMultiple());
2685 auto closeFn = [&]() { ps <<
"}}"; };
2689 if (
auto concatOp = op.getOperand().getDefiningOp<
ConcatOp>()) {
2690 if (op.getOperand().hasOneUse()) {
2691 emitBracedList(concatOp.getOperands(), openFn, closeFn);
2692 return {Symbol, IsUnsigned};
2695 emitBracedList(op.getOperand(), openFn, closeFn);
2696 return {Symbol, IsUnsigned};
2699 SubExprInfo ExprEmitter::visitComb(
ConcatOp op) {
2700 emitBracedList(op.getOperands());
2701 return {Symbol, IsUnsigned};
2704 SubExprInfo ExprEmitter::visitTypeOp(
BitcastOp op) {
2708 Type toType = op.getType();
2711 ps.invokeWithStringOS(
2712 [&](
auto &os) { emitter.emitTypeDims(toType, op.getLoc(), os); });
2715 return emitSubExpr(op.getInput(), LowestPrecedence);
2718 SubExprInfo ExprEmitter::visitComb(ICmpOp op) {
2719 const char *symop[] = {
"==",
"!=",
"<",
"<=",
">",
">=",
"<",
2720 "<=",
">",
">=",
"===",
"!==",
"==?",
"!=?"};
2721 SubExprSignRequirement signop[] = {
2723 NoRequirement, NoRequirement,
2725 RequireSigned, RequireSigned, RequireSigned, RequireSigned,
2727 RequireUnsigned, RequireUnsigned, RequireUnsigned, RequireUnsigned,
2729 NoRequirement, NoRequirement, NoRequirement, NoRequirement};
2731 auto pred =
static_cast<uint64_t
>(op.getPredicate());
2732 assert(pred <
sizeof(symop) /
sizeof(symop[0]));
2735 if (op.isEqualAllOnes())
2736 return emitUnary(op,
"&",
true);
2739 if (op.isNotEqualZero())
2740 return emitUnary(op,
"|",
true);
2742 auto result = emitBinary(op, Comparison, symop[pred], signop[pred]);
2746 result.signedness = IsUnsigned;
2750 SubExprInfo ExprEmitter::visitComb(
ExtractOp op) {
2752 emitError(op,
"SV attributes emission is unimplemented for the op");
2754 unsigned loBit = op.getLowBit();
2755 unsigned hiBit = loBit + cast<IntegerType>(op.getType()).getWidth() - 1;
2757 auto x = emitSubExpr(op.getInput(), LowestPrecedence);
2758 assert((x.precedence == Symbol ||
2760 "should be handled by isExpressionUnableToInline");
2765 op.getInput().getType().getIntOrFloatBitWidth() == hiBit + 1)
2769 ps.addAsString(hiBit);
2770 if (hiBit != loBit) {
2772 ps.addAsString(loBit);
2775 return {Unary, IsUnsigned};
2778 SubExprInfo ExprEmitter::visitSV(GetModportOp op) {
2780 emitError(op,
"SV attributes emission is unimplemented for the op");
2782 auto decl = op.getReferencedDecl(state.symbolCache);
2785 return {Selection, IsUnsigned};
2788 SubExprInfo ExprEmitter::visitSV(SystemFunctionOp op) {
2790 emitError(op,
"SV attributes emission is unimplemented for the op");
2793 ps.scopedBox(PP::ibox0, [&]() {
2795 op.getOperands(), [&](Value v) { emitSubExpr(v, LowestPrecedence); },
2796 [&]() { ps <<
"," << PP::space; });
2799 return {Symbol, IsUnsigned};
2802 SubExprInfo ExprEmitter::visitSV(ReadInterfaceSignalOp op) {
2804 emitError(op,
"SV attributes emission is unimplemented for the op");
2806 auto decl = op.getReferencedDecl(state.symbolCache);
2810 return {Selection, IsUnsigned};
2813 SubExprInfo ExprEmitter::visitSV(XMROp op) {
2815 emitError(op,
"SV attributes emission is unimplemented for the op");
2817 if (op.getIsRooted())
2819 for (
auto s : op.getPath())
2820 ps << PPExtString(cast<StringAttr>(s).getValue()) <<
".";
2822 return {Selection, IsUnsigned};
2827 SubExprInfo ExprEmitter::visitSV(XMRRefOp op) {
2829 emitError(op,
"SV attributes emission is unimplemented for the op");
2832 auto globalRef = op.getReferencedPath(&state.symbolCache);
2833 auto namepath = globalRef.getNamepathAttr().getValue();
2834 auto *module = state.symbolCache.getDefinition(
2835 cast<InnerRefAttr>(namepath.front()).getModule());
2837 for (
auto sym : namepath) {
2839 auto innerRef = cast<InnerRefAttr>(sym);
2840 auto ref = state.symbolCache.getInnerDefinition(innerRef.getModule(),
2841 innerRef.getName());
2842 if (ref.hasPort()) {
2848 auto leaf = op.getVerbatimSuffixAttr();
2849 if (leaf && leaf.size())
2851 return {Selection, IsUnsigned};
2854 SubExprInfo ExprEmitter::visitVerbatimExprOp(Operation *op, ArrayAttr symbols) {
2856 emitError(op,
"SV attributes emission is unimplemented for the op");
2858 emitTextWithSubstitutions(
2859 ps, op->getAttrOfType<StringAttr>(
"format_string").getValue(), op,
2860 [&](Value operand) { emitSubExpr(operand, LowestPrecedence); }, symbols);
2862 return {Unary, IsUnsigned};
2865 template <
typename MacroTy>
2866 SubExprInfo ExprEmitter::emitMacroCall(MacroTy op) {
2868 emitError(op,
"SV attributes emission is unimplemented for the op");
2871 auto macroOp = op.getReferencedMacro(&state.symbolCache);
2872 assert(macroOp &&
"Invalid IR");
2874 macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
2876 if (!op.getInputs().empty()) {
2878 llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
2879 emitExpression(val, LowestPrecedence, false);
2883 return {LowestPrecedence, IsUnsigned};
2886 SubExprInfo ExprEmitter::visitSV(MacroRefExprOp op) {
2887 return emitMacroCall(op);
2890 SubExprInfo ExprEmitter::visitSV(MacroRefExprSEOp op) {
2891 return emitMacroCall(op);
2894 SubExprInfo ExprEmitter::visitSV(ConstantXOp op) {
2896 emitError(op,
"SV attributes emission is unimplemented for the op");
2898 ps.addAsString(op.getWidth());
2900 return {Unary, IsUnsigned};
2903 SubExprInfo ExprEmitter::visitSV(ConstantStrOp op) {
2905 emitError(op,
"SV attributes emission is unimplemented for the op");
2907 ps.writeQuotedEscaped(op.getStr());
2908 return {Symbol, IsUnsigned};
2911 SubExprInfo ExprEmitter::visitSV(ConstantZOp op) {
2913 emitError(op,
"SV attributes emission is unimplemented for the op");
2915 ps.addAsString(op.getWidth());
2917 return {Unary, IsUnsigned};
2920 SubExprInfo ExprEmitter::printConstantScalar(APInt &value, IntegerType type) {
2921 bool isNegated =
false;
2924 if (signPreference == RequireSigned && value.isNegative() &&
2925 !value.isMinSignedValue()) {
2930 ps.addAsString(type.getWidth());
2934 if (signPreference == RequireSigned)
2940 SmallString<32> valueStr;
2942 (-value).toStringUnsigned(valueStr, 16);
2944 value.toStringUnsigned(valueStr, 16);
2947 return {Unary, signPreference == RequireSigned ? IsSigned : IsUnsigned};
2950 SubExprInfo ExprEmitter::visitTypeOp(
ConstantOp op) {
2952 emitError(op,
"SV attributes emission is unimplemented for the op");
2954 auto value = op.getValue();
2958 if (value.getBitWidth() == 0) {
2959 emitOpError(op,
"will not emit zero width constants in the general case");
2960 ps <<
"<<unsupported zero width constant: "
2961 <<
PPExtString(op->getName().getStringRef()) <<
">>";
2962 return {Unary, IsUnsigned};
2965 return printConstantScalar(value, cast<IntegerType>(op.getType()));
2968 void ExprEmitter::printConstantArray(ArrayAttr elementValues, Type
elementType,
2969 bool printAsPattern, Operation *op) {
2970 if (printAsPattern && !isAssignmentLikeContext)
2971 emitAssignmentPatternContextError(op);
2972 StringRef openDelim = printAsPattern ?
"'{" :
"{";
2975 elementValues, [&]() { ps << openDelim; },
2976 [&](Attribute elementValue) {
2977 printConstantAggregate(elementValue,
elementType, op);
2979 [&]() { ps <<
"}"; });
2982 void ExprEmitter::printConstantStruct(
2983 ArrayRef<hw::detail::FieldInfo> fieldInfos, ArrayAttr fieldValues,
2984 bool printAsPattern, Operation *op) {
2985 if (printAsPattern && !isAssignmentLikeContext)
2986 emitAssignmentPatternContextError(op);
2993 auto fieldRange = llvm::make_filter_range(
2994 llvm::zip(fieldInfos, fieldValues), [](
const auto &fieldAndValue) {
2999 if (printAsPattern) {
3001 fieldRange, [&]() { ps <<
"'{"; },
3002 [&](
const auto &fieldAndValue) {
3003 ps.scopedBox(PP::ibox2, [&]() {
3004 const auto &[field, value] = fieldAndValue;
3005 ps <<
PPExtString(emitter.getVerilogStructFieldName(field.name))
3006 <<
":" << PP::space;
3007 printConstantAggregate(value, field.type, op);
3010 [&]() { ps <<
"}"; });
3013 fieldRange, [&]() { ps <<
"{"; },
3014 [&](
const auto &fieldAndValue) {
3015 ps.scopedBox(PP::ibox2, [&]() {
3016 const auto &[field, value] = fieldAndValue;
3017 printConstantAggregate(value, field.type, op);
3020 [&]() { ps <<
"}"; });
3024 void ExprEmitter::printConstantAggregate(Attribute attr, Type type,
3027 if (
auto arrayType = hw::type_dyn_cast<ArrayType>(type))
3028 return printConstantArray(cast<ArrayAttr>(attr), arrayType.getElementType(),
3029 isAssignmentLikeContext, op);
3032 if (
auto arrayType = hw::type_dyn_cast<UnpackedArrayType>(type))
3033 return printConstantArray(cast<ArrayAttr>(attr), arrayType.getElementType(),
3037 if (
auto structType = hw::type_dyn_cast<StructType>(type))
3038 return printConstantStruct(structType.getElements(), cast<ArrayAttr>(attr),
3039 isAssignmentLikeContext, op);
3041 if (
auto intType = hw::type_dyn_cast<IntegerType>(type)) {
3042 auto value = cast<IntegerAttr>(attr).getValue();
3043 printConstantScalar(value, intType);
3047 emitOpError(op,
"contains constant of type ")
3048 << type <<
" which cannot be emitted as Verilog";
3051 SubExprInfo ExprEmitter::visitTypeOp(AggregateConstantOp op) {
3053 emitError(op,
"SV attributes emission is unimplemented for the op");
3057 "zero-bit types not allowed at this point");
3059 printConstantAggregate(op.getFields(), op.getType(), op);
3060 return {Symbol, IsUnsigned};
3063 SubExprInfo ExprEmitter::visitTypeOp(ParamValueOp op) {
3065 emitError(op,
"SV attributes emission is unimplemented for the op");
3067 return ps.invokeWithStringOS([&](
auto &os) {
3068 return emitter.printParamValue(op.getValue(), os, [&]() {
3069 return op->emitOpError(
"invalid parameter use");
3076 SubExprInfo ExprEmitter::visitTypeOp(
ArraySliceOp op) {
3078 emitError(op,
"SV attributes emission is unimplemented for the op");
3080 auto arrayPrec = emitSubExpr(op.getInput(), Selection);
3082 unsigned dstWidth = type_cast<ArrayType>(op.getType()).getNumElements();
3084 emitSubExpr(op.getLowIndex(), LowestPrecedence);
3086 ps.addAsString(dstWidth);
3088 return {Selection, arrayPrec.signedness};
3091 SubExprInfo ExprEmitter::visitTypeOp(
ArrayGetOp op) {
3092 emitSubExpr(op.getInput(), Selection);
3097 emitSubExpr(op.getIndex(), LowestPrecedence);
3099 emitSVAttributes(op);
3100 return {Selection, IsUnsigned};
3106 emitError(op,
"SV attributes emission is unimplemented for the op");
3108 if (op.isUniform()) {
3110 ps.addAsString(op.getInputs().size());
3112 emitSubExpr(op.getUniformElement(), LowestPrecedence);
3116 op.getInputs(), [&]() { ps <<
"{"; },
3119 emitSubExprIBox2(v);
3122 [&]() { ps <<
"}"; });
3124 return {Unary, IsUnsigned};
3127 SubExprInfo ExprEmitter::visitSV(UnpackedArrayCreateOp op) {
3129 emitError(op,
"SV attributes emission is unimplemented for the op");
3132 llvm::reverse(op.getInputs()), [&]() { ps <<
"'{"; },
3133 [&](Value v) { emitSubExprIBox2(v); }, [&]() { ps <<
"}"; });
3134 return {Unary, IsUnsigned};
3139 emitError(op,
"SV attributes emission is unimplemented for the op");
3141 emitBracedList(op.getOperands());
3142 return {Unary, IsUnsigned};
3145 SubExprInfo ExprEmitter::visitSV(ArrayIndexInOutOp op) {
3147 emitError(op,
"SV attributes emission is unimplemented for the op");
3149 auto index = op.getIndex();
3150 auto arrayPrec = emitSubExpr(op.getInput(), Selection);
3155 emitSubExpr(index, LowestPrecedence);
3157 return {Selection, arrayPrec.signedness};
3160 SubExprInfo ExprEmitter::visitSV(IndexedPartSelectInOutOp op) {
3162 emitError(op,
"SV attributes emission is unimplemented for the op");
3164 auto prec = emitSubExpr(op.getInput(), Selection);
3166 emitSubExpr(op.getBase(), LowestPrecedence);
3167 if (op.getDecrement())
3171 ps.addAsString(op.getWidth());
3173 return {Selection, prec.signedness};
3176 SubExprInfo ExprEmitter::visitSV(IndexedPartSelectOp op) {
3178 emitError(op,
"SV attributes emission is unimplemented for the op");
3180 auto info = emitSubExpr(op.getInput(), LowestPrecedence);
3182 emitSubExpr(op.getBase(), LowestPrecedence);
3183 if (op.getDecrement())
3187 ps.addAsString(op.getWidth());
3192 SubExprInfo ExprEmitter::visitSV(StructFieldInOutOp op) {
3194 emitError(op,
"SV attributes emission is unimplemented for the op");
3196 auto prec = emitSubExpr(op.getInput(), Selection);
3198 <<
PPExtString(emitter.getVerilogStructFieldName(op.getFieldAttr()));
3199 return {Selection, prec.signedness};
3202 SubExprInfo ExprEmitter::visitSV(SampledOp op) {
3204 emitError(op,
"SV attributes emission is unimplemented for the op");
3207 auto info = emitSubExpr(op.getExpression(), LowestPrecedence);
3212 SubExprInfo ExprEmitter::visitComb(
MuxOp op) {
3226 return ps.scopedBox(PP::cbox0, [&]() -> SubExprInfo {
3227 ps.scopedBox(PP::ibox0, [&]() {
3228 emitSubExpr(op.getCond(), VerilogPrecedence(Conditional - 1));
3232 emitSVAttributes(op);
3234 auto lhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3235 return emitSubExpr(op.getTrueValue(), VerilogPrecedence(Conditional - 1));
3239 auto rhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3240 return emitSubExpr(op.getFalseValue(), Conditional);
3243 SubExprSignResult signedness = IsUnsigned;
3244 if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
3245 signedness = IsSigned;
3247 return {Conditional, signedness};
3251 SubExprInfo ExprEmitter::printStructCreate(
3252 ArrayRef<hw::detail::FieldInfo> fieldInfos,
3254 bool printAsPattern, Operation *op) {
3255 if (printAsPattern && !isAssignmentLikeContext)
3256 emitAssignmentPatternContextError(op);
3259 auto filteredFields = llvm::make_filter_range(
3260 llvm::enumerate(fieldInfos),
3261 [](
const auto &field) {
return !
isZeroBitType(field.value().type); });
3263 if (printAsPattern) {
3265 filteredFields, [&]() { ps <<
"'{"; },
3266 [&](
const auto &field) {
3267 ps.scopedBox(PP::ibox2, [&]() {
3269 emitter.getVerilogStructFieldName(field.value().name))
3270 <<
":" << PP::space;
3271 fieldFn(field.value(), field.index());
3274 [&]() { ps <<
"}"; });
3277 filteredFields, [&]() { ps <<
"{"; },
3278 [&](
const auto &field) {
3279 ps.scopedBox(PP::ibox2,
3280 [&]() { fieldFn(field.value(), field.index()); });
3282 [&]() { ps <<
"}"; });
3285 return {Selection, IsUnsigned};
3290 emitError(op,
"SV attributes emission is unimplemented for the op");
3294 bool printAsPattern = isAssignmentLikeContext;
3295 StructType structType = op.getType();
3296 return printStructCreate(
3297 structType.getElements(),
3298 [&](
const auto &field,
auto index) {
3299 emitSubExpr(op.getOperand(index), Selection, NoRequirement,
3301 isAssignmentLikeContext);
3303 printAsPattern, op);
3308 emitError(op,
"SV attributes emission is unimplemented for the op");
3310 emitSubExpr(op.getInput(), Selection);
3312 <<
PPExtString(emitter.getVerilogStructFieldName(op.getFieldNameAttr()));
3313 return {Selection, IsUnsigned};
3316 SubExprInfo ExprEmitter::visitTypeOp(StructInjectOp op) {
3318 emitError(op,
"SV attributes emission is unimplemented for the op");
3322 bool printAsPattern = isAssignmentLikeContext;
3323 StructType structType = op.getType();
3324 return printStructCreate(
3325 structType.getElements(),
3326 [&](
const auto &field,
auto index) {
3327 if (field.name == op.getFieldNameAttr()) {
3328 emitSubExpr(op.getNewValue(), Selection);
3330 emitSubExpr(op.getInput(), Selection);
3332 << PPExtString(emitter.getVerilogStructFieldName(field.name));
3335 printAsPattern, op);
3338 SubExprInfo ExprEmitter::visitTypeOp(EnumConstantOp op) {
3339 ps <<
PPSaveString(emitter.fieldNameResolver.getEnumFieldName(op.getField()));
3340 return {Selection, IsUnsigned};
3343 SubExprInfo ExprEmitter::visitTypeOp(EnumCmpOp op) {
3345 emitError(op,
"SV attributes emission is unimplemented for the op");
3346 auto result = emitBinary(op, Comparison,
"==", NoRequirement);
3349 result.signedness = IsUnsigned;
3353 SubExprInfo ExprEmitter::visitTypeOp(UnionCreateOp op) {
3355 emitError(op,
"SV attributes emission is unimplemented for the op");
3360 auto &element = unionType.getElements()[op.getFieldIndex()];
3364 if (!elementWidth) {
3365 ps.addAsString(unionWidth);
3367 return {Unary, IsUnsigned};
3371 if (elementWidth == unionWidth) {
3372 emitSubExpr(op.getInput(), LowestPrecedence);
3373 return {Unary, IsUnsigned};
3378 ps.scopedBox(PP::ibox0, [&]() {
3379 if (
auto prePadding = element.offset) {
3380 ps.addAsString(prePadding);
3381 ps <<
"'h0," << PP::space;
3383 emitSubExpr(op.getInput(), Selection);
3384 if (
auto postPadding = unionWidth - elementWidth - element.offset) {
3385 ps <<
"," << PP::space;
3386 ps.addAsString(postPadding);
3392 return {Unary, IsUnsigned};
3395 SubExprInfo ExprEmitter::visitTypeOp(UnionExtractOp op) {
3397 emitError(op,
"SV attributes emission is unimplemented for the op");
3398 emitSubExpr(op.getInput(), Selection);
3401 auto unionType = cast<UnionType>(
getCanonicalType(op.getInput().getType()));
3403 auto &element = unionType.getElements()[op.getFieldIndex()];
3405 bool needsPadding = elementWidth < unionWidth || element.offset > 0;
3406 auto verilogFieldName = emitter.getVerilogStructFieldName(element.name);
3415 return {Selection, IsUnsigned};
3418 SubExprInfo ExprEmitter::visitUnhandledExpr(Operation *op) {
3419 emitOpError(op,
"cannot emit this expression to Verilog");
3420 ps <<
"<<unsupported expr: " <<
PPExtString(op->getName().getStringRef())
3422 return {Symbol, IsUnsigned};
3438 enum class PropertyPrecedence {
3458 struct EmittedProperty {
3460 PropertyPrecedence precedence;
3465 class PropertyEmitter :
public EmitterBase,
3466 public ltl::Visitor<PropertyEmitter, EmittedProperty> {
3470 PropertyEmitter(ModuleEmitter &emitter,
3471 SmallPtrSetImpl<Operation *> &emittedOps)
3472 : PropertyEmitter(emitter, emittedOps, localTokens) {}
3473 PropertyEmitter(ModuleEmitter &emitter,
3474 SmallPtrSetImpl<Operation *> &emittedOps,
3476 : EmitterBase(emitter.state), emitter(emitter), emittedOps(emittedOps),
3478 ps(buffer, state.saver, state.options.emitVerilogLocations) {
3479 assert(state.pp.getListener() == &state.saver);
3482 void emitAssertPropertyDisable(
3483 Value property, Value disable,
3484 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3486 void emitAssertPropertyBody(
3487 Value property, Value disable,
3488 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3490 void emitAssertPropertyBody(
3491 Value property, sv::EventControl event, Value clock, Value disable,
3492 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3497 emitNestedProperty(Value property,
3498 PropertyPrecedence parenthesizeIfLooserThan);
3499 using ltl::Visitor<PropertyEmitter, EmittedProperty>::visitLTL;
3500 friend class ltl::Visitor<PropertyEmitter, EmittedProperty>;
3502 EmittedProperty visitUnhandledLTL(Operation *op);
3503 EmittedProperty visitLTL(ltl::AndOp op);
3504 EmittedProperty visitLTL(ltl::OrOp op);
3505 EmittedProperty visitLTL(ltl::IntersectOp op);
3506 EmittedProperty visitLTL(ltl::DelayOp op);
3507 EmittedProperty visitLTL(ltl::ConcatOp op);
3508 EmittedProperty visitLTL(ltl::RepeatOp op);
3509 EmittedProperty visitLTL(ltl::GoToRepeatOp op);
3510 EmittedProperty visitLTL(ltl::NonConsecutiveRepeatOp op);
3511 EmittedProperty visitLTL(ltl::NotOp op);
3512 EmittedProperty visitLTL(ltl::ImplicationOp op);
3513 EmittedProperty visitLTL(ltl::UntilOp op);
3514 EmittedProperty visitLTL(ltl::EventuallyOp op);
3515 EmittedProperty visitLTL(ltl::ClockOp op);
3517 void emitLTLConcat(ValueRange inputs);
3520 ModuleEmitter &emitter;
3525 SmallPtrSetImpl<Operation *> &emittedOps;
3528 SmallVector<Token> localTokens;
3541 void PropertyEmitter::emitAssertPropertyDisable(
3542 Value property, Value disable,
3543 PropertyPrecedence parenthesizeIfLooserThan) {
3546 ps <<
"disable iff" << PP::nbsp <<
"(";
3548 emitNestedProperty(disable, PropertyPrecedence::Unary);
3554 ps.scopedBox(PP::ibox0,
3555 [&] { emitNestedProperty(property, parenthesizeIfLooserThan); });
3561 void PropertyEmitter::emitAssertPropertyBody(
3562 Value property, Value disable,
3563 PropertyPrecedence parenthesizeIfLooserThan) {
3564 assert(localTokens.empty());
3566 emitAssertPropertyDisable(property, disable, parenthesizeIfLooserThan);
3571 if (&buffer.tokens == &localTokens)
3572 buffer.flush(state.pp);
3575 void PropertyEmitter::emitAssertPropertyBody(
3576 Value property, sv::EventControl event, Value clock, Value disable,
3577 PropertyPrecedence parenthesizeIfLooserThan) {
3578 assert(localTokens.empty());
3581 ps.scopedBox(PP::ibox2, [&] {
3582 ps <<
PPExtString(stringifyEventControl(event)) << PP::space;
3583 emitNestedProperty(clock, PropertyPrecedence::Lowest);
3589 emitAssertPropertyDisable(property, disable, parenthesizeIfLooserThan);
3594 if (&buffer.tokens == &localTokens)
3595 buffer.flush(state.pp);
3598 EmittedProperty PropertyEmitter::emitNestedProperty(
3599 Value property, PropertyPrecedence parenthesizeIfLooserThan) {
3609 if (!isa<ltl::SequenceType, ltl::PropertyType>(property.getType())) {
3610 ExprEmitter(emitter, emittedOps, buffer.tokens)
3611 .emitExpression(property, LowestPrecedence,
3613 return {PropertyPrecedence::Symbol};
3616 unsigned startIndex = buffer.tokens.size();
3617 auto info = dispatchLTLVisitor(property.getDefiningOp());
3622 if (info.precedence > parenthesizeIfLooserThan) {
3624 buffer.tokens.insert(buffer.tokens.begin() + startIndex,
BeginToken(0));
3625 buffer.tokens.insert(buffer.tokens.begin() + startIndex,
StringToken(
"("));
3627 ps << PP::end <<
")";
3629 info.precedence = PropertyPrecedence::Symbol;
3633 emittedOps.insert(property.getDefiningOp());
3637 EmittedProperty PropertyEmitter::visitUnhandledLTL(Operation *op) {
3638 emitOpError(op,
"emission as Verilog property or sequence not supported");
3639 ps <<
"<<unsupported: " <<
PPExtString(op->getName().getStringRef()) <<
">>";
3640 return {PropertyPrecedence::Symbol};
3643 EmittedProperty PropertyEmitter::visitLTL(ltl::AndOp op) {
3646 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::And); },
3647 [&]() { ps << PP::space <<
"and" << PP::nbsp; });
3648 return {PropertyPrecedence::And};
3651 EmittedProperty PropertyEmitter::visitLTL(ltl::OrOp op) {
3654 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::Or); },
3655 [&]() { ps << PP::space <<
"or" << PP::nbsp; });
3656 return {PropertyPrecedence::Or};
3659 EmittedProperty PropertyEmitter::visitLTL(ltl::IntersectOp op) {
3663 emitNestedProperty(input, PropertyPrecedence::Intersect);
3665 [&]() { ps << PP::space <<
"intersect" << PP::nbsp; });
3666 return {PropertyPrecedence::Intersect};
3669 EmittedProperty PropertyEmitter::visitLTL(ltl::DelayOp op) {
3671 if (
auto length = op.getLength()) {
3673 ps.addAsString(op.getDelay());
3676 ps.addAsString(op.getDelay());
3678 ps.addAsString(op.getDelay() + *length);
3682 if (op.getDelay() == 0) {
3684 }
else if (op.getDelay() == 1) {
3688 ps.addAsString(op.getDelay());
3693 emitNestedProperty(op.getInput(), PropertyPrecedence::Concat);
3694 return {PropertyPrecedence::Concat};
3697 void PropertyEmitter::emitLTLConcat(ValueRange inputs) {
3698 bool addSeparator =
false;
3699 for (
auto input : inputs) {
3702 if (!input.getDefiningOp<ltl::DelayOp>())
3703 ps <<
"##0" << PP::space;
3705 addSeparator =
true;
3706 emitNestedProperty(input, PropertyPrecedence::Concat);
3710 EmittedProperty PropertyEmitter::visitLTL(ltl::ConcatOp op) {
3711 emitLTLConcat(op.getInputs());
3712 return {PropertyPrecedence::Concat};
3715 EmittedProperty PropertyEmitter::visitLTL(ltl::RepeatOp op) {
3716 emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3717 if (
auto more = op.getMore()) {
3719 ps.addAsString(op.getBase());
3722 ps.addAsString(op.getBase() + *more);
3726 if (op.getBase() == 0) {
3728 }
else if (op.getBase() == 1) {
3732 ps.addAsString(op.getBase());
3736 return {PropertyPrecedence::Repeat};
3739 EmittedProperty PropertyEmitter::visitLTL(ltl::GoToRepeatOp op) {
3740 emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3742 auto more = op.getMore();
3744 ps.addAsString(op.getBase());
3747 ps.addAsString(op.getBase() + more);
3751 return {PropertyPrecedence::Repeat};
3754 EmittedProperty PropertyEmitter::visitLTL(ltl::NonConsecutiveRepeatOp op) {
3755 emitNestedProperty(op.getInput(), PropertyPrecedence::Repeat);
3757 auto more = op.getMore();
3759 ps.addAsString(op.getBase());
3762 ps.addAsString(op.getBase() + more);
3766 return {PropertyPrecedence::Repeat};
3769 EmittedProperty PropertyEmitter::visitLTL(ltl::NotOp op) {
3770 ps <<
"not" << PP::space;
3771 emitNestedProperty(op.getInput(), PropertyPrecedence::Unary);
3772 return {PropertyPrecedence::Unary};
3778 auto concatOp = value.getDefiningOp<ltl::ConcatOp>();
3779 if (!concatOp || concatOp.getInputs().size() < 2)
3781 auto delayOp = concatOp.getInputs().back().getDefiningOp<ltl::DelayOp>();
3782 if (!delayOp || delayOp.getDelay() != 1 || delayOp.getLength() != 0)
3784 auto constOp = delayOp.getInput().getDefiningOp<
ConstantOp>();
3785 if (!constOp || !constOp.getValue().isOne())
3787 return concatOp.getInputs().drop_back();
3790 EmittedProperty PropertyEmitter::visitLTL(ltl::ImplicationOp op) {
3794 emitLTLConcat(range);
3795 ps << PP::space <<
"|=>" << PP::nbsp;
3797 emitNestedProperty(op.getAntecedent(), PropertyPrecedence::Implication);
3798 ps << PP::space <<
"|->" << PP::nbsp;
3800 emitNestedProperty(op.getConsequent(), PropertyPrecedence::Implication);
3801 return {PropertyPrecedence::Implication};
3804 EmittedProperty PropertyEmitter::visitLTL(ltl::UntilOp op) {
3805 emitNestedProperty(op.getInput(), PropertyPrecedence::Until);
3806 ps << PP::space <<
"until" << PP::space;
3807 emitNestedProperty(op.getCondition(), PropertyPrecedence::Until);
3808 return {PropertyPrecedence::Until};
3811 EmittedProperty PropertyEmitter::visitLTL(ltl::EventuallyOp op) {
3812 ps <<
"s_eventually" << PP::space;
3813 emitNestedProperty(op.getInput(), PropertyPrecedence::Qualifier);
3814 return {PropertyPrecedence::Qualifier};
3817 EmittedProperty PropertyEmitter::visitLTL(ltl::ClockOp op) {
3819 ps.scopedBox(PP::ibox2, [&] {
3820 ps <<
PPExtString(stringifyClockEdge(op.getEdge())) << PP::space;
3821 emitNestedProperty(op.getClock(), PropertyPrecedence::Lowest);
3825 emitNestedProperty(op.getInput(), PropertyPrecedence::Clocking);
3826 return {PropertyPrecedence::Clocking};
3836 class NameCollector {
3838 NameCollector(ModuleEmitter &moduleEmitter) : moduleEmitter(moduleEmitter) {}
3842 void collectNames(Block &block);
3844 size_t getMaxDeclNameWidth()
const {
return maxDeclNameWidth; }
3845 size_t getMaxTypeWidth()
const {
return maxTypeWidth; }
3848 size_t maxDeclNameWidth = 0, maxTypeWidth = 0;
3849 ModuleEmitter &moduleEmitter;
3854 static constexpr
size_t maxTypeWidthBound = 32;
3859 void NameCollector::collectNames(Block &block) {
3862 for (
auto &op : block) {
3866 if (isa<InstanceOp, InstanceChoiceOp, InterfaceInstanceOp,
3867 FuncCallProceduralOp, FuncCallOp>(op))
3869 if (isa<ltl::LTLDialect, debug::DebugDialect>(op.getDialect()))
3873 for (
auto result : op.getResults()) {
3875 maxDeclNameWidth = std::max(declName.size(), maxDeclNameWidth);
3876 SmallString<16> typeString;
3880 llvm::raw_svector_ostream stringStream(typeString);
3882 stringStream, op.getLoc());
3884 if (typeString.size() <= maxTypeWidthBound)
3885 maxTypeWidth = std::max(typeString.size(), maxTypeWidth);
3892 if (isa<IfDefProceduralOp, OrderedOutputOp>(op)) {
3893 for (
auto ®ion : op.getRegions()) {
3894 if (!region.empty())
3895 collectNames(region.front());
3909 class StmtEmitter :
public EmitterBase,
3910 public hw::StmtVisitor<StmtEmitter, LogicalResult>,
3911 public sv::Visitor<StmtEmitter, LogicalResult>,
3912 public verif::Visitor<StmtEmitter, LogicalResult> {
3917 : EmitterBase(emitter.state), emitter(emitter), options(options) {}
3919 void emitStatement(Operation *op);
3920 void emitStatementBlock(Block &body);
3923 LogicalResult emitDeclaration(Operation *op);
3926 void collectNamesAndCalculateDeclarationWidths(Block &block);
3929 emitExpression(Value exp, SmallPtrSetImpl<Operation *> &emittedExprs,
3930 VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence,
3931 bool isAssignmentLikeContext =
false);
3932 void emitSVAttributes(Operation *op);
3934 using hw::StmtVisitor<StmtEmitter, LogicalResult>::visitStmt;
3935 using sv::Visitor<StmtEmitter, LogicalResult>::visitSV;
3936 using verif::Visitor<StmtEmitter, LogicalResult>::visitVerif;
3937 friend class hw::StmtVisitor<StmtEmitter, LogicalResult>;
3938 friend class sv::Visitor<StmtEmitter, LogicalResult>;
3939 friend class verif::Visitor<StmtEmitter, LogicalResult>;
3942 LogicalResult visitUnhandledStmt(Operation *op) {
return failure(); }
3943 LogicalResult visitInvalidStmt(Operation *op) {
return failure(); }
3944 LogicalResult visitUnhandledSV(Operation *op) {
return failure(); }
3945 LogicalResult visitInvalidSV(Operation *op) {
return failure(); }
3946 LogicalResult visitUnhandledVerif(Operation *op) {
return failure(); }
3947 LogicalResult visitInvalidVerif(Operation *op) {
return failure(); }
3949 LogicalResult visitSV(
sv::WireOp op) {
return emitDeclaration(op); }
3950 LogicalResult visitSV(
RegOp op) {
return emitDeclaration(op); }
3951 LogicalResult visitSV(LogicOp op) {
return emitDeclaration(op); }
3952 LogicalResult visitSV(LocalParamOp op) {
return emitDeclaration(op); }
3953 template <
typename Op>
3956 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
3957 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
3958 llvm::function_ref<
void()> emitRHS,
PPExtString syntax,
3960 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
3961 LogicalResult visitSV(
AssignOp op);
3962 LogicalResult visitSV(BPAssignOp op);
3963 LogicalResult visitSV(PAssignOp op);
3964 LogicalResult visitSV(ForceOp op);
3965 LogicalResult visitSV(ReleaseOp op);
3966 LogicalResult visitSV(AliasOp op);
3967 LogicalResult visitSV(InterfaceInstanceOp op);
3968 LogicalResult emitOutputLikeOp(Operation *op,
const ModulePortInfo &ports);
3969 LogicalResult visitStmt(OutputOp op);
3971 LogicalResult visitStmt(InstanceOp op);
3972 LogicalResult visitStmt(InstanceChoiceOp op);
3973 void emitInstancePortList(Operation *op,
ModulePortInfo &modPortInfo,
3974 ArrayRef<Value> instPortValues);
3979 LogicalResult emitIfDef(Operation *op, MacroIdentAttr cond);
3980 LogicalResult visitSV(OrderedOutputOp op);
3981 LogicalResult visitSV(
IfDefOp op) {
return emitIfDef(op, op.getCond()); }
3982 LogicalResult visitSV(IfDefProceduralOp op) {
3983 return emitIfDef(op, op.getCond());
3985 LogicalResult visitSV(IfOp op);
3986 LogicalResult visitSV(AlwaysOp op);
3987 LogicalResult visitSV(AlwaysCombOp op);
3988 LogicalResult visitSV(AlwaysFFOp op);
3989 LogicalResult visitSV(InitialOp op);
3990 LogicalResult visitSV(CaseOp op);
3991 LogicalResult visitSV(FWriteOp op);
3992 LogicalResult visitSV(VerbatimOp op);
3993 LogicalResult visitSV(MacroRefOp op);
3995 LogicalResult emitSimulationControlTask(Operation *op,
PPExtString taskName,
3996 std::optional<unsigned> verbosity);
3997 LogicalResult visitSV(StopOp op);
3998 LogicalResult visitSV(FinishOp op);
3999 LogicalResult visitSV(ExitOp op);
4001 LogicalResult emitSeverityMessageTask(Operation *op,
PPExtString taskName,
4002 std::optional<unsigned> verbosity,
4004 ValueRange operands);
4005 LogicalResult visitSV(FatalOp op);
4006 LogicalResult visitSV(ErrorOp op);
4007 LogicalResult visitSV(WarningOp op);
4008 LogicalResult visitSV(InfoOp op);
4010 LogicalResult visitSV(ReadMemOp op);
4012 LogicalResult visitSV(GenerateOp op);
4013 LogicalResult visitSV(GenerateCaseOp op);
4015 LogicalResult visitSV(ForOp op);
4017 void emitAssertionLabel(Operation *op);
4018 void emitAssertionMessage(StringAttr message, ValueRange args,
4019 SmallPtrSetImpl<Operation *> &ops,
4021 template <
typename Op>
4022 LogicalResult emitImmediateAssertion(Op op,
PPExtString opName);
4023 LogicalResult visitSV(AssertOp op);
4024 LogicalResult visitSV(AssumeOp op);
4025 LogicalResult visitSV(CoverOp op);
4026 template <
typename Op>
4027 LogicalResult emitConcurrentAssertion(Op op,
PPExtString opName);
4028 LogicalResult visitSV(AssertConcurrentOp op);
4029 LogicalResult visitSV(AssumeConcurrentOp op);
4030 LogicalResult visitSV(CoverConcurrentOp op);
4031 template <
typename Op>
4032 LogicalResult emitPropertyAssertion(Op op,
PPExtString opName);
4033 LogicalResult visitSV(AssertPropertyOp op);
4034 LogicalResult visitSV(AssumePropertyOp op);
4035 LogicalResult visitSV(CoverPropertyOp op);
4037 LogicalResult visitSV(BindOp op);
4038 LogicalResult visitSV(InterfaceOp op);
4039 LogicalResult visitSV(InterfaceSignalOp op);
4040 LogicalResult visitSV(InterfaceModportOp op);
4041 LogicalResult visitSV(AssignInterfaceSignalOp op);
4042 LogicalResult visitSV(MacroDefOp op);
4044 void emitBlockAsStatement(Block *block,
4045 const SmallPtrSetImpl<Operation *> &locationOps,
4046 StringRef multiLineComment = StringRef());
4048 LogicalResult visitSV(FuncDPIImportOp op);
4049 template <
typename CallOp>
4050 LogicalResult emitFunctionCall(CallOp callOp);
4051 LogicalResult visitSV(FuncCallProceduralOp op);
4052 LogicalResult visitSV(FuncCallOp op);
4053 LogicalResult visitSV(ReturnOp op);
4056 ModuleEmitter &emitter;
4061 size_t maxDeclNameWidth = 0;
4062 size_t maxTypeWidth = 0;
4073 void StmtEmitter::emitExpression(Value exp,
4074 SmallPtrSetImpl<Operation *> &emittedExprs,
4075 VerilogPrecedence parenthesizeIfLooserThan,
4076 bool isAssignmentLikeContext) {
4077 ExprEmitter(emitter, emittedExprs)
4078 .emitExpression(exp, parenthesizeIfLooserThan, isAssignmentLikeContext);
4083 void StmtEmitter::emitSVAttributes(Operation *op) {
4091 setPendingNewline();
4094 void StmtEmitter::emitAssignLike(llvm::function_ref<
void()> emitLHS,
4095 llvm::function_ref<
void()> emitRHS,
4097 std::optional<PPExtString> wordBeforeLHS) {
4099 ps.scopedBox(PP::ibox2, [&]() {
4100 if (wordBeforeLHS) {
4101 ps << *wordBeforeLHS << PP::space;
4105 ps << PP::space << syntax << PP::space;
4107 ps.scopedBox(PP::ibox0, [&]() {
4114 template <
typename Op>
4116 StmtEmitter::emitAssignLike(Op op,
PPExtString syntax,
4117 std::optional<PPExtString> wordBeforeLHS) {
4118 SmallPtrSet<Operation *, 8> ops;
4122 ps.addCallback({op,
true});
4123 emitAssignLike([&]() { emitExpression(op.getDest(), ops); },
4125 emitExpression(op.getSrc(), ops, LowestPrecedence,
4130 ps.addCallback({op,
false});
4131 emitLocationInfoAndNewLine(ops);
4135 LogicalResult StmtEmitter::visitSV(
AssignOp op) {
4138 if (isa_and_nonnull<HWInstanceLike, FuncCallOp>(op.getSrc().getDefiningOp()))
4141 if (emitter.assignsInlined.count(op))
4145 emitSVAttributes(op);
4150 LogicalResult StmtEmitter::visitSV(BPAssignOp op) {
4151 if (op.getSrc().getDefiningOp<FuncCallProceduralOp>())
4155 if (emitter.assignsInlined.count(op))
4159 emitSVAttributes(op);
4164 LogicalResult StmtEmitter::visitSV(PAssignOp op) {
4166 emitSVAttributes(op);
4171 LogicalResult StmtEmitter::visitSV(ForceOp op) {
4173 emitError(op,
"SV attributes emission is unimplemented for the op");
4178 LogicalResult StmtEmitter::visitSV(ReleaseOp op) {
4180 emitError(op,
"SV attributes emission is unimplemented for the op");
4183 SmallPtrSet<Operation *, 8> ops;
4185 ps.addCallback({op,
true});
4186 ps.scopedBox(PP::ibox2, [&]() {
4187 ps <<
"release" << PP::space;
4188 emitExpression(op.getDest(), ops);
4191 ps.addCallback({op,
false});
4192 emitLocationInfoAndNewLine(ops);
4196 LogicalResult StmtEmitter::visitSV(AliasOp op) {
4198 emitError(op,
"SV attributes emission is unimplemented for the op");
4201 SmallPtrSet<Operation *, 8> ops;
4203 ps.addCallback({op,
true});
4204 ps.scopedBox(PP::ibox2, [&]() {
4205 ps <<
"alias" << PP::space;
4206 ps.scopedBox(PP::cbox0, [&]() {
4208 op.getOperands(), [&](Value v) { emitExpression(v, ops); },
4209 [&]() { ps << PP::nbsp <<
"=" << PP::space; });
4213 ps.addCallback({op,
false});
4214 emitLocationInfoAndNewLine(ops);
4218 LogicalResult StmtEmitter::visitSV(InterfaceInstanceOp op) {
4219 auto doNotPrint = op->hasAttr(
"doNotPrint");
4220 if (doNotPrint && !state.options.emitBindComments)
4224 emitError(op,
"SV attributes emission is unimplemented for the op");
4227 StringRef prefix =
"";
4228 ps.addCallback({op,
true});
4231 ps <<
"// This interface is elsewhere emitted as a bind statement."
4235 SmallPtrSet<Operation *, 8> ops;
4238 auto *interfaceOp = op.getReferencedInterface(&state.symbolCache);
4239 assert(interfaceOp &&
"InterfaceInstanceOp has invalid symbol that does not "
4240 "point to an interface");
4243 if (!prefix.empty())
4249 ps.addCallback({op,
false});
4250 emitLocationInfoAndNewLine(ops);
4258 LogicalResult StmtEmitter::emitOutputLikeOp(Operation *op,
4260 SmallPtrSet<Operation *, 8> ops;
4261 size_t operandIndex = 0;
4262 bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
4264 auto operand = op->getOperand(operandIndex);
4268 if (operand.hasOneUse() && operand.getDefiningOp() &&
4269 isa<InstanceOp, InstanceChoiceOp>(operand.getDefiningOp())) {
4278 ps.addCallback({op,
true});
4280 ps.scopedBox(isZeroBit ? PP::neverbox : PP::ibox2, [&]() {
4282 ps <<
"// Zero width: ";
4285 ps <<
"assign" << PP::space;
4287 ps << PP::space <<
"=" << PP::space;
4288 ps.scopedBox(PP::ibox0, [&]() {
4292 isa_and_nonnull<hw::ConstantOp>(operand.getDefiningOp()))
4293 ps <<
"/*Zero width*/";
4295 emitExpression(operand, ops, LowestPrecedence,
4300 ps.addCallback({op,
false});
4301 emitLocationInfoAndNewLine(ops);
4308 LogicalResult StmtEmitter::visitStmt(OutputOp op) {
4309 auto parent = op->getParentOfType<PortList>();
4311 return emitOutputLikeOp(op, ports);
4314 LogicalResult StmtEmitter::visitStmt(
TypeScopeOp op) {
4316 auto typescopeDef = (
"_TYPESCOPE_" + op.getSymName()).str();
4317 ps <<
"`ifndef " << typescopeDef << PP::newline;
4318 ps <<
"`define " << typescopeDef;
4319 setPendingNewline();
4320 emitStatementBlock(*op.getBodyBlock());
4322 ps <<
"`endif // " << typescopeDef;
4323 setPendingNewline();
4327 LogicalResult StmtEmitter::visitStmt(
TypedeclOp op) {
4329 emitError(op,
"SV attributes emission is unimplemented for the op");
4334 ps << PP::neverbox <<
"// ";
4336 SmallPtrSet<Operation *, 8> ops;
4338 ps.scopedBox(PP::ibox2, [&]() {
4339 ps <<
"typedef" << PP::space;
4340 ps.invokeWithStringOS([&](
auto &os) {
4342 op.getAliasType(),
false);
4344 ps << PP::space <<
PPExtString(op.getPreferredName());
4345 ps.invokeWithStringOS(
4346 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
4351 emitLocationInfoAndNewLine(ops);
4355 template <
typename CallOpTy>
4356 LogicalResult StmtEmitter::emitFunctionCall(CallOpTy op) {
4360 dyn_cast<FuncOp>(state.symbolCache.getDefinition(op.getCalleeAttr()));
4362 SmallPtrSet<Operation *, 8> ops;
4366 auto explicitReturn = op.getExplicitlyReturnedValue(callee);
4367 if (explicitReturn) {
4368 assert(explicitReturn.hasOneUse());
4369 if (op->getParentOp()->template hasTrait<ProceduralRegion>()) {
4370 auto bpassignOp = cast<sv::BPAssignOp>(*explicitReturn.user_begin());
4371 emitExpression(bpassignOp.getDest(), ops);
4373 auto assignOp = cast<sv::AssignOp>(*explicitReturn.user_begin());
4374 ps <<
"assign" << PP::nbsp;
4375 emitExpression(assignOp.getDest(), ops);
4377 ps << PP::nbsp <<
"=" << PP::nbsp;
4380 auto arguments = callee.getPortList(
true);
4384 bool needsComma =
false;
4385 auto printArg = [&](Value value) {
4387 ps <<
"," << PP::space;
4388 emitExpression(value, ops);
4392 ps.scopedBox(PP::ibox0, [&] {
4393 unsigned inputIndex = 0, outputIndex = 0;
4394 for (
auto arg : arguments) {
4397 op.getResults()[outputIndex++].getUsers().begin()->getOperand(0));
4399 printArg(op.getInputs()[inputIndex++]);
4404 emitLocationInfoAndNewLine(ops);
4408 LogicalResult StmtEmitter::visitSV(FuncCallProceduralOp op) {
4409 return emitFunctionCall(op);
4412 LogicalResult StmtEmitter::visitSV(FuncCallOp op) {
4413 return emitFunctionCall(op);
4416 template <
typename PPS>
4418 bool isAutomatic =
false,
4419 bool emitAsTwoStateType =
false) {
4420 ps <<
"function" << PP::nbsp;
4422 ps <<
"automatic" << PP::nbsp;
4423 auto retType = op.getExplicitlyReturnedType();
4425 ps.invokeWithStringOS([&](
auto &os) {
4426 emitter.printPackedType(retType, os, op->getLoc(), {},
false,
true,
4427 emitAsTwoStateType);
4433 emitter.emitPortList(
4437 LogicalResult StmtEmitter::visitSV(ReturnOp op) {
4438 auto parent = op->getParentOfType<sv::FuncOp>();
4440 return emitOutputLikeOp(op, ports);
4443 LogicalResult StmtEmitter::visitSV(FuncDPIImportOp importOp) {
4446 ps <<
"import" << PP::nbsp <<
"\"DPI-C\"" << PP::nbsp <<
"context"
4450 if (
auto linkageName = importOp.getLinkageName())
4451 ps << *linkageName << PP::nbsp <<
"=" << PP::nbsp;
4453 cast<FuncOp>(state.symbolCache.getDefinition(importOp.getCalleeAttr()));
4454 assert(op.isDeclaration() &&
"function must be a declaration");
4457 assert(state.pendingNewline);
4463 LogicalResult StmtEmitter::visitSV(FWriteOp op) {
4465 emitError(op,
"SV attributes emission is unimplemented for the op");
4468 SmallPtrSet<Operation *, 8> ops;
4471 ps.addCallback({op,
true});
4473 ps.scopedBox(PP::ibox0, [&]() {
4474 emitExpression(op.getFd(), ops);
4476 ps <<
"," << PP::space;
4477 ps.writeQuotedEscaped(op.getFormatString());
4485 for (
auto operand : op.getSubstitutions()) {
4486 ps <<
"," << PP::space;
4487 emitExpression(operand, ops);
4491 ps.addCallback({op,
false});
4492 emitLocationInfoAndNewLine(ops);
4496 LogicalResult StmtEmitter::visitSV(VerbatimOp op) {
4498 emitError(op,
"SV attributes emission is unimplemented for the op");
4501 SmallPtrSet<Operation *, 8> ops;
4506 StringRef
string = op.getFormatString();
4507 if (
string.ends_with(
"\n"))
4508 string =
string.drop_back();
4513 bool isFirst =
true;
4516 while (!
string.
empty()) {
4517 auto lhsRhs =
string.split(
'\n');
4521 ps << PP::end << PP::newline << PP::neverbox;
4525 emitTextWithSubstitutions(
4526 ps, lhsRhs.first, op,
4527 [&](Value operand) { emitExpression(operand, ops); }, op.getSymbols());
4528 string = lhsRhs.second;
4533 emitLocationInfoAndNewLine(ops);
4538 LogicalResult StmtEmitter::visitSV(MacroRefOp op) {
4540 emitError(op,
"SV attributes emission is unimplemented for the op");
4544 SmallPtrSet<Operation *, 8> ops;
4549 auto macroOp = op.getReferencedMacro(&state.symbolCache);
4550 assert(macroOp &&
"Invalid IR");
4552 macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
4554 if (!op.getInputs().empty()) {
4556 llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
4557 emitExpression(val, ops, LowestPrecedence,
4563 emitLocationInfoAndNewLine(ops);
4569 StmtEmitter::emitSimulationControlTask(Operation *op,
PPExtString taskName,
4570 std::optional<unsigned> verbosity) {
4572 emitError(op,
"SV attributes emission is unimplemented for the op");
4575 SmallPtrSet<Operation *, 8> ops;
4577 ps.addCallback({op,
true});
4579 if (verbosity && *verbosity != 1) {
4581 ps.addAsString(*verbosity);
4585 ps.addCallback({op,
false});
4586 emitLocationInfoAndNewLine(ops);
4590 LogicalResult StmtEmitter::visitSV(StopOp op) {
4591 return emitSimulationControlTask(op,
PPExtString(
"$stop"), op.getVerbosity());
4594 LogicalResult StmtEmitter::visitSV(FinishOp op) {
4595 return emitSimulationControlTask(op,
PPExtString(
"$finish"),
4599 LogicalResult StmtEmitter::visitSV(ExitOp op) {
4600 return emitSimulationControlTask(op,
PPExtString(
"$exit"), {});
4606 StmtEmitter::emitSeverityMessageTask(Operation *op,
PPExtString taskName,
4607 std::optional<unsigned> verbosity,
4608 StringAttr message, ValueRange operands) {
4610 emitError(op,
"SV attributes emission is unimplemented for the op");
4613 SmallPtrSet<Operation *, 8> ops;
4615 ps.addCallback({op,
true});
4621 if ((verbosity && *verbosity != 1) || message) {
4623 ps.scopedBox(PP::ibox0, [&]() {
4627 ps.addAsString(*verbosity);
4632 ps <<
"," << PP::space;
4633 ps.writeQuotedEscaped(message.getValue());
4635 for (
auto operand : operands) {
4636 ps <<
"," << PP::space;
4637 emitExpression(operand, ops);
4646 ps.addCallback({op,
false});
4647 emitLocationInfoAndNewLine(ops);
4651 LogicalResult StmtEmitter::visitSV(FatalOp op) {
4652 return emitSeverityMessageTask(op,
PPExtString(
"$fatal"), op.getVerbosity(),
4653 op.getMessageAttr(), op.getSubstitutions());
4656 LogicalResult StmtEmitter::visitSV(ErrorOp op) {
4657 return emitSeverityMessageTask(op,
PPExtString(
"$error"), {},
4658 op.getMessageAttr(), op.getSubstitutions());
4661 LogicalResult StmtEmitter::visitSV(WarningOp op) {
4662 return emitSeverityMessageTask(op,
PPExtString(
"$warning"), {},
4663 op.getMessageAttr(), op.getSubstitutions());
4666 LogicalResult StmtEmitter::visitSV(InfoOp op) {
4667 return emitSeverityMessageTask(op,
PPExtString(
"$info"), {},
4668 op.getMessageAttr(), op.getSubstitutions());
4671 LogicalResult StmtEmitter::visitSV(ReadMemOp op) {
4672 SmallPtrSet<Operation *, 8> ops({op});
4675 ps.addCallback({op,
true});
4677 switch (op.getBaseAttr().getValue()) {
4678 case MemBaseTypeAttr::MemBaseBin:
4681 case MemBaseTypeAttr::MemBaseHex:
4686 ps.scopedBox(PP::ibox0, [&]() {
4687 ps.writeQuotedEscaped(op.getFilename());
4688 ps <<
"," << PP::space;
4689 emitExpression(op.getDest(), ops);
4693 ps.addCallback({op,
false});
4694 emitLocationInfoAndNewLine(ops);
4698 LogicalResult StmtEmitter::visitSV(GenerateOp op) {
4699 emitSVAttributes(op);
4702 ps.addCallback({op,
true});
4703 ps <<
"generate" << PP::newline;
4705 setPendingNewline();
4706 emitStatementBlock(op.getBody().getBlocks().front());
4709 ps <<
"endgenerate";
4710 ps.addCallback({op,
false});
4711 setPendingNewline();
4715 LogicalResult StmtEmitter::visitSV(GenerateCaseOp op) {
4716 emitSVAttributes(op);
4719 ps.addCallback({op,
true});
4721 ps.invokeWithStringOS([&](
auto &os) {
4722 emitter.printParamValue(
4723 op.getCond(), os, VerilogPrecedence::Selection,
4724 [&]() { return op->emitOpError(
"invalid case parameter"); });
4727 setPendingNewline();
4730 ArrayAttr
patterns = op.getCasePatterns();
4731 ArrayAttr caseNames = op.getCaseNames();
4732 MutableArrayRef<Region> regions = op.getCaseRegions();
4739 llvm::StringMap<size_t> nextGenIds;
4740 ps.scopedBox(PP::bbox2, [&]() {
4742 for (
size_t i = 0, e =
patterns.size(); i < e; ++i) {
4743 auto ®ion = regions[i];
4744 assert(region.hasOneBlock());
4745 Attribute patternAttr = patterns[i];
4748 if (!isa<mlir::TypedAttr>(patternAttr))
4751 ps.invokeWithStringOS([&](auto &os) {
4752 emitter.printParamValue(
4753 patternAttr, os, VerilogPrecedence::LowestPrecedence,
4754 [&]() { return op->emitOpError(
"invalid case value"); });
4757 StringRef legalName =
4758 legalizeName(cast<StringAttr>(caseNames[i]).getValue(), nextGenIds,
4761 setPendingNewline();
4762 emitStatementBlock(region.getBlocks().front());
4765 setPendingNewline();
4771 ps.addCallback({op,
false});
4772 setPendingNewline();
4776 LogicalResult StmtEmitter::visitSV(ForOp op) {
4777 emitSVAttributes(op);
4778 llvm::SmallPtrSet<Operation *, 8> ops;
4779 ps.addCallback({op,
true});
4781 auto inductionVarName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
4784 ps.scopedBox(PP::cbox0, [&]() {
4788 ps <<
"logic" << PP::nbsp;
4789 ps.invokeWithStringOS([&](
auto &os) {
4790 emitter.emitTypeDims(op.getInductionVar().getType(), op.getLoc(),
4795 [&]() { emitExpression(op.getLowerBound(), ops); },
PPExtString(
"="));
4800 emitAssignLike([&]() { ps <<
PPExtString(inductionVarName); },
4801 [&]() { emitExpression(op.getUpperBound(), ops); },
4807 emitAssignLike([&]() { ps <<
PPExtString(inductionVarName); },
4808 [&]() { emitExpression(op.getStep(), ops); },
4812 ps << PP::neverbreak;
4813 setPendingNewline();
4814 emitStatementBlock(op.getBody().getBlocks().front());
4817 ps.addCallback({op,
false});
4818 emitLocationInfoAndNewLine(ops);
4823 void StmtEmitter::emitAssertionLabel(Operation *op) {
4824 if (
auto label = op->getAttrOfType<StringAttr>(
"hw.verilogName"))
4830 void StmtEmitter::emitAssertionMessage(StringAttr message, ValueRange args,
4831 SmallPtrSetImpl<Operation *> &ops,
4832 bool isConcurrent =
false) {
4835 ps << PP::space <<
"else" << PP::nbsp <<
"$error(";
4836 ps.scopedBox(PP::ibox0, [&]() {
4837 ps.writeQuotedEscaped(message.getValue());
4839 for (
auto arg : args) {
4840 ps <<
"," << PP::space;
4841 emitExpression(arg, ops);
4847 template <
typename Op>
4848 LogicalResult StmtEmitter::emitImmediateAssertion(Op op,
PPExtString opName) {
4850 emitError(op,
"SV attributes emission is unimplemented for the op");
4853 SmallPtrSet<Operation *, 8> ops;
4855 ps.addCallback({op,
true});
4856 ps.scopedBox(PP::ibox2, [&]() {
4857 emitAssertionLabel(op);
4858 ps.scopedBox(PP::cbox0, [&]() {
4860 switch (op.getDefer()) {
4861 case DeferAssert::Immediate:
4863 case DeferAssert::Observed:
4866 case DeferAssert::Final:
4871 ps.scopedBox(PP::ibox0, [&]() {
4872 emitExpression(op.getExpression(), ops);
4875 emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops);
4879 ps.addCallback({op,
false});
4880 emitLocationInfoAndNewLine(ops);
4884 LogicalResult StmtEmitter::visitSV(AssertOp op) {
4885 return emitImmediateAssertion(op,
PPExtString(
"assert"));
4888 LogicalResult StmtEmitter::visitSV(AssumeOp op) {
4889 return emitImmediateAssertion(op,
PPExtString(
"assume"));
4892 LogicalResult StmtEmitter::visitSV(CoverOp op) {
4893 return emitImmediateAssertion(op,
PPExtString(
"cover"));
4896 template <
typename Op>
4897 LogicalResult StmtEmitter::emitConcurrentAssertion(Op op,
PPExtString opName) {
4899 emitError(op,
"SV attributes emission is unimplemented for the op");
4902 SmallPtrSet<Operation *, 8> ops;
4904 ps.addCallback({op,
true});
4905 ps.scopedBox(PP::ibox2, [&]() {
4906 emitAssertionLabel(op);
4907 ps.scopedBox(PP::cbox0, [&]() {
4908 ps << opName << PP::nbsp <<
"property (";
4909 ps.scopedBox(PP::ibox0, [&]() {
4910 ps <<
"@(" <<
PPExtString(stringifyEventControl(op.getEvent()))
4912 emitExpression(op.getClock(), ops);
4913 ps <<
")" << PP::space;
4914 emitExpression(op.getProperty(), ops);
4917 emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops,
4922 ps.addCallback({op,
false});
4923 emitLocationInfoAndNewLine(ops);
4927 LogicalResult StmtEmitter::visitSV(AssertConcurrentOp op) {
4928 return emitConcurrentAssertion(op,
PPExtString(
"assert"));
4931 LogicalResult StmtEmitter::visitSV(AssumeConcurrentOp op) {
4932 return emitConcurrentAssertion(op,
PPExtString(
"assume"));
4935 LogicalResult StmtEmitter::visitSV(CoverConcurrentOp op) {
4936 return emitConcurrentAssertion(op,
PPExtString(
"cover"));
4941 template <
typename Op>
4942 LogicalResult StmtEmitter::emitPropertyAssertion(Op op,
PPExtString opName) {
4944 emitError(op,
"SV attributes emission is unimplemented for the op");
4954 Operation *parent = op->getParentOp();
4955 Value
property = op.getProperty();
4956 bool isTemporal = !
property.getType().isSignlessInteger(1);
4957 bool isProcedural = parent->hasTrait<ProceduralRegion>();
4958 bool emitAsImmediate = !isTemporal && isProcedural;
4961 SmallPtrSet<Operation *, 8> ops;
4963 ps.addCallback({op,
true});
4964 ps.scopedBox(PP::ibox2, [&]() {
4966 emitAssertionLabel(op);
4968 ps.scopedBox(PP::cbox0, [&]() {
4969 if (emitAsImmediate)
4970 ps << opName <<
"(";
4972 ps << opName << PP::nbsp <<
"property" << PP::nbsp <<
"(";
4974 Value clock = op.getClock();
4975 auto event = op.getEvent();
4977 ps.scopedBox(PP::ibox2, [&]() {
4978 PropertyEmitter(emitter, ops)
4979 .emitAssertPropertyBody(property, *event, clock, op.getDisable());
4982 ps.scopedBox(PP::ibox2, [&]() {
4983 PropertyEmitter(emitter, ops)
4984 .emitAssertPropertyBody(property, op.getDisable());
4989 ps.addCallback({op,
false});
4990 emitLocationInfoAndNewLine(ops);
4994 LogicalResult StmtEmitter::visitSV(AssertPropertyOp op) {
4995 return emitPropertyAssertion(op,
PPExtString(
"assert"));
4998 LogicalResult StmtEmitter::visitSV(AssumePropertyOp op) {
4999 return emitPropertyAssertion(op,
PPExtString(
"assume"));
5002 LogicalResult StmtEmitter::visitSV(CoverPropertyOp op) {
5003 return emitPropertyAssertion(op,
PPExtString(
"cover"));
5006 LogicalResult StmtEmitter::emitIfDef(Operation *op, MacroIdentAttr cond) {
5008 emitError(op,
"SV attributes emission is unimplemented for the op");
5013 bool hasEmptyThen = op->getRegion(0).front().empty();
5015 ps <<
"`ifndef " << ident;
5017 ps <<
"`ifdef " << ident;
5019 SmallPtrSet<Operation *, 8> ops;
5021 emitLocationInfoAndNewLine(ops);
5024 emitStatementBlock(op->getRegion(0).front());
5026 if (!op->getRegion(1).empty()) {
5027 if (!hasEmptyThen) {
5029 ps <<
"`else // " << ident;
5030 setPendingNewline();
5032 emitStatementBlock(op->getRegion(1).front());
5039 setPendingNewline();
5047 void StmtEmitter::emitBlockAsStatement(
5048 Block *block,
const SmallPtrSetImpl<Operation *> &locationOps,
5049 StringRef multiLineComment) {
5056 emitLocationInfoAndNewLine(locationOps);
5059 emitStatementBlock(*block);
5061 if (needsBeginEnd) {
5065 if (!multiLineComment.empty())
5066 ps <<
" // " << multiLineComment;
5067 setPendingNewline();
5071 LogicalResult StmtEmitter::visitSV(OrderedOutputOp ooop) {
5073 for (
auto &op : ooop.getBody().front())
5078 LogicalResult StmtEmitter::visitSV(IfOp op) {
5079 SmallPtrSet<Operation *, 8> ops;
5081 auto ifcondBox = PP::ibox2;
5083 emitSVAttributes(op);
5085 ps.addCallback({op,
true});
5086 ps <<
"if (" << ifcondBox;
5096 emitExpression(ifOp.getCond(), ops);
5097 ps << PP::end <<
")";
5098 emitBlockAsStatement(ifOp.getThenBlock(), ops);
5100 if (!ifOp.hasElse())
5104 Block *elseBlock = ifOp.getElseBlock();
5106 if (!nestedElseIfOp) {
5111 emitBlockAsStatement(elseBlock, ops);
5117 ifOp = nestedElseIfOp;
5118 ps <<
"else if (" << ifcondBox;
5120 ps.addCallback({op,
false});
5125 LogicalResult StmtEmitter::visitSV(AlwaysOp op) {
5126 emitSVAttributes(op);
5127 SmallPtrSet<Operation *, 8> ops;
5131 auto printEvent = [&](AlwaysOp::Condition cond) {
5132 ps <<
PPExtString(stringifyEventControl(cond.event)) << PP::nbsp;
5133 ps.scopedBox(PP::cbox0, [&]() { emitExpression(cond.value, ops); });
5135 ps.addCallback({op,
true});
5137 switch (op.getNumConditions()) {
5143 printEvent(op.getCondition(0));
5148 ps.scopedBox(PP::cbox0, [&]() {
5149 printEvent(op.getCondition(0));
5150 for (
size_t i = 1, e = op.getNumConditions(); i != e; ++i) {
5151 ps << PP::space <<
"or" << PP::space;
5152 printEvent(op.getCondition(i));
5161 std::string comment;
5162 if (op.getNumConditions() == 0) {
5163 comment =
"always @*";
5165 comment =
"always @(";
5168 [&](Attribute eventAttr) {
5169 auto event = sv::EventControl(cast<IntegerAttr>(eventAttr).getInt());
5170 comment += stringifyEventControl(event);
5172 [&]() { comment +=
", "; });
5176 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5177 ps.addCallback({op,
false});
5181 LogicalResult StmtEmitter::visitSV(AlwaysCombOp op) {
5182 emitSVAttributes(op);
5183 SmallPtrSet<Operation *, 8> ops;
5187 ps.addCallback({op,
true});
5188 StringRef opString =
"always_comb";
5189 if (state.options.noAlwaysComb)
5190 opString =
"always @(*)";
5193 emitBlockAsStatement(op.getBodyBlock(), ops, opString);
5194 ps.addCallback({op,
false});
5198 LogicalResult StmtEmitter::visitSV(AlwaysFFOp op) {
5199 emitSVAttributes(op);
5201 SmallPtrSet<Operation *, 8> ops;
5205 ps.addCallback({op,
true});
5206 ps <<
"always_ff @(";
5207 ps.scopedBox(PP::cbox0, [&]() {
5208 ps <<
PPExtString(stringifyEventControl(op.getClockEdge())) << PP::nbsp;
5209 emitExpression(op.getClock(), ops);
5210 if (op.getResetStyle() == ResetType::AsyncReset) {
5211 ps << PP::nbsp <<
"or" << PP::space
5212 <<
PPExtString(stringifyEventControl(*op.getResetEdge())) << PP::nbsp;
5213 emitExpression(op.getReset(), ops);
5220 std::string comment;
5221 comment +=
"always_ff @(";
5222 comment += stringifyEventControl(op.getClockEdge());
5223 if (op.getResetStyle() == ResetType::AsyncReset) {
5225 comment += stringifyEventControl(*op.getResetEdge());
5229 if (op.getResetStyle() == ResetType::NoReset)
5230 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5233 emitLocationInfoAndNewLine(ops);
5234 ps.scopedBox(PP::bbox2, [&]() {
5240 if (op.getResetStyle() == ResetType::AsyncReset &&
5241 *op.getResetEdge() == sv::EventControl::AtNegEdge)
5243 emitExpression(op.getReset(), ops);
5245 emitBlockAsStatement(op.getResetBlock(), ops);
5248 emitBlockAsStatement(op.getBodyBlock(), ops);
5253 ps <<
" // " << comment;
5254 setPendingNewline();
5256 ps.addCallback({op,
false});
5260 LogicalResult StmtEmitter::visitSV(InitialOp op) {
5261 emitSVAttributes(op);
5262 SmallPtrSet<Operation *, 8> ops;
5265 ps.addCallback({op,
true});
5267 emitBlockAsStatement(op.getBodyBlock(), ops,
"initial");
5268 ps.addCallback({op,
false});
5272 LogicalResult StmtEmitter::visitSV(CaseOp op) {
5273 emitSVAttributes(op);
5274 SmallPtrSet<Operation *, 8> ops, emptyOps;
5277 ps.addCallback({op,
true});
5278 if (op.getValidationQualifier() !=
5279 ValidationQualifierTypeEnum::ValidationQualifierPlain)
5280 ps <<
PPExtString(circt::sv::stringifyValidationQualifierTypeEnum(
5281 op.getValidationQualifier()))
5283 const char *opname =
nullptr;
5284 switch (op.getCaseStyle()) {
5285 case CaseStmtType::CaseStmt:
5288 case CaseStmtType::CaseXStmt:
5291 case CaseStmtType::CaseZStmt:
5295 ps << opname <<
" (";
5296 ps.scopedBox(PP::ibox0, [&]() {
5297 emitExpression(op.getCond(), ops);
5300 emitLocationInfoAndNewLine(ops);
5302 ps.scopedBox(PP::bbox2, [&]() {
5303 for (
auto &caseInfo : op.getCases()) {
5305 auto &pattern = caseInfo.pattern;
5307 llvm::TypeSwitch<CasePattern *>(pattern.get())
5308 .Case<CaseBitPattern>([&](auto bitPattern) {
5311 ps.invokeWithStringOS([&](auto &os) {
5312 os << bitPattern->getWidth() <<
"'b";
5313 for (size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
5314 os << getLetter(bitPattern->getBit(e - bit - 1));
5317 .Case<CaseEnumPattern>([&](
auto enumPattern) {
5318 ps <<
PPExtString(emitter.fieldNameResolver.getEnumFieldName(
5319 cast<hw::EnumFieldAttr>(enumPattern->attr())));
5321 .Case<CaseDefaultPattern>([&](
auto) { ps <<
"default"; })
5322 .Default([&](
auto) {
assert(
false &&
"unhandled case pattern"); });
5325 emitBlockAsStatement(caseInfo.block, emptyOps);
5331 ps.addCallback({op,
false});
5332 emitLocationInfoAndNewLine(ops);
5336 LogicalResult StmtEmitter::visitStmt(InstanceOp op) {
5337 bool doNotPrint = op->hasAttr(
"doNotPrint");
5338 if (doNotPrint && !state.options.emitBindComments)
5343 emitSVAttributes(op);
5345 ps.addCallback({op,
true});
5348 <<
"/* This instance is elsewhere emitted as a bind statement."
5351 op->emitWarning() <<
"is emitted as a bind statement but has SV "
5352 "attributes. The attributes will not be emitted.";
5355 SmallPtrSet<Operation *, 8> ops;
5360 state.symbolCache.getDefinition(op.getReferencedModuleNameAttr());
5361 assert(moduleOp &&
"Invalid IR");
5365 if (!op.getParameters().empty()) {
5368 bool printed =
false;
5370 llvm::zip(op.getParameters(),
5371 moduleOp->getAttrOfType<ArrayAttr>(
"parameters"))) {
5372 auto param = cast<ParamDeclAttr>(std::get<0>(params));
5373 auto modParam = cast<ParamDeclAttr>(std::get<1>(params));
5375 if (param.getValue() == modParam.getValue())
5380 ps <<
" #(" << PP::bbox2 << PP::newline;
5383 ps <<
"," << PP::newline;
5387 state.globalNames.getParameterVerilogName(moduleOp, param.getName()));
5389 ps.invokeWithStringOS([&](
auto &os) {
5390 emitter.printParamValue(param.getValue(), os, [&]() {
5391 return op->emitOpError(
"invalid instance parameter '")
5392 << param.getName().getValue() <<
"' value";
5398 ps << PP::end << PP::newline <<
")";
5405 SmallVector<Value> instPortValues(modPortInfo.size());
5406 op.getValues(instPortValues, modPortInfo);
5407 emitInstancePortList(op, modPortInfo, instPortValues);
5409 ps.addCallback({op,
false});
5410 emitLocationInfoAndNewLine(ops);
5415 setPendingNewline();
5420 LogicalResult StmtEmitter::visitStmt(InstanceChoiceOp op) {
5422 Operation *choiceMacroDeclOp = state.symbolCache.getDefinition(
5423 op->getAttrOfType<FlatSymbolRefAttr>(
"hw.choiceTarget"));
5428 Operation *defaultModuleOp =
5429 state.symbolCache.getDefinition(op.getDefaultModuleNameAttr());
5431 SmallVector<Value> instPortValues(modPortInfo.size());
5432 op.getValues(instPortValues, modPortInfo);
5433 emitInstancePortList(op, modPortInfo, instPortValues);
5435 SmallPtrSet<Operation *, 8> ops;
5437 ps.addCallback({op,
false});
5438 emitLocationInfoAndNewLine(ops);
5443 void StmtEmitter::emitInstancePortList(Operation *op,
5445 ArrayRef<Value> instPortValues) {
5446 SmallPtrSet<Operation *, 8> ops;
5449 auto containingModule = cast<HWModuleOp>(emitter.currentModuleOp);
5450 ModulePortInfo containingPortList(containingModule.getPortList());
5455 size_t maxNameLength = 0;
5456 for (
auto &elt : modPortInfo) {
5457 maxNameLength = std::max(maxNameLength, elt.getVerilogName().size());
5460 auto getWireForValue = [&](Value result) {
5461 return result.getUsers().begin()->getOperand(0);
5465 bool isFirst =
true;
5466 bool isZeroWidth =
false;
5468 for (
size_t portNum = 0, portEnd = modPortInfo.size(); portNum < portEnd;
5470 auto &modPort = modPortInfo.at(portNum);
5472 Value portVal = instPortValues[portNum];
5477 bool shouldPrintComma =
true;
5479 shouldPrintComma =
false;
5480 for (
size_t i = portNum + 1, e = modPortInfo.size(); i != e; ++i)
5482 shouldPrintComma =
true;
5487 if (shouldPrintComma)
5490 emitLocationInfoAndNewLine(ops);
5505 ps.scopedBox(isZeroWidth ? PP::neverbox : PP::ibox2, [&]() {
5506 auto modPortName = modPort.getVerilogName();
5508 ps.spaces(maxNameLength - modPortName.size() + 1);
5510 ps.scopedBox(PP::ibox0, [&]() {
5517 if (!modPort.isOutput()) {
5519 isa_and_nonnull<ConstantOp>(portVal.getDefiningOp()))
5520 ps <<
"/* Zero width */";
5522 emitExpression(portVal, ops, LowestPrecedence);
5523 }
else if (portVal.use_empty()) {
5524 ps <<
"/* unused */";
5525 }
else if (portVal.hasOneUse() &&
5526 (output = dyn_cast_or_null<OutputOp>(
5527 portVal.getUses().begin()->getOwner()))) {
5532 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
5534 containingPortList.atOutput(outputPortNo).getVerilogName());
5536 portVal = getWireForValue(portVal);
5537 emitExpression(portVal, ops);
5543 if (!isFirst || isZeroWidth) {
5544 emitLocationInfoAndNewLine(ops);
5557 LogicalResult StmtEmitter::visitSV(BindOp op) {
5558 emitter.emitBind(op);
5559 assert(state.pendingNewline);
5563 LogicalResult StmtEmitter::visitSV(InterfaceOp op) {
5564 emitComment(op.getCommentAttr());
5566 emitSVAttributes(op);
5569 ps.addCallback({op,
true});
5571 setPendingNewline();
5573 emitStatementBlock(*op.getBodyBlock());
5575 ps <<
"endinterface" << PP::newline;
5576 ps.addCallback({op,
false});
5577 setPendingNewline();
5581 LogicalResult StmtEmitter::visitSV(InterfaceSignalOp op) {
5583 emitSVAttributes(op);
5585 ps.addCallback({op,
true});
5587 ps << PP::neverbox <<
"// ";
5588 ps.invokeWithStringOS([&](
auto &os) {
5593 ps.invokeWithStringOS(
5594 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
5598 ps.addCallback({op,
false});
5599 setPendingNewline();
5603 LogicalResult StmtEmitter::visitSV(InterfaceModportOp op) {
5605 ps.addCallback({op,
true});
5609 llvm::interleaveComma(op.getPorts(), ps, [&](
const Attribute &portAttr) {
5610 auto port = cast<ModportStructAttr>(portAttr);
5611 ps << PPExtString(stringifyEnum(port.getDirection().getValue())) <<
" ";
5612 auto *signalDecl = state.symbolCache.getDefinition(port.getSignal());
5613 ps << PPExtString(getSymOpName(signalDecl));
5617 ps.addCallback({op,
false});
5618 setPendingNewline();
5622 LogicalResult StmtEmitter::visitSV(AssignInterfaceSignalOp op) {
5624 ps.addCallback({op,
true});
5625 SmallPtrSet<Operation *, 8> emitted;
5628 emitExpression(op.getIface(), emitted);
5629 ps <<
"." <<
PPExtString(op.getSignalName()) <<
" = ";
5630 emitExpression(op.getRhs(), emitted);
5632 ps.addCallback({op,
false});
5633 setPendingNewline();
5637 LogicalResult StmtEmitter::visitSV(MacroDefOp op) {
5638 auto decl = op.getReferencedMacro(&state.symbolCache);
5641 ps.addCallback({op,
true});
5643 if (decl.getArgs()) {
5645 llvm::interleaveComma(*decl.getArgs(), ps, [&](
const Attribute &name) {
5646 ps << cast<StringAttr>(name);
5650 if (!op.getFormatString().empty()) {
5652 emitTextWithSubstitutions(ps, op.getFormatString(), op, {},
5655 ps.addCallback({op,
false});
5656 setPendingNewline();
5660 void StmtEmitter::emitStatement(Operation *op) {
5667 if (isa<ltl::LTLDialect, debug::DebugDialect>(op->getDialect()))
5671 if (succeeded(dispatchStmtVisitor(op)) || succeeded(dispatchSVVisitor(op)) ||
5672 succeeded(dispatchVerifVisitor(op)))
5675 emitOpError(op,
"emission to Verilog not supported");
5676 emitPendingNewlineIfNeeded();
5677 ps <<
"unknown MLIR operation " <<
PPExtString(op->getName().getStringRef());
5678 setPendingNewline();
5689 StmtEmitter &stmtEmitter) {
5696 if (isa<IfDefProceduralOp>(op->getParentOp()))
5704 SmallVector<Value, 8> exprsToScan(op->getOperands());
5709 while (!exprsToScan.empty()) {
5710 Operation *expr = exprsToScan.pop_back_val().getDefiningOp();
5717 if (
auto readInout = dyn_cast<sv::ReadInOutOp>(expr)) {
5718 auto *defOp = readInout.getOperand().getDefiningOp();
5725 if (isa<sv::WireOp>(defOp))
5730 if (!isa<RegOp, LogicOp>(defOp))
5736 if (isa<LogicOp>(defOp) &&
5737 stmtEmitter.emitter.expressionsEmittedIntoDecl.count(defOp))
5741 if (llvm::all_of(defOp->getResult(0).getUsers(), [&](Operation *op) {
5742 return isa<ReadInOutOp, PAssignOp, AssignOp>(op);
5750 exprsToScan.append(expr->getOperands().begin(),
5751 expr->getOperands().end());
5757 if (expr->getBlock() != op->getBlock())
5762 if (!stmtEmitter.emitter.expressionsEmittedIntoDecl.count(expr))
5769 template <
class AssignTy>
5771 AssignTy singleAssign;
5772 if (llvm::all_of(op->getUsers(), [&](Operation *user) {
5773 if (hasSVAttributes(user))
5776 if (auto assign = dyn_cast<AssignTy>(user)) {
5779 singleAssign = assign;
5783 return isa<ReadInOutOp>(user);
5785 return singleAssign;
5791 return llvm::all_of(op2->getUsers(), [&](Operation *user) {
5795 if (op1->getBlock() != user->getBlock())
5801 return op1->isBeforeInBlock(user);
5805 LogicalResult StmtEmitter::emitDeclaration(Operation *op) {
5806 emitSVAttributes(op);
5807 auto value = op->getResult(0);
5808 SmallPtrSet<Operation *, 8> opsForLocation;
5809 opsForLocation.insert(op);
5811 ps.addCallback({op,
true});
5814 auto type = value.getType();
5817 ps.scopedBox(isZeroBit ? PP::neverbox : PP::ibox2, [&]() {
5818 unsigned targetColumn = 0;
5819 unsigned column = 0;
5822 if (maxDeclNameWidth > 0)
5823 targetColumn += maxDeclNameWidth + 1;
5826 ps <<
"// Zero width: " <<
PPExtString(word) << PP::space;
5827 }
else if (!word.empty()) {
5829 column += word.size();
5830 unsigned numSpaces = targetColumn > column ? targetColumn - column : 1;
5831 ps.spaces(numSpaces);
5832 column += numSpaces;
5835 SmallString<8> typeString;
5838 llvm::raw_svector_ostream stringStream(typeString);
5843 if (maxTypeWidth > 0)
5844 targetColumn += maxTypeWidth + 1;
5845 unsigned numSpaces = 0;
5846 if (!typeString.empty()) {
5848 column += typeString.size();
5851 if (targetColumn > column)
5852 numSpaces = targetColumn - column;
5853 ps.spaces(numSpaces);
5854 column += numSpaces;
5860 ps.invokeWithStringOS(
5861 [&](
auto &os) { emitter.printUnpackedTypePostfix(type, os); });
5864 if (state.options.printDebugInfo) {
5865 if (
auto innerSymOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
5866 auto innerSym = innerSymOp.getInnerSymAttr();
5867 if (innerSym && !innerSym.empty()) {
5869 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
5875 if (
auto localparam = dyn_cast<LocalParamOp>(op)) {
5876 ps << PP::space <<
"=" << PP::space;
5877 ps.invokeWithStringOS([&](
auto &os) {
5878 emitter.printParamValue(localparam.getValue(), os, [&]() {
5879 return op->emitOpError(
"invalid localparam value");
5884 if (
auto regOp = dyn_cast<RegOp>(op)) {
5885 if (
auto initValue = regOp.getInit()) {
5886 ps << PP::space <<
"=" << PP::space;
5887 ps.scopedBox(PP::ibox0, [&]() {
5888 emitExpression(initValue, opsForLocation, LowestPrecedence,
5897 if (isa<sv::WireOp, LogicOp>(op) &&
5898 !op->getParentOp()->hasTrait<ProceduralRegion>() &&
5901 if (
auto singleAssign = getSingleAssignAndCheckUsers<AssignOp>(op)) {
5902 auto *source = singleAssign.getSrc().getDefiningOp();
5906 if (!source || isa<ConstantOp>(source) ||
5907 op->getNextNode() == singleAssign) {
5908 ps << PP::space <<
"=" << PP::space;
5909 ps.scopedBox(PP::ibox0, [&]() {
5910 emitExpression(singleAssign.getSrc(), opsForLocation,
5914 emitter.assignsInlined.insert(singleAssign);
5922 if (isa<LogicOp>(op) && op->getParentOp()->hasTrait<ProceduralRegion>() &&
5925 if (
auto singleAssign = getSingleAssignAndCheckUsers<BPAssignOp>(op)) {
5928 auto *source = singleAssign.getSrc().getDefiningOp();
5932 if (!source || isa<ConstantOp>(source) ||
5935 ps << PP::space <<
"=" << PP::space;
5936 ps.scopedBox(PP::ibox0, [&]() {
5937 emitExpression(singleAssign.getSrc(), opsForLocation,
5942 emitter.assignsInlined.insert(singleAssign);
5943 emitter.expressionsEmittedIntoDecl.insert(op);
5950 ps.addCallback({op,
false});
5951 emitLocationInfoAndNewLine(opsForLocation);
5955 void StmtEmitter::collectNamesAndCalculateDeclarationWidths(Block &block) {
5958 NameCollector collector(emitter);
5959 collector.collectNames(block);
5962 maxDeclNameWidth = collector.getMaxDeclNameWidth();
5963 maxTypeWidth = collector.getMaxTypeWidth();
5966 void StmtEmitter::emitStatementBlock(Block &body) {
5967 ps.scopedBox(PP::bbox2, [&]() {
5972 llvm::SaveAndRestore<size_t> x(maxDeclNameWidth);
5973 llvm::SaveAndRestore<size_t> x2(maxTypeWidth);
5978 if (!isa<IfDefProceduralOp>(body.getParentOp()))
5979 collectNamesAndCalculateDeclarationWidths(body);
5982 for (
auto &op : body) {
5989 void ModuleEmitter::emitStatement(Operation *op) {
5990 StmtEmitter(*
this, state.options).emitStatement(op);
5995 void ModuleEmitter::emitSVAttributes(Operation *op) {
6003 setPendingNewline();
6010 void ModuleEmitter::emitHWGeneratedModule(HWModuleGeneratedOp module) {
6011 auto verilogName = module.getVerilogModuleNameAttr();
6013 ps <<
"// external generated module " <<
PPExtString(verilogName.getValue())
6015 setPendingNewline();
6024 void ModuleEmitter::emitBind(BindOp op) {
6026 emitError(op,
"SV attributes emission is unimplemented for the op");
6027 InstanceOp inst = op.getReferencedInstance(&state.symbolCache);
6033 Operation *childMod =
6034 state.symbolCache.getDefinition(inst.getReferencedModuleNameAttr());
6038 ps.addCallback({op,
true});
6039 ps <<
"bind " <<
PPExtString(parentVerilogName.getValue()) << PP::nbsp
6040 <<
PPExtString(childVerilogName.getValue()) << PP::nbsp
6042 bool isFirst =
true;
6043 ps.scopedBox(PP::bbox2, [&]() {
6044 auto parentPortInfo = parentMod.getPortList();
6048 size_t maxNameLength = 0;
6049 for (
auto &elt : childPortInfo) {
6050 auto portName = elt.getVerilogName();
6051 elt.name = Builder(inst.getContext()).getStringAttr(portName);
6052 maxNameLength = std::max(maxNameLength, elt.getName().size());
6055 SmallVector<Value> instPortValues(childPortInfo.size());
6056 inst.getValues(instPortValues, childPortInfo);
6058 for (
auto [idx, elt] : llvm::enumerate(childPortInfo)) {
6060 Value portVal = instPortValues[idx];
6066 bool shouldPrintComma =
true;
6068 shouldPrintComma =
false;
6069 for (
size_t i = idx + 1, e = childPortInfo.size(); i != e; ++i)
6071 shouldPrintComma =
true;
6076 if (shouldPrintComma)
6089 ps << PP::neverbox <<
"//";
6093 ps.nbsp(maxNameLength - elt.getName().size());
6095 llvm::SmallPtrSet<Operation *, 4> ops;
6096 if (elt.isOutput()) {
6097 assert((portVal.hasOneUse() || portVal.use_empty()) &&
6098 "output port must have either single or no use");
6099 if (portVal.use_empty()) {
6100 ps <<
"/* unused */";
6101 }
else if (
auto output = dyn_cast_or_null<OutputOp>(
6102 portVal.getUses().begin()->getOwner())) {
6105 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
6107 parentPortList.atOutput(outputPortNo).getVerilogName());
6109 portVal = portVal.getUsers().begin()->getOperand(0);
6110 ExprEmitter(*
this, ops)
6111 .emitExpression(portVal, LowestPrecedence,
6115 ExprEmitter(*
this, ops)
6116 .emitExpression(portVal, LowestPrecedence,
6129 ps.addCallback({op,
false});
6130 setPendingNewline();
6133 void ModuleEmitter::emitBindInterface(BindInterfaceOp op) {
6135 emitError(op,
"SV attributes emission is unimplemented for the op");
6137 auto instance = op.getReferencedInstance(&state.symbolCache);
6139 auto *
interface = op->getParentOfType<ModuleOp>().lookupSymbol(
6140 instance.getInterfaceType().getInterface());
6142 ps.addCallback({op,
true});
6143 ps <<
"bind " <<
PPExtString(instantiator) << PP::nbsp
6144 <<
PPExtString(cast<InterfaceOp>(*interface).getSymName()) << PP::nbsp
6146 ps.addCallback({op,
false});
6147 setPendingNewline();
6150 void ModuleEmitter::emitParameters(Operation *module, ArrayAttr params) {
6154 auto printParamType = [&](Type type, Attribute defaultValue,
6155 SmallString<8> &result) {
6157 llvm::raw_svector_ostream sstream(result);
6162 if (
auto intAttr = dyn_cast<IntegerAttr>(defaultValue))
6163 if (intAttr.getValue().getBitWidth() == 32)
6165 if (
auto fpAttr = dyn_cast<FloatAttr>(defaultValue))
6166 if (fpAttr.getType().isF64())
6169 if (isa<NoneType>(type))
6176 if (
auto intType = type_dyn_cast<IntegerType>(type))
6177 if (intType.getWidth() == 32) {
6178 sstream <<
"/*integer*/";
6182 printPackedType(type, sstream, module->getLoc(),
6190 size_t maxTypeWidth = 0;
6191 SmallString<8> scratch;
6192 for (
auto param : params) {
6193 auto paramAttr = cast<ParamDeclAttr>(param);
6195 printParamType(paramAttr.getType(), paramAttr.getValue(), scratch);
6196 maxTypeWidth = std::max(scratch.size(), maxTypeWidth);
6199 if (maxTypeWidth > 0)
6202 ps.scopedBox(PP::bbox2, [&]() {
6203 ps << PP::newline <<
"#(";
6204 ps.scopedBox(PP::cbox0, [&]() {
6207 [&](Attribute param) {
6208 auto paramAttr = cast<ParamDeclAttr>(param);
6209 auto defaultValue = paramAttr.getValue();
6211 printParamType(paramAttr.getType(), defaultValue, scratch);
6212 if (!scratch.empty())
6214 if (scratch.size() < maxTypeWidth)
6215 ps.nbsp(maxTypeWidth - scratch.size());
6217 ps <<
PPExtString(state.globalNames.getParameterVerilogName(
6218 module, paramAttr.getName()));
6222 ps.invokeWithStringOS([&](
auto &os) {
6224 return module->emitError(
"parameter '")
6225 << paramAttr.getName().getValue()
6226 <<
"' has invalid value";
6231 [&]() { ps <<
"," << PP::newline; });
6237 void ModuleEmitter::emitPortList(Operation *module,
6239 bool emitAsTwoStateType) {
6241 if (portInfo.
size())
6242 emitLocationInfo(module->getLoc());
6246 bool hasOutputs =
false, hasZeroWidth =
false;
6247 size_t maxTypeWidth = 0, lastNonZeroPort = -1;
6248 SmallVector<SmallString<8>, 16> portTypeStrings;
6250 for (
size_t i = 0, e = portInfo.
size(); i < e; ++i) {
6251 auto port = portInfo.
at(i);
6255 lastNonZeroPort = i;
6258 portTypeStrings.push_back({});
6260 llvm::raw_svector_ostream stringStream(portTypeStrings.back());
6262 module->getLoc(), {},
true,
true, emitAsTwoStateType);
6265 maxTypeWidth = std::max(portTypeStrings.back().size(), maxTypeWidth);
6268 if (maxTypeWidth > 0)
6272 ps.scopedBox(PP::bbox2, [&]() {
6273 for (
size_t portIdx = 0, e = portInfo.
size(); portIdx != e;) {
6274 auto lastPort = e - 1;
6277 auto portType = portInfo.at(portIdx).type;
6281 bool isZeroWidth = false;
6283 isZeroWidth = isZeroBitType(portType);
6286 ps << (isZeroWidth ?
"// " :
" ");
6290 auto thisPortDirection = portInfo.
at(portIdx).
dir;
6291 switch (thisPortDirection) {
6296 ps << (hasOutputs ?
"input " :
"input ");
6299 ps << (hasOutputs ?
"inout " :
"inout ");
6302 bool emitWireInPorts = state.options.emitWireInPorts;
6303 if (emitWireInPorts)
6307 if (!portTypeStrings[portIdx].
empty())
6308 ps << portTypeStrings[portIdx];
6309 if (portTypeStrings[portIdx].size() < maxTypeWidth)
6310 ps.nbsp(maxTypeWidth - portTypeStrings[portIdx].size());
6312 size_t startOfNamePos =
6313 (hasOutputs ? 7 : 6) + (emitWireInPorts ? 5 : 0) + maxTypeWidth;
6319 ps.invokeWithStringOS(
6320 [&](
auto &os) { printUnpackedTypePostfix(portType, os); });
6323 auto innerSym = portInfo.
at(portIdx).
getSym();
6324 if (state.options.printDebugInfo && innerSym && !innerSym.empty()) {
6326 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
6331 if (portIdx != lastNonZeroPort && portIdx != lastPort)
6335 if (
auto loc = portInfo.
at(portIdx).
loc)
6336 emitLocationInfo(loc);
6346 if (!state.options.disallowPortDeclSharing) {
6347 while (portIdx != e && portInfo.
at(portIdx).
dir == thisPortDirection &&
6350 auto port = portInfo.
at(portIdx);
6354 bool isZeroWidth =
false;
6359 ps << (isZeroWidth ?
"// " :
" ");
6362 ps.nbsp(startOfNamePos);
6365 StringRef name = port.getVerilogName();
6369 ps.invokeWithStringOS(
6370 [&](
auto &os) { printUnpackedTypePostfix(port.type, os); });
6373 auto sym = port.getSym();
6374 if (state.options.printDebugInfo && sym && !sym.empty())
6375 ps <<
" /* inner_sym: " <<
PPExtString(sym.getSymName().getValue())
6379 if (portIdx != lastNonZeroPort && portIdx != lastPort)
6383 if (
auto loc = port.loc)
6384 emitLocationInfo(loc);
6395 if (!portInfo.
size()) {
6397 SmallPtrSet<Operation *, 8> moduleOpSet;
6398 moduleOpSet.insert(module);
6399 emitLocationInfoAndNewLine(moduleOpSet);
6402 ps <<
");" << PP::newline;
6403 setPendingNewline();
6407 void ModuleEmitter::emitHWModule(
HWModuleOp module) {
6408 currentModuleOp = module;
6410 emitComment(module.getCommentAttr());
6411 emitSVAttributes(module);
6413 ps.addCallback({module,
true});
6417 emitParameters(module, module.getParameters());
6421 assert(state.pendingNewline);
6424 StmtEmitter(*
this, state.options).emitStatementBlock(*module.getBodyBlock());
6427 ps.addCallback({module,
false});
6429 setPendingNewline();
6431 currentModuleOp =
nullptr;
6434 void ModuleEmitter::emitFunc(FuncOp func) {
6436 if (func.isDeclaration())
6439 currentModuleOp = func;
6441 ps.addCallback({func,
true});
6445 StmtEmitter(*
this, state.options).emitStatementBlock(*func.getBodyBlock());
6447 ps <<
"endfunction";
6449 currentModuleOp =
nullptr;
6458 explicit FileEmitter(VerilogEmitterState &state) : EmitterBase(state) {}
6465 void emit(emit::FileListOp op);
6468 void emit(Block *block);
6470 void emitOp(emit::RefOp op);
6471 void emitOp(emit::VerbatimOp op);
6475 for (Operation &op : *block) {
6476 TypeSwitch<Operation *>(&op)
6477 .Case<emit::VerbatimOp, emit::RefOp>([&](
auto op) { emitOp(op); })
6478 .Case<VerbatimOp, IfDefOp, MacroDefOp, sv::FuncDPIImportOp>(
6479 [&](
auto op) { ModuleEmitter(state).emitStatement(op); })
6480 .Case<BindOp>([&](
auto op) { ModuleEmitter(state).emitBind(op); })
6481 .Case<BindInterfaceOp>(
6482 [&](
auto op) { ModuleEmitter(state).emitBindInterface(op); })
6483 .Case<TypeScopeOp>([&](
auto typedecls) {
6484 ModuleEmitter(state).emitStatement(typedecls);
6487 [&](
auto op) { emitOpError(op,
"cannot be emitted to a file"); });
6493 for (
auto sym : op.getFiles()) {
6494 auto fileName = cast<FlatSymbolRefAttr>(sym).getAttr();
6496 auto it = state.fileMapping.find(fileName);
6497 if (it == state.fileMapping.end()) {
6498 emitOpError(op,
" references an invalid file: ") << sym;
6502 auto file = cast<emit::FileOp>(it->second);
6503 ps << PP::neverbox <<
PPExtString(file.getFileName()) << PP::end
6510 StringAttr target = op.getTargetAttr().getAttr();
6511 auto *targetOp = state.symbolCache.getDefinition(target);
6512 assert(isa<emit::Emittable>(targetOp) &&
"target must be emittable");
6514 TypeSwitch<Operation *>(targetOp)
6515 .Case<sv::FuncOp>([&](
auto func) { ModuleEmitter(state).emitFunc(func); })
6516 .Case<hw::HWModuleOp>(
6517 [&](
auto module) { ModuleEmitter(state).emitHWModule(module); })
6518 .Case<TypeScopeOp>([&](
auto typedecls) {
6519 ModuleEmitter(state).emitStatement(typedecls);
6522 [&](
auto op) { emitOpError(op,
"cannot be emitted to a file"); });
6528 SmallPtrSet<Operation *, 8> ops;
6533 StringRef text = op.getText();
6537 const auto &[lhs, rhs] = text.split(
'\n');
6541 ps << PP::end << PP::newline << PP::neverbox;
6543 }
while (!text.empty());
6546 emitLocationInfoAndNewLine(ops);
6557 void SharedEmitterState::gatherFiles(
bool separateModules) {
6564 auto collectInstanceSymbolsAndBinds = [&](Operation *moduleOp) {
6565 moduleOp->walk([&](Operation *op) {
6567 if (
auto name = op->getAttrOfType<InnerSymAttr>(
6570 SymbolTable::getSymbolAttrName()),
6571 name.getSymName(), op);
6572 if (isa<BindOp>(op))
6578 auto collectPorts = [&](
auto moduleOp) {
6579 auto portInfo = moduleOp.getPortList();
6580 for (
auto [i, p] : llvm::enumerate(portInfo)) {
6581 if (!p.attrs || p.attrs.empty())
6583 for (NamedAttribute portAttr : p.attrs) {
6584 if (
auto sym = dyn_cast<InnerSymAttr>(portAttr.getValue())) {
6593 DenseMap<StringAttr, SmallVector<emit::FileOp>> symbolsToFiles;
6594 for (
auto file :
designOp.getOps<emit::FileOp>())
6595 for (
auto refs : file.getOps<emit::RefOp>())
6596 symbolsToFiles[refs.getTargetAttr().getAttr()].push_back(file);
6598 SmallString<32> outputPath;
6599 for (
auto &op : *
designOp.getBody()) {
6602 bool isFileOp = isa<emit::FileOp, emit::FileListOp>(&op);
6604 bool hasFileName =
false;
6605 bool emitReplicatedOps = !isFileOp;
6606 bool addToFilelist = !isFileOp;
6612 auto attr = op.getAttrOfType<hw::OutputFileAttr>(
"output_file");
6614 LLVM_DEBUG(llvm::dbgs() <<
"Found output_file attribute " << attr
6615 <<
" on " << op <<
"\n";);
6616 if (!attr.isDirectory())
6619 emitReplicatedOps = attr.getIncludeReplicatedOps().getValue();
6620 addToFilelist = !attr.getExcludeFromFilelist().getValue();
6623 auto separateFile = [&](Operation *op, Twine defaultFileName =
"") {
6628 if (!defaultFileName.isTriviallyEmpty()) {
6631 op->emitError(
"file name unspecified");
6638 auto &file =
files[destFile];
6639 file.ops.push_back(info);
6640 file.emitReplicatedOps = emitReplicatedOps;
6641 file.addToFilelist = addToFilelist;
6642 file.isVerilog = outputPath.ends_with(
".sv");
6647 TypeSwitch<Operation *>(&op)
6648 .Case<emit::FileOp, emit::FileListOp>([&](
auto file) {
6650 fileMapping.try_emplace(file.getSymNameAttr(), file);
6651 separateFile(file, file.getFileName());
6653 .Case<emit::FragmentOp>([&](
auto fragment) {
6656 .Case<HWModuleOp>([&](
auto mod) {
6658 auto sym = mod.getNameAttr();
6661 collectInstanceSymbolsAndBinds(mod);
6663 if (
auto it = symbolsToFiles.find(sym); it != symbolsToFiles.end()) {
6664 if (it->second.size() != 1 || attr) {
6667 op.emitError(
"modules can be emitted to a single file");
6675 if (attr || separateModules)
6681 .Case<InterfaceOp>([&](InterfaceOp intf) {
6686 for (
auto &op : *intf.getBodyBlock())
6687 if (
auto symOp = dyn_cast<mlir::SymbolOpInterface>(op))
6688 if (
auto name = symOp.getNameAttr())
6692 if (attr || separateModules)
6693 separateFile(intf, intf.getSymName() +
".sv");
6703 .Case<VerbatimOp, IfDefOp, MacroDefOp, FuncDPIImportOp>(
6704 [&](Operation *op) {
6710 separateFile(op,
"");
6712 .Case<FuncOp>([&](
auto op) {
6718 separateFile(op,
"");
6722 .Case<HWGeneratorSchemaOp>([&](HWGeneratorSchemaOp schemaOp) {
6725 .Case<HierPathOp>([&](HierPathOp hierPathOp) {
6734 separateFile(op,
"");
6736 .Case<BindOp>([&](
auto op) {
6738 separateFile(op,
"bindfile.sv");
6743 .Case<MacroDeclOp>([&](
auto op) {
6746 .Case<sv::ReserveNamesOp>([](
auto op) {
6749 .Case<om::ClassLike>([&](
auto op) {
6752 .Case<om::ConstantOp>([&](
auto op) {
6755 .Default([&](
auto *) {
6756 op.emitError(
"unknown operation (SharedEmitterState::gatherFiles)");
6776 size_t lastReplicatedOp = 0;
6778 bool emitHeaderInclude =
6781 if (emitHeaderInclude)
6784 size_t numReplicatedOps =