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()))
583 if (port->direction == ArgumentDirection::InOut) {
584 auto portType = moore::RefType::get(
585 cast<moore::UnpackedType>(
context.convertType(port->getType())));
586 if (value.getType() != portType)
587 return mlir::emitError(loc)
588 <<
"inout port `" << port->name <<
"` expects " << portType
589 <<
" but is connected to " << value.getType();
592 portValues.insert({port, value});
599 if (
const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
601 auto value =
context.convertLvalueExpression(*expr);
605 for (
const auto *port :
llvm::reverse(multiPort->ports)) {
606 if (
auto *existingPort = moduleLowering->portsBySyntaxNode.lookup(
607 con->port.getSyntax()))
609 unsigned width = port->getType().getBitWidth();
610 auto sliceType =
context.convertType(port->getType());
613 Value slice = moore::ExtractRefOp::create(
615 moore::RefType::get(cast<moore::UnpackedType>(sliceType)), value,
618 if (port->direction == ArgumentDirection::In)
619 slice = moore::ReadOp::create(builder, loc, slice);
620 portValues.insert({port, slice});
628 if (
const auto *ifacePort =
629 con->port.as_if<slang::ast::InterfacePortSymbol>()) {
630 auto ifaceConn = con->getIfaceConn();
631 const auto *connInst =
632 ifaceConn.first->as_if<slang::ast::InstanceSymbol>();
634 ifaceConnMap[ifacePort] = connInst;
638 mlir::emitError(loc) <<
"unsupported instance port `" << con->port.name
639 <<
"` (" << slang::ast::toString(con->port.kind)
647 SmallVector<Value> inputValues(moduleLowering->numExplicitInputs);
648 SmallVector<Value> outputValues(moduleLowering->numExplicitOutputs);
650 for (
auto &port : moduleLowering->ports) {
651 auto value = portValues.lookup(&port.ast);
652 if (port.ast.direction == ArgumentDirection::Out)
653 outputValues[*port.outputIdx] = value;
655 inputValues[*port.inputIdx] = value;
661 for (
auto &fp : moduleLowering->ifacePorts) {
662 if (!fp.bodySym || !fp.origin)
665 auto it = ifaceConnMap.find(fp.origin);
666 if (it == ifaceConnMap.end()) {
668 <<
"no interface connection for port `" << fp.name <<
"`";
671 const auto *connInst = it->second;
673 auto *ifaceLowering =
context.interfaceInstances.lookup(connInst);
674 if (!ifaceLowering) {
676 <<
"interface instance `" << connInst->name <<
"` was not expanded";
680 auto valIt = ifaceLowering->expandedMembers.find(fp.bodySym);
681 if (valIt == ifaceLowering->expandedMembers.end()) {
683 <<
"unresolved interface port signal `" << fp.name <<
"`";
686 Value val = valIt->second;
688 outputValues[*fp.outputIdx] = val;
692 if (isa<moore::RefType>(val.getType()) && !isa<moore::RefType>(fp.type))
693 val = moore::ReadOp::create(builder, loc, val);
694 inputValues[*fp.inputIdx] = val;
700 for (
auto [value, type] :
701 llvm::zip(inputValues, moduleType.getInputTypes())) {
705 value =
context.materializeConversion(type, value,
false, value.getLoc());
707 return mlir::emitError(loc) <<
"unsupported port";
714 for (
const auto &hierPath :
context.hierPaths[body]) {
715 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
716 if (!hierPath.hierName || hierPath.direction != ArgumentDirection::In)
721 for (
auto &alias : hierPath.valueSyms)
722 if ((hierValue =
context.valueSymbols.lookup(alias.first)))
724 inputValues.push_back(hierValue);
728 for (
auto value : inputValues)
730 return
mlir::emitError(loc) <<
"unsupported port";
738 SmallString<64> instName(blockNamePrefix);
739 if (instNode.arrayPath.empty()) {
740 instName += instNode.name;
742 instName += instNode.getArrayName();
743 slang::SmallVector<slang::ConstantRange, 4> dims;
744 instNode.getArrayDimensions(dims);
745 for (
auto [dim, index] :
llvm::zip(dims, instNode.arrayPath)) {
747 Twine(dim.lower() + int32_t(index)).toVector(instName);
752 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
753 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
754 auto inst = moore::InstanceOp::create(
755 builder, loc, moduleType.getOutputTypes(),
756 builder.getStringAttr(instName),
757 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
758 inputNames, outputNames);
762 auto aliasReachedThroughInstance =
763 [&](
const slang::ast::InstanceBodySymbol *aliasBody) {
764 for (
auto *b = aliasBody; b && b->parentInstance;
765 b = b->parentInstance->getParentScope()->getContainingInstance())
766 if (b->parentInstance == &instNode)
776 for (
const auto &hierPath :
context.hierPaths[body])
777 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out) {
778 auto result = inst->getResult(*hierPath.idx);
779 for (
auto &alias : hierPath.valueSyms)
780 if (aliasReachedThroughInstance(alias.second))
781 context.valueSymbols.insert(alias.first, result);
782 context.hierValueSymbols[{&instNode, hierPath.hierName}] = result;
786 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
789 Value rvalue = output;
790 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
792 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
795 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
802 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
803 auto ref =
context.valueSymbols.lookup(&varNode);
805 return mlir::emitError(loc)
806 <<
"internal error: missing predeclared variable `" << varNode.name
809 auto varOp = ref.getDefiningOp<moore::VariableOp>();
811 return mlir::emitError(loc)
812 <<
"internal error: predeclared variable `" << varNode.name
813 <<
"` is not a moore.variable";
815 if (
const auto *init = varNode.getInitializer()) {
816 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
817 auto initial =
context.convertRvalueExpression(*init, loweredType);
820 varOp.getInitialMutable().assign(initial);
827 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
828 auto ref =
context.valueSymbols.lookup(&netNode);
830 return mlir::emitError(loc) <<
"internal error: missing predeclared net `"
831 << netNode.name <<
"`";
833 auto netOp = ref.getDefiningOp<moore::NetOp>();
835 return mlir::emitError(loc) <<
"internal error: predeclared net `"
836 << netNode.name <<
"` is not a moore.net";
838 if (
const auto *init = netNode.getInitializer()) {
839 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
840 auto assignment =
context.convertRvalueExpression(*init, loweredType);
843 netOp.getAssignmentMutable().assign(assignment);
849 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
851 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
852 auto lhs =
context.convertLvalueExpression(expr.left());
856 auto rhs =
context.convertRvalueExpression(
857 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
862 if (
auto *timingCtrl = assignNode.getDelay()) {
863 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
864 auto delay =
context.convertRvalueExpression(
865 ctrl->expr, moore::TimeType::get(builder.getContext()));
868 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
871 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
876 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
881 LogicalResult convertProcedure(moore::ProcedureKind kind,
882 const slang::ast::Statement &body) {
883 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
884 return context.convertStatement(body);
885 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
886 OpBuilder::InsertionGuard guard(builder);
887 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
888 Context::ValueSymbolScope scope(
context.valueSymbols);
889 Context::VirtualInterfaceMemberScope vifMemberScope(
891 if (failed(
context.convertStatement(body)))
893 if (builder.getBlock())
894 moore::ReturnOp::create(builder, loc);
898 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
901 if (
context.options.lowerAlwaysAtStarAsComb) {
902 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
903 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
905 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
906 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
914 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
916 if (genNode.isUninstantiated)
920 SmallString<64> prefix = blockNamePrefix;
921 if (!genNode.name.empty() ||
922 genNode.getParentScope()->asSymbol().kind !=
923 slang::ast::SymbolKind::GenerateBlockArray) {
924 prefix += genNode.getExternalName();
929 for (
auto &member : genNode.members())
930 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
936 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
939 SmallString<64> prefix = blockNamePrefix;
940 prefix += genArrNode.getExternalName();
942 auto prefixBaseLen = prefix.size();
945 for (
const auto *entry : genArrNode.entries) {
947 prefix.resize(prefixBaseLen);
948 if (entry->arrayIndex)
949 prefix += entry->arrayIndex->toString();
951 Twine(entry->constructIndex).toVector(prefix);
955 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
967 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
973 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
979 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
985 LogicalResult visit(
const slang::ast::ClockingBlockSymbol &) {
991 LogicalResult visit(
const slang::ast::LetDeclSymbol &) {
return success(); }
994 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
995 if (!
context.declareFunction(subroutine))
1001 LogicalResult visit(
const slang::ast::PrimitiveInstanceSymbol &prim) {
1002 return context.convertPrimitiveInstance(prim);
1006 LogicalResult visit(
const slang::ast::InstanceArraySymbol &arrNode) {
1008 for (
const auto *element : arrNode.elements)
1009 if (failed(element->visit(*this)))
1015 template <
typename T>
1016 LogicalResult visit(T &&node) {
1017 mlir::emitError(loc,
"unsupported module member: ")
1018 << slang::ast::toString(node.kind);
1023struct ModulePredeclaration {
1027 ModulePredeclaration(
Context &context)
1028 : context(context), builder(context.builder) {}
1030 LogicalResult declareVariable(
const slang::ast::VariableSymbol &varNode,
1031 Location loc, StringRef blockNamePrefix) {
1032 auto loweredType = context.
convertType(*varNode.getDeclaredType());
1036 auto varOp = moore::VariableOp::create(
1038 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
1039 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), Value{});
1042 const auto &canonTy = varNode.getType().getCanonicalType();
1043 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
1050 LogicalResult declareNet(
const slang::ast::NetSymbol &netNode, Location loc,
1051 StringRef blockNamePrefix) {
1052 auto loweredType = context.
convertType(*netNode.getDeclaredType());
1057 if (netkind == moore::NetKind::Interconnect ||
1058 netkind == moore::NetKind::UserDefined ||
1059 netkind == moore::NetKind::Unknown)
1060 return mlir::emitError(loc,
"unsupported net kind `")
1061 << netNode.netType.name <<
"`";
1063 auto netOp = moore::NetOp::create(
1065 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
1066 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
1073 getGenerateBlockPrefix(
const slang::ast::GenerateBlockSymbol &genNode,
1074 StringRef blockNamePrefix) {
1075 SmallString<64> prefix = blockNamePrefix;
1076 if (!genNode.name.empty() ||
1077 genNode.getParentScope()->asSymbol().kind !=
1078 slang::ast::SymbolKind::GenerateBlockArray) {
1079 prefix += genNode.getExternalName();
1086 predeclareStorageGenerateBlock(
const slang::ast::GenerateBlockSymbol &genNode,
1087 StringRef blockNamePrefix) {
1088 if (genNode.isUninstantiated)
1090 return predeclareStorageScope(
1091 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1094 LogicalResult predeclareInterfaceGenerateBlock(
1095 const slang::ast::GenerateBlockSymbol &genNode,
1096 StringRef blockNamePrefix) {
1097 if (genNode.isUninstantiated)
1099 return predeclareInterfaceScope(
1100 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1103 LogicalResult predeclareModuleInstanceGenerateBlock(
1104 const slang::ast::GenerateBlockSymbol &genNode,
1105 StringRef blockNamePrefix) {
1106 if (genNode.isUninstantiated)
1108 return predeclareModuleInstanceScope(
1109 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1112 LogicalResult predeclareGenerateBlockArray(
1113 const slang::ast::GenerateBlockArraySymbol &genArrNode,
1114 StringRef blockNamePrefix,
1115 llvm::function_ref<LogicalResult(
const slang::ast::GenerateBlockSymbol &,
1118 SmallString<64> prefix = blockNamePrefix;
1119 prefix += genArrNode.getExternalName();
1121 auto prefixBaseLen = prefix.size();
1123 for (
const auto *entry : genArrNode.entries) {
1124 prefix.resize(prefixBaseLen);
1125 if (entry->arrayIndex)
1126 prefix += entry->arrayIndex->toString();
1128 Twine(entry->constructIndex).toVector(prefix);
1131 if (failed(predeclareBlock(*entry, prefix)))
1137 LogicalResult predeclareStorageMember(
const slang::ast::Symbol &member,
1138 StringRef blockNamePrefix) {
1140 if (
const auto *varNode = member.as_if<slang::ast::VariableSymbol>())
1141 return declareVariable(*varNode, loc, blockNamePrefix);
1143 if (
const auto *netNode = member.as_if<slang::ast::NetSymbol>())
1144 return declareNet(*netNode, loc, blockNamePrefix);
1146 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1147 return predeclareStorageGenerateBlock(*genNode, blockNamePrefix);
1149 if (
const auto *genArrNode =
1150 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1151 return predeclareGenerateBlockArray(
1152 *genArrNode, blockNamePrefix,
1153 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1154 return predeclareStorageGenerateBlock(gen, prefix);
1160 LogicalResult predeclareInterfaceMember(
const slang::ast::Symbol &member,
1161 StringRef blockNamePrefix) {
1163 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1164 if (instNode->body.getDefinition().definitionKind ==
1165 slang::ast::DefinitionKind::Interface)
1166 return ModuleVisitor(context, loc, blockNamePrefix)
1167 .expandInterfaceInstance(*instNode);
1171 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1172 return predeclareInterfaceGenerateBlock(*genNode, blockNamePrefix);
1174 if (
const auto *genArrNode =
1175 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1176 return predeclareGenerateBlockArray(
1177 *genArrNode, blockNamePrefix,
1178 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1179 return predeclareInterfaceGenerateBlock(gen, prefix);
1185 LogicalResult predeclareModuleInstanceMember(
const slang::ast::Symbol &member,
1186 StringRef blockNamePrefix) {
1188 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1189 if (instNode->body.getDefinition().definitionKind !=
1190 slang::ast::DefinitionKind::Interface) {
1192 ModuleVisitor(context, loc, blockNamePrefix).visit(*instNode)))
1199 if (
const auto *arrNode = member.as_if<slang::ast::InstanceArraySymbol>()) {
1200 for (
const auto *element : arrNode->elements)
1201 if (failed(predeclareModuleInstanceMember(*element, blockNamePrefix)))
1206 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1207 return predeclareModuleInstanceGenerateBlock(*genNode, blockNamePrefix);
1209 if (
const auto *genArrNode =
1210 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1211 return predeclareGenerateBlockArray(
1212 *genArrNode, blockNamePrefix,
1213 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1214 return predeclareModuleInstanceGenerateBlock(gen, prefix);
1220 LogicalResult predeclareStorageScope(
const slang::ast::Scope &scope,
1221 StringRef blockNamePrefix) {
1222 for (
auto &member : scope.members())
1223 if (failed(predeclareStorageMember(member, blockNamePrefix)))
1228 LogicalResult predeclareInterfaceScope(
const slang::ast::Scope &scope,
1229 StringRef blockNamePrefix) {
1230 for (
auto &member : scope.members())
1231 if (failed(predeclareInterfaceMember(member, blockNamePrefix)))
1236 LogicalResult predeclareModuleInstanceScope(
const slang::ast::Scope &scope,
1237 StringRef blockNamePrefix) {
1238 for (
auto &member : scope.members())
1239 if (failed(predeclareModuleInstanceMember(member, blockNamePrefix)))
1244 LogicalResult predeclareScope(
const slang::ast::Scope &scope,
1245 StringRef blockNamePrefix) {
1249 if (failed(predeclareStorageScope(scope, blockNamePrefix)))
1255 if (failed(predeclareInterfaceScope(scope, blockNamePrefix)))
1260 return predeclareModuleInstanceScope(scope, blockNamePrefix);
1271LogicalResult Context::convertCompilation() {
1277 timeScale = root.getTimeScale().value_or(slang::TimeScale());
1278 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1282 SmallVector<AmbiguousHierCapture> ambiguousHierCaptures;
1284 for (
auto &ambiguous : ambiguousHierCaptures) {
1285 auto d = mlir::emitError(
convertLocation(ambiguous.function->location))
1286 <<
"hierarchical reference to `" << ambiguous.symbol->name
1287 <<
"` is ambiguous: this function reaches it through more than "
1288 "one instance of the same module, which is not yet supported";
1290 <<
"symbol declared here";
1292 if (!ambiguousHierCaptures.empty())
1297 for (
auto *inst : root.topInstances)
1307 for (
auto *unit : root.compilationUnits) {
1309 for (
const auto &member : unit->members()) {
1311 if (failed(member.visit(RootVisitor(*
this, loc))))
1319 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
1320 for (
auto *inst : root.topInstances) {
1322 if (body->getDefinition().definitionKind !=
1323 slang::ast::DefinitionKind::Interface)
1330 auto *
module = moduleWorklist.front();
1338 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
1339 classMethodWorklist.reserve(
classes.size());
1341 classMethodWorklist.push_back(kv.first);
1343 for (
auto *inst : classMethodWorklist) {
1362 auto &block = varOp.getInitRegion().emplaceBlock();
1363 OpBuilder::InsertionGuard guard(
builder);
1364 builder.setInsertionPointToEnd(&block);
1369 moore::YieldOp::create(
builder, varOp.getLoc(), value);
1378 using slang::ast::ArgumentDirection;
1379 using slang::ast::MultiPortSymbol;
1380 using slang::ast::ParameterSymbol;
1381 using slang::ast::PortSymbol;
1382 using slang::ast::TypeParameterSymbol;
1387 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1388 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1395 slot = std::make_unique<ModuleLowering>();
1396 auto &lowering = *slot;
1399 OpBuilder::InsertionGuard g(
builder);
1404 auto kind =
module->getDefinition().definitionKind;
1405 if (kind != slang::ast::DefinitionKind::Module &&
1406 kind != slang::ast::DefinitionKind::Program) {
1407 mlir::emitError(loc) <<
"unsupported definition: "
1408 <<
module->getDefinition().getKindString();
1413 auto block = std::make_unique<Block>();
1414 SmallVector<hw::ModulePort> modulePorts;
1417 unsigned int outputIdx = 0, inputIdx = 0;
1418 for (
auto *symbol :
module->getPortList()) {
1419 auto handlePort = [&](const PortSymbol &port) {
1420 auto portLoc = convertLocation(port.location);
1424 auto portName =
builder.getStringAttr(port.name);
1426 std::optional<unsigned> portOutputIdx;
1427 std::optional<unsigned> portInputIdx;
1428 if (port.direction == ArgumentDirection::Out) {
1430 portOutputIdx = outputIdx++;
1434 if (port.direction != ArgumentDirection::In)
1435 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1437 arg = block->addArgument(type, portLoc);
1438 portInputIdx = inputIdx++;
1440 lowering.ports.push_back(
1441 {port, portLoc, arg, portOutputIdx, portInputIdx});
1448 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1451 auto [connSym, modportSym] = ifacePort.getConnection();
1452 const auto *ifaceInst =
1453 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1454 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1458 for (
const auto &member : modportSym->members()) {
1459 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1466 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1469 std::optional<unsigned> ifaceOutputIdx;
1470 std::optional<unsigned> ifaceInputIdx;
1471 if (mpp->direction == ArgumentDirection::Out) {
1473 modulePorts.push_back({name, type, dir});
1474 ifaceOutputIdx = outputIdx++;
1477 if (mpp->direction != ArgumentDirection::In)
1478 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1479 modulePorts.push_back({name, type, dir});
1480 arg = block->addArgument(type, portLoc);
1481 ifaceInputIdx = inputIdx++;
1483 lowering.ifacePorts.push_back(
1484 {name, dir, type, portLoc, arg, &ifacePort, mpp->internalSymbol,
1485 ifaceInst, mpp, ifaceOutputIdx, ifaceInputIdx});
1490 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1492 mlir::emitError(portLoc)
1493 <<
"unsupported interface port connection for `" << ifacePort.name
1497 for (
const auto &member : instSym->body.members()) {
1498 const slang::ast::Type *slangType =
nullptr;
1499 const slang::ast::Symbol *bodySym =
nullptr;
1500 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1501 slangType = &var->getType();
1503 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1504 slangType = &net->getType();
1512 auto name = builder.getStringAttr(Twine(portPrefix) +
1513 StringRef(bodySym->name));
1514 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1516 auto arg = block->addArgument(refType, portLoc);
1517 lowering.ifacePorts.push_back(
1519 bodySym, instSym,
nullptr, std::nullopt, inputIdx++});
1525 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1526 if (failed(handlePort(*port)))
1528 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1529 for (
auto *port : multiPort->ports)
1530 if (failed(handlePort(*port)))
1532 }
else if (
const auto *ifacePort =
1533 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1534 if (failed(handleIfacePort(*ifacePort)))
1538 <<
"unsupported module port `" << symbol->name <<
"` ("
1539 << slang::ast::toString(symbol->kind) <<
")";
1545 lowering.numExplicitOutputs = outputIdx;
1546 lowering.numExplicitInputs = inputIdx;
1549 for (
auto &hierPath : hierPaths[module]) {
1550 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1551 auto hierType =
convertType(hierPath.valueSyms.front().first->getType());
1555 if (
auto hierName = hierPath.hierName) {
1557 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1558 if (hierPath.direction == ArgumentDirection::Out) {
1559 hierPath.idx = outputIdx++;
1562 hierPath.idx = inputIdx++;
1566 block->addArgument(hierType, hierLoc);
1570 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1575 auto it = orderedRootOps.upper_bound(key);
1576 if (it == orderedRootOps.end())
1577 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1579 builder.setInsertionPoint(it->second);
1583 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1584 orderedRootOps.insert(it, {key, moduleOp});
1585 moduleOp.getBodyRegion().push_back(block.release());
1586 lowering.op = moduleOp;
1590 symbolTable.insert(moduleOp);
1593 moduleWorklist.push(module);
1596 for (
const auto &port : lowering.ports)
1597 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1604 auto &lowering = *
modules[module];
1607 llvm::scope_exit currentDefinitionGuard(
1611 OpBuilder::InsertionGuard g(
builder);
1612 builder.setInsertionPointToEnd(lowering.op.getBody());
1621 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1622 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1627 for (
auto &hierPath :
hierPaths[module])
1628 if (hierPath.direction == slang::ast::ArgumentDirection::In &&
1630 auto arg = lowering.op.getBody()->getArgument(*hierPath.idx);
1631 for (
auto &alias : hierPath.valueSyms)
1639 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1642 auto getIfacePortLowering =
1648 if (
auto it = ifacePortLowerings.find(ifaceInst);
1649 it != ifacePortLowerings.end())
1652 auto lowering = std::make_unique<InterfaceLowering>();
1656 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1660 for (
auto &fp : lowering.ifacePorts) {
1663 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1672 portValue = moore::VariableOp::create(
1674 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1683 if (fp.modportPortSym)
1684 if (
auto *mppSym = fp.modportPortSym->as_if<slang::ast::ValueSymbol>())
1685 if (mppSym != valueSym)
1688 if (!fp.ifaceInstance)
1691 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1694 ifaceLowering->expandedMembers[fp.bodySym] = val;
1696 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1702 llvm::scope_exit predeclaredInstancesGuard(
1712 if (failed(ModulePredeclaration(*this).predeclareScope(*module,
"")))
1716 for (
auto &member :
module->members()) {
1717 auto loc = convertLocation(member.location);
1718 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1730 SmallVector<Value> outputs(lowering.numExplicitOutputs);
1731 for (
auto &port : lowering.ports) {
1733 if (
auto *expr = port.ast.getInternalExpr()) {
1734 value = convertLvalueExpression(*expr);
1735 }
else if (port.ast.internalSymbol) {
1736 if (
const auto *sym =
1737 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1738 value = valueSymbols.lookup(sym);
1741 return mlir::emitError(port.loc,
"unsupported port: `")
1743 <<
"` does not map to an internal symbol or expression";
1746 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1747 if (isa<moore::RefType>(value.getType()))
1748 value = moore::ReadOp::create(builder, value.getLoc(), value);
1749 outputs[*port.outputIdx] = value;
1755 Value portArg = port.arg;
1756 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1757 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1758 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1763 for (
auto &fp : lowering.ifacePorts) {
1767 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1770 Value ref = valueSymbols.lookup(valueSym);
1773 outputs[*fp.outputIdx] =
1774 moore::ReadOp::create(builder, fp.loc, ref).getResult();
1779 for (
auto &hierPath : hierPaths[module]) {
1780 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1781 if (hierPath.direction != slang::ast::ArgumentDirection::Out)
1785 for (
auto &alias : hierPath.valueSyms)
1786 if ((hierValue = valueSymbols.lookup(alias.first)))
1791 auto name = hierPath.hierName.getValue();
1792 if (
auto dot = name.find(
"."); dot != llvm::StringRef::npos) {
1793 auto innerName = builder.getStringAttr(name.drop_front(dot + 1));
1794 for (
auto &member : module->members())
1795 if (auto *inst = member.as_if<
slang::ast::InstanceSymbol>())
1796 if (
llvm::StringRef(inst->name.
data(), inst->name.size()) ==
1797 name.take_front(dot)) {
1798 hierValue = hierValueSymbols.lookup({inst, innerName});
1801 }
else if (
auto *sym =
1802 module->find(std::string_view(name.data(), name.size()))) {
1804 if (
auto *valueSym = sym->as_if<slang::ast::ValueSymbol>())
1805 hierValue = valueSymbols.lookup(valueSym);
1809 return mlir::emitError(lowering.op.getLoc())
1810 <<
"unable to resolve hierarchical output `"
1811 << hierPath.hierName.getValue() <<
"` in module `" <<
module->name
1813 outputs.push_back(hierValue);
1816 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1826 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1827 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1831 OpBuilder::InsertionGuard g(
builder);
1834 for (
auto &member : package.members()) {
1836 if (failed(member.visit(PackageVisitor(*
this, loc))))
1847 auto &lowering =
functions[&subroutine];
1849 if (!lowering->op.getOperation())
1851 return lowering.get();
1854 if (!subroutine.thisVar) {
1856 SmallString<64> name;
1858 name += subroutine.name;
1860 SmallVector<Type, 1> noThis = {};
1867 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1868 moore::ClassDeclOp ownerDecl;
1870 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1871 auto &ownerLowering =
classes[classTy];
1872 ownerDecl = ownerLowering->op;
1874 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1875 << thisTy.toString();
1880 SmallString<64> qualName;
1881 qualName += ownerDecl.getSymName();
1883 qualName += subroutine.name;
1886 SmallVector<Type, 1> extraParams;
1888 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1889 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1890 extraParams.push_back(handleTy);
1900 Context &
context,
const slang::ast::SubroutineSymbol &subroutine,
1901 ArrayRef<Type> prefixParams, ArrayRef<Type> suffixParams = {}) {
1902 using slang::ast::ArgumentDirection;
1904 SmallVector<Type> inputTypes;
1905 inputTypes.append(prefixParams.begin(), prefixParams.end());
1906 SmallVector<Type, 1> outputTypes;
1908 for (
const auto *arg : subroutine.getArguments()) {
1909 auto type =
context.convertType(arg->getType());
1912 if (arg->direction == ArgumentDirection::In) {
1913 inputTypes.push_back(type);
1915 inputTypes.push_back(
1916 moore::RefType::get(cast<moore::UnpackedType>(type)));
1920 inputTypes.append(suffixParams.begin(), suffixParams.end());
1922 const auto &returnType = subroutine.getReturnType();
1923 if (!returnType.isVoid()) {
1924 auto type =
context.convertType(returnType);
1927 outputTypes.push_back(type);
1930 return FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1933static FailureOr<SmallVector<moore::DPIArgInfo>>
1935 const slang::ast::SubroutineSymbol &subroutine) {
1936 using slang::ast::ArgumentDirection;
1938 SmallVector<moore::DPIArgInfo> args;
1939 args.reserve(subroutine.getArguments().size() +
1940 (!subroutine.getReturnType().isVoid() ? 1 : 0));
1942 for (
const auto *arg : subroutine.getArguments()) {
1943 auto type =
context.convertType(arg->getType());
1946 moore::DPIArgDirection dir;
1947 switch (arg->direction) {
1948 case ArgumentDirection::In:
1949 dir = moore::DPIArgDirection::In;
1951 case ArgumentDirection::Out:
1952 dir = moore::DPIArgDirection::Out;
1954 case ArgumentDirection::InOut:
1955 dir = moore::DPIArgDirection::InOut;
1957 case ArgumentDirection::Ref:
1958 llvm_unreachable(
"'ref' is not legal for DPI functions");
1961 {StringAttr::get(
context.getContext(), arg->name), type, dir});
1964 if (!subroutine.getReturnType().isVoid()) {
1965 auto type =
context.convertType(subroutine.getReturnType());
1968 args.push_back({StringAttr::get(
context.getContext(),
"return"), type,
1969 moore::DPIArgDirection::Return});
1979 mlir::StringRef qualifiedName,
1980 llvm::SmallVectorImpl<Type> &extraParams) {
1984 OpBuilder::InsertionGuard g(
builder);
1990 builder.setInsertionPoint(it->second);
1995 SmallVector<Type> captureTypes;
1998 for (
auto *sym : capturesIt->second) {
2002 captureTypes.push_back(
2003 moore::RefType::get(cast<moore::UnpackedType>(type)));
2012 std::unique_ptr<FunctionLowering> lowering;
2013 Operation *insertedOp =
nullptr;
2018 auto setVisibilityAndExportAttr = [&](Operation *op) {
2021 builder.getStringAttr(dpiExportIt->second));
2022 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Public);
2025 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
2027 if (!subroutine.thisVar &&
2028 subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
2034 auto dpiOp = moore::DPIFuncOp::create(
2037 StringAttr::get(
getContext(), subroutine.name));
2038 setVisibilityAndExportAttr(dpiOp);
2039 lowering = std::make_unique<FunctionLowering>(dpiOp);
2041 }
else if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
2043 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
2044 setVisibilityAndExportAttr(op);
2045 lowering = std::make_unique<FunctionLowering>(op);
2050 mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
2051 setVisibilityAndExportAttr(funcOp);
2052 lowering = std::make_unique<FunctionLowering>(funcOp);
2053 insertedOp = funcOp;
2059 lowering->capturedSymbols.assign(capturesIt->second.begin(),
2060 capturesIt->second.end());
2065 functions[&subroutine] = std::move(lowering);
2079 auto *lowering =
functions.at(&subroutine).get();
2084 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
2085 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2090 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport))
2093 const bool isMethod = (subroutine.thisVar !=
nullptr);
2098 if (
const auto *classTy =
2099 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
2100 for (
auto &member : classTy->members()) {
2101 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
2104 const auto &propCanon = prop->getType().getCanonicalType();
2105 if (
const auto *vi =
2106 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
2116 SmallVector<moore::VariableOp> argVariables;
2117 auto &block = lowering->op.getFunctionBody().emplaceBlock();
2124 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
2125 auto thisArg = block.addArgument(thisType, thisLoc);
2133 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
2134 auto astArgs = subroutine.getArguments();
2135 unsigned prefixCount = isMethod ? 1 : 0;
2136 auto valInputs = llvm::ArrayRef<Type>(inputs)
2137 .drop_front(prefixCount)
2138 .take_front(astArgs.size());
2140 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
2142 auto blockArg = block.addArgument(type, loc);
2144 if (isa<moore::RefType>(type)) {
2147 OpBuilder::InsertionGuard g(
builder);
2148 builder.setInsertionPointToEnd(&block);
2150 auto shadowArg = moore::VariableOp::create(
2151 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
2152 StringAttr{}, blockArg);
2154 argVariables.push_back(shadowArg);
2157 const auto &argCanon = astArg->getType().getCanonicalType();
2158 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
2164 OpBuilder::InsertionGuard g(
builder);
2165 builder.setInsertionPointToEnd(&block);
2168 if (subroutine.returnValVar) {
2169 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
2172 returnVar = moore::VariableOp::create(
2173 builder, lowering->op->getLoc(),
2174 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
2176 valueSymbols.insert(subroutine.returnValVar, returnVar);
2184 for (
auto *sym : lowering->capturedSymbols) {
2188 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
2190 auto blockArg = block.addArgument(refType, loc);
2196 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
2200 llvm::scope_exit restoreFunctionLowering(
2209 if (isa<moore::CoroutineOp>(lowering->op.getOperation())) {
2210 moore::ReturnOp::create(
builder, lowering->op->getLoc());
2211 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
2213 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
2214 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(), read);
2216 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(),
2220 if (returnVar && returnVar.use_empty())
2221 returnVar.getDefiningOp()->erase();
2223 for (
auto var : argVariables) {
2224 if (llvm::all_of(var->getUsers(),
2225 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
2226 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
2227 user->getResult(0).replaceAllUsesWith(var.getInitial());
2239 const slang::ast::PrimitiveInstanceSymbol &prim) {
2240 if (prim.getDriveStrength().first.has_value() ||
2241 prim.getDriveStrength().second.has_value())
2243 <<
"primitive instances with explicit drive strengths are not "
2246 switch (prim.primitiveType.primitiveKind) {
2247 case slang::ast::PrimitiveSymbol::PrimitiveKind::NInput:
2250 case slang::ast::PrimitiveSymbol::PrimitiveKind::NOutput:
2253 case slang::ast::PrimitiveSymbol::PrimitiveKind::Fixed:
2258 <<
"unsupported instance of primitive `" << prim.primitiveType.name
2264 const slang::ast::PrimitiveInstanceSymbol &prim) {
2266 auto primName = prim.primitiveType.name;
2268 auto portConns = prim.getPortConnections();
2269 assert(portConns.size() >= 2 &&
2270 "n-input primitives should have at least 2 ports");
2274 portConns[0]->as<slang::ast::AssignmentExpression>().left();
2280 SmallVector<Value> inputVals;
2281 inputVals.reserve(portConns.size() - 1);
2282 for (
const auto *inputConn : portConns.subspan(1, portConns.size() - 1)) {
2286 inputVals.push_back(inputVal);
2289 Value nextInput = inputVals.front();
2291 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2293 for (Value inputVal : llvm::drop_begin(inputVals))
2295 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2299 for (Value inputVal : llvm::drop_begin(inputVals))
2301 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2305 for (Value inputVal : llvm::drop_begin(inputVals))
2307 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2310 .Case(
"nand", ([&] {
2311 for (Value inputVal : llvm::drop_begin(inputVals))
2313 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2314 return moore::NotOp::create(
builder, loc, nextInput);
2317 for (Value inputVal : llvm::drop_begin(inputVals))
2319 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2320 return moore::NotOp::create(
builder, loc, nextInput);
2322 .Case(
"xnor", ([&] {
2323 for (Value inputVal : llvm::drop_begin(inputVals))
2325 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2326 return moore::NotOp::create(
builder, loc, nextInput);
2329 mlir::emitError(loc)
2330 <<
"unsupported primitive `" << primName <<
"`";
2337 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2342 if (prim.getDelay()) {
2343 const slang::ast::Expression *delayExpr;
2344 if (
const auto *delay3 =
2345 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2346 if (delay3->expr2 || delay3->expr3)
2347 return mlir::emitError(loc) <<
"only n-input primitives that specify a "
2348 "single delay are currently supported.";
2349 delayExpr = &delay3->expr1;
2350 }
else if (
const auto *delay =
2351 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2352 delayExpr = &delay->expr;
2354 llvm_unreachable(
"unexpected delay control type in primitive instance");
2357 *delayExpr, moore::TimeType::get(
getContext()));
2360 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal, result,
2363 moore::ContinuousAssignOp::create(
builder, loc, outputVal, result);
2370 const slang::ast::PrimitiveInstanceSymbol &prim) {
2372 auto primName = prim.primitiveType.name;
2374 auto portConns = prim.getPortConnections();
2375 assert(portConns.size() >= 2 &&
2376 "n-output primitives should have at least 2 ports");
2379 SmallVector<Value> outputVals;
2380 outputVals.reserve(portConns.size() - 1);
2381 for (
const auto *outputConn : portConns.subspan(0, portConns.size() - 1)) {
2382 auto &output = outputConn->as<slang::ast::AssignmentExpression>().left();
2386 outputVals.push_back(outputVal);
2394 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2396 ([&] {
return moore::NotOp::create(
builder, loc, inputVal); }))
2398 return moore::BoolCastOp::create(
builder, loc, inputVal);
2401 mlir::emitError(loc)
2402 <<
"unsupported primitive `" << primName <<
"`";
2410 if (prim.getDelay()) {
2411 const slang::ast::Expression *delayExpr;
2412 if (
const auto *delay3 =
2413 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2414 if (delay3->expr2 || delay3->expr3)
2415 return mlir::emitError(loc)
2416 <<
"only n-output primitives that specify a "
2417 "single delay are currently supported.";
2418 delayExpr = &delay3->expr1;
2419 }
else if (
const auto *delay =
2420 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2421 delayExpr = &delay->expr;
2423 llvm_unreachable(
"unexpected delay control type in primitive instance");
2426 *delayExpr, moore::TimeType::get(
getContext()));
2431 for (
auto outputVal : outputVals) {
2432 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2437 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal,
2438 converted, delayVal);
2440 moore::ContinuousAssignOp::create(
builder, loc, outputVal, converted);
2447 const slang::ast::PrimitiveInstanceSymbol &prim) {
2448 auto primName = prim.primitiveType.name;
2453 if (primName ==
"pullup" || primName ==
"pulldown")
2457 mlir::emitError(loc) <<
"unsupported primitive `" << primName <<
"`";
2462 const slang::ast::PrimitiveInstanceSymbol &prim) {
2463 assert((prim.primitiveType.name ==
"pullup" ||
2464 prim.primitiveType.name ==
"pulldown") &&
2465 "expected pullup or pulldown primitive");
2467 assert(!prim.getDelay() &&
2468 "SystemVerilog does not allow pull gate primitives with delays");
2470 auto primName = prim.primitiveType.name;
2472 auto portConns = prim.getPortConnections();
2474 assert(portConns.size() == 1 &&
2475 "pullup/pulldown primitives should have exactly one port");
2478 portConns.front()->as<slang::ast::AssignmentExpression>().left());
2480 auto dstType = cast<moore::RefType>(portVal.getType()).getNestedType();
2481 auto dstTypeWidth = dstType.getBitSize();
2484 "expected fixed-width type for pullup/pulldown primitive");
2485 auto constVal = primName ==
"pullup" ? -1 : 0;
2486 auto c = moore::ConstantOp::create(
2488 moore::IntType::getInt(this->
getContext(), dstTypeWidth.value()),
2494 moore::ContinuousAssignOp::create(
builder, loc, portVal, converted);
2502mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
2503 const slang::ast::Type &ty) {
2504 SmallString<64> name;
2505 SmallVector<llvm::StringRef, 8> parts;
2507 const slang::ast::Scope *scope = ty.getParentScope();
2509 const auto &sym = scope->asSymbol();
2511 case slang::ast::SymbolKind::Root:
2514 case slang::ast::SymbolKind::InstanceBody:
2515 case slang::ast::SymbolKind::Instance:
2516 case slang::ast::SymbolKind::Package:
2517 case slang::ast::SymbolKind::ClassType:
2518 if (!sym.name.empty())
2519 parts.push_back(sym.name);
2524 scope = sym.getParentScope();
2527 for (
auto p :
llvm::reverse(parts)) {
2532 return mlir::StringAttr::get(ctx.
getContext(), name);
2537std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
2539 const slang::ast::ClassType &cls) {
2543 mlir::SymbolRefAttr base;
2544 if (
const auto *b = cls.getBaseClass())
2545 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
2548 SmallVector<mlir::Attribute> impls;
2549 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
2550 impls.reserve(ifaces.size());
2551 for (
const auto *iface : ifaces)
2552 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
2553 fullyQualifiedClassName(
context, *iface)));
2556 mlir::ArrayAttr implArr =
2557 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
2559 return {base, implArr};
2564struct ClassDeclVisitorBase {
2570 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
2574 return context.convertLocation(sloc);
2580struct ClassPropertyVisitor : ClassDeclVisitorBase {
2581 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2584 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2585 if (!classLowering.
op.getBody().empty())
2588 OpBuilder::InsertionGuard ig(builder);
2590 Block *body = &classLowering.
op.getBody().emplaceBlock();
2591 builder.setInsertionPointToEnd(body);
2594 for (
const auto &mem : classAST.members()) {
2595 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
2596 if (failed(prop->visit(*
this)))
2605 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
2607 auto ty =
context.convertType(prop.getType());
2611 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
2612 moore::ClassPropertyDeclOp::create(builder, loc, prop.name,
2621 if (!
context.globalVariables.lookup(&prop))
2622 return context.convertGlobalVariable(prop);
2627 LogicalResult visit(
const slang::ast::ClassType &cls) {
2628 return context.buildClassProperties(cls);
2632 template <
typename T>
2633 LogicalResult visit(T &&) {
2640struct ClassMethodVisitor : ClassDeclVisitorBase {
2641 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2644 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2648 if (classLowering.
op.getBody().empty())
2651 OpBuilder::InsertionGuard ig(builder);
2652 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2655 for (
const auto &mem : classAST.members()) {
2656 if (failed(mem.visit(*
this)))
2665 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2671 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2675 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2681 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2684 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2689 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2694 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2699 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2700 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2701 static bool remarkEmitted =
false;
2705 mlir::emitRemark(classLowering.
op.getLoc())
2706 <<
"Class builtin functions (needed for randomization, constraints, "
2707 "and covergroups) are not yet supported and will be dropped "
2709 remarkEmitted =
true;
2713 const mlir::UnitAttr isVirtual =
2714 (fn.flags & slang::ast::MethodFlags::Virtual)
2715 ? UnitAttr::get(
context.getContext())
2722 if (fn.flags & slang::ast::MethodFlags::Pure) {
2724 SmallVector<Type, 1> extraParams;
2726 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2728 moore::ClassHandleType::get(
context.getContext(), classSym);
2729 extraParams.push_back(handleTy);
2733 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2737 moore::ClassMethodDeclOp::create(builder, loc, fn.name,
2738 {}, funcTy,
nullptr);
2742 auto *lowering =
context.declareFunction(fn);
2751 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2753 moore::ClassMethodDeclOp::create(
2754 builder, loc, fn.name, {}, fnTy,
2755 SymbolRefAttr::get(lowering->op.getNameAttr()));
2772 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2773 const auto *externImpl = fn.getSubroutine();
2777 <<
"Didn't find an implementation matching the forward declaration "
2782 return visit(*externImpl);
2786 LogicalResult visit(
const slang::ast::ClassType &cls) {
2787 if (failed(
context.buildClassProperties(cls)))
2789 return context.materializeClassMethods(cls);
2793 template <
typename T>
2794 LogicalResult visit(T &&node) {
2795 Location loc = UnknownLoc::get(
context.getContext());
2796 if constexpr (
requires { node.location; })
2798 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2799 << slang::ast::toString(node.kind);
2807 auto &lowering =
classes[&cls];
2809 return lowering.get();
2810 lowering = std::make_unique<ClassLowering>();
2815 OpBuilder::InsertionGuard g(
builder);
2821 builder.setInsertionPoint(it->second);
2823 auto symName = fullyQualifiedClassName(*
this, cls);
2825 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2826 auto classDeclOp = moore::ClassDeclOp::create(
2827 builder, loc, symName, {}, base, impls);
2829 SymbolTable::setSymbolVisibility(classDeclOp,
2830 SymbolTable::Visibility::Public);
2832 lowering->op = classDeclOp;
2835 return lowering.get();
2842 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2843 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2850 if (classdecl.getBaseClass()) {
2851 if (
const auto *baseClassDecl =
2852 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2863 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2870 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2871 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2874 auto *lowering =
classes[&classdecl].get();
2881 if (classdecl.getBaseClass()) {
2882 if (
const auto *baseClassDecl =
2883 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2889 return ClassMethodVisitor(*
this, *lowering).run(classdecl);
2899 OpBuilder::InsertionGuard g(
builder);
2905 builder.setInsertionPoint(it->second);
2909 SmallString<64> symName;
2913 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2914 if (
const auto *parentScope = classVar->getParentScope()) {
2915 if (
const auto *parentClass =
2916 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2917 symName = fullyQualifiedClassName(*
this, *parentClass);
2919 mlir::emitError(loc)
2920 <<
"Could not access parent class of class property "
2925 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2930 symName += var.name;
2933 symName += var.name;
2942 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2944 cast<moore::UnpackedType>(type));
2955 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...
void populateSampledValueClocks()
Generates a map from sampled value system calls to clocks using Slang's analysis.
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)
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.