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"
68using namespace ExportVerilog;
70using namespace pretty;
72#define DEBUG_TYPE "export-verilog"
80enum VerilogPrecedence {
101enum 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);
126static 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(
"");
221template <
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))
261static 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))
322 return hw::getBitWidth(unionType) == 0;
334 return TypeSwitch<Type, Type>(type)
335 .Case<InOutType>([](InOutType inoutType) {
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; });
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();
398template <
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); });
465template <
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);
485 const SmallPtrSetImpl<Operation *> &ops) {
489 SmallPtrSet<Attribute, 8> locationSet;
492 llvm::raw_string_ostream os(
output);
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)
538 bool withName = !loc.getName().empty();
540 os <<
"'" << loc.getName().strref() <<
"'(";
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>(
612 .Case<mlir::FusedLoc>([&](
auto loc) {
613 SmallPtrSet<Attribute, 8> locationSet;
617 .Default([&](
auto loc) {
629 switch (locationSet.size()) {
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;
675 if (recheckEmittedSomething()) {
677 recheckEmittedSomething();
683 if (emittedAnything && !flcLocs.empty())
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)) {
914template <
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");
993class 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;
1082using 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;
1159template <
typename PPS>
1160void 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())
1292void 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());
1367 result = StringAttr::get(expr.getContext(), name);
1369 }
else if (
auto *op = expr.getDefiningOp()) {
1371 if (isa<sv::WireOp, RegOp, LogicOp>(op)) {
1373 result = StringAttr::get(expr.getContext(), name);
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) {
1388 result = StringAttr::get(verbatim.getContext(), name);
1391 .Case([&result](VerbatimExprSEOp verbatim) {
1392 verbatim.getAsmResultNames([&](Value, StringRef name) {
1393 result = StringAttr::get(verbatim.getContext(), name);
1399 if (
auto operandName =
1402 cast<IntegerType>(extract.getType()).getWidth();
1404 result = StringAttr::get(extract.getContext(),
1405 operandName.strref() +
"_" +
1406 Twine(extract.getLowBit()));
1408 result = StringAttr::get(
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() !=
'_')
1425 result = StringAttr::get(expr.getContext(),
"_" + result.strref());
1437class 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();
1543 if (
auto innerType = dyn_cast<ArrayType>(
elementType)) {
1544 while (isa<ArrayType>(innerType.getElementType()))
1545 innerType = cast<ArrayType>(innerType.getElementType());
1546 if (isa<StructType>(innerType.getElementType()) ||
1547 isa<TypeAliasType>(innerType.getElementType()))
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";
1603static void emitDim(Attribute width, raw_ostream &os, Location loc,
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));
1634 width = ParamExprAttr::get(PEO::Add, typedAttr, negOne);
1638 emitter.printParamValue(width, os, [loc]() {
1639 return mlir::emitError(loc,
"invalid parameter in type");
1647static void emitDims(ArrayRef<Attribute> dims, raw_ostream &os, Location loc,
1648 ModuleEmitter &emitter) {
1649 for (Attribute width : dims) {
1650 emitDim(width, os, loc, emitter,
true);
1655void 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*/";
1784 int64_t unionWidth = hw::getBitWidth(unionType);
1785 os <<
"union packed {";
1786 for (
auto &element : unionType.getElements()) {
1788 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1789 <<
": Zero Width;*/ ";
1792 int64_t elementWidth = hw::getBitWidth(element.type);
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;
1867bool ModuleEmitter::printPackedType(Type type, raw_ostream &os, Location loc,
1868 Type optionalAliasType,
1869 bool implicitIntType,
1870 bool singleBitDefaultType,
1871 bool emitAsTwoStateType) {
1872 SmallVector<Attribute, 8> packedDimensions;
1874 singleBitDefaultType, *
this, optionalAliasType,
1875 emitAsTwoStateType);
1881void 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) {
1911ModuleEmitter::printParamValue(Attribute value, raw_ostream &os,
1912 function_ref<InFlightDiagnostic()> emitError) {
1913 return printParamValue(value, os, VerilogPrecedence::LowestPrecedence,
1921ModuleEmitter::printParamValue(Attribute value, raw_ostream &os,
1922 VerilogPrecedence parenthesizeIfLooserThan,
1923 function_ref<InFlightDiagnostic()> emitError) {
1924 if (
auto intAttr = dyn_cast<IntegerAttr>(value)) {
1925 IntegerType intTy = cast<IntegerType>(intAttr.getType());
1926 APInt value = intAttr.getValue();
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 &=
2105 emitOperand(IntegerAttr::get(op.getType(), -value));
2112 allOperandsSigned &= emitOperand(op);
2116 if (prec > parenthesizeIfLooserThan) {
2120 return {prec, allOperandsSigned ? IsSigned : IsUnsigned};
2135class 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) {
2202 SubExprInfo visitUnhandledComb(Operation *op) {
2203 return visitUnhandledExpr(op);
2206 return dispatchSVVisitor(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;
2479SubExprInfo 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};
2540SubExprInfo 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};
2556void ExprEmitter::emitSVAttributes(Operation *op) {
2575 if (constant && constant.getValue().isZero())
2576 return concat.getOperand(1);
2586SubExprInfo 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());
2679SubExprInfo 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};
2699SubExprInfo ExprEmitter::visitComb(
ConcatOp op) {
2700 emitBracedList(op.getOperands());
2701 return {Symbol, IsUnsigned};
2704SubExprInfo 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);
2718SubExprInfo 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;
2750SubExprInfo 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};
2778SubExprInfo 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};
2788SubExprInfo 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};
2802SubExprInfo 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};
2813SubExprInfo 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};
2827SubExprInfo 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};
2854SubExprInfo 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};
2865template <
typename MacroTy>
2866SubExprInfo 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};
2886SubExprInfo ExprEmitter::visitSV(MacroRefExprOp op) {
2887 return emitMacroCall(op);
2890SubExprInfo ExprEmitter::visitSV(MacroRefExprSEOp op) {
2891 return emitMacroCall(op);
2894SubExprInfo ExprEmitter::visitSV(ConstantXOp op) {
2896 emitError(op,
"SV attributes emission is unimplemented for the op");
2898 ps.addAsString(op.getWidth());
2900 return {Unary, IsUnsigned};
2903SubExprInfo ExprEmitter::visitSV(ConstantStrOp op) {
2905 emitError(op,
"SV attributes emission is unimplemented for the op");
2907 ps.writeQuotedEscaped(op.getStr());
2908 return {Symbol, IsUnsigned};
2911SubExprInfo ExprEmitter::visitSV(ConstantZOp op) {
2913 emitError(op,
"SV attributes emission is unimplemented for the op");
2915 ps.addAsString(op.getWidth());
2917 return {Unary, IsUnsigned};
2920SubExprInfo 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};
2950SubExprInfo 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()));
2968void 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 <<
"}"; });
2982void 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 <<
"}"; });
3024void 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";
3051SubExprInfo 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};
3063SubExprInfo 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");
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};
3091SubExprInfo 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};
3127SubExprInfo 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};
3145SubExprInfo 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};
3160SubExprInfo 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};
3176SubExprInfo 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());
3192SubExprInfo 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};
3202SubExprInfo ExprEmitter::visitSV(SampledOp op) {
3204 emitError(op,
"SV attributes emission is unimplemented for the op");
3207 auto info = emitSubExpr(op.getExpression(), LowestPrecedence);
3212SubExprInfo 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};
3251SubExprInfo 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};
3316SubExprInfo 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);
3338SubExprInfo ExprEmitter::visitTypeOp(EnumConstantOp op) {
3339 ps <<
PPSaveString(emitter.fieldNameResolver.getEnumFieldName(op.getField()));
3340 return {Selection, IsUnsigned};
3343SubExprInfo 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;
3353SubExprInfo ExprEmitter::visitTypeOp(UnionCreateOp op) {
3355 emitError(op,
"SV attributes emission is unimplemented for the op");
3359 auto unionWidth = hw::getBitWidth(unionType);
3360 auto &element = unionType.getElements()[op.getFieldIndex()];
3361 auto elementWidth = hw::getBitWidth(element.type);
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};
3395SubExprInfo 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()));
3402 auto unionWidth = hw::getBitWidth(unionType);
3403 auto &element = unionType.getElements()[op.getFieldIndex()];
3404 auto elementWidth = hw::getBitWidth(element.type);
3405 bool needsPadding = elementWidth < unionWidth || element.offset > 0;
3406 auto verilogFieldName = emitter.getVerilogStructFieldName(element.name);
3415 return {Selection, IsUnsigned};
3418SubExprInfo 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};
3438enum class PropertyPrecedence {
3458struct EmittedProperty {
3460 PropertyPrecedence precedence;
3465class 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;
3541void 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); });
3561void 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);
3575void 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);
3598EmittedProperty 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());
3637EmittedProperty PropertyEmitter::visitUnhandledLTL(Operation *op) {
3638 emitOpError(op,
"emission as Verilog property or sequence not supported");
3639 ps <<
"<<unsupported: " <<
PPExtString(op->getName().getStringRef()) <<
">>";
3640 return {PropertyPrecedence::Symbol};
3643EmittedProperty PropertyEmitter::visitLTL(ltl::AndOp op) {
3646 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::And); },
3647 [&]() { ps << PP::space <<
"and" << PP::nbsp; });
3648 return {PropertyPrecedence::And};
3651EmittedProperty PropertyEmitter::visitLTL(ltl::OrOp op) {
3654 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::Or); },
3655 [&]() { ps << PP::space <<
"or" << PP::nbsp; });
3656 return {PropertyPrecedence::Or};
3659EmittedProperty PropertyEmitter::visitLTL(ltl::IntersectOp op) {
3663 emitNestedProperty(input, PropertyPrecedence::Intersect);
3665 [&]() { ps << PP::space <<
"intersect" << PP::nbsp; });
3666 return {PropertyPrecedence::Intersect};
3669EmittedProperty 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};
3697void 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);
3710EmittedProperty PropertyEmitter::visitLTL(ltl::ConcatOp op) {
3711 emitLTLConcat(op.getInputs());
3712 return {PropertyPrecedence::Concat};
3715EmittedProperty 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};
3739EmittedProperty 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};
3754EmittedProperty 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};
3769EmittedProperty 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();
3790EmittedProperty 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};
3804EmittedProperty PropertyEmitter::visitLTL(ltl::UntilOp op) {
3805 emitNestedProperty(op.getInput(), PropertyPrecedence::Until);
3806 ps << PP::space <<
"until" << PP::space;
3807 emitNestedProperty(op.getCondition(), PropertyPrecedence::Until);
3808 return {PropertyPrecedence::Until};
3811EmittedProperty PropertyEmitter::visitLTL(ltl::EventuallyOp op) {
3812 ps <<
"s_eventually" << PP::space;
3813 emitNestedProperty(op.getInput(), PropertyPrecedence::Qualifier);
3814 return {PropertyPrecedence::Qualifier};
3817EmittedProperty 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};
3836class 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;
3859void 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());
3909class StmtEmitter :
public EmitterBase,
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);
3935 using sv::Visitor<StmtEmitter, LogicalResult>::visitSV;
3938 friend class sv::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;
4073void StmtEmitter::emitExpression(Value exp,
4074 SmallPtrSetImpl<Operation *> &emittedExprs,
4075 VerilogPrecedence parenthesizeIfLooserThan,
4076 bool isAssignmentLikeContext) {
4077 ExprEmitter(emitter, emittedExprs)
4078 .emitExpression(exp, parenthesizeIfLooserThan, isAssignmentLikeContext);
4083void StmtEmitter::emitSVAttributes(Operation *op) {
4091 setPendingNewline();
4094void 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, [&]() {
4114template <
typename Op>
4116StmtEmitter::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);
4135LogicalResult StmtEmitter::visitSV(
AssignOp op) {
4138 if (isa_and_nonnull<HWInstanceLike, FuncCallOp>(op.getSrc().getDefiningOp()))
4141 if (emitter.assignsInlined.count(op))
4145 emitSVAttributes(op);
4150LogicalResult StmtEmitter::visitSV(BPAssignOp op) {
4151 if (op.getSrc().getDefiningOp<FuncCallProceduralOp>())
4155 if (emitter.assignsInlined.count(op))
4159 emitSVAttributes(op);
4164LogicalResult StmtEmitter::visitSV(PAssignOp op) {
4166 emitSVAttributes(op);
4171LogicalResult StmtEmitter::visitSV(ForceOp op) {
4173 emitError(op,
"SV attributes emission is unimplemented for the op");
4178LogicalResult 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);
4196LogicalResult 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);
4218LogicalResult StmtEmitter::visitSV(InterfaceInstanceOp op) {
4219 auto doNotPrint = op.getDoNotPrint();
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);
4258LogicalResult StmtEmitter::emitOutputLikeOp(Operation *op,
4260 SmallPtrSet<Operation *, 8> ops;
4261 size_t operandIndex = 0;
4262 bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
4263 for (
PortInfo port : ports.getOutputs()) {
4264 auto operand = op->getOperand(operandIndex);
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);
4308LogicalResult StmtEmitter::visitStmt(OutputOp op) {
4309 auto parent = op->getParentOfType<PortList>();
4311 return emitOutputLikeOp(op, ports);
4314LogicalResult 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();
4327LogicalResult 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);
4355template <
typename CallOpTy>
4356LogicalResult 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);
4408LogicalResult StmtEmitter::visitSV(FuncCallProceduralOp op) {
4409 return emitFunctionCall(op);
4412LogicalResult StmtEmitter::visitSV(FuncCallOp op) {
4413 return emitFunctionCall(op);
4416template <
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(
4437LogicalResult StmtEmitter::visitSV(ReturnOp op) {
4438 auto parent = op->getParentOfType<sv::FuncOp>();
4440 return emitOutputLikeOp(op, ports);
4443LogicalResult 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);
4463LogicalResult 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);
4496LogicalResult 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);
4538LogicalResult 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);
4569StmtEmitter::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);
4590LogicalResult StmtEmitter::visitSV(StopOp op) {
4591 return emitSimulationControlTask(op,
PPExtString(
"$stop"), op.getVerbosity());
4594LogicalResult StmtEmitter::visitSV(FinishOp op) {
4595 return emitSimulationControlTask(op,
PPExtString(
"$finish"),
4599LogicalResult StmtEmitter::visitSV(ExitOp op) {
4600 return emitSimulationControlTask(op,
PPExtString(
"$exit"), {});
4606StmtEmitter::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);
4651LogicalResult StmtEmitter::visitSV(FatalOp op) {
4652 return emitSeverityMessageTask(op,
PPExtString(
"$fatal"), op.getVerbosity(),
4653 op.getMessageAttr(), op.getSubstitutions());
4656LogicalResult StmtEmitter::visitSV(ErrorOp op) {
4657 return emitSeverityMessageTask(op,
PPExtString(
"$error"), {},
4658 op.getMessageAttr(), op.getSubstitutions());
4661LogicalResult StmtEmitter::visitSV(WarningOp op) {
4662 return emitSeverityMessageTask(op,
PPExtString(
"$warning"), {},
4663 op.getMessageAttr(), op.getSubstitutions());
4666LogicalResult StmtEmitter::visitSV(InfoOp op) {
4667 return emitSeverityMessageTask(op,
PPExtString(
"$info"), {},
4668 op.getMessageAttr(), op.getSubstitutions());
4671LogicalResult 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);
4698LogicalResult 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();
4715LogicalResult 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();
4776LogicalResult 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);
4823void StmtEmitter::emitAssertionLabel(Operation *op) {
4824 if (
auto label = op->getAttrOfType<StringAttr>(
"hw.verilogName"))
4830void 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);
4847template <
typename Op>
4848LogicalResult 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);
4884LogicalResult StmtEmitter::visitSV(AssertOp op) {
4885 return emitImmediateAssertion(op,
PPExtString(
"assert"));
4888LogicalResult StmtEmitter::visitSV(AssumeOp op) {
4889 return emitImmediateAssertion(op,
PPExtString(
"assume"));
4892LogicalResult StmtEmitter::visitSV(CoverOp op) {
4893 return emitImmediateAssertion(op,
PPExtString(
"cover"));
4896template <
typename Op>
4897LogicalResult 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);
4927LogicalResult StmtEmitter::visitSV(AssertConcurrentOp op) {
4928 return emitConcurrentAssertion(op,
PPExtString(
"assert"));
4931LogicalResult StmtEmitter::visitSV(AssumeConcurrentOp op) {
4932 return emitConcurrentAssertion(op,
PPExtString(
"assume"));
4935LogicalResult StmtEmitter::visitSV(CoverConcurrentOp op) {
4936 return emitConcurrentAssertion(op,
PPExtString(
"cover"));
4941template <
typename Op>
4942LogicalResult 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);
4994LogicalResult StmtEmitter::visitSV(AssertPropertyOp op) {
4995 return emitPropertyAssertion(op,
PPExtString(
"assert"));
4998LogicalResult StmtEmitter::visitSV(AssumePropertyOp op) {
4999 return emitPropertyAssertion(op,
PPExtString(
"assume"));
5002LogicalResult StmtEmitter::visitSV(CoverPropertyOp op) {
5003 return emitPropertyAssertion(op,
PPExtString(
"cover"));
5006LogicalResult StmtEmitter::emitIfDef(Operation *op, MacroIdentAttr cond) {
5008 emitError(op,
"SV attributes emission is unimplemented for the op");
5011 cast<MacroDeclOp>(state.symbolCache.getDefinition(cond.getIdent()))
5012 .getMacroIdentifier());
5015 bool hasEmptyThen = op->getRegion(0).front().empty();
5017 ps <<
"`ifndef " << ident;
5019 ps <<
"`ifdef " << ident;
5021 SmallPtrSet<Operation *, 8> ops;
5023 emitLocationInfoAndNewLine(ops);
5026 emitStatementBlock(op->getRegion(0).front());
5028 if (!op->getRegion(1).empty()) {
5029 if (!hasEmptyThen) {
5031 ps <<
"`else // " << ident;
5032 setPendingNewline();
5034 emitStatementBlock(op->getRegion(1).front());
5041 setPendingNewline();
5049void StmtEmitter::emitBlockAsStatement(
5050 Block *block,
const SmallPtrSetImpl<Operation *> &locationOps,
5051 StringRef multiLineComment) {
5058 emitLocationInfoAndNewLine(locationOps);
5061 emitStatementBlock(*block);
5063 if (needsBeginEnd) {
5067 if (!multiLineComment.empty())
5068 ps <<
" // " << multiLineComment;
5069 setPendingNewline();
5073LogicalResult StmtEmitter::visitSV(OrderedOutputOp ooop) {
5075 for (
auto &op : ooop.getBody().front())
5080LogicalResult StmtEmitter::visitSV(IfOp op) {
5081 SmallPtrSet<Operation *, 8> ops;
5083 auto ifcondBox = PP::ibox2;
5085 emitSVAttributes(op);
5087 ps.addCallback({op,
true});
5088 ps <<
"if (" << ifcondBox;
5098 emitExpression(ifOp.getCond(), ops);
5099 ps << PP::end <<
")";
5100 emitBlockAsStatement(ifOp.getThenBlock(), ops);
5102 if (!ifOp.hasElse())
5106 Block *elseBlock = ifOp.getElseBlock();
5108 if (!nestedElseIfOp) {
5113 emitBlockAsStatement(elseBlock, ops);
5119 ifOp = nestedElseIfOp;
5120 ps <<
"else if (" << ifcondBox;
5122 ps.addCallback({op,
false});
5127LogicalResult StmtEmitter::visitSV(AlwaysOp op) {
5128 emitSVAttributes(op);
5129 SmallPtrSet<Operation *, 8> ops;
5133 auto printEvent = [&](AlwaysOp::Condition cond) {
5134 ps <<
PPExtString(stringifyEventControl(cond.event)) << PP::nbsp;
5135 ps.scopedBox(PP::cbox0, [&]() { emitExpression(cond.value, ops); });
5137 ps.addCallback({op,
true});
5139 switch (op.getNumConditions()) {
5145 printEvent(op.getCondition(0));
5150 ps.scopedBox(PP::cbox0, [&]() {
5151 printEvent(op.getCondition(0));
5152 for (
size_t i = 1, e = op.getNumConditions(); i != e; ++i) {
5153 ps << PP::space <<
"or" << PP::space;
5154 printEvent(op.getCondition(i));
5163 std::string comment;
5164 if (op.getNumConditions() == 0) {
5165 comment =
"always @*";
5167 comment =
"always @(";
5170 [&](Attribute eventAttr) {
5171 auto event = sv::EventControl(cast<IntegerAttr>(eventAttr).getInt());
5172 comment += stringifyEventControl(event);
5174 [&]() { comment +=
", "; });
5178 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5179 ps.addCallback({op,
false});
5183LogicalResult StmtEmitter::visitSV(AlwaysCombOp op) {
5184 emitSVAttributes(op);
5185 SmallPtrSet<Operation *, 8> ops;
5189 ps.addCallback({op,
true});
5190 StringRef opString =
"always_comb";
5191 if (state.options.noAlwaysComb)
5192 opString =
"always @(*)";
5195 emitBlockAsStatement(op.getBodyBlock(), ops, opString);
5196 ps.addCallback({op,
false});
5200LogicalResult StmtEmitter::visitSV(AlwaysFFOp op) {
5201 emitSVAttributes(op);
5203 SmallPtrSet<Operation *, 8> ops;
5207 ps.addCallback({op,
true});
5208 ps <<
"always_ff @(";
5209 ps.scopedBox(PP::cbox0, [&]() {
5210 ps <<
PPExtString(stringifyEventControl(op.getClockEdge())) << PP::nbsp;
5211 emitExpression(op.getClock(), ops);
5212 if (op.getResetStyle() == ResetType::AsyncReset) {
5213 ps << PP::nbsp <<
"or" << PP::space
5214 <<
PPExtString(stringifyEventControl(*op.getResetEdge())) << PP::nbsp;
5215 emitExpression(op.getReset(), ops);
5222 std::string comment;
5223 comment +=
"always_ff @(";
5224 comment += stringifyEventControl(op.getClockEdge());
5225 if (op.getResetStyle() == ResetType::AsyncReset) {
5227 comment += stringifyEventControl(*op.getResetEdge());
5231 if (op.getResetStyle() == ResetType::NoReset)
5232 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
5235 emitLocationInfoAndNewLine(ops);
5236 ps.scopedBox(PP::bbox2, [&]() {
5242 if (op.getResetStyle() == ResetType::AsyncReset &&
5243 *op.getResetEdge() == sv::EventControl::AtNegEdge)
5245 emitExpression(op.getReset(), ops);
5247 emitBlockAsStatement(op.getResetBlock(), ops);
5250 emitBlockAsStatement(op.getBodyBlock(), ops);
5255 ps <<
" // " << comment;
5256 setPendingNewline();
5258 ps.addCallback({op,
false});
5262LogicalResult StmtEmitter::visitSV(InitialOp op) {
5263 emitSVAttributes(op);
5264 SmallPtrSet<Operation *, 8> ops;
5267 ps.addCallback({op,
true});
5269 emitBlockAsStatement(op.getBodyBlock(), ops,
"initial");
5270 ps.addCallback({op,
false});
5274LogicalResult StmtEmitter::visitSV(CaseOp op) {
5275 emitSVAttributes(op);
5276 SmallPtrSet<Operation *, 8> ops, emptyOps;
5279 ps.addCallback({op,
true});
5280 if (op.getValidationQualifier() !=
5281 ValidationQualifierTypeEnum::ValidationQualifierPlain)
5282 ps <<
PPExtString(circt::sv::stringifyValidationQualifierTypeEnum(
5283 op.getValidationQualifier()))
5285 const char *opname =
nullptr;
5286 switch (op.getCaseStyle()) {
5287 case CaseStmtType::CaseStmt:
5290 case CaseStmtType::CaseXStmt:
5293 case CaseStmtType::CaseZStmt:
5297 ps << opname <<
" (";
5298 ps.scopedBox(PP::ibox0, [&]() {
5299 emitExpression(op.getCond(), ops);
5302 emitLocationInfoAndNewLine(ops);
5304 ps.scopedBox(PP::bbox2, [&]() {
5305 for (
auto &caseInfo : op.getCases()) {
5307 auto &
pattern = caseInfo.pattern;
5309 llvm::TypeSwitch<CasePattern *>(
pattern.get())
5310 .Case<CaseBitPattern>([&](
auto bitPattern) {
5313 ps.invokeWithStringOS([&](
auto &os) {
5314 os << bitPattern->getWidth() <<
"'b";
5315 for (
size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
5316 os <<
getLetter(bitPattern->getBit(e - bit - 1));
5319 .Case<CaseEnumPattern>([&](
auto enumPattern) {
5320 ps <<
PPExtString(emitter.fieldNameResolver.getEnumFieldName(
5321 cast<hw::EnumFieldAttr>(enumPattern->attr())));
5323 .Case<CaseDefaultPattern>([&](
auto) { ps <<
"default"; })
5324 .Default([&](
auto) {
assert(
false &&
"unhandled case pattern"); });
5327 emitBlockAsStatement(caseInfo.block, emptyOps);
5333 ps.addCallback({op,
false});
5334 emitLocationInfoAndNewLine(ops);
5338LogicalResult StmtEmitter::visitStmt(InstanceOp op) {
5339 bool doNotPrint = op.getDoNotPrint();
5340 if (doNotPrint && !state.options.emitBindComments)
5345 emitSVAttributes(op);
5347 ps.addCallback({op,
true});
5350 <<
"/* This instance is elsewhere emitted as a bind statement."
5353 op->emitWarning() <<
"is emitted as a bind statement but has SV "
5354 "attributes. The attributes will not be emitted.";
5357 SmallPtrSet<Operation *, 8> ops;
5362 state.symbolCache.getDefinition(op.getReferencedModuleNameAttr());
5363 assert(moduleOp &&
"Invalid IR");
5367 if (!op.getParameters().empty()) {
5370 bool printed =
false;
5372 llvm::zip(op.getParameters(),
5373 moduleOp->getAttrOfType<ArrayAttr>(
"parameters"))) {
5374 auto param = cast<ParamDeclAttr>(std::get<0>(params));
5375 auto modParam = cast<ParamDeclAttr>(std::get<1>(params));
5377 if (param.getValue() == modParam.getValue())
5382 ps <<
" #(" << PP::bbox2 << PP::newline;
5385 ps <<
"," << PP::newline;
5389 state.globalNames.getParameterVerilogName(moduleOp, param.getName()));
5391 ps.invokeWithStringOS([&](
auto &os) {
5392 emitter.printParamValue(param.getValue(), os, [&]() {
5393 return op->emitOpError(
"invalid instance parameter '")
5394 << param.getName().getValue() <<
"' value";
5400 ps << PP::end << PP::newline <<
")";
5407 SmallVector<Value> instPortValues(modPortInfo.size());
5408 op.getValues(instPortValues, modPortInfo);
5409 emitInstancePortList(op, modPortInfo, instPortValues);
5411 ps.addCallback({op,
false});
5412 emitLocationInfoAndNewLine(ops);
5417 setPendingNewline();
5422LogicalResult StmtEmitter::visitStmt(InstanceChoiceOp op) {
5424 Operation *choiceMacroDeclOp = state.symbolCache.getDefinition(
5425 op->getAttrOfType<FlatSymbolRefAttr>(
"hw.choiceTarget"));
5430 Operation *defaultModuleOp =
5431 state.symbolCache.getDefinition(op.getDefaultModuleNameAttr());
5433 SmallVector<Value> instPortValues(modPortInfo.size());
5434 op.getValues(instPortValues, modPortInfo);
5435 emitInstancePortList(op, modPortInfo, instPortValues);
5437 SmallPtrSet<Operation *, 8> ops;
5439 ps.addCallback({op,
false});
5440 emitLocationInfoAndNewLine(ops);
5445void StmtEmitter::emitInstancePortList(Operation *op,
5447 ArrayRef<Value> instPortValues) {
5448 SmallPtrSet<Operation *, 8> ops;
5451 auto containingModule = cast<HWModuleOp>(emitter.currentModuleOp);
5452 ModulePortInfo containingPortList(containingModule.getPortList());
5457 size_t maxNameLength = 0;
5458 for (
auto &elt : modPortInfo) {
5459 maxNameLength = std::max(maxNameLength, elt.getVerilogName().size());
5462 auto getWireForValue = [&](Value result) {
5463 return result.getUsers().begin()->getOperand(0);
5467 bool isFirst =
true;
5468 bool isZeroWidth =
false;
5470 for (
size_t portNum = 0, portEnd = modPortInfo.
size(); portNum < portEnd;
5472 auto &modPort = modPortInfo.
at(portNum);
5474 Value portVal = instPortValues[portNum];
5479 bool shouldPrintComma =
true;
5481 shouldPrintComma =
false;
5482 for (
size_t i = portNum + 1, e = modPortInfo.
size(); i != e; ++i)
5484 shouldPrintComma =
true;
5489 if (shouldPrintComma)
5492 emitLocationInfoAndNewLine(ops);
5507 ps.scopedBox(isZeroWidth ? PP::neverbox :
PP::
ibox2, [&]() {
5508 auto modPortName = modPort.getVerilogName();
5510 ps.spaces(maxNameLength - modPortName.size() + 1);
5512 ps.scopedBox(PP::ibox0, [&]() {
5519 if (!modPort.isOutput()) {
5521 isa_and_nonnull<ConstantOp>(portVal.getDefiningOp()))
5522 ps <<
"/* Zero width */";
5524 emitExpression(portVal, ops, LowestPrecedence);
5525 }
else if (portVal.use_empty()) {
5526 ps <<
"/* unused */";
5527 }
else if (portVal.hasOneUse() &&
5528 (output = dyn_cast_or_null<OutputOp>(
5529 portVal.getUses().begin()->getOwner()))) {
5534 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
5536 containingPortList.atOutput(outputPortNo).getVerilogName());
5538 portVal = getWireForValue(portVal);
5539 emitExpression(portVal, ops);
5545 if (!isFirst || isZeroWidth) {
5546 emitLocationInfoAndNewLine(ops);
5559LogicalResult StmtEmitter::visitSV(BindOp op) {
5560 emitter.emitBind(op);
5561 assert(state.pendingNewline);
5565LogicalResult StmtEmitter::visitSV(InterfaceOp op) {
5566 emitComment(op.getCommentAttr());
5568 emitSVAttributes(op);
5571 ps.addCallback({op,
true});
5573 setPendingNewline();
5575 emitStatementBlock(*op.getBodyBlock());
5577 ps <<
"endinterface" << PP::newline;
5578 ps.addCallback({op,
false});
5579 setPendingNewline();
5583LogicalResult StmtEmitter::visitSV(InterfaceSignalOp op) {
5585 emitSVAttributes(op);
5587 ps.addCallback({op,
true});
5589 ps << PP::neverbox <<
"// ";
5590 ps.invokeWithStringOS([&](
auto &os) {
5595 ps.invokeWithStringOS(
5596 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
5600 ps.addCallback({op,
false});
5601 setPendingNewline();
5605LogicalResult StmtEmitter::visitSV(InterfaceModportOp op) {
5607 ps.addCallback({op,
true});
5611 llvm::interleaveComma(op.getPorts(), ps, [&](
const Attribute &portAttr) {
5612 auto port = cast<ModportStructAttr>(portAttr);
5613 ps << PPExtString(stringifyEnum(port.getDirection().getValue())) <<
" ";
5614 auto *signalDecl = state.symbolCache.getDefinition(port.getSignal());
5615 ps << PPExtString(getSymOpName(signalDecl));
5619 ps.addCallback({op,
false});
5620 setPendingNewline();
5624LogicalResult StmtEmitter::visitSV(AssignInterfaceSignalOp op) {
5626 ps.addCallback({op,
true});
5627 SmallPtrSet<Operation *, 8> emitted;
5630 emitExpression(op.getIface(), emitted);
5631 ps <<
"." <<
PPExtString(op.getSignalName()) <<
" = ";
5632 emitExpression(op.getRhs(), emitted);
5634 ps.addCallback({op,
false});
5635 setPendingNewline();
5639LogicalResult StmtEmitter::visitSV(MacroDefOp op) {
5640 auto decl = op.getReferencedMacro(&state.symbolCache);
5643 ps.addCallback({op,
true});
5645 if (decl.getArgs()) {
5647 llvm::interleaveComma(*decl.getArgs(), ps, [&](
const Attribute &name) {
5648 ps << cast<StringAttr>(name);
5652 if (!op.getFormatString().empty()) {
5654 emitTextWithSubstitutions(ps, op.getFormatString(), op, {},
5657 ps.addCallback({op,
false});
5658 setPendingNewline();
5662void StmtEmitter::emitStatement(Operation *op) {
5669 if (isa<ltl::LTLDialect, debug::DebugDialect>(op->getDialect()))
5673 if (succeeded(dispatchStmtVisitor(op)) || succeeded(dispatchSVVisitor(op)) ||
5674 succeeded(dispatchVerifVisitor(op)))
5677 emitOpError(op,
"emission to Verilog not supported");
5678 emitPendingNewlineIfNeeded();
5679 ps <<
"unknown MLIR operation " <<
PPExtString(op->getName().getStringRef());
5680 setPendingNewline();
5691 StmtEmitter &stmtEmitter) {
5698 if (isa<IfDefProceduralOp>(op->getParentOp()))
5706 SmallVector<Value, 8> exprsToScan(op->getOperands());
5711 while (!exprsToScan.empty()) {
5712 Operation *expr = exprsToScan.pop_back_val().getDefiningOp();
5719 if (
auto readInout = dyn_cast<sv::ReadInOutOp>(expr)) {
5720 auto *defOp = readInout.getOperand().getDefiningOp();
5727 if (isa<sv::WireOp>(defOp))
5732 if (!isa<RegOp, LogicOp>(defOp))
5738 if (isa<LogicOp>(defOp) &&
5739 stmtEmitter.emitter.expressionsEmittedIntoDecl.count(defOp))
5743 if (llvm::all_of(defOp->getResult(0).getUsers(), [&](Operation *op) {
5744 return isa<ReadInOutOp, PAssignOp, AssignOp>(op);
5752 exprsToScan.append(expr->getOperands().begin(),
5753 expr->getOperands().end());
5759 if (expr->getBlock() != op->getBlock())
5764 if (!stmtEmitter.emitter.expressionsEmittedIntoDecl.count(expr))
5771template <
class AssignTy>
5773 AssignTy singleAssign;
5774 if (llvm::all_of(op->getUsers(), [&](Operation *user) {
5775 if (hasSVAttributes(user))
5778 if (auto assign = dyn_cast<AssignTy>(user)) {
5781 singleAssign = assign;
5785 return isa<ReadInOutOp>(user);
5787 return singleAssign;
5793 return llvm::all_of(op2->getUsers(), [&](Operation *user) {
5797 if (op1->getBlock() != user->getBlock())
5803 return op1->isBeforeInBlock(user);
5807LogicalResult StmtEmitter::emitDeclaration(Operation *op) {
5808 emitSVAttributes(op);
5809 auto value = op->getResult(0);
5810 SmallPtrSet<Operation *, 8> opsForLocation;
5811 opsForLocation.insert(op);
5813 ps.addCallback({op,
true});
5816 auto type = value.getType();
5819 ps.scopedBox(isZeroBit ? PP::neverbox :
PP::
ibox2, [&]() {
5820 unsigned targetColumn = 0;
5821 unsigned column = 0;
5824 if (maxDeclNameWidth > 0)
5825 targetColumn += maxDeclNameWidth + 1;
5828 ps <<
"// Zero width: " <<
PPExtString(word) << PP::space;
5829 }
else if (!word.empty()) {
5831 column += word.size();
5832 unsigned numSpaces = targetColumn > column ? targetColumn - column : 1;
5833 ps.spaces(numSpaces);
5834 column += numSpaces;
5837 SmallString<8> typeString;
5840 llvm::raw_svector_ostream stringStream(typeString);
5845 if (maxTypeWidth > 0)
5846 targetColumn += maxTypeWidth + 1;
5847 unsigned numSpaces = 0;
5848 if (!typeString.empty()) {
5850 column += typeString.size();
5853 if (targetColumn > column)
5854 numSpaces = targetColumn - column;
5855 ps.spaces(numSpaces);
5856 column += numSpaces;
5862 ps.invokeWithStringOS(
5863 [&](
auto &os) { emitter.printUnpackedTypePostfix(type, os); });
5866 if (state.options.printDebugInfo) {
5867 if (
auto innerSymOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
5868 auto innerSym = innerSymOp.getInnerSymAttr();
5869 if (innerSym && !innerSym.empty()) {
5871 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
5877 if (
auto localparam = dyn_cast<LocalParamOp>(op)) {
5878 ps << PP::space <<
"=" << PP::space;
5879 ps.invokeWithStringOS([&](
auto &os) {
5880 emitter.printParamValue(localparam.getValue(), os, [&]() {
5881 return op->emitOpError(
"invalid localparam value");
5886 if (
auto regOp = dyn_cast<RegOp>(op)) {
5887 if (
auto initValue = regOp.getInit()) {
5888 ps << PP::space <<
"=" << PP::space;
5889 ps.scopedBox(PP::ibox0, [&]() {
5890 emitExpression(initValue, opsForLocation, LowestPrecedence,
5899 if (isa<sv::WireOp>(op) &&
5900 !op->getParentOp()->hasTrait<ProceduralRegion>() &&
5903 if (
auto singleAssign = getSingleAssignAndCheckUsers<AssignOp>(op)) {
5904 auto *source = singleAssign.getSrc().getDefiningOp();
5908 if (!source || isa<ConstantOp>(source) ||
5909 op->getNextNode() == singleAssign) {
5910 ps << PP::space <<
"=" << PP::space;
5911 ps.scopedBox(PP::ibox0, [&]() {
5912 emitExpression(singleAssign.getSrc(), opsForLocation,
5916 emitter.assignsInlined.insert(singleAssign);
5924 if (isa<LogicOp>(op) && op->getParentOp()->hasTrait<ProceduralRegion>() &&
5927 if (
auto singleAssign = getSingleAssignAndCheckUsers<BPAssignOp>(op)) {
5930 auto *source = singleAssign.getSrc().getDefiningOp();
5934 if (!source || isa<ConstantOp>(source) ||
5937 ps << PP::space <<
"=" << PP::space;
5938 ps.scopedBox(PP::ibox0, [&]() {
5939 emitExpression(singleAssign.getSrc(), opsForLocation,
5944 emitter.assignsInlined.insert(singleAssign);
5945 emitter.expressionsEmittedIntoDecl.insert(op);
5952 ps.addCallback({op,
false});
5953 emitLocationInfoAndNewLine(opsForLocation);
5957void StmtEmitter::collectNamesAndCalculateDeclarationWidths(Block &block) {
5960 NameCollector collector(emitter);
5961 collector.collectNames(block);
5964 maxDeclNameWidth = collector.getMaxDeclNameWidth();
5965 maxTypeWidth = collector.getMaxTypeWidth();
5968void StmtEmitter::emitStatementBlock(Block &body) {
5969 ps.scopedBox(PP::bbox2, [&]() {
5974 llvm::SaveAndRestore<size_t> x(maxDeclNameWidth);
5975 llvm::SaveAndRestore<size_t> x2(maxTypeWidth);
5980 if (!isa<IfDefProceduralOp>(body.getParentOp()))
5981 collectNamesAndCalculateDeclarationWidths(body);
5984 for (
auto &op : body) {
5991void ModuleEmitter::emitStatement(Operation *op) {
5992 StmtEmitter(*
this, state.options).emitStatement(op);
5997void ModuleEmitter::emitSVAttributes(Operation *op) {
6005 setPendingNewline();
6012void ModuleEmitter::emitHWGeneratedModule(HWModuleGeneratedOp module) {
6013 auto verilogName =
module.getVerilogModuleNameAttr();
6015 ps <<
"// external generated module " <<
PPExtString(verilogName.getValue())
6017 setPendingNewline();
6026void ModuleEmitter::emitBind(BindOp op) {
6028 emitError(op,
"SV attributes emission is unimplemented for the op");
6029 InstanceOp inst = op.getReferencedInstance(&state.symbolCache);
6035 Operation *childMod =
6036 state.symbolCache.getDefinition(inst.getReferencedModuleNameAttr());
6040 ps.addCallback({op,
true});
6041 ps <<
"bind " <<
PPExtString(parentVerilogName.getValue()) << PP::nbsp
6042 <<
PPExtString(childVerilogName.getValue()) << PP::nbsp
6044 bool isFirst =
true;
6045 ps.scopedBox(PP::bbox2, [&]() {
6046 auto parentPortInfo = parentMod.getPortList();
6050 size_t maxNameLength = 0;
6051 for (
auto &elt : childPortInfo) {
6052 auto portName = elt.getVerilogName();
6053 elt.name = Builder(inst.getContext()).getStringAttr(portName);
6054 maxNameLength = std::max(maxNameLength, elt.getName().size());
6057 SmallVector<Value> instPortValues(childPortInfo.size());
6058 inst.getValues(instPortValues, childPortInfo);
6060 for (
auto [idx, elt] :
llvm::enumerate(childPortInfo)) {
6062 Value portVal = instPortValues[idx];
6068 bool shouldPrintComma =
true;
6070 shouldPrintComma =
false;
6071 for (
size_t i = idx + 1, e = childPortInfo.size(); i != e; ++i)
6073 shouldPrintComma =
true;
6078 if (shouldPrintComma)
6091 ps << PP::neverbox <<
"//";
6095 ps.nbsp(maxNameLength - elt.getName().size());
6097 llvm::SmallPtrSet<Operation *, 4> ops;
6098 if (elt.isOutput()) {
6099 assert((portVal.hasOneUse() || portVal.use_empty()) &&
6100 "output port must have either single or no use");
6101 if (portVal.use_empty()) {
6102 ps <<
"/* unused */";
6103 }
else if (
auto output = dyn_cast_or_null<OutputOp>(
6104 portVal.getUses().begin()->getOwner())) {
6107 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
6109 parentPortList.atOutput(outputPortNo).getVerilogName());
6111 portVal = portVal.getUsers().begin()->getOperand(0);
6112 ExprEmitter(*
this, ops)
6113 .emitExpression(portVal, LowestPrecedence,
6117 ExprEmitter(*
this, ops)
6118 .emitExpression(portVal, LowestPrecedence,
6131 ps.addCallback({op,
false});
6132 setPendingNewline();
6135void ModuleEmitter::emitBindInterface(BindInterfaceOp op) {
6137 emitError(op,
"SV attributes emission is unimplemented for the op");
6139 auto instance = op.getReferencedInstance(&state.symbolCache);
6141 auto *
interface = op->getParentOfType<ModuleOp>().lookupSymbol(
6142 instance.getInterfaceType().getInterface());
6144 ps.addCallback({op,
true});
6145 ps <<
"bind " <<
PPExtString(instantiator) << PP::nbsp
6146 <<
PPExtString(cast<InterfaceOp>(*interface).getSymName()) << PP::nbsp
6148 ps.addCallback({op,
false});
6149 setPendingNewline();
6152void ModuleEmitter::emitParameters(Operation *module, ArrayAttr params) {
6156 auto printParamType = [&](Type type, Attribute defaultValue,
6157 SmallString<8> &result) {
6159 llvm::raw_svector_ostream sstream(result);
6164 if (
auto intAttr = dyn_cast<IntegerAttr>(defaultValue))
6165 if (intAttr.getValue().getBitWidth() == 32)
6167 if (
auto fpAttr = dyn_cast<FloatAttr>(defaultValue))
6168 if (fpAttr.getType().isF64())
6171 if (isa<NoneType>(type))
6178 if (
auto intType = type_dyn_cast<IntegerType>(type))
6179 if (intType.getWidth() == 32) {
6180 sstream <<
"/*integer*/";
6184 printPackedType(type, sstream, module->getLoc(),
6192 size_t maxTypeWidth = 0;
6193 SmallString<8> scratch;
6194 for (
auto param : params) {
6195 auto paramAttr = cast<ParamDeclAttr>(param);
6197 printParamType(paramAttr.getType(), paramAttr.getValue(), scratch);
6198 maxTypeWidth = std::max(scratch.size(), maxTypeWidth);
6201 if (maxTypeWidth > 0)
6204 ps.scopedBox(PP::bbox2, [&]() {
6205 ps << PP::newline <<
"#(";
6206 ps.scopedBox(PP::cbox0, [&]() {
6209 [&](Attribute param) {
6210 auto paramAttr = cast<ParamDeclAttr>(param);
6211 auto defaultValue = paramAttr.getValue();
6213 printParamType(paramAttr.getType(), defaultValue, scratch);
6214 if (!scratch.empty())
6216 if (scratch.size() < maxTypeWidth)
6217 ps.nbsp(maxTypeWidth - scratch.size());
6219 ps <<
PPExtString(state.globalNames.getParameterVerilogName(
6220 module, paramAttr.getName()));
6224 ps.invokeWithStringOS([&](
auto &os) {
6226 return module->emitError("parameter '")
6227 << paramAttr.getName().getValue()
6228 << "' has invalid value";
6233 [&]() { ps <<
"," << PP::newline; });
6239void ModuleEmitter::emitPortList(Operation *module,
6241 bool emitAsTwoStateType) {
6243 if (portInfo.
size())
6244 emitLocationInfo(module->getLoc());
6248 bool hasOutputs =
false, hasZeroWidth =
false;
6249 size_t maxTypeWidth = 0, lastNonZeroPort = -1;
6250 SmallVector<SmallString<8>, 16> portTypeStrings;
6252 for (
size_t i = 0, e = portInfo.
size(); i < e; ++i) {
6253 auto port = portInfo.
at(i);
6257 lastNonZeroPort = i;
6260 portTypeStrings.push_back({});
6262 llvm::raw_svector_ostream stringStream(portTypeStrings.back());
6264 module->getLoc(), {},
true,
true, emitAsTwoStateType);
6267 maxTypeWidth = std::max(portTypeStrings.back().size(), maxTypeWidth);
6270 if (maxTypeWidth > 0)
6274 ps.scopedBox(PP::bbox2, [&]() {
6275 for (
size_t portIdx = 0, e = portInfo.
size(); portIdx != e;) {
6276 auto lastPort = e - 1;
6279 auto portType = portInfo.
at(portIdx).
type;
6283 bool isZeroWidth =
false;
6288 ps << (isZeroWidth ?
"// " :
" ");
6292 auto thisPortDirection = portInfo.
at(portIdx).
dir;
6293 switch (thisPortDirection) {
6294 case ModulePort::Direction::Output:
6297 case ModulePort::Direction::Input:
6298 ps << (hasOutputs ?
"input " :
"input ");
6300 case ModulePort::Direction::InOut:
6301 ps << (hasOutputs ?
"inout " :
"inout ");
6304 bool emitWireInPorts = state.options.emitWireInPorts;
6305 if (emitWireInPorts)
6309 if (!portTypeStrings[portIdx].
empty())
6310 ps << portTypeStrings[portIdx];
6311 if (portTypeStrings[portIdx].size() < maxTypeWidth)
6312 ps.nbsp(maxTypeWidth - portTypeStrings[portIdx].size());
6314 size_t startOfNamePos =
6315 (hasOutputs ? 7 : 6) + (emitWireInPorts ? 5 : 0) + maxTypeWidth;
6321 ps.invokeWithStringOS(
6322 [&](
auto &os) { printUnpackedTypePostfix(portType, os); });
6325 auto innerSym = portInfo.
at(portIdx).
getSym();
6326 if (state.options.printDebugInfo && innerSym && !innerSym.empty()) {
6328 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
6333 if (portIdx != lastNonZeroPort && portIdx != lastPort)
6337 if (
auto loc = portInfo.
at(portIdx).
loc)
6338 emitLocationInfo(loc);
6348 if (!state.options.disallowPortDeclSharing) {
6349 while (portIdx != e && portInfo.
at(portIdx).
dir == thisPortDirection &&
6352 auto port = portInfo.
at(portIdx);
6356 bool isZeroWidth =
false;
6361 ps << (isZeroWidth ?
"// " :
" ");
6364 ps.nbsp(startOfNamePos);
6367 StringRef name = port.getVerilogName();
6371 ps.invokeWithStringOS(
6372 [&](
auto &os) { printUnpackedTypePostfix(port.type, os); });
6375 auto sym = port.getSym();
6376 if (state.options.printDebugInfo && sym && !sym.empty())
6377 ps <<
" /* inner_sym: " <<
PPExtString(sym.getSymName().getValue())
6381 if (portIdx != lastNonZeroPort && portIdx != lastPort)
6385 if (
auto loc = port.loc)
6386 emitLocationInfo(loc);
6397 if (!portInfo.
size()) {
6399 SmallPtrSet<Operation *, 8> moduleOpSet;
6400 moduleOpSet.insert(module);
6401 emitLocationInfoAndNewLine(moduleOpSet);
6404 ps <<
");" << PP::newline;
6405 setPendingNewline();
6409void ModuleEmitter::emitHWModule(
HWModuleOp module) {
6410 currentModuleOp =
module;
6412 emitComment(module.getCommentAttr());
6413 emitSVAttributes(module);
6415 ps.addCallback({module,
true});
6419 emitParameters(module, module.getParameters());
6423 assert(state.pendingNewline);
6426 StmtEmitter(*
this, state.options).emitStatementBlock(*module.getBodyBlock());
6429 ps.addCallback({module,
false});
6431 setPendingNewline();
6433 currentModuleOp =
nullptr;
6436void ModuleEmitter::emitFunc(FuncOp func) {
6438 if (func.isDeclaration())
6441 currentModuleOp = func;
6443 ps.addCallback({func,
true});
6447 StmtEmitter(*
this, state.options).emitStatementBlock(*func.getBodyBlock());
6449 ps <<
"endfunction";
6451 currentModuleOp =
nullptr;
6460 explicit FileEmitter(VerilogEmitterState &state) : EmitterBase(state) {}