10#include "slang/ast/Compilation.h"
11#include "slang/ast/symbols/ClassSymbols.h"
12#include "slang/syntax/AllSyntax.h"
13#include "slang/syntax/SyntaxVisitor.h"
14#include "llvm/ADT/STLFunctionalExtras.h"
15#include "llvm/ADT/ScopeExit.h"
18using namespace ImportVerilog;
31 const slang::ast::Scope &scope,
32 const slang::syntax::SyntaxNode *syntax) {
36 auto visitor = slang::syntax::makeSyntaxVisitor(
37 [&](
auto &visitor,
const slang::syntax::DPIExportSyntax &exportSyntax) {
38 auto svName = exportSyntax.name.valueText();
42 const auto *symbol = scope.find(svName);
43 const auto *subroutine =
44 symbol ? symbol->as_if<slang::ast::SubroutineSymbol>() :
nullptr;
48 auto cName = exportSyntax.c_identifier.valueText();
51 context.dpiExportCNames[subroutine] = std::string(cName);
53 [](
auto &visitor,
const slang::syntax::SyntaxNode &node) {
54 visitor.visitDefault(node);
56 syntax->visit(visitor);
60 SmallString<64> &prefix) {
61 if (symbol.kind != slang::ast::SymbolKind::Package)
64 if (!symbol.name.empty()) {
65 prefix += symbol.name;
82 BaseVisitor(
Context &context, Location loc)
83 : context(context), loc(loc), builder(context.builder) {}
86 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
92 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
97 LogicalResult visit(
const slang::ast::ClassType &classdecl) {
107 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
112 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
113 LogicalResult visit(
const slang::ast::ForwardingTypedefSymbol &) {
118 LogicalResult visit(
const slang::ast::ExplicitImportSymbol &) {
121 LogicalResult visit(
const slang::ast::WildcardImportSymbol &) {
126 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
131 LogicalResult visit(
const slang::ast::ElabSystemTaskSymbol &) {
136 LogicalResult visit(
const slang::ast::ParameterSymbol ¶m) {
137 visitParameter(param);
141 LogicalResult visit(
const slang::ast::SpecparamSymbol ¶m) {
142 visitParameter(param);
146 template <
class Node>
147 void visitParameter(
const Node ¶m) {
157 if (builder.getInsertionBlock()->getParentOp() == context.
intoModuleOp) {
164 SmallString<64> paramName;
166 paramName += param.name;
168 debug::VariableOp::create(builder, loc, builder.getStringAttr(paramName),
179struct RootVisitor :
public BaseVisitor {
180 using BaseVisitor::BaseVisitor;
181 using BaseVisitor::visit;
184 LogicalResult visit(
const slang::ast::PackageSymbol &package) {
185 return context.convertPackage(package);
189 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
190 if (!
context.declareFunction(subroutine))
196 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
197 return context.convertGlobalVariable(var);
201 template <
typename T>
202 LogicalResult visit(T &&node) {
203 mlir::emitError(loc,
"unsupported construct: ")
204 << slang::ast::toString(node.kind);
215struct PackageVisitor :
public BaseVisitor {
216 using BaseVisitor::BaseVisitor;
217 using BaseVisitor::visit;
220 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
221 if (!
context.declareFunction(subroutine))
227 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
228 return context.convertGlobalVariable(var);
232 template <
typename T>
233 LogicalResult visit(T &&node) {
234 mlir::emitError(loc,
"unsupported package member: ")
235 << slang::ast::toString(node.kind);
245static moore::ProcedureKind
248 case slang::ast::ProceduralBlockKind::Always:
249 return moore::ProcedureKind::Always;
250 case slang::ast::ProceduralBlockKind::AlwaysComb:
251 return moore::ProcedureKind::AlwaysComb;
252 case slang::ast::ProceduralBlockKind::AlwaysLatch:
253 return moore::ProcedureKind::AlwaysLatch;
254 case slang::ast::ProceduralBlockKind::AlwaysFF:
255 return moore::ProcedureKind::AlwaysFF;
256 case slang::ast::ProceduralBlockKind::Initial:
257 return moore::ProcedureKind::Initial;
258 case slang::ast::ProceduralBlockKind::Final:
259 return moore::ProcedureKind::Final;
261 llvm_unreachable(
"all procedure kinds handled");
266 case slang::ast::NetType::Supply0:
267 return moore::NetKind::Supply0;
268 case slang::ast::NetType::Supply1:
269 return moore::NetKind::Supply1;
270 case slang::ast::NetType::Tri:
271 return moore::NetKind::Tri;
272 case slang::ast::NetType::TriAnd:
273 return moore::NetKind::TriAnd;
274 case slang::ast::NetType::TriOr:
275 return moore::NetKind::TriOr;
276 case slang::ast::NetType::TriReg:
277 return moore::NetKind::TriReg;
278 case slang::ast::NetType::Tri0:
279 return moore::NetKind::Tri0;
280 case slang::ast::NetType::Tri1:
281 return moore::NetKind::Tri1;
282 case slang::ast::NetType::UWire:
283 return moore::NetKind::UWire;
284 case slang::ast::NetType::Wire:
285 return moore::NetKind::Wire;
286 case slang::ast::NetType::WAnd:
287 return moore::NetKind::WAnd;
288 case slang::ast::NetType::WOr:
289 return moore::NetKind::WOr;
290 case slang::ast::NetType::Interconnect:
291 return moore::NetKind::Interconnect;
292 case slang::ast::NetType::UserDefined:
293 return moore::NetKind::UserDefined;
294 case slang::ast::NetType::Unknown:
295 return moore::NetKind::Unknown;
297 llvm_unreachable(
"all net kinds handled");
301struct ModuleVisitor :
public BaseVisitor {
302 using BaseVisitor::visit;
306 StringRef blockNamePrefix;
308 ModuleVisitor(
Context &
context, Location loc, StringRef blockNamePrefix =
"")
309 : BaseVisitor(
context, loc), blockNamePrefix(blockNamePrefix) {}
312 LogicalResult visit(
const slang::ast::PortSymbol &) {
return success(); }
313 LogicalResult visit(
const slang::ast::MultiPortSymbol &) {
return success(); }
314 LogicalResult visit(
const slang::ast::InterfacePortSymbol &) {
319 LogicalResult visit(
const slang::ast::GenvarSymbol &genvarNode) {
324 LogicalResult visit(
const slang::ast::DefParamSymbol &) {
return success(); }
328 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
336 expandInterfaceInstance(
const slang::ast::InstanceSymbol &instNode) {
337 auto prefix = (Twine(blockNamePrefix) + instNode.name +
"_").str();
338 auto lowering = std::make_unique<InterfaceLowering>();
339 Context::ValueSymbolScope scope(
context.valueSymbols);
341 auto recordMember = [&](
const slang::ast::Symbol &sym,
342 Value value) ->
void {
343 lowering->expandedMembers[&sym] = value;
344 auto nameAttr = builder.getStringAttr(sym.name);
345 lowering->expandedMembersByName[nameAttr] = value;
346 if (
auto *valueSym = sym.as_if<slang::ast::ValueSymbol>())
347 context.valueSymbols.insert(valueSym, value);
350 for (
const auto &member : instNode.body.members()) {
352 if (
const auto *nestedInst = member.as_if<slang::ast::InstanceSymbol>()) {
353 if (nestedInst->body.getDefinition().definitionKind ==
354 slang::ast::DefinitionKind::Interface)
355 return mlir::emitError(loc)
356 <<
"nested interface instances are not supported: `"
357 << nestedInst->name <<
"` inside `" << instNode.name <<
"`";
360 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
361 auto loweredType =
context.convertType(*var->getDeclaredType());
364 auto varOp = moore::VariableOp::create(
366 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
367 builder.getStringAttr(Twine(prefix) + StringRef(var->name)),
369 recordMember(*var, varOp);
373 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
374 auto loweredType =
context.convertType(*net->getDeclaredType());
378 if (netKind == moore::NetKind::Interconnect ||
379 netKind == moore::NetKind::UserDefined ||
380 netKind == moore::NetKind::Unknown)
381 return mlir::emitError(loc,
"unsupported net kind `")
382 << net->netType.name <<
"`";
383 auto netOp = moore::NetOp::create(
385 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
386 builder.getStringAttr(Twine(prefix) + StringRef(net->name)),
388 recordMember(*net, netOp);
397 for (
const auto *con : instNode.getPortConnections()) {
398 const auto *expr = con->getExpression();
399 const auto *port = con->port.as_if<slang::ast::PortSymbol>();
407 Value lvalue =
context.convertLvalueExpression(*expr);
411 recordMember(*port, lvalue);
412 if (port->internalSymbol) {
413 recordMember(*port->internalSymbol, lvalue);
419 for (
const auto &member : instNode.body.members()) {
420 switch (member.kind) {
421 case slang::ast::SymbolKind::ContinuousAssign:
422 case slang::ast::SymbolKind::ProceduralBlock:
423 case slang::ast::SymbolKind::StatementBlock:
428 auto memberLoc =
context.convertLocation(member.location);
429 if (failed(member.visit(ModuleVisitor(
context, memberLoc, prefix))))
431 if (failed(
context.flushPendingMonitors()))
435 context.interfaceInstanceStorage.push_back(std::move(lowering));
436 context.interfaceInstances.insert(
437 &instNode,
context.interfaceInstanceStorage.back().get());
442 LogicalResult visit(
const slang::ast::InstanceSymbol &instNode) {
443 using slang::ast::ArgumentDirection;
444 using slang::ast::AssignmentExpression;
445 using slang::ast::MultiPortSymbol;
446 using slang::ast::PortSymbol;
448 if (
context.predeclaredInstances.contains(&instNode))
459 auto defKind = body->getDefinition().definitionKind;
460 if (defKind == slang::ast::DefinitionKind::Interface) {
461 if (
context.interfaceInstances.lookup(&instNode))
463 return expandInterfaceInstance(instNode);
466 auto *moduleLowering =
context.convertModuleHeader(body);
469 auto module = moduleLowering->op;
470 auto moduleType =
module.getModuleType();
473 SymbolTable::setSymbolVisibility(module, SymbolTable::Visibility::Private);
480 portValues.reserve(moduleType.getNumPorts());
484 const slang::ast::InstanceSymbol *>
487 for (
const auto *con : instNode.getPortConnections()) {
488 const auto *expr = con->getExpression();
493 auto *port = con->port.as_if<PortSymbol>();
494 if (
auto *existingPort =
495 moduleLowering->portsBySyntaxNode.lookup(port->getSyntax()))
498 switch (port->direction) {
499 case ArgumentDirection::In: {
500 auto refType = moore::RefType::get(
501 cast<moore::UnpackedType>(
context.convertType(port->getType())));
503 if (
const auto *net =
504 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
505 auto netOp = moore::NetOp::create(
506 builder, loc, refType,
507 StringAttr::get(builder.getContext(), net->name),
509 auto readOp = moore::ReadOp::create(builder, loc, netOp);
510 portValues.insert({port, readOp});
511 }
else if (
const auto *var =
513 ->as_if<slang::ast::VariableSymbol>()) {
514 auto varOp = moore::VariableOp::create(
515 builder, loc, refType,
516 StringAttr::get(builder.getContext(), var->name),
nullptr);
517 auto readOp = moore::ReadOp::create(builder, loc, varOp);
518 portValues.insert({port, readOp});
520 return mlir::emitError(loc)
521 <<
"unsupported internal symbol for unconnected port `"
522 << port->name <<
"`";
529 case ArgumentDirection::Out:
532 case ArgumentDirection::InOut:
533 case ArgumentDirection::Ref: {
534 auto refType = moore::RefType::get(
535 cast<moore::UnpackedType>(
context.convertType(port->getType())));
537 if (
const auto *net =
538 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
539 auto netOp = moore::NetOp::create(
540 builder, loc, refType,
541 StringAttr::get(builder.getContext(), net->name),
543 portValues.insert({port, netOp});
544 }
else if (
const auto *var =
546 ->as_if<slang::ast::VariableSymbol>()) {
547 auto varOp = moore::VariableOp::create(
548 builder, loc, refType,
549 StringAttr::get(builder.getContext(), var->name),
nullptr);
550 portValues.insert({port, varOp});
552 return mlir::emitError(loc)
553 <<
"unsupported internal symbol for unconnected port `"
554 << port->name <<
"`";
563 if (
const auto *assign = expr->as_if<AssignmentExpression>())
564 expr = &assign->left();
569 if (
auto *port = con->port.as_if<PortSymbol>()) {
571 auto value = (port->direction == ArgumentDirection::In)
572 ?
context.convertRvalueExpression(*expr)
573 :
context.convertLvalueExpression(*expr);
576 if (
auto *existingPort =
577 moduleLowering->portsBySyntaxNode.lookup(con->port.getSyntax()))
579 portValues.insert({port, value});
586 if (
const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
588 auto value =
context.convertLvalueExpression(*expr);
592 for (
const auto *port :
llvm::reverse(multiPort->ports)) {
593 if (
auto *existingPort = moduleLowering->portsBySyntaxNode.lookup(
594 con->port.getSyntax()))
596 unsigned width = port->getType().getBitWidth();
597 auto sliceType =
context.convertType(port->getType());
600 Value slice = moore::ExtractRefOp::create(
602 moore::RefType::get(cast<moore::UnpackedType>(sliceType)), value,
605 if (port->direction == ArgumentDirection::In)
606 slice = moore::ReadOp::create(builder, loc, slice);
607 portValues.insert({port, slice});
615 if (
const auto *ifacePort =
616 con->port.as_if<slang::ast::InterfacePortSymbol>()) {
617 auto ifaceConn = con->getIfaceConn();
618 const auto *connInst =
619 ifaceConn.first->as_if<slang::ast::InstanceSymbol>();
621 ifaceConnMap[ifacePort] = connInst;
625 mlir::emitError(loc) <<
"unsupported instance port `" << con->port.name
626 <<
"` (" << slang::ast::toString(con->port.kind)
634 SmallVector<Value> inputValues(moduleLowering->numExplicitInputs);
635 SmallVector<Value> outputValues(moduleLowering->numExplicitOutputs);
637 for (
auto &port : moduleLowering->ports) {
638 auto value = portValues.lookup(&port.ast);
639 if (port.ast.direction == ArgumentDirection::Out)
640 outputValues[*port.outputIdx] = value;
642 inputValues[*port.inputIdx] = value;
648 for (
auto &fp : moduleLowering->ifacePorts) {
649 if (!fp.bodySym || !fp.origin)
652 auto it = ifaceConnMap.find(fp.origin);
653 if (it == ifaceConnMap.end()) {
655 <<
"no interface connection for port `" << fp.name <<
"`";
658 const auto *connInst = it->second;
660 auto *ifaceLowering =
context.interfaceInstances.lookup(connInst);
661 if (!ifaceLowering) {
663 <<
"interface instance `" << connInst->name <<
"` was not expanded";
667 auto valIt = ifaceLowering->expandedMembers.find(fp.bodySym);
668 if (valIt == ifaceLowering->expandedMembers.end()) {
670 <<
"unresolved interface port signal `" << fp.name <<
"`";
673 Value val = valIt->second;
675 outputValues[*fp.outputIdx] = val;
679 if (isa<moore::RefType>(val.getType()) && !isa<moore::RefType>(fp.type))
680 val = moore::ReadOp::create(builder, loc, val);
681 inputValues[*fp.inputIdx] = val;
687 for (
auto [value, type] :
688 llvm::zip(inputValues, moduleType.getInputTypes())) {
692 value =
context.materializeConversion(type, value,
false, value.getLoc());
694 return mlir::emitError(loc) <<
"unsupported port";
701 for (
const auto &hierPath :
context.hierPaths[body]) {
702 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
704 context.valueSymbols.lookup(hierPath.valueSyms.front());
705 hierPath.hierName && hierPath.direction == ArgumentDirection::In)
706 inputValues.push_back(hierValue);
710 for (
auto value : inputValues)
712 return
mlir::emitError(loc) <<
"unsupported port";
715 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
716 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
717 auto inst = moore::InstanceOp::create(
718 builder, loc, moduleType.getOutputTypes(),
719 builder.getStringAttr(Twine(blockNamePrefix) + instNode.name),
720 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
721 inputNames, outputNames);
728 for (
const auto &hierPath :
context.hierPaths[body])
729 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out) {
730 auto result = inst->getResult(*hierPath.idx);
733 for (
auto *sym : hierPath.valueSyms)
734 context.valueSymbols.insert(sym, result);
735 context.hierValueSymbols[{&instNode, hierPath.hierName}] = result;
739 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
742 Value rvalue = output;
743 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
745 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
746 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
753 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
754 auto ref =
context.valueSymbols.lookup(&varNode);
756 return mlir::emitError(loc)
757 <<
"internal error: missing predeclared variable `" << varNode.name
760 auto varOp = ref.getDefiningOp<moore::VariableOp>();
762 return mlir::emitError(loc)
763 <<
"internal error: predeclared variable `" << varNode.name
764 <<
"` is not a moore.variable";
766 if (
const auto *init = varNode.getInitializer()) {
767 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
768 auto initial =
context.convertRvalueExpression(*init, loweredType);
771 varOp.getInitialMutable().assign(initial);
778 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
779 auto ref =
context.valueSymbols.lookup(&netNode);
781 return mlir::emitError(loc) <<
"internal error: missing predeclared net `"
782 << netNode.name <<
"`";
784 auto netOp = ref.getDefiningOp<moore::NetOp>();
786 return mlir::emitError(loc) <<
"internal error: predeclared net `"
787 << netNode.name <<
"` is not a moore.net";
789 if (
const auto *init = netNode.getInitializer()) {
790 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
791 auto assignment =
context.convertRvalueExpression(*init, loweredType);
794 netOp.getAssignmentMutable().assign(assignment);
800 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
802 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
803 auto lhs =
context.convertLvalueExpression(expr.left());
807 auto rhs =
context.convertRvalueExpression(
808 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
813 if (
auto *timingCtrl = assignNode.getDelay()) {
814 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
815 auto delay =
context.convertRvalueExpression(
816 ctrl->expr, moore::TimeType::get(builder.getContext()));
819 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
822 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
827 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
832 LogicalResult convertProcedure(moore::ProcedureKind kind,
833 const slang::ast::Statement &body) {
834 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
835 return context.convertStatement(body);
836 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
837 OpBuilder::InsertionGuard guard(builder);
838 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
839 Context::ValueSymbolScope scope(
context.valueSymbols);
840 Context::VirtualInterfaceMemberScope vifMemberScope(
842 if (failed(
context.convertStatement(body)))
844 if (builder.getBlock())
845 moore::ReturnOp::create(builder, loc);
849 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
852 if (
context.options.lowerAlwaysAtStarAsComb) {
853 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
854 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
856 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
857 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
865 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
867 if (genNode.isUninstantiated)
871 SmallString<64> prefix = blockNamePrefix;
872 if (!genNode.name.empty() ||
873 genNode.getParentScope()->asSymbol().kind !=
874 slang::ast::SymbolKind::GenerateBlockArray) {
875 prefix += genNode.getExternalName();
880 for (
auto &member : genNode.members())
881 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
887 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
890 SmallString<64> prefix = blockNamePrefix;
891 prefix += genArrNode.getExternalName();
893 auto prefixBaseLen = prefix.size();
896 for (
const auto *entry : genArrNode.entries) {
898 prefix.resize(prefixBaseLen);
899 if (entry->arrayIndex)
900 prefix += entry->arrayIndex->toString();
902 Twine(entry->constructIndex).toVector(prefix);
906 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
918 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
924 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
930 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
935 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
936 if (!
context.declareFunction(subroutine))
942 LogicalResult visit(
const slang::ast::PrimitiveInstanceSymbol &prim) {
943 return context.convertPrimitiveInstance(prim);
947 template <
typename T>
948 LogicalResult visit(T &&node) {
949 mlir::emitError(loc,
"unsupported module member: ")
950 << slang::ast::toString(node.kind);
955struct ModulePredeclaration {
959 ModulePredeclaration(
Context &context)
960 : context(context), builder(context.builder) {}
962 LogicalResult declareVariable(
const slang::ast::VariableSymbol &varNode,
963 Location loc, StringRef blockNamePrefix) {
964 auto loweredType = context.
convertType(*varNode.getDeclaredType());
968 auto varOp = moore::VariableOp::create(
970 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
971 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), Value{});
974 const auto &canonTy = varNode.getType().getCanonicalType();
975 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
982 LogicalResult declareNet(
const slang::ast::NetSymbol &netNode, Location loc,
983 StringRef blockNamePrefix) {
984 auto loweredType = context.
convertType(*netNode.getDeclaredType());
989 if (netkind == moore::NetKind::Interconnect ||
990 netkind == moore::NetKind::UserDefined ||
991 netkind == moore::NetKind::Unknown)
992 return mlir::emitError(loc,
"unsupported net kind `")
993 << netNode.netType.name <<
"`";
995 auto netOp = moore::NetOp::create(
997 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
998 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
1005 getGenerateBlockPrefix(
const slang::ast::GenerateBlockSymbol &genNode,
1006 StringRef blockNamePrefix) {
1007 SmallString<64> prefix = blockNamePrefix;
1008 if (!genNode.name.empty() ||
1009 genNode.getParentScope()->asSymbol().kind !=
1010 slang::ast::SymbolKind::GenerateBlockArray) {
1011 prefix += genNode.getExternalName();
1018 predeclareStorageGenerateBlock(
const slang::ast::GenerateBlockSymbol &genNode,
1019 StringRef blockNamePrefix) {
1020 if (genNode.isUninstantiated)
1022 return predeclareStorageScope(
1023 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1026 LogicalResult predeclareInterfaceGenerateBlock(
1027 const slang::ast::GenerateBlockSymbol &genNode,
1028 StringRef blockNamePrefix) {
1029 if (genNode.isUninstantiated)
1031 return predeclareInterfaceScope(
1032 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1035 LogicalResult predeclareModuleInstanceGenerateBlock(
1036 const slang::ast::GenerateBlockSymbol &genNode,
1037 StringRef blockNamePrefix) {
1038 if (genNode.isUninstantiated)
1040 return predeclareModuleInstanceScope(
1041 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1044 LogicalResult predeclareGenerateBlockArray(
1045 const slang::ast::GenerateBlockArraySymbol &genArrNode,
1046 StringRef blockNamePrefix,
1047 llvm::function_ref<LogicalResult(
const slang::ast::GenerateBlockSymbol &,
1050 SmallString<64> prefix = blockNamePrefix;
1051 prefix += genArrNode.getExternalName();
1053 auto prefixBaseLen = prefix.size();
1055 for (
const auto *entry : genArrNode.entries) {
1056 prefix.resize(prefixBaseLen);
1057 if (entry->arrayIndex)
1058 prefix += entry->arrayIndex->toString();
1060 Twine(entry->constructIndex).toVector(prefix);
1063 if (failed(predeclareBlock(*entry, prefix)))
1069 LogicalResult predeclareStorageMember(
const slang::ast::Symbol &member,
1070 StringRef blockNamePrefix) {
1072 if (
const auto *varNode = member.as_if<slang::ast::VariableSymbol>())
1073 return declareVariable(*varNode, loc, blockNamePrefix);
1075 if (
const auto *netNode = member.as_if<slang::ast::NetSymbol>())
1076 return declareNet(*netNode, loc, blockNamePrefix);
1078 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1079 return predeclareStorageGenerateBlock(*genNode, blockNamePrefix);
1081 if (
const auto *genArrNode =
1082 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1083 return predeclareGenerateBlockArray(
1084 *genArrNode, blockNamePrefix,
1085 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1086 return predeclareStorageGenerateBlock(gen, prefix);
1092 LogicalResult predeclareInterfaceMember(
const slang::ast::Symbol &member,
1093 StringRef blockNamePrefix) {
1095 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1096 if (instNode->body.getDefinition().definitionKind ==
1097 slang::ast::DefinitionKind::Interface)
1098 return ModuleVisitor(context, loc, blockNamePrefix)
1099 .expandInterfaceInstance(*instNode);
1103 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1104 return predeclareInterfaceGenerateBlock(*genNode, blockNamePrefix);
1106 if (
const auto *genArrNode =
1107 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1108 return predeclareGenerateBlockArray(
1109 *genArrNode, blockNamePrefix,
1110 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1111 return predeclareInterfaceGenerateBlock(gen, prefix);
1117 LogicalResult predeclareModuleInstanceMember(
const slang::ast::Symbol &member,
1118 StringRef blockNamePrefix) {
1120 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1121 if (instNode->body.getDefinition().definitionKind !=
1122 slang::ast::DefinitionKind::Interface) {
1124 ModuleVisitor(context, loc, blockNamePrefix).visit(*instNode)))
1131 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1132 return predeclareModuleInstanceGenerateBlock(*genNode, blockNamePrefix);
1134 if (
const auto *genArrNode =
1135 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1136 return predeclareGenerateBlockArray(
1137 *genArrNode, blockNamePrefix,
1138 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1139 return predeclareModuleInstanceGenerateBlock(gen, prefix);
1145 LogicalResult predeclareStorageScope(
const slang::ast::Scope &scope,
1146 StringRef blockNamePrefix) {
1147 for (
auto &member : scope.members())
1148 if (failed(predeclareStorageMember(member, blockNamePrefix)))
1153 LogicalResult predeclareInterfaceScope(
const slang::ast::Scope &scope,
1154 StringRef blockNamePrefix) {
1155 for (
auto &member : scope.members())
1156 if (failed(predeclareInterfaceMember(member, blockNamePrefix)))
1161 LogicalResult predeclareModuleInstanceScope(
const slang::ast::Scope &scope,
1162 StringRef blockNamePrefix) {
1163 for (
auto &member : scope.members())
1164 if (failed(predeclareModuleInstanceMember(member, blockNamePrefix)))
1169 LogicalResult predeclareScope(
const slang::ast::Scope &scope,
1170 StringRef blockNamePrefix) {
1174 if (failed(predeclareStorageScope(scope, blockNamePrefix)))
1180 if (failed(predeclareInterfaceScope(scope, blockNamePrefix)))
1185 return predeclareModuleInstanceScope(scope, blockNamePrefix);
1196LogicalResult Context::convertCompilation() {
1202 timeScale = root.getTimeScale().value_or(slang::TimeScale());
1203 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1211 for (
auto *inst : root.topInstances)
1221 for (
auto *unit : root.compilationUnits) {
1223 for (
const auto &member : unit->members()) {
1225 if (failed(member.visit(RootVisitor(*
this, loc))))
1233 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
1234 for (
auto *inst : root.topInstances) {
1236 if (body->getDefinition().definitionKind !=
1237 slang::ast::DefinitionKind::Interface)
1244 auto *
module = moduleWorklist.front();
1252 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
1253 classMethodWorklist.reserve(
classes.size());
1255 classMethodWorklist.push_back(kv.first);
1257 for (
auto *inst : classMethodWorklist) {
1276 auto &block = varOp.getInitRegion().emplaceBlock();
1277 OpBuilder::InsertionGuard guard(
builder);
1278 builder.setInsertionPointToEnd(&block);
1283 moore::YieldOp::create(
builder, varOp.getLoc(), value);
1292 using slang::ast::ArgumentDirection;
1293 using slang::ast::MultiPortSymbol;
1294 using slang::ast::ParameterSymbol;
1295 using slang::ast::PortSymbol;
1296 using slang::ast::TypeParameterSymbol;
1301 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1302 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1309 slot = std::make_unique<ModuleLowering>();
1310 auto &lowering = *slot;
1313 OpBuilder::InsertionGuard g(
builder);
1318 auto kind =
module->getDefinition().definitionKind;
1319 if (kind != slang::ast::DefinitionKind::Module &&
1320 kind != slang::ast::DefinitionKind::Program) {
1321 mlir::emitError(loc) <<
"unsupported definition: "
1322 <<
module->getDefinition().getKindString();
1327 auto block = std::make_unique<Block>();
1328 SmallVector<hw::ModulePort> modulePorts;
1331 unsigned int outputIdx = 0, inputIdx = 0;
1332 for (
auto *symbol :
module->getPortList()) {
1333 auto handlePort = [&](const PortSymbol &port) {
1334 auto portLoc = convertLocation(port.location);
1338 auto portName =
builder.getStringAttr(port.name);
1340 std::optional<unsigned> portOutputIdx;
1341 std::optional<unsigned> portInputIdx;
1342 if (port.direction == ArgumentDirection::Out) {
1344 portOutputIdx = outputIdx++;
1348 if (port.direction != ArgumentDirection::In)
1349 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1351 arg = block->addArgument(type, portLoc);
1352 portInputIdx = inputIdx++;
1354 lowering.ports.push_back(
1355 {port, portLoc, arg, portOutputIdx, portInputIdx});
1362 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1365 auto [connSym, modportSym] = ifacePort.getConnection();
1366 const auto *ifaceInst =
1367 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1368 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1372 for (
const auto &member : modportSym->members()) {
1373 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1380 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1383 std::optional<unsigned> ifaceOutputIdx;
1384 std::optional<unsigned> ifaceInputIdx;
1385 if (mpp->direction == ArgumentDirection::Out) {
1387 modulePorts.push_back({name, type, dir});
1388 ifaceOutputIdx = outputIdx++;
1391 if (mpp->direction != ArgumentDirection::In)
1392 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1393 modulePorts.push_back({name, type, dir});
1394 arg = block->addArgument(type, portLoc);
1395 ifaceInputIdx = inputIdx++;
1397 lowering.ifacePorts.push_back(
1398 {name, dir, type, portLoc, arg, &ifacePort, mpp->internalSymbol,
1399 ifaceInst, mpp, ifaceOutputIdx, ifaceInputIdx});
1404 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1406 mlir::emitError(portLoc)
1407 <<
"unsupported interface port connection for `" << ifacePort.name
1411 for (
const auto &member : instSym->body.members()) {
1412 const slang::ast::Type *slangType =
nullptr;
1413 const slang::ast::Symbol *bodySym =
nullptr;
1414 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1415 slangType = &var->getType();
1417 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1418 slangType = &net->getType();
1426 auto name = builder.getStringAttr(Twine(portPrefix) +
1427 StringRef(bodySym->name));
1428 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1430 auto arg = block->addArgument(refType, portLoc);
1431 lowering.ifacePorts.push_back(
1433 bodySym, instSym,
nullptr, std::nullopt, inputIdx++});
1439 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1440 if (failed(handlePort(*port)))
1442 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1443 for (
auto *port : multiPort->ports)
1444 if (failed(handlePort(*port)))
1446 }
else if (
const auto *ifacePort =
1447 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1448 if (failed(handleIfacePort(*ifacePort)))
1452 <<
"unsupported module port `" << symbol->name <<
"` ("
1453 << slang::ast::toString(symbol->kind) <<
")";
1459 lowering.numExplicitOutputs = outputIdx;
1460 lowering.numExplicitInputs = inputIdx;
1463 for (
auto &hierPath : hierPaths[module]) {
1464 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1465 auto hierType =
convertType(hierPath.valueSyms.front()->getType());
1469 if (
auto hierName = hierPath.hierName) {
1471 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1472 if (hierPath.direction == ArgumentDirection::Out) {
1473 hierPath.idx = outputIdx++;
1476 hierPath.idx = inputIdx++;
1479 block->addArgument(hierType, hierLoc);
1483 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1488 auto it = orderedRootOps.upper_bound(key);
1489 if (it == orderedRootOps.end())
1490 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1492 builder.setInsertionPoint(it->second);
1496 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1497 orderedRootOps.insert(it, {key, moduleOp});
1498 moduleOp.getBodyRegion().push_back(block.release());
1499 lowering.op = moduleOp;
1503 symbolTable.insert(moduleOp);
1506 moduleWorklist.push(module);
1509 for (
const auto &port : lowering.ports)
1510 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1517 auto &lowering = *
modules[module];
1520 OpBuilder::InsertionGuard g(
builder);
1521 builder.setInsertionPointToEnd(lowering.op.getBody());
1530 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1531 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1536 for (
auto &hierPath :
hierPaths[module])
1537 if (hierPath.direction == slang::ast::ArgumentDirection::In &&
1539 auto arg = lowering.op.getBody()->getArgument(*hierPath.idx);
1540 for (
auto *sym : hierPath.valueSyms)
1548 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1551 auto getIfacePortLowering =
1557 if (
auto it = ifacePortLowerings.find(ifaceInst);
1558 it != ifacePortLowerings.end())
1561 auto lowering = std::make_unique<InterfaceLowering>();
1565 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1569 for (
auto &fp : lowering.ifacePorts) {
1572 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1581 portValue = moore::VariableOp::create(
1583 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1592 if (fp.modportPortSym)
1593 if (
auto *mppSym = fp.modportPortSym->as_if<slang::ast::ValueSymbol>())
1594 if (mppSym != valueSym)
1597 if (!fp.ifaceInstance)
1600 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1603 ifaceLowering->expandedMembers[fp.bodySym] = val;
1605 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1611 llvm::scope_exit predeclaredInstancesGuard(
1621 if (failed(ModulePredeclaration(*this).predeclareScope(*module,
"")))
1625 for (
auto &member :
module->members()) {
1626 auto loc = convertLocation(member.location);
1627 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1639 SmallVector<Value> outputs(lowering.numExplicitOutputs);
1640 for (
auto &port : lowering.ports) {
1642 if (
auto *expr = port.ast.getInternalExpr()) {
1643 value = convertLvalueExpression(*expr);
1644 }
else if (port.ast.internalSymbol) {
1645 if (
const auto *sym =
1646 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1647 value = valueSymbols.lookup(sym);
1650 return mlir::emitError(port.loc,
"unsupported port: `")
1652 <<
"` does not map to an internal symbol or expression";
1655 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1656 if (isa<moore::RefType>(value.getType()))
1657 value = moore::ReadOp::create(builder, value.getLoc(), value);
1658 outputs[*port.outputIdx] = value;
1664 Value portArg = port.arg;
1665 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1666 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1667 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1672 for (
auto &fp : lowering.ifacePorts) {
1676 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1679 Value ref = valueSymbols.lookup(valueSym);
1682 outputs[*fp.outputIdx] =
1683 moore::ReadOp::create(builder, fp.loc, ref).getResult();
1688 for (
auto &hierPath : hierPaths[module]) {
1689 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1690 if (
auto hierValue = valueSymbols.lookup(hierPath.valueSyms.front()))
1691 if (hierPath.direction == slang::ast::ArgumentDirection::Out)
1692 outputs.push_back(hierValue);
1695 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1705 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1706 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1710 OpBuilder::InsertionGuard g(
builder);
1713 for (
auto &member : package.members()) {
1715 if (failed(member.visit(PackageVisitor(*
this, loc))))
1726 auto &lowering =
functions[&subroutine];
1728 if (!lowering->op.getOperation())
1730 return lowering.get();
1733 if (!subroutine.thisVar) {
1735 SmallString<64> name;
1737 name += subroutine.name;
1739 SmallVector<Type, 1> noThis = {};
1746 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1747 moore::ClassDeclOp ownerDecl;
1749 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1750 auto &ownerLowering =
classes[classTy];
1751 ownerDecl = ownerLowering->op;
1753 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1754 << thisTy.toString();
1759 SmallString<64> qualName;
1760 qualName += ownerDecl.getSymName();
1762 qualName += subroutine.name;
1765 SmallVector<Type, 1> extraParams;
1767 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1768 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1769 extraParams.push_back(handleTy);
1779 Context &
context,
const slang::ast::SubroutineSymbol &subroutine,
1780 ArrayRef<Type> prefixParams, ArrayRef<Type> suffixParams = {}) {
1781 using slang::ast::ArgumentDirection;
1783 SmallVector<Type> inputTypes;
1784 inputTypes.append(prefixParams.begin(), prefixParams.end());
1785 SmallVector<Type, 1> outputTypes;
1787 for (
const auto *arg : subroutine.getArguments()) {
1788 auto type =
context.convertType(arg->getType());
1791 if (arg->direction == ArgumentDirection::In) {
1792 inputTypes.push_back(type);
1794 inputTypes.push_back(
1795 moore::RefType::get(cast<moore::UnpackedType>(type)));
1799 inputTypes.append(suffixParams.begin(), suffixParams.end());
1801 const auto &returnType = subroutine.getReturnType();
1802 if (!returnType.isVoid()) {
1803 auto type =
context.convertType(returnType);
1806 outputTypes.push_back(type);
1809 return FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1812static FailureOr<SmallVector<moore::DPIArgInfo>>
1814 const slang::ast::SubroutineSymbol &subroutine) {
1815 using slang::ast::ArgumentDirection;
1817 SmallVector<moore::DPIArgInfo> args;
1818 args.reserve(subroutine.getArguments().size() +
1819 (!subroutine.getReturnType().isVoid() ? 1 : 0));
1821 for (
const auto *arg : subroutine.getArguments()) {
1822 auto type =
context.convertType(arg->getType());
1825 moore::DPIArgDirection dir;
1826 switch (arg->direction) {
1827 case ArgumentDirection::In:
1828 dir = moore::DPIArgDirection::In;
1830 case ArgumentDirection::Out:
1831 dir = moore::DPIArgDirection::Out;
1833 case ArgumentDirection::InOut:
1834 dir = moore::DPIArgDirection::InOut;
1836 case ArgumentDirection::Ref:
1837 llvm_unreachable(
"'ref' is not legal for DPI functions");
1840 {StringAttr::get(
context.getContext(), arg->name), type, dir});
1843 if (!subroutine.getReturnType().isVoid()) {
1844 auto type =
context.convertType(subroutine.getReturnType());
1847 args.push_back({StringAttr::get(
context.getContext(),
"return"), type,
1848 moore::DPIArgDirection::Return});
1858 mlir::StringRef qualifiedName,
1859 llvm::SmallVectorImpl<Type> &extraParams) {
1863 OpBuilder::InsertionGuard g(
builder);
1869 builder.setInsertionPoint(it->second);
1874 SmallVector<Type> captureTypes;
1877 for (
auto *sym : capturesIt->second) {
1881 captureTypes.push_back(
1882 moore::RefType::get(cast<moore::UnpackedType>(type)));
1891 std::unique_ptr<FunctionLowering> lowering;
1892 Operation *insertedOp =
nullptr;
1897 auto setVisibilityAndExportAttr = [&](Operation *op) {
1900 builder.getStringAttr(dpiExportIt->second));
1901 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Public);
1904 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
1906 if (!subroutine.thisVar &&
1907 subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
1913 auto dpiOp = moore::DPIFuncOp::create(
1916 StringAttr::get(
getContext(), subroutine.name));
1917 setVisibilityAndExportAttr(dpiOp);
1918 lowering = std::make_unique<FunctionLowering>(dpiOp);
1920 }
else if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
1922 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
1923 setVisibilityAndExportAttr(op);
1924 lowering = std::make_unique<FunctionLowering>(op);
1929 mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
1930 setVisibilityAndExportAttr(funcOp);
1931 lowering = std::make_unique<FunctionLowering>(funcOp);
1932 insertedOp = funcOp;
1938 lowering->capturedSymbols.assign(capturesIt->second.begin(),
1939 capturesIt->second.end());
1944 functions[&subroutine] = std::move(lowering);
1958 auto *lowering =
functions.at(&subroutine).get();
1963 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
1964 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1969 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport))
1972 const bool isMethod = (subroutine.thisVar !=
nullptr);
1977 if (
const auto *classTy =
1978 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
1979 for (
auto &member : classTy->members()) {
1980 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
1983 const auto &propCanon = prop->getType().getCanonicalType();
1984 if (
const auto *vi =
1985 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
1995 SmallVector<moore::VariableOp> argVariables;
1996 auto &block = lowering->op.getFunctionBody().emplaceBlock();
2003 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
2004 auto thisArg = block.addArgument(thisType, thisLoc);
2012 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
2013 auto astArgs = subroutine.getArguments();
2014 unsigned prefixCount = isMethod ? 1 : 0;
2015 auto valInputs = llvm::ArrayRef<Type>(inputs)
2016 .drop_front(prefixCount)
2017 .take_front(astArgs.size());
2019 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
2021 auto blockArg = block.addArgument(type, loc);
2023 if (isa<moore::RefType>(type)) {
2026 OpBuilder::InsertionGuard g(
builder);
2027 builder.setInsertionPointToEnd(&block);
2029 auto shadowArg = moore::VariableOp::create(
2030 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
2031 StringAttr{}, blockArg);
2033 argVariables.push_back(shadowArg);
2036 const auto &argCanon = astArg->getType().getCanonicalType();
2037 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
2043 OpBuilder::InsertionGuard g(
builder);
2044 builder.setInsertionPointToEnd(&block);
2047 if (subroutine.returnValVar) {
2048 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
2051 returnVar = moore::VariableOp::create(
2052 builder, lowering->op->getLoc(),
2053 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
2055 valueSymbols.insert(subroutine.returnValVar, returnVar);
2063 for (
auto *sym : lowering->capturedSymbols) {
2067 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
2069 auto blockArg = block.addArgument(refType, loc);
2075 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
2083 if (isa<moore::CoroutineOp>(lowering->op.getOperation())) {
2084 moore::ReturnOp::create(
builder, lowering->op->getLoc());
2085 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
2087 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
2088 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(), read);
2090 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(),
2094 if (returnVar && returnVar.use_empty())
2095 returnVar.getDefiningOp()->erase();
2097 for (
auto var : argVariables) {
2098 if (llvm::all_of(var->getUsers(),
2099 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
2100 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
2101 user->getResult(0).replaceAllUsesWith(var.getInitial());
2113 const slang::ast::PrimitiveInstanceSymbol &prim) {
2114 if (prim.getDriveStrength().first.has_value() ||
2115 prim.getDriveStrength().second.has_value())
2117 <<
"primitive instances with explicit drive strengths are not "
2120 switch (prim.primitiveType.primitiveKind) {
2121 case slang::ast::PrimitiveSymbol::PrimitiveKind::NInput:
2124 case slang::ast::PrimitiveSymbol::PrimitiveKind::NOutput:
2127 case slang::ast::PrimitiveSymbol::PrimitiveKind::Fixed:
2132 <<
"unsupported instance of primitive `" << prim.primitiveType.name
2138 const slang::ast::PrimitiveInstanceSymbol &prim) {
2140 auto primName = prim.primitiveType.name;
2142 auto portConns = prim.getPortConnections();
2143 assert(portConns.size() >= 2 &&
2144 "n-input primitives should have at least 2 ports");
2148 portConns[0]->as<slang::ast::AssignmentExpression>().left();
2154 SmallVector<Value> inputVals;
2155 inputVals.reserve(portConns.size() - 1);
2156 for (
const auto *inputConn : portConns.subspan(1, portConns.size() - 1)) {
2160 inputVals.push_back(inputVal);
2163 Value nextInput = inputVals.front();
2165 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2167 for (Value inputVal : llvm::drop_begin(inputVals))
2169 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2173 for (Value inputVal : llvm::drop_begin(inputVals))
2175 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2179 for (Value inputVal : llvm::drop_begin(inputVals))
2181 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2184 .Case(
"nand", ([&] {
2185 for (Value inputVal : llvm::drop_begin(inputVals))
2187 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2188 return moore::NotOp::create(
builder, loc, nextInput);
2191 for (Value inputVal : llvm::drop_begin(inputVals))
2193 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2194 return moore::NotOp::create(
builder, loc, nextInput);
2196 .Case(
"xnor", ([&] {
2197 for (Value inputVal : llvm::drop_begin(inputVals))
2199 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2200 return moore::NotOp::create(
builder, loc, nextInput);
2203 mlir::emitError(loc)
2204 <<
"unsupported primitive `" << primName <<
"`";
2211 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2216 if (prim.getDelay()) {
2217 const slang::ast::Expression *delayExpr;
2218 if (
const auto *delay3 =
2219 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2220 if (delay3->expr2 || delay3->expr3)
2221 return mlir::emitError(loc) <<
"only n-input primitives that specify a "
2222 "single delay are currently supported.";
2223 delayExpr = &delay3->expr1;
2224 }
else if (
const auto *delay =
2225 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2226 delayExpr = &delay->expr;
2228 llvm_unreachable(
"unexpected delay control type in primitive instance");
2231 *delayExpr, moore::TimeType::get(
getContext()));
2234 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal, result,
2237 moore::ContinuousAssignOp::create(
builder, loc, outputVal, result);
2244 const slang::ast::PrimitiveInstanceSymbol &prim) {
2246 auto primName = prim.primitiveType.name;
2248 auto portConns = prim.getPortConnections();
2249 assert(portConns.size() >= 2 &&
2250 "n-output primitives should have at least 2 ports");
2253 SmallVector<Value> outputVals;
2254 outputVals.reserve(portConns.size() - 1);
2255 for (
const auto *outputConn : portConns.subspan(0, portConns.size() - 1)) {
2256 auto &output = outputConn->as<slang::ast::AssignmentExpression>().left();
2260 outputVals.push_back(outputVal);
2268 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2270 ([&] {
return moore::NotOp::create(
builder, loc, inputVal); }))
2272 return moore::BoolCastOp::create(
builder, loc, inputVal);
2275 mlir::emitError(loc)
2276 <<
"unsupported primitive `" << primName <<
"`";
2284 if (prim.getDelay()) {
2285 const slang::ast::Expression *delayExpr;
2286 if (
const auto *delay3 =
2287 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2288 if (delay3->expr2 || delay3->expr3)
2289 return mlir::emitError(loc)
2290 <<
"only n-output primitives that specify a "
2291 "single delay are currently supported.";
2292 delayExpr = &delay3->expr1;
2293 }
else if (
const auto *delay =
2294 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2295 delayExpr = &delay->expr;
2297 llvm_unreachable(
"unexpected delay control type in primitive instance");
2300 *delayExpr, moore::TimeType::get(
getContext()));
2305 for (
auto outputVal : outputVals) {
2306 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2311 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal,
2312 converted, delayVal);
2314 moore::ContinuousAssignOp::create(
builder, loc, outputVal, converted);
2321 const slang::ast::PrimitiveInstanceSymbol &prim) {
2322 auto primName = prim.primitiveType.name;
2327 if (primName ==
"pullup" || primName ==
"pulldown")
2331 mlir::emitError(loc) <<
"unsupported primitive `" << primName <<
"`";
2336 const slang::ast::PrimitiveInstanceSymbol &prim) {
2337 assert((prim.primitiveType.name ==
"pullup" ||
2338 prim.primitiveType.name ==
"pulldown") &&
2339 "expected pullup or pulldown primitive");
2341 assert(!prim.getDelay() &&
2342 "SystemVerilog does not allow pull gate primitives with delays");
2344 auto primName = prim.primitiveType.name;
2346 auto portConns = prim.getPortConnections();
2348 assert(portConns.size() == 1 &&
2349 "pullup/pulldown primitives should have exactly one port");
2352 portConns.front()->as<slang::ast::AssignmentExpression>().left());
2354 auto dstType = cast<moore::RefType>(portVal.getType()).getNestedType();
2355 auto dstTypeWidth = dstType.getBitSize();
2358 "expected fixed-width type for pullup/pulldown primitive");
2359 auto constVal = primName ==
"pullup" ? -1 : 0;
2360 auto c = moore::ConstantOp::create(
2362 moore::IntType::getInt(this->
getContext(), dstTypeWidth.value()),
2368 moore::ContinuousAssignOp::create(
builder, loc, portVal, converted);
2376mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
2377 const slang::ast::Type &ty) {
2378 SmallString<64> name;
2379 SmallVector<llvm::StringRef, 8> parts;
2381 const slang::ast::Scope *scope = ty.getParentScope();
2383 const auto &sym = scope->asSymbol();
2385 case slang::ast::SymbolKind::Root:
2388 case slang::ast::SymbolKind::InstanceBody:
2389 case slang::ast::SymbolKind::Instance:
2390 case slang::ast::SymbolKind::Package:
2391 case slang::ast::SymbolKind::ClassType:
2392 if (!sym.name.empty())
2393 parts.push_back(sym.name);
2398 scope = sym.getParentScope();
2401 for (
auto p :
llvm::reverse(parts)) {
2406 return mlir::StringAttr::get(ctx.
getContext(), name);
2411std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
2413 const slang::ast::ClassType &cls) {
2417 mlir::SymbolRefAttr base;
2418 if (
const auto *b = cls.getBaseClass())
2419 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
2422 SmallVector<mlir::Attribute> impls;
2423 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
2424 impls.reserve(ifaces.size());
2425 for (
const auto *iface : ifaces)
2426 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
2427 fullyQualifiedClassName(
context, *iface)));
2430 mlir::ArrayAttr implArr =
2431 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
2433 return {base, implArr};
2438struct ClassDeclVisitorBase {
2444 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
2448 return context.convertLocation(sloc);
2454struct ClassPropertyVisitor : ClassDeclVisitorBase {
2455 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2458 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2459 if (!classLowering.
op.getBody().empty())
2462 OpBuilder::InsertionGuard ig(builder);
2464 Block *body = &classLowering.
op.getBody().emplaceBlock();
2465 builder.setInsertionPointToEnd(body);
2468 for (
const auto &mem : classAST.members()) {
2469 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
2470 if (failed(prop->visit(*
this)))
2479 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
2481 auto ty =
context.convertType(prop.getType());
2485 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
2486 moore::ClassPropertyDeclOp::create(builder, loc, prop.name, ty);
2494 if (!
context.globalVariables.lookup(&prop))
2495 return context.convertGlobalVariable(prop);
2500 LogicalResult visit(
const slang::ast::ClassType &cls) {
2501 return context.buildClassProperties(cls);
2505 template <
typename T>
2506 LogicalResult visit(T &&) {
2513struct ClassMethodVisitor : ClassDeclVisitorBase {
2514 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2517 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2521 if (classLowering.
op.getBody().empty())
2524 OpBuilder::InsertionGuard ig(builder);
2525 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2528 for (
const auto &mem : classAST.members()) {
2529 if (failed(mem.visit(*
this)))
2538 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2544 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2548 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2554 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2557 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2562 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2567 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2572 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2573 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2574 static bool remarkEmitted =
false;
2578 mlir::emitRemark(classLowering.
op.getLoc())
2579 <<
"Class builtin functions (needed for randomization, constraints, "
2580 "and covergroups) are not yet supported and will be dropped "
2582 remarkEmitted =
true;
2586 const mlir::UnitAttr isVirtual =
2587 (fn.flags & slang::ast::MethodFlags::Virtual)
2588 ? UnitAttr::get(
context.getContext())
2595 if (fn.flags & slang::ast::MethodFlags::Pure) {
2597 SmallVector<Type, 1> extraParams;
2599 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2601 moore::ClassHandleType::get(
context.getContext(), classSym);
2602 extraParams.push_back(handleTy);
2606 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2610 moore::ClassMethodDeclOp::create(builder, loc, fn.name, funcTy,
nullptr);
2614 auto *lowering =
context.declareFunction(fn);
2623 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2625 moore::ClassMethodDeclOp::create(
2626 builder, loc, fn.name, fnTy,
2627 SymbolRefAttr::get(lowering->op.getNameAttr()));
2644 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2645 const auto *externImpl = fn.getSubroutine();
2649 <<
"Didn't find an implementation matching the forward declaration "
2654 return visit(*externImpl);
2658 LogicalResult visit(
const slang::ast::ClassType &cls) {
2659 if (failed(
context.buildClassProperties(cls)))
2661 return context.materializeClassMethods(cls);
2665 template <
typename T>
2666 LogicalResult visit(T &&node) {
2667 Location loc = UnknownLoc::get(
context.getContext());
2668 if constexpr (
requires { node.location; })
2670 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2671 << slang::ast::toString(node.kind);
2679 auto &lowering =
classes[&cls];
2681 return lowering.get();
2682 lowering = std::make_unique<ClassLowering>();
2687 OpBuilder::InsertionGuard g(
builder);
2693 builder.setInsertionPoint(it->second);
2695 auto symName = fullyQualifiedClassName(*
this, cls);
2697 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2699 moore::ClassDeclOp::create(
builder, loc, symName, base, impls);
2701 SymbolTable::setSymbolVisibility(classDeclOp,
2702 SymbolTable::Visibility::Public);
2704 lowering->op = classDeclOp;
2707 return lowering.get();
2714 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2715 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2722 if (classdecl.getBaseClass()) {
2723 if (
const auto *baseClassDecl =
2724 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2735 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2742 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2743 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2746 auto *lowering =
classes[&classdecl].get();
2753 if (classdecl.getBaseClass()) {
2754 if (
const auto *baseClassDecl =
2755 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2761 return ClassMethodVisitor(*
this, *lowering).run(classdecl);
2771 OpBuilder::InsertionGuard g(
builder);
2777 builder.setInsertionPoint(it->second);
2781 SmallString<64> symName;
2785 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2786 if (
const auto *parentScope = classVar->getParentScope()) {
2787 if (
const auto *parentClass =
2788 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2789 symName = fullyQualifiedClassName(*
this, *parentClass);
2791 mlir::emitError(loc)
2792 <<
"Could not access parent class of class property "
2797 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2802 symName += var.name;
2805 symName += var.name;
2814 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2815 cast<moore::UnpackedType>(type));
2826 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)
CaptureMap analyzeFunctionCaptures(const slang::ast::RootSymbol &root)
Analyze the AST rooted at root to determine which variables each function captures.
const slang::ast::InstanceBodySymbol * getCanonicalBody(const slang::ast::InstanceSymbol &inst)
Get the slang canonical body for the given instance, if there is one.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
bool debugInfo
Generate debug information in the form of debug dialect ops in the IR.
circt::moore::ClassDeclOp op
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
FunctionLowering * declareCallableImpl(const slang::ast::SubroutineSymbol &subroutine, mlir::StringRef qualifiedName, llvm::SmallVectorImpl< Type > &extraParams)
Helper function to extract the commonalities in lowering of functions and methods.
ModuleLowering * convertModuleHeader(const slang::ast::InstanceBodySymbol *module)
Convert a module and its ports to an empty module op in the IR.
std::queue< const slang::ast::SubroutineSymbol * > functionWorklist
A list of functions for which the declaration has been created, but the body has not been defined yet...
Value convertLvalueExpression(const slang::ast::Expression &expr)
LogicalResult registerVirtualInterfaceMembers(const slang::ast::ValueSymbol &base, const slang::ast::VirtualInterfaceType &type, Location loc)
Register the interface members of a virtual interface base symbol for use in later expression convers...
Value materializeConstant(const slang::ConstantValue &constant, const slang::ast::Type &type, Location loc)
Helper function to materialize a ConstantValue as an SSA value.
LogicalResult convertModuleBody(const slang::ast::InstanceBodySymbol *module)
Convert a module's body to the corresponding IR ops.
LogicalResult materializeClassMethods(const slang::ast::ClassType &classdecl)
DenseMap< const slang::ast::ValueSymbol *, moore::GlobalVariableOp > globalVariables
A table of defined global variables that may be referred to by name in expressions.
slang::ast::Compilation & compilation
LogicalResult flushPendingMonitors()
Process any pending $monitor calls and generate the monitoring procedures at module level.
LogicalResult convertNInputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
OpBuilder builder
The builder used to create IR operations.
std::queue< const slang::ast::InstanceBodySymbol * > moduleWorklist
A list of modules for which the header has been created, but the body has not been converted yet.
LogicalResult convertGlobalVariable(const slang::ast::VariableSymbol &var)
Convert a variable to a moore.global_variable operation.
DenseSet< const slang::ast::InstanceSymbol * > predeclaredInstances
Module instances already emitted by the predeclaration pass.
CaptureMap functionCaptures
Pre-computed capture analysis: maps each function to the set of non-local, non-global variables it ca...
DenseMap< const slang::ast::ClassType *, std::unique_ptr< ClassLowering > > classes
Classes that have already been converted.
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.
DenseMap< const slang::ast::SubroutineSymbol *, std::unique_ptr< FunctionLowering > > functions
Functions that have already been converted.
slang::TimeScale timeScale
The time scale currently in effect.
ClassLowering * declareClass(const slang::ast::ClassType &cls)
VirtualInterfaceMembers::ScopeTy VirtualInterfaceMemberScope
LogicalResult convertFixedPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
ValueSymbols valueSymbols
DenseMap< const slang::ast::SubroutineSymbol *, std::string > dpiExportCNames
DPI-C export directives keyed by the SystemVerilog subroutine they expose.
ValueSymbols::ScopeTy ValueSymbolScope
const ImportVerilogOptions & options
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
SmallVector< std::unique_ptr< InterfaceLowering > > interfaceInstanceStorage
Owning storage for InterfaceLowering objects because ScopedHashTable stores values by copy.
VirtualInterfaceMembers virtualIfaceMembers
Value currentThisRef
Variable to track the value of the current function's implicit this reference.
const slang::SourceManager & sourceManager
Value materializeConversion(Type type, Value value, bool isSigned, Location loc, bool fallible=false)
Helper function to insert the necessary operations to cast a value from one type to another.
void traverseInstanceBody(const slang::ast::InstanceSymbol &symbol)
void populateAssertionClocks()
Generates a map from assertions to clocks using Slang's analysis.
std::map< LocationKey, Operation * > orderedRootOps
The top-level operations ordered by their Slang source location.
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.