19 #include "../PassDetail.h"
39 #include "mlir/IR/BuiltinOps.h"
40 #include "mlir/IR/ImplicitLocOpBuilder.h"
41 #include "mlir/IR/Location.h"
42 #include "mlir/IR/Threading.h"
43 #include "mlir/Interfaces/FunctionImplementation.h"
44 #include "mlir/Pass/PassManager.h"
45 #include "mlir/Support/FileUtilities.h"
46 #include "llvm/ADT/MapVector.h"
47 #include "llvm/ADT/STLExtras.h"
48 #include "llvm/ADT/StringSet.h"
49 #include "llvm/ADT/TypeSwitch.h"
50 #include "llvm/Support/FileSystem.h"
51 #include "llvm/Support/FormattedStream.h"
52 #include "llvm/Support/Path.h"
53 #include "llvm/Support/SaveAndRestore.h"
54 #include "llvm/Support/ToolOutputFile.h"
55 #include "llvm/Support/raw_ostream.h"
57 using namespace circt;
62 using namespace ExportVerilog;
64 using namespace pretty;
66 #define DEBUG_TYPE "export-verilog"
74 enum VerilogPrecedence {
95 enum SubExprSignResult { IsSigned, IsUnsigned };
101 VerilogPrecedence precedence;
104 SubExprSignResult signedness;
106 SubExprInfo(VerilogPrecedence precedence, SubExprSignResult signedness)
107 : precedence(precedence), signedness(signedness) {}
117 return Builder(ctx).getI32IntegerAttr(value);
120 static TypedAttr
getIntAttr(MLIRContext *ctx, Type t,
const APInt &value) {
121 return Builder(ctx).getIntegerAttr(t, value);
137 if (isa<VerbatimExprOp>(op)) {
138 if (op->getNumOperands() == 0 &&
139 op->getAttrOfType<StringAttr>(
"format_string").getValue().size() <= 32)
144 if (isa<XMRRefOp>(op))
148 if (isa<MacroRefExprOp>(op))
158 if (op->getNumOperands() == 0)
162 if (isa<comb::ExtractOp, hw::StructExtractOp, hw::UnionExtractOp>(op))
166 if (
auto array = dyn_cast<hw::ArrayGetOp>(op)) {
167 auto *indexOp = array.getIndex().getDefiningOp();
168 if (!indexOp || isa<ConstantOp>(indexOp))
170 if (
auto read = dyn_cast<ReadInOutOp>(indexOp)) {
171 auto *readSrc = read.getInput().getDefiningOp();
173 return !readSrc || isa<sv::WireOp, LogicOp>(readSrc);
188 if (
auto attr = symOp->getAttrOfType<StringAttr>(
"hw.verilogName"))
189 return attr.getValue();
190 return TypeSwitch<Operation *, StringRef>(symOp)
191 .Case<HWModuleOp, HWModuleExternOp, HWModuleGeneratedOp, HWTestModuleOp>(
193 .Case<InterfaceOp>([&](InterfaceOp op) {
196 .Case<InterfaceSignalOp>(
197 [&](InterfaceSignalOp op) {
return op.getSymName(); })
198 .Case<InterfaceModportOp>(
199 [&](InterfaceModportOp op) {
return op.getSymName(); })
200 .Default([&](Operation *op) {
201 if (
auto attr = op->getAttrOfType<StringAttr>(
"name"))
202 return attr.getValue();
203 if (
auto attr = op->getAttrOfType<StringAttr>(
"instanceName"))
204 return attr.getValue();
205 if (
auto attr = op->getAttrOfType<StringAttr>(
"sv.namehint"))
206 return attr.getValue();
208 op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()))
209 return attr.getValue();
210 return StringRef(
"");
215 template <
typename PPS>
217 os <<
"/*Zero width*/ 1\'b0";
221 char verilogNameAttr[] =
"hw.verilogName";
223 if (
auto updatedName = port.attrs.get(verilogNameAttr))
224 return updatedName.cast<StringAttr>().getValue();
230 if (
auto htmo = dyn_cast<HWTestModuleOp>(module))
234 char verilogNameAttr[] =
"hw.verilogName";
235 auto portAttr = cast<HWModuleLike>(module).getAllPortAttrs();
236 if (
auto portDict = cast_or_null<DictionaryAttr>(portAttr[portArgNum]))
237 if (
auto updatedName = portDict.get(verilogNameAttr))
238 return updatedName.cast<StringAttr>().getValue();
240 return cast<HWModuleLike>(module).getPortName(portArgNum);
249 if (isa<ReadInOutOp, AggregateConstantOp, ArrayIndexInOutOp,
250 IndexedPartSelectInOutOp, StructFieldInOutOp, IndexedPartSelectOp,
251 ParamValueOp, XMROp, XMRRefOp, SampledOp, EnumConstantOp,
252 SystemFunctionOp>(op))
262 static void getTypeDims(SmallVectorImpl<Attribute> &dims, Type type,
264 if (
auto integer = hw::type_dyn_cast<IntegerType>(type)) {
265 if (integer.getWidth() != 1)
266 dims.push_back(
getInt32Attr(type.getContext(), integer.getWidth()));
269 if (
auto array = hw::type_dyn_cast<ArrayType>(type)) {
270 dims.push_back(
getInt32Attr(type.getContext(), array.getNumElements()));
275 if (
auto intType = hw::type_dyn_cast<IntType>(type)) {
276 dims.push_back(intType.getWidth());
280 if (
auto inout = hw::type_dyn_cast<InOutType>(type))
281 return getTypeDims(dims, inout.getElementType(), loc);
282 if (
auto uarray = hw::type_dyn_cast<hw::UnpackedArrayType>(type))
283 return getTypeDims(dims, uarray.getElementType(), loc);
284 if (hw::type_isa<InterfaceType, StructType, EnumType>(type))
287 mlir::emitError(loc,
"value has an unsupported verilog type ") << type;
293 SmallVector<Attribute, 4> aDims;
296 SmallVector<Attribute, 4> bDims;
299 return aDims == bDims;
305 if (
auto intType = type.dyn_cast<IntegerType>())
306 return intType.getWidth() == 0;
309 if (
auto uarray = type.dyn_cast<hw::UnpackedArrayType>())
310 return uarray.getNumElements() == 0 ||
312 if (
auto array = type.dyn_cast<hw::ArrayType>())
313 return array.getNumElements() == 0 ||
isZeroBitType(array.getElementType());
314 if (
auto structType = type.dyn_cast<hw::StructType>())
315 return llvm::all_of(structType.getElements(),
316 [](
auto elem) { return isZeroBitType(elem.type); });
317 if (
auto enumType = type.dyn_cast<hw::EnumType>())
318 return enumType.getFields().empty();
319 if (
auto unionType = type.dyn_cast<hw::UnionType>())
332 return TypeSwitch<Type, Type>(type)
336 .Case<UnpackedArrayType>([](UnpackedArrayType arrayType) {
339 .Default([](Type type) {
return type; });
344 return TypeSwitch<Type, bool>(type)
345 .Case<
InOutType, UnpackedArrayType, ArrayType>([](
auto parentType) {
348 .Case<StructType>([](
auto) {
return true; })
349 .Default([](
auto) {
return false; });
356 if (isa<RegOp>(op)) {
361 op->getResult(0).getType().cast<
InOutType>().getElementType();
369 while (
innerType.getElementType().isa<ArrayType>())
371 if (
innerType.getElementType().isa<StructType>() ||
372 innerType.getElementType().isa<TypeAliasType>())
380 if (isa<sv::WireOp>(op))
382 if (isa<ConstantOp, AggregateConstantOp, LocalParamOp, ParamValueOp>(op))
386 if (
auto interface = dyn_cast<InterfaceInstanceOp>(op))
387 return interface.getInterfaceType().getInterface().getValue();
391 bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
393 if (isa<LogicOp>(op)) {
400 return hasStruct ?
"automatic" :
"automatic logic";
401 return hasStruct ?
"" :
"logic";
412 return hasStructType(op->getResult(0).getType()) ?
"automatic"
422 static int compareLocs(Location lhs, Location rhs);
426 if (
auto name = lhs.getName().compare(rhs.getName()))
428 return compareLocs(lhs.getChildLoc(), rhs.getChildLoc());
433 if (
auto fn = lhs.getFilename().compare(rhs.getFilename()))
435 if (lhs.getLine() != rhs.getLine())
436 return lhs.getLine() < rhs.getLine() ? -1 : 1;
437 return lhs.getColumn() < rhs.getColumn() ? -1 : 1;
442 Location lhsCallee = lhs.getCallee();
443 Location rhsCallee = rhs.getCallee();
447 Location lhsCaller = lhs.getCaller();
448 Location rhsCaller = rhs.getCaller();
452 template <
typename TTargetLoc>
454 auto lhsT = dyn_cast<TTargetLoc>(lhs);
455 auto rhsT = dyn_cast<TTargetLoc>(rhs);
482 if (
auto res = dispatchCompareLocations<mlir::FileLineColLoc>(lhs, rhs);
487 if (
auto res = dispatchCompareLocations<mlir::NameLoc>(lhs, rhs);
492 if (
auto res = dispatchCompareLocations<mlir::CallSiteLoc>(lhs, rhs);
509 SmallPtrSetImpl<Attribute> &locationSet) {
510 llvm::TypeSwitch<Location, void>(loc)
511 .Case<FusedLoc>([&](
auto fusedLoc) {
512 for (
auto subLoc : fusedLoc.getLocations())
515 .Default([&](
auto loc) { locationSet.insert(loc); });
519 template <
typename TVector>
521 llvm::array_pod_sort(
522 vec.begin(), vec.end(), [](
const auto *lhs,
const auto *rhs) ->
int {
523 return compareLocs(cast<Location>(*lhs), cast<Location>(*rhs));
531 SmallPtrSet<Attribute, 8> locationSet;
532 locationSet.insert(loc);
533 llvm::raw_string_ostream os(output);
534 emitLocationSetInfo(os, style, locationSet);
539 const SmallPtrSetImpl<Operation *> &ops) {
543 SmallPtrSet<Attribute, 8> locationSet;
546 llvm::raw_string_ostream os(output);
547 emitLocationSetInfo(os, style, locationSet);
555 const SmallPtrSetImpl<Attribute> &locationSet) {
556 if (style == LoweringOptions::LocationInfoStyle::None)
559 llvm::raw_string_ostream sstr(resstr);
561 if (resstr.empty() || style == LoweringOptions::LocationInfoStyle::Plain) {
565 assert(style == LoweringOptions::LocationInfoStyle::WrapInAtSquareBracket &&
566 "other styles must be already handled");
567 os <<
"@[" << resstr <<
"]";
576 const SmallPtrSetImpl<Attribute> &locationSet)
577 : os(os), style(style) {
578 emitLocationSetInfoImpl(locationSet);
584 emitLocationInfo(loc.getCallee());
586 emitLocationInfo(loc.getCaller());
592 bool withName = !loc.getName().empty();
594 os <<
"'" << loc.getName().strref() <<
"'(";
595 emitLocationInfo(loc.getChildLoc());
603 os << loc.getFilename().getValue();
604 if (
auto line = loc.getLine()) {
606 if (
auto col = loc.getColumn())
618 StringRef lastFileName;
619 for (
size_t i = 0, e = locVector.size(); i != e;) {
624 auto first = locVector[i];
625 if (first.getFilename() != lastFileName) {
626 lastFileName = first.getFilename();
633 first.getFilename() == locVector[
end].getFilename() &&
634 first.getLine() == locVector[
end].getLine())
639 if (
auto line = first.getLine()) {
641 if (
auto col = first.getColumn())
649 os <<
':' << first.getLine() <<
":{";
651 os << locVector[i++].getColumn();
663 llvm::TypeSwitch<Location, void>(loc)
664 .Case<mlir::CallSiteLoc, mlir::NameLoc, mlir::FileLineColLoc>(
665 [&](
auto loc) { emitLocationInfo(loc); })
666 .Case<mlir::FusedLoc>([&](
auto loc) {
667 SmallPtrSet<Attribute, 8> locationSet;
669 emitLocationSetInfoImpl(locationSet);
671 .Default([&](
auto loc) {
683 switch (locationSet.size()) {
685 emitLocationInfo(cast<LocationAttr>(*locationSet.begin()));
694 SmallVector<FileLineColLoc, 8> flcLocs;
695 SmallVector<Attribute, 8> otherLocs;
696 flcLocs.reserve(locationSet.size());
697 otherLocs.reserve(locationSet.size());
698 for (Attribute loc : locationSet) {
699 if (
auto flcLoc = loc.dyn_cast<FileLineColLoc>())
700 flcLocs.push_back(flcLoc);
702 otherLocs.push_back(loc);
713 size_t sstrSize = os.tell();
714 bool emittedAnything =
false;
715 auto recheckEmittedSomething = [&]() {
716 size_t currSize = os.tell();
717 bool emittedSomethingSinceLastCheck = currSize != sstrSize;
718 emittedAnything |= emittedSomethingSinceLastCheck;
720 return emittedSomethingSinceLastCheck;
727 [&](Attribute loc) { emitLocationInfo(cast<LocationAttr>(loc)); },
729 if (recheckEmittedSomething()) {
731 recheckEmittedSomething();
737 if (emittedAnything && !flcLocs.empty())
740 printFileLineColSetInfo(flcLocs);
742 llvm::raw_string_ostream &
os;
754 if (v.isa<BlockArgument>())
759 if (
auto read = v.getDefiningOp<ReadInOutOp>())
763 if (isa_and_nonnull<StructExtractOp, UnionExtractOp, ArrayGetOp>(
768 if (v.getDefiningOp<ReadInterfaceSignalOp>())
781 if (
auto cast = dyn_cast<BitcastOp>(op))
782 if (!
haveMatchingDims(cast.getInput().getType(), cast.getResult().getType(),
786 if (op->hasOneUse() &&
787 isa<comb::ConcatOp, hw::ArrayConcatOp>(*op->getUsers().begin()))
795 if (isa<StructCreateOp, UnionCreateOp>(op))
800 if (
auto aggConstantOp = dyn_cast<AggregateConstantOp>(op))
804 if (
auto verbatim = dyn_cast<VerbatimExprOp>(op))
805 if (verbatim.getFormatString().size() > 32)
810 for (
auto *user : op->getUsers()) {
818 if (isa<ExtractOp, ArraySliceOp, ArrayGetOp, StructExtractOp,
819 UnionExtractOp, IndexedPartSelectOp>(user))
820 if (op->getResult(0) == user->getOperand(0) &&
827 if (
auto read = dyn_cast<ReadInOutOp>(op))
828 if (read.getInput().getDefiningOp<sv::WireOp>() ||
829 read.getInput().getDefiningOp<RegOp>())
841 unsigned numStatements = 0;
842 block.walk([&](Operation *op) {
844 return WalkResult::advance();
846 TypeSwitch<Operation *, unsigned>(op)
847 .Case<VerbatimOp>([&](
auto) {
853 .Case<IfOp>([&](
auto) {
864 .Case<IfDefOp, IfDefProceduralOp>([&](
auto) { return 3; })
865 .Case<OutputOp>([&](OutputOp oop) {
868 return llvm::count_if(oop->getOperands(), [&](auto operand) {
869 return !operand.hasOneUse() ||
870 !dyn_cast_or_null<InstanceOp>(operand.getDefiningOp());
873 .Default([](
auto) {
return 1; });
874 if (numStatements > 1)
875 return WalkResult::interrupt();
876 return WalkResult::advance();
878 if (numStatements == 0)
880 if (numStatements == 1)
890 if (op->getResult(0).use_empty())
895 if (op->hasOneUse() &&
896 isa<hw::OutputOp, sv::AssignOp, sv::BPAssignOp, sv::PAssignOp>(
897 *op->getUsers().begin()))
919 for (
auto &op : *elseBlock) {
920 if (
auto opIf = dyn_cast<IfOp>(op)) {
937 template <
typename PPS>
939 enum Container { NoContainer, InComment, InAttr };
940 Container currentContainer = NoContainer;
942 auto closeContainer = [&] {
943 if (currentContainer == NoContainer)
945 if (currentContainer == InComment)
947 else if (currentContainer == InAttr)
949 ps << PP::end << PP::end;
951 currentContainer = NoContainer;
954 bool isFirstContainer =
true;
955 auto openContainer = [&](Container newContainer) {
956 assert(newContainer != NoContainer);
957 if (currentContainer == newContainer)
961 if (!isFirstContainer)
962 ps << (mayBreak ? PP::space : PP::nbsp);
963 isFirstContainer =
false;
966 if (newContainer == InComment)
968 else if (newContainer == InAttr)
970 currentContainer = newContainer;
978 ps.scopedBox(PP::cbox0, [&]() {
979 for (
auto attr : attrs.getAsRange<SVAttributeAttr>()) {
980 if (!openContainer(attr.getEmitAsComment().getValue() ? InComment
982 ps <<
"," << (mayBreak ? PP::space : PP::nbsp);
984 if (attr.getExpression())
985 ps <<
" = " <<
PPExtString(attr.getExpression().getValue());
994 if (
auto *op = val.getDefiningOp())
997 if (
auto port = val.dyn_cast<BlockArgument>()) {
999 if (
auto forOp = dyn_cast<ForOp>(port.getParentBlock()->getParentOp()))
1000 return forOp->getAttrOfType<StringAttr>(
"hw.verilogName");
1002 port.getArgNumber());
1004 assert(
false &&
"unhandled value");
1016 class VerilogEmitterState {
1018 explicit VerilogEmitterState(ModuleOp designOp,
1021 const HWSymbolCache &symbolCache,
1023 llvm::formatted_raw_ostream &os,
1024 StringAttr fileName,
OpLocMap &verilogLocMap)
1025 : designOp(designOp), shared(shared), options(options),
1026 symbolCache(symbolCache), globalNames(globalNames), os(os),
1027 verilogLocMap(verilogLocMap), pp(os, options.emittedLineLength),
1028 fileName(fileName) {
1029 pp.setListener(&saver);
1040 const HWSymbolCache &symbolCache;
1049 llvm::formatted_raw_ostream &os;
1051 bool encounteredError =
false;
1052 unsigned currentIndent = 0;
1061 bool pendingNewline =
false;
1075 StringAttr fileName;
1081 void addVerilogLocToOps(
unsigned int lineOffset, StringAttr fileName) {
1084 verilogLocMap.
clear();
1088 VerilogEmitterState(
const VerilogEmitterState &) =
delete;
1089 void operator=(
const VerilogEmitterState &) =
delete;
1102 using CallbackDataTy = std::pair<Operation *, bool>;
1106 VerilogEmitterState &state;
1111 explicit EmitterBase(VerilogEmitterState &state)
1113 ps(state.pp, state.saver, state.options.emitVerilogLocations) {}
1115 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
1116 state.encounteredError =
true;
1117 return op->emitError(message);
1120 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
1121 state.encounteredError =
true;
1122 return op->emitOpError(message);
1125 void emitLocationImpl(llvm::StringRef location) {
1128 ps << PP::neverbreak;
1129 if (!location.empty())
1130 ps <<
"\t// " << location;
1133 void emitLocationInfo(Location loc) {
1141 void emitLocationInfoAndNewLine(
const SmallPtrSetImpl<Operation *> &ops) {
1144 setPendingNewline();
1147 template <
typename PPS>
1148 void emitTextWithSubstitutions(PPS &ps, StringRef
string, Operation *op,
1149 llvm::function_ref<
void(Value)> operandEmitter,
1150 ArrayAttr symAttrs);
1156 void emitComment(StringAttr comment);
1160 void emitPendingNewlineIfNeeded() {
1161 if (state.pendingNewline) {
1162 state.pendingNewline =
false;
1166 void setPendingNewline() {
1167 assert(!state.pendingNewline);
1168 state.pendingNewline =
true;
1171 void startStatement() { emitPendingNewlineIfNeeded(); }
1174 void operator=(
const EmitterBase &) =
delete;
1175 EmitterBase(
const EmitterBase &) =
delete;
1179 template <
typename PPS>
1180 void EmitterBase::emitTextWithSubstitutions(
1181 PPS &ps, StringRef
string, Operation *op,
1182 llvm::function_ref<
void(Value)> operandEmitter, ArrayAttr symAttrs) {
1186 auto namify = [&](Attribute sym, HWSymbolCache::Item item) {
1193 if (
auto *itemOp = item.getOp()) {
1194 if (item.hasPort()) {
1198 if (!symOpName.empty())
1200 emitError(itemOp,
"cannot get name for symbol ") << sym;
1202 emitError(op,
"cannot get name for symbol ") << sym;
1204 return StringRef(
"<INVALID>");
1210 unsigned numSymOps = symAttrs.size();
1211 auto emitUntilSubstitution = [&](
size_t next = 0) ->
bool {
1214 next =
string.find(
"{{", next);
1215 if (next == StringRef::npos)
1222 while (next <
string.
size() &&
isdigit(
string[next]))
1225 if (start == next) {
1231 if (!
string.substr(next).startswith(
"}}"))
1235 unsigned operandNo = 0;
1236 if (
string.drop_front(start)
1237 .take_front(next - start)
1238 .getAsInteger(10, operandNo)) {
1239 emitError(op,
"operand substitution too large");
1245 auto before =
string.take_front(start - 2);
1246 if (!before.empty())
1251 if (operandNo < op->getNumOperands())
1253 operandEmitter(op->getOperand(operandNo));
1254 else if ((operandNo - op->getNumOperands()) < numSymOps) {
1255 unsigned symOpNum = operandNo - op->getNumOperands();
1256 auto sym = symAttrs[symOpNum];
1257 StringRef symVerilogName;
1258 if (
auto fsym = sym.dyn_cast<FlatSymbolRefAttr>()) {
1259 if (
auto *symOp = state.symbolCache.getDefinition(fsym)) {
1260 if (
auto globalRef = dyn_cast<HierPathOp>(symOp)) {
1261 auto namepath = globalRef.getNamepathAttr().getValue();
1262 for (
auto [index, sym] : llvm::enumerate(namepath)) {
1266 auto innerRef = cast<InnerRefAttr>(sym);
1267 auto ref = state.symbolCache.getInnerDefinition(
1268 innerRef.getModule(), innerRef.getName());
1269 ps << namify(innerRef, ref);
1272 symVerilogName = namify(sym, symOp);
1275 }
else if (
auto isym = sym.dyn_cast<InnerRefAttr>()) {
1276 auto symOp = state.symbolCache.getInnerDefinition(isym.getModule(),
1278 symVerilogName = namify(sym, symOp);
1280 if (!symVerilogName.empty())
1283 emitError(op,
"operand " + llvm::utostr(operandNo) +
" isn't valid");
1287 string =
string.drop_front(next);
1293 while (emitUntilSubstitution())
1297 if (!
string.
empty())
1301 void EmitterBase::emitComment(StringAttr comment) {
1308 auto lineLength = state.options.emittedLineLength - state.currentIndent - 3;
1309 if (lineLength > state.options.emittedLineLength)
1314 auto ref = comment.getValue();
1316 while (!ref.empty()) {
1317 std::tie(line, ref) = ref.split(
"\n");
1324 if (line.size() <= lineLength) {
1326 setPendingNewline();
1337 auto breakPos = line.rfind(
' ', lineLength);
1339 if (breakPos == StringRef::npos) {
1340 breakPos = line.find(
' ', lineLength);
1343 if (breakPos == StringRef::npos)
1344 breakPos = line.size();
1351 setPendingNewline();
1352 breakPos = line.find_first_not_of(
' ', breakPos);
1354 if (breakPos == StringRef::npos)
1357 line = line.drop_front(breakPos);
1367 bool addPrefixUnderScore =
true;
1370 if (
auto read = expr.getDefiningOp<ReadInOutOp>())
1374 if (
auto blockArg = expr.dyn_cast<BlockArgument>()) {
1375 auto moduleOp = cast<HWModuleOp>(blockArg.getOwner()->getParentOp());
1379 }
else if (
auto *op = expr.getDefiningOp()) {
1381 if (isa<sv::WireOp, RegOp, LogicOp>(op)) {
1385 }
else if (
auto nameHint = op->getAttrOfType<StringAttr>(
"sv.namehint")) {
1391 addPrefixUnderScore =
false;
1393 TypeSwitch<Operation *>(op)
1396 .Case([&result](VerbatimExprOp verbatim) {
1397 verbatim.getAsmResultNames([&](Value, StringRef name) {
1401 .Case([&result](VerbatimExprSEOp verbatim) {
1402 verbatim.getAsmResultNames([&](Value, StringRef name) {
1408 .Case([&result](ExtractOp extract) {
1409 if (
auto operandName =
1412 extract.getType().cast<IntegerType>().getWidth();
1415 operandName.strref() +
"_" +
1416 Twine(extract.getLowBit()));
1419 extract.getContext(),
1420 operandName.strref() +
"_" +
1421 Twine(extract.getLowBit() + numBits - 1) +
"to" +
1422 Twine(extract.getLowBit()));
1430 if (!result || result.strref().empty())
1434 if (addPrefixUnderScore && result.strref().front() !=
'_')
1447 class ModuleEmitter :
public EmitterBase {
1449 explicit ModuleEmitter(VerilogEmitterState &state)
1450 : EmitterBase(state),
1454 emitPendingNewlineIfNeeded();
1458 void emitParameters(Operation *module, ArrayAttr params);
1459 void emitPortList(Operation *module,
const ModulePortInfo &portInfo);
1461 void emitHWModule(HWModuleOp module);
1462 void emitHWTestModule(HWTestModuleOp module);
1463 void emitHWExternModule(HWModuleExternOp module);
1464 void emitHWGeneratedModule(HWModuleGeneratedOp module);
1467 void emitStatement(Operation *op);
1468 void emitBind(BindOp op);
1469 void emitBindInterface(BindInterfaceOp op);
1471 void emitSVAttributes(Operation *op);
1474 StringRef getVerilogStructFieldName(StringAttr field) {
1475 return fieldNameResolver.getRenamedFieldName(field).getValue();
1482 void emitTypeDims(Type type, Location loc, raw_ostream &os);
1494 bool printPackedType(Type type, raw_ostream &os, Location loc,
1495 Type optionalAliasType = {},
bool implicitIntType =
true,
1496 bool singleBitDefaultType =
true);
1500 void printUnpackedTypePostfix(Type type, raw_ostream &os);
1508 function_ref<InFlightDiagnostic()> emitError);
1511 VerilogPrecedence parenthesizeIfLooserThan,
1512 function_ref<InFlightDiagnostic()> emitError);
1518 Operation *currentModuleOp;
1524 SmallPtrSet<Operation *, 16> expressionsEmittedIntoDecl;
1530 SmallPtrSet<Operation *, 16> assignsInlined;
1539 static void emitDims(ArrayRef<Attribute> dims, raw_ostream &os, Location loc,
1540 ModuleEmitter &emitter) {
1541 for (Attribute
width : dims) {
1543 os <<
"<<invalid type>>";
1546 if (
auto intAttr =
width.dyn_cast<IntegerAttr>()) {
1547 if (intAttr.getValue().isZero())
1548 os <<
"/*Zero Width*/";
1550 os <<
'[' << (intAttr.getValue().getZExtValue() - 1) <<
":0]";
1556 auto typedAttr =
width.dyn_cast<TypedAttr>();
1558 mlir::emitError(loc,
"untyped dimension attribute ") <<
width;
1562 loc.getContext(), typedAttr.getType(),
1563 APInt(typedAttr.getType().getIntOrFloatBitWidth(), -1L,
true));
1566 emitter.printParamValue(
width, os, [loc]() {
1567 return mlir::emitError(loc,
"invalid parameter in type");
1574 void ModuleEmitter::emitTypeDims(Type type, Location loc, raw_ostream &os) {
1575 SmallVector<Attribute, 4> dims;
1590 SmallVectorImpl<Attribute> &dims,
1591 bool implicitIntType,
bool singleBitDefaultType,
1592 ModuleEmitter &emitter,
1593 Type optionalAliasType = {}) {
1594 return TypeSwitch<Type, bool>(type)
1595 .Case<IntegerType>([&](IntegerType integerType) {
1596 if (!implicitIntType)
1598 if (integerType.getWidth() != 1 || !singleBitDefaultType)
1600 getInt32Attr(type.getContext(), integerType.getWidth()));
1601 if (!dims.empty() && !implicitIntType)
1605 return !dims.empty() || !implicitIntType;
1607 .Case<IntType>([&](IntType intType) {
1608 if (!implicitIntType)
1610 dims.push_back(intType.getWidth());
1614 .Case<ArrayType>([&](ArrayType arrayType) {
1615 dims.push_back(arrayType.getSizeAttr());
1617 implicitIntType, singleBitDefaultType,
1620 .Case<InOutType>([&](
InOutType inoutType) {
1622 implicitIntType, singleBitDefaultType,
1625 .Case<EnumType>([&](EnumType enumType) {
1627 if (enumType.getBitWidth() != 32)
1628 os <<
"bit [" << enumType.getBitWidth() - 1 <<
":0] ";
1630 Type enumPrefixType = optionalAliasType ? optionalAliasType : enumType;
1631 llvm::interleaveComma(
1632 enumType.getFields().getAsRange<StringAttr>(), os,
1633 [&](
auto enumerator) {
1634 os << emitter.fieldNameResolver.getEnumFieldName(
1635 hw::EnumFieldAttr::get(loc, enumerator, enumPrefixType));
1640 .Case<StructType>([&](StructType structType) {
1641 if (structType.getElements().empty() ||
isZeroBitType(structType)) {
1642 os <<
"/*Zero Width*/";
1645 os <<
"struct packed {";
1646 for (
auto &element : structType.getElements()) {
1648 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1649 <<
": Zero Width;*/ ";
1652 SmallVector<Attribute, 8> structDims;
1657 os <<
' ' << emitter.getVerilogStructFieldName(element.name);
1658 emitter.printUnpackedTypePostfix(element.type, os);
1665 .Case<UnionType>([&](UnionType unionType) {
1666 if (unionType.getElements().empty() ||
isZeroBitType(unionType)) {
1667 os <<
"/*Zero Width*/";
1672 os <<
"union packed {";
1673 for (
auto &element : unionType.getElements()) {
1675 os <<
"/*" << emitter.getVerilogStructFieldName(element.name)
1676 <<
": Zero Width;*/ ";
1680 bool needsPadding = elementWidth < unionWidth || element.offset > 0;
1682 os <<
" struct packed {";
1683 if (element.offset) {
1684 os <<
"logic [" << element.offset - 1 <<
":0] "
1685 <<
"__pre_padding_" << element.name.getValue() <<
"; ";
1689 SmallVector<Attribute, 8> structDims;
1694 os <<
' ' << emitter.getVerilogStructFieldName(element.name);
1695 emitter.printUnpackedTypePostfix(element.type, os);
1699 if (elementWidth + (int64_t)element.offset < unionWidth) {
1701 << unionWidth - (elementWidth + element.offset) - 1 <<
":0] "
1702 <<
"__post_padding_" << element.name.getValue() <<
";";
1704 os <<
"} " << emitter.getVerilogStructFieldName(element.name)
1713 .Case<InterfaceType>([](InterfaceType ifaceType) {
return false; })
1714 .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1715 os <<
"<<unexpected unpacked array>>";
1716 mlir::emitError(loc,
"Unexpected unpacked array in packed type ")
1720 .Case<TypeAliasType>([&](TypeAliasType typeRef) {
1721 auto typedecl = typeRef.getTypeDecl(emitter.state.symbolCache);
1723 mlir::emitError(loc,
"unresolvable type reference");
1726 if (typedecl.getType() != typeRef.getInnerType()) {
1727 mlir::emitError(loc,
"declared type did not match aliased type");
1731 os << typedecl.getPreferredName();
1732 emitDims(dims, os, typedecl->getLoc(), emitter);
1735 .Default([&](Type type) {
1736 os <<
"<<invalid type '" << type <<
"'>>";
1737 mlir::emitError(loc,
"value has an unsupported verilog type ") << type;
1751 bool ModuleEmitter::printPackedType(Type type, raw_ostream &os, Location loc,
1752 Type optionalAliasType,
1753 bool implicitIntType,
1754 bool singleBitDefaultType) {
1755 SmallVector<Attribute, 8> packedDimensions;
1757 singleBitDefaultType, *
this, optionalAliasType);
1763 void ModuleEmitter::printUnpackedTypePostfix(Type type, raw_ostream &os) {
1764 TypeSwitch<Type, void>(type)
1766 printUnpackedTypePostfix(inoutType.getElementType(), os);
1768 .Case<UnpackedArrayType>([&](UnpackedArrayType arrayType) {
1769 os <<
"[0:" << (arrayType.getNumElements() - 1) <<
"]";
1770 printUnpackedTypePostfix(arrayType.getElementType(), os);
1772 .Case<InterfaceType>([&](
auto) {
1787 function_ref<InFlightDiagnostic()> emitError) {
1788 return printParamValue(value, os, VerilogPrecedence::LowestPrecedence,
1797 VerilogPrecedence parenthesizeIfLooserThan,
1798 function_ref<InFlightDiagnostic()> emitError) {
1799 if (
auto intAttr = value.dyn_cast<IntegerAttr>()) {
1800 IntegerType intTy = intAttr.getType().cast<IntegerType>();
1801 APInt value = intAttr.getValue();
1805 if (intTy.getWidth() > 32) {
1807 if (value.isNegative() && (intTy.isSigned() || intTy.isSignless())) {
1811 if (intTy.isSigned())
1812 os << intTy.getWidth() <<
"'sd";
1814 os << intTy.getWidth() <<
"'d";
1816 value.print(os, intTy.isSigned());
1817 return {Symbol, intTy.isSigned() ? IsSigned : IsUnsigned};
1819 if (
auto strAttr = value.dyn_cast<StringAttr>()) {
1821 os.write_escaped(strAttr.getValue());
1823 return {Symbol, IsUnsigned};
1825 if (
auto fpAttr = value.dyn_cast<FloatAttr>()) {
1827 os << fpAttr.getValueAsDouble();
1828 return {Symbol, IsUnsigned};
1830 if (
auto verbatimParam = value.dyn_cast<ParamVerbatimAttr>()) {
1831 os << verbatimParam.getValue().getValue();
1832 return {Symbol, IsUnsigned};
1834 if (
auto parameterRef = value.dyn_cast<ParamDeclRefAttr>()) {
1836 os << state.globalNames.getParameterVerilogName(currentModuleOp,
1837 parameterRef.getName());
1840 return {Symbol, IsUnsigned};
1844 auto expr = value.dyn_cast<ParamExprAttr>();
1846 os <<
"<<UNKNOWN MLIRATTR: " << value <<
">>";
1847 emitError() <<
" = " << value;
1848 return {LowestPrecedence, IsUnsigned};
1851 StringRef operatorStr;
1852 StringRef openStr, closeStr;
1853 VerilogPrecedence subprecedence = LowestPrecedence;
1854 VerilogPrecedence prec;
1855 std::optional<SubExprSignResult> operandSign;
1856 bool isUnary =
false;
1857 bool hasOpenClose =
false;
1859 switch (expr.getOpcode()) {
1861 operatorStr =
" + ";
1862 subprecedence = Addition;
1865 operatorStr =
" * ";
1866 subprecedence = Multiply;
1869 operatorStr =
" & ";
1870 subprecedence = And;
1873 operatorStr =
" | ";
1877 operatorStr =
" ^ ";
1878 subprecedence = Xor;
1881 operatorStr =
" << ";
1882 subprecedence = Shift;
1886 operatorStr =
" >> ";
1887 subprecedence = Shift;
1891 operatorStr =
" >>> ";
1892 subprecedence = Shift;
1893 operandSign = IsSigned;
1896 operatorStr =
" / ";
1897 subprecedence = Multiply;
1898 operandSign = IsUnsigned;
1901 operatorStr =
" / ";
1902 subprecedence = Multiply;
1903 operandSign = IsSigned;
1906 operatorStr =
" % ";
1907 subprecedence = Multiply;
1908 operandSign = IsUnsigned;
1911 operatorStr =
" % ";
1912 subprecedence = Multiply;
1913 operandSign = IsSigned;
1916 openStr =
"$clog2(";
1918 operandSign = IsUnsigned;
1919 hasOpenClose =
true;
1922 case PEO::StrConcat:
1925 hasOpenClose =
true;
1928 subprecedence = LowestPrecedence;
1933 prec = subprecedence;
1936 assert(!isUnary || llvm::hasSingleElement(expr.getOperands()));
1938 assert(isUnary || hasOpenClose ||
1939 !llvm::hasSingleElement(expr.getOperands()));
1946 auto emitOperand = [&](Attribute operand) ->
bool {
1948 auto subprec = operandSign.has_value() ? LowestPrecedence : subprecedence;
1949 if (operandSign.has_value())
1950 os << (*operandSign == IsSigned ?
"$signed(" :
"$unsigned(");
1953 if (operandSign.has_value()) {
1955 signedness = *operandSign;
1957 return signedness == IsSigned;
1961 if (prec > parenthesizeIfLooserThan)
1970 bool allOperandsSigned = emitOperand(expr.getOperands()[0]);
1971 for (
auto op : expr.getOperands().drop_front()) {
1974 if (expr.getOpcode() == PEO::Add) {
1975 if (
auto integer = op.dyn_cast<IntegerAttr>()) {
1976 const APInt &value = integer.getValue();
1977 if (value.isNegative() && !value.isMinSignedValue()) {
1979 allOperandsSigned &=
1987 allOperandsSigned &= emitOperand(op);
1991 if (prec > parenthesizeIfLooserThan) {
1995 return {prec, allOperandsSigned ? IsSigned : IsUnsigned};
2010 class ExprEmitter :
public EmitterBase,
2011 public TypeOpVisitor<ExprEmitter, SubExprInfo>,
2012 public CombinationalVisitor<ExprEmitter, SubExprInfo>,
2013 public Visitor<ExprEmitter, SubExprInfo> {
2017 ExprEmitter(ModuleEmitter &emitter,
2018 SmallPtrSetImpl<Operation *> &emittedExprs)
2019 : ExprEmitter(emitter, emittedExprs, localTokens) {}
2021 ExprEmitter(ModuleEmitter &emitter,
2022 SmallPtrSetImpl<Operation *> &emittedExprs,
2024 : EmitterBase(emitter.state), emitter(emitter),
2025 emittedExprs(emittedExprs), buffer(tokens),
2026 ps(buffer, state.saver, state.options.emitVerilogLocations) {
2027 assert(state.pp.getListener() == &state.saver);
2034 void emitExpression(Value exp, VerilogPrecedence parenthesizeIfLooserThan) {
2035 assert(localTokens.empty());
2037 ps.scopedBox(PP::ibox0, [&]() {
2038 emitSubExpr(exp, parenthesizeIfLooserThan,
2045 if (&buffer.tokens == &localTokens)
2046 buffer.flush(state.pp);
2050 friend class TypeOpVisitor<ExprEmitter, SubExprInfo>;
2051 friend class CombinationalVisitor<ExprEmitter, SubExprInfo>;
2052 friend class Visitor<ExprEmitter, SubExprInfo>;
2054 enum SubExprSignRequirement { NoRequirement, RequireSigned, RequireUnsigned };
2062 SubExprInfo emitSubExpr(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
2063 SubExprSignRequirement signReq = NoRequirement,
2064 bool isSelfDeterminedUnsignedValue =
false);
2068 void emitSVAttributes(Operation *op);
2070 SubExprInfo visitUnhandledExpr(Operation *op);
2071 SubExprInfo visitInvalidComb(Operation *op) {
2072 return dispatchTypeOpVisitor(op);
2074 SubExprInfo visitUnhandledComb(Operation *op) {
2075 return visitUnhandledExpr(op);
2077 SubExprInfo visitInvalidTypeOp(Operation *op) {
2078 return dispatchSVVisitor(op);
2080 SubExprInfo visitUnhandledTypeOp(Operation *op) {
2081 return visitUnhandledExpr(op);
2083 SubExprInfo visitUnhandledSV(Operation *op) {
return visitUnhandledExpr(op); }
2085 using Visitor::visitSV;
2088 enum EmitBinaryFlags {
2089 EB_RequireSignedOperands = RequireSigned,
2090 EB_RequireUnsignedOperands = RequireUnsigned,
2091 EB_OperandSignRequirementMask = 0x3,
2096 EB_RHS_UnsignedWithSelfDeterminedWidth = 0x4,
2100 EB_ForceResultSigned = 0x8,
2105 SubExprInfo emitBinary(Operation *op, VerilogPrecedence prec,
2106 const char *syntax,
unsigned emitBinaryFlags = 0);
2108 SubExprInfo emitUnary(Operation *op,
const char *syntax,
2109 bool resultAlwaysUnsigned =
false);
2112 void emitSubExprIBox2(
2113 Value v, VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence) {
2114 ps.scopedBox(PP::ibox2,
2115 [&]() { emitSubExpr(v, parenthesizeIfLooserThan); });
2120 template <
typename Container,
typename EachFn>
2121 void interleaveComma(
const Container &c, EachFn eachFn) {
2122 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
2127 void interleaveComma(ValueRange ops) {
2128 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
2145 template <
typename Container,
typename OpenFunc,
typename CloseFunc,
2147 void emitBracedList(
const Container &c, OpenFunc openFn, EachFunc eachFn,
2148 CloseFunc closeFn) {
2150 ps.scopedBox(PP::cbox0, [&]() {
2151 interleaveComma(c, eachFn);
2157 template <
typename OpenFunc,
typename CloseFunc>
2158 void emitBracedList(ValueRange ops, OpenFunc openFn, CloseFunc closeFn) {
2159 return emitBracedList(
2160 ops, openFn, [&](Value v) { emitSubExprIBox2(v); }, closeFn);
2164 void emitBracedList(ValueRange ops) {
2165 return emitBracedList(
2166 ops, [&]() { ps <<
"{"; }, [&]() { ps <<
"}"; });
2170 SubExprInfo printConstantScalar(APInt &value, IntegerType type);
2172 SubExprInfo visitSV(GetModportOp op);
2173 SubExprInfo visitSV(SystemFunctionOp op);
2174 SubExprInfo visitSV(ReadInterfaceSignalOp op);
2175 SubExprInfo visitSV(XMROp op);
2176 SubExprInfo visitSV(XMRRefOp op);
2177 SubExprInfo visitVerbatimExprOp(Operation *op, ArrayAttr symbols);
2178 SubExprInfo visitSV(VerbatimExprOp op) {
2179 return visitVerbatimExprOp(op, op.getSymbols());
2181 SubExprInfo visitSV(VerbatimExprSEOp op) {
2182 return visitVerbatimExprOp(op, op.getSymbols());
2184 SubExprInfo visitSV(MacroRefExprOp op);
2185 SubExprInfo visitSV(MacroRefExprSEOp op);
2186 template <
typename MacroTy>
2187 SubExprInfo emitMacroCall(MacroTy op);
2189 SubExprInfo visitSV(ConstantXOp op);
2190 SubExprInfo visitSV(ConstantZOp op);
2191 SubExprInfo visitSV(ConstantStrOp op);
2194 SubExprInfo visitSV(ReadInOutOp op) {
2195 auto result = emitSubExpr(op->getOperand(0), LowestPrecedence);
2196 emitSVAttributes(op);
2199 SubExprInfo visitSV(ArrayIndexInOutOp op);
2200 SubExprInfo visitSV(IndexedPartSelectInOutOp op);
2201 SubExprInfo visitSV(IndexedPartSelectOp op);
2202 SubExprInfo visitSV(StructFieldInOutOp op);
2205 SubExprInfo visitSV(SampledOp op);
2208 using TypeOpVisitor::visitTypeOp;
2209 SubExprInfo visitTypeOp(ConstantOp op);
2210 SubExprInfo visitTypeOp(AggregateConstantOp op);
2211 SubExprInfo visitTypeOp(BitcastOp op);
2212 SubExprInfo visitTypeOp(ParamValueOp op);
2213 SubExprInfo visitTypeOp(ArraySliceOp op);
2214 SubExprInfo visitTypeOp(ArrayGetOp op);
2215 SubExprInfo visitTypeOp(ArrayCreateOp op);
2216 SubExprInfo visitTypeOp(ArrayConcatOp op);
2217 SubExprInfo visitTypeOp(StructCreateOp op);
2218 SubExprInfo visitTypeOp(StructExtractOp op);
2219 SubExprInfo visitTypeOp(StructInjectOp op);
2220 SubExprInfo visitTypeOp(UnionCreateOp op);
2221 SubExprInfo visitTypeOp(UnionExtractOp op);
2222 SubExprInfo visitTypeOp(EnumCmpOp op);
2223 SubExprInfo visitTypeOp(EnumConstantOp op);
2226 using CombinationalVisitor::visitComb;
2227 SubExprInfo visitComb(MuxOp op);
2228 SubExprInfo visitComb(AddOp op) {
2229 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2230 return emitBinary(op, Addition,
"+");
2232 SubExprInfo visitComb(SubOp op) {
return emitBinary(op, Addition,
"-"); }
2233 SubExprInfo visitComb(MulOp op) {
2234 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2235 return emitBinary(op, Multiply,
"*");
2237 SubExprInfo visitComb(DivUOp op) {
2238 return emitBinary(op, Multiply,
"/", EB_RequireUnsignedOperands);
2240 SubExprInfo visitComb(DivSOp op) {
2241 return emitBinary(op, Multiply,
"/", EB_RequireSignedOperands);
2243 SubExprInfo visitComb(ModUOp op) {
2244 return emitBinary(op, Multiply,
"%", EB_RequireUnsignedOperands);
2246 SubExprInfo visitComb(ModSOp op) {
2247 return emitBinary(op, Multiply,
"%", EB_RequireSignedOperands);
2249 SubExprInfo visitComb(ShlOp op) {
2250 return emitBinary(op, Shift,
"<<", EB_RHS_UnsignedWithSelfDeterminedWidth);
2252 SubExprInfo visitComb(ShrUOp op) {
2254 return emitBinary(op, Shift,
">>", EB_RHS_UnsignedWithSelfDeterminedWidth);
2256 SubExprInfo visitComb(ShrSOp op) {
2259 return emitBinary(op, Shift,
">>>",
2260 EB_RequireSignedOperands | EB_ForceResultSigned |
2261 EB_RHS_UnsignedWithSelfDeterminedWidth);
2263 SubExprInfo visitComb(AndOp op) {
2264 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2265 return emitBinary(op, And,
"&");
2267 SubExprInfo visitComb(OrOp op) {
2268 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2269 return emitBinary(op, Or,
"|");
2271 SubExprInfo visitComb(XorOp op) {
2272 if (op.isBinaryNot())
2273 return emitUnary(op,
"~");
2274 assert(op.getNumOperands() == 2 &&
"prelowering should handle variadics");
2275 return emitBinary(op, Xor,
"^");
2280 SubExprInfo visitComb(ParityOp op) {
return emitUnary(op,
"^",
true); }
2282 SubExprInfo visitComb(ReplicateOp op);
2283 SubExprInfo visitComb(ConcatOp op);
2284 SubExprInfo visitComb(ExtractOp op);
2285 SubExprInfo visitComb(ICmpOp op);
2288 ModuleEmitter &emitter;
2295 SubExprSignRequirement signPreference = NoRequirement;
2299 SmallPtrSetImpl<Operation *> &emittedExprs;
2302 SmallVector<Token> localTokens;
2312 SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
2314 unsigned emitBinaryFlags) {
2316 emitError(op,
"SV attributes emission is unimplemented for the op");
2327 if (emitBinaryFlags & EB_ForceResultSigned)
2328 ps <<
"$signed(" << PP::ibox0;
2329 auto operandSignReq =
2330 SubExprSignRequirement(emitBinaryFlags & EB_OperandSignRequirementMask);
2331 auto lhsInfo = emitSubExpr(op->getOperand(0), prec, operandSignReq);
2333 auto lhsSpace = prec == VerilogPrecedence::Comparison ? PP::nbsp : PP::space;
2335 ps << lhsSpace << syntax << PP::nbsp;
2342 auto rhsPrec = prec;
2343 if (!isa<AddOp, MulOp, AndOp, OrOp, XorOp>(op))
2344 rhsPrec = VerilogPrecedence(prec - 1);
2349 bool rhsIsUnsignedValueWithSelfDeterminedWidth =
false;
2350 if (emitBinaryFlags & EB_RHS_UnsignedWithSelfDeterminedWidth) {
2351 rhsIsUnsignedValueWithSelfDeterminedWidth =
true;
2352 operandSignReq = NoRequirement;
2355 auto rhsInfo = emitSubExpr(op->getOperand(1), rhsPrec, operandSignReq,
2356 rhsIsUnsignedValueWithSelfDeterminedWidth);
2360 SubExprSignResult signedness = IsUnsigned;
2361 if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
2362 signedness = IsSigned;
2364 if (emitBinaryFlags & EB_ForceResultSigned) {
2365 ps << PP::end <<
")";
2366 signedness = IsSigned;
2370 return {prec, signedness};
2373 SubExprInfo ExprEmitter::emitUnary(Operation *op,
const char *syntax,
2374 bool resultAlwaysUnsigned) {
2376 emitError(op,
"SV attributes emission is unimplemented for the op");
2379 auto signedness = emitSubExpr(op->getOperand(0), Selection).signedness;
2383 return {isa<ICmpOp>(op) ? LowestPrecedence : Unary,
2384 resultAlwaysUnsigned ? IsUnsigned : signedness};
2389 void ExprEmitter::emitSVAttributes(Operation *op) {
2403 auto concat = value.getDefiningOp<ConcatOp>();
2407 auto constant =
concat.getOperand(0).getDefiningOp<ConstantOp>();
2408 if (constant && constant.getValue().isZero())
2409 return concat.getOperand(1);
2419 SubExprInfo ExprEmitter::emitSubExpr(Value exp,
2420 VerilogPrecedence parenthesizeIfLooserThan,
2421 SubExprSignRequirement signRequirement,
2422 bool isSelfDeterminedUnsignedValue) {
2425 if (isSelfDeterminedUnsignedValue && exp.hasOneUse()) {
2430 auto *op = exp.getDefiningOp();
2434 if (!shouldEmitInlineExpr) {
2437 if (signRequirement == RequireSigned) {
2439 return {Symbol, IsSigned};
2443 return {Symbol, IsUnsigned};
2446 unsigned subExprStartIndex = buffer.tokens.size();
2448 ps.addCallback({op,
true});
2449 auto done = llvm::make_scope_exit([&]() {
2451 ps.addCallback({op, false});
2457 signPreference = signRequirement;
2459 bool bitCastAdded =
false;
2460 if (state.options.explicitBitcast && isa<AddOp, MulOp, SubOp>(op))
2462 (op->getResult(0).getType().dyn_cast_or_null<IntegerType>())) {
2463 ps.addAsString(inType.getWidth());
2464 ps <<
"'(" << PP::ibox0;
2465 bitCastAdded =
true;
2469 auto expInfo = dispatchCombinationalVisitor(exp.getDefiningOp());
2475 buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex,
2477 buffer.tokens.insert(buffer.tokens.begin() + subExprStartIndex, t);
2479 auto closeBoxAndParen = [&]() { ps << PP::end <<
")"; };
2480 if (signRequirement == RequireSigned && expInfo.signedness == IsUnsigned) {
2483 expInfo.signedness = IsSigned;
2484 expInfo.precedence = Selection;
2485 }
else if (signRequirement == RequireUnsigned &&
2486 expInfo.signedness == IsSigned) {
2489 expInfo.signedness = IsUnsigned;
2490 expInfo.precedence = Selection;
2491 }
else if (expInfo.precedence > parenthesizeIfLooserThan) {
2498 expInfo.precedence = Selection;
2505 emittedExprs.insert(exp.getDefiningOp());
2509 SubExprInfo ExprEmitter::visitComb(ReplicateOp op) {
2510 auto openFn = [&]() {
2512 ps.addAsString(op.getMultiple());
2515 auto closeFn = [&]() { ps <<
"}}"; };
2519 if (
auto concatOp = op.getOperand().getDefiningOp<ConcatOp>()) {
2520 if (op.getOperand().hasOneUse()) {
2521 emitBracedList(concatOp.getOperands(), openFn, closeFn);
2522 return {Symbol, IsUnsigned};
2525 emitBracedList(op.getOperand(), openFn, closeFn);
2526 return {Symbol, IsUnsigned};
2529 SubExprInfo ExprEmitter::visitComb(ConcatOp op) {
2530 emitBracedList(op.getOperands());
2531 return {Symbol, IsUnsigned};
2534 SubExprInfo ExprEmitter::visitTypeOp(BitcastOp op) {
2538 Type toType = op.getType();
2541 ps.invokeWithStringOS(
2542 [&](
auto &os) { emitter.emitTypeDims(toType, op.getLoc(), os); });
2545 return emitSubExpr(op.getInput(), LowestPrecedence);
2548 SubExprInfo ExprEmitter::visitComb(ICmpOp op) {
2549 const char *symop[] = {
"==",
"!=",
"<",
"<=",
">",
">=",
"<",
2550 "<=",
">",
">=",
"===",
"!==",
"==?",
"!=?"};
2551 SubExprSignRequirement signop[] = {
2553 NoRequirement, NoRequirement,
2555 RequireSigned, RequireSigned, RequireSigned, RequireSigned,
2557 RequireUnsigned, RequireUnsigned, RequireUnsigned, RequireUnsigned,
2559 NoRequirement, NoRequirement, NoRequirement, NoRequirement};
2561 auto pred =
static_cast<uint64_t
>(op.getPredicate());
2562 assert(pred <
sizeof(symop) /
sizeof(symop[0]));
2565 if (op.isEqualAllOnes())
2566 return emitUnary(op,
"&",
true);
2569 if (op.isNotEqualZero())
2570 return emitUnary(op,
"|",
true);
2572 auto result = emitBinary(op, Comparison, symop[pred], signop[pred]);
2576 result.signedness = IsUnsigned;
2580 SubExprInfo ExprEmitter::visitComb(ExtractOp op) {
2582 emitError(op,
"SV attributes emission is unimplemented for the op");
2584 unsigned loBit = op.getLowBit();
2585 unsigned hiBit = loBit + op.getType().cast<IntegerType>().getWidth() - 1;
2587 auto x = emitSubExpr(op.getInput(), LowestPrecedence);
2588 assert((x.precedence == Symbol ||
2590 "should be handled by isExpressionUnableToInline");
2595 op.getInput().getType().getIntOrFloatBitWidth() == hiBit + 1)
2599 ps.addAsString(hiBit);
2600 if (hiBit != loBit) {
2602 ps.addAsString(loBit);
2605 return {Unary, IsUnsigned};
2608 SubExprInfo ExprEmitter::visitSV(GetModportOp op) {
2610 emitError(op,
"SV attributes emission is unimplemented for the op");
2612 auto decl = op.getReferencedDecl(state.symbolCache);
2615 return {Selection, IsUnsigned};
2618 SubExprInfo ExprEmitter::visitSV(SystemFunctionOp op) {
2620 emitError(op,
"SV attributes emission is unimplemented for the op");
2623 ps.scopedBox(PP::ibox0, [&]() {
2625 op.getOperands(), [&](Value v) { emitSubExpr(v, LowestPrecedence); },
2626 [&]() { ps <<
"," << PP::space; });
2629 return {Symbol, IsUnsigned};
2632 SubExprInfo ExprEmitter::visitSV(ReadInterfaceSignalOp op) {
2634 emitError(op,
"SV attributes emission is unimplemented for the op");
2636 auto decl = op.getReferencedDecl(state.symbolCache);
2640 return {Selection, IsUnsigned};
2643 SubExprInfo ExprEmitter::visitSV(XMROp op) {
2645 emitError(op,
"SV attributes emission is unimplemented for the op");
2647 if (op.getIsRooted())
2649 for (
auto s : op.getPath())
2650 ps <<
PPExtString(s.cast<StringAttr>().getValue()) <<
".";
2652 return {Selection, IsUnsigned};
2657 SubExprInfo ExprEmitter::visitSV(XMRRefOp op) {
2659 emitError(op,
"SV attributes emission is unimplemented for the op");
2662 auto globalRef = op.getReferencedPath(&state.symbolCache);
2663 auto namepath = globalRef.getNamepathAttr().getValue();
2664 auto *module = state.symbolCache.getDefinition(
2665 cast<InnerRefAttr>(namepath.front()).getModule());
2667 for (
auto sym : namepath) {
2669 auto innerRef = cast<InnerRefAttr>(sym);
2670 auto ref = state.symbolCache.getInnerDefinition(innerRef.getModule(),
2671 innerRef.getName());
2672 if (ref.hasPort()) {
2678 auto leaf = op.getVerbatimSuffixAttr();
2679 if (leaf && leaf.size())
2681 return {Selection, IsUnsigned};
2684 SubExprInfo ExprEmitter::visitVerbatimExprOp(Operation *op, ArrayAttr symbols) {
2686 emitError(op,
"SV attributes emission is unimplemented for the op");
2688 emitTextWithSubstitutions(
2689 ps, op->getAttrOfType<StringAttr>(
"format_string").getValue(), op,
2690 [&](Value operand) { emitSubExpr(operand, LowestPrecedence); }, symbols);
2692 return {Unary, IsUnsigned};
2695 template <
typename MacroTy>
2696 SubExprInfo ExprEmitter::emitMacroCall(MacroTy op) {
2698 emitError(op,
"SV attributes emission is unimplemented for the op");
2701 auto macroOp = op.getReferencedMacro(&state.symbolCache);
2702 assert(macroOp &&
"Invalid IR");
2704 macroOp.getVerilogName() ? *macroOp.getVerilogName() : macroOp.getName();
2706 if (!op.getInputs().empty()) {
2708 llvm::interleaveComma(op.getInputs(), ps, [&](Value val) {
2709 emitExpression(val, LowestPrecedence);
2713 return {LowestPrecedence, IsUnsigned};
2716 SubExprInfo ExprEmitter::visitSV(MacroRefExprOp op) {
2717 return emitMacroCall(op);
2720 SubExprInfo ExprEmitter::visitSV(MacroRefExprSEOp op) {
2721 return emitMacroCall(op);
2724 SubExprInfo ExprEmitter::visitSV(ConstantXOp op) {
2726 emitError(op,
"SV attributes emission is unimplemented for the op");
2728 ps.addAsString(op.getWidth());
2730 return {Unary, IsUnsigned};
2733 SubExprInfo ExprEmitter::visitSV(ConstantStrOp op) {
2735 emitError(op,
"SV attributes emission is unimplemented for the op");
2737 ps.writeQuotedEscaped(op.getStr());
2738 return {Symbol, IsUnsigned};
2741 SubExprInfo ExprEmitter::visitSV(ConstantZOp op) {
2743 emitError(op,
"SV attributes emission is unimplemented for the op");
2745 ps.addAsString(op.getWidth());
2747 return {Unary, IsUnsigned};
2750 SubExprInfo ExprEmitter::printConstantScalar(APInt &value, IntegerType type) {
2751 bool isNegated =
false;
2754 if (signPreference == RequireSigned && value.isNegative() &&
2755 !value.isMinSignedValue()) {
2760 ps.addAsString(type.getWidth());
2764 if (signPreference == RequireSigned)
2770 SmallString<32> valueStr;
2772 (-value).toStringUnsigned(valueStr, 16);
2774 value.toStringUnsigned(valueStr, 16);
2777 return {Unary, signPreference == RequireSigned ? IsSigned : IsUnsigned};
2780 SubExprInfo ExprEmitter::visitTypeOp(ConstantOp op) {
2782 emitError(op,
"SV attributes emission is unimplemented for the op");
2784 auto value = op.getValue();
2788 if (value.getBitWidth() == 0) {
2789 emitOpError(op,
"will not emit zero width constants in the general case");
2790 ps <<
"<<unsupported zero width constant: "
2791 <<
PPExtString(op->getName().getStringRef()) <<
">>";
2792 return {Unary, IsUnsigned};
2795 return printConstantScalar(value, op.getType().cast<IntegerType>());
2798 SubExprInfo ExprEmitter::visitTypeOp(AggregateConstantOp op) {
2800 emitError(op,
"SV attributes emission is unimplemented for the op");
2804 "zero-bit types not allowed at this point");
2806 std::function<void(Attribute, Type)> printAggregate = [&](Attribute attr,
2808 if (
auto arrayType = hw::type_dyn_cast<ArrayType>(type)) {
2811 attr.cast<ArrayAttr>(), [&]() { ps <<
"{"; },
2812 [&](Attribute attr) { printAggregate(attr, elementType); },
2813 [&]() { ps <<
"}"; });
2814 }
else if (
auto arrayType = hw::type_dyn_cast<UnpackedArrayType>(type)) {
2817 attr.cast<ArrayAttr>(), [&]() { ps <<
"'{"; },
2818 [&](Attribute attr) { printAggregate(attr, elementType); },
2819 [&]() { ps <<
"}"; });
2820 }
else if (
auto structType = hw::type_dyn_cast<StructType>(type)) {
2827 llvm::make_filter_range(
2828 llvm::zip(structType.getElements(), attr.cast<ArrayAttr>()),
2829 [](
const auto &fieldAndAttr) {
2831 return !isZeroBitType(std::get<0>(fieldAndAttr).type);
2833 [&]() { ps <<
"'{"; },
2834 [&](
const auto &fieldAndAttr) {
2835 ps.scopedBox(PP::ibox2, [&]() {
2836 const auto &[field, attr] = fieldAndAttr;
2837 ps << PPExtString(emitter.getVerilogStructFieldName(field.name))
2838 <<
":" << PP::space;
2839 printAggregate(attr, field.type);
2842 [&]() { ps <<
"}"; });
2843 }
else if (
auto enumType = hw::type_dyn_cast<EnumType>(type)) {
2844 assert(
false &&
"unsupported");
2845 auto value = attr.cast<StringAttr>();
2846 ps << value.getValue();
2847 }
else if (
auto intType = hw::type_dyn_cast<IntegerType>(type)) {
2848 auto value = attr.cast<IntegerAttr>().getValue();
2849 printConstantScalar(value, intType);
2851 assert(
false &&
"unknown constant kind");
2855 printAggregate(op.getFields(), op.getType());
2856 return {Symbol, IsUnsigned};
2859 SubExprInfo ExprEmitter::visitTypeOp(ParamValueOp op) {
2861 emitError(op,
"SV attributes emission is unimplemented for the op");
2863 return ps.invokeWithStringOS([&](
auto &os) {
2864 return emitter.printParamValue(op.getValue(), os, [&]() {
2865 return op->emitOpError(
"invalid parameter use");
2872 SubExprInfo ExprEmitter::visitTypeOp(ArraySliceOp op) {
2874 emitError(op,
"SV attributes emission is unimplemented for the op");
2876 auto arrayPrec = emitSubExpr(op.getInput(), Selection);
2878 unsigned dstWidth = type_cast<ArrayType>(op.getType()).getNumElements();
2880 emitSubExpr(op.getLowIndex(), LowestPrecedence);
2882 ps.addAsString(dstWidth);
2884 return {Selection, arrayPrec.signedness};
2887 SubExprInfo ExprEmitter::visitTypeOp(ArrayGetOp op) {
2888 emitSubExpr(op.getInput(), Selection);
2893 emitSubExpr(op.getIndex(), LowestPrecedence);
2895 emitSVAttributes(op);
2896 return {Selection, IsUnsigned};
2900 SubExprInfo ExprEmitter::visitTypeOp(ArrayCreateOp op) {
2902 emitError(op,
"SV attributes emission is unimplemented for the op");
2904 if (op.isUniform()) {
2906 ps.addAsString(op.getInputs().size());
2908 emitSubExpr(op.getUniformElement(), LowestPrecedence);
2912 op.getInputs(), [&]() { ps <<
"{"; },
2915 emitSubExprIBox2(v);
2918 [&]() { ps <<
"}"; });
2920 return {Unary, IsUnsigned};
2923 SubExprInfo ExprEmitter::visitTypeOp(ArrayConcatOp op) {
2925 emitError(op,
"SV attributes emission is unimplemented for the op");
2927 emitBracedList(op.getOperands());
2928 return {Unary, IsUnsigned};
2931 SubExprInfo ExprEmitter::visitSV(ArrayIndexInOutOp op) {
2933 emitError(op,
"SV attributes emission is unimplemented for the op");
2935 auto index = op.getIndex();
2936 auto arrayPrec = emitSubExpr(op.getInput(), Selection);
2941 emitSubExpr(index, LowestPrecedence);
2943 return {Selection, arrayPrec.signedness};
2946 SubExprInfo ExprEmitter::visitSV(IndexedPartSelectInOutOp op) {
2948 emitError(op,
"SV attributes emission is unimplemented for the op");
2950 auto prec = emitSubExpr(op.getInput(), Selection);
2952 emitSubExpr(op.getBase(), LowestPrecedence);
2953 if (op.getDecrement())
2957 ps.addAsString(op.getWidth());
2959 return {Selection, prec.signedness};
2962 SubExprInfo ExprEmitter::visitSV(IndexedPartSelectOp op) {
2964 emitError(op,
"SV attributes emission is unimplemented for the op");
2966 auto info = emitSubExpr(op.getInput(), LowestPrecedence);
2968 emitSubExpr(op.getBase(), LowestPrecedence);
2969 if (op.getDecrement())
2973 ps.addAsString(op.getWidth());
2978 SubExprInfo ExprEmitter::visitSV(StructFieldInOutOp op) {
2980 emitError(op,
"SV attributes emission is unimplemented for the op");
2982 auto prec = emitSubExpr(op.getInput(), Selection);
2984 <<
PPExtString(emitter.getVerilogStructFieldName(op.getFieldAttr()));
2985 return {Selection, prec.signedness};
2988 SubExprInfo ExprEmitter::visitSV(SampledOp op) {
2990 emitError(op,
"SV attributes emission is unimplemented for the op");
2993 auto info = emitSubExpr(op.getExpression(), LowestPrecedence);
2998 SubExprInfo ExprEmitter::visitComb(MuxOp op) {
3012 return ps.scopedBox(PP::cbox0, [&]() -> SubExprInfo {
3013 ps.scopedBox(PP::ibox0, [&]() {
3014 emitSubExpr(op.getCond(), VerilogPrecedence(Conditional - 1));
3018 emitSVAttributes(op);
3020 auto lhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3021 return emitSubExpr(op.getTrueValue(), VerilogPrecedence(Conditional - 1));
3025 auto rhsInfo = ps.scopedBox(PP::ibox0, [&]() {
3026 return emitSubExpr(op.getFalseValue(), Conditional);
3029 SubExprSignResult signedness = IsUnsigned;
3030 if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
3031 signedness = IsSigned;
3033 return {Conditional, signedness};
3037 SubExprInfo ExprEmitter::visitTypeOp(StructCreateOp op) {
3039 emitError(op,
"SV attributes emission is unimplemented for the op");
3041 StructType stype = op.getType();
3047 llvm::make_filter_range(llvm::zip(stype.getElements(), op.getOperands()),
3048 [](
const auto &fieldAndOperand) {
3050 const auto &[field, _] = fieldAndOperand;
3051 return !isZeroBitType(field.type);
3053 [&]() { ps <<
"'{"; },
3054 [&](
const auto &fieldAndOperand) {
3055 ps.scopedBox(PP::ibox2, [&]() {
3056 const auto &[field, operand] = fieldAndOperand;
3057 ps << PPExtString(emitter.getVerilogStructFieldName(field.name))
3058 <<
":" << PP::space;
3059 emitSubExpr(operand, Selection);
3062 [&]() { ps <<
"}"; });
3063 return {Unary, IsUnsigned};
3066 SubExprInfo ExprEmitter::visitTypeOp(StructExtractOp op) {
3068 emitError(op,
"SV attributes emission is unimplemented for the op");
3070 emitSubExpr(op.getInput(), Selection);
3072 <<
PPExtString(emitter.getVerilogStructFieldName(op.getFieldAttr()));
3073 return {Selection, IsUnsigned};
3076 SubExprInfo ExprEmitter::visitTypeOp(StructInjectOp op) {
3078 emitError(op,
"SV attributes emission is unimplemented for the op");
3080 StructType stype = op.getType().cast<StructType>();
3084 llvm::make_filter_range(
3085 stype.getElements(),
3086 [](
const auto &field) { return !isZeroBitType(field.type); }),
3087 [&]() { ps <<
"'{"; },
3088 [&](
const StructType::FieldInfo &field) {
3089 ps.scopedBox(PP::ibox2, [&]() {
3090 ps << PPExtString(emitter.getVerilogStructFieldName(field.name))
3091 <<
":" << PP::space;
3092 if (field.name == op.getField()) {
3093 emitSubExpr(op.getNewValue(), Selection);
3095 emitSubExpr(op.getInput(), Selection);
3096 ps <<
"." << PPExtString(field.name.getValue());
3100 [&]() { ps <<
"}"; });
3101 return {Selection, IsUnsigned};
3104 SubExprInfo ExprEmitter::visitTypeOp(EnumConstantOp op) {
3105 ps <<
PPSaveString(emitter.fieldNameResolver.getEnumFieldName(op.getField()));
3106 return {Selection, IsUnsigned};
3109 SubExprInfo ExprEmitter::visitTypeOp(EnumCmpOp op) {
3111 emitError(op,
"SV attributes emission is unimplemented for the op");
3112 auto result = emitBinary(op, Comparison,
"==", NoRequirement);
3115 result.signedness = IsUnsigned;
3119 SubExprInfo ExprEmitter::visitTypeOp(UnionCreateOp op) {
3121 emitError(op,
"SV attributes emission is unimplemented for the op");
3124 auto fieldName = op.getFieldAttr();
3127 auto element = unionType.getFieldInfo(fieldName.getValue());
3131 if (!elementWidth) {
3132 ps.addAsString(unionWidth);
3134 return {Unary, IsUnsigned};
3138 if (elementWidth == unionWidth) {
3139 emitSubExpr(op.getInput(), LowestPrecedence);
3140 return {Unary, IsUnsigned};
3145 ps.scopedBox(PP::ibox0, [&]() {
3146 if (
auto prePadding = element.offset) {
3147 ps.addAsString(prePadding);
3148 ps <<
"'h0," << PP::space;
3150 emitSubExpr(op.getInput(), Selection);
3151 if (
auto postPadding = unionWidth - elementWidth - element.offset) {
3152 ps <<
"," << PP::space;
3153 ps.addAsString(postPadding);
3159 return {Unary, IsUnsigned};
3162 SubExprInfo ExprEmitter::visitTypeOp(UnionExtractOp op) {
3164 emitError(op,
"SV attributes emission is unimplemented for the op");
3165 emitSubExpr(op.getInput(), Selection);
3168 auto fieldName = op.getFieldAttr();
3169 auto unionType = cast<UnionType>(
getCanonicalType(op.getInput().getType()));
3171 auto element = unionType.getFieldInfo(fieldName.getValue());
3173 bool needsPadding = elementWidth < unionWidth || element.offset > 0;
3174 auto verilogFieldName = emitter.getVerilogStructFieldName(fieldName);
3183 return {Selection, IsUnsigned};
3186 SubExprInfo ExprEmitter::visitUnhandledExpr(Operation *op) {
3187 emitOpError(op,
"cannot emit this expression to Verilog");
3188 ps <<
"<<unsupported expr: " <<
PPExtString(op->getName().getStringRef())
3190 return {Symbol, IsUnsigned};
3206 enum class PropertyPrecedence {
3226 struct EmittedProperty {
3228 PropertyPrecedence precedence;
3233 class PropertyEmitter :
public EmitterBase,
3234 public ltl::Visitor<PropertyEmitter, EmittedProperty> {
3238 PropertyEmitter(ModuleEmitter &emitter,
3239 SmallPtrSetImpl<Operation *> &emittedOps)
3240 : PropertyEmitter(emitter, emittedOps, localTokens) {}
3241 PropertyEmitter(ModuleEmitter &emitter,
3242 SmallPtrSetImpl<Operation *> &emittedOps,
3244 : EmitterBase(emitter.state), emitter(emitter), emittedOps(emittedOps),
3246 ps(buffer, state.saver, state.options.emitVerilogLocations) {
3247 assert(state.pp.getListener() == &state.saver);
3255 PropertyPrecedence parenthesizeIfLooserThan = PropertyPrecedence::Lowest);
3258 using ltl::Visitor<PropertyEmitter, EmittedProperty>::visitLTL;
3259 friend class ltl::Visitor<PropertyEmitter, EmittedProperty>;
3263 emitNestedProperty(Value property,
3264 PropertyPrecedence parenthesizeIfLooserThan);
3266 EmittedProperty visitUnhandledLTL(Operation *op);
3267 EmittedProperty visitLTL(ltl::AndOp op);
3268 EmittedProperty visitLTL(ltl::OrOp op);
3269 EmittedProperty visitLTL(ltl::DelayOp op);
3270 EmittedProperty visitLTL(ltl::ConcatOp op);
3271 EmittedProperty visitLTL(ltl::NotOp op);
3272 EmittedProperty visitLTL(ltl::ImplicationOp op);
3273 EmittedProperty visitLTL(ltl::EventuallyOp op);
3274 EmittedProperty visitLTL(ltl::ClockOp op);
3275 EmittedProperty visitLTL(ltl::DisableOp op);
3277 void emitLTLConcat(ValueRange
inputs);
3280 ModuleEmitter &emitter;
3285 SmallPtrSetImpl<Operation *> &emittedOps;
3288 SmallVector<Token> localTokens;
3298 void PropertyEmitter::emitProperty(
3299 Value property, PropertyPrecedence parenthesizeIfLooserThan) {
3300 assert(localTokens.empty());
3302 ps.scopedBox(PP::ibox0,
3303 [&] { emitNestedProperty(property, parenthesizeIfLooserThan); });
3307 if (&buffer.tokens == &localTokens)
3308 buffer.flush(state.pp);
3311 EmittedProperty PropertyEmitter::emitNestedProperty(
3312 Value property, PropertyPrecedence parenthesizeIfLooserThan) {
3322 if (!isa<ltl::SequenceType, ltl::PropertyType>(property.getType())) {
3323 ExprEmitter(emitter, emittedOps, buffer.tokens)
3324 .emitExpression(property, LowestPrecedence);
3325 return {PropertyPrecedence::Symbol};
3328 unsigned startIndex = buffer.tokens.size();
3329 auto info = dispatchLTLVisitor(property.getDefiningOp());
3334 if (info.precedence > parenthesizeIfLooserThan) {
3336 buffer.tokens.insert(buffer.tokens.begin() + startIndex,
BeginToken(0));
3337 buffer.tokens.insert(buffer.tokens.begin() + startIndex,
StringToken(
"("));
3339 ps << PP::end <<
")";
3341 info.precedence = PropertyPrecedence::Symbol;
3345 emittedOps.insert(property.getDefiningOp());
3349 EmittedProperty PropertyEmitter::visitUnhandledLTL(Operation *op) {
3350 emitOpError(op,
"emission as Verilog property or sequence not supported");
3351 ps <<
"<<unsupported: " <<
PPExtString(op->getName().getStringRef()) <<
">>";
3352 return {PropertyPrecedence::Symbol};
3355 EmittedProperty PropertyEmitter::visitLTL(ltl::AndOp op) {
3358 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::And); },
3359 [&]() { ps << PP::space <<
"and" << PP::nbsp; });
3360 return {PropertyPrecedence::And};
3363 EmittedProperty PropertyEmitter::visitLTL(ltl::OrOp op) {
3366 [&](
auto input) { emitNestedProperty(input, PropertyPrecedence::Or); },
3367 [&]() { ps << PP::space <<
"or" << PP::nbsp; });
3368 return {PropertyPrecedence::Or};
3371 EmittedProperty PropertyEmitter::visitLTL(ltl::DelayOp op) {
3373 if (
auto length = op.getLength()) {
3375 ps.addAsString(op.getDelay());
3378 ps.addAsString(op.getDelay());
3380 ps.addAsString(op.getDelay() + *length);
3384 if (op.getDelay() == 0) {
3386 }
else if (op.getDelay() == 1) {
3390 ps.addAsString(op.getDelay());
3395 emitNestedProperty(op.getInput(), PropertyPrecedence::Concat);
3396 return {PropertyPrecedence::Concat};
3399 void PropertyEmitter::emitLTLConcat(ValueRange
inputs) {
3400 bool addSeparator =
false;
3401 for (
auto input :
inputs) {
3404 if (!input.getDefiningOp<ltl::DelayOp>())
3405 ps <<
"##0" << PP::space;
3407 addSeparator =
true;
3408 emitNestedProperty(input, PropertyPrecedence::Concat);
3412 EmittedProperty PropertyEmitter::visitLTL(ltl::ConcatOp op) {
3413 emitLTLConcat(op.getInputs());
3414 return {PropertyPrecedence::Concat};
3417 EmittedProperty PropertyEmitter::visitLTL(ltl::NotOp op) {
3418 ps <<
"not" << PP::space;
3419 emitNestedProperty(op.getInput(), PropertyPrecedence::Unary);
3420 return {PropertyPrecedence::Unary};
3426 auto concatOp = value.getDefiningOp<ltl::ConcatOp>();
3427 if (!concatOp || concatOp.getInputs().size() < 2)
3429 auto delayOp = concatOp.getInputs().back().getDefiningOp<ltl::DelayOp>();
3430 if (!delayOp || delayOp.getDelay() != 1 || delayOp.getLength() != 0)
3432 auto constOp = delayOp.getInput().getDefiningOp<ConstantOp>();
3433 if (!constOp || !constOp.getValue().isOne())
3435 return concatOp.getInputs().drop_back();
3438 EmittedProperty PropertyEmitter::visitLTL(ltl::ImplicationOp op) {
3442 emitLTLConcat(range);
3443 ps << PP::space <<
"|=>" << PP::nbsp;
3445 emitNestedProperty(op.getAntecedent(), PropertyPrecedence::Implication);
3446 ps << PP::space <<
"|->" << PP::nbsp;
3448 emitNestedProperty(op.getConsequent(), PropertyPrecedence::Implication);
3449 return {PropertyPrecedence::Implication};
3452 EmittedProperty PropertyEmitter::visitLTL(ltl::EventuallyOp op) {
3453 ps <<
"s_eventually" << PP::space;
3454 emitNestedProperty(op.getInput(), PropertyPrecedence::Qualifier);
3455 return {PropertyPrecedence::Qualifier};
3458 EmittedProperty PropertyEmitter::visitLTL(ltl::ClockOp op) {
3460 ps.scopedBox(PP::ibox2, [&] {
3461 ps <<
PPExtString(stringifyClockEdge(op.getEdge())) << PP::space;
3462 emitNestedProperty(op.getClock(), PropertyPrecedence::Lowest);
3466 emitNestedProperty(op.getInput(), PropertyPrecedence::Clocking);
3467 return {PropertyPrecedence::Clocking};
3470 EmittedProperty PropertyEmitter::visitLTL(ltl::DisableOp op) {
3471 ps <<
"disable iff" << PP::nbsp <<
"(";
3472 ps.scopedBox(PP::ibox2, [&] {
3473 emitNestedProperty(op.getCondition(), PropertyPrecedence::Lowest);
3477 emitNestedProperty(op.getInput(), PropertyPrecedence::Clocking);
3478 return {PropertyPrecedence::Clocking};
3488 class NameCollector {
3490 NameCollector(ModuleEmitter &moduleEmitter) : moduleEmitter(moduleEmitter) {}
3494 void collectNames(Block &block);
3496 size_t getMaxDeclNameWidth()
const {
return maxDeclNameWidth; }
3497 size_t getMaxTypeWidth()
const {
return maxTypeWidth; }
3500 size_t maxDeclNameWidth = 0, maxTypeWidth = 0;
3501 ModuleEmitter &moduleEmitter;
3506 void NameCollector::collectNames(Block &block) {
3509 for (
auto &op : block) {
3513 if (isa<InstanceOp, InterfaceInstanceOp>(op))
3515 if (isa<ltl::LTLDialect>(op.getDialect()))
3519 for (
auto result : op.getResults()) {
3520 StringRef declName =
3522 maxDeclNameWidth = std::max(declName.size(), maxDeclNameWidth);
3523 SmallString<16> typeString;
3527 llvm::raw_svector_ostream stringStream(typeString);
3529 stringStream, op.getLoc());
3531 maxTypeWidth = std::max(typeString.size(), maxTypeWidth);
3538 if (isa<IfDefProceduralOp, OrderedOutputOp>(op)) {
3539 for (
auto ®ion : op.getRegions()) {
3540 if (!region.empty())
3541 collectNames(region.front());
3555 class StmtEmitter :
public EmitterBase,
3556 public hw::StmtVisitor<StmtEmitter, LogicalResult>,
3557 public sv::Visitor<StmtEmitter, LogicalResult>,
3558 public verif::Visitor<StmtEmitter, LogicalResult> {
3563 : EmitterBase(emitter.state), emitter(emitter), options(options) {}
3565 void emitStatement(Operation *op);
3566 void emitStatementBlock(Block &body);
3569 LogicalResult emitDeclaration(Operation *op);
3572 void collectNamesAndCalculateDeclarationWidths(Block &block);
3575 emitExpression(Value exp, SmallPtrSetImpl<Operation *> &emittedExprs,
3576 VerilogPrecedence parenthesizeIfLooserThan = LowestPrecedence);
3577 void emitSVAttributes(Operation *op);
3579 using hw::StmtVisitor<StmtEmitter, LogicalResult>::visitStmt;
3580 using sv::Visitor<StmtEmitter, LogicalResult>::visitSV;
3581 using verif::Visitor<StmtEmitter, LogicalResult>::visitVerif;
3582 friend class hw::StmtVisitor<StmtEmitter, LogicalResult>;
3583 friend class sv::Visitor<StmtEmitter, LogicalResult>;
3584 friend class verif::Visitor<StmtEmitter, LogicalResult>;
3587 LogicalResult visitUnhandledStmt(Operation *op) {
return failure(); }
3588 LogicalResult visitInvalidStmt(Operation *op) {
return failure(); }
3589 LogicalResult visitUnhandledSV(Operation *op) {
return failure(); }
3590 LogicalResult visitInvalidSV(Operation *op) {
return failure(); }
3591 LogicalResult visitUnhandledVerif(Operation *op) {
return failure(); }
3592 LogicalResult visitInvalidVerif(Operation *op) {
return failure(); }
3594 LogicalResult visitSV(sv::WireOp op) {
return emitDeclaration(op); }
3595 LogicalResult visitSV(RegOp op) {
return emitDeclaration(op); }
3596 LogicalResult visitSV(LogicOp op) {
return emitDeclaration(op); }
3597 LogicalResult visitSV(LocalParamOp op) {
return emitDeclaration(op); }
3598 template <
typename Op>
3601 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
3602 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
3603 llvm::function_ref<
void()> emitRHS,
PPExtString syntax,
3605 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
3606 LogicalResult visitSV(AssignOp op);
3607 LogicalResult visitSV(BPAssignOp op);
3608 LogicalResult visitSV(PAssignOp op);
3609 LogicalResult visitSV(ForceOp op);
3610 LogicalResult visitSV(ReleaseOp op);
3611 LogicalResult visitSV(AliasOp op);
3612 LogicalResult visitSV(InterfaceInstanceOp op);
3613 LogicalResult visitStmt(OutputOp op);
3614 LogicalResult visitStmt(InstanceOp op);
3615 LogicalResult visitStmt(TypeScopeOp op);
3616 LogicalResult visitStmt(TypedeclOp op);
3618 LogicalResult emitIfDef(Operation *op, MacroIdentAttr cond);
3619 LogicalResult visitSV(OrderedOutputOp op);
3620 LogicalResult visitSV(IfDefOp op) {
return emitIfDef(op, op.getCond()); }
3621 LogicalResult visitSV(IfDefProceduralOp op) {
3622 return emitIfDef(op, op.getCond());
3624 LogicalResult visitSV(IfOp op);
3625 LogicalResult visitSV(AlwaysOp op);
3626 LogicalResult visitSV(AlwaysCombOp op);
3627 LogicalResult visitSV(AlwaysFFOp op);
3628 LogicalResult visitSV(InitialOp op);
3629 LogicalResult visitSV(CaseOp op);
3630 LogicalResult visitSV(FWriteOp op);
3631 LogicalResult visitSV(VerbatimOp op);
3633 LogicalResult emitSimulationControlTask(Operation *op,
PPExtString taskName,
3634 std::optional<unsigned> verbosity);
3635 LogicalResult visitSV(StopOp op);
3636 LogicalResult visitSV(FinishOp op);
3637 LogicalResult visitSV(ExitOp op);
3639 LogicalResult emitSeverityMessageTask(Operation *op,
PPExtString taskName,
3640 std::optional<unsigned> verbosity,
3642 ValueRange operands);
3643 LogicalResult visitSV(FatalOp op);
3644 LogicalResult visitSV(ErrorOp op);
3645 LogicalResult visitSV(WarningOp op);
3646 LogicalResult visitSV(InfoOp op);
3648 LogicalResult visitSV(ReadMemOp op);
3650 LogicalResult visitSV(GenerateOp op);
3651 LogicalResult visitSV(GenerateCaseOp op);
3653 LogicalResult visitSV(ForOp op);
3655 void emitAssertionLabel(Operation *op);
3656 void emitAssertionMessage(StringAttr message, ValueRange args,
3657 SmallPtrSetImpl<Operation *> &ops,
3659 template <
typename Op>
3660 LogicalResult emitImmediateAssertion(Op op,
PPExtString opName);
3661 LogicalResult visitSV(AssertOp op);
3662 LogicalResult visitSV(AssumeOp op);
3663 LogicalResult visitSV(CoverOp op);
3664 template <
typename Op>
3665 LogicalResult emitConcurrentAssertion(Op op,
PPExtString opName);
3666 LogicalResult visitSV(AssertConcurrentOp op);
3667 LogicalResult visitSV(AssumeConcurrentOp op);
3668 LogicalResult visitSV(CoverConcurrentOp op);
3670 LogicalResult visitSV(BindOp op);
3671 LogicalResult visitSV(InterfaceOp op);
3672 LogicalResult visitSV(InterfaceSignalOp op);
3673 LogicalResult visitSV(InterfaceModportOp op);
3674 LogicalResult visitSV(AssignInterfaceSignalOp op);
3675 LogicalResult visitSV(MacroDefOp op);
3677 void emitBlockAsStatement(Block *block,
3678 const SmallPtrSetImpl<Operation *> &locationOps,
3679 StringRef multiLineComment = StringRef());
3681 LogicalResult emitVerifAssertLike(Operation *op, Value property,
3683 LogicalResult visitVerif(verif::AssertOp op);
3684 LogicalResult visitVerif(verif::AssumeOp op);
3685 LogicalResult visitVerif(verif::CoverOp op);
3688 ModuleEmitter &emitter;
3693 size_t maxDeclNameWidth = 0;
3694 size_t maxTypeWidth = 0;
3705 void StmtEmitter::emitExpression(Value exp,
3706 SmallPtrSetImpl<Operation *> &emittedExprs,
3707 VerilogPrecedence parenthesizeIfLooserThan) {
3708 ExprEmitter(emitter, emittedExprs)
3709 .emitExpression(exp, parenthesizeIfLooserThan);
3714 void StmtEmitter::emitSVAttributes(Operation *op) {
3722 setPendingNewline();
3725 void StmtEmitter::emitAssignLike(llvm::function_ref<
void()> emitLHS,
3726 llvm::function_ref<
void()> emitRHS,
3728 std::optional<PPExtString> wordBeforeLHS) {
3730 ps.scopedBox(PP::ibox2, [&]() {
3731 if (wordBeforeLHS) {
3732 ps << *wordBeforeLHS << PP::space;
3736 ps << PP::space << syntax << PP::space;
3738 ps.scopedBox(PP::ibox0, [&]() {
3745 template <
typename Op>
3747 StmtEmitter::emitAssignLike(Op op,
PPExtString syntax,
3748 std::optional<PPExtString> wordBeforeLHS) {
3749 SmallPtrSet<Operation *, 8> ops;
3753 ps.addCallback({op,
true});
3754 emitAssignLike([&]() { emitExpression(op.getDest(), ops); },
3755 [&]() { emitExpression(op.getSrc(), ops); }, syntax,
3758 ps.addCallback({op,
false});
3759 emitLocationInfoAndNewLine(ops);
3763 LogicalResult StmtEmitter::visitSV(AssignOp op) {
3766 if (dyn_cast_or_null<InstanceOp>(op.getSrc().getDefiningOp()))
3769 if (emitter.assignsInlined.count(op))
3773 emitSVAttributes(op);
3778 LogicalResult StmtEmitter::visitSV(BPAssignOp op) {
3780 if (emitter.assignsInlined.count(op))
3784 emitSVAttributes(op);
3789 LogicalResult StmtEmitter::visitSV(PAssignOp op) {
3791 emitSVAttributes(op);
3796 LogicalResult StmtEmitter::visitSV(ForceOp op) {
3798 emitError(op,
"SV attributes emission is unimplemented for the op");
3803 LogicalResult StmtEmitter::visitSV(ReleaseOp op) {
3805 emitError(op,
"SV attributes emission is unimplemented for the op");
3808 SmallPtrSet<Operation *, 8> ops;
3810 ps.addCallback({op,
true});
3811 ps.scopedBox(PP::ibox2, [&]() {
3812 ps <<
"release" << PP::space;
3813 emitExpression(op.getDest(), ops);
3816 ps.addCallback({op,
false});
3817 emitLocationInfoAndNewLine(ops);
3821 LogicalResult StmtEmitter::visitSV(AliasOp op) {
3823 emitError(op,
"SV attributes emission is unimplemented for the op");
3826 SmallPtrSet<Operation *, 8> ops;
3828 ps.addCallback({op,
true});
3829 ps.scopedBox(PP::ibox2, [&]() {
3830 ps <<
"alias" << PP::space;
3831 ps.scopedBox(PP::cbox0, [&]() {
3833 op.getOperands(), [&](Value v) { emitExpression(v, ops); },
3834 [&]() { ps << PP::nbsp <<
"=" << PP::space; });
3838 ps.addCallback({op,
false});
3839 emitLocationInfoAndNewLine(ops);
3843 LogicalResult StmtEmitter::visitSV(InterfaceInstanceOp op) {
3844 auto doNotPrint = op->hasAttr(
"doNotPrint");
3845 if (doNotPrint && !state.options.emitBindComments)
3849 emitError(op,
"SV attributes emission is unimplemented for the op");
3852 StringRef prefix =
"";
3853 ps.addCallback({op,
true});
3856 ps <<
"// This interface is elsewhere emitted as a bind statement."
3860 SmallPtrSet<Operation *, 8> ops;
3863 auto *interfaceOp = op.getReferencedInterface(&state.symbolCache);
3864 assert(interfaceOp &&
"InterfaceInstanceOp has invalid symbol that does not "
3865 "point to an interface");
3868 if (!prefix.empty())
3874 ps.addCallback({op,
false});
3875 emitLocationInfoAndNewLine(ops);
3882 LogicalResult StmtEmitter::visitStmt(OutputOp op) {
3883 SmallPtrSet<Operation *, 8> ops;
3884 auto parent = op->getParentOfType<PortList>();
3886 size_t operandIndex = 0;
3887 auto ports = parent.getPortList();
3888 for (PortInfo port : ports.getOutputs()) {
3889 auto operand = op.getOperand(operandIndex);
3893 if (operand.hasOneUse() &&
3894 dyn_cast_or_null<InstanceOp>(operand.getDefiningOp())) {
3903 ps.addCallback({op,
true});
3905 ps.scopedBox(isZeroBit ? PP::neverbox : PP::ibox2, [&]() {
3907 ps <<
"// Zero width: ";
3909 ps <<
"assign" << PP::space;
3911 ps << PP::space <<
"=" << PP::space;
3912 ps.scopedBox(PP::ibox0, [&]() {
3916 isa_and_nonnull<hw::ConstantOp>(operand.getDefiningOp()))
3917 ps <<
"/*Zero width*/";
3919 emitExpression(operand, ops, LowestPrecedence);
3923 ps.addCallback({op,
false});
3924 emitLocationInfoAndNewLine(ops);
3931 LogicalResult StmtEmitter::visitStmt(TypeScopeOp op) {
3933 auto typescopeDef = (
"_TYPESCOPE_" + op.getSymName()).str();
3934 ps <<
"`ifndef " << typescopeDef << PP::newline;
3935 ps <<
"`define " << typescopeDef;
3936 setPendingNewline();
3937 emitStatementBlock(*op.getBodyBlock());
3939 ps <<
"`endif // " << typescopeDef;
3940 setPendingNewline();
3944 LogicalResult StmtEmitter::visitStmt(TypedeclOp op) {
3946 emitError(op,
"SV attributes emission is unimplemented for the op");
3951 ps << PP::neverbox <<
"// ";
3953 SmallPtrSet<Operation *, 8> ops;
3955 ps.scopedBox(PP::ibox2, [&]() {
3956 ps <<
"typedef" << PP::space;
3957 ps.invokeWithStringOS([&](
auto &os) {
3959 op.getAliasType(),
false);
3961 ps << PP::space <<
PPExtString(op.getPreferredName());
3962 ps.invokeWithStringOS(
3963 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
3968 emitLocationInfoAndNewLine(ops);
3972 LogicalResult StmtEmitter::visitSV(FWriteOp op) {
3974 emitError(op,
"SV attributes emission is unimplemented for the op");
3977 SmallPtrSet<Operation *, 8> ops;
3980 ps.addCallback({op,
true});
3982 ps.scopedBox(PP::ibox0, [&]() {
3983 emitExpression(op.getFd(), ops);
3985 ps <<
"," << PP::space;
3986 ps.writeQuotedEscaped(op.getFormatString());
3994 for (
auto operand : op.getSubstitutions()) {
3995 ps <<
"," << PP::space;
3996 emitExpression(operand, ops);
4000 ps.addCallback({op,
false});
4001 emitLocationInfoAndNewLine(ops);
4005 LogicalResult StmtEmitter::visitSV(VerbatimOp op) {
4007 emitError(op,
"SV attributes emission is unimplemented for the op");
4010 SmallPtrSet<Operation *, 8> ops;
4015 StringRef
string = op.getFormatString();
4016 if (
string.endswith(
"\n"))
4017 string =
string.drop_back();
4022 bool isFirst =
true;
4025 while (!
string.
empty()) {
4026 auto lhsRhs =
string.split(
'\n');
4030 ps << PP::end << PP::newline << PP::neverbox;
4034 emitTextWithSubstitutions(
4035 ps, lhsRhs.first, op,
4036 [&](Value operand) { emitExpression(operand, ops); }, op.getSymbols());
4037 string = lhsRhs.second;
4042 emitLocationInfoAndNewLine(ops);
4048 StmtEmitter::emitSimulationControlTask(Operation *op,
PPExtString taskName,
4049 std::optional<unsigned> verbosity) {
4051 emitError(op,
"SV attributes emission is unimplemented for the op");
4054 SmallPtrSet<Operation *, 8> ops;
4056 ps.addCallback({op,
true});
4058 if (verbosity && *verbosity != 1) {
4060 ps.addAsString(*verbosity);
4064 ps.addCallback({op,
false});
4065 emitLocationInfoAndNewLine(ops);
4069 LogicalResult StmtEmitter::visitSV(StopOp op) {
4070 return emitSimulationControlTask(op,
PPExtString(
"$stop"), op.getVerbosity());
4073 LogicalResult StmtEmitter::visitSV(FinishOp op) {
4074 return emitSimulationControlTask(op,
PPExtString(
"$finish"),
4078 LogicalResult StmtEmitter::visitSV(ExitOp op) {
4079 return emitSimulationControlTask(op,
PPExtString(
"$exit"), {});
4085 StmtEmitter::emitSeverityMessageTask(Operation *op,
PPExtString taskName,
4086 std::optional<unsigned> verbosity,
4087 StringAttr message, ValueRange operands) {
4089 emitError(op,
"SV attributes emission is unimplemented for the op");
4092 SmallPtrSet<Operation *, 8> ops;
4094 ps.addCallback({op,
true});
4100 if ((verbosity && *verbosity != 1) || message) {
4102 ps.scopedBox(PP::ibox0, [&]() {
4106 ps.addAsString(*verbosity);
4111 ps <<
"," << PP::space;
4112 ps.writeQuotedEscaped(message.getValue());
4114 for (
auto operand : operands) {
4115 ps <<
"," << PP::space;
4116 emitExpression(operand, ops);
4125 ps.addCallback({op,
false});
4126 emitLocationInfoAndNewLine(ops);
4130 LogicalResult StmtEmitter::visitSV(FatalOp op) {
4131 return emitSeverityMessageTask(op,
PPExtString(
"$fatal"), op.getVerbosity(),
4132 op.getMessageAttr(), op.getSubstitutions());
4135 LogicalResult StmtEmitter::visitSV(ErrorOp op) {
4136 return emitSeverityMessageTask(op,
PPExtString(
"$error"), {},
4137 op.getMessageAttr(), op.getSubstitutions());
4140 LogicalResult StmtEmitter::visitSV(WarningOp op) {
4141 return emitSeverityMessageTask(op,
PPExtString(
"$warning"), {},
4142 op.getMessageAttr(), op.getSubstitutions());
4145 LogicalResult StmtEmitter::visitSV(InfoOp op) {
4146 return emitSeverityMessageTask(op,
PPExtString(
"$info"), {},
4147 op.getMessageAttr(), op.getSubstitutions());
4150 LogicalResult StmtEmitter::visitSV(ReadMemOp op) {
4151 SmallPtrSet<Operation *, 8> ops({op});
4154 ps.addCallback({op,
true});
4156 switch (op.getBaseAttr().getValue()) {
4157 case MemBaseTypeAttr::MemBaseBin:
4160 case MemBaseTypeAttr::MemBaseHex:
4165 ps.scopedBox(PP::ibox0, [&]() {
4166 ps.writeQuotedEscaped(op.getFilename());
4167 ps <<
"," << PP::space;
4168 emitExpression(op.getDest(), ops);
4172 ps.addCallback({op,
false});
4173 emitLocationInfoAndNewLine(ops);
4177 LogicalResult StmtEmitter::visitSV(GenerateOp op) {
4178 emitSVAttributes(op);
4181 ps.addCallback({op,
true});
4182 ps <<
"generate" << PP::newline;
4184 setPendingNewline();
4185 emitStatementBlock(op.getBody().getBlocks().front());
4188 ps <<
"endgenerate";
4189 ps.addCallback({op,
false});
4190 setPendingNewline();
4194 LogicalResult StmtEmitter::visitSV(GenerateCaseOp op) {
4195 emitSVAttributes(op);
4198 ps.addCallback({op,
true});
4200 ps.invokeWithStringOS([&](
auto &os) {
4201 emitter.printParamValue(
4202 op.getCond(), os, VerilogPrecedence::Selection,
4203 [&]() { return op->emitOpError(
"invalid case parameter"); });
4206 setPendingNewline();
4209 ArrayAttr
patterns = op.getCasePatterns();
4210 ArrayAttr caseNames = op.getCaseNames();
4211 MutableArrayRef<Region> regions = op.getCaseRegions();
4218 llvm::StringMap<size_t> nextGenIds;
4219 ps.scopedBox(PP::bbox2, [&]() {
4221 for (
size_t i = 0, e =
patterns.size(); i < e; ++i) {
4222 auto ®ion = regions[i];
4223 assert(region.hasOneBlock());
4224 Attribute patternAttr = patterns[i];
4227 if (!patternAttr.isa<mlir::TypedAttr>())
4230 ps.invokeWithStringOS([&](auto &os) {
4231 emitter.printParamValue(
4232 patternAttr, os, VerilogPrecedence::LowestPrecedence,
4233 [&]() { return op->emitOpError(
"invalid case value"); });
4236 StringRef legalName =
4237 legalizeName(caseNames[i].cast<StringAttr>().getValue(), nextGenIds,
4240 setPendingNewline();
4241 emitStatementBlock(region.getBlocks().front());
4244 setPendingNewline();
4250 ps.addCallback({op,
false});
4251 setPendingNewline();
4255 LogicalResult StmtEmitter::visitSV(ForOp op) {
4256 emitSVAttributes(op);
4257 llvm::SmallPtrSet<Operation *, 8> ops;
4258 ps.addCallback({op,
true});
4260 auto inductionVarName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
4263 ps.scopedBox(PP::cbox0, [&]() {
4267 ps <<
"logic" << PP::nbsp;
4268 ps.invokeWithStringOS([&](
auto &os) {
4269 emitter.emitTypeDims(op.getInductionVar().getType(), op.getLoc(),
4274 [&]() { emitExpression(op.getLowerBound(), ops); },
PPExtString(
"="));
4279 emitAssignLike([&]() { ps <<
PPExtString(inductionVarName); },
4280 [&]() { emitExpression(op.getUpperBound(), ops); },
4286 emitAssignLike([&]() { ps <<
PPExtString(inductionVarName); },
4287 [&]() { emitExpression(op.getStep(), ops); },
4291 ps << PP::neverbreak;
4292 setPendingNewline();
4293 emitStatementBlock(op.getBody().getBlocks().front());
4296 ps.addCallback({op,
false});
4297 emitLocationInfoAndNewLine(ops);
4302 void StmtEmitter::emitAssertionLabel(Operation *op) {
4303 if (
auto label = op->getAttrOfType<StringAttr>(
"hw.verilogName"))
4309 void StmtEmitter::emitAssertionMessage(StringAttr message, ValueRange args,
4310 SmallPtrSetImpl<Operation *> &ops,
4311 bool isConcurrent =
false) {
4314 ps << PP::space <<
"else" << PP::nbsp <<
"$error(";
4315 ps.scopedBox(PP::ibox0, [&]() {
4316 ps.writeQuotedEscaped(message.getValue());
4318 for (
auto arg : args) {
4319 ps <<
"," << PP::space;
4320 emitExpression(arg, ops);
4326 template <
typename Op>
4327 LogicalResult StmtEmitter::emitImmediateAssertion(Op op,
PPExtString opName) {
4329 emitError(op,
"SV attributes emission is unimplemented for the op");
4332 SmallPtrSet<Operation *, 8> ops;
4334 ps.addCallback({op,
true});
4335 ps.scopedBox(PP::ibox2, [&]() {
4336 emitAssertionLabel(op);
4337 ps.scopedBox(PP::cbox0, [&]() {
4339 switch (op.getDefer()) {
4340 case DeferAssert::Immediate:
4342 case DeferAssert::Observed:
4345 case DeferAssert::Final:
4350 ps.scopedBox(PP::ibox0, [&]() {
4351 emitExpression(op.getExpression(), ops);
4354 emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops);
4358 ps.addCallback({op,
false});
4359 emitLocationInfoAndNewLine(ops);
4363 LogicalResult StmtEmitter::visitSV(AssertOp op) {
4364 return emitImmediateAssertion(op,
PPExtString(
"assert"));
4367 LogicalResult StmtEmitter::visitSV(AssumeOp op) {
4368 return emitImmediateAssertion(op,
PPExtString(
"assume"));
4371 LogicalResult StmtEmitter::visitSV(CoverOp op) {
4372 return emitImmediateAssertion(op,
PPExtString(
"cover"));
4375 template <
typename Op>
4376 LogicalResult StmtEmitter::emitConcurrentAssertion(Op op,
PPExtString opName) {
4378 emitError(op,
"SV attributes emission is unimplemented for the op");
4381 SmallPtrSet<Operation *, 8> ops;
4383 ps.addCallback({op,
true});
4384 ps.scopedBox(PP::ibox2, [&]() {
4385 emitAssertionLabel(op);
4386 ps.scopedBox(PP::cbox0, [&]() {
4387 ps << opName << PP::nbsp <<
"property (";
4388 ps.scopedBox(PP::ibox0, [&]() {
4389 ps <<
"@(" <<
PPExtString(stringifyEventControl(op.getEvent()))
4391 emitExpression(op.getClock(), ops);
4392 ps <<
")" << PP::space;
4393 emitExpression(op.getProperty(), ops);
4396 emitAssertionMessage(op.getMessageAttr(), op.getSubstitutions(), ops,
4401 ps.addCallback({op,
false});
4402 emitLocationInfoAndNewLine(ops);
4406 LogicalResult StmtEmitter::visitSV(AssertConcurrentOp op) {
4407 return emitConcurrentAssertion(op,
PPExtString(
"assert"));
4410 LogicalResult StmtEmitter::visitSV(AssumeConcurrentOp op) {
4411 return emitConcurrentAssertion(op,
PPExtString(
"assume"));
4414 LogicalResult StmtEmitter::visitSV(CoverConcurrentOp op) {
4415 return emitConcurrentAssertion(op,
PPExtString(
"cover"));
4420 LogicalResult StmtEmitter::emitVerifAssertLike(Operation *op, Value property,
4423 emitError(op,
"SV attributes emission is unimplemented for the op");
4433 bool isTemporal = !
property.getType().isSignlessInteger(1);
4434 bool isProcedural = op->getParentOp()->hasTrait<ProceduralRegion>();
4435 bool emitAsImmediate = !isTemporal && isProcedural;
4438 SmallPtrSet<Operation *, 8> ops;
4440 ps.addCallback({op,
true});
4441 ps.scopedBox(PP::ibox2, [&]() {
4442 emitAssertionLabel(op);
4443 ps.scopedBox(PP::cbox0, [&]() {
4444 if (emitAsImmediate)
4445 ps << opName <<
"(";
4447 ps << opName << PP::nbsp <<
"property" << PP::nbsp <<
"(";
4448 ps.scopedBox(PP::ibox2, [&]() {
4449 PropertyEmitter(emitter, ops).emitProperty(property);
4454 ps.addCallback({op,
false});
4455 emitLocationInfoAndNewLine(ops);
4459 LogicalResult StmtEmitter::visitVerif(verif::AssertOp op) {
4460 return emitVerifAssertLike(op, op.getProperty(),
PPExtString(
"assert"));
4463 LogicalResult StmtEmitter::visitVerif(verif::AssumeOp op) {
4464 return emitVerifAssertLike(op, op.getProperty(),
PPExtString(
"assume"));
4467 LogicalResult StmtEmitter::visitVerif(verif::CoverOp op) {
4468 return emitVerifAssertLike(op, op.getProperty(),
PPExtString(
"cover"));
4471 LogicalResult StmtEmitter::emitIfDef(Operation *op, MacroIdentAttr cond) {
4473 emitError(op,
"SV attributes emission is unimplemented for the op");
4478 bool hasEmptyThen = op->getRegion(0).front().empty();
4480 ps <<
"`ifndef " << ident;
4482 ps <<
"`ifdef " << ident;
4484 SmallPtrSet<Operation *, 8> ops;
4486 emitLocationInfoAndNewLine(ops);
4489 emitStatementBlock(op->getRegion(0).front());
4491 if (!op->getRegion(1).empty()) {
4492 if (!hasEmptyThen) {
4494 ps <<
"`else // " << ident;
4495 setPendingNewline();
4497 emitStatementBlock(op->getRegion(1).front());
4504 setPendingNewline();
4512 void StmtEmitter::emitBlockAsStatement(
4513 Block *block,
const SmallPtrSetImpl<Operation *> &locationOps,
4514 StringRef multiLineComment) {
4521 emitLocationInfoAndNewLine(locationOps);
4524 emitStatementBlock(*block);
4526 if (needsBeginEnd) {
4530 if (!multiLineComment.empty())
4531 ps <<
" // " << multiLineComment;
4532 setPendingNewline();
4536 LogicalResult StmtEmitter::visitSV(OrderedOutputOp ooop) {
4538 for (
auto &op : ooop.getBody().front())
4543 LogicalResult StmtEmitter::visitSV(IfOp op) {
4544 SmallPtrSet<Operation *, 8> ops;
4546 auto ifcondBox = PP::ibox2;
4548 emitSVAttributes(op);
4550 ps.addCallback({op,
true});
4551 ps <<
"if (" << ifcondBox;
4561 emitExpression(ifOp.getCond(), ops);
4562 ps << PP::end <<
")";
4563 emitBlockAsStatement(ifOp.getThenBlock(), ops);
4565 if (!ifOp.hasElse())
4569 Block *elseBlock = ifOp.getElseBlock();
4571 if (!nestedElseIfOp) {
4576 emitBlockAsStatement(elseBlock, ops);
4582 ifOp = nestedElseIfOp;
4583 ps <<
"else if (" << ifcondBox;
4585 ps.addCallback({op,
false});
4590 LogicalResult StmtEmitter::visitSV(AlwaysOp op) {
4591 emitSVAttributes(op);
4592 SmallPtrSet<Operation *, 8> ops;
4596 auto printEvent = [&](AlwaysOp::Condition cond) {
4597 ps <<
PPExtString(stringifyEventControl(cond.event)) << PP::nbsp;
4598 ps.scopedBox(PP::cbox0, [&]() { emitExpression(cond.value, ops); });
4600 ps.addCallback({op,
true});
4602 switch (op.getNumConditions()) {
4608 printEvent(op.getCondition(0));
4613 ps.scopedBox(PP::cbox0, [&]() {
4614 printEvent(op.getCondition(0));
4615 for (
size_t i = 1, e = op.getNumConditions(); i != e; ++i) {
4616 ps << PP::space <<
"or" << PP::space;
4617 printEvent(op.getCondition(i));
4626 std::string comment;
4627 if (op.getNumConditions() == 0) {
4628 comment =
"always @*";
4630 comment =
"always @(";
4633 [&](Attribute eventAttr) {
4634 auto event = sv::EventControl(eventAttr.cast<IntegerAttr>().getInt());
4635 comment += stringifyEventControl(event);
4637 [&]() { comment +=
", "; });
4641 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
4642 ps.addCallback({op,
false});
4646 LogicalResult StmtEmitter::visitSV(AlwaysCombOp op) {
4647 emitSVAttributes(op);
4648 SmallPtrSet<Operation *, 8> ops;
4652 ps.addCallback({op,
true});
4653 StringRef opString =
"always_comb";
4654 if (state.options.noAlwaysComb)
4655 opString =
"always @(*)";
4658 emitBlockAsStatement(op.getBodyBlock(), ops, opString);
4659 ps.addCallback({op,
false});
4663 LogicalResult StmtEmitter::visitSV(AlwaysFFOp op) {
4664 emitSVAttributes(op);
4666 SmallPtrSet<Operation *, 8> ops;
4670 ps.addCallback({op,
true});
4671 ps <<
"always_ff @(";
4672 ps.scopedBox(PP::cbox0, [&]() {
4673 ps <<
PPExtString(stringifyEventControl(op.getClockEdge())) << PP::nbsp;
4674 emitExpression(op.getClock(), ops);
4675 if (op.getResetStyle() == ResetType::AsyncReset) {
4676 ps << PP::nbsp <<
"or" << PP::space
4677 <<
PPExtString(stringifyEventControl(*op.getResetEdge())) << PP::nbsp;
4678 emitExpression(op.getReset(), ops);
4685 std::string comment;
4686 comment +=
"always_ff @(";
4687 comment += stringifyEventControl(op.getClockEdge());
4688 if (op.getResetStyle() == ResetType::AsyncReset) {
4690 comment += stringifyEventControl(*op.getResetEdge());
4694 if (op.getResetStyle() == ResetType::NoReset)
4695 emitBlockAsStatement(op.getBodyBlock(), ops, comment);
4698 emitLocationInfoAndNewLine(ops);
4699 ps.scopedBox(PP::bbox2, [&]() {
4705 if (op.getResetStyle() == ResetType::AsyncReset &&
4706 *op.getResetEdge() == sv::EventControl::AtNegEdge)
4708 emitExpression(op.getReset(), ops);
4710 emitBlockAsStatement(op.getResetBlock(), ops);
4713 emitBlockAsStatement(op.getBodyBlock(), ops);
4718 ps <<
" // " << comment;
4719 setPendingNewline();
4721 ps.addCallback({op,
false});
4725 LogicalResult StmtEmitter::visitSV(InitialOp op) {
4726 emitSVAttributes(op);
4727 SmallPtrSet<Operation *, 8> ops;
4730 ps.addCallback({op,
true});
4732 emitBlockAsStatement(op.getBodyBlock(), ops,
"initial");
4733 ps.addCallback({op,
false});
4737 LogicalResult StmtEmitter::visitSV(CaseOp op) {
4738 emitSVAttributes(op);
4739 SmallPtrSet<Operation *, 8> ops, emptyOps;
4742 ps.addCallback({op,
true});
4743 if (op.getValidationQualifier() !=
4744 ValidationQualifierTypeEnum::ValidationQualifierPlain)
4745 ps <<
PPExtString(circt::sv::stringifyValidationQualifierTypeEnum(
4746 op.getValidationQualifier()))
4748 const char *opname =
nullptr;
4749 switch (op.getCaseStyle()) {
4750 case CaseStmtType::CaseStmt:
4753 case CaseStmtType::CaseXStmt:
4756 case CaseStmtType::CaseZStmt:
4760 ps << opname <<
" (";
4761 ps.scopedBox(PP::ibox0, [&]() {
4762 emitExpression(op.getCond(), ops);
4765 emitLocationInfoAndNewLine(ops);
4767 ps.scopedBox(PP::bbox2, [&]() {
4768 for (
auto &caseInfo : op.getCases()) {
4770 auto &pattern = caseInfo.pattern;
4772 llvm::TypeSwitch<CasePattern *>(pattern.get())
4773 .Case<CaseBitPattern>([&](auto bitPattern) {
4776 ps.invokeWithStringOS([&](auto &os) {
4777 os << bitPattern->getWidth() <<
"'b";
4778 for (size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
4779 os << getLetter(bitPattern->getBit(e - bit - 1));
4782 .Case<CaseEnumPattern>([&](
auto enumPattern) {
4783 ps <<
PPExtString(emitter.fieldNameResolver.getEnumFieldName(
4784 enumPattern->attr().template cast<hw::EnumFieldAttr>()));
4786 .Case<CaseDefaultPattern>([&](
auto) { ps <<
"default"; })
4787 .Default([&](
auto) {
assert(
false &&
"unhandled case pattern"); });
4790 emitBlockAsStatement(caseInfo.block, emptyOps);
4796 ps.addCallback({op,
false});
4797 emitLocationInfoAndNewLine(ops);
4801 LogicalResult StmtEmitter::visitStmt(InstanceOp op) {
4802 bool doNotPrint = op->hasAttr(
"doNotPrint");
4803 if (doNotPrint && !state.options.emitBindComments)
4808 emitSVAttributes(op);
4810 ps.addCallback({op,
true});
4813 <<
"/* This instance is elsewhere emitted as a bind statement."
4816 op->emitWarning() <<
"is emitted as a bind statement but has SV "
4817 "attributes. The attributes will not be emitted.";
4820 SmallPtrSet<Operation *, 8> ops;
4824 auto *moduleOp = op.getReferencedModuleCached(&state.symbolCache);
4825 assert(moduleOp &&
"Invalid IR");
4829 if (!op.getParameters().empty()) {
4832 bool printed =
false;
4834 llvm::zip(op.getParameters(),
4835 moduleOp->getAttrOfType<ArrayAttr>(
"parameters"))) {
4836 auto param = std::get<0>(params).cast<ParamDeclAttr>();
4837 auto modParam = std::get<1>(params).cast<ParamDeclAttr>();
4839 if (param.getValue() == modParam.getValue())
4844 ps <<
" #(" << PP::bbox2 << PP::newline;
4847 ps <<
"," << PP::newline;
4851 state.globalNames.getParameterVerilogName(moduleOp, param.getName()));
4853 ps.invokeWithStringOS([&](
auto &os) {
4854 emitter.printParamValue(param.getValue(), os, [&]() {
4855 return op->emitOpError(
"invalid instance parameter '")
4856 << param.getName().getValue() <<
"' value";
4862 ps << PP::end << PP::newline <<
")";
4868 auto modPortInfo = cast<PortList>(moduleOp).getPortList();
4870 size_t maxNameLength = 0;
4871 for (
auto &elt : modPortInfo) {
4876 auto getWireForValue = [&](Value result) {
4877 return result.getUsers().begin()->getOperand(0);
4881 bool isFirst =
true;
4882 bool isZeroWidth =
false;
4884 auto containingModule = cast<HWModuleOp>(emitter.currentModuleOp);
4885 auto containingPortList = containingModule.getPortList();
4886 SmallVector<Value> instPortValues(modPortInfo.size());
4887 op.getValues(instPortValues, modPortInfo);
4888 for (
size_t portNum = 0, portEnd = modPortInfo.size(); portNum < portEnd;
4890 auto &modPort = modPortInfo.at(portNum);
4892 Value portVal = instPortValues[portNum];
4897 bool shouldPrintComma =
true;
4899 shouldPrintComma =
false;
4900 for (
size_t i = portNum + 1, e = modPortInfo.size(); i != e; ++i)
4902 shouldPrintComma =
true;
4907 if (shouldPrintComma)
4910 emitLocationInfoAndNewLine(ops);
4925 ps.scopedBox(isZeroWidth ? PP::neverbox : PP::ibox2, [&]() {
4928 ps.spaces(maxNameLength - modPortName.size() + 1);
4930 ps.scopedBox(PP::ibox0, [&]() {
4937 if (!modPort.isOutput()) {
4939 isa_and_nonnull<ConstantOp>(portVal.getDefiningOp()))
4940 ps <<
"/* Zero width */";
4942 emitExpression(portVal, ops, LowestPrecedence);
4943 }
else if (portVal.use_empty()) {
4944 ps <<
"/* unused */";
4945 }
else if (portVal.hasOneUse() &&
4946 (output = dyn_cast_or_null<OutputOp>(
4947 portVal.getUses().begin()->getOwner()))) {
4952 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
4953 ps << PPExtString(getPortVerilogName(
4954 containingModule, containingPortList.atOutput(outputPortNo)));
4956 portVal = getWireForValue(portVal);
4957 emitExpression(portVal, ops);
4963 if (!isFirst || isZeroWidth) {
4964 emitLocationInfoAndNewLine(ops);
4969 ps.addCallback({op,
false});
4970 emitLocationInfoAndNewLine(ops);
4975 setPendingNewline();
4986 LogicalResult StmtEmitter::visitSV(BindOp op) {
4987 emitter.emitBind(op);
4988 assert(state.pendingNewline);
4992 LogicalResult StmtEmitter::visitSV(InterfaceOp op) {
4993 emitComment(op.getCommentAttr());
4995 emitSVAttributes(op);
4998 ps.addCallback({op,
true});
5000 setPendingNewline();
5002 emitStatementBlock(*op.getBodyBlock());
5004 ps <<
"endinterface" << PP::newline;
5005 ps.addCallback({op,
false});
5006 setPendingNewline();
5010 LogicalResult StmtEmitter::visitSV(InterfaceSignalOp op) {
5012 emitSVAttributes(op);
5014 ps.addCallback({op,
true});
5016 ps << PP::neverbox <<
"// ";
5017 ps.invokeWithStringOS([&](
auto &os) {
5022 ps.invokeWithStringOS(
5023 [&](
auto &os) { emitter.printUnpackedTypePostfix(op.getType(), os); });
5027 ps.addCallback({op,
false});
5028 setPendingNewline();
5032 LogicalResult StmtEmitter::visitSV(InterfaceModportOp op) {
5034 ps.addCallback({op,
true});
5038 llvm::interleaveComma(op.getPorts(), ps, [&](
const Attribute &portAttr) {
5039 auto port = portAttr.cast<ModportStructAttr>();
5040 ps << PPExtString(stringifyEnum(port.getDirection().getValue())) <<
" ";
5041 auto *signalDecl = state.symbolCache.getDefinition(port.getSignal());
5042 ps << PPExtString(getSymOpName(signalDecl));
5046 ps.addCallback({op,
false});
5047 setPendingNewline();
5051 LogicalResult StmtEmitter::visitSV(AssignInterfaceSignalOp op) {
5053 ps.addCallback({op,
true});
5054 SmallPtrSet<Operation *, 8> emitted;
5057 emitExpression(op.getIface(), emitted);
5058 ps <<
"." <<
PPExtString(op.getSignalName()) <<
" = ";
5059 emitExpression(op.getRhs(), emitted);
5061 ps.addCallback({op,
false});
5062 setPendingNewline();
5066 LogicalResult StmtEmitter::visitSV(MacroDefOp op) {
5067 auto decl = op.getReferencedMacro(&state.symbolCache);
5070 ps.addCallback({op,
true});
5072 if (decl.getArgs()) {
5074 llvm::interleaveComma(*decl.getArgs(), ps, [&](
const Attribute &name) {
5075 ps << name.cast<StringAttr>();
5079 if (!op.getFormatString().empty()) {
5081 emitTextWithSubstitutions(ps, op.getFormatString(), op, {},
5084 ps.addCallback({op,
false});
5085 setPendingNewline();
5089 void StmtEmitter::emitStatement(Operation *op) {
5096 if (isa<ltl::LTLDialect>(op->getDialect()))
5100 if (succeeded(dispatchStmtVisitor(op)) || succeeded(dispatchSVVisitor(op)) ||
5101 succeeded(dispatchVerifVisitor(op)))
5104 emitOpError(op,
"emission to Verilog not supported");
5105 emitPendingNewlineIfNeeded();
5106 ps <<
"unknown MLIR operation " <<
PPExtString(op->getName().getStringRef());
5107 setPendingNewline();
5118 StmtEmitter &stmtEmitter) {
5125 if (isa<IfDefProceduralOp>(op->getParentOp()))
5133 SmallVector<Value, 8> exprsToScan(op->getOperands());
5138 while (!exprsToScan.empty()) {
5139 Operation *expr = exprsToScan.pop_back_val().getDefiningOp();
5146 if (
auto readInout = dyn_cast<sv::ReadInOutOp>(expr)) {
5147 auto *defOp = readInout.getOperand().getDefiningOp();
5154 if (isa<sv::WireOp>(defOp))
5159 if (!isa<RegOp, LogicOp>(defOp))
5165 if (isa<LogicOp>(defOp) &&
5166 stmtEmitter.emitter.expressionsEmittedIntoDecl.count(defOp))
5170 if (llvm::all_of(defOp->getResult(0).getUsers(), [&](Operation *op) {
5171 return isa<ReadInOutOp, PAssignOp, AssignOp>(op);
5179 exprsToScan.append(expr->getOperands().begin(),
5180 expr->getOperands().end());
5186 if (expr->getBlock() != op->getBlock())
5191 if (!stmtEmitter.emitter.expressionsEmittedIntoDecl.count(expr))
5198 template <
class AssignTy>
5200 AssignTy singleAssign;
5201 if (llvm::all_of(op->getUsers(), [&](Operation *user) {
5202 if (hasSVAttributes(user))
5205 if (auto assign = dyn_cast<AssignTy>(user)) {
5208 singleAssign = assign;
5212 return isa<ReadInOutOp>(user);
5214 return singleAssign;
5220 return llvm::all_of(op2->getUsers(), [&](Operation *user) {
5224 if (op1->getBlock() != user->getBlock())
5230 return op1->isBeforeInBlock(user);
5234 LogicalResult StmtEmitter::emitDeclaration(Operation *op) {
5235 emitSVAttributes(op);
5236 auto value = op->getResult(0);
5237 SmallPtrSet<Operation *, 8> opsForLocation;
5238 opsForLocation.insert(op);
5240 ps.addCallback({op,
true});
5243 auto type = value.getType();
5246 ps.scopedBox(isZeroBit ? PP::neverbox : PP::ibox2, [&]() {
5250 unsigned spaces = 0;
5251 if (word.size() < maxDeclNameWidth)
5252 spaces += maxDeclNameWidth - word.size();
5253 auto extraIndent = word.empty() ? 0 : 1;
5254 ps.spaces(spaces + extraIndent);
5256 ps <<
"// Zero width: " <<
PPExtString(word) << PP::space;
5259 SmallString<8> typeString;
5262 llvm::raw_svector_ostream stringStream(typeString);
5267 if (!typeString.empty())
5269 if (typeString.size() < maxTypeWidth)
5270 ps.spaces(maxTypeWidth - typeString.size());
5276 ps.invokeWithStringOS(
5277 [&](
auto &os) { emitter.printUnpackedTypePostfix(type, os); });
5280 if (state.options.printDebugInfo) {
5281 if (
auto innerSymOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
5282 auto innerSym = innerSymOp.getInnerSymAttr();
5283 if (innerSym && !innerSym.empty()) {
5285 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
5291 if (
auto localparam = dyn_cast<LocalParamOp>(op)) {
5292 ps << PP::space <<
"=" << PP::space;
5293 ps.invokeWithStringOS([&](
auto &os) {
5294 emitter.printParamValue(localparam.getValue(), os, [&]() {
5295 return op->emitOpError(
"invalid localparam value");
5300 if (
auto regOp = dyn_cast<RegOp>(op)) {
5301 if (
auto initValue = regOp.getInit()) {
5302 ps << PP::space <<
"=" << PP::space;
5303 ps.scopedBox(PP::ibox0,
5304 [&]() { emitExpression(initValue, opsForLocation); });
5309 if (isa<sv::WireOp, LogicOp>(op) &&
5310 !op->getParentOp()->hasTrait<ProceduralRegion>()) {
5312 if (
auto singleAssign = getSingleAssignAndCheckUsers<AssignOp>(op)) {
5313 auto *source = singleAssign.getSrc().getDefiningOp();
5317 if (!source || isa<ConstantOp>(source) ||
5318 op->getNextNode() == singleAssign) {
5319 ps << PP::space <<
"=" << PP::space;
5320 ps.scopedBox(PP::ibox0, [&]() {
5321 emitExpression(singleAssign.getSrc(), opsForLocation);
5323 emitter.assignsInlined.insert(singleAssign);
5329 if (isa<LogicOp>(op) && op->getParentOp()->hasTrait<ProceduralRegion>()) {
5331 if (
auto singleAssign = getSingleAssignAndCheckUsers<BPAssignOp>(op)) {
5334 auto *source = singleAssign.getSrc().getDefiningOp();
5338 if (!source || isa<ConstantOp>(source) ||
5341 ps << PP::space <<
"=" << PP::space;
5342 ps.scopedBox(PP::ibox0, [&]() {
5343 emitExpression(singleAssign.getSrc(), opsForLocation);
5346 emitter.assignsInlined.insert(singleAssign);
5347 emitter.expressionsEmittedIntoDecl.insert(op);
5354 ps.addCallback({op,
false});
5355 emitLocationInfoAndNewLine(opsForLocation);
5359 void StmtEmitter::collectNamesAndCalculateDeclarationWidths(Block &block) {
5362 NameCollector collector(emitter);
5363 collector.collectNames(block);
5366 maxDeclNameWidth = collector.getMaxDeclNameWidth();
5367 maxTypeWidth = collector.getMaxTypeWidth();
5369 if (maxTypeWidth > 0)
5373 void StmtEmitter::emitStatementBlock(Block &body) {
5374 ps.scopedBox(PP::bbox2, [&]() {
5379 llvm::SaveAndRestore<size_t> x(maxDeclNameWidth);
5380 llvm::SaveAndRestore<size_t> x2(maxTypeWidth);
5385 if (!isa<IfDefProceduralOp>(body.getParentOp()))
5386 collectNamesAndCalculateDeclarationWidths(body);
5389 for (
auto &op : body) {
5396 void ModuleEmitter::emitStatement(Operation *op) {
5397 StmtEmitter(*
this, state.options).emitStatement(op);
5402 void ModuleEmitter::emitSVAttributes(Operation *op) {
5410 setPendingNewline();
5417 void ModuleEmitter::emitHWExternModule(HWModuleExternOp module) {
5418 auto verilogName = module.getVerilogModuleNameAttr();
5420 ps.addCallback({module,
true});
5421 ps <<
"// external module " <<
PPExtString(verilogName.getValue())
5423 ps.addCallback({module,
false});
5424 setPendingNewline();
5427 void ModuleEmitter::emitHWGeneratedModule(HWModuleGeneratedOp module) {
5428 auto verilogName = module.getVerilogModuleNameAttr();
5430 ps <<
"// external generated module " <<
PPExtString(verilogName.getValue())
5432 setPendingNewline();
5441 void ModuleEmitter::emitBind(BindOp op) {
5443 emitError(op,
"SV attributes emission is unimplemented for the op");
5444 InstanceOp inst = op.getReferencedInstance(&state.symbolCache);
5446 HWModuleOp parentMod = inst->getParentOfType<hw::HWModuleOp>();
5447 auto parentPortList = parentMod.getPortList();
5450 Operation *childMod = inst.getReferencedModuleCached(&state.symbolCache);
5454 ps.addCallback({op,
true});
5455 ps <<
"bind " <<
PPExtString(parentVerilogName.getValue()) << PP::nbsp
5456 <<
PPExtString(childVerilogName.getValue()) << PP::nbsp
5458 bool isFirst =
true;
5459 ps.scopedBox(PP::bbox2, [&]() {
5460 auto parentPortInfo = parentMod.getPortList();
5461 auto childPortInfo = cast<PortList>(childMod).getPortList();
5464 size_t maxNameLength = 0;
5465 for (
auto &elt : childPortInfo) {
5467 elt.name = Builder(inst.getContext()).getStringAttr(portName);
5468 maxNameLength = std::max(maxNameLength, elt.getName().size());
5471 SmallVector<Value> instPortValues(childPortInfo.size());
5472 inst.getValues(instPortValues, childPortInfo);
5474 for (
auto [idx, elt] : llvm::enumerate(childPortInfo)) {
5476 Value portVal = instPortValues[idx];
5482 bool shouldPrintComma =
true;
5484 shouldPrintComma =
false;
5485 for (
size_t i = idx + 1, e = childPortInfo.size(); i != e; ++i)
5487 shouldPrintComma =
true;
5492 if (shouldPrintComma)
5505 ps << PP::neverbox <<
"//";
5509 ps.nbsp(maxNameLength - elt.getName().size());
5511 llvm::SmallPtrSet<Operation *, 4> ops;
5512 if (elt.isOutput()) {
5513 assert((portVal.hasOneUse() || portVal.use_empty()) &&
5514 "output port must have either single or no use");
5515 if (portVal.use_empty()) {
5516 ps <<
"/* unused */";
5517 }
else if (
auto output = dyn_cast_or_null<OutputOp>(
5518 portVal.getUses().begin()->getOwner())) {
5521 size_t outputPortNo = portVal.getUses().begin()->getOperandNumber();
5523 parentMod, parentPortList.atOutput(outputPortNo)));
5525 portVal = portVal.getUsers().begin()->getOperand(0);
5526 ExprEmitter(*
this, ops).emitExpression(portVal, LowestPrecedence);
5529 ExprEmitter(*
this, ops).emitExpression(portVal, LowestPrecedence);
5541 ps.addCallback({op,
false});
5542 setPendingNewline();
5545 void ModuleEmitter::emitBindInterface(BindInterfaceOp op) {
5547 emitError(op,
"SV attributes emission is unimplemented for the op");
5549 auto instance = op.getReferencedInstance(&state.symbolCache);
5550 auto instantiator = instance->getParentOfType<HWModuleOp>().
getName();
5551 auto *
interface = op->getParentOfType<ModuleOp>().lookupSymbol(
5552 instance.getInterfaceType().getInterface());
5554 ps.addCallback({op,
true});
5555 ps <<
"bind " <<
PPExtString(instantiator) << PP::nbsp
5556 <<
PPExtString(cast<InterfaceOp>(*interface).getSymName()) << PP::nbsp
5558 ps.addCallback({op,
false});
5559 setPendingNewline();
5562 void ModuleEmitter::emitParameters(Operation *module, ArrayAttr params) {
5566 auto printParamType = [&](Type type, Attribute defaultValue,
5567 SmallString<8> &result) {
5569 llvm::raw_svector_ostream sstream(result);
5574 if (
auto intAttr = defaultValue.dyn_cast<IntegerAttr>())
5575 if (intAttr.getValue().getBitWidth() == 32)
5577 if (
auto fpAttr = defaultValue.dyn_cast<FloatAttr>())
5578 if (fpAttr.getType().isF64())
5581 if (type.isa<NoneType>())
5588 if (
auto intType = type_dyn_cast<IntegerType>(type))
5589 if (intType.getWidth() == 32) {
5590 sstream <<
"/*integer*/";
5594 printPackedType(type, sstream, module->getLoc(),
5602 size_t maxTypeWidth = 0;
5603 SmallString<8> scratch;
5604 for (
auto param : params) {
5605 auto paramAttr = param.cast<ParamDeclAttr>();
5607 printParamType(paramAttr.getType(), paramAttr.getValue(), scratch);
5608 maxTypeWidth = std::max(scratch.size(), maxTypeWidth);
5611 if (maxTypeWidth > 0)
5614 ps.scopedBox(PP::bbox2, [&]() {
5615 ps << PP::newline <<
"#(";
5616 ps.scopedBox(PP::cbox0, [&]() {
5619 [&](Attribute param) {
5620 auto paramAttr = param.cast<ParamDeclAttr>();
5621 auto defaultValue = paramAttr.getValue();
5623 printParamType(paramAttr.getType(), defaultValue, scratch);
5624 if (!scratch.empty())
5626 if (scratch.size() < maxTypeWidth)
5627 ps.nbsp(maxTypeWidth - scratch.size());
5629 ps <<
PPExtString(state.globalNames.getParameterVerilogName(
5630 module, paramAttr.getName()));
5634 ps.invokeWithStringOS([&](
auto &os) {
5636 return module->emitError(
"parameter '")
5637 << paramAttr.getName().getValue()
5638 <<
"' has invalid value";
5643 [&]() { ps <<
"," << PP::newline; });
5649 void ModuleEmitter::emitPortList(Operation *module,
5650 const ModulePortInfo &portInfo) {
5652 if (portInfo.size())
5653 emitLocationInfo(module->getLoc());
5657 bool hasOutputs =
false, hasZeroWidth =
false;
5658 size_t maxTypeWidth = 0, lastNonZeroPort = -1;
5659 SmallVector<SmallString<8>, 16> portTypeStrings;
5661 for (
size_t i = 0, e = portInfo.size(); i < e; ++i) {
5662 auto port = portInfo.at(i);
5663 hasOutputs |= port.isOutput();
5666 lastNonZeroPort = i;
5669 portTypeStrings.push_back({});
5671 llvm::raw_svector_ostream stringStream(portTypeStrings.back());
5676 maxTypeWidth = std::max(portTypeStrings.back().size(), maxTypeWidth);
5679 if (maxTypeWidth > 0)
5683 ps.scopedBox(PP::bbox2, [&]() {
5684 for (
size_t portIdx = 0, e = portInfo.size(); portIdx != e;) {
5685 auto lastPort = e - 1;
5688 auto portType = portInfo.at(portIdx).type;
5692 bool isZeroWidth = false;
5694 isZeroWidth = isZeroBitType(portType);
5697 ps << (isZeroWidth ?
"// " :
" ");
5701 auto thisPortDirection = portInfo.at(portIdx).dir;
5702 switch (thisPortDirection) {
5707 ps << (hasOutputs ?
"input " :
"input ");
5710 ps << (hasOutputs ?
"inout " :
"inout ");
5713 bool emitWireInPorts = state.options.emitWireInPorts;
5714 if (emitWireInPorts)
5718 if (!portTypeStrings[portIdx].
empty())
5719 ps << portTypeStrings[portIdx];
5720 if (portTypeStrings[portIdx].
size() < maxTypeWidth)
5721 ps.nbsp(maxTypeWidth - portTypeStrings[portIdx].size());
5723 size_t startOfNamePos =
5724 (hasOutputs ? 7 : 6) + (emitWireInPorts ? 5 : 0) + maxTypeWidth;
5730 ps.invokeWithStringOS(
5731 [&](
auto &os) { printUnpackedTypePostfix(portType, os); });
5734 auto innerSym = portInfo.at(portIdx).sym;
5735 if (state.options.printDebugInfo && innerSym && !innerSym.empty()) {
5737 ps.invokeWithStringOS([&](
auto &os) { os << innerSym; });
5742 if (portIdx != lastNonZeroPort && portIdx != lastPort)
5746 if (
auto loc = portInfo.at(portIdx).loc)
5747 emitLocationInfo(loc);
5757 if (!state.options.disallowPortDeclSharing) {
5758 while (portIdx != e && portInfo.at(portIdx).dir == thisPortDirection &&
5761 auto port = portInfo.at(portIdx);
5765 bool isZeroWidth =
false;
5770 ps << (isZeroWidth ?
"// " :
" ");
5773 ps.nbsp(startOfNamePos);
5780 ps.invokeWithStringOS(
5781 [&](
auto &os) { printUnpackedTypePostfix(port.type, os); });
5784 if (state.options.printDebugInfo && port.sym && !port.sym.empty())
5785 ps <<
" /* inner_sym: "
5786 <<
PPExtString(port.sym.getSymName().getValue()) <<
" */";
5789 if (portIdx != lastNonZeroPort && portIdx != lastPort)
5793 if (
auto loc = port.loc)
5794 emitLocationInfo(loc);
5805 if (!portInfo.size()) {
5807 SmallPtrSet<Operation *, 8> moduleOpSet;
5808 moduleOpSet.insert(module);
5809 emitLocationInfoAndNewLine(moduleOpSet);
5812 ps <<
");" << PP::newline;
5813 setPendingNewline();
5817 void ModuleEmitter::emitHWModule(HWModuleOp module) {
5818 currentModuleOp = module;
5820 emitComment(module.getCommentAttr());
5821 emitSVAttributes(module);
5823 ps.addCallback({module,
true});
5827 emitParameters(module, module.getParameters());
5829 emitPortList(module, module.getPortList());
5831 assert(state.pendingNewline);
5834 StmtEmitter(*
this, state.options).emitStatementBlock(*module.getBodyBlock());
5837 ps.addCallback({module,
false});
5839 setPendingNewline();
5841 currentModuleOp =
nullptr;
5844 void ModuleEmitter::emitHWTestModule(HWTestModuleOp module) {
5845 currentModuleOp = module;
5847 emitComment(module.getCommentAttr());
5848 emitSVAttributes(module);
5853 emitParameters(module, module.getParameters());
5855 emitPortList(module, module.getPortList());
5857 assert(state.pendingNewline);
5860 StmtEmitter(*
this, state.options).emitStatementBlock(*module.getBodyBlock());
5862 ps <<
"endmodule" << PP::newline;
5863 setPendingNewline();
5865 currentModuleOp =
nullptr;
5876 void SharedEmitterState::gatherFiles(
bool separateModules) {
5883 auto collectInstanceSymbolsAndBinds = [&](Operation *moduleOp) {
5884 moduleOp->walk([&](Operation *op) {
5886 if (
auto name = op->getAttrOfType<InnerSymAttr>(
5889 SymbolTable::getSymbolAttrName()),
5890 name.getSymName(), op);
5891 if (isa<BindOp>(op))
5896 auto collectPorts = [&](
auto moduleOp) {
5897 auto portInfo = moduleOp.getPortList();
5898 for (
auto [i, p] : llvm::enumerate(portInfo)) {
5899 if (!p.attrs || p.attrs.empty())
5901 for (NamedAttribute portAttr : p.attrs) {
5902 if (
auto sym = portAttr.getValue().dyn_cast<InnerSymAttr>()) {
5910 SmallString<32> outputPath;
5911 for (
auto &op : *
designOp.getBody()) {
5914 bool hasFileName =
false;
5915 bool emitReplicatedOps =
true;
5916 bool addToFilelist =
true;
5922 auto attr = op.getAttrOfType<hw::OutputFileAttr>(
"output_file");
5924 LLVM_DEBUG(
llvm::dbgs() <<
"Found output_file attribute " << attr
5925 <<
" on " << op <<
"\n";);
5926 if (!attr.isDirectory())
5929 emitReplicatedOps = attr.getIncludeReplicatedOps().getValue();
5930 addToFilelist = !attr.getExcludeFromFilelist().getValue();
5934 SmallVector<StringAttr> opFileList;
5935 if (
auto fl = op.getAttrOfType<hw::FileListAttr>(
"output_filelist"))
5936 opFileList.push_back(fl.getFilename());
5937 if (
auto fla = op.getAttrOfType<ArrayAttr>(
"output_filelist"))
5939 opFileList.push_back(fl.cast<hw::FileListAttr>().getFilename());
5941 auto separateFile = [&](Operation *op, Twine defaultFileName =
"") {
5946 if (!defaultFileName.isTriviallyEmpty()) {
5949 op->emitError(
"file name unspecified");
5956 auto &file =
files[destFile];
5957 file.ops.push_back(info);
5958 file.emitReplicatedOps = emitReplicatedOps;
5959 file.addToFilelist = addToFilelist;
5960 file.isVerilog = outputPath.endswith(
".sv");
5961 for (
auto fl : opFileList)
5962 fileLists[fl.getValue()].push_back(destFile);
5967 TypeSwitch<Operation *>(&op)
5968 .Case<HWModuleOp>([&](
auto mod) {
5972 collectInstanceSymbolsAndBinds(mod);
5975 if (attr || separateModules)
5980 .Case<HWTestModuleOp>([&](
auto mod) {
5984 collectInstanceSymbolsAndBinds(mod);
5987 if (attr || separateModules)
5992 .Case<InterfaceOp>([&](InterfaceOp intf) {
5997 for (
auto &op : *intf.getBodyBlock())
5998 if (
auto symOp = dyn_cast<mlir::SymbolOpInterface>(op))
5999 if (
auto name = symOp.getNameAttr())
6003 if (attr || separateModules)
6004 separateFile(intf, intf.getSymName() +
".sv");
6008 .Case<HWModuleExternOp>([&](HWModuleExternOp op) {
6012 if (separateModules)
6013 separateFile(op,
"extern_modules.sv");
6017 .Case<VerbatimOp, IfDefOp, MacroDefOp>([&](Operation *op) {
6023 separateFile(op,
"");
6025 .Case<HWGeneratorSchemaOp>([&](HWGeneratorSchemaOp schemaOp) {
6028 .Case<HierPathOp>([&](HierPathOp hierPathOp) {
6031 .Case<TypeScopeOp>([&](TypeScopeOp op) {
6037 separateFile(op,
"");
6039 .Case<BindOp, BindInterfaceOp>([&](
auto op) {
6041 separateFile(op,
"bindfile.sv");
6046 .Case<MacroDeclOp>([&](
auto op) {
6049 .Case<om::ClassLike>([&](
auto op) {
6052 .Case<om::ConstantOp>([&](
auto op) {
6055 .Default([&](
auto *) {
6056 op.emitError(
"unknown operation (SharedEmitterState::gatherFiles)");
6076 size_t lastReplicatedOp = 0;
6078 bool emitHeaderInclude =
6081 if (emitHeaderInclude)
6084 size_t numReplicatedOps =
6087 thingsToEmit.reserve(thingsToEmit.size() + numReplicatedOps +
6092 for (
const auto &opInfo : file.
ops) {
6095 for (; lastReplicatedOp < std::min(opInfo.position, numReplicatedOps);
6100 thingsToEmit.emplace_back(opInfo.op);
6105 for (; lastReplicatedOp < numReplicatedOps; lastReplicatedOp++)
6110 TypeSwitch<Operation *>(op)
6111 .Case<HWModuleOp>([&](
auto op) { ModuleEmitter(state).emitHWModule(op); })
6112 .Case<HWTestModuleOp>(
6113 [&](
auto op) { ModuleEmitter(state).emitHWTestModule(op); })
6114 .Case<HWModuleExternOp>(
6115 [&](
auto op) { ModuleEmitter(state).emitHWExternModule(op); })
6116 .Case<HWModuleGeneratedOp>(
6117 [&](
auto op) { ModuleEmitter(state).emitHWGeneratedModule(op); })
6118 .Case<HWGeneratorSchemaOp>([&](
auto op) { })
6119 .Case<BindOp>([&](
auto op) { ModuleEmitter(state).emitBind(op); })
6120 .Case<BindInterfaceOp>(
6121 [&](
auto op) { ModuleEmitter(state).emitBindInterface(op); })
6122 .Case<InterfaceOp, VerbatimOp, IfDefOp>(
6123 [&](
auto op) { ModuleEmitter(state).emitStatement(op); })
6124 .Case<TypeScopeOp>([&](
auto typedecls) {
6125 ModuleEmitter(state).emitStatement(typedecls);
6128 [&](
auto op) { ModuleEmitter(state).emitStatement(op); })
6129 .Default([&](
auto *op) {
6130 state.encounteredError =
true;
6131 op->emitError(
"unknown operation (ExportVerilog::emitOperation)");
6138 llvm::formatted_raw_ostream &os,
6139 StringAttr fileName,
bool parallelize) {
6140 MLIRContext *context =
designOp->getContext();
6144 parallelize &= context->isMultithreadingEnabled();
6154 size_t lineOffset = 0;
6155 for (
auto &entry : thingsToEmit) {
6156 entry.verilogLocs.setStream(os);
6157 if (
auto *op = entry.getOperation()) {
6162 state.addVerilogLocToOps(lineOffset, fileName);
6164 os << entry.getStringData();
6168 if (state.encounteredError)
6186 SmallString<256> buffer;
6187 llvm::raw_svector_ostream tmpStream(buffer);
6188 llvm::formatted_raw_ostream rs(tmpStream);
6199 for (
auto &entry : thingsToEmit) {
6202 auto *op = entry.getOperation();
6204 auto lineOffset = os.getLine() + 1;
6205 os << entry.getStringData();
6209 entry.verilogLocs.updateIRWithLoc(lineOffset, fileName, context);
6212 entry.verilogLocs.setStream(os);
6218 state.addVerilogLocToOps(0, fileName);
6234 module.emitWarning()
6235 <<
"`emitReplicatedOpsToHeader` option is enabled but an header is "
6236 "created only at SplitExportVerilog";
6245 for (
const auto &it : emitter.
files) {
6246 list.emplace_back(
"\n// ----- 8< ----- FILE \"" + it.first.str() +
6247 "\" ----- 8< -----\n\n");
6253 std::string contents(
"\n// ----- 8< ----- FILE \"" + it.first().str() +
6254 "\" ----- 8< -----\n\n");
6255 for (
auto &name : it.second)
6256 contents += name.str() +
"\n";
6257 list.emplace_back(contents);
6260 llvm::formatted_raw_ostream rs(os);
6271 SmallVector<HWModuleOp> modulesToPrepare;
6272 module.walk([&](HWModuleOp op) { modulesToPrepare.push_back(op); });
6273 if (failed(failableParallelForEach(
6274 module->getContext(), modulesToPrepare,
6275 [&](
auto op) { return prepareHWModule(op, options); })))
6282 struct ExportVerilogPass :
public ExportVerilogBase<ExportVerilogPass> {
6283 ExportVerilogPass(raw_ostream &os) : os(os) {}
6284 void runOnOperation()
override {
6286 mlir::OpPassManager preparePM(
"builtin.module");
6288 auto &modulePM = preparePM.nest<hw::HWModuleOp>();
6290 if (failed(runPipeline(preparePM, getOperation())))
6291 return signalPassFailure();
6294 return signalPassFailure();
6302 std::unique_ptr<mlir::Pass>
6304 return std::make_unique<ExportVerilogPass>(os);
6315 static std::unique_ptr<llvm::ToolOutputFile>
6319 SmallString<128> outputFilename(dirname);
6321 auto outputDir = llvm::sys::path::parent_path(outputFilename);
6324 std::error_code error = llvm::sys::fs::create_directories(outputDir);
6326 emitter.
designOp.emitError(
"cannot create output directory \"")
6327 << outputDir <<
"\": " << error.message();
6333 std::string errorMessage;
6334 auto output = mlir::openOutputFile(outputFilename, &errorMessage);
6336 emitter.
designOp.emitError(errorMessage);
6353 llvm::formatted_raw_ostream rs(output->os());
6365 StringRef dirname) {
6376 bool insertSuccess =
6384 if (!insertSuccess) {
6385 module.emitError() <<
"tried to emit a heder to " <<
circtHeader
6386 <<
", but the file is used as an output too.";
6392 parallelForEach(module->getContext(), emitter.
files.begin(),
6393 emitter.
files.end(), [&](
auto &it) {
6394 createSplitOutputFile(it.first, it.second, dirname,
6399 SmallString<128> filelistPath(dirname);
6402 std::string errorMessage;
6403 auto output = mlir::openOutputFile(filelistPath, &errorMessage);
6405 module->emitError(errorMessage);
6409 for (
const auto &it : emitter.
files) {
6410 if (it.second.addToFilelist)
6411 output->os() << it.first.str() <<
"\n";
6420 for (
auto &name : it.second)
6421 output->os() << name.str() <<
"\n";
6430 SmallVector<HWModuleOp> modulesToPrepare;
6431 module.walk([&](HWModuleOp op) { modulesToPrepare.push_back(op); });
6432 if (failed(failableParallelForEach(
6433 module->getContext(), modulesToPrepare,
6434 [&](
auto op) { return prepareHWModule(op, options); })))
6442 struct ExportSplitVerilogPass
6443 :
public ExportSplitVerilogBase<ExportSplitVerilogPass> {
6444 ExportSplitVerilogPass(StringRef directory) {
6445 directoryName = directory.str();
6447 void runOnOperation()
override {
6449 mlir::OpPassManager preparePM(
"builtin.module");
6450 auto &modulePM = preparePM.nest<hw::HWModuleOp>();
6452 if (failed(runPipeline(preparePM, getOperation())))
6453 return signalPassFailure();
6456 return signalPassFailure();
6461 std::unique_ptr<mlir::Pass>
6463 return std::make_unique<ExportSplitVerilogPass>(directory);
assert(baseType &&"element must be base type")
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
static LogicalResult isCombinational(Value value, GroupInterface group)
Verifies the defining operation of a value is combinational.
static bool hasSVAttributes(Operation *op)
static StringRef getVerilogDeclWord(Operation *op, const LoweringOptions &options)
Return the word (e.g. "reg") in Verilog to declare the specified thing.
static void emitOperation(VerilogEmitterState &state, Operation *op)
static LogicalResult exportVerilogImpl(ModuleOp module, llvm::raw_ostream &os)
static int compareLocs(Location lhs, Location rhs)
static bool isDuplicatableExpression(Operation *op)
static TypedAttr getInt32Attr(MLIRContext *ctx, uint32_t value)
StringRef getVerilogValueName(Value val)
Retrieve value's verilog name from IR.
static void sortLocationVector(TVector &vec)
static bool hasStructType(Type type)
Return true if type has a struct type as a subtype.
static StringRef getPortVerilogName(Operation *module, PortInfo port)
static std::unique_ptr< llvm::ToolOutputFile > createOutputFile(StringRef fileName, StringRef dirname, SharedEmitterState &emitter)
FailureOr< int > dispatchCompareLocations(Location lhs, Location rhs)
static bool isOkToBitSelectFrom(Value v)
Most expressions are invalid to bit-select from in Verilog, but some things are ok.
static LogicalResult exportSplitVerilogImpl(ModuleOp module, StringRef dirname)
static int compareLocsImpl(mlir::NameLoc lhs, mlir::NameLoc rhs)
static bool printPackedTypeImpl(Type type, raw_ostream &os, Location loc, SmallVectorImpl< Attribute > &dims, bool implicitIntType, bool singleBitDefaultType, ModuleEmitter &emitter, Type optionalAliasType={})
Output the basic type that consists of packed and primitive types.
static void emitZeroWidthIndexingValue(PPS &os)
Emits a known-safe token that is legal when indexing into singleton arrays.
static bool checkDominanceOfUsers(Operation *op1, Operation *op2)
Return true if op1 dominates users of op2.
static void emitDims(ArrayRef< Attribute > dims, raw_ostream &os, Location loc, ModuleEmitter &emitter)
Emit a list of dimensions.
static bool isExpressionEmittedInlineIntoProceduralDeclaration(Operation *op, StmtEmitter &stmtEmitter)
Given an operation corresponding to a VerilogExpression, determine whether it is safe to emit inline ...
static void collectAndUniqueLocations(Location loc, SmallPtrSetImpl< Attribute > &locationSet)
Pull apart any fused locations into the location set, such that they are uniqued.
static Value isZeroExtension(Value value)
If the specified extension is a zero extended version of another value, return the shorter value,...
static void createSplitOutputFile(StringAttr fileName, FileInfo &file, StringRef dirname, SharedEmitterState &emitter)
static void getTypeDims(SmallVectorImpl< Attribute > &dims, Type type, Location loc)
Push this type's dimension into a vector.
static TypedAttr getIntAttr(MLIRContext *ctx, Type t, const APInt &value)
static BlockStatementCount countStatements(Block &block)
Compute how many statements are within this block, for begin/end markers.
static bool haveMatchingDims(Type a, Type b, Location loc)
True iff 'a' and 'b' have the same wire dims.
static Type stripUnpackedTypes(Type type)
Given a set of known nested types (those supported by this pass), strip off leading unpacked types.
static bool isExpressionUnableToInline(Operation *op, const LoweringOptions &options)
Return true if we are unable to ever inline the specified operation.
static AssignTy getSingleAssignAndCheckUsers(Operation *op)
static void emitSVAttributesImpl(PPS &ps, ArrayAttr attrs, bool mayBreak)
Emit SystemVerilog attributes.
static bool isDuplicatableNullaryExpression(Operation *op)
Return true for nullary operations that are better emitted multiple times as inline expression (when ...
static IfOp findNestedElseIf(Block *elseBlock)
Find a nested IfOp in an else block that can be printed as else if instead of nesting it into a new b...
StringRef circtHeaderInclude
static ValueRange getNonOverlappingConcatSubrange(Value value)
For a value concat(..., delay(const(true), 1, 0)), return ....
static void printParamValue(OpAsmPrinter &p, Operation *, Attribute value, Type resultType)
static InstancePath empty
llvm::SmallVector< StringAttr > inputs
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static int64_t size(hw::ArrayType mType, capnp::schema::Field::Reader cField)
Returns the expected size of an array (capnp list) in 64-bit words.
LocationEmitter(LoweringOptions::LocationInfoStyle style, Location loc)
void emitLocationSetInfo(llvm::raw_string_ostream &os, LoweringOptions::LocationInfoStyle style, const SmallPtrSetImpl< Attribute > &locationSet)
LocationEmitter(LoweringOptions::LocationInfoStyle style, const SmallPtrSetImpl< Operation * > &ops)
Track the output verilog line,column number information for every op.
void setStream(llvm::formatted_raw_ostream &f)
Set the output stream.
void updateIRWithLoc(unsigned lineOffset, StringAttr fileName, MLIRContext *context)
Called after the verilog has been exported and the corresponding locations are recorded in the map.
This class wraps an operation or a fixed string that should be emitted.
Operation * getOperation() const
If the value is an Operation*, return it. Otherwise return null.
OpLocMap verilogLocs
Verilog output location information for entry.
void setString(StringRef value)
This method transforms the entry from an operation to a string value.
void freeze()
Mark the cache as frozen, which allows it to be shared across threads.
void addDefinition(mlir::StringAttr modSymbol, mlir::StringAttr name, mlir::Operation *op, size_t port=~0ULL)
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
Note: Callable class must implement a callable with signature: void (Data)
Wrap the TokenStream with a helper for CallbackTokens, to record the print events on the stream.
bool isExpressionEmittedInline(Operation *op, const LoweringOptions &options)
Return true if this expression should be emitted inline into any statement that uses it.
bool isVerilogExpression(Operation *op)
This predicate returns true if the specified operation is considered a potentially inlinable Verilog ...
GlobalNameTable legalizeGlobalNames(ModuleOp topLevel, const LoweringOptions &options)
Rewrite module names and interfaces to not conflict with each other or with Verilog keywords.
StringAttr inferStructuralNameForTemporary(Value expr)
Given an expression that is spilled into a temporary wire, try to synthesize a better name than "_T_4...
static bool isConstantExpression(Operation *op)
Return whether an operation is a constant.
bool isZeroBitType(Type type)
Return true if this is a zero bit type, e.g.
StringRef getSymOpName(Operation *symOp)
Return the verilog name of the operations that can define a symbol.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
StringRef getVerilogModuleName(Operation *module)
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.