10#include "slang/ast/Compilation.h"
11#include "slang/ast/symbols/ClassSymbols.h"
12#include "llvm/ADT/ScopeExit.h"
15using namespace ImportVerilog;
22 SmallString<64> &prefix) {
23 if (symbol.kind != slang::ast::SymbolKind::Package)
26 if (!symbol.name.empty()) {
27 prefix += symbol.name;
44 BaseVisitor(
Context &context, Location loc)
45 : context(context), loc(loc), builder(context.builder) {}
48 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
54 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
59 LogicalResult visit(
const slang::ast::ClassType &classdecl) {
69 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
74 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
75 LogicalResult visit(
const slang::ast::ForwardingTypedefSymbol &) {
80 LogicalResult visit(
const slang::ast::ExplicitImportSymbol &) {
83 LogicalResult visit(
const slang::ast::WildcardImportSymbol &) {
88 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
93 LogicalResult visit(
const slang::ast::ElabSystemTaskSymbol &) {
98 LogicalResult visit(
const slang::ast::ParameterSymbol ¶m) {
99 visitParameter(param);
103 LogicalResult visit(
const slang::ast::SpecparamSymbol ¶m) {
104 visitParameter(param);
108 template <
class Node>
109 void visitParameter(
const Node ¶m) {
119 if (builder.getInsertionBlock()->getParentOp() == context.
intoModuleOp)
120 context.
orderedRootOps.insert({param.location, value.getDefiningOp()});
124 SmallString<64> paramName;
126 paramName += param.name;
128 debug::VariableOp::create(builder, loc, builder.getStringAttr(paramName),
139struct RootVisitor :
public BaseVisitor {
140 using BaseVisitor::BaseVisitor;
141 using BaseVisitor::visit;
144 LogicalResult visit(
const slang::ast::PackageSymbol &package) {
145 return context.convertPackage(package);
149 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
150 return context.convertFunction(subroutine);
154 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
155 return context.convertGlobalVariable(var);
159 template <
typename T>
160 LogicalResult visit(T &&node) {
161 mlir::emitError(loc,
"unsupported construct: ")
162 << slang::ast::toString(node.kind);
173struct PackageVisitor :
public BaseVisitor {
174 using BaseVisitor::BaseVisitor;
175 using BaseVisitor::visit;
178 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
179 return context.convertFunction(subroutine);
183 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
184 return context.convertGlobalVariable(var);
188 template <
typename T>
189 LogicalResult visit(T &&node) {
190 mlir::emitError(loc,
"unsupported package member: ")
191 << slang::ast::toString(node.kind);
201static moore::ProcedureKind
204 case slang::ast::ProceduralBlockKind::Always:
205 return moore::ProcedureKind::Always;
206 case slang::ast::ProceduralBlockKind::AlwaysComb:
207 return moore::ProcedureKind::AlwaysComb;
208 case slang::ast::ProceduralBlockKind::AlwaysLatch:
209 return moore::ProcedureKind::AlwaysLatch;
210 case slang::ast::ProceduralBlockKind::AlwaysFF:
211 return moore::ProcedureKind::AlwaysFF;
212 case slang::ast::ProceduralBlockKind::Initial:
213 return moore::ProcedureKind::Initial;
214 case slang::ast::ProceduralBlockKind::Final:
215 return moore::ProcedureKind::Final;
217 llvm_unreachable(
"all procedure kinds handled");
222 case slang::ast::NetType::Supply0:
223 return moore::NetKind::Supply0;
224 case slang::ast::NetType::Supply1:
225 return moore::NetKind::Supply1;
226 case slang::ast::NetType::Tri:
227 return moore::NetKind::Tri;
228 case slang::ast::NetType::TriAnd:
229 return moore::NetKind::TriAnd;
230 case slang::ast::NetType::TriOr:
231 return moore::NetKind::TriOr;
232 case slang::ast::NetType::TriReg:
233 return moore::NetKind::TriReg;
234 case slang::ast::NetType::Tri0:
235 return moore::NetKind::Tri0;
236 case slang::ast::NetType::Tri1:
237 return moore::NetKind::Tri1;
238 case slang::ast::NetType::UWire:
239 return moore::NetKind::UWire;
240 case slang::ast::NetType::Wire:
241 return moore::NetKind::Wire;
242 case slang::ast::NetType::WAnd:
243 return moore::NetKind::WAnd;
244 case slang::ast::NetType::WOr:
245 return moore::NetKind::WOr;
246 case slang::ast::NetType::Interconnect:
247 return moore::NetKind::Interconnect;
248 case slang::ast::NetType::UserDefined:
249 return moore::NetKind::UserDefined;
250 case slang::ast::NetType::Unknown:
251 return moore::NetKind::Unknown;
253 llvm_unreachable(
"all net kinds handled");
257struct ModuleVisitor :
public BaseVisitor {
258 using BaseVisitor::visit;
262 StringRef blockNamePrefix;
264 ModuleVisitor(
Context &
context, Location loc, StringRef blockNamePrefix =
"")
265 : BaseVisitor(
context, loc), blockNamePrefix(blockNamePrefix) {}
268 LogicalResult visit(
const slang::ast::PortSymbol &) {
return success(); }
269 LogicalResult visit(
const slang::ast::MultiPortSymbol &) {
return success(); }
270 LogicalResult visit(
const slang::ast::InterfacePortSymbol &) {
275 LogicalResult visit(
const slang::ast::GenvarSymbol &genvarNode) {
280 LogicalResult visit(
const slang::ast::DefParamSymbol &) {
return success(); }
284 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
292 expandInterfaceInstance(
const slang::ast::InstanceSymbol &instNode) {
293 auto prefix = (Twine(blockNamePrefix) + instNode.name +
"_").str();
294 auto lowering = std::make_unique<InterfaceLowering>();
296 auto recordMember = [&](
const slang::ast::Symbol &sym,
297 Value value) ->
void {
298 lowering->expandedMembers[&sym] = value;
299 auto nameAttr = builder.getStringAttr(sym.name);
300 lowering->expandedMembersByName[nameAttr] = value;
303 for (
const auto &member : instNode.body.members()) {
305 if (
const auto *nestedInst = member.as_if<slang::ast::InstanceSymbol>()) {
306 if (nestedInst->body.getDefinition().definitionKind ==
307 slang::ast::DefinitionKind::Interface)
308 return mlir::emitError(loc)
309 <<
"nested interface instances are not supported: `"
310 << nestedInst->name <<
"` inside `" << instNode.name <<
"`";
313 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
314 auto loweredType =
context.convertType(*var->getDeclaredType());
317 auto varOp = moore::VariableOp::create(
319 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
320 builder.getStringAttr(Twine(prefix) + StringRef(var->name)),
322 recordMember(*var, varOp);
326 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
327 auto loweredType =
context.convertType(*net->getDeclaredType());
331 if (netKind == moore::NetKind::Interconnect ||
332 netKind == moore::NetKind::UserDefined ||
333 netKind == moore::NetKind::Unknown)
334 return mlir::emitError(loc,
"unsupported net kind `")
335 << net->netType.name <<
"`";
336 auto netOp = moore::NetOp::create(
338 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
339 builder.getStringAttr(Twine(prefix) + StringRef(net->name)),
341 recordMember(*net, netOp);
350 for (
const auto *con : instNode.getPortConnections()) {
351 const auto *expr = con->getExpression();
352 const auto *port = con->port.as_if<slang::ast::PortSymbol>();
360 Value lvalue =
context.convertLvalueExpression(*expr);
364 recordMember(*port, lvalue);
365 if (port->internalSymbol) {
366 recordMember(*port->internalSymbol, lvalue);
370 context.interfaceInstanceStorage.push_back(std::move(lowering));
371 context.interfaceInstances.insert(
372 &instNode,
context.interfaceInstanceStorage.back().get());
377 LogicalResult visit(
const slang::ast::InstanceSymbol &instNode) {
378 using slang::ast::ArgumentDirection;
379 using slang::ast::AssignmentExpression;
380 using slang::ast::MultiPortSymbol;
381 using slang::ast::PortSymbol;
385 auto defKind = instNode.body.getDefinition().definitionKind;
386 if (defKind == slang::ast::DefinitionKind::Interface)
387 return expandInterfaceInstance(instNode);
389 auto *moduleLowering =
context.convertModuleHeader(&instNode.body);
392 auto module = moduleLowering->op;
393 auto moduleType =
module.getModuleType();
396 SymbolTable::setSymbolVisibility(module, SymbolTable::Visibility::Private);
403 portValues.reserve(moduleType.getNumPorts());
407 const slang::ast::InstanceSymbol *>
410 for (
const auto *con : instNode.getPortConnections()) {
411 const auto *expr = con->getExpression();
416 auto *port = con->port.as_if<PortSymbol>();
417 if (
auto *existingPort =
418 moduleLowering->portsBySyntaxNode.lookup(port->getSyntax()))
421 switch (port->direction) {
422 case ArgumentDirection::In: {
423 auto refType = moore::RefType::get(
424 cast<moore::UnpackedType>(
context.convertType(port->getType())));
426 if (
const auto *net =
427 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
428 auto netOp = moore::NetOp::create(
429 builder, loc, refType,
430 StringAttr::get(builder.getContext(), net->name),
432 auto readOp = moore::ReadOp::create(builder, loc, netOp);
433 portValues.insert({port, readOp});
434 }
else if (
const auto *var =
436 ->as_if<slang::ast::VariableSymbol>()) {
437 auto varOp = moore::VariableOp::create(
438 builder, loc, refType,
439 StringAttr::get(builder.getContext(), var->name),
nullptr);
440 auto readOp = moore::ReadOp::create(builder, loc, varOp);
441 portValues.insert({port, readOp});
443 return mlir::emitError(loc)
444 <<
"unsupported internal symbol for unconnected port `"
445 << port->name <<
"`";
452 case ArgumentDirection::Out:
455 case ArgumentDirection::InOut:
456 case ArgumentDirection::Ref: {
457 auto refType = moore::RefType::get(
458 cast<moore::UnpackedType>(
context.convertType(port->getType())));
460 if (
const auto *net =
461 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
462 auto netOp = moore::NetOp::create(
463 builder, loc, refType,
464 StringAttr::get(builder.getContext(), net->name),
466 portValues.insert({port, netOp});
467 }
else if (
const auto *var =
469 ->as_if<slang::ast::VariableSymbol>()) {
470 auto varOp = moore::VariableOp::create(
471 builder, loc, refType,
472 StringAttr::get(builder.getContext(), var->name),
nullptr);
473 portValues.insert({port, varOp});
475 return mlir::emitError(loc)
476 <<
"unsupported internal symbol for unconnected port `"
477 << port->name <<
"`";
486 if (
const auto *assign = expr->as_if<AssignmentExpression>())
487 expr = &assign->left();
492 if (
auto *port = con->port.as_if<PortSymbol>()) {
494 auto value = (port->direction == ArgumentDirection::In)
495 ?
context.convertRvalueExpression(*expr)
496 :
context.convertLvalueExpression(*expr);
499 if (
auto *existingPort =
500 moduleLowering->portsBySyntaxNode.lookup(con->port.getSyntax()))
502 portValues.insert({port, value});
509 if (
const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
511 auto value =
context.convertLvalueExpression(*expr);
515 for (
const auto *port :
llvm::reverse(multiPort->ports)) {
516 if (
auto *existingPort = moduleLowering->portsBySyntaxNode.lookup(
517 con->port.getSyntax()))
519 unsigned width = port->getType().getBitWidth();
520 auto sliceType =
context.convertType(port->getType());
523 Value slice = moore::ExtractRefOp::create(
525 moore::RefType::get(cast<moore::UnpackedType>(sliceType)), value,
528 if (port->direction == ArgumentDirection::In)
529 slice = moore::ReadOp::create(builder, loc, slice);
530 portValues.insert({port, slice});
538 if (
const auto *ifacePort =
539 con->port.as_if<slang::ast::InterfacePortSymbol>()) {
540 auto ifaceConn = con->getIfaceConn();
541 const auto *connInst =
542 ifaceConn.first->as_if<slang::ast::InstanceSymbol>();
544 ifaceConnMap[ifacePort] = connInst;
548 mlir::emitError(loc) <<
"unsupported instance port `" << con->port.name
549 <<
"` (" << slang::ast::toString(con->port.kind)
555 SmallVector<Value> inputValues;
556 SmallVector<Value> outputValues;
557 inputValues.reserve(moduleType.getNumInputs());
558 outputValues.reserve(moduleType.getNumOutputs());
560 for (
auto &port : moduleLowering->ports) {
561 auto value = portValues.lookup(&port.ast);
562 if (port.ast.direction == ArgumentDirection::Out)
563 outputValues.push_back(value);
565 inputValues.push_back(value);
571 for (
auto &fp : moduleLowering->ifacePorts) {
572 if (!fp.bodySym || !fp.origin)
575 auto it = ifaceConnMap.find(fp.origin);
576 if (it == ifaceConnMap.end()) {
578 <<
"no interface connection for port `" << fp.name <<
"`";
581 const auto *connInst = it->second;
583 auto *ifaceLowering =
context.interfaceInstances.lookup(connInst);
584 if (!ifaceLowering) {
586 <<
"interface instance `" << connInst->name <<
"` was not expanded";
590 auto valIt = ifaceLowering->expandedMembers.find(fp.bodySym);
591 if (valIt == ifaceLowering->expandedMembers.end()) {
593 <<
"unresolved interface port signal `" << fp.name <<
"`";
596 Value val = valIt->second;
598 outputValues.push_back(val);
602 if (isa<moore::RefType>(val.getType()) && !isa<moore::RefType>(fp.type))
603 val = moore::ReadOp::create(builder, loc, val);
604 inputValues.push_back(val);
609 for (
auto [value, type] :
610 llvm::zip(inputValues, moduleType.getInputTypes())) {
612 value =
context.materializeConversion(type, value,
false, value.getLoc());
614 return mlir::emitError(loc) <<
"unsupported port";
619 for (
const auto &hierPath :
context.hierPaths[&instNode.body])
620 if (auto hierValue =
context.valueSymbols.lookup(hierPath.valueSym);
621 hierPath.hierName && hierPath.direction == ArgumentDirection::In)
622 inputValues.push_back(hierValue);
625 for (
auto value : inputValues)
627 return
mlir::emitError(loc) <<
"unsupported port";
630 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
631 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
632 auto inst = moore::InstanceOp::create(
633 builder, loc, moduleType.getOutputTypes(),
634 builder.getStringAttr(Twine(blockNamePrefix) + instNode.name),
635 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
636 inputNames, outputNames);
639 for (
const auto &hierPath :
context.hierPaths[&instNode.body])
640 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out)
641 context.valueSymbols.insert(hierPath.valueSym,
642 inst->getResult(*hierPath.idx));
645 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
648 Value rvalue = output;
649 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
651 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
652 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
659 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
660 auto loweredType =
context.convertType(*varNode.getDeclaredType());
665 if (
const auto *init = varNode.getInitializer()) {
666 initial =
context.convertRvalueExpression(*init, loweredType);
671 auto varOp = moore::VariableOp::create(
673 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
674 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), initial);
675 context.valueSymbols.insert(&varNode, varOp);
676 const auto &canonTy = varNode.getType().getCanonicalType();
677 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
678 if (failed(
context.registerVirtualInterfaceMembers(varNode, *vi, loc)))
684 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
685 auto loweredType =
context.convertType(*netNode.getDeclaredType());
690 if (
const auto *init = netNode.getInitializer()) {
691 assignment =
context.convertRvalueExpression(*init, loweredType);
697 if (netkind == moore::NetKind::Interconnect ||
698 netkind == moore::NetKind::UserDefined ||
699 netkind == moore::NetKind::Unknown)
700 return mlir::emitError(loc,
"unsupported net kind `")
701 << netNode.netType.name <<
"`";
703 auto netOp = moore::NetOp::create(
705 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
706 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
708 context.valueSymbols.insert(&netNode, netOp);
713 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
715 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
716 auto lhs =
context.convertLvalueExpression(expr.left());
720 auto rhs =
context.convertRvalueExpression(
721 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
726 if (
auto *timingCtrl = assignNode.getDelay()) {
727 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
728 auto delay =
context.convertRvalueExpression(
729 ctrl->expr, moore::TimeType::get(builder.getContext()));
732 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
735 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
740 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
745 LogicalResult convertProcedure(moore::ProcedureKind kind,
746 const slang::ast::Statement &body) {
747 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
748 return context.convertStatement(body);
749 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
750 OpBuilder::InsertionGuard guard(builder);
751 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
752 Context::ValueSymbolScope scope(
context.valueSymbols);
753 Context::VirtualInterfaceMemberScope vifMemberScope(
755 if (failed(
context.convertStatement(body)))
757 if (builder.getBlock())
758 moore::ReturnOp::create(builder, loc);
762 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
765 if (
context.options.lowerAlwaysAtStarAsComb) {
766 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
767 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
769 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
770 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
778 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
780 if (genNode.isUninstantiated)
784 SmallString<64> prefix = blockNamePrefix;
785 if (!genNode.name.empty() ||
786 genNode.getParentScope()->asSymbol().kind !=
787 slang::ast::SymbolKind::GenerateBlockArray) {
788 prefix += genNode.getExternalName();
793 for (
auto &member : genNode.members())
794 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
800 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
803 SmallString<64> prefix = blockNamePrefix;
804 prefix += genArrNode.getExternalName();
806 auto prefixBaseLen = prefix.size();
809 for (
const auto *entry : genArrNode.entries) {
811 prefix.resize(prefixBaseLen);
812 if (entry->arrayIndex)
813 prefix += entry->arrayIndex->toString();
815 Twine(entry->constructIndex).toVector(prefix);
819 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
831 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
837 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
843 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
848 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
849 return context.convertFunction(subroutine);
853 template <
typename T>
854 LogicalResult visit(T &&node) {
855 mlir::emitError(loc,
"unsupported module member: ")
856 << slang::ast::toString(node.kind);
868LogicalResult Context::convertCompilation() {
874 timeScale = root.getTimeScale().value_or(slang::TimeScale());
875 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
879 for (
auto *inst : root.topInstances)
886 for (
auto *unit : root.compilationUnits) {
887 for (
const auto &member : unit->members()) {
889 if (failed(member.visit(RootVisitor(*
this, loc))))
897 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
898 for (
auto *inst : root.topInstances)
899 if (inst->body.getDefinition().definitionKind !=
900 slang::ast::DefinitionKind::Interface)
906 auto *
module = moduleWorklist.front();
914 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
915 classMethodWorklist.reserve(
classes.size());
917 classMethodWorklist.push_back(kv.first);
919 for (
auto *inst : classMethodWorklist) {
927 auto &block = varOp.getInitRegion().emplaceBlock();
928 OpBuilder::InsertionGuard guard(
builder);
929 builder.setInsertionPointToEnd(&block);
934 moore::YieldOp::create(
builder, varOp.getLoc(), value);
947 using slang::ast::ArgumentDirection;
948 using slang::ast::MultiPortSymbol;
949 using slang::ast::ParameterSymbol;
950 using slang::ast::PortSymbol;
951 using slang::ast::TypeParameterSymbol;
956 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
957 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
959 auto parameters =
module->getParameters();
960 bool hasModuleSame =
false;
964 for (
auto const &existingModule :
modules) {
965 if (module->getDeclaringDefinition() ==
966 existingModule.getFirst()->getDeclaringDefinition()) {
967 auto moduleParameters = existingModule.getFirst()->getParameters();
968 hasModuleSame =
true;
969 for (
auto it1 = parameters.begin(), it2 = moduleParameters.begin();
970 it1 != parameters.end() && it2 != moduleParameters.end();
973 if (it1 == parameters.end() || it2 == moduleParameters.end()) {
974 hasModuleSame =
false;
977 const auto *para1 = (*it1)->symbol.as_if<ParameterSymbol>();
978 const auto *para2 = (*it2)->symbol.as_if<ParameterSymbol>();
980 if ((para1 ==
nullptr) ^ (para2 ==
nullptr)) {
981 hasModuleSame =
false;
985 if (para1 !=
nullptr) {
986 hasModuleSame = para1->getValue() == para2->getValue();
989 if (para1 ==
nullptr) {
991 (*it1)->symbol.as<TypeParameterSymbol>().getTypeAlias());
993 (*it2)->symbol.as<TypeParameterSymbol>().getTypeAlias());
994 hasModuleSame = para1Type == para2Type;
1000 module = existingModule.first;
1009 slot = std::make_unique<ModuleLowering>();
1010 auto &lowering = *slot;
1013 OpBuilder::InsertionGuard g(
builder);
1018 auto kind =
module->getDefinition().definitionKind;
1019 if (kind != slang::ast::DefinitionKind::Module &&
1020 kind != slang::ast::DefinitionKind::Program) {
1021 mlir::emitError(loc) <<
"unsupported definition: "
1022 <<
module->getDefinition().getKindString();
1027 auto block = std::make_unique<Block>();
1028 SmallVector<hw::ModulePort> modulePorts;
1031 unsigned int outputIdx = 0, inputIdx = 0;
1032 for (
auto *symbol :
module->getPortList()) {
1033 auto handlePort = [&](const PortSymbol &port) {
1034 auto portLoc = convertLocation(port.location);
1038 auto portName =
builder.getStringAttr(port.name);
1040 if (port.direction == ArgumentDirection::Out) {
1046 if (port.direction != ArgumentDirection::In)
1047 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1049 arg = block->addArgument(type, portLoc);
1052 lowering.ports.push_back({port, portLoc, arg});
1059 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1062 auto [connSym, modportSym] = ifacePort.getConnection();
1063 const auto *ifaceInst =
1064 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1065 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1069 for (
const auto &member : modportSym->members()) {
1070 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1077 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1080 if (mpp->direction == ArgumentDirection::Out) {
1082 modulePorts.push_back({name, type, dir});
1086 if (mpp->direction != ArgumentDirection::In)
1087 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1088 modulePorts.push_back({name, type, dir});
1089 arg = block->addArgument(type, portLoc);
1092 lowering.ifacePorts.push_back({name, dir, type, portLoc, arg,
1093 &ifacePort, mpp->internalSymbol,
1099 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1101 mlir::emitError(portLoc)
1102 <<
"unsupported interface port connection for `" << ifacePort.name
1106 for (
const auto &member : instSym->body.members()) {
1107 const slang::ast::Type *slangType =
nullptr;
1108 const slang::ast::Symbol *bodySym =
nullptr;
1109 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1110 slangType = &var->getType();
1112 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1113 slangType = &net->getType();
1121 auto name = builder.getStringAttr(Twine(portPrefix) +
1122 StringRef(bodySym->name));
1123 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1125 auto arg = block->addArgument(refType, portLoc);
1128 portLoc, arg, &ifacePort, bodySym,
1135 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1136 if (failed(handlePort(*port)))
1138 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1139 for (
auto *port : multiPort->ports)
1140 if (failed(handlePort(*port)))
1142 }
else if (
const auto *ifacePort =
1143 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1144 if (failed(handleIfacePort(*ifacePort)))
1148 <<
"unsupported module port `" << symbol->name <<
"` ("
1149 << slang::ast::toString(symbol->kind) <<
")";
1155 for (
auto &hierPath : hierPaths[module]) {
1156 auto hierType =
convertType(hierPath.valueSym->getType());
1160 if (
auto hierName = hierPath.hierName) {
1162 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1163 if (hierPath.direction == ArgumentDirection::Out) {
1164 hierPath.idx = outputIdx++;
1167 hierPath.idx = inputIdx++;
1170 block->addArgument(hierType, hierLoc);
1174 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1178 auto it = orderedRootOps.upper_bound(module->location);
1179 if (it == orderedRootOps.end())
1180 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1182 builder.setInsertionPoint(it->second);
1186 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1187 orderedRootOps.insert(it, {
module->location, moduleOp});
1188 moduleOp.getBodyRegion().push_back(block.release());
1189 lowering.op = moduleOp;
1193 symbolTable.insert(moduleOp);
1196 moduleWorklist.push(module);
1199 for (
const auto &port : lowering.ports)
1200 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1209 auto &lowering = *
modules[module];
1210 OpBuilder::InsertionGuard g(
builder);
1211 builder.setInsertionPointToEnd(lowering.op.getBody());
1220 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1221 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1226 for (
auto &hierPath :
hierPaths[module])
1227 if (hierPath.direction == slang::ast::ArgumentDirection::In && hierPath.idx)
1229 lowering.op.getBody()->getArgument(*hierPath.idx));
1235 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1238 auto getIfacePortLowering =
1244 if (
auto it = ifacePortLowerings.find(ifaceInst);
1245 it != ifacePortLowerings.end())
1248 auto lowering = std::make_unique<InterfaceLowering>();
1252 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1256 for (
auto &fp : lowering.ifacePorts) {
1259 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1267 auto varOp = moore::VariableOp::create(
1269 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1276 if (!fp.ifaceInstance)
1279 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1282 ifaceLowering->expandedMembers[fp.bodySym] = val;
1284 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1290 for (
auto &member :
module->members()) {
1291 auto loc = convertLocation(member.location);
1292 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1303 SmallVector<Value> outputs;
1304 for (
auto &port : lowering.ports) {
1306 if (
auto *expr = port.ast.getInternalExpr()) {
1307 value = convertLvalueExpression(*expr);
1308 }
else if (port.ast.internalSymbol) {
1309 if (
const auto *sym =
1310 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1311 value = valueSymbols.lookup(sym);
1314 return mlir::emitError(port.loc,
"unsupported port: `")
1316 <<
"` does not map to an internal symbol or expression";
1319 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1320 if (isa<moore::RefType>(value.getType()))
1321 value = moore::ReadOp::create(builder, value.getLoc(), value);
1322 outputs.push_back(value);
1328 Value portArg = port.arg;
1329 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1330 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1331 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1336 for (
auto &fp : lowering.ifacePorts) {
1340 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1343 Value ref = valueSymbols.lookup(valueSym);
1346 outputs.push_back(moore::ReadOp::create(builder, fp.loc, ref).getResult());
1351 for (
auto &hierPath : hierPaths[module])
1352 if (auto hierValue = valueSymbols.lookup(hierPath.valueSym))
1353 if (hierPath.direction == slang::ast::ArgumentDirection::
Out)
1354 outputs.push_back(hierValue);
1356 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1366 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1367 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1369 OpBuilder::InsertionGuard g(
builder);
1372 for (
auto &member : package.members()) {
1374 if (failed(member.visit(PackageVisitor(*
this, loc))))
1385 auto &lowering =
functions[&subroutine];
1389 return lowering.get();
1392 if (!subroutine.thisVar) {
1394 SmallString<64> name;
1396 name += subroutine.name;
1398 SmallVector<Type, 1> noThis = {};
1405 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1406 moore::ClassDeclOp ownerDecl;
1408 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1409 auto &ownerLowering =
classes[classTy];
1410 ownerDecl = ownerLowering->op;
1412 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1413 << thisTy.toString();
1418 SmallString<64> qualName;
1419 qualName += ownerDecl.getSymName();
1421 qualName += subroutine.name;
1424 SmallVector<Type, 1> extraParams;
1426 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1427 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1428 extraParams.push_back(handleTy);
1439 const slang::ast::SubroutineSymbol &subroutine,
1440 llvm::SmallVectorImpl<Type> &extraParams) {
1441 using slang::ast::ArgumentDirection;
1443 SmallVector<Type> inputTypes;
1444 inputTypes.append(extraParams.begin(), extraParams.end());
1445 SmallVector<Type, 1> outputTypes;
1447 for (
const auto *arg : subroutine.getArguments()) {
1448 auto type =
context.convertType(arg->getType());
1451 if (arg->direction == ArgumentDirection::In) {
1452 inputTypes.push_back(type);
1454 inputTypes.push_back(
1455 moore::RefType::get(cast<moore::UnpackedType>(type)));
1459 const auto &returnType = subroutine.getReturnType();
1460 if (!returnType.isVoid()) {
1461 auto type =
context.convertType(returnType);
1464 outputTypes.push_back(type);
1468 FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1478 mlir::StringRef qualifiedName,
1479 llvm::SmallVectorImpl<Type> &extraParams) {
1481 std::unique_ptr<FunctionLowering> lowering =
1482 std::make_unique<FunctionLowering>();
1486 OpBuilder::InsertionGuard g(
builder);
1491 builder.setInsertionPoint(it->second);
1500 if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
1501 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
1502 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
1506 auto op = mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
1507 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
1516 functions[&subroutine] = std::move(lowering);
1526 auto &captures = lowering.
captures;
1527 if (captures.empty())
1530 auto *callee = lowering.
op.getOperation();
1531 mlir::ModuleOp
module = callee->getParentOfType<mlir::ModuleOp>();
1533 return lowering.
op.emitError(
"expected callee to be nested under ModuleOp");
1535 auto usesOpt = mlir::SymbolTable::getSymbolUses(callee, module);
1537 return lowering.
op.emitError(
"failed to compute symbol uses");
1540 SmallVector<Operation *, 8> callSites;
1541 for (
const mlir::SymbolTable::SymbolUse &use : *usesOpt) {
1542 auto *user = use.getUser();
1543 if (isa<mlir::func::CallOp>(user) || isa<moore::CallCoroutineOp>(user))
1544 callSites.push_back(user);
1546 if (callSites.empty())
1549 Block &entry = lowering.
op.getFunctionBody().front();
1550 const unsigned numCaps = captures.size();
1551 const unsigned numEntryArgs = entry.getNumArguments();
1552 if (numEntryArgs < numCaps)
1553 return lowering.
op.emitError(
"entry block has fewer args than captures");
1554 const unsigned capArgStart = numEntryArgs - numCaps;
1556 auto fTy = cast<FunctionType>(lowering.
op.getFunctionType());
1558 for (
auto *callOp : callSites) {
1560 auto argOperands = callOp->getOperands();
1561 SmallVector<Value> newOperands(argOperands.begin(), argOperands.end());
1563 const bool inSameFunc = callee->isProperAncestor(callOp);
1565 for (
unsigned i = 0; i < numCaps; ++i)
1566 newOperands.push_back(entry.getArgument(capArgStart + i));
1568 newOperands.append(captures.begin(), captures.end());
1571 OpBuilder b(callOp);
1572 auto flatRef = mlir::FlatSymbolRefAttr::get(callee->getContext(),
1573 lowering.
op.getName());
1576 newCall = moore::CallCoroutineOp::create(
1577 b, callOp->getLoc(), fTy.getResults(), flatRef, newOperands);
1579 newCall = mlir::func::CallOp::create(
1580 b, callOp->getLoc(), fTy.getResults(), flatRef, newOperands);
1582 callOp->replaceAllUsesWith(newCall);
1595 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
1596 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1605 if (lowering->capturesFinalized || lowering->isConverting)
1611 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
1612 lowering->capturesFinalized =
true;
1616 const bool isMethod = (subroutine.thisVar !=
nullptr);
1622 if (
const auto *classTy =
1623 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
1624 for (
auto &member : classTy->members()) {
1625 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
1628 const auto &propCanon = prop->getType().getCanonicalType();
1629 if (
const auto *vi =
1630 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
1640 SmallVector<moore::VariableOp> argVariables;
1641 auto &block = lowering->op.getFunctionBody().emplaceBlock();
1648 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
1649 auto thisArg = block.addArgument(thisType, thisLoc);
1656 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
1657 auto astArgs = subroutine.getArguments();
1658 auto valInputs = llvm::ArrayRef<Type>(inputs).drop_front(isMethod ? 1 : 0);
1660 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
1662 auto blockArg = block.addArgument(type, loc);
1664 if (isa<moore::RefType>(type)) {
1667 OpBuilder::InsertionGuard g(
builder);
1668 builder.setInsertionPointToEnd(&block);
1670 auto shadowArg = moore::VariableOp::create(
1671 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
1672 StringAttr{}, blockArg);
1674 argVariables.push_back(shadowArg);
1677 const auto &argCanon = astArg->getType().getCanonicalType();
1678 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
1684 OpBuilder::InsertionGuard g(
builder);
1685 builder.setInsertionPointToEnd(&block);
1688 if (subroutine.returnValVar) {
1689 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
1692 returnVar = moore::VariableOp::create(
1693 builder, lowering->op.getLoc(),
1694 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
1696 valueSymbols.insert(subroutine.returnValVar, returnVar);
1702 llvm::scope_exit prevRCbGuard([&] {
1709 mlir::Value ref = rop.getInput();
1712 mlir::Type ty = ref.getType();
1713 if (!ty || !(isa<moore::RefType>(ty)))
1717 mlir::Region *defReg = ref.getParentRegion();
1718 if (defReg && lowering->op.getFunctionBody().isAncestor(defReg))
1722 if (lowering->captureIndex.count(ref))
1726 auto [it, inserted] =
1727 lowering->captureIndex.try_emplace(ref, lowering->captures.size());
1729 lowering->captures.push_back(ref);
1737 mlir::Value dstRef =
1738 llvm::TypeSwitch<mlir::Operation *, mlir::Value>(op)
1739 .Case<moore::BlockingAssignOp, moore::NonBlockingAssignOp,
1740 moore::DelayedNonBlockingAssignOp>(
1741 [](
auto op) {
return op.getDst(); })
1742 .Default([](
auto) -> mlir::Value {
return {}; });
1745 mlir::Type ty = dstRef.getType();
1746 if (!ty || !(isa<moore::RefType>(ty)))
1750 mlir::Region *defReg = dstRef.getParentRegion();
1751 if (defReg && lowering->op.getFunctionBody().isAncestor(defReg))
1755 if (lowering->captureIndex.count(dstRef))
1759 auto [it, inserted] =
1760 lowering->captureIndex.try_emplace(dstRef, lowering->captures.size());
1762 lowering->captures.push_back(dstRef);
1771 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
1773 lowering->isConverting =
true;
1774 llvm::scope_exit convertingGuard([&] { lowering->isConverting =
false; });
1791 if (lowering->isCoroutine()) {
1792 moore::ReturnOp::create(
builder, lowering->op.getLoc());
1793 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
1795 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
1796 mlir::func::ReturnOp::create(
builder, lowering->op.getLoc(), read);
1798 mlir::func::ReturnOp::create(
builder, lowering->op.getLoc(),
1802 if (returnVar && returnVar.use_empty())
1803 returnVar.getDefiningOp()->erase();
1805 for (
auto var : argVariables) {
1806 if (llvm::all_of(var->getUsers(),
1807 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
1808 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
1809 user->getResult(0).replaceAllUsesWith(var.getInitial());
1816 lowering->capturesFinalized =
true;
1828 SmallVector<Type> newInputs(
1829 cast<FunctionType>(lowering.
op.getFunctionType()).getInputs().begin(),
1830 cast<FunctionType>(lowering.
op.getFunctionType()).getInputs().end());
1832 for (Value cap : lowering.
captures) {
1834 Type capTy = cap.getType();
1835 if (!isa<moore::RefType>(capTy)) {
1836 return lowering.
op.emitError(
1837 "expected captured value to be a ref-like type");
1839 newInputs.push_back(capTy);
1843 auto newFuncTy = FunctionType::get(
1845 cast<FunctionType>(lowering.
op.getFunctionType()).getResults());
1846 lowering.
op.setType(newFuncTy);
1849 Block &entry = lowering.
op.getFunctionBody().front();
1850 SmallVector<Value> capArgs;
1851 capArgs.reserve(lowering.
captures.size());
1853 llvm::ArrayRef<Type>(newInputs).take_back(lowering.
captures.size())) {
1854 capArgs.push_back(entry.addArgument(t, lowering.
op.getLoc()));
1860 Value arg = capArgs[idx];
1861 cap.replaceUsesWithIf(arg, [&](OpOperand &use) {
1862 return lowering.
op->isProperAncestor(use.getOwner());
1873mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
1874 const slang::ast::Type &ty) {
1875 SmallString<64> name;
1876 SmallVector<llvm::StringRef, 8> parts;
1878 const slang::ast::Scope *scope = ty.getParentScope();
1880 const auto &sym = scope->asSymbol();
1882 case slang::ast::SymbolKind::Root:
1885 case slang::ast::SymbolKind::InstanceBody:
1886 case slang::ast::SymbolKind::Instance:
1887 case slang::ast::SymbolKind::Package:
1888 case slang::ast::SymbolKind::ClassType:
1889 if (!sym.name.empty())
1890 parts.push_back(sym.name);
1895 scope = sym.getParentScope();
1898 for (
auto p :
llvm::reverse(parts)) {
1903 return mlir::StringAttr::get(ctx.
getContext(), name);
1908std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
1910 const slang::ast::ClassType &cls) {
1914 mlir::SymbolRefAttr base;
1915 if (
const auto *b = cls.getBaseClass())
1916 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
1919 SmallVector<mlir::Attribute> impls;
1920 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
1921 impls.reserve(ifaces.size());
1922 for (
const auto *iface : ifaces)
1923 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
1924 fullyQualifiedClassName(
context, *iface)));
1927 mlir::ArrayAttr implArr =
1928 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
1930 return {base, implArr};
1935struct ClassDeclVisitorBase {
1941 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
1945 return context.convertLocation(sloc);
1951struct ClassPropertyVisitor : ClassDeclVisitorBase {
1952 using ClassDeclVisitorBase::ClassDeclVisitorBase;
1955 LogicalResult
run(
const slang::ast::ClassType &classAST) {
1956 if (!classLowering.
op.getBody().empty())
1959 OpBuilder::InsertionGuard ig(builder);
1961 Block *body = &classLowering.
op.getBody().emplaceBlock();
1962 builder.setInsertionPointToEnd(body);
1965 for (
const auto &mem : classAST.members()) {
1966 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
1967 if (failed(prop->visit(*
this)))
1976 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
1978 auto ty =
context.convertType(prop.getType());
1982 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
1983 moore::ClassPropertyDeclOp::create(builder, loc, prop.name, ty);
1991 if (!
context.globalVariables.lookup(&prop))
1992 return context.convertGlobalVariable(prop);
1997 LogicalResult visit(
const slang::ast::ClassType &cls) {
1998 return context.buildClassProperties(cls);
2002 template <
typename T>
2003 LogicalResult visit(T &&) {
2010struct ClassMethodVisitor : ClassDeclVisitorBase {
2011 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2014 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2018 if (classLowering.
op.getBody().empty())
2021 OpBuilder::InsertionGuard ig(builder);
2022 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2025 for (
const auto &mem : classAST.members()) {
2026 if (failed(mem.visit(*
this)))
2035 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2041 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2045 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2051 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2054 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2059 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2064 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2069 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2070 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2071 static bool remarkEmitted =
false;
2075 mlir::emitRemark(classLowering.
op.getLoc())
2076 <<
"Class builtin functions (needed for randomization, constraints, "
2077 "and covergroups) are not yet supported and will be dropped "
2079 remarkEmitted =
true;
2083 const mlir::UnitAttr isVirtual =
2084 (fn.flags & slang::ast::MethodFlags::Virtual)
2085 ? UnitAttr::get(
context.getContext())
2092 if (fn.flags & slang::ast::MethodFlags::Pure) {
2094 SmallVector<Type, 1> extraParams;
2096 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2098 moore::ClassHandleType::get(
context.getContext(), classSym);
2099 extraParams.push_back(handleTy);
2103 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2107 moore::ClassMethodDeclOp::create(builder, loc, fn.name, funcTy,
nullptr);
2111 auto *lowering =
context.declareFunction(fn);
2115 if (failed(
context.convertFunction(fn)))
2118 if (!lowering->capturesFinalized)
2126 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2128 moore::ClassMethodDeclOp::create(builder, loc, fn.name, fnTy,
2129 SymbolRefAttr::get(lowering->op));
2146 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2147 const auto *externImpl = fn.getSubroutine();
2151 <<
"Didn't find an implementation matching the forward declaration "
2156 return visit(*externImpl);
2160 LogicalResult visit(
const slang::ast::ClassType &cls) {
2161 if (failed(
context.buildClassProperties(cls)))
2163 return context.materializeClassMethods(cls);
2167 template <
typename T>
2168 LogicalResult visit(T &&node) {
2169 Location loc = UnknownLoc::get(
context.getContext());
2170 if constexpr (
requires { node.location; })
2172 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2173 << slang::ast::toString(node.kind);
2181 auto &lowering =
classes[&cls];
2183 return lowering.get();
2184 lowering = std::make_unique<ClassLowering>();
2189 OpBuilder::InsertionGuard g(
builder);
2194 builder.setInsertionPoint(it->second);
2196 auto symName = fullyQualifiedClassName(*
this, cls);
2198 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2200 moore::ClassDeclOp::create(
builder, loc, symName, base, impls);
2202 SymbolTable::setSymbolVisibility(classDeclOp,
2203 SymbolTable::Visibility::Public);
2205 lowering->op = classDeclOp;
2208 return lowering.get();
2215 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2216 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2223 if (classdecl.getBaseClass()) {
2224 if (
const auto *baseClassDecl =
2225 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2236 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2243 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2244 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2247 auto it =
classes.find(&classdecl);
2248 if (it ==
classes.end() || !it->second)
2252 if (classdecl.getBaseClass()) {
2253 if (
const auto *baseClassDecl =
2254 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2260 return ClassMethodVisitor(*
this, *it->second).run(classdecl);
2270 OpBuilder::InsertionGuard g(
builder);
2275 builder.setInsertionPoint(it->second);
2279 SmallString<64> symName;
2283 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2284 if (
const auto *parentScope = classVar->getParentScope()) {
2285 if (
const auto *parentClass =
2286 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2287 symName = fullyQualifiedClassName(*
this, *parentClass);
2289 mlir::emitError(loc)
2290 <<
"Could not access parent class of class property "
2295 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2300 symName += var.name;
2303 symName += var.name;
2312 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2313 cast<moore::UnpackedType>(type));
2324 if (var.getInitializer())
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 FunctionType getFunctionSignature(Context &context, const slang::ast::SubroutineSymbol &subroutine, llvm::SmallVectorImpl< Type > &extraParams)
Helper function to generate the function signature from a SubroutineSymbol and optional extra argumen...
static void guessNamespacePrefix(const slang::ast::Symbol &symbol, SmallString< 64 > &prefix)
static moore::NetKind convertNetKind(slang::ast::NetType::NetKind kind)
static LogicalResult rewriteCallSitesToPassCaptures(FunctionLowering &lowering)
Special case handling for recursive functions with captures; this function fixes the in-body call of ...
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.
LogicalResult convertFunction(const slang::ast::SubroutineSymbol &subroutine)
Convert a function.
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.
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.
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.
DenseMap< const slang::ast::ClassType *, std::unique_ptr< ClassLowering > > classes
Classes that have already been converted.
std::function< void(moore::ReadOp)> rvalueReadCallback
A listener called for every variable or net being read.
std::map< slang::SourceLocation, Operation * > orderedRootOps
The top-level operations ordered by their Slang source location.
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.
LogicalResult finalizeFunctionBodyCaptures(FunctionLowering &lowering)
ClassLowering * declareClass(const slang::ast::ClassType &cls)
VirtualInterfaceMembers::ScopeTy VirtualInterfaceMemberScope
ValueSymbols valueSymbols
std::function< void(mlir::Operation *)> variableAssignCallback
A listener called for every variable or net being assigned.
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
LogicalResult traverseInstanceBody(const slang::ast::Symbol &symbol)
Value currentThisRef
Variable to track the value of the current function's implicit this reference.
InterfaceInstances::ScopeTy InterfaceInstanceScope
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.
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 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.
llvm::DenseMap< Value, unsigned > captureIndex
llvm::SmallVector< Value, 4 > captures
bool isCoroutine()
Whether this is a coroutine (task) or a regular function.
mlir::FunctionOpInterface op
Lowering information for an expanded interface instance.
Module lowering information.