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";
726 SmallString<64> instName(blockNamePrefix);
727 if (instNode.arrayPath.empty()) {
728 instName += instNode.name;
730 instName += instNode.getArrayName();
731 slang::SmallVector<slang::ConstantRange, 4> dims;
732 instNode.getArrayDimensions(dims);
733 for (
auto [dim, index] :
llvm::zip(dims, instNode.arrayPath)) {
735 Twine(dim.lower() + int32_t(index)).toVector(instName);
740 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
741 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
742 auto inst = moore::InstanceOp::create(
743 builder, loc, moduleType.getOutputTypes(),
744 builder.getStringAttr(instName),
745 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
746 inputNames, outputNames);
750 auto aliasReachedThroughInstance =
751 [&](
const slang::ast::InstanceBodySymbol *aliasBody) {
752 for (
auto *b = aliasBody; b && b->parentInstance;
753 b = b->parentInstance->getParentScope()->getContainingInstance())
754 if (b->parentInstance == &instNode)
764 for (
const auto &hierPath :
context.hierPaths[body])
765 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out) {
766 auto result = inst->getResult(*hierPath.idx);
767 for (
auto &alias : hierPath.valueSyms)
768 if (aliasReachedThroughInstance(alias.second))
769 context.valueSymbols.insert(alias.first, result);
770 context.hierValueSymbols[{&instNode, hierPath.hierName}] = result;
774 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
777 Value rvalue = output;
778 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
780 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
781 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
788 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
789 auto ref =
context.valueSymbols.lookup(&varNode);
791 return mlir::emitError(loc)
792 <<
"internal error: missing predeclared variable `" << varNode.name
795 auto varOp = ref.getDefiningOp<moore::VariableOp>();
797 return mlir::emitError(loc)
798 <<
"internal error: predeclared variable `" << varNode.name
799 <<
"` is not a moore.variable";
801 if (
const auto *init = varNode.getInitializer()) {
802 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
803 auto initial =
context.convertRvalueExpression(*init, loweredType);
806 varOp.getInitialMutable().assign(initial);
813 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
814 auto ref =
context.valueSymbols.lookup(&netNode);
816 return mlir::emitError(loc) <<
"internal error: missing predeclared net `"
817 << netNode.name <<
"`";
819 auto netOp = ref.getDefiningOp<moore::NetOp>();
821 return mlir::emitError(loc) <<
"internal error: predeclared net `"
822 << netNode.name <<
"` is not a moore.net";
824 if (
const auto *init = netNode.getInitializer()) {
825 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
826 auto assignment =
context.convertRvalueExpression(*init, loweredType);
829 netOp.getAssignmentMutable().assign(assignment);
835 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
837 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
838 auto lhs =
context.convertLvalueExpression(expr.left());
842 auto rhs =
context.convertRvalueExpression(
843 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
848 if (
auto *timingCtrl = assignNode.getDelay()) {
849 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
850 auto delay =
context.convertRvalueExpression(
851 ctrl->expr, moore::TimeType::get(builder.getContext()));
854 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
857 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
862 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
867 LogicalResult convertProcedure(moore::ProcedureKind kind,
868 const slang::ast::Statement &body) {
869 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
870 return context.convertStatement(body);
871 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
872 OpBuilder::InsertionGuard guard(builder);
873 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
874 Context::ValueSymbolScope scope(
context.valueSymbols);
875 Context::VirtualInterfaceMemberScope vifMemberScope(
877 if (failed(
context.convertStatement(body)))
879 if (builder.getBlock())
880 moore::ReturnOp::create(builder, loc);
884 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
887 if (
context.options.lowerAlwaysAtStarAsComb) {
888 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
889 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
891 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
892 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
900 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
902 if (genNode.isUninstantiated)
906 SmallString<64> prefix = blockNamePrefix;
907 if (!genNode.name.empty() ||
908 genNode.getParentScope()->asSymbol().kind !=
909 slang::ast::SymbolKind::GenerateBlockArray) {
910 prefix += genNode.getExternalName();
915 for (
auto &member : genNode.members())
916 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
922 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
925 SmallString<64> prefix = blockNamePrefix;
926 prefix += genArrNode.getExternalName();
928 auto prefixBaseLen = prefix.size();
931 for (
const auto *entry : genArrNode.entries) {
933 prefix.resize(prefixBaseLen);
934 if (entry->arrayIndex)
935 prefix += entry->arrayIndex->toString();
937 Twine(entry->constructIndex).toVector(prefix);
941 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
953 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
959 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
965 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
971 LogicalResult visit(
const slang::ast::ClockingBlockSymbol &) {
977 LogicalResult visit(
const slang::ast::LetDeclSymbol &) {
return success(); }
980 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
981 if (!
context.declareFunction(subroutine))
987 LogicalResult visit(
const slang::ast::PrimitiveInstanceSymbol &prim) {
988 return context.convertPrimitiveInstance(prim);
992 LogicalResult visit(
const slang::ast::InstanceArraySymbol &arrNode) {
994 for (
const auto *element : arrNode.elements)
995 if (failed(element->visit(*this)))
1001 template <
typename T>
1002 LogicalResult visit(T &&node) {
1003 mlir::emitError(loc,
"unsupported module member: ")
1004 << slang::ast::toString(node.kind);
1009struct ModulePredeclaration {
1013 ModulePredeclaration(
Context &context)
1014 : context(context), builder(context.builder) {}
1016 LogicalResult declareVariable(
const slang::ast::VariableSymbol &varNode,
1017 Location loc, StringRef blockNamePrefix) {
1018 auto loweredType = context.
convertType(*varNode.getDeclaredType());
1022 auto varOp = moore::VariableOp::create(
1024 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
1025 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), Value{});
1028 const auto &canonTy = varNode.getType().getCanonicalType();
1029 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
1036 LogicalResult declareNet(
const slang::ast::NetSymbol &netNode, Location loc,
1037 StringRef blockNamePrefix) {
1038 auto loweredType = context.
convertType(*netNode.getDeclaredType());
1043 if (netkind == moore::NetKind::Interconnect ||
1044 netkind == moore::NetKind::UserDefined ||
1045 netkind == moore::NetKind::Unknown)
1046 return mlir::emitError(loc,
"unsupported net kind `")
1047 << netNode.netType.name <<
"`";
1049 auto netOp = moore::NetOp::create(
1051 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
1052 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
1059 getGenerateBlockPrefix(
const slang::ast::GenerateBlockSymbol &genNode,
1060 StringRef blockNamePrefix) {
1061 SmallString<64> prefix = blockNamePrefix;
1062 if (!genNode.name.empty() ||
1063 genNode.getParentScope()->asSymbol().kind !=
1064 slang::ast::SymbolKind::GenerateBlockArray) {
1065 prefix += genNode.getExternalName();
1072 predeclareStorageGenerateBlock(
const slang::ast::GenerateBlockSymbol &genNode,
1073 StringRef blockNamePrefix) {
1074 if (genNode.isUninstantiated)
1076 return predeclareStorageScope(
1077 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1080 LogicalResult predeclareInterfaceGenerateBlock(
1081 const slang::ast::GenerateBlockSymbol &genNode,
1082 StringRef blockNamePrefix) {
1083 if (genNode.isUninstantiated)
1085 return predeclareInterfaceScope(
1086 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1089 LogicalResult predeclareModuleInstanceGenerateBlock(
1090 const slang::ast::GenerateBlockSymbol &genNode,
1091 StringRef blockNamePrefix) {
1092 if (genNode.isUninstantiated)
1094 return predeclareModuleInstanceScope(
1095 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1098 LogicalResult predeclareGenerateBlockArray(
1099 const slang::ast::GenerateBlockArraySymbol &genArrNode,
1100 StringRef blockNamePrefix,
1101 llvm::function_ref<LogicalResult(
const slang::ast::GenerateBlockSymbol &,
1104 SmallString<64> prefix = blockNamePrefix;
1105 prefix += genArrNode.getExternalName();
1107 auto prefixBaseLen = prefix.size();
1109 for (
const auto *entry : genArrNode.entries) {
1110 prefix.resize(prefixBaseLen);
1111 if (entry->arrayIndex)
1112 prefix += entry->arrayIndex->toString();
1114 Twine(entry->constructIndex).toVector(prefix);
1117 if (failed(predeclareBlock(*entry, prefix)))
1123 LogicalResult predeclareStorageMember(
const slang::ast::Symbol &member,
1124 StringRef blockNamePrefix) {
1126 if (
const auto *varNode = member.as_if<slang::ast::VariableSymbol>())
1127 return declareVariable(*varNode, loc, blockNamePrefix);
1129 if (
const auto *netNode = member.as_if<slang::ast::NetSymbol>())
1130 return declareNet(*netNode, loc, blockNamePrefix);
1132 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1133 return predeclareStorageGenerateBlock(*genNode, blockNamePrefix);
1135 if (
const auto *genArrNode =
1136 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1137 return predeclareGenerateBlockArray(
1138 *genArrNode, blockNamePrefix,
1139 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1140 return predeclareStorageGenerateBlock(gen, prefix);
1146 LogicalResult predeclareInterfaceMember(
const slang::ast::Symbol &member,
1147 StringRef blockNamePrefix) {
1149 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1150 if (instNode->body.getDefinition().definitionKind ==
1151 slang::ast::DefinitionKind::Interface)
1152 return ModuleVisitor(context, loc, blockNamePrefix)
1153 .expandInterfaceInstance(*instNode);
1157 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1158 return predeclareInterfaceGenerateBlock(*genNode, blockNamePrefix);
1160 if (
const auto *genArrNode =
1161 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1162 return predeclareGenerateBlockArray(
1163 *genArrNode, blockNamePrefix,
1164 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1165 return predeclareInterfaceGenerateBlock(gen, prefix);
1171 LogicalResult predeclareModuleInstanceMember(
const slang::ast::Symbol &member,
1172 StringRef blockNamePrefix) {
1174 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1175 if (instNode->body.getDefinition().definitionKind !=
1176 slang::ast::DefinitionKind::Interface) {
1178 ModuleVisitor(context, loc, blockNamePrefix).visit(*instNode)))
1185 if (
const auto *arrNode = member.as_if<slang::ast::InstanceArraySymbol>()) {
1186 for (
const auto *element : arrNode->elements)
1187 if (failed(predeclareModuleInstanceMember(*element, blockNamePrefix)))
1192 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1193 return predeclareModuleInstanceGenerateBlock(*genNode, blockNamePrefix);
1195 if (
const auto *genArrNode =
1196 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1197 return predeclareGenerateBlockArray(
1198 *genArrNode, blockNamePrefix,
1199 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1200 return predeclareModuleInstanceGenerateBlock(gen, prefix);
1206 LogicalResult predeclareStorageScope(
const slang::ast::Scope &scope,
1207 StringRef blockNamePrefix) {
1208 for (
auto &member : scope.members())
1209 if (failed(predeclareStorageMember(member, blockNamePrefix)))
1214 LogicalResult predeclareInterfaceScope(
const slang::ast::Scope &scope,
1215 StringRef blockNamePrefix) {
1216 for (
auto &member : scope.members())
1217 if (failed(predeclareInterfaceMember(member, blockNamePrefix)))
1222 LogicalResult predeclareModuleInstanceScope(
const slang::ast::Scope &scope,
1223 StringRef blockNamePrefix) {
1224 for (
auto &member : scope.members())
1225 if (failed(predeclareModuleInstanceMember(member, blockNamePrefix)))
1230 LogicalResult predeclareScope(
const slang::ast::Scope &scope,
1231 StringRef blockNamePrefix) {
1235 if (failed(predeclareStorageScope(scope, blockNamePrefix)))
1241 if (failed(predeclareInterfaceScope(scope, blockNamePrefix)))
1246 return predeclareModuleInstanceScope(scope, blockNamePrefix);
1257LogicalResult Context::convertCompilation() {
1263 timeScale = root.getTimeScale().value_or(slang::TimeScale());
1264 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1268 SmallVector<AmbiguousHierCapture> ambiguousHierCaptures;
1270 for (
auto &ambiguous : ambiguousHierCaptures) {
1271 auto d = mlir::emitError(
convertLocation(ambiguous.function->location))
1272 <<
"hierarchical reference to `" << ambiguous.symbol->name
1273 <<
"` is ambiguous: this function reaches it through more than "
1274 "one instance of the same module, which is not yet supported";
1276 <<
"symbol declared here";
1278 if (!ambiguousHierCaptures.empty())
1283 for (
auto *inst : root.topInstances)
1293 for (
auto *unit : root.compilationUnits) {
1295 for (
const auto &member : unit->members()) {
1297 if (failed(member.visit(RootVisitor(*
this, loc))))
1305 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
1306 for (
auto *inst : root.topInstances) {
1308 if (body->getDefinition().definitionKind !=
1309 slang::ast::DefinitionKind::Interface)
1316 auto *
module = moduleWorklist.front();
1324 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
1325 classMethodWorklist.reserve(
classes.size());
1327 classMethodWorklist.push_back(kv.first);
1329 for (
auto *inst : classMethodWorklist) {
1348 auto &block = varOp.getInitRegion().emplaceBlock();
1349 OpBuilder::InsertionGuard guard(
builder);
1350 builder.setInsertionPointToEnd(&block);
1355 moore::YieldOp::create(
builder, varOp.getLoc(), value);
1364 using slang::ast::ArgumentDirection;
1365 using slang::ast::MultiPortSymbol;
1366 using slang::ast::ParameterSymbol;
1367 using slang::ast::PortSymbol;
1368 using slang::ast::TypeParameterSymbol;
1373 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1374 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1381 slot = std::make_unique<ModuleLowering>();
1382 auto &lowering = *slot;
1385 OpBuilder::InsertionGuard g(
builder);
1390 auto kind =
module->getDefinition().definitionKind;
1391 if (kind != slang::ast::DefinitionKind::Module &&
1392 kind != slang::ast::DefinitionKind::Program) {
1393 mlir::emitError(loc) <<
"unsupported definition: "
1394 <<
module->getDefinition().getKindString();
1399 auto block = std::make_unique<Block>();
1400 SmallVector<hw::ModulePort> modulePorts;
1403 unsigned int outputIdx = 0, inputIdx = 0;
1404 for (
auto *symbol :
module->getPortList()) {
1405 auto handlePort = [&](const PortSymbol &port) {
1406 auto portLoc = convertLocation(port.location);
1410 auto portName =
builder.getStringAttr(port.name);
1412 std::optional<unsigned> portOutputIdx;
1413 std::optional<unsigned> portInputIdx;
1414 if (port.direction == ArgumentDirection::Out) {
1416 portOutputIdx = outputIdx++;
1420 if (port.direction != ArgumentDirection::In)
1421 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1423 arg = block->addArgument(type, portLoc);
1424 portInputIdx = inputIdx++;
1426 lowering.ports.push_back(
1427 {port, portLoc, arg, portOutputIdx, portInputIdx});
1434 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1437 auto [connSym, modportSym] = ifacePort.getConnection();
1438 const auto *ifaceInst =
1439 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1440 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1444 for (
const auto &member : modportSym->members()) {
1445 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1452 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1455 std::optional<unsigned> ifaceOutputIdx;
1456 std::optional<unsigned> ifaceInputIdx;
1457 if (mpp->direction == ArgumentDirection::Out) {
1459 modulePorts.push_back({name, type, dir});
1460 ifaceOutputIdx = outputIdx++;
1463 if (mpp->direction != ArgumentDirection::In)
1464 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1465 modulePorts.push_back({name, type, dir});
1466 arg = block->addArgument(type, portLoc);
1467 ifaceInputIdx = inputIdx++;
1469 lowering.ifacePorts.push_back(
1470 {name, dir, type, portLoc, arg, &ifacePort, mpp->internalSymbol,
1471 ifaceInst, mpp, ifaceOutputIdx, ifaceInputIdx});
1476 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1478 mlir::emitError(portLoc)
1479 <<
"unsupported interface port connection for `" << ifacePort.name
1483 for (
const auto &member : instSym->body.members()) {
1484 const slang::ast::Type *slangType =
nullptr;
1485 const slang::ast::Symbol *bodySym =
nullptr;
1486 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1487 slangType = &var->getType();
1489 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1490 slangType = &net->getType();
1498 auto name = builder.getStringAttr(Twine(portPrefix) +
1499 StringRef(bodySym->name));
1500 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1502 auto arg = block->addArgument(refType, portLoc);
1503 lowering.ifacePorts.push_back(
1505 bodySym, instSym,
nullptr, std::nullopt, inputIdx++});
1511 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1512 if (failed(handlePort(*port)))
1514 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1515 for (
auto *port : multiPort->ports)
1516 if (failed(handlePort(*port)))
1518 }
else if (
const auto *ifacePort =
1519 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1520 if (failed(handleIfacePort(*ifacePort)))
1524 <<
"unsupported module port `" << symbol->name <<
"` ("
1525 << slang::ast::toString(symbol->kind) <<
")";
1531 lowering.numExplicitOutputs = outputIdx;
1532 lowering.numExplicitInputs = inputIdx;
1535 for (
auto &hierPath : hierPaths[module]) {
1536 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1537 auto hierType =
convertType(hierPath.valueSyms.front().first->getType());
1541 if (
auto hierName = hierPath.hierName) {
1543 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1544 if (hierPath.direction == ArgumentDirection::Out) {
1545 hierPath.idx = outputIdx++;
1548 hierPath.idx = inputIdx++;
1552 block->addArgument(hierType, hierLoc);
1556 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1561 auto it = orderedRootOps.upper_bound(key);
1562 if (it == orderedRootOps.end())
1563 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1565 builder.setInsertionPoint(it->second);
1569 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1570 orderedRootOps.insert(it, {key, moduleOp});
1571 moduleOp.getBodyRegion().push_back(block.release());
1572 lowering.op = moduleOp;
1576 symbolTable.insert(moduleOp);
1579 moduleWorklist.push(module);
1582 for (
const auto &port : lowering.ports)
1583 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1590 auto &lowering = *
modules[module];
1593 llvm::scope_exit currentDefinitionGuard(
1597 OpBuilder::InsertionGuard g(
builder);
1598 builder.setInsertionPointToEnd(lowering.op.getBody());
1607 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1608 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1613 for (
auto &hierPath :
hierPaths[module])
1614 if (hierPath.direction == slang::ast::ArgumentDirection::In &&
1616 auto arg = lowering.op.getBody()->getArgument(*hierPath.idx);
1617 for (
auto &alias : hierPath.valueSyms)
1625 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1628 auto getIfacePortLowering =
1634 if (
auto it = ifacePortLowerings.find(ifaceInst);
1635 it != ifacePortLowerings.end())
1638 auto lowering = std::make_unique<InterfaceLowering>();
1642 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1646 for (
auto &fp : lowering.ifacePorts) {
1649 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1658 portValue = moore::VariableOp::create(
1660 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1669 if (fp.modportPortSym)
1670 if (
auto *mppSym = fp.modportPortSym->as_if<slang::ast::ValueSymbol>())
1671 if (mppSym != valueSym)
1674 if (!fp.ifaceInstance)
1677 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1680 ifaceLowering->expandedMembers[fp.bodySym] = val;
1682 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1688 llvm::scope_exit predeclaredInstancesGuard(
1698 if (failed(ModulePredeclaration(*this).predeclareScope(*module,
"")))
1702 for (
auto &member :
module->members()) {
1703 auto loc = convertLocation(member.location);
1704 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1716 SmallVector<Value> outputs(lowering.numExplicitOutputs);
1717 for (
auto &port : lowering.ports) {
1719 if (
auto *expr = port.ast.getInternalExpr()) {
1720 value = convertLvalueExpression(*expr);
1721 }
else if (port.ast.internalSymbol) {
1722 if (
const auto *sym =
1723 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1724 value = valueSymbols.lookup(sym);
1727 return mlir::emitError(port.loc,
"unsupported port: `")
1729 <<
"` does not map to an internal symbol or expression";
1732 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1733 if (isa<moore::RefType>(value.getType()))
1734 value = moore::ReadOp::create(builder, value.getLoc(), value);
1735 outputs[*port.outputIdx] = value;
1741 Value portArg = port.arg;
1742 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1743 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1744 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1749 for (
auto &fp : lowering.ifacePorts) {
1753 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1756 Value ref = valueSymbols.lookup(valueSym);
1759 outputs[*fp.outputIdx] =
1760 moore::ReadOp::create(builder, fp.loc, ref).getResult();
1765 for (
auto &hierPath : hierPaths[module]) {
1766 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1767 if (hierPath.direction != slang::ast::ArgumentDirection::Out)
1771 for (
auto &alias : hierPath.valueSyms)
1772 if ((hierValue = valueSymbols.lookup(alias.first)))
1777 auto name = hierPath.hierName.getValue();
1778 if (
auto dot = name.find(
"."); dot != llvm::StringRef::npos) {
1779 auto innerName = builder.getStringAttr(name.drop_front(dot + 1));
1780 for (
auto &member : module->members())
1781 if (auto *inst = member.as_if<
slang::ast::InstanceSymbol>())
1782 if (
llvm::StringRef(inst->name.
data(), inst->name.size()) ==
1783 name.take_front(dot)) {
1784 hierValue = hierValueSymbols.lookup({inst, innerName});
1787 }
else if (
auto *sym =
1788 module->find(std::string_view(name.data(), name.size()))) {
1790 if (
auto *valueSym = sym->as_if<slang::ast::ValueSymbol>())
1791 hierValue = valueSymbols.lookup(valueSym);
1795 return mlir::emitError(lowering.op.getLoc())
1796 <<
"unable to resolve hierarchical output `"
1797 << hierPath.hierName.getValue() <<
"` in module `" <<
module->name
1799 outputs.push_back(hierValue);
1802 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1812 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1813 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1817 OpBuilder::InsertionGuard g(
builder);
1820 for (
auto &member : package.members()) {
1822 if (failed(member.visit(PackageVisitor(*
this, loc))))
1833 auto &lowering =
functions[&subroutine];
1835 if (!lowering->op.getOperation())
1837 return lowering.get();
1840 if (!subroutine.thisVar) {
1842 SmallString<64> name;
1844 name += subroutine.name;
1846 SmallVector<Type, 1> noThis = {};
1853 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1854 moore::ClassDeclOp ownerDecl;
1856 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1857 auto &ownerLowering =
classes[classTy];
1858 ownerDecl = ownerLowering->op;
1860 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1861 << thisTy.toString();
1866 SmallString<64> qualName;
1867 qualName += ownerDecl.getSymName();
1869 qualName += subroutine.name;
1872 SmallVector<Type, 1> extraParams;
1874 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1875 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1876 extraParams.push_back(handleTy);
1886 Context &
context,
const slang::ast::SubroutineSymbol &subroutine,
1887 ArrayRef<Type> prefixParams, ArrayRef<Type> suffixParams = {}) {
1888 using slang::ast::ArgumentDirection;
1890 SmallVector<Type> inputTypes;
1891 inputTypes.append(prefixParams.begin(), prefixParams.end());
1892 SmallVector<Type, 1> outputTypes;
1894 for (
const auto *arg : subroutine.getArguments()) {
1895 auto type =
context.convertType(arg->getType());
1898 if (arg->direction == ArgumentDirection::In) {
1899 inputTypes.push_back(type);
1901 inputTypes.push_back(
1902 moore::RefType::get(cast<moore::UnpackedType>(type)));
1906 inputTypes.append(suffixParams.begin(), suffixParams.end());
1908 const auto &returnType = subroutine.getReturnType();
1909 if (!returnType.isVoid()) {
1910 auto type =
context.convertType(returnType);
1913 outputTypes.push_back(type);
1916 return FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1919static FailureOr<SmallVector<moore::DPIArgInfo>>
1921 const slang::ast::SubroutineSymbol &subroutine) {
1922 using slang::ast::ArgumentDirection;
1924 SmallVector<moore::DPIArgInfo> args;
1925 args.reserve(subroutine.getArguments().size() +
1926 (!subroutine.getReturnType().isVoid() ? 1 : 0));
1928 for (
const auto *arg : subroutine.getArguments()) {
1929 auto type =
context.convertType(arg->getType());
1932 moore::DPIArgDirection dir;
1933 switch (arg->direction) {
1934 case ArgumentDirection::In:
1935 dir = moore::DPIArgDirection::In;
1937 case ArgumentDirection::Out:
1938 dir = moore::DPIArgDirection::Out;
1940 case ArgumentDirection::InOut:
1941 dir = moore::DPIArgDirection::InOut;
1943 case ArgumentDirection::Ref:
1944 llvm_unreachable(
"'ref' is not legal for DPI functions");
1947 {StringAttr::get(
context.getContext(), arg->name), type, dir});
1950 if (!subroutine.getReturnType().isVoid()) {
1951 auto type =
context.convertType(subroutine.getReturnType());
1954 args.push_back({StringAttr::get(
context.getContext(),
"return"), type,
1955 moore::DPIArgDirection::Return});
1965 mlir::StringRef qualifiedName,
1966 llvm::SmallVectorImpl<Type> &extraParams) {
1970 OpBuilder::InsertionGuard g(
builder);
1976 builder.setInsertionPoint(it->second);
1981 SmallVector<Type> captureTypes;
1984 for (
auto *sym : capturesIt->second) {
1988 captureTypes.push_back(
1989 moore::RefType::get(cast<moore::UnpackedType>(type)));
1998 std::unique_ptr<FunctionLowering> lowering;
1999 Operation *insertedOp =
nullptr;
2004 auto setVisibilityAndExportAttr = [&](Operation *op) {
2007 builder.getStringAttr(dpiExportIt->second));
2008 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Public);
2011 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
2013 if (!subroutine.thisVar &&
2014 subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
2020 auto dpiOp = moore::DPIFuncOp::create(
2023 StringAttr::get(
getContext(), subroutine.name));
2024 setVisibilityAndExportAttr(dpiOp);
2025 lowering = std::make_unique<FunctionLowering>(dpiOp);
2027 }
else if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
2029 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
2030 setVisibilityAndExportAttr(op);
2031 lowering = std::make_unique<FunctionLowering>(op);
2036 mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
2037 setVisibilityAndExportAttr(funcOp);
2038 lowering = std::make_unique<FunctionLowering>(funcOp);
2039 insertedOp = funcOp;
2045 lowering->capturedSymbols.assign(capturesIt->second.begin(),
2046 capturesIt->second.end());
2051 functions[&subroutine] = std::move(lowering);
2065 auto *lowering =
functions.at(&subroutine).get();
2070 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
2071 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2076 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport))
2079 const bool isMethod = (subroutine.thisVar !=
nullptr);
2084 if (
const auto *classTy =
2085 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
2086 for (
auto &member : classTy->members()) {
2087 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
2090 const auto &propCanon = prop->getType().getCanonicalType();
2091 if (
const auto *vi =
2092 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
2102 SmallVector<moore::VariableOp> argVariables;
2103 auto &block = lowering->op.getFunctionBody().emplaceBlock();
2110 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
2111 auto thisArg = block.addArgument(thisType, thisLoc);
2119 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
2120 auto astArgs = subroutine.getArguments();
2121 unsigned prefixCount = isMethod ? 1 : 0;
2122 auto valInputs = llvm::ArrayRef<Type>(inputs)
2123 .drop_front(prefixCount)
2124 .take_front(astArgs.size());
2126 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
2128 auto blockArg = block.addArgument(type, loc);
2130 if (isa<moore::RefType>(type)) {
2133 OpBuilder::InsertionGuard g(
builder);
2134 builder.setInsertionPointToEnd(&block);
2136 auto shadowArg = moore::VariableOp::create(
2137 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
2138 StringAttr{}, blockArg);
2140 argVariables.push_back(shadowArg);
2143 const auto &argCanon = astArg->getType().getCanonicalType();
2144 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
2150 OpBuilder::InsertionGuard g(
builder);
2151 builder.setInsertionPointToEnd(&block);
2154 if (subroutine.returnValVar) {
2155 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
2158 returnVar = moore::VariableOp::create(
2159 builder, lowering->op->getLoc(),
2160 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
2162 valueSymbols.insert(subroutine.returnValVar, returnVar);
2170 for (
auto *sym : lowering->capturedSymbols) {
2174 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
2176 auto blockArg = block.addArgument(refType, loc);
2182 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
2186 llvm::scope_exit restoreFunctionLowering(
2195 if (isa<moore::CoroutineOp>(lowering->op.getOperation())) {
2196 moore::ReturnOp::create(
builder, lowering->op->getLoc());
2197 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
2199 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
2200 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(), read);
2202 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(),
2206 if (returnVar && returnVar.use_empty())
2207 returnVar.getDefiningOp()->erase();
2209 for (
auto var : argVariables) {
2210 if (llvm::all_of(var->getUsers(),
2211 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
2212 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
2213 user->getResult(0).replaceAllUsesWith(var.getInitial());
2225 const slang::ast::PrimitiveInstanceSymbol &prim) {
2226 if (prim.getDriveStrength().first.has_value() ||
2227 prim.getDriveStrength().second.has_value())
2229 <<
"primitive instances with explicit drive strengths are not "
2232 switch (prim.primitiveType.primitiveKind) {
2233 case slang::ast::PrimitiveSymbol::PrimitiveKind::NInput:
2236 case slang::ast::PrimitiveSymbol::PrimitiveKind::NOutput:
2239 case slang::ast::PrimitiveSymbol::PrimitiveKind::Fixed:
2244 <<
"unsupported instance of primitive `" << prim.primitiveType.name
2250 const slang::ast::PrimitiveInstanceSymbol &prim) {
2252 auto primName = prim.primitiveType.name;
2254 auto portConns = prim.getPortConnections();
2255 assert(portConns.size() >= 2 &&
2256 "n-input primitives should have at least 2 ports");
2260 portConns[0]->as<slang::ast::AssignmentExpression>().left();
2266 SmallVector<Value> inputVals;
2267 inputVals.reserve(portConns.size() - 1);
2268 for (
const auto *inputConn : portConns.subspan(1, portConns.size() - 1)) {
2272 inputVals.push_back(inputVal);
2275 Value nextInput = inputVals.front();
2277 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2279 for (Value inputVal : llvm::drop_begin(inputVals))
2281 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2285 for (Value inputVal : llvm::drop_begin(inputVals))
2287 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2291 for (Value inputVal : llvm::drop_begin(inputVals))
2293 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2296 .Case(
"nand", ([&] {
2297 for (Value inputVal : llvm::drop_begin(inputVals))
2299 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2300 return moore::NotOp::create(
builder, loc, nextInput);
2303 for (Value inputVal : llvm::drop_begin(inputVals))
2305 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2306 return moore::NotOp::create(
builder, loc, nextInput);
2308 .Case(
"xnor", ([&] {
2309 for (Value inputVal : llvm::drop_begin(inputVals))
2311 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2312 return moore::NotOp::create(
builder, loc, nextInput);
2315 mlir::emitError(loc)
2316 <<
"unsupported primitive `" << primName <<
"`";
2323 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2328 if (prim.getDelay()) {
2329 const slang::ast::Expression *delayExpr;
2330 if (
const auto *delay3 =
2331 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2332 if (delay3->expr2 || delay3->expr3)
2333 return mlir::emitError(loc) <<
"only n-input primitives that specify a "
2334 "single delay are currently supported.";
2335 delayExpr = &delay3->expr1;
2336 }
else if (
const auto *delay =
2337 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2338 delayExpr = &delay->expr;
2340 llvm_unreachable(
"unexpected delay control type in primitive instance");
2343 *delayExpr, moore::TimeType::get(
getContext()));
2346 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal, result,
2349 moore::ContinuousAssignOp::create(
builder, loc, outputVal, result);
2356 const slang::ast::PrimitiveInstanceSymbol &prim) {
2358 auto primName = prim.primitiveType.name;
2360 auto portConns = prim.getPortConnections();
2361 assert(portConns.size() >= 2 &&
2362 "n-output primitives should have at least 2 ports");
2365 SmallVector<Value> outputVals;
2366 outputVals.reserve(portConns.size() - 1);
2367 for (
const auto *outputConn : portConns.subspan(0, portConns.size() - 1)) {
2368 auto &output = outputConn->as<slang::ast::AssignmentExpression>().left();
2372 outputVals.push_back(outputVal);
2380 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2382 ([&] {
return moore::NotOp::create(
builder, loc, inputVal); }))
2384 return moore::BoolCastOp::create(
builder, loc, inputVal);
2387 mlir::emitError(loc)
2388 <<
"unsupported primitive `" << primName <<
"`";
2396 if (prim.getDelay()) {
2397 const slang::ast::Expression *delayExpr;
2398 if (
const auto *delay3 =
2399 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2400 if (delay3->expr2 || delay3->expr3)
2401 return mlir::emitError(loc)
2402 <<
"only n-output primitives that specify a "
2403 "single delay are currently supported.";
2404 delayExpr = &delay3->expr1;
2405 }
else if (
const auto *delay =
2406 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2407 delayExpr = &delay->expr;
2409 llvm_unreachable(
"unexpected delay control type in primitive instance");
2412 *delayExpr, moore::TimeType::get(
getContext()));
2417 for (
auto outputVal : outputVals) {
2418 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2423 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal,
2424 converted, delayVal);
2426 moore::ContinuousAssignOp::create(
builder, loc, outputVal, converted);
2433 const slang::ast::PrimitiveInstanceSymbol &prim) {
2434 auto primName = prim.primitiveType.name;
2439 if (primName ==
"pullup" || primName ==
"pulldown")
2443 mlir::emitError(loc) <<
"unsupported primitive `" << primName <<
"`";
2448 const slang::ast::PrimitiveInstanceSymbol &prim) {
2449 assert((prim.primitiveType.name ==
"pullup" ||
2450 prim.primitiveType.name ==
"pulldown") &&
2451 "expected pullup or pulldown primitive");
2453 assert(!prim.getDelay() &&
2454 "SystemVerilog does not allow pull gate primitives with delays");
2456 auto primName = prim.primitiveType.name;
2458 auto portConns = prim.getPortConnections();
2460 assert(portConns.size() == 1 &&
2461 "pullup/pulldown primitives should have exactly one port");
2464 portConns.front()->as<slang::ast::AssignmentExpression>().left());
2466 auto dstType = cast<moore::RefType>(portVal.getType()).getNestedType();
2467 auto dstTypeWidth = dstType.getBitSize();
2470 "expected fixed-width type for pullup/pulldown primitive");
2471 auto constVal = primName ==
"pullup" ? -1 : 0;
2472 auto c = moore::ConstantOp::create(
2474 moore::IntType::getInt(this->
getContext(), dstTypeWidth.value()),
2480 moore::ContinuousAssignOp::create(
builder, loc, portVal, converted);
2488mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
2489 const slang::ast::Type &ty) {
2490 SmallString<64> name;
2491 SmallVector<llvm::StringRef, 8> parts;
2493 const slang::ast::Scope *scope = ty.getParentScope();
2495 const auto &sym = scope->asSymbol();
2497 case slang::ast::SymbolKind::Root:
2500 case slang::ast::SymbolKind::InstanceBody:
2501 case slang::ast::SymbolKind::Instance:
2502 case slang::ast::SymbolKind::Package:
2503 case slang::ast::SymbolKind::ClassType:
2504 if (!sym.name.empty())
2505 parts.push_back(sym.name);
2510 scope = sym.getParentScope();
2513 for (
auto p :
llvm::reverse(parts)) {
2518 return mlir::StringAttr::get(ctx.
getContext(), name);
2523std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
2525 const slang::ast::ClassType &cls) {
2529 mlir::SymbolRefAttr base;
2530 if (
const auto *b = cls.getBaseClass())
2531 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
2534 SmallVector<mlir::Attribute> impls;
2535 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
2536 impls.reserve(ifaces.size());
2537 for (
const auto *iface : ifaces)
2538 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
2539 fullyQualifiedClassName(
context, *iface)));
2542 mlir::ArrayAttr implArr =
2543 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
2545 return {base, implArr};
2550struct ClassDeclVisitorBase {
2556 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
2560 return context.convertLocation(sloc);
2566struct ClassPropertyVisitor : ClassDeclVisitorBase {
2567 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2570 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2571 if (!classLowering.
op.getBody().empty())
2574 OpBuilder::InsertionGuard ig(builder);
2576 Block *body = &classLowering.
op.getBody().emplaceBlock();
2577 builder.setInsertionPointToEnd(body);
2580 for (
const auto &mem : classAST.members()) {
2581 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
2582 if (failed(prop->visit(*
this)))
2591 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
2593 auto ty =
context.convertType(prop.getType());
2597 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
2598 moore::ClassPropertyDeclOp::create(builder, loc, prop.name, ty);
2606 if (!
context.globalVariables.lookup(&prop))
2607 return context.convertGlobalVariable(prop);
2612 LogicalResult visit(
const slang::ast::ClassType &cls) {
2613 return context.buildClassProperties(cls);
2617 template <
typename T>
2618 LogicalResult visit(T &&) {
2625struct ClassMethodVisitor : ClassDeclVisitorBase {
2626 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2629 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2633 if (classLowering.
op.getBody().empty())
2636 OpBuilder::InsertionGuard ig(builder);
2637 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2640 for (
const auto &mem : classAST.members()) {
2641 if (failed(mem.visit(*
this)))
2650 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2656 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2660 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2666 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2669 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2674 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2679 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2684 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2685 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2686 static bool remarkEmitted =
false;
2690 mlir::emitRemark(classLowering.
op.getLoc())
2691 <<
"Class builtin functions (needed for randomization, constraints, "
2692 "and covergroups) are not yet supported and will be dropped "
2694 remarkEmitted =
true;
2698 const mlir::UnitAttr isVirtual =
2699 (fn.flags & slang::ast::MethodFlags::Virtual)
2700 ? UnitAttr::get(
context.getContext())
2707 if (fn.flags & slang::ast::MethodFlags::Pure) {
2709 SmallVector<Type, 1> extraParams;
2711 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2713 moore::ClassHandleType::get(
context.getContext(), classSym);
2714 extraParams.push_back(handleTy);
2718 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2722 moore::ClassMethodDeclOp::create(builder, loc, fn.name, funcTy,
nullptr);
2726 auto *lowering =
context.declareFunction(fn);
2735 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2737 moore::ClassMethodDeclOp::create(
2738 builder, loc, fn.name, fnTy,
2739 SymbolRefAttr::get(lowering->op.getNameAttr()));
2756 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2757 const auto *externImpl = fn.getSubroutine();
2761 <<
"Didn't find an implementation matching the forward declaration "
2766 return visit(*externImpl);
2770 LogicalResult visit(
const slang::ast::ClassType &cls) {
2771 if (failed(
context.buildClassProperties(cls)))
2773 return context.materializeClassMethods(cls);
2777 template <
typename T>
2778 LogicalResult visit(T &&node) {
2779 Location loc = UnknownLoc::get(
context.getContext());
2780 if constexpr (
requires { node.location; })
2782 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2783 << slang::ast::toString(node.kind);
2791 auto &lowering =
classes[&cls];
2793 return lowering.get();
2794 lowering = std::make_unique<ClassLowering>();
2799 OpBuilder::InsertionGuard g(
builder);
2805 builder.setInsertionPoint(it->second);
2807 auto symName = fullyQualifiedClassName(*
this, cls);
2809 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2811 moore::ClassDeclOp::create(
builder, loc, symName, base, impls);
2813 SymbolTable::setSymbolVisibility(classDeclOp,
2814 SymbolTable::Visibility::Public);
2816 lowering->op = classDeclOp;
2819 return lowering.get();
2826 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2827 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2834 if (classdecl.getBaseClass()) {
2835 if (
const auto *baseClassDecl =
2836 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2847 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2854 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2855 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2858 auto *lowering =
classes[&classdecl].get();
2865 if (classdecl.getBaseClass()) {
2866 if (
const auto *baseClassDecl =
2867 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2873 return ClassMethodVisitor(*
this, *lowering).run(classdecl);
2883 OpBuilder::InsertionGuard g(
builder);
2889 builder.setInsertionPoint(it->second);
2893 SmallString<64> symName;
2897 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2898 if (
const auto *parentScope = classVar->getParentScope()) {
2899 if (
const auto *parentClass =
2900 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2901 symName = fullyQualifiedClassName(*
this, *parentClass);
2903 mlir::emitError(loc)
2904 <<
"Could not access parent class of class property "
2909 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2914 symName += var.name;
2917 symName += var.name;
2926 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2927 cast<moore::UnpackedType>(type));
2938 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.