10#include "slang/ast/Compilation.h"
11#include "slang/ast/symbols/ClassSymbols.h"
12#include "llvm/ADT/ScopeExit.h"
15using namespace ImportVerilog;
22 SmallString<64> &prefix) {
23 if (symbol.kind != slang::ast::SymbolKind::Package)
26 if (!symbol.name.empty()) {
27 prefix += symbol.name;
44 BaseVisitor(
Context &context, Location loc)
45 : context(context), loc(loc), builder(context.builder) {}
48 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
54 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
59 LogicalResult visit(
const slang::ast::ClassType &classdecl) {
69 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
74 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
75 LogicalResult visit(
const slang::ast::ForwardingTypedefSymbol &) {
80 LogicalResult visit(
const slang::ast::ExplicitImportSymbol &) {
83 LogicalResult visit(
const slang::ast::WildcardImportSymbol &) {
88 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
93 LogicalResult visit(
const slang::ast::ElabSystemTaskSymbol &) {
98 LogicalResult visit(
const slang::ast::ParameterSymbol ¶m) {
99 visitParameter(param);
103 LogicalResult visit(
const slang::ast::SpecparamSymbol ¶m) {
104 visitParameter(param);
108 template <
class Node>
109 void visitParameter(
const Node ¶m) {
119 if (builder.getInsertionBlock()->getParentOp() == context.
intoModuleOp) {
126 SmallString<64> paramName;
128 paramName += param.name;
130 debug::VariableOp::create(builder, loc, builder.getStringAttr(paramName),
141struct RootVisitor :
public BaseVisitor {
142 using BaseVisitor::BaseVisitor;
143 using BaseVisitor::visit;
146 LogicalResult visit(
const slang::ast::PackageSymbol &package) {
147 return context.convertPackage(package);
151 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
152 if (!
context.declareFunction(subroutine))
158 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
159 return context.convertGlobalVariable(var);
163 template <
typename T>
164 LogicalResult visit(T &&node) {
165 mlir::emitError(loc,
"unsupported construct: ")
166 << slang::ast::toString(node.kind);
177struct PackageVisitor :
public BaseVisitor {
178 using BaseVisitor::BaseVisitor;
179 using BaseVisitor::visit;
182 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
183 if (!
context.declareFunction(subroutine))
189 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
190 return context.convertGlobalVariable(var);
194 template <
typename T>
195 LogicalResult visit(T &&node) {
196 mlir::emitError(loc,
"unsupported package member: ")
197 << slang::ast::toString(node.kind);
207static moore::ProcedureKind
210 case slang::ast::ProceduralBlockKind::Always:
211 return moore::ProcedureKind::Always;
212 case slang::ast::ProceduralBlockKind::AlwaysComb:
213 return moore::ProcedureKind::AlwaysComb;
214 case slang::ast::ProceduralBlockKind::AlwaysLatch:
215 return moore::ProcedureKind::AlwaysLatch;
216 case slang::ast::ProceduralBlockKind::AlwaysFF:
217 return moore::ProcedureKind::AlwaysFF;
218 case slang::ast::ProceduralBlockKind::Initial:
219 return moore::ProcedureKind::Initial;
220 case slang::ast::ProceduralBlockKind::Final:
221 return moore::ProcedureKind::Final;
223 llvm_unreachable(
"all procedure kinds handled");
228 case slang::ast::NetType::Supply0:
229 return moore::NetKind::Supply0;
230 case slang::ast::NetType::Supply1:
231 return moore::NetKind::Supply1;
232 case slang::ast::NetType::Tri:
233 return moore::NetKind::Tri;
234 case slang::ast::NetType::TriAnd:
235 return moore::NetKind::TriAnd;
236 case slang::ast::NetType::TriOr:
237 return moore::NetKind::TriOr;
238 case slang::ast::NetType::TriReg:
239 return moore::NetKind::TriReg;
240 case slang::ast::NetType::Tri0:
241 return moore::NetKind::Tri0;
242 case slang::ast::NetType::Tri1:
243 return moore::NetKind::Tri1;
244 case slang::ast::NetType::UWire:
245 return moore::NetKind::UWire;
246 case slang::ast::NetType::Wire:
247 return moore::NetKind::Wire;
248 case slang::ast::NetType::WAnd:
249 return moore::NetKind::WAnd;
250 case slang::ast::NetType::WOr:
251 return moore::NetKind::WOr;
252 case slang::ast::NetType::Interconnect:
253 return moore::NetKind::Interconnect;
254 case slang::ast::NetType::UserDefined:
255 return moore::NetKind::UserDefined;
256 case slang::ast::NetType::Unknown:
257 return moore::NetKind::Unknown;
259 llvm_unreachable(
"all net kinds handled");
263struct ModuleVisitor :
public BaseVisitor {
264 using BaseVisitor::visit;
268 StringRef blockNamePrefix;
270 ModuleVisitor(
Context &
context, Location loc, StringRef blockNamePrefix =
"")
271 : BaseVisitor(
context, loc), blockNamePrefix(blockNamePrefix) {}
274 LogicalResult visit(
const slang::ast::PortSymbol &) {
return success(); }
275 LogicalResult visit(
const slang::ast::MultiPortSymbol &) {
return success(); }
276 LogicalResult visit(
const slang::ast::InterfacePortSymbol &) {
281 LogicalResult visit(
const slang::ast::GenvarSymbol &genvarNode) {
286 LogicalResult visit(
const slang::ast::DefParamSymbol &) {
return success(); }
290 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
298 expandInterfaceInstance(
const slang::ast::InstanceSymbol &instNode) {
299 auto prefix = (Twine(blockNamePrefix) + instNode.name +
"_").str();
300 auto lowering = std::make_unique<InterfaceLowering>();
301 Context::ValueSymbolScope scope(
context.valueSymbols);
303 auto recordMember = [&](
const slang::ast::Symbol &sym,
304 Value value) ->
void {
305 lowering->expandedMembers[&sym] = value;
306 auto nameAttr = builder.getStringAttr(sym.name);
307 lowering->expandedMembersByName[nameAttr] = value;
308 if (
auto *valueSym = sym.as_if<slang::ast::ValueSymbol>())
309 context.valueSymbols.insert(valueSym, value);
312 for (
const auto &member : instNode.body.members()) {
314 if (
const auto *nestedInst = member.as_if<slang::ast::InstanceSymbol>()) {
315 if (nestedInst->body.getDefinition().definitionKind ==
316 slang::ast::DefinitionKind::Interface)
317 return mlir::emitError(loc)
318 <<
"nested interface instances are not supported: `"
319 << nestedInst->name <<
"` inside `" << instNode.name <<
"`";
322 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
323 auto loweredType =
context.convertType(*var->getDeclaredType());
326 auto varOp = moore::VariableOp::create(
328 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
329 builder.getStringAttr(Twine(prefix) + StringRef(var->name)),
331 recordMember(*var, varOp);
335 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
336 auto loweredType =
context.convertType(*net->getDeclaredType());
340 if (netKind == moore::NetKind::Interconnect ||
341 netKind == moore::NetKind::UserDefined ||
342 netKind == moore::NetKind::Unknown)
343 return mlir::emitError(loc,
"unsupported net kind `")
344 << net->netType.name <<
"`";
345 auto netOp = moore::NetOp::create(
347 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
348 builder.getStringAttr(Twine(prefix) + StringRef(net->name)),
350 recordMember(*net, netOp);
359 for (
const auto *con : instNode.getPortConnections()) {
360 const auto *expr = con->getExpression();
361 const auto *port = con->port.as_if<slang::ast::PortSymbol>();
369 Value lvalue =
context.convertLvalueExpression(*expr);
373 recordMember(*port, lvalue);
374 if (port->internalSymbol) {
375 recordMember(*port->internalSymbol, lvalue);
381 for (
const auto &member : instNode.body.members()) {
382 switch (member.kind) {
383 case slang::ast::SymbolKind::ContinuousAssign:
384 case slang::ast::SymbolKind::ProceduralBlock:
385 case slang::ast::SymbolKind::StatementBlock:
390 auto memberLoc =
context.convertLocation(member.location);
391 if (failed(member.visit(ModuleVisitor(
context, memberLoc, prefix))))
393 if (failed(
context.flushPendingMonitors()))
397 context.interfaceInstanceStorage.push_back(std::move(lowering));
398 context.interfaceInstances.insert(
399 &instNode,
context.interfaceInstanceStorage.back().get());
404 LogicalResult visit(
const slang::ast::InstanceSymbol &instNode) {
405 using slang::ast::ArgumentDirection;
406 using slang::ast::AssignmentExpression;
407 using slang::ast::MultiPortSymbol;
408 using slang::ast::PortSymbol;
418 auto defKind = body->getDefinition().definitionKind;
419 if (defKind == slang::ast::DefinitionKind::Interface)
420 return expandInterfaceInstance(instNode);
422 auto *moduleLowering =
context.convertModuleHeader(body);
425 auto module = moduleLowering->op;
426 auto moduleType =
module.getModuleType();
429 SymbolTable::setSymbolVisibility(module, SymbolTable::Visibility::Private);
436 portValues.reserve(moduleType.getNumPorts());
440 const slang::ast::InstanceSymbol *>
443 for (
const auto *con : instNode.getPortConnections()) {
444 const auto *expr = con->getExpression();
449 auto *port = con->port.as_if<PortSymbol>();
450 if (
auto *existingPort =
451 moduleLowering->portsBySyntaxNode.lookup(port->getSyntax()))
454 switch (port->direction) {
455 case ArgumentDirection::In: {
456 auto refType = moore::RefType::get(
457 cast<moore::UnpackedType>(
context.convertType(port->getType())));
459 if (
const auto *net =
460 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
461 auto netOp = moore::NetOp::create(
462 builder, loc, refType,
463 StringAttr::get(builder.getContext(), net->name),
465 auto readOp = moore::ReadOp::create(builder, loc, netOp);
466 portValues.insert({port, readOp});
467 }
else if (
const auto *var =
469 ->as_if<slang::ast::VariableSymbol>()) {
470 auto varOp = moore::VariableOp::create(
471 builder, loc, refType,
472 StringAttr::get(builder.getContext(), var->name),
nullptr);
473 auto readOp = moore::ReadOp::create(builder, loc, varOp);
474 portValues.insert({port, readOp});
476 return mlir::emitError(loc)
477 <<
"unsupported internal symbol for unconnected port `"
478 << port->name <<
"`";
485 case ArgumentDirection::Out:
488 case ArgumentDirection::InOut:
489 case ArgumentDirection::Ref: {
490 auto refType = moore::RefType::get(
491 cast<moore::UnpackedType>(
context.convertType(port->getType())));
493 if (
const auto *net =
494 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
495 auto netOp = moore::NetOp::create(
496 builder, loc, refType,
497 StringAttr::get(builder.getContext(), net->name),
499 portValues.insert({port, netOp});
500 }
else if (
const auto *var =
502 ->as_if<slang::ast::VariableSymbol>()) {
503 auto varOp = moore::VariableOp::create(
504 builder, loc, refType,
505 StringAttr::get(builder.getContext(), var->name),
nullptr);
506 portValues.insert({port, varOp});
508 return mlir::emitError(loc)
509 <<
"unsupported internal symbol for unconnected port `"
510 << port->name <<
"`";
519 if (
const auto *assign = expr->as_if<AssignmentExpression>())
520 expr = &assign->left();
525 if (
auto *port = con->port.as_if<PortSymbol>()) {
527 auto value = (port->direction == ArgumentDirection::In)
528 ?
context.convertRvalueExpression(*expr)
529 :
context.convertLvalueExpression(*expr);
532 if (
auto *existingPort =
533 moduleLowering->portsBySyntaxNode.lookup(con->port.getSyntax()))
535 portValues.insert({port, value});
542 if (
const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
544 auto value =
context.convertLvalueExpression(*expr);
548 for (
const auto *port :
llvm::reverse(multiPort->ports)) {
549 if (
auto *existingPort = moduleLowering->portsBySyntaxNode.lookup(
550 con->port.getSyntax()))
552 unsigned width = port->getType().getBitWidth();
553 auto sliceType =
context.convertType(port->getType());
556 Value slice = moore::ExtractRefOp::create(
558 moore::RefType::get(cast<moore::UnpackedType>(sliceType)), value,
561 if (port->direction == ArgumentDirection::In)
562 slice = moore::ReadOp::create(builder, loc, slice);
563 portValues.insert({port, slice});
571 if (
const auto *ifacePort =
572 con->port.as_if<slang::ast::InterfacePortSymbol>()) {
573 auto ifaceConn = con->getIfaceConn();
574 const auto *connInst =
575 ifaceConn.first->as_if<slang::ast::InstanceSymbol>();
577 ifaceConnMap[ifacePort] = connInst;
581 mlir::emitError(loc) <<
"unsupported instance port `" << con->port.name
582 <<
"` (" << slang::ast::toString(con->port.kind)
588 SmallVector<Value> inputValues;
589 SmallVector<Value> outputValues;
590 inputValues.reserve(moduleType.getNumInputs());
591 outputValues.reserve(moduleType.getNumOutputs());
593 for (
auto &port : moduleLowering->ports) {
594 auto value = portValues.lookup(&port.ast);
595 if (port.ast.direction == ArgumentDirection::Out)
596 outputValues.push_back(value);
598 inputValues.push_back(value);
604 for (
auto &fp : moduleLowering->ifacePorts) {
605 if (!fp.bodySym || !fp.origin)
608 auto it = ifaceConnMap.find(fp.origin);
609 if (it == ifaceConnMap.end()) {
611 <<
"no interface connection for port `" << fp.name <<
"`";
614 const auto *connInst = it->second;
616 auto *ifaceLowering =
context.interfaceInstances.lookup(connInst);
617 if (!ifaceLowering) {
619 <<
"interface instance `" << connInst->name <<
"` was not expanded";
623 auto valIt = ifaceLowering->expandedMembers.find(fp.bodySym);
624 if (valIt == ifaceLowering->expandedMembers.end()) {
626 <<
"unresolved interface port signal `" << fp.name <<
"`";
629 Value val = valIt->second;
631 outputValues.push_back(val);
635 if (isa<moore::RefType>(val.getType()) && !isa<moore::RefType>(fp.type))
636 val = moore::ReadOp::create(builder, loc, val);
637 inputValues.push_back(val);
642 for (
auto [value, type] :
643 llvm::zip(inputValues, moduleType.getInputTypes())) {
645 value =
context.materializeConversion(type, value,
false, value.getLoc());
647 return mlir::emitError(loc) <<
"unsupported port";
654 for (
const auto &hierPath :
context.hierPaths[body]) {
655 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
657 context.valueSymbols.lookup(hierPath.valueSyms.front());
658 hierPath.hierName && hierPath.direction == ArgumentDirection::In)
659 inputValues.push_back(hierValue);
663 for (
auto value : inputValues)
665 return
mlir::emitError(loc) <<
"unsupported port";
668 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
669 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
670 auto inst = moore::InstanceOp::create(
671 builder, loc, moduleType.getOutputTypes(),
672 builder.getStringAttr(Twine(blockNamePrefix) + instNode.name),
673 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
674 inputNames, outputNames);
681 for (
const auto &hierPath :
context.hierPaths[body])
682 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out) {
683 auto result = inst->getResult(*hierPath.idx);
686 for (
auto *sym : hierPath.valueSyms)
687 context.valueSymbols.insert(sym, result);
688 context.hierValueSymbols[{&instNode, hierPath.hierName}] = result;
692 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
695 Value rvalue = output;
696 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
698 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
699 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
706 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
707 auto loweredType =
context.convertType(*varNode.getDeclaredType());
712 if (
const auto *init = varNode.getInitializer()) {
713 initial =
context.convertRvalueExpression(*init, loweredType);
718 auto varOp = moore::VariableOp::create(
720 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
721 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), initial);
722 context.valueSymbols.insert(&varNode, varOp);
723 const auto &canonTy = varNode.getType().getCanonicalType();
724 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
725 if (failed(
context.registerVirtualInterfaceMembers(varNode, *vi, loc)))
731 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
732 auto loweredType =
context.convertType(*netNode.getDeclaredType());
737 if (
const auto *init = netNode.getInitializer()) {
738 assignment =
context.convertRvalueExpression(*init, loweredType);
744 if (netkind == moore::NetKind::Interconnect ||
745 netkind == moore::NetKind::UserDefined ||
746 netkind == moore::NetKind::Unknown)
747 return mlir::emitError(loc,
"unsupported net kind `")
748 << netNode.netType.name <<
"`";
750 auto netOp = moore::NetOp::create(
752 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
753 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
755 context.valueSymbols.insert(&netNode, netOp);
760 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
762 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
763 auto lhs =
context.convertLvalueExpression(expr.left());
767 auto rhs =
context.convertRvalueExpression(
768 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
773 if (
auto *timingCtrl = assignNode.getDelay()) {
774 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
775 auto delay =
context.convertRvalueExpression(
776 ctrl->expr, moore::TimeType::get(builder.getContext()));
779 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
782 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
787 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
792 LogicalResult convertProcedure(moore::ProcedureKind kind,
793 const slang::ast::Statement &body) {
794 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
795 return context.convertStatement(body);
796 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
797 OpBuilder::InsertionGuard guard(builder);
798 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
799 Context::ValueSymbolScope scope(
context.valueSymbols);
800 Context::VirtualInterfaceMemberScope vifMemberScope(
802 if (failed(
context.convertStatement(body)))
804 if (builder.getBlock())
805 moore::ReturnOp::create(builder, loc);
809 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
812 if (
context.options.lowerAlwaysAtStarAsComb) {
813 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
814 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
816 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
817 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
825 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
827 if (genNode.isUninstantiated)
831 SmallString<64> prefix = blockNamePrefix;
832 if (!genNode.name.empty() ||
833 genNode.getParentScope()->asSymbol().kind !=
834 slang::ast::SymbolKind::GenerateBlockArray) {
835 prefix += genNode.getExternalName();
840 for (
auto &member : genNode.members())
841 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
847 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
850 SmallString<64> prefix = blockNamePrefix;
851 prefix += genArrNode.getExternalName();
853 auto prefixBaseLen = prefix.size();
856 for (
const auto *entry : genArrNode.entries) {
858 prefix.resize(prefixBaseLen);
859 if (entry->arrayIndex)
860 prefix += entry->arrayIndex->toString();
862 Twine(entry->constructIndex).toVector(prefix);
866 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
878 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
884 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
890 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
895 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
896 if (!
context.declareFunction(subroutine))
902 LogicalResult visit(
const slang::ast::PrimitiveInstanceSymbol &prim) {
903 return context.convertPrimitiveInstance(prim);
907 template <
typename T>
908 LogicalResult visit(T &&node) {
909 mlir::emitError(loc,
"unsupported module member: ")
910 << slang::ast::toString(node.kind);
922LogicalResult Context::convertCompilation() {
928 timeScale = root.getTimeScale().value_or(slang::TimeScale());
929 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
937 for (
auto *inst : root.topInstances)
947 for (
auto *unit : root.compilationUnits) {
948 for (
const auto &member : unit->members()) {
950 if (failed(member.visit(RootVisitor(*
this, loc))))
958 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
959 for (
auto *inst : root.topInstances) {
961 if (body->getDefinition().definitionKind !=
962 slang::ast::DefinitionKind::Interface)
969 auto *
module = moduleWorklist.front();
977 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
978 classMethodWorklist.reserve(
classes.size());
980 classMethodWorklist.push_back(kv.first);
982 for (
auto *inst : classMethodWorklist) {
1001 auto &block = varOp.getInitRegion().emplaceBlock();
1002 OpBuilder::InsertionGuard guard(
builder);
1003 builder.setInsertionPointToEnd(&block);
1008 moore::YieldOp::create(
builder, varOp.getLoc(), value);
1017 using slang::ast::ArgumentDirection;
1018 using slang::ast::MultiPortSymbol;
1019 using slang::ast::ParameterSymbol;
1020 using slang::ast::PortSymbol;
1021 using slang::ast::TypeParameterSymbol;
1026 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1027 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1034 slot = std::make_unique<ModuleLowering>();
1035 auto &lowering = *slot;
1038 OpBuilder::InsertionGuard g(
builder);
1043 auto kind =
module->getDefinition().definitionKind;
1044 if (kind != slang::ast::DefinitionKind::Module &&
1045 kind != slang::ast::DefinitionKind::Program) {
1046 mlir::emitError(loc) <<
"unsupported definition: "
1047 <<
module->getDefinition().getKindString();
1052 auto block = std::make_unique<Block>();
1053 SmallVector<hw::ModulePort> modulePorts;
1056 unsigned int outputIdx = 0, inputIdx = 0;
1057 for (
auto *symbol :
module->getPortList()) {
1058 auto handlePort = [&](const PortSymbol &port) {
1059 auto portLoc = convertLocation(port.location);
1063 auto portName =
builder.getStringAttr(port.name);
1065 if (port.direction == ArgumentDirection::Out) {
1071 if (port.direction != ArgumentDirection::In)
1072 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1074 arg = block->addArgument(type, portLoc);
1077 lowering.ports.push_back({port, portLoc, arg});
1084 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1087 auto [connSym, modportSym] = ifacePort.getConnection();
1088 const auto *ifaceInst =
1089 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1090 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1094 for (
const auto &member : modportSym->members()) {
1095 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1102 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1105 if (mpp->direction == ArgumentDirection::Out) {
1107 modulePorts.push_back({name, type, dir});
1111 if (mpp->direction != ArgumentDirection::In)
1112 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1113 modulePorts.push_back({name, type, dir});
1114 arg = block->addArgument(type, portLoc);
1117 lowering.ifacePorts.push_back({name, dir, type, portLoc, arg,
1118 &ifacePort, mpp->internalSymbol,
1124 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1126 mlir::emitError(portLoc)
1127 <<
"unsupported interface port connection for `" << ifacePort.name
1131 for (
const auto &member : instSym->body.members()) {
1132 const slang::ast::Type *slangType =
nullptr;
1133 const slang::ast::Symbol *bodySym =
nullptr;
1134 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1135 slangType = &var->getType();
1137 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1138 slangType = &net->getType();
1146 auto name = builder.getStringAttr(Twine(portPrefix) +
1147 StringRef(bodySym->name));
1148 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1150 auto arg = block->addArgument(refType, portLoc);
1153 portLoc, arg, &ifacePort, bodySym,
1160 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1161 if (failed(handlePort(*port)))
1163 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1164 for (
auto *port : multiPort->ports)
1165 if (failed(handlePort(*port)))
1167 }
else if (
const auto *ifacePort =
1168 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1169 if (failed(handleIfacePort(*ifacePort)))
1173 <<
"unsupported module port `" << symbol->name <<
"` ("
1174 << slang::ast::toString(symbol->kind) <<
")";
1180 for (
auto &hierPath : hierPaths[module]) {
1181 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1182 auto hierType =
convertType(hierPath.valueSyms.front()->getType());
1186 if (
auto hierName = hierPath.hierName) {
1188 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1189 if (hierPath.direction == ArgumentDirection::Out) {
1190 hierPath.idx = outputIdx++;
1193 hierPath.idx = inputIdx++;
1196 block->addArgument(hierType, hierLoc);
1200 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1205 auto it = orderedRootOps.upper_bound(key);
1206 if (it == orderedRootOps.end())
1207 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1209 builder.setInsertionPoint(it->second);
1213 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1214 orderedRootOps.insert(it, {key, moduleOp});
1215 moduleOp.getBodyRegion().push_back(block.release());
1216 lowering.op = moduleOp;
1220 symbolTable.insert(moduleOp);
1223 moduleWorklist.push(module);
1226 for (
const auto &port : lowering.ports)
1227 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1234 auto &lowering = *
modules[module];
1235 OpBuilder::InsertionGuard g(
builder);
1236 builder.setInsertionPointToEnd(lowering.op.getBody());
1245 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1246 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1251 for (
auto &hierPath :
hierPaths[module])
1252 if (hierPath.direction == slang::ast::ArgumentDirection::In &&
1254 auto arg = lowering.op.getBody()->getArgument(*hierPath.idx);
1255 for (
auto *sym : hierPath.valueSyms)
1263 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1266 auto getIfacePortLowering =
1272 if (
auto it = ifacePortLowerings.find(ifaceInst);
1273 it != ifacePortLowerings.end())
1276 auto lowering = std::make_unique<InterfaceLowering>();
1280 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1284 for (
auto &fp : lowering.ifacePorts) {
1287 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1296 portValue = moore::VariableOp::create(
1298 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1307 if (fp.modportPortSym)
1308 if (
auto *mppSym = fp.modportPortSym->as_if<slang::ast::ValueSymbol>())
1309 if (mppSym != valueSym)
1312 if (!fp.ifaceInstance)
1315 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1318 ifaceLowering->expandedMembers[fp.bodySym] = val;
1320 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1326 for (
auto &member :
module->members()) {
1327 auto loc = convertLocation(member.location);
1328 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1339 SmallVector<Value> outputs;
1340 for (
auto &port : lowering.ports) {
1342 if (
auto *expr = port.ast.getInternalExpr()) {
1343 value = convertLvalueExpression(*expr);
1344 }
else if (port.ast.internalSymbol) {
1345 if (
const auto *sym =
1346 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1347 value = valueSymbols.lookup(sym);
1350 return mlir::emitError(port.loc,
"unsupported port: `")
1352 <<
"` does not map to an internal symbol or expression";
1355 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1356 if (isa<moore::RefType>(value.getType()))
1357 value = moore::ReadOp::create(builder, value.getLoc(), value);
1358 outputs.push_back(value);
1364 Value portArg = port.arg;
1365 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1366 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1367 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1372 for (
auto &fp : lowering.ifacePorts) {
1376 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1379 Value ref = valueSymbols.lookup(valueSym);
1382 outputs.push_back(moore::ReadOp::create(builder, fp.loc, ref).getResult());
1387 for (
auto &hierPath : hierPaths[module]) {
1388 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1389 if (
auto hierValue = valueSymbols.lookup(hierPath.valueSyms.front()))
1390 if (hierPath.direction == slang::ast::ArgumentDirection::Out)
1391 outputs.push_back(hierValue);
1394 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1404 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1405 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1407 OpBuilder::InsertionGuard g(
builder);
1410 for (
auto &member : package.members()) {
1412 if (failed(member.visit(PackageVisitor(*
this, loc))))
1423 auto &lowering =
functions[&subroutine];
1425 if (!lowering->op.getOperation())
1427 return lowering.get();
1430 if (!subroutine.thisVar) {
1432 SmallString<64> name;
1434 name += subroutine.name;
1436 SmallVector<Type, 1> noThis = {};
1443 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1444 moore::ClassDeclOp ownerDecl;
1446 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1447 auto &ownerLowering =
classes[classTy];
1448 ownerDecl = ownerLowering->op;
1450 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1451 << thisTy.toString();
1456 SmallString<64> qualName;
1457 qualName += ownerDecl.getSymName();
1459 qualName += subroutine.name;
1462 SmallVector<Type, 1> extraParams;
1464 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1465 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1466 extraParams.push_back(handleTy);
1476 Context &
context,
const slang::ast::SubroutineSymbol &subroutine,
1477 ArrayRef<Type> prefixParams, ArrayRef<Type> suffixParams = {}) {
1478 using slang::ast::ArgumentDirection;
1480 SmallVector<Type> inputTypes;
1481 inputTypes.append(prefixParams.begin(), prefixParams.end());
1482 SmallVector<Type, 1> outputTypes;
1484 for (
const auto *arg : subroutine.getArguments()) {
1485 auto type =
context.convertType(arg->getType());
1488 if (arg->direction == ArgumentDirection::In) {
1489 inputTypes.push_back(type);
1491 inputTypes.push_back(
1492 moore::RefType::get(cast<moore::UnpackedType>(type)));
1496 inputTypes.append(suffixParams.begin(), suffixParams.end());
1498 const auto &returnType = subroutine.getReturnType();
1499 if (!returnType.isVoid()) {
1500 auto type =
context.convertType(returnType);
1503 outputTypes.push_back(type);
1506 return FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1509static FailureOr<SmallVector<moore::DPIArgInfo>>
1511 const slang::ast::SubroutineSymbol &subroutine) {
1512 using slang::ast::ArgumentDirection;
1514 SmallVector<moore::DPIArgInfo> args;
1515 args.reserve(subroutine.getArguments().size() +
1516 (!subroutine.getReturnType().isVoid() ? 1 : 0));
1518 for (
const auto *arg : subroutine.getArguments()) {
1519 auto type =
context.convertType(arg->getType());
1522 moore::DPIArgDirection dir;
1523 switch (arg->direction) {
1524 case ArgumentDirection::In:
1525 dir = moore::DPIArgDirection::In;
1527 case ArgumentDirection::Out:
1528 dir = moore::DPIArgDirection::Out;
1530 case ArgumentDirection::InOut:
1531 dir = moore::DPIArgDirection::InOut;
1533 case ArgumentDirection::Ref:
1534 llvm_unreachable(
"'ref' is not legal for DPI functions");
1537 {StringAttr::get(
context.getContext(), arg->name), type, dir});
1540 if (!subroutine.getReturnType().isVoid()) {
1541 auto type =
context.convertType(subroutine.getReturnType());
1544 args.push_back({StringAttr::get(
context.getContext(),
"return"), type,
1545 moore::DPIArgDirection::Return});
1555 mlir::StringRef qualifiedName,
1556 llvm::SmallVectorImpl<Type> &extraParams) {
1560 OpBuilder::InsertionGuard g(
builder);
1566 builder.setInsertionPoint(it->second);
1571 SmallVector<Type> captureTypes;
1574 for (
auto *sym : capturesIt->second) {
1578 captureTypes.push_back(
1579 moore::RefType::get(cast<moore::UnpackedType>(type)));
1588 std::unique_ptr<FunctionLowering> lowering;
1589 Operation *insertedOp =
nullptr;
1590 if (!subroutine.thisVar &&
1591 subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
1597 auto dpiOp = moore::DPIFuncOp::create(
1600 StringAttr::get(
getContext(), subroutine.name));
1601 SymbolTable::setSymbolVisibility(dpiOp, SymbolTable::Visibility::Private);
1602 lowering = std::make_unique<FunctionLowering>(dpiOp);
1604 }
else if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
1606 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
1607 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
1608 lowering = std::make_unique<FunctionLowering>(op);
1613 mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
1614 SymbolTable::setSymbolVisibility(funcOp, SymbolTable::Visibility::Private);
1615 lowering = std::make_unique<FunctionLowering>(funcOp);
1616 insertedOp = funcOp;
1622 lowering->capturedSymbols.assign(capturesIt->second.begin(),
1623 capturesIt->second.end());
1628 functions[&subroutine] = std::move(lowering);
1642 auto *lowering =
functions.at(&subroutine).get();
1647 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
1648 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1653 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport))
1656 const bool isMethod = (subroutine.thisVar !=
nullptr);
1661 if (
const auto *classTy =
1662 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
1663 for (
auto &member : classTy->members()) {
1664 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
1667 const auto &propCanon = prop->getType().getCanonicalType();
1668 if (
const auto *vi =
1669 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
1679 SmallVector<moore::VariableOp> argVariables;
1680 auto &block = lowering->op.getFunctionBody().emplaceBlock();
1687 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
1688 auto thisArg = block.addArgument(thisType, thisLoc);
1696 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
1697 auto astArgs = subroutine.getArguments();
1698 unsigned prefixCount = isMethod ? 1 : 0;
1699 auto valInputs = llvm::ArrayRef<Type>(inputs)
1700 .drop_front(prefixCount)
1701 .take_front(astArgs.size());
1703 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
1705 auto blockArg = block.addArgument(type, loc);
1707 if (isa<moore::RefType>(type)) {
1710 OpBuilder::InsertionGuard g(
builder);
1711 builder.setInsertionPointToEnd(&block);
1713 auto shadowArg = moore::VariableOp::create(
1714 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
1715 StringAttr{}, blockArg);
1717 argVariables.push_back(shadowArg);
1720 const auto &argCanon = astArg->getType().getCanonicalType();
1721 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
1727 OpBuilder::InsertionGuard g(
builder);
1728 builder.setInsertionPointToEnd(&block);
1731 if (subroutine.returnValVar) {
1732 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
1735 returnVar = moore::VariableOp::create(
1736 builder, lowering->op->getLoc(),
1737 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
1739 valueSymbols.insert(subroutine.returnValVar, returnVar);
1747 for (
auto *sym : lowering->capturedSymbols) {
1751 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1753 auto blockArg = block.addArgument(refType, loc);
1759 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
1767 if (isa<moore::CoroutineOp>(lowering->op.getOperation())) {
1768 moore::ReturnOp::create(
builder, lowering->op->getLoc());
1769 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
1771 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
1772 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(), read);
1774 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(),
1778 if (returnVar && returnVar.use_empty())
1779 returnVar.getDefiningOp()->erase();
1781 for (
auto var : argVariables) {
1782 if (llvm::all_of(var->getUsers(),
1783 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
1784 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
1785 user->getResult(0).replaceAllUsesWith(var.getInitial());
1797 const slang::ast::PrimitiveInstanceSymbol &prim) {
1798 if (prim.getDriveStrength().first.has_value() ||
1799 prim.getDriveStrength().second.has_value())
1801 <<
"primitive instances with explicit drive strengths are not "
1804 switch (prim.primitiveType.primitiveKind) {
1805 case slang::ast::PrimitiveSymbol::PrimitiveKind::NInput:
1808 case slang::ast::PrimitiveSymbol::PrimitiveKind::NOutput:
1811 case slang::ast::PrimitiveSymbol::PrimitiveKind::Fixed:
1816 <<
"unsupported instance of primitive `" << prim.primitiveType.name
1822 const slang::ast::PrimitiveInstanceSymbol &prim) {
1824 auto primName = prim.primitiveType.name;
1826 auto portConns = prim.getPortConnections();
1827 assert(portConns.size() >= 2 &&
1828 "n-input primitives should have at least 2 ports");
1832 portConns[0]->as<slang::ast::AssignmentExpression>().left();
1838 SmallVector<Value> inputVals;
1839 inputVals.reserve(portConns.size() - 1);
1840 for (
const auto *inputConn : portConns.subspan(1, portConns.size() - 1)) {
1844 inputVals.push_back(inputVal);
1847 Value nextInput = inputVals.front();
1849 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
1851 for (Value inputVal : llvm::drop_begin(inputVals))
1853 moore::AndOp::create(
builder, loc, nextInput, inputVal);
1857 for (Value inputVal : llvm::drop_begin(inputVals))
1859 moore::OrOp::create(
builder, loc, nextInput, inputVal);
1863 for (Value inputVal : llvm::drop_begin(inputVals))
1865 moore::XorOp::create(
builder, loc, nextInput, inputVal);
1868 .Case(
"nand", ([&] {
1869 for (Value inputVal : llvm::drop_begin(inputVals))
1871 moore::AndOp::create(
builder, loc, nextInput, inputVal);
1872 return moore::NotOp::create(
builder, loc, nextInput);
1875 for (Value inputVal : llvm::drop_begin(inputVals))
1877 moore::OrOp::create(
builder, loc, nextInput, inputVal);
1878 return moore::NotOp::create(
builder, loc, nextInput);
1880 .Case(
"xnor", ([&] {
1881 for (Value inputVal : llvm::drop_begin(inputVals))
1883 moore::XorOp::create(
builder, loc, nextInput, inputVal);
1884 return moore::NotOp::create(
builder, loc, nextInput);
1887 mlir::emitError(loc)
1888 <<
"unsupported primitive `" << primName <<
"`";
1895 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
1900 if (prim.getDelay()) {
1901 const slang::ast::Expression *delayExpr;
1902 if (
const auto *delay3 =
1903 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
1904 if (delay3->expr2 || delay3->expr3)
1905 return mlir::emitError(loc) <<
"only n-input primitives that specify a "
1906 "single delay are currently supported.";
1907 delayExpr = &delay3->expr1;
1908 }
else if (
const auto *delay =
1909 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
1910 delayExpr = &delay->expr;
1912 llvm_unreachable(
"unexpected delay control type in primitive instance");
1915 *delayExpr, moore::TimeType::get(
getContext()));
1918 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal, result,
1921 moore::ContinuousAssignOp::create(
builder, loc, outputVal, result);
1928 const slang::ast::PrimitiveInstanceSymbol &prim) {
1930 auto primName = prim.primitiveType.name;
1932 auto portConns = prim.getPortConnections();
1933 assert(portConns.size() >= 2 &&
1934 "n-output primitives should have at least 2 ports");
1937 SmallVector<Value> outputVals;
1938 outputVals.reserve(portConns.size() - 1);
1939 for (
const auto *outputConn : portConns.subspan(0, portConns.size() - 1)) {
1940 auto &output = outputConn->as<slang::ast::AssignmentExpression>().left();
1944 outputVals.push_back(outputVal);
1952 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
1954 ([&] {
return moore::NotOp::create(
builder, loc, inputVal); }))
1956 return moore::BoolCastOp::create(
builder, loc, inputVal);
1959 mlir::emitError(loc)
1960 <<
"unsupported primitive `" << primName <<
"`";
1968 if (prim.getDelay()) {
1969 const slang::ast::Expression *delayExpr;
1970 if (
const auto *delay3 =
1971 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
1972 if (delay3->expr2 || delay3->expr3)
1973 return mlir::emitError(loc)
1974 <<
"only n-output primitives that specify a "
1975 "single delay are currently supported.";
1976 delayExpr = &delay3->expr1;
1977 }
else if (
const auto *delay =
1978 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
1979 delayExpr = &delay->expr;
1981 llvm_unreachable(
"unexpected delay control type in primitive instance");
1984 *delayExpr, moore::TimeType::get(
getContext()));
1989 for (
auto outputVal : outputVals) {
1990 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
1995 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal,
1996 converted, delayVal);
1998 moore::ContinuousAssignOp::create(
builder, loc, outputVal, converted);
2005 const slang::ast::PrimitiveInstanceSymbol &prim) {
2006 auto primName = prim.primitiveType.name;
2011 if (primName ==
"pullup" || primName ==
"pulldown")
2015 mlir::emitError(loc) <<
"unsupported primitive `" << primName <<
"`";
2020 const slang::ast::PrimitiveInstanceSymbol &prim) {
2021 assert((prim.primitiveType.name ==
"pullup" ||
2022 prim.primitiveType.name ==
"pulldown") &&
2023 "expected pullup or pulldown primitive");
2025 assert(!prim.getDelay() &&
2026 "SystemVerilog does not allow pull gate primitives with delays");
2028 auto primName = prim.primitiveType.name;
2030 auto portConns = prim.getPortConnections();
2032 assert(portConns.size() == 1 &&
2033 "pullup/pulldown primitives should have exactly one port");
2036 portConns.front()->as<slang::ast::AssignmentExpression>().left());
2038 auto dstType = cast<moore::RefType>(portVal.getType()).getNestedType();
2039 auto dstTypeWidth = dstType.getBitSize();
2042 "expected fixed-width type for pullup/pulldown primitive");
2043 auto constVal = primName ==
"pullup" ? -1 : 0;
2044 auto c = moore::ConstantOp::create(
2046 moore::IntType::getInt(this->
getContext(), dstTypeWidth.value()),
2052 moore::ContinuousAssignOp::create(
builder, loc, portVal, converted);
2060mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
2061 const slang::ast::Type &ty) {
2062 SmallString<64> name;
2063 SmallVector<llvm::StringRef, 8> parts;
2065 const slang::ast::Scope *scope = ty.getParentScope();
2067 const auto &sym = scope->asSymbol();
2069 case slang::ast::SymbolKind::Root:
2072 case slang::ast::SymbolKind::InstanceBody:
2073 case slang::ast::SymbolKind::Instance:
2074 case slang::ast::SymbolKind::Package:
2075 case slang::ast::SymbolKind::ClassType:
2076 if (!sym.name.empty())
2077 parts.push_back(sym.name);
2082 scope = sym.getParentScope();
2085 for (
auto p :
llvm::reverse(parts)) {
2090 return mlir::StringAttr::get(ctx.
getContext(), name);
2095std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
2097 const slang::ast::ClassType &cls) {
2101 mlir::SymbolRefAttr base;
2102 if (
const auto *b = cls.getBaseClass())
2103 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
2106 SmallVector<mlir::Attribute> impls;
2107 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
2108 impls.reserve(ifaces.size());
2109 for (
const auto *iface : ifaces)
2110 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
2111 fullyQualifiedClassName(
context, *iface)));
2114 mlir::ArrayAttr implArr =
2115 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
2117 return {base, implArr};
2122struct ClassDeclVisitorBase {
2128 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
2132 return context.convertLocation(sloc);
2138struct ClassPropertyVisitor : ClassDeclVisitorBase {
2139 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2142 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2143 if (!classLowering.
op.getBody().empty())
2146 OpBuilder::InsertionGuard ig(builder);
2148 Block *body = &classLowering.
op.getBody().emplaceBlock();
2149 builder.setInsertionPointToEnd(body);
2152 for (
const auto &mem : classAST.members()) {
2153 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
2154 if (failed(prop->visit(*
this)))
2163 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
2165 auto ty =
context.convertType(prop.getType());
2169 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
2170 moore::ClassPropertyDeclOp::create(builder, loc, prop.name, ty);
2178 if (!
context.globalVariables.lookup(&prop))
2179 return context.convertGlobalVariable(prop);
2184 LogicalResult visit(
const slang::ast::ClassType &cls) {
2185 return context.buildClassProperties(cls);
2189 template <
typename T>
2190 LogicalResult visit(T &&) {
2197struct ClassMethodVisitor : ClassDeclVisitorBase {
2198 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2201 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2205 if (classLowering.
op.getBody().empty())
2208 OpBuilder::InsertionGuard ig(builder);
2209 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2212 for (
const auto &mem : classAST.members()) {
2213 if (failed(mem.visit(*
this)))
2222 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2228 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2232 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2238 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2241 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2246 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2251 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2256 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2257 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2258 static bool remarkEmitted =
false;
2262 mlir::emitRemark(classLowering.
op.getLoc())
2263 <<
"Class builtin functions (needed for randomization, constraints, "
2264 "and covergroups) are not yet supported and will be dropped "
2266 remarkEmitted =
true;
2270 const mlir::UnitAttr isVirtual =
2271 (fn.flags & slang::ast::MethodFlags::Virtual)
2272 ? UnitAttr::get(
context.getContext())
2279 if (fn.flags & slang::ast::MethodFlags::Pure) {
2281 SmallVector<Type, 1> extraParams;
2283 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2285 moore::ClassHandleType::get(
context.getContext(), classSym);
2286 extraParams.push_back(handleTy);
2290 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2294 moore::ClassMethodDeclOp::create(builder, loc, fn.name, funcTy,
nullptr);
2298 auto *lowering =
context.declareFunction(fn);
2307 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2309 moore::ClassMethodDeclOp::create(
2310 builder, loc, fn.name, fnTy,
2311 SymbolRefAttr::get(lowering->op.getNameAttr()));
2328 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2329 const auto *externImpl = fn.getSubroutine();
2333 <<
"Didn't find an implementation matching the forward declaration "
2338 return visit(*externImpl);
2342 LogicalResult visit(
const slang::ast::ClassType &cls) {
2343 if (failed(
context.buildClassProperties(cls)))
2345 return context.materializeClassMethods(cls);
2349 template <
typename T>
2350 LogicalResult visit(T &&node) {
2351 Location loc = UnknownLoc::get(
context.getContext());
2352 if constexpr (
requires { node.location; })
2354 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2355 << slang::ast::toString(node.kind);
2363 auto &lowering =
classes[&cls];
2365 return lowering.get();
2366 lowering = std::make_unique<ClassLowering>();
2371 OpBuilder::InsertionGuard g(
builder);
2377 builder.setInsertionPoint(it->second);
2379 auto symName = fullyQualifiedClassName(*
this, cls);
2381 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2383 moore::ClassDeclOp::create(
builder, loc, symName, base, impls);
2385 SymbolTable::setSymbolVisibility(classDeclOp,
2386 SymbolTable::Visibility::Public);
2388 lowering->op = classDeclOp;
2391 return lowering.get();
2398 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2399 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2406 if (classdecl.getBaseClass()) {
2407 if (
const auto *baseClassDecl =
2408 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2419 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2426 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2427 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2430 auto *lowering =
classes[&classdecl].get();
2437 if (classdecl.getBaseClass()) {
2438 if (
const auto *baseClassDecl =
2439 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2445 return ClassMethodVisitor(*
this, *lowering).run(classdecl);
2455 OpBuilder::InsertionGuard g(
builder);
2461 builder.setInsertionPoint(it->second);
2465 SmallString<64> symName;
2469 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2470 if (
const auto *parentScope = classVar->getParentScope()) {
2471 if (
const auto *parentClass =
2472 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2473 symName = fullyQualifiedClassName(*
this, *parentClass);
2475 mlir::emitError(loc)
2476 <<
"Could not access parent class of class property "
2481 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2486 symName += var.name;
2489 symName += var.name;
2498 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2499 cast<moore::UnpackedType>(type));
2510 if (var.getInitializer())
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
static Location convertLocation(MLIRContext *context, const slang::SourceManager &sourceManager, slang::SourceLocation loc)
Convert a slang SourceLocation to an MLIR Location.
static moore::ProcedureKind convertProcedureKind(slang::ast::ProceduralBlockKind kind)
static FailureOr< SmallVector< moore::DPIArgInfo > > getDPISignature(Context &context, const slang::ast::SubroutineSymbol &subroutine)
static void guessNamespacePrefix(const slang::ast::Symbol &symbol, SmallString< 64 > &prefix)
static FunctionType getFunctionSignature(Context &context, const slang::ast::SubroutineSymbol &subroutine, ArrayRef< Type > prefixParams, ArrayRef< Type > suffixParams={})
Helper function to generate the function signature from a SubroutineSymbol and optional extra argumen...
static moore::NetKind convertNetKind(slang::ast::NetType::NetKind kind)
CaptureMap analyzeFunctionCaptures(const slang::ast::RootSymbol &root)
Analyze the AST rooted at root to determine which variables each function captures.
const slang::ast::InstanceBodySymbol * getCanonicalBody(const slang::ast::InstanceSymbol &inst)
Get the slang canonical body for the given instance, if there is one.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
bool debugInfo
Generate debug information in the form of debug dialect ops in the IR.
circt::moore::ClassDeclOp op
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
FunctionLowering * declareCallableImpl(const slang::ast::SubroutineSymbol &subroutine, mlir::StringRef qualifiedName, llvm::SmallVectorImpl< Type > &extraParams)
Helper function to extract the commonalities in lowering of functions and methods.
ModuleLowering * convertModuleHeader(const slang::ast::InstanceBodySymbol *module)
Convert a module and its ports to an empty module op in the IR.
std::queue< const slang::ast::SubroutineSymbol * > functionWorklist
A list of functions for which the declaration has been created, but the body has not been defined yet...
Value convertLvalueExpression(const slang::ast::Expression &expr)
LogicalResult registerVirtualInterfaceMembers(const slang::ast::ValueSymbol &base, const slang::ast::VirtualInterfaceType &type, Location loc)
Register the interface members of a virtual interface base symbol for use in later expression convers...
Value materializeConstant(const slang::ConstantValue &constant, const slang::ast::Type &type, Location loc)
Helper function to materialize a ConstantValue as an SSA value.
LogicalResult convertModuleBody(const slang::ast::InstanceBodySymbol *module)
Convert a module's body to the corresponding IR ops.
LogicalResult materializeClassMethods(const slang::ast::ClassType &classdecl)
DenseMap< const slang::ast::ValueSymbol *, moore::GlobalVariableOp > globalVariables
A table of defined global variables that may be referred to by name in expressions.
slang::ast::Compilation & compilation
LogicalResult flushPendingMonitors()
Process any pending $monitor calls and generate the monitoring procedures at module level.
LogicalResult convertNInputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
OpBuilder builder
The builder used to create IR operations.
std::queue< const slang::ast::InstanceBodySymbol * > moduleWorklist
A list of modules for which the header has been created, but the body has not been converted yet.
LogicalResult convertGlobalVariable(const slang::ast::VariableSymbol &var)
Convert a variable to a moore.global_variable operation.
CaptureMap functionCaptures
Pre-computed capture analysis: maps each function to the set of non-local, non-global variables it ca...
DenseMap< const slang::ast::ClassType *, std::unique_ptr< ClassLowering > > classes
Classes that have already been converted.
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.
DenseMap< const slang::ast::SubroutineSymbol *, std::unique_ptr< FunctionLowering > > functions
Functions that have already been converted.
slang::TimeScale timeScale
The time scale currently in effect.
ClassLowering * declareClass(const slang::ast::ClassType &cls)
VirtualInterfaceMembers::ScopeTy VirtualInterfaceMemberScope
LogicalResult convertFixedPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
ValueSymbols valueSymbols
ValueSymbols::ScopeTy ValueSymbolScope
const ImportVerilogOptions & options
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
SmallVector< std::unique_ptr< InterfaceLowering > > interfaceInstanceStorage
Owning storage for InterfaceLowering objects because ScopedHashTable stores values by copy.
VirtualInterfaceMembers virtualIfaceMembers
Value currentThisRef
Variable to track the value of the current function's implicit this reference.
const slang::SourceManager & sourceManager
Value materializeConversion(Type type, Value value, bool isSigned, Location loc, bool fallible=false)
Helper function to insert the necessary operations to cast a value from one type to another.
void traverseInstanceBody(const slang::ast::InstanceSymbol &symbol)
void populateAssertionClocks()
Generates a map from assertions to clocks using Slang's analysis.
std::map< LocationKey, Operation * > orderedRootOps
The top-level operations ordered by their Slang source location.
InterfaceInstances::ScopeTy InterfaceInstanceScope
LogicalResult convertPrimitiveInstance(const slang::ast::PrimitiveInstanceSymbol &prim)
Convert a primitive instance.
mlir::ModuleOp intoModuleOp
SymbolTable symbolTable
A symbol table of the MLIR module we are emitting into.
DenseMap< const slang::ast::InstanceBodySymbol *, SmallVector< HierPathInfo > > hierPaths
Collect all hierarchical names used for the per module/instance.
FunctionLowering * declareFunction(const slang::ast::SubroutineSymbol &subroutine)
Convert a function and its arguments to a function declaration in the IR.
LogicalResult convertNOutputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
InterfaceInstances interfaceInstances
LogicalResult buildClassProperties(const slang::ast::ClassType &classdecl)
LogicalResult convertPackage(const slang::ast::PackageSymbol &package)
Convert a package and its contents.
MLIRContext * getContext()
Return the MLIR context.
LogicalResult defineFunction(const slang::ast::SubroutineSymbol &subroutine)
Define a function’s body.
LogicalResult convertPullGatePrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
LogicalResult convertStatement(const slang::ast::Statement &stmt)
SmallVector< const slang::ast::ValueSymbol * > globalVariableWorklist
A list of global variables that still need their initializers to be converted.
DenseMap< const slang::ast::InstanceBodySymbol *, std::unique_ptr< ModuleLowering > > modules
How we have lowered modules to MLIR.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Function lowering information.
Lowering information for an expanded interface instance.
static LocationKey get(const slang::SourceLocation &loc, const slang::SourceManager &mgr)
Module lowering information.