10#include "slang/ast/Compilation.h"
11#include "slang/ast/symbols/ClassSymbols.h"
12#include "slang/ast/symbols/MemberSymbols.h"
13#include "slang/syntax/AllSyntax.h"
14#include "slang/syntax/SyntaxVisitor.h"
15#include "llvm/ADT/STLFunctionalExtras.h"
16#include "llvm/ADT/ScopeExit.h"
19using namespace ImportVerilog;
32 const slang::ast::Scope &scope,
33 const slang::syntax::SyntaxNode *syntax) {
37 auto visitor = slang::syntax::makeSyntaxVisitor(
38 [&](
auto &visitor,
const slang::syntax::DPIExportSyntax &exportSyntax) {
39 auto svName = exportSyntax.name.valueText();
43 const auto *symbol = scope.find(svName);
44 const auto *subroutine =
45 symbol ? symbol->as_if<slang::ast::SubroutineSymbol>() :
nullptr;
49 auto cName = exportSyntax.c_identifier.valueText();
52 context.dpiExportCNames[subroutine] = std::string(cName);
54 [](
auto &visitor,
const slang::syntax::SyntaxNode &node) {
55 visitor.visitDefault(node);
57 syntax->visit(visitor);
61 SmallString<64> &prefix) {
62 if (symbol.kind != slang::ast::SymbolKind::Package)
65 if (!symbol.name.empty()) {
66 prefix += symbol.name;
83 BaseVisitor(
Context &context, Location loc)
84 : context(context), loc(loc), builder(context.builder) {}
87 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
93 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
98 LogicalResult visit(
const slang::ast::ClassType &classdecl) {
108 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
113 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
114 LogicalResult visit(
const slang::ast::ForwardingTypedefSymbol &) {
119 LogicalResult visit(
const slang::ast::ExplicitImportSymbol &) {
122 LogicalResult visit(
const slang::ast::WildcardImportSymbol &) {
127 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
132 LogicalResult visit(
const slang::ast::ElabSystemTaskSymbol &) {
137 LogicalResult visit(
const slang::ast::ParameterSymbol ¶m) {
138 visitParameter(param);
142 LogicalResult visit(
const slang::ast::SpecparamSymbol ¶m) {
143 visitParameter(param);
147 template <
class Node>
148 void visitParameter(
const Node ¶m) {
158 if (builder.getInsertionBlock()->getParentOp() == context.
intoModuleOp) {
165 SmallString<64> paramName;
167 paramName += param.name;
169 debug::VariableOp::create(builder, loc, builder.getStringAttr(paramName),
180struct RootVisitor :
public BaseVisitor {
181 using BaseVisitor::BaseVisitor;
182 using BaseVisitor::visit;
185 LogicalResult visit(
const slang::ast::PackageSymbol &package) {
186 return context.convertPackage(package);
190 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
191 if (!
context.declareFunction(subroutine))
197 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
198 return context.convertGlobalVariable(var);
202 template <
typename T>
203 LogicalResult visit(T &&node) {
204 mlir::emitError(loc,
"unsupported construct: ")
205 << slang::ast::toString(node.kind);
216struct PackageVisitor :
public BaseVisitor {
217 using BaseVisitor::BaseVisitor;
218 using BaseVisitor::visit;
221 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
222 if (!
context.declareFunction(subroutine))
228 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
229 return context.convertGlobalVariable(var);
233 template <
typename T>
234 LogicalResult visit(T &&node) {
235 mlir::emitError(loc,
"unsupported package member: ")
236 << slang::ast::toString(node.kind);
246static moore::ProcedureKind
249 case slang::ast::ProceduralBlockKind::Always:
250 return moore::ProcedureKind::Always;
251 case slang::ast::ProceduralBlockKind::AlwaysComb:
252 return moore::ProcedureKind::AlwaysComb;
253 case slang::ast::ProceduralBlockKind::AlwaysLatch:
254 return moore::ProcedureKind::AlwaysLatch;
255 case slang::ast::ProceduralBlockKind::AlwaysFF:
256 return moore::ProcedureKind::AlwaysFF;
257 case slang::ast::ProceduralBlockKind::Initial:
258 return moore::ProcedureKind::Initial;
259 case slang::ast::ProceduralBlockKind::Final:
260 return moore::ProcedureKind::Final;
262 llvm_unreachable(
"all procedure kinds handled");
267 case slang::ast::NetType::Supply0:
268 return moore::NetKind::Supply0;
269 case slang::ast::NetType::Supply1:
270 return moore::NetKind::Supply1;
271 case slang::ast::NetType::Tri:
272 return moore::NetKind::Tri;
273 case slang::ast::NetType::TriAnd:
274 return moore::NetKind::TriAnd;
275 case slang::ast::NetType::TriOr:
276 return moore::NetKind::TriOr;
277 case slang::ast::NetType::TriReg:
278 return moore::NetKind::TriReg;
279 case slang::ast::NetType::Tri0:
280 return moore::NetKind::Tri0;
281 case slang::ast::NetType::Tri1:
282 return moore::NetKind::Tri1;
283 case slang::ast::NetType::UWire:
284 return moore::NetKind::UWire;
285 case slang::ast::NetType::Wire:
286 return moore::NetKind::Wire;
287 case slang::ast::NetType::WAnd:
288 return moore::NetKind::WAnd;
289 case slang::ast::NetType::WOr:
290 return moore::NetKind::WOr;
291 case slang::ast::NetType::Interconnect:
292 return moore::NetKind::Interconnect;
293 case slang::ast::NetType::UserDefined:
294 return moore::NetKind::UserDefined;
295 case slang::ast::NetType::Unknown:
296 return moore::NetKind::Unknown;
298 llvm_unreachable(
"all net kinds handled");
302struct ModuleVisitor :
public BaseVisitor {
303 using BaseVisitor::visit;
307 StringRef blockNamePrefix;
309 ModuleVisitor(
Context &
context, Location loc, StringRef blockNamePrefix =
"")
310 : BaseVisitor(
context, loc), blockNamePrefix(blockNamePrefix) {}
313 LogicalResult visit(
const slang::ast::PortSymbol &) {
return success(); }
314 LogicalResult visit(
const slang::ast::MultiPortSymbol &) {
return success(); }
315 LogicalResult visit(
const slang::ast::InterfacePortSymbol &) {
320 LogicalResult visit(
const slang::ast::GenvarSymbol &genvarNode) {
325 LogicalResult visit(
const slang::ast::DefParamSymbol &) {
return success(); }
329 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
337 expandInterfaceInstance(
const slang::ast::InstanceSymbol &instNode) {
338 auto prefix = (Twine(blockNamePrefix) + instNode.name +
"_").str();
339 auto lowering = std::make_unique<InterfaceLowering>();
340 Context::ValueSymbolScope scope(
context.valueSymbols);
342 auto recordMember = [&](
const slang::ast::Symbol &sym,
343 Value value) ->
void {
344 lowering->expandedMembers[&sym] = value;
345 auto nameAttr = builder.getStringAttr(sym.name);
346 lowering->expandedMembersByName[nameAttr] = value;
347 if (
auto *valueSym = sym.as_if<slang::ast::ValueSymbol>())
348 context.valueSymbols.insert(valueSym, value);
351 for (
const auto &member : instNode.body.members()) {
353 if (
const auto *nestedInst = member.as_if<slang::ast::InstanceSymbol>()) {
354 if (nestedInst->body.getDefinition().definitionKind ==
355 slang::ast::DefinitionKind::Interface)
356 return mlir::emitError(loc)
357 <<
"nested interface instances are not supported: `"
358 << nestedInst->name <<
"` inside `" << instNode.name <<
"`";
361 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
362 auto loweredType =
context.convertType(*var->getDeclaredType());
365 auto varOp = moore::VariableOp::create(
367 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
368 builder.getStringAttr(Twine(prefix) + StringRef(var->name)),
370 recordMember(*var, varOp);
374 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
375 auto loweredType =
context.convertType(*net->getDeclaredType());
379 if (netKind == moore::NetKind::Interconnect ||
380 netKind == moore::NetKind::UserDefined ||
381 netKind == moore::NetKind::Unknown)
382 return mlir::emitError(loc,
"unsupported net kind `")
383 << net->netType.name <<
"`";
384 auto netOp = moore::NetOp::create(
386 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
387 builder.getStringAttr(Twine(prefix) + StringRef(net->name)),
389 recordMember(*net, netOp);
398 for (
const auto *con : instNode.getPortConnections()) {
399 const auto *expr = con->getExpression();
400 const auto *port = con->port.as_if<slang::ast::PortSymbol>();
408 Value lvalue =
context.convertLvalueExpression(*expr);
412 recordMember(*port, lvalue);
413 if (port->internalSymbol) {
414 recordMember(*port->internalSymbol, lvalue);
420 for (
const auto &member : instNode.body.members()) {
421 switch (member.kind) {
422 case slang::ast::SymbolKind::ContinuousAssign:
423 case slang::ast::SymbolKind::ProceduralBlock:
424 case slang::ast::SymbolKind::StatementBlock:
429 auto memberLoc =
context.convertLocation(member.location);
430 if (failed(member.visit(ModuleVisitor(
context, memberLoc, prefix))))
432 if (failed(
context.flushPendingMonitors()))
436 context.interfaceInstanceStorage.push_back(std::move(lowering));
437 context.interfaceInstances.insert(
438 &instNode,
context.interfaceInstanceStorage.back().get());
443 LogicalResult visit(
const slang::ast::InstanceSymbol &instNode) {
444 using slang::ast::ArgumentDirection;
445 using slang::ast::AssignmentExpression;
446 using slang::ast::MultiPortSymbol;
447 using slang::ast::PortSymbol;
449 if (
context.predeclaredInstances.contains(&instNode))
460 auto defKind = body->getDefinition().definitionKind;
461 if (defKind == slang::ast::DefinitionKind::Interface) {
462 if (
context.interfaceInstances.lookup(&instNode))
464 return expandInterfaceInstance(instNode);
467 auto *moduleLowering =
context.convertModuleHeader(body);
470 auto module = moduleLowering->op;
471 auto moduleType =
module.getModuleType();
474 SymbolTable::setSymbolVisibility(module, SymbolTable::Visibility::Private);
481 portValues.reserve(moduleType.getNumPorts());
485 const slang::ast::InstanceSymbol *>
488 for (
const auto *con : instNode.getPortConnections()) {
489 const auto *expr = con->getExpression();
494 auto *port = con->port.as_if<PortSymbol>();
495 if (
auto *existingPort =
496 moduleLowering->portsBySyntaxNode.lookup(port->getSyntax()))
499 switch (port->direction) {
500 case ArgumentDirection::In: {
501 auto refType = moore::RefType::get(
502 cast<moore::UnpackedType>(
context.convertType(port->getType())));
504 if (
const auto *net =
505 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
506 auto netOp = moore::NetOp::create(
507 builder, loc, refType,
508 StringAttr::get(builder.getContext(), net->name),
510 auto readOp = moore::ReadOp::create(builder, loc, netOp);
511 portValues.insert({port, readOp});
512 }
else if (
const auto *var =
514 ->as_if<slang::ast::VariableSymbol>()) {
515 auto varOp = moore::VariableOp::create(
516 builder, loc, refType,
517 StringAttr::get(builder.getContext(), var->name),
nullptr);
518 auto readOp = moore::ReadOp::create(builder, loc, varOp);
519 portValues.insert({port, readOp});
521 return mlir::emitError(loc)
522 <<
"unsupported internal symbol for unconnected port `"
523 << port->name <<
"`";
530 case ArgumentDirection::Out:
533 case ArgumentDirection::InOut:
534 case ArgumentDirection::Ref: {
535 auto refType = moore::RefType::get(
536 cast<moore::UnpackedType>(
context.convertType(port->getType())));
538 if (
const auto *net =
539 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
540 auto netOp = moore::NetOp::create(
541 builder, loc, refType,
542 StringAttr::get(builder.getContext(), net->name),
544 portValues.insert({port, netOp});
545 }
else if (
const auto *var =
547 ->as_if<slang::ast::VariableSymbol>()) {
548 auto varOp = moore::VariableOp::create(
549 builder, loc, refType,
550 StringAttr::get(builder.getContext(), var->name),
nullptr);
551 portValues.insert({port, varOp});
553 return mlir::emitError(loc)
554 <<
"unsupported internal symbol for unconnected port `"
555 << port->name <<
"`";
564 if (
const auto *assign = expr->as_if<AssignmentExpression>())
565 expr = &assign->left();
570 if (
auto *port = con->port.as_if<PortSymbol>()) {
572 auto value = (port->direction == ArgumentDirection::In)
573 ?
context.convertRvalueExpression(*expr)
574 :
context.convertLvalueExpression(*expr);
577 if (
auto *existingPort =
578 moduleLowering->portsBySyntaxNode.lookup(con->port.getSyntax()))
580 portValues.insert({port, value});
587 if (
const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
589 auto value =
context.convertLvalueExpression(*expr);
593 for (
const auto *port :
llvm::reverse(multiPort->ports)) {
594 if (
auto *existingPort = moduleLowering->portsBySyntaxNode.lookup(
595 con->port.getSyntax()))
597 unsigned width = port->getType().getBitWidth();
598 auto sliceType =
context.convertType(port->getType());
601 Value slice = moore::ExtractRefOp::create(
603 moore::RefType::get(cast<moore::UnpackedType>(sliceType)), value,
606 if (port->direction == ArgumentDirection::In)
607 slice = moore::ReadOp::create(builder, loc, slice);
608 portValues.insert({port, slice});
616 if (
const auto *ifacePort =
617 con->port.as_if<slang::ast::InterfacePortSymbol>()) {
618 auto ifaceConn = con->getIfaceConn();
619 const auto *connInst =
620 ifaceConn.first->as_if<slang::ast::InstanceSymbol>();
622 ifaceConnMap[ifacePort] = connInst;
626 mlir::emitError(loc) <<
"unsupported instance port `" << con->port.name
627 <<
"` (" << slang::ast::toString(con->port.kind)
635 SmallVector<Value> inputValues(moduleLowering->numExplicitInputs);
636 SmallVector<Value> outputValues(moduleLowering->numExplicitOutputs);
638 for (
auto &port : moduleLowering->ports) {
639 auto value = portValues.lookup(&port.ast);
640 if (port.ast.direction == ArgumentDirection::Out)
641 outputValues[*port.outputIdx] = value;
643 inputValues[*port.inputIdx] = value;
649 for (
auto &fp : moduleLowering->ifacePorts) {
650 if (!fp.bodySym || !fp.origin)
653 auto it = ifaceConnMap.find(fp.origin);
654 if (it == ifaceConnMap.end()) {
656 <<
"no interface connection for port `" << fp.name <<
"`";
659 const auto *connInst = it->second;
661 auto *ifaceLowering =
context.interfaceInstances.lookup(connInst);
662 if (!ifaceLowering) {
664 <<
"interface instance `" << connInst->name <<
"` was not expanded";
668 auto valIt = ifaceLowering->expandedMembers.find(fp.bodySym);
669 if (valIt == ifaceLowering->expandedMembers.end()) {
671 <<
"unresolved interface port signal `" << fp.name <<
"`";
674 Value val = valIt->second;
676 outputValues[*fp.outputIdx] = val;
680 if (isa<moore::RefType>(val.getType()) && !isa<moore::RefType>(fp.type))
681 val = moore::ReadOp::create(builder, loc, val);
682 inputValues[*fp.inputIdx] = val;
688 for (
auto [value, type] :
689 llvm::zip(inputValues, moduleType.getInputTypes())) {
693 value =
context.materializeConversion(type, value,
false, value.getLoc());
695 return mlir::emitError(loc) <<
"unsupported port";
702 for (
const auto &hierPath :
context.hierPaths[body]) {
703 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
704 if (!hierPath.hierName || hierPath.direction != ArgumentDirection::In)
709 for (
auto &alias : hierPath.valueSyms)
710 if ((hierValue =
context.valueSymbols.lookup(alias.first)))
712 inputValues.push_back(hierValue);
716 for (
auto value : inputValues)
718 return
mlir::emitError(loc) <<
"unsupported port";
721 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
722 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
723 auto inst = moore::InstanceOp::create(
724 builder, loc, moduleType.getOutputTypes(),
725 builder.getStringAttr(Twine(blockNamePrefix) + instNode.name),
726 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
727 inputNames, outputNames);
731 auto aliasReachedThroughInstance =
732 [&](
const slang::ast::InstanceBodySymbol *aliasBody) {
733 for (
auto *b = aliasBody; b && b->parentInstance;
734 b = b->parentInstance->getParentScope()->getContainingInstance())
735 if (b->parentInstance == &instNode)
745 for (
const auto &hierPath :
context.hierPaths[body])
746 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out) {
747 auto result = inst->getResult(*hierPath.idx);
748 for (
auto &alias : hierPath.valueSyms)
749 if (aliasReachedThroughInstance(alias.second))
750 context.valueSymbols.insert(alias.first, result);
751 context.hierValueSymbols[{&instNode, hierPath.hierName}] = result;
755 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
758 Value rvalue = output;
759 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
761 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
762 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
769 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
770 auto ref =
context.valueSymbols.lookup(&varNode);
772 return mlir::emitError(loc)
773 <<
"internal error: missing predeclared variable `" << varNode.name
776 auto varOp = ref.getDefiningOp<moore::VariableOp>();
778 return mlir::emitError(loc)
779 <<
"internal error: predeclared variable `" << varNode.name
780 <<
"` is not a moore.variable";
782 if (
const auto *init = varNode.getInitializer()) {
783 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
784 auto initial =
context.convertRvalueExpression(*init, loweredType);
787 varOp.getInitialMutable().assign(initial);
794 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
795 auto ref =
context.valueSymbols.lookup(&netNode);
797 return mlir::emitError(loc) <<
"internal error: missing predeclared net `"
798 << netNode.name <<
"`";
800 auto netOp = ref.getDefiningOp<moore::NetOp>();
802 return mlir::emitError(loc) <<
"internal error: predeclared net `"
803 << netNode.name <<
"` is not a moore.net";
805 if (
const auto *init = netNode.getInitializer()) {
806 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
807 auto assignment =
context.convertRvalueExpression(*init, loweredType);
810 netOp.getAssignmentMutable().assign(assignment);
816 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
818 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
819 auto lhs =
context.convertLvalueExpression(expr.left());
823 auto rhs =
context.convertRvalueExpression(
824 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
829 if (
auto *timingCtrl = assignNode.getDelay()) {
830 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
831 auto delay =
context.convertRvalueExpression(
832 ctrl->expr, moore::TimeType::get(builder.getContext()));
835 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
838 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
843 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
848 LogicalResult convertProcedure(moore::ProcedureKind kind,
849 const slang::ast::Statement &body) {
850 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
851 return context.convertStatement(body);
852 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
853 OpBuilder::InsertionGuard guard(builder);
854 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
855 Context::ValueSymbolScope scope(
context.valueSymbols);
856 Context::VirtualInterfaceMemberScope vifMemberScope(
858 if (failed(
context.convertStatement(body)))
860 if (builder.getBlock())
861 moore::ReturnOp::create(builder, loc);
865 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
868 if (
context.options.lowerAlwaysAtStarAsComb) {
869 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
870 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
872 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
873 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
881 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
883 if (genNode.isUninstantiated)
887 SmallString<64> prefix = blockNamePrefix;
888 if (!genNode.name.empty() ||
889 genNode.getParentScope()->asSymbol().kind !=
890 slang::ast::SymbolKind::GenerateBlockArray) {
891 prefix += genNode.getExternalName();
896 for (
auto &member : genNode.members())
897 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
903 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
906 SmallString<64> prefix = blockNamePrefix;
907 prefix += genArrNode.getExternalName();
909 auto prefixBaseLen = prefix.size();
912 for (
const auto *entry : genArrNode.entries) {
914 prefix.resize(prefixBaseLen);
915 if (entry->arrayIndex)
916 prefix += entry->arrayIndex->toString();
918 Twine(entry->constructIndex).toVector(prefix);
922 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
934 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
940 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
946 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
952 LogicalResult visit(
const slang::ast::LetDeclSymbol &) {
return success(); }
955 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
956 if (!
context.declareFunction(subroutine))
962 LogicalResult visit(
const slang::ast::PrimitiveInstanceSymbol &prim) {
963 return context.convertPrimitiveInstance(prim);
967 template <
typename T>
968 LogicalResult visit(T &&node) {
969 mlir::emitError(loc,
"unsupported module member: ")
970 << slang::ast::toString(node.kind);
975struct ModulePredeclaration {
979 ModulePredeclaration(
Context &context)
980 : context(context), builder(context.builder) {}
982 LogicalResult declareVariable(
const slang::ast::VariableSymbol &varNode,
983 Location loc, StringRef blockNamePrefix) {
984 auto loweredType = context.
convertType(*varNode.getDeclaredType());
988 auto varOp = moore::VariableOp::create(
990 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
991 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), Value{});
994 const auto &canonTy = varNode.getType().getCanonicalType();
995 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
1002 LogicalResult declareNet(
const slang::ast::NetSymbol &netNode, Location loc,
1003 StringRef blockNamePrefix) {
1004 auto loweredType = context.
convertType(*netNode.getDeclaredType());
1009 if (netkind == moore::NetKind::Interconnect ||
1010 netkind == moore::NetKind::UserDefined ||
1011 netkind == moore::NetKind::Unknown)
1012 return mlir::emitError(loc,
"unsupported net kind `")
1013 << netNode.netType.name <<
"`";
1015 auto netOp = moore::NetOp::create(
1017 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
1018 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
1025 getGenerateBlockPrefix(
const slang::ast::GenerateBlockSymbol &genNode,
1026 StringRef blockNamePrefix) {
1027 SmallString<64> prefix = blockNamePrefix;
1028 if (!genNode.name.empty() ||
1029 genNode.getParentScope()->asSymbol().kind !=
1030 slang::ast::SymbolKind::GenerateBlockArray) {
1031 prefix += genNode.getExternalName();
1038 predeclareStorageGenerateBlock(
const slang::ast::GenerateBlockSymbol &genNode,
1039 StringRef blockNamePrefix) {
1040 if (genNode.isUninstantiated)
1042 return predeclareStorageScope(
1043 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1046 LogicalResult predeclareInterfaceGenerateBlock(
1047 const slang::ast::GenerateBlockSymbol &genNode,
1048 StringRef blockNamePrefix) {
1049 if (genNode.isUninstantiated)
1051 return predeclareInterfaceScope(
1052 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1055 LogicalResult predeclareModuleInstanceGenerateBlock(
1056 const slang::ast::GenerateBlockSymbol &genNode,
1057 StringRef blockNamePrefix) {
1058 if (genNode.isUninstantiated)
1060 return predeclareModuleInstanceScope(
1061 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1064 LogicalResult predeclareGenerateBlockArray(
1065 const slang::ast::GenerateBlockArraySymbol &genArrNode,
1066 StringRef blockNamePrefix,
1067 llvm::function_ref<LogicalResult(
const slang::ast::GenerateBlockSymbol &,
1070 SmallString<64> prefix = blockNamePrefix;
1071 prefix += genArrNode.getExternalName();
1073 auto prefixBaseLen = prefix.size();
1075 for (
const auto *entry : genArrNode.entries) {
1076 prefix.resize(prefixBaseLen);
1077 if (entry->arrayIndex)
1078 prefix += entry->arrayIndex->toString();
1080 Twine(entry->constructIndex).toVector(prefix);
1083 if (failed(predeclareBlock(*entry, prefix)))
1089 LogicalResult predeclareStorageMember(
const slang::ast::Symbol &member,
1090 StringRef blockNamePrefix) {
1092 if (
const auto *varNode = member.as_if<slang::ast::VariableSymbol>())
1093 return declareVariable(*varNode, loc, blockNamePrefix);
1095 if (
const auto *netNode = member.as_if<slang::ast::NetSymbol>())
1096 return declareNet(*netNode, loc, blockNamePrefix);
1098 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1099 return predeclareStorageGenerateBlock(*genNode, blockNamePrefix);
1101 if (
const auto *genArrNode =
1102 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1103 return predeclareGenerateBlockArray(
1104 *genArrNode, blockNamePrefix,
1105 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1106 return predeclareStorageGenerateBlock(gen, prefix);
1112 LogicalResult predeclareInterfaceMember(
const slang::ast::Symbol &member,
1113 StringRef blockNamePrefix) {
1115 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1116 if (instNode->body.getDefinition().definitionKind ==
1117 slang::ast::DefinitionKind::Interface)
1118 return ModuleVisitor(context, loc, blockNamePrefix)
1119 .expandInterfaceInstance(*instNode);
1123 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1124 return predeclareInterfaceGenerateBlock(*genNode, blockNamePrefix);
1126 if (
const auto *genArrNode =
1127 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1128 return predeclareGenerateBlockArray(
1129 *genArrNode, blockNamePrefix,
1130 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1131 return predeclareInterfaceGenerateBlock(gen, prefix);
1137 LogicalResult predeclareModuleInstanceMember(
const slang::ast::Symbol &member,
1138 StringRef blockNamePrefix) {
1140 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1141 if (instNode->body.getDefinition().definitionKind !=
1142 slang::ast::DefinitionKind::Interface) {
1144 ModuleVisitor(context, loc, blockNamePrefix).visit(*instNode)))
1151 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1152 return predeclareModuleInstanceGenerateBlock(*genNode, blockNamePrefix);
1154 if (
const auto *genArrNode =
1155 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1156 return predeclareGenerateBlockArray(
1157 *genArrNode, blockNamePrefix,
1158 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1159 return predeclareModuleInstanceGenerateBlock(gen, prefix);
1165 LogicalResult predeclareStorageScope(
const slang::ast::Scope &scope,
1166 StringRef blockNamePrefix) {
1167 for (
auto &member : scope.members())
1168 if (failed(predeclareStorageMember(member, blockNamePrefix)))
1173 LogicalResult predeclareInterfaceScope(
const slang::ast::Scope &scope,
1174 StringRef blockNamePrefix) {
1175 for (
auto &member : scope.members())
1176 if (failed(predeclareInterfaceMember(member, blockNamePrefix)))
1181 LogicalResult predeclareModuleInstanceScope(
const slang::ast::Scope &scope,
1182 StringRef blockNamePrefix) {
1183 for (
auto &member : scope.members())
1184 if (failed(predeclareModuleInstanceMember(member, blockNamePrefix)))
1189 LogicalResult predeclareScope(
const slang::ast::Scope &scope,
1190 StringRef blockNamePrefix) {
1194 if (failed(predeclareStorageScope(scope, blockNamePrefix)))
1200 if (failed(predeclareInterfaceScope(scope, blockNamePrefix)))
1205 return predeclareModuleInstanceScope(scope, blockNamePrefix);
1216LogicalResult Context::convertCompilation() {
1222 timeScale = root.getTimeScale().value_or(slang::TimeScale());
1223 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1227 SmallVector<AmbiguousHierCapture> ambiguousHierCaptures;
1229 for (
auto &ambiguous : ambiguousHierCaptures) {
1230 auto d = mlir::emitError(
convertLocation(ambiguous.function->location))
1231 <<
"hierarchical reference to `" << ambiguous.symbol->name
1232 <<
"` is ambiguous: this function reaches it through more than "
1233 "one instance of the same module, which is not yet supported";
1235 <<
"symbol declared here";
1237 if (!ambiguousHierCaptures.empty())
1242 for (
auto *inst : root.topInstances)
1252 for (
auto *unit : root.compilationUnits) {
1254 for (
const auto &member : unit->members()) {
1256 if (failed(member.visit(RootVisitor(*
this, loc))))
1264 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
1265 for (
auto *inst : root.topInstances) {
1267 if (body->getDefinition().definitionKind !=
1268 slang::ast::DefinitionKind::Interface)
1275 auto *
module = moduleWorklist.front();
1283 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
1284 classMethodWorklist.reserve(
classes.size());
1286 classMethodWorklist.push_back(kv.first);
1288 for (
auto *inst : classMethodWorklist) {
1307 auto &block = varOp.getInitRegion().emplaceBlock();
1308 OpBuilder::InsertionGuard guard(
builder);
1309 builder.setInsertionPointToEnd(&block);
1314 moore::YieldOp::create(
builder, varOp.getLoc(), value);
1323 using slang::ast::ArgumentDirection;
1324 using slang::ast::MultiPortSymbol;
1325 using slang::ast::ParameterSymbol;
1326 using slang::ast::PortSymbol;
1327 using slang::ast::TypeParameterSymbol;
1332 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1333 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1340 slot = std::make_unique<ModuleLowering>();
1341 auto &lowering = *slot;
1344 OpBuilder::InsertionGuard g(
builder);
1349 auto kind =
module->getDefinition().definitionKind;
1350 if (kind != slang::ast::DefinitionKind::Module &&
1351 kind != slang::ast::DefinitionKind::Program) {
1352 mlir::emitError(loc) <<
"unsupported definition: "
1353 <<
module->getDefinition().getKindString();
1358 auto block = std::make_unique<Block>();
1359 SmallVector<hw::ModulePort> modulePorts;
1362 unsigned int outputIdx = 0, inputIdx = 0;
1363 for (
auto *symbol :
module->getPortList()) {
1364 auto handlePort = [&](const PortSymbol &port) {
1365 auto portLoc = convertLocation(port.location);
1369 auto portName =
builder.getStringAttr(port.name);
1371 std::optional<unsigned> portOutputIdx;
1372 std::optional<unsigned> portInputIdx;
1373 if (port.direction == ArgumentDirection::Out) {
1375 portOutputIdx = outputIdx++;
1379 if (port.direction != ArgumentDirection::In)
1380 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1382 arg = block->addArgument(type, portLoc);
1383 portInputIdx = inputIdx++;
1385 lowering.ports.push_back(
1386 {port, portLoc, arg, portOutputIdx, portInputIdx});
1393 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1396 auto [connSym, modportSym] = ifacePort.getConnection();
1397 const auto *ifaceInst =
1398 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1399 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1403 for (
const auto &member : modportSym->members()) {
1404 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1411 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1414 std::optional<unsigned> ifaceOutputIdx;
1415 std::optional<unsigned> ifaceInputIdx;
1416 if (mpp->direction == ArgumentDirection::Out) {
1418 modulePorts.push_back({name, type, dir});
1419 ifaceOutputIdx = outputIdx++;
1422 if (mpp->direction != ArgumentDirection::In)
1423 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1424 modulePorts.push_back({name, type, dir});
1425 arg = block->addArgument(type, portLoc);
1426 ifaceInputIdx = inputIdx++;
1428 lowering.ifacePorts.push_back(
1429 {name, dir, type, portLoc, arg, &ifacePort, mpp->internalSymbol,
1430 ifaceInst, mpp, ifaceOutputIdx, ifaceInputIdx});
1435 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1437 mlir::emitError(portLoc)
1438 <<
"unsupported interface port connection for `" << ifacePort.name
1442 for (
const auto &member : instSym->body.members()) {
1443 const slang::ast::Type *slangType =
nullptr;
1444 const slang::ast::Symbol *bodySym =
nullptr;
1445 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1446 slangType = &var->getType();
1448 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1449 slangType = &net->getType();
1457 auto name = builder.getStringAttr(Twine(portPrefix) +
1458 StringRef(bodySym->name));
1459 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1461 auto arg = block->addArgument(refType, portLoc);
1462 lowering.ifacePorts.push_back(
1464 bodySym, instSym,
nullptr, std::nullopt, inputIdx++});
1470 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1471 if (failed(handlePort(*port)))
1473 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1474 for (
auto *port : multiPort->ports)
1475 if (failed(handlePort(*port)))
1477 }
else if (
const auto *ifacePort =
1478 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1479 if (failed(handleIfacePort(*ifacePort)))
1483 <<
"unsupported module port `" << symbol->name <<
"` ("
1484 << slang::ast::toString(symbol->kind) <<
")";
1490 lowering.numExplicitOutputs = outputIdx;
1491 lowering.numExplicitInputs = inputIdx;
1494 for (
auto &hierPath : hierPaths[module]) {
1495 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1496 auto hierType =
convertType(hierPath.valueSyms.front().first->getType());
1500 if (
auto hierName = hierPath.hierName) {
1502 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1503 if (hierPath.direction == ArgumentDirection::Out) {
1504 hierPath.idx = outputIdx++;
1507 hierPath.idx = inputIdx++;
1511 block->addArgument(hierType, hierLoc);
1515 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1520 auto it = orderedRootOps.upper_bound(key);
1521 if (it == orderedRootOps.end())
1522 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1524 builder.setInsertionPoint(it->second);
1528 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1529 orderedRootOps.insert(it, {key, moduleOp});
1530 moduleOp.getBodyRegion().push_back(block.release());
1531 lowering.op = moduleOp;
1535 symbolTable.insert(moduleOp);
1538 moduleWorklist.push(module);
1541 for (
const auto &port : lowering.ports)
1542 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1549 auto &lowering = *
modules[module];
1552 llvm::scope_exit currentDefinitionGuard(
1556 OpBuilder::InsertionGuard g(
builder);
1557 builder.setInsertionPointToEnd(lowering.op.getBody());
1566 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1567 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1572 for (
auto &hierPath :
hierPaths[module])
1573 if (hierPath.direction == slang::ast::ArgumentDirection::In &&
1575 auto arg = lowering.op.getBody()->getArgument(*hierPath.idx);
1576 for (
auto &alias : hierPath.valueSyms)
1584 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1587 auto getIfacePortLowering =
1593 if (
auto it = ifacePortLowerings.find(ifaceInst);
1594 it != ifacePortLowerings.end())
1597 auto lowering = std::make_unique<InterfaceLowering>();
1601 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1605 for (
auto &fp : lowering.ifacePorts) {
1608 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1617 portValue = moore::VariableOp::create(
1619 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1628 if (fp.modportPortSym)
1629 if (
auto *mppSym = fp.modportPortSym->as_if<slang::ast::ValueSymbol>())
1630 if (mppSym != valueSym)
1633 if (!fp.ifaceInstance)
1636 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1639 ifaceLowering->expandedMembers[fp.bodySym] = val;
1641 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1647 llvm::scope_exit predeclaredInstancesGuard(
1657 if (failed(ModulePredeclaration(*this).predeclareScope(*module,
"")))
1661 for (
auto &member :
module->members()) {
1662 auto loc = convertLocation(member.location);
1663 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1675 SmallVector<Value> outputs(lowering.numExplicitOutputs);
1676 for (
auto &port : lowering.ports) {
1678 if (
auto *expr = port.ast.getInternalExpr()) {
1679 value = convertLvalueExpression(*expr);
1680 }
else if (port.ast.internalSymbol) {
1681 if (
const auto *sym =
1682 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1683 value = valueSymbols.lookup(sym);
1686 return mlir::emitError(port.loc,
"unsupported port: `")
1688 <<
"` does not map to an internal symbol or expression";
1691 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1692 if (isa<moore::RefType>(value.getType()))
1693 value = moore::ReadOp::create(builder, value.getLoc(), value);
1694 outputs[*port.outputIdx] = value;
1700 Value portArg = port.arg;
1701 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1702 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1703 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1708 for (
auto &fp : lowering.ifacePorts) {
1712 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1715 Value ref = valueSymbols.lookup(valueSym);
1718 outputs[*fp.outputIdx] =
1719 moore::ReadOp::create(builder, fp.loc, ref).getResult();
1724 for (
auto &hierPath : hierPaths[module]) {
1725 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1726 if (hierPath.direction != slang::ast::ArgumentDirection::Out)
1730 for (
auto &alias : hierPath.valueSyms)
1731 if ((hierValue = valueSymbols.lookup(alias.first)))
1736 auto name = hierPath.hierName.getValue();
1737 if (
auto dot = name.find(
"."); dot != llvm::StringRef::npos) {
1738 auto innerName = builder.getStringAttr(name.drop_front(dot + 1));
1739 for (
auto &member : module->members())
1740 if (auto *inst = member.as_if<
slang::ast::InstanceSymbol>())
1741 if (
llvm::StringRef(inst->name.
data(), inst->name.size()) ==
1742 name.take_front(dot)) {
1743 hierValue = hierValueSymbols.lookup({inst, innerName});
1746 }
else if (
auto *sym =
1747 module->find(std::string_view(name.data(), name.size()))) {
1749 if (
auto *valueSym = sym->as_if<slang::ast::ValueSymbol>())
1750 hierValue = valueSymbols.lookup(valueSym);
1754 return mlir::emitError(lowering.op.getLoc())
1755 <<
"unable to resolve hierarchical output `"
1756 << hierPath.hierName.getValue() <<
"` in module `" <<
module->name
1758 outputs.push_back(hierValue);
1761 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1771 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1772 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1776 OpBuilder::InsertionGuard g(
builder);
1779 for (
auto &member : package.members()) {
1781 if (failed(member.visit(PackageVisitor(*
this, loc))))
1792 auto &lowering =
functions[&subroutine];
1794 if (!lowering->op.getOperation())
1796 return lowering.get();
1799 if (!subroutine.thisVar) {
1801 SmallString<64> name;
1803 name += subroutine.name;
1805 SmallVector<Type, 1> noThis = {};
1812 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1813 moore::ClassDeclOp ownerDecl;
1815 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1816 auto &ownerLowering =
classes[classTy];
1817 ownerDecl = ownerLowering->op;
1819 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1820 << thisTy.toString();
1825 SmallString<64> qualName;
1826 qualName += ownerDecl.getSymName();
1828 qualName += subroutine.name;
1831 SmallVector<Type, 1> extraParams;
1833 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1834 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1835 extraParams.push_back(handleTy);
1845 Context &
context,
const slang::ast::SubroutineSymbol &subroutine,
1846 ArrayRef<Type> prefixParams, ArrayRef<Type> suffixParams = {}) {
1847 using slang::ast::ArgumentDirection;
1849 SmallVector<Type> inputTypes;
1850 inputTypes.append(prefixParams.begin(), prefixParams.end());
1851 SmallVector<Type, 1> outputTypes;
1853 for (
const auto *arg : subroutine.getArguments()) {
1854 auto type =
context.convertType(arg->getType());
1857 if (arg->direction == ArgumentDirection::In) {
1858 inputTypes.push_back(type);
1860 inputTypes.push_back(
1861 moore::RefType::get(cast<moore::UnpackedType>(type)));
1865 inputTypes.append(suffixParams.begin(), suffixParams.end());
1867 const auto &returnType = subroutine.getReturnType();
1868 if (!returnType.isVoid()) {
1869 auto type =
context.convertType(returnType);
1872 outputTypes.push_back(type);
1875 return FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1878static FailureOr<SmallVector<moore::DPIArgInfo>>
1880 const slang::ast::SubroutineSymbol &subroutine) {
1881 using slang::ast::ArgumentDirection;
1883 SmallVector<moore::DPIArgInfo> args;
1884 args.reserve(subroutine.getArguments().size() +
1885 (!subroutine.getReturnType().isVoid() ? 1 : 0));
1887 for (
const auto *arg : subroutine.getArguments()) {
1888 auto type =
context.convertType(arg->getType());
1891 moore::DPIArgDirection dir;
1892 switch (arg->direction) {
1893 case ArgumentDirection::In:
1894 dir = moore::DPIArgDirection::In;
1896 case ArgumentDirection::Out:
1897 dir = moore::DPIArgDirection::Out;
1899 case ArgumentDirection::InOut:
1900 dir = moore::DPIArgDirection::InOut;
1902 case ArgumentDirection::Ref:
1903 llvm_unreachable(
"'ref' is not legal for DPI functions");
1906 {StringAttr::get(
context.getContext(), arg->name), type, dir});
1909 if (!subroutine.getReturnType().isVoid()) {
1910 auto type =
context.convertType(subroutine.getReturnType());
1913 args.push_back({StringAttr::get(
context.getContext(),
"return"), type,
1914 moore::DPIArgDirection::Return});
1924 mlir::StringRef qualifiedName,
1925 llvm::SmallVectorImpl<Type> &extraParams) {
1929 OpBuilder::InsertionGuard g(
builder);
1935 builder.setInsertionPoint(it->second);
1940 SmallVector<Type> captureTypes;
1943 for (
auto *sym : capturesIt->second) {
1947 captureTypes.push_back(
1948 moore::RefType::get(cast<moore::UnpackedType>(type)));
1957 std::unique_ptr<FunctionLowering> lowering;
1958 Operation *insertedOp =
nullptr;
1963 auto setVisibilityAndExportAttr = [&](Operation *op) {
1966 builder.getStringAttr(dpiExportIt->second));
1967 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Public);
1970 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
1972 if (!subroutine.thisVar &&
1973 subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
1979 auto dpiOp = moore::DPIFuncOp::create(
1982 StringAttr::get(
getContext(), subroutine.name));
1983 setVisibilityAndExportAttr(dpiOp);
1984 lowering = std::make_unique<FunctionLowering>(dpiOp);
1986 }
else if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
1988 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
1989 setVisibilityAndExportAttr(op);
1990 lowering = std::make_unique<FunctionLowering>(op);
1995 mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
1996 setVisibilityAndExportAttr(funcOp);
1997 lowering = std::make_unique<FunctionLowering>(funcOp);
1998 insertedOp = funcOp;
2004 lowering->capturedSymbols.assign(capturesIt->second.begin(),
2005 capturesIt->second.end());
2010 functions[&subroutine] = std::move(lowering);
2024 auto *lowering =
functions.at(&subroutine).get();
2029 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
2030 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2035 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport))
2038 const bool isMethod = (subroutine.thisVar !=
nullptr);
2043 if (
const auto *classTy =
2044 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
2045 for (
auto &member : classTy->members()) {
2046 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
2049 const auto &propCanon = prop->getType().getCanonicalType();
2050 if (
const auto *vi =
2051 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
2061 SmallVector<moore::VariableOp> argVariables;
2062 auto &block = lowering->op.getFunctionBody().emplaceBlock();
2069 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
2070 auto thisArg = block.addArgument(thisType, thisLoc);
2078 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
2079 auto astArgs = subroutine.getArguments();
2080 unsigned prefixCount = isMethod ? 1 : 0;
2081 auto valInputs = llvm::ArrayRef<Type>(inputs)
2082 .drop_front(prefixCount)
2083 .take_front(astArgs.size());
2085 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
2087 auto blockArg = block.addArgument(type, loc);
2089 if (isa<moore::RefType>(type)) {
2092 OpBuilder::InsertionGuard g(
builder);
2093 builder.setInsertionPointToEnd(&block);
2095 auto shadowArg = moore::VariableOp::create(
2096 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
2097 StringAttr{}, blockArg);
2099 argVariables.push_back(shadowArg);
2102 const auto &argCanon = astArg->getType().getCanonicalType();
2103 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
2109 OpBuilder::InsertionGuard g(
builder);
2110 builder.setInsertionPointToEnd(&block);
2113 if (subroutine.returnValVar) {
2114 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
2117 returnVar = moore::VariableOp::create(
2118 builder, lowering->op->getLoc(),
2119 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
2121 valueSymbols.insert(subroutine.returnValVar, returnVar);
2129 for (
auto *sym : lowering->capturedSymbols) {
2133 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
2135 auto blockArg = block.addArgument(refType, loc);
2141 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
2145 llvm::scope_exit restoreFunctionLowering(
2154 if (isa<moore::CoroutineOp>(lowering->op.getOperation())) {
2155 moore::ReturnOp::create(
builder, lowering->op->getLoc());
2156 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
2158 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
2159 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(), read);
2161 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(),
2165 if (returnVar && returnVar.use_empty())
2166 returnVar.getDefiningOp()->erase();
2168 for (
auto var : argVariables) {
2169 if (llvm::all_of(var->getUsers(),
2170 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
2171 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
2172 user->getResult(0).replaceAllUsesWith(var.getInitial());
2184 const slang::ast::PrimitiveInstanceSymbol &prim) {
2185 if (prim.getDriveStrength().first.has_value() ||
2186 prim.getDriveStrength().second.has_value())
2188 <<
"primitive instances with explicit drive strengths are not "
2191 switch (prim.primitiveType.primitiveKind) {
2192 case slang::ast::PrimitiveSymbol::PrimitiveKind::NInput:
2195 case slang::ast::PrimitiveSymbol::PrimitiveKind::NOutput:
2198 case slang::ast::PrimitiveSymbol::PrimitiveKind::Fixed:
2203 <<
"unsupported instance of primitive `" << prim.primitiveType.name
2209 const slang::ast::PrimitiveInstanceSymbol &prim) {
2211 auto primName = prim.primitiveType.name;
2213 auto portConns = prim.getPortConnections();
2214 assert(portConns.size() >= 2 &&
2215 "n-input primitives should have at least 2 ports");
2219 portConns[0]->as<slang::ast::AssignmentExpression>().left();
2225 SmallVector<Value> inputVals;
2226 inputVals.reserve(portConns.size() - 1);
2227 for (
const auto *inputConn : portConns.subspan(1, portConns.size() - 1)) {
2231 inputVals.push_back(inputVal);
2234 Value nextInput = inputVals.front();
2236 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2238 for (Value inputVal : llvm::drop_begin(inputVals))
2240 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2244 for (Value inputVal : llvm::drop_begin(inputVals))
2246 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2250 for (Value inputVal : llvm::drop_begin(inputVals))
2252 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2255 .Case(
"nand", ([&] {
2256 for (Value inputVal : llvm::drop_begin(inputVals))
2258 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2259 return moore::NotOp::create(
builder, loc, nextInput);
2262 for (Value inputVal : llvm::drop_begin(inputVals))
2264 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2265 return moore::NotOp::create(
builder, loc, nextInput);
2267 .Case(
"xnor", ([&] {
2268 for (Value inputVal : llvm::drop_begin(inputVals))
2270 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2271 return moore::NotOp::create(
builder, loc, nextInput);
2274 mlir::emitError(loc)
2275 <<
"unsupported primitive `" << primName <<
"`";
2282 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2287 if (prim.getDelay()) {
2288 const slang::ast::Expression *delayExpr;
2289 if (
const auto *delay3 =
2290 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2291 if (delay3->expr2 || delay3->expr3)
2292 return mlir::emitError(loc) <<
"only n-input primitives that specify a "
2293 "single delay are currently supported.";
2294 delayExpr = &delay3->expr1;
2295 }
else if (
const auto *delay =
2296 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2297 delayExpr = &delay->expr;
2299 llvm_unreachable(
"unexpected delay control type in primitive instance");
2302 *delayExpr, moore::TimeType::get(
getContext()));
2305 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal, result,
2308 moore::ContinuousAssignOp::create(
builder, loc, outputVal, result);
2315 const slang::ast::PrimitiveInstanceSymbol &prim) {
2317 auto primName = prim.primitiveType.name;
2319 auto portConns = prim.getPortConnections();
2320 assert(portConns.size() >= 2 &&
2321 "n-output primitives should have at least 2 ports");
2324 SmallVector<Value> outputVals;
2325 outputVals.reserve(portConns.size() - 1);
2326 for (
const auto *outputConn : portConns.subspan(0, portConns.size() - 1)) {
2327 auto &output = outputConn->as<slang::ast::AssignmentExpression>().left();
2331 outputVals.push_back(outputVal);
2339 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2341 ([&] {
return moore::NotOp::create(
builder, loc, inputVal); }))
2343 return moore::BoolCastOp::create(
builder, loc, inputVal);
2346 mlir::emitError(loc)
2347 <<
"unsupported primitive `" << primName <<
"`";
2355 if (prim.getDelay()) {
2356 const slang::ast::Expression *delayExpr;
2357 if (
const auto *delay3 =
2358 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2359 if (delay3->expr2 || delay3->expr3)
2360 return mlir::emitError(loc)
2361 <<
"only n-output primitives that specify a "
2362 "single delay are currently supported.";
2363 delayExpr = &delay3->expr1;
2364 }
else if (
const auto *delay =
2365 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2366 delayExpr = &delay->expr;
2368 llvm_unreachable(
"unexpected delay control type in primitive instance");
2371 *delayExpr, moore::TimeType::get(
getContext()));
2376 for (
auto outputVal : outputVals) {
2377 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2382 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal,
2383 converted, delayVal);
2385 moore::ContinuousAssignOp::create(
builder, loc, outputVal, converted);
2392 const slang::ast::PrimitiveInstanceSymbol &prim) {
2393 auto primName = prim.primitiveType.name;
2398 if (primName ==
"pullup" || primName ==
"pulldown")
2402 mlir::emitError(loc) <<
"unsupported primitive `" << primName <<
"`";
2407 const slang::ast::PrimitiveInstanceSymbol &prim) {
2408 assert((prim.primitiveType.name ==
"pullup" ||
2409 prim.primitiveType.name ==
"pulldown") &&
2410 "expected pullup or pulldown primitive");
2412 assert(!prim.getDelay() &&
2413 "SystemVerilog does not allow pull gate primitives with delays");
2415 auto primName = prim.primitiveType.name;
2417 auto portConns = prim.getPortConnections();
2419 assert(portConns.size() == 1 &&
2420 "pullup/pulldown primitives should have exactly one port");
2423 portConns.front()->as<slang::ast::AssignmentExpression>().left());
2425 auto dstType = cast<moore::RefType>(portVal.getType()).getNestedType();
2426 auto dstTypeWidth = dstType.getBitSize();
2429 "expected fixed-width type for pullup/pulldown primitive");
2430 auto constVal = primName ==
"pullup" ? -1 : 0;
2431 auto c = moore::ConstantOp::create(
2433 moore::IntType::getInt(this->
getContext(), dstTypeWidth.value()),
2439 moore::ContinuousAssignOp::create(
builder, loc, portVal, converted);
2447mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
2448 const slang::ast::Type &ty) {
2449 SmallString<64> name;
2450 SmallVector<llvm::StringRef, 8> parts;
2452 const slang::ast::Scope *scope = ty.getParentScope();
2454 const auto &sym = scope->asSymbol();
2456 case slang::ast::SymbolKind::Root:
2459 case slang::ast::SymbolKind::InstanceBody:
2460 case slang::ast::SymbolKind::Instance:
2461 case slang::ast::SymbolKind::Package:
2462 case slang::ast::SymbolKind::ClassType:
2463 if (!sym.name.empty())
2464 parts.push_back(sym.name);
2469 scope = sym.getParentScope();
2472 for (
auto p :
llvm::reverse(parts)) {
2477 return mlir::StringAttr::get(ctx.
getContext(), name);
2482std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
2484 const slang::ast::ClassType &cls) {
2488 mlir::SymbolRefAttr base;
2489 if (
const auto *b = cls.getBaseClass())
2490 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
2493 SmallVector<mlir::Attribute> impls;
2494 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
2495 impls.reserve(ifaces.size());
2496 for (
const auto *iface : ifaces)
2497 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
2498 fullyQualifiedClassName(
context, *iface)));
2501 mlir::ArrayAttr implArr =
2502 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
2504 return {base, implArr};
2509struct ClassDeclVisitorBase {
2515 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
2519 return context.convertLocation(sloc);
2525struct ClassPropertyVisitor : ClassDeclVisitorBase {
2526 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2529 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2530 if (!classLowering.
op.getBody().empty())
2533 OpBuilder::InsertionGuard ig(builder);
2535 Block *body = &classLowering.
op.getBody().emplaceBlock();
2536 builder.setInsertionPointToEnd(body);
2539 for (
const auto &mem : classAST.members()) {
2540 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
2541 if (failed(prop->visit(*
this)))
2550 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
2552 auto ty =
context.convertType(prop.getType());
2556 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
2557 moore::ClassPropertyDeclOp::create(builder, loc, prop.name, ty);
2565 if (!
context.globalVariables.lookup(&prop))
2566 return context.convertGlobalVariable(prop);
2571 LogicalResult visit(
const slang::ast::ClassType &cls) {
2572 return context.buildClassProperties(cls);
2576 template <
typename T>
2577 LogicalResult visit(T &&) {
2584struct ClassMethodVisitor : ClassDeclVisitorBase {
2585 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2588 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2592 if (classLowering.
op.getBody().empty())
2595 OpBuilder::InsertionGuard ig(builder);
2596 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2599 for (
const auto &mem : classAST.members()) {
2600 if (failed(mem.visit(*
this)))
2609 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2615 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2619 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2625 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2628 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2633 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2638 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2643 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2644 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2645 static bool remarkEmitted =
false;
2649 mlir::emitRemark(classLowering.
op.getLoc())
2650 <<
"Class builtin functions (needed for randomization, constraints, "
2651 "and covergroups) are not yet supported and will be dropped "
2653 remarkEmitted =
true;
2657 const mlir::UnitAttr isVirtual =
2658 (fn.flags & slang::ast::MethodFlags::Virtual)
2659 ? UnitAttr::get(
context.getContext())
2666 if (fn.flags & slang::ast::MethodFlags::Pure) {
2668 SmallVector<Type, 1> extraParams;
2670 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2672 moore::ClassHandleType::get(
context.getContext(), classSym);
2673 extraParams.push_back(handleTy);
2677 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2681 moore::ClassMethodDeclOp::create(builder, loc, fn.name, funcTy,
nullptr);
2685 auto *lowering =
context.declareFunction(fn);
2694 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2696 moore::ClassMethodDeclOp::create(
2697 builder, loc, fn.name, fnTy,
2698 SymbolRefAttr::get(lowering->op.getNameAttr()));
2715 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2716 const auto *externImpl = fn.getSubroutine();
2720 <<
"Didn't find an implementation matching the forward declaration "
2725 return visit(*externImpl);
2729 LogicalResult visit(
const slang::ast::ClassType &cls) {
2730 if (failed(
context.buildClassProperties(cls)))
2732 return context.materializeClassMethods(cls);
2736 template <
typename T>
2737 LogicalResult visit(T &&node) {
2738 Location loc = UnknownLoc::get(
context.getContext());
2739 if constexpr (
requires { node.location; })
2741 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2742 << slang::ast::toString(node.kind);
2750 auto &lowering =
classes[&cls];
2752 return lowering.get();
2753 lowering = std::make_unique<ClassLowering>();
2758 OpBuilder::InsertionGuard g(
builder);
2764 builder.setInsertionPoint(it->second);
2766 auto symName = fullyQualifiedClassName(*
this, cls);
2768 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2770 moore::ClassDeclOp::create(
builder, loc, symName, base, impls);
2772 SymbolTable::setSymbolVisibility(classDeclOp,
2773 SymbolTable::Visibility::Public);
2775 lowering->op = classDeclOp;
2778 return lowering.get();
2785 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2786 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2793 if (classdecl.getBaseClass()) {
2794 if (
const auto *baseClassDecl =
2795 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2806 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2813 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2814 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2817 auto *lowering =
classes[&classdecl].get();
2824 if (classdecl.getBaseClass()) {
2825 if (
const auto *baseClassDecl =
2826 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2832 return ClassMethodVisitor(*
this, *lowering).run(classdecl);
2842 OpBuilder::InsertionGuard g(
builder);
2848 builder.setInsertionPoint(it->second);
2852 SmallString<64> symName;
2856 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2857 if (
const auto *parentScope = classVar->getParentScope()) {
2858 if (
const auto *parentClass =
2859 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2860 symName = fullyQualifiedClassName(*
this, *parentClass);
2862 mlir::emitError(loc)
2863 <<
"Could not access parent class of class property "
2868 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2873 symName += var.name;
2876 symName += var.name;
2885 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2886 cast<moore::UnpackedType>(type));
2897 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 constexpr StringLiteral dpiExportAttrName
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 void recordDPIExportDirectives(Context &context, const slang::ast::Scope &scope, const slang::syntax::SyntaxNode *syntax)
Record export "DPI-C" directives in the given scope so that callable declarations can be tagged with ...
static moore::NetKind convertNetKind(slang::ast::NetType::NetKind kind)
const slang::ast::InstanceBodySymbol * getCanonicalBody(const slang::ast::InstanceSymbol &inst)
Get the slang canonical body for the given instance, if there is one.
CaptureMap analyzeFunctionCaptures(const slang::ast::RootSymbol &root, SmallVectorImpl< AmbiguousHierCapture > &ambiguous)
Analyze the AST rooted at root to determine which variables each function captures: symbols reference...
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, List[str] 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.
const slang::ast::DefinitionSymbol * currentDefinition
The definition symbol of the module body currently being converted.
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.
DenseSet< const slang::ast::InstanceSymbol * > predeclaredInstances
Module instances already emitted by the predeclaration pass.
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
DenseMap< const slang::ast::SubroutineSymbol *, std::string > dpiExportCNames
DPI-C export directives keyed by the SystemVerilog subroutine they expose.
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.
FunctionLowering * currentFunctionLowering
The function currently being converted, if any.
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.