10#include "slang/ast/Compilation.h"
11#include "slang/ast/symbols/ClassSymbols.h"
12#include "llvm/ADT/STLFunctionalExtras.h"
13#include "llvm/ADT/ScopeExit.h"
16using namespace ImportVerilog;
23 SmallString<64> &prefix) {
24 if (symbol.kind != slang::ast::SymbolKind::Package)
27 if (!symbol.name.empty()) {
28 prefix += symbol.name;
45 BaseVisitor(
Context &context, Location loc)
46 : context(context), loc(loc), builder(context.builder) {}
49 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
55 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
60 LogicalResult visit(
const slang::ast::ClassType &classdecl) {
70 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
75 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
76 LogicalResult visit(
const slang::ast::ForwardingTypedefSymbol &) {
81 LogicalResult visit(
const slang::ast::ExplicitImportSymbol &) {
84 LogicalResult visit(
const slang::ast::WildcardImportSymbol &) {
89 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
94 LogicalResult visit(
const slang::ast::ElabSystemTaskSymbol &) {
99 LogicalResult visit(
const slang::ast::ParameterSymbol ¶m) {
100 visitParameter(param);
104 LogicalResult visit(
const slang::ast::SpecparamSymbol ¶m) {
105 visitParameter(param);
109 template <
class Node>
110 void visitParameter(
const Node ¶m) {
120 if (builder.getInsertionBlock()->getParentOp() == context.
intoModuleOp) {
127 SmallString<64> paramName;
129 paramName += param.name;
131 debug::VariableOp::create(builder, loc, builder.getStringAttr(paramName),
142struct RootVisitor :
public BaseVisitor {
143 using BaseVisitor::BaseVisitor;
144 using BaseVisitor::visit;
147 LogicalResult visit(
const slang::ast::PackageSymbol &package) {
148 return context.convertPackage(package);
152 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
153 if (!
context.declareFunction(subroutine))
159 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
160 return context.convertGlobalVariable(var);
164 template <
typename T>
165 LogicalResult visit(T &&node) {
166 mlir::emitError(loc,
"unsupported construct: ")
167 << slang::ast::toString(node.kind);
178struct PackageVisitor :
public BaseVisitor {
179 using BaseVisitor::BaseVisitor;
180 using BaseVisitor::visit;
183 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
184 if (!
context.declareFunction(subroutine))
190 LogicalResult visit(
const slang::ast::VariableSymbol &var) {
191 return context.convertGlobalVariable(var);
195 template <
typename T>
196 LogicalResult visit(T &&node) {
197 mlir::emitError(loc,
"unsupported package member: ")
198 << slang::ast::toString(node.kind);
208static moore::ProcedureKind
211 case slang::ast::ProceduralBlockKind::Always:
212 return moore::ProcedureKind::Always;
213 case slang::ast::ProceduralBlockKind::AlwaysComb:
214 return moore::ProcedureKind::AlwaysComb;
215 case slang::ast::ProceduralBlockKind::AlwaysLatch:
216 return moore::ProcedureKind::AlwaysLatch;
217 case slang::ast::ProceduralBlockKind::AlwaysFF:
218 return moore::ProcedureKind::AlwaysFF;
219 case slang::ast::ProceduralBlockKind::Initial:
220 return moore::ProcedureKind::Initial;
221 case slang::ast::ProceduralBlockKind::Final:
222 return moore::ProcedureKind::Final;
224 llvm_unreachable(
"all procedure kinds handled");
229 case slang::ast::NetType::Supply0:
230 return moore::NetKind::Supply0;
231 case slang::ast::NetType::Supply1:
232 return moore::NetKind::Supply1;
233 case slang::ast::NetType::Tri:
234 return moore::NetKind::Tri;
235 case slang::ast::NetType::TriAnd:
236 return moore::NetKind::TriAnd;
237 case slang::ast::NetType::TriOr:
238 return moore::NetKind::TriOr;
239 case slang::ast::NetType::TriReg:
240 return moore::NetKind::TriReg;
241 case slang::ast::NetType::Tri0:
242 return moore::NetKind::Tri0;
243 case slang::ast::NetType::Tri1:
244 return moore::NetKind::Tri1;
245 case slang::ast::NetType::UWire:
246 return moore::NetKind::UWire;
247 case slang::ast::NetType::Wire:
248 return moore::NetKind::Wire;
249 case slang::ast::NetType::WAnd:
250 return moore::NetKind::WAnd;
251 case slang::ast::NetType::WOr:
252 return moore::NetKind::WOr;
253 case slang::ast::NetType::Interconnect:
254 return moore::NetKind::Interconnect;
255 case slang::ast::NetType::UserDefined:
256 return moore::NetKind::UserDefined;
257 case slang::ast::NetType::Unknown:
258 return moore::NetKind::Unknown;
260 llvm_unreachable(
"all net kinds handled");
264struct ModuleVisitor :
public BaseVisitor {
265 using BaseVisitor::visit;
269 StringRef blockNamePrefix;
271 ModuleVisitor(
Context &
context, Location loc, StringRef blockNamePrefix =
"")
272 : BaseVisitor(
context, loc), blockNamePrefix(blockNamePrefix) {}
275 LogicalResult visit(
const slang::ast::PortSymbol &) {
return success(); }
276 LogicalResult visit(
const slang::ast::MultiPortSymbol &) {
return success(); }
277 LogicalResult visit(
const slang::ast::InterfacePortSymbol &) {
282 LogicalResult visit(
const slang::ast::GenvarSymbol &genvarNode) {
287 LogicalResult visit(
const slang::ast::DefParamSymbol &) {
return success(); }
291 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
299 expandInterfaceInstance(
const slang::ast::InstanceSymbol &instNode) {
300 auto prefix = (Twine(blockNamePrefix) + instNode.name +
"_").str();
301 auto lowering = std::make_unique<InterfaceLowering>();
302 Context::ValueSymbolScope scope(
context.valueSymbols);
304 auto recordMember = [&](
const slang::ast::Symbol &sym,
305 Value value) ->
void {
306 lowering->expandedMembers[&sym] = value;
307 auto nameAttr = builder.getStringAttr(sym.name);
308 lowering->expandedMembersByName[nameAttr] = value;
309 if (
auto *valueSym = sym.as_if<slang::ast::ValueSymbol>())
310 context.valueSymbols.insert(valueSym, value);
313 for (
const auto &member : instNode.body.members()) {
315 if (
const auto *nestedInst = member.as_if<slang::ast::InstanceSymbol>()) {
316 if (nestedInst->body.getDefinition().definitionKind ==
317 slang::ast::DefinitionKind::Interface)
318 return mlir::emitError(loc)
319 <<
"nested interface instances are not supported: `"
320 << nestedInst->name <<
"` inside `" << instNode.name <<
"`";
323 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
324 auto loweredType =
context.convertType(*var->getDeclaredType());
327 auto varOp = moore::VariableOp::create(
329 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
330 builder.getStringAttr(Twine(prefix) + StringRef(var->name)),
332 recordMember(*var, varOp);
336 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
337 auto loweredType =
context.convertType(*net->getDeclaredType());
341 if (netKind == moore::NetKind::Interconnect ||
342 netKind == moore::NetKind::UserDefined ||
343 netKind == moore::NetKind::Unknown)
344 return mlir::emitError(loc,
"unsupported net kind `")
345 << net->netType.name <<
"`";
346 auto netOp = moore::NetOp::create(
348 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
349 builder.getStringAttr(Twine(prefix) + StringRef(net->name)),
351 recordMember(*net, netOp);
360 for (
const auto *con : instNode.getPortConnections()) {
361 const auto *expr = con->getExpression();
362 const auto *port = con->port.as_if<slang::ast::PortSymbol>();
370 Value lvalue =
context.convertLvalueExpression(*expr);
374 recordMember(*port, lvalue);
375 if (port->internalSymbol) {
376 recordMember(*port->internalSymbol, lvalue);
382 for (
const auto &member : instNode.body.members()) {
383 switch (member.kind) {
384 case slang::ast::SymbolKind::ContinuousAssign:
385 case slang::ast::SymbolKind::ProceduralBlock:
386 case slang::ast::SymbolKind::StatementBlock:
391 auto memberLoc =
context.convertLocation(member.location);
392 if (failed(member.visit(ModuleVisitor(
context, memberLoc, prefix))))
394 if (failed(
context.flushPendingMonitors()))
398 context.interfaceInstanceStorage.push_back(std::move(lowering));
399 context.interfaceInstances.insert(
400 &instNode,
context.interfaceInstanceStorage.back().get());
405 LogicalResult visit(
const slang::ast::InstanceSymbol &instNode) {
406 using slang::ast::ArgumentDirection;
407 using slang::ast::AssignmentExpression;
408 using slang::ast::MultiPortSymbol;
409 using slang::ast::PortSymbol;
411 if (
context.predeclaredInstances.contains(&instNode))
422 auto defKind = body->getDefinition().definitionKind;
423 if (defKind == slang::ast::DefinitionKind::Interface) {
424 if (
context.interfaceInstances.lookup(&instNode))
426 return expandInterfaceInstance(instNode);
429 auto *moduleLowering =
context.convertModuleHeader(body);
432 auto module = moduleLowering->op;
433 auto moduleType =
module.getModuleType();
436 SymbolTable::setSymbolVisibility(module, SymbolTable::Visibility::Private);
443 portValues.reserve(moduleType.getNumPorts());
447 const slang::ast::InstanceSymbol *>
450 for (
const auto *con : instNode.getPortConnections()) {
451 const auto *expr = con->getExpression();
456 auto *port = con->port.as_if<PortSymbol>();
457 if (
auto *existingPort =
458 moduleLowering->portsBySyntaxNode.lookup(port->getSyntax()))
461 switch (port->direction) {
462 case ArgumentDirection::In: {
463 auto refType = moore::RefType::get(
464 cast<moore::UnpackedType>(
context.convertType(port->getType())));
466 if (
const auto *net =
467 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
468 auto netOp = moore::NetOp::create(
469 builder, loc, refType,
470 StringAttr::get(builder.getContext(), net->name),
472 auto readOp = moore::ReadOp::create(builder, loc, netOp);
473 portValues.insert({port, readOp});
474 }
else if (
const auto *var =
476 ->as_if<slang::ast::VariableSymbol>()) {
477 auto varOp = moore::VariableOp::create(
478 builder, loc, refType,
479 StringAttr::get(builder.getContext(), var->name),
nullptr);
480 auto readOp = moore::ReadOp::create(builder, loc, varOp);
481 portValues.insert({port, readOp});
483 return mlir::emitError(loc)
484 <<
"unsupported internal symbol for unconnected port `"
485 << port->name <<
"`";
492 case ArgumentDirection::Out:
495 case ArgumentDirection::InOut:
496 case ArgumentDirection::Ref: {
497 auto refType = moore::RefType::get(
498 cast<moore::UnpackedType>(
context.convertType(port->getType())));
500 if (
const auto *net =
501 port->internalSymbol->as_if<slang::ast::NetSymbol>()) {
502 auto netOp = moore::NetOp::create(
503 builder, loc, refType,
504 StringAttr::get(builder.getContext(), net->name),
506 portValues.insert({port, netOp});
507 }
else if (
const auto *var =
509 ->as_if<slang::ast::VariableSymbol>()) {
510 auto varOp = moore::VariableOp::create(
511 builder, loc, refType,
512 StringAttr::get(builder.getContext(), var->name),
nullptr);
513 portValues.insert({port, varOp});
515 return mlir::emitError(loc)
516 <<
"unsupported internal symbol for unconnected port `"
517 << port->name <<
"`";
526 if (
const auto *assign = expr->as_if<AssignmentExpression>())
527 expr = &assign->left();
532 if (
auto *port = con->port.as_if<PortSymbol>()) {
534 auto value = (port->direction == ArgumentDirection::In)
535 ?
context.convertRvalueExpression(*expr)
536 :
context.convertLvalueExpression(*expr);
539 if (
auto *existingPort =
540 moduleLowering->portsBySyntaxNode.lookup(con->port.getSyntax()))
542 portValues.insert({port, value});
549 if (
const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
551 auto value =
context.convertLvalueExpression(*expr);
555 for (
const auto *port :
llvm::reverse(multiPort->ports)) {
556 if (
auto *existingPort = moduleLowering->portsBySyntaxNode.lookup(
557 con->port.getSyntax()))
559 unsigned width = port->getType().getBitWidth();
560 auto sliceType =
context.convertType(port->getType());
563 Value slice = moore::ExtractRefOp::create(
565 moore::RefType::get(cast<moore::UnpackedType>(sliceType)), value,
568 if (port->direction == ArgumentDirection::In)
569 slice = moore::ReadOp::create(builder, loc, slice);
570 portValues.insert({port, slice});
578 if (
const auto *ifacePort =
579 con->port.as_if<slang::ast::InterfacePortSymbol>()) {
580 auto ifaceConn = con->getIfaceConn();
581 const auto *connInst =
582 ifaceConn.first->as_if<slang::ast::InstanceSymbol>();
584 ifaceConnMap[ifacePort] = connInst;
588 mlir::emitError(loc) <<
"unsupported instance port `" << con->port.name
589 <<
"` (" << slang::ast::toString(con->port.kind)
597 SmallVector<Value> inputValues(moduleLowering->numExplicitInputs);
598 SmallVector<Value> outputValues(moduleLowering->numExplicitOutputs);
600 for (
auto &port : moduleLowering->ports) {
601 auto value = portValues.lookup(&port.ast);
602 if (port.ast.direction == ArgumentDirection::Out)
603 outputValues[*port.outputIdx] = value;
605 inputValues[*port.inputIdx] = value;
611 for (
auto &fp : moduleLowering->ifacePorts) {
612 if (!fp.bodySym || !fp.origin)
615 auto it = ifaceConnMap.find(fp.origin);
616 if (it == ifaceConnMap.end()) {
618 <<
"no interface connection for port `" << fp.name <<
"`";
621 const auto *connInst = it->second;
623 auto *ifaceLowering =
context.interfaceInstances.lookup(connInst);
624 if (!ifaceLowering) {
626 <<
"interface instance `" << connInst->name <<
"` was not expanded";
630 auto valIt = ifaceLowering->expandedMembers.find(fp.bodySym);
631 if (valIt == ifaceLowering->expandedMembers.end()) {
633 <<
"unresolved interface port signal `" << fp.name <<
"`";
636 Value val = valIt->second;
638 outputValues[*fp.outputIdx] = val;
642 if (isa<moore::RefType>(val.getType()) && !isa<moore::RefType>(fp.type))
643 val = moore::ReadOp::create(builder, loc, val);
644 inputValues[*fp.inputIdx] = val;
650 for (
auto [value, type] :
651 llvm::zip(inputValues, moduleType.getInputTypes())) {
655 value =
context.materializeConversion(type, value,
false, value.getLoc());
657 return mlir::emitError(loc) <<
"unsupported port";
664 for (
const auto &hierPath :
context.hierPaths[body]) {
665 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
667 context.valueSymbols.lookup(hierPath.valueSyms.front());
668 hierPath.hierName && hierPath.direction == ArgumentDirection::In)
669 inputValues.push_back(hierValue);
673 for (
auto value : inputValues)
675 return
mlir::emitError(loc) <<
"unsupported port";
678 auto inputNames = builder.getArrayAttr(moduleType.getInputNames());
679 auto outputNames = builder.getArrayAttr(moduleType.getOutputNames());
680 auto inst = moore::InstanceOp::create(
681 builder, loc, moduleType.getOutputTypes(),
682 builder.getStringAttr(Twine(blockNamePrefix) + instNode.name),
683 FlatSymbolRefAttr::get(module.getSymNameAttr()), inputValues,
684 inputNames, outputNames);
691 for (
const auto &hierPath :
context.hierPaths[body])
692 if (hierPath.idx && hierPath.direction == ArgumentDirection::
Out) {
693 auto result = inst->getResult(*hierPath.idx);
696 for (
auto *sym : hierPath.valueSyms)
697 context.valueSymbols.insert(sym, result);
698 context.hierValueSymbols[{&instNode, hierPath.hierName}] = result;
702 for (
auto [lvalue, output] :
llvm::zip(outputValues, inst.getOutputs())) {
705 Value rvalue = output;
706 auto dstType = cast<moore::RefType>(lvalue.getType()).getNestedType();
708 rvalue =
context.materializeConversion(dstType, rvalue,
false, loc);
709 moore::ContinuousAssignOp::create(builder, loc, lvalue, rvalue);
716 LogicalResult visit(
const slang::ast::VariableSymbol &varNode) {
717 auto ref =
context.valueSymbols.lookup(&varNode);
719 return mlir::emitError(loc)
720 <<
"internal error: missing predeclared variable `" << varNode.name
723 auto varOp = ref.getDefiningOp<moore::VariableOp>();
725 return mlir::emitError(loc)
726 <<
"internal error: predeclared variable `" << varNode.name
727 <<
"` is not a moore.variable";
729 if (
const auto *init = varNode.getInitializer()) {
730 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
731 auto initial =
context.convertRvalueExpression(*init, loweredType);
734 varOp.getInitialMutable().assign(initial);
741 LogicalResult visit(
const slang::ast::NetSymbol &netNode) {
742 auto ref =
context.valueSymbols.lookup(&netNode);
744 return mlir::emitError(loc) <<
"internal error: missing predeclared net `"
745 << netNode.name <<
"`";
747 auto netOp = ref.getDefiningOp<moore::NetOp>();
749 return mlir::emitError(loc) <<
"internal error: predeclared net `"
750 << netNode.name <<
"` is not a moore.net";
752 if (
const auto *init = netNode.getInitializer()) {
753 auto loweredType = cast<moore::RefType>(ref.getType()).getNestedType();
754 auto assignment =
context.convertRvalueExpression(*init, loweredType);
757 netOp.getAssignmentMutable().assign(assignment);
763 LogicalResult visit(
const slang::ast::ContinuousAssignSymbol &assignNode) {
765 assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
766 auto lhs =
context.convertLvalueExpression(expr.left());
770 auto rhs =
context.convertRvalueExpression(
771 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
776 if (
auto *timingCtrl = assignNode.getDelay()) {
777 if (
auto *ctrl = timingCtrl->as_if<slang::ast::DelayControl>()) {
778 auto delay =
context.convertRvalueExpression(
779 ctrl->expr, moore::TimeType::get(builder.getContext()));
782 moore::DelayedContinuousAssignOp::create(builder, loc, lhs, rhs, delay);
785 mlir::emitError(loc) <<
"unsupported delay with rise/fall/turn-off";
790 moore::ContinuousAssignOp::create(builder, loc, lhs, rhs);
795 LogicalResult convertProcedure(moore::ProcedureKind kind,
796 const slang::ast::Statement &body) {
797 if (body.as_if<slang::ast::ConcurrentAssertionStatement>())
798 return context.convertStatement(body);
799 auto procOp = moore::ProcedureOp::create(builder, loc, kind);
800 OpBuilder::InsertionGuard guard(builder);
801 builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
802 Context::ValueSymbolScope scope(
context.valueSymbols);
803 Context::VirtualInterfaceMemberScope vifMemberScope(
805 if (failed(
context.convertStatement(body)))
807 if (builder.getBlock())
808 moore::ReturnOp::create(builder, loc);
812 LogicalResult visit(
const slang::ast::ProceduralBlockSymbol &procNode) {
815 if (
context.options.lowerAlwaysAtStarAsComb) {
816 auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
817 if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
819 stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
820 return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
828 LogicalResult visit(
const slang::ast::GenerateBlockSymbol &genNode) {
830 if (genNode.isUninstantiated)
834 SmallString<64> prefix = blockNamePrefix;
835 if (!genNode.name.empty() ||
836 genNode.getParentScope()->asSymbol().kind !=
837 slang::ast::SymbolKind::GenerateBlockArray) {
838 prefix += genNode.getExternalName();
843 for (
auto &member : genNode.members())
844 if (failed(member.visit(ModuleVisitor(
context, loc, prefix))))
850 LogicalResult visit(
const slang::ast::GenerateBlockArraySymbol &genArrNode) {
853 SmallString<64> prefix = blockNamePrefix;
854 prefix += genArrNode.getExternalName();
856 auto prefixBaseLen = prefix.size();
859 for (
const auto *entry : genArrNode.entries) {
861 prefix.resize(prefixBaseLen);
862 if (entry->arrayIndex)
863 prefix += entry->arrayIndex->toString();
865 Twine(entry->constructIndex).toVector(prefix);
869 if (failed(entry->asSymbol().visit(ModuleVisitor(
context, loc, prefix))))
881 LogicalResult visit(
const slang::ast::StatementBlockSymbol &) {
887 LogicalResult visit(
const slang::ast::SequenceSymbol &seqNode) {
893 LogicalResult visit(
const slang::ast::PropertySymbol &propNode) {
898 LogicalResult visit(
const slang::ast::SubroutineSymbol &subroutine) {
899 if (!
context.declareFunction(subroutine))
905 LogicalResult visit(
const slang::ast::PrimitiveInstanceSymbol &prim) {
906 return context.convertPrimitiveInstance(prim);
910 template <
typename T>
911 LogicalResult visit(T &&node) {
912 mlir::emitError(loc,
"unsupported module member: ")
913 << slang::ast::toString(node.kind);
918struct ModulePredeclaration {
922 ModulePredeclaration(
Context &context)
923 : context(context), builder(context.builder) {}
925 LogicalResult declareVariable(
const slang::ast::VariableSymbol &varNode,
926 Location loc, StringRef blockNamePrefix) {
927 auto loweredType = context.
convertType(*varNode.getDeclaredType());
931 auto varOp = moore::VariableOp::create(
933 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
934 builder.getStringAttr(Twine(blockNamePrefix) + varNode.name), Value{});
937 const auto &canonTy = varNode.getType().getCanonicalType();
938 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>())
945 LogicalResult declareNet(
const slang::ast::NetSymbol &netNode, Location loc,
946 StringRef blockNamePrefix) {
947 auto loweredType = context.
convertType(*netNode.getDeclaredType());
952 if (netkind == moore::NetKind::Interconnect ||
953 netkind == moore::NetKind::UserDefined ||
954 netkind == moore::NetKind::Unknown)
955 return mlir::emitError(loc,
"unsupported net kind `")
956 << netNode.netType.name <<
"`";
958 auto netOp = moore::NetOp::create(
960 moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
961 builder.getStringAttr(Twine(blockNamePrefix) + netNode.name), netkind,
968 getGenerateBlockPrefix(
const slang::ast::GenerateBlockSymbol &genNode,
969 StringRef blockNamePrefix) {
970 SmallString<64> prefix = blockNamePrefix;
971 if (!genNode.name.empty() ||
972 genNode.getParentScope()->asSymbol().kind !=
973 slang::ast::SymbolKind::GenerateBlockArray) {
974 prefix += genNode.getExternalName();
981 predeclareStorageGenerateBlock(
const slang::ast::GenerateBlockSymbol &genNode,
982 StringRef blockNamePrefix) {
983 if (genNode.isUninstantiated)
985 return predeclareStorageScope(
986 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
989 LogicalResult predeclareInterfaceGenerateBlock(
990 const slang::ast::GenerateBlockSymbol &genNode,
991 StringRef blockNamePrefix) {
992 if (genNode.isUninstantiated)
994 return predeclareInterfaceScope(
995 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
998 LogicalResult predeclareModuleInstanceGenerateBlock(
999 const slang::ast::GenerateBlockSymbol &genNode,
1000 StringRef blockNamePrefix) {
1001 if (genNode.isUninstantiated)
1003 return predeclareModuleInstanceScope(
1004 genNode, getGenerateBlockPrefix(genNode, blockNamePrefix));
1007 LogicalResult predeclareGenerateBlockArray(
1008 const slang::ast::GenerateBlockArraySymbol &genArrNode,
1009 StringRef blockNamePrefix,
1010 llvm::function_ref<LogicalResult(
const slang::ast::GenerateBlockSymbol &,
1013 SmallString<64> prefix = blockNamePrefix;
1014 prefix += genArrNode.getExternalName();
1016 auto prefixBaseLen = prefix.size();
1018 for (
const auto *entry : genArrNode.entries) {
1019 prefix.resize(prefixBaseLen);
1020 if (entry->arrayIndex)
1021 prefix += entry->arrayIndex->toString();
1023 Twine(entry->constructIndex).toVector(prefix);
1026 if (failed(predeclareBlock(*entry, prefix)))
1032 LogicalResult predeclareStorageMember(
const slang::ast::Symbol &member,
1033 StringRef blockNamePrefix) {
1035 if (
const auto *varNode = member.as_if<slang::ast::VariableSymbol>())
1036 return declareVariable(*varNode, loc, blockNamePrefix);
1038 if (
const auto *netNode = member.as_if<slang::ast::NetSymbol>())
1039 return declareNet(*netNode, loc, blockNamePrefix);
1041 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1042 return predeclareStorageGenerateBlock(*genNode, blockNamePrefix);
1044 if (
const auto *genArrNode =
1045 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1046 return predeclareGenerateBlockArray(
1047 *genArrNode, blockNamePrefix,
1048 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1049 return predeclareStorageGenerateBlock(gen, prefix);
1055 LogicalResult predeclareInterfaceMember(
const slang::ast::Symbol &member,
1056 StringRef blockNamePrefix) {
1058 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1059 if (instNode->body.getDefinition().definitionKind ==
1060 slang::ast::DefinitionKind::Interface)
1061 return ModuleVisitor(context, loc, blockNamePrefix)
1062 .expandInterfaceInstance(*instNode);
1066 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1067 return predeclareInterfaceGenerateBlock(*genNode, blockNamePrefix);
1069 if (
const auto *genArrNode =
1070 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1071 return predeclareGenerateBlockArray(
1072 *genArrNode, blockNamePrefix,
1073 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1074 return predeclareInterfaceGenerateBlock(gen, prefix);
1080 LogicalResult predeclareModuleInstanceMember(
const slang::ast::Symbol &member,
1081 StringRef blockNamePrefix) {
1083 if (
const auto *instNode = member.as_if<slang::ast::InstanceSymbol>()) {
1084 if (instNode->body.getDefinition().definitionKind !=
1085 slang::ast::DefinitionKind::Interface) {
1087 ModuleVisitor(context, loc, blockNamePrefix).visit(*instNode)))
1094 if (
const auto *genNode = member.as_if<slang::ast::GenerateBlockSymbol>())
1095 return predeclareModuleInstanceGenerateBlock(*genNode, blockNamePrefix);
1097 if (
const auto *genArrNode =
1098 member.as_if<slang::ast::GenerateBlockArraySymbol>())
1099 return predeclareGenerateBlockArray(
1100 *genArrNode, blockNamePrefix,
1101 [&](
const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1102 return predeclareModuleInstanceGenerateBlock(gen, prefix);
1108 LogicalResult predeclareStorageScope(
const slang::ast::Scope &scope,
1109 StringRef blockNamePrefix) {
1110 for (
auto &member : scope.members())
1111 if (failed(predeclareStorageMember(member, blockNamePrefix)))
1116 LogicalResult predeclareInterfaceScope(
const slang::ast::Scope &scope,
1117 StringRef blockNamePrefix) {
1118 for (
auto &member : scope.members())
1119 if (failed(predeclareInterfaceMember(member, blockNamePrefix)))
1124 LogicalResult predeclareModuleInstanceScope(
const slang::ast::Scope &scope,
1125 StringRef blockNamePrefix) {
1126 for (
auto &member : scope.members())
1127 if (failed(predeclareModuleInstanceMember(member, blockNamePrefix)))
1132 LogicalResult predeclareScope(
const slang::ast::Scope &scope,
1133 StringRef blockNamePrefix) {
1137 if (failed(predeclareStorageScope(scope, blockNamePrefix)))
1143 if (failed(predeclareInterfaceScope(scope, blockNamePrefix)))
1148 return predeclareModuleInstanceScope(scope, blockNamePrefix);
1159LogicalResult Context::convertCompilation() {
1165 timeScale = root.getTimeScale().value_or(slang::TimeScale());
1166 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1174 for (
auto *inst : root.topInstances)
1184 for (
auto *unit : root.compilationUnits) {
1185 for (
const auto &member : unit->members()) {
1187 if (failed(member.visit(RootVisitor(*
this, loc))))
1195 SmallVector<const slang::ast::InstanceSymbol *> topInstances;
1196 for (
auto *inst : root.topInstances) {
1198 if (body->getDefinition().definitionKind !=
1199 slang::ast::DefinitionKind::Interface)
1206 auto *
module = moduleWorklist.front();
1214 SmallVector<const slang::ast::ClassType *, 16> classMethodWorklist;
1215 classMethodWorklist.reserve(
classes.size());
1217 classMethodWorklist.push_back(kv.first);
1219 for (
auto *inst : classMethodWorklist) {
1238 auto &block = varOp.getInitRegion().emplaceBlock();
1239 OpBuilder::InsertionGuard guard(
builder);
1240 builder.setInsertionPointToEnd(&block);
1245 moore::YieldOp::create(
builder, varOp.getLoc(), value);
1254 using slang::ast::ArgumentDirection;
1255 using slang::ast::MultiPortSymbol;
1256 using slang::ast::ParameterSymbol;
1257 using slang::ast::PortSymbol;
1258 using slang::ast::TypeParameterSymbol;
1263 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1264 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1271 slot = std::make_unique<ModuleLowering>();
1272 auto &lowering = *slot;
1275 OpBuilder::InsertionGuard g(
builder);
1280 auto kind =
module->getDefinition().definitionKind;
1281 if (kind != slang::ast::DefinitionKind::Module &&
1282 kind != slang::ast::DefinitionKind::Program) {
1283 mlir::emitError(loc) <<
"unsupported definition: "
1284 <<
module->getDefinition().getKindString();
1289 auto block = std::make_unique<Block>();
1290 SmallVector<hw::ModulePort> modulePorts;
1293 unsigned int outputIdx = 0, inputIdx = 0;
1294 for (
auto *symbol :
module->getPortList()) {
1295 auto handlePort = [&](const PortSymbol &port) {
1296 auto portLoc = convertLocation(port.location);
1300 auto portName =
builder.getStringAttr(port.name);
1302 std::optional<unsigned> portOutputIdx;
1303 std::optional<unsigned> portInputIdx;
1304 if (port.direction == ArgumentDirection::Out) {
1306 portOutputIdx = outputIdx++;
1310 if (port.direction != ArgumentDirection::In)
1311 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1313 arg = block->addArgument(type, portLoc);
1314 portInputIdx = inputIdx++;
1316 lowering.ports.push_back(
1317 {port, portLoc, arg, portOutputIdx, portInputIdx});
1324 auto handleIfacePort = [&](
const slang::ast::InterfacePortSymbol
1327 auto [connSym, modportSym] = ifacePort.getConnection();
1328 const auto *ifaceInst =
1329 connSym ? connSym->as_if<slang::ast::InstanceSymbol>() : nullptr;
1330 auto portPrefix = (Twine(ifacePort.name) +
"_").str();
1334 for (
const auto &member : modportSym->members()) {
1335 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
1342 builder.getStringAttr(Twine(portPrefix) + StringRef(mpp->name));
1345 std::optional<unsigned> ifaceOutputIdx;
1346 std::optional<unsigned> ifaceInputIdx;
1347 if (mpp->direction == ArgumentDirection::Out) {
1349 modulePorts.push_back({name, type, dir});
1350 ifaceOutputIdx = outputIdx++;
1353 if (mpp->direction != ArgumentDirection::In)
1354 type = moore::RefType::get(cast<moore::UnpackedType>(type));
1355 modulePorts.push_back({name, type, dir});
1356 arg = block->addArgument(type, portLoc);
1357 ifaceInputIdx = inputIdx++;
1359 lowering.ifacePorts.push_back(
1360 {name, dir, type, portLoc, arg, &ifacePort, mpp->internalSymbol,
1361 ifaceInst, mpp, ifaceOutputIdx, ifaceInputIdx});
1366 const auto *instSym = connSym->as_if<slang::ast::InstanceSymbol>();
1368 mlir::emitError(portLoc)
1369 <<
"unsupported interface port connection for `" << ifacePort.name
1373 for (
const auto &member : instSym->body.members()) {
1374 const slang::ast::Type *slangType =
nullptr;
1375 const slang::ast::Symbol *bodySym =
nullptr;
1376 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
1377 slangType = &var->getType();
1379 }
else if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
1380 slangType = &net->getType();
1388 auto name = builder.getStringAttr(Twine(portPrefix) +
1389 StringRef(bodySym->name));
1390 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
1392 auto arg = block->addArgument(refType, portLoc);
1393 lowering.ifacePorts.push_back(
1395 bodySym, instSym,
nullptr, std::nullopt, inputIdx++});
1401 if (
const auto *port = symbol->as_if<PortSymbol>()) {
1402 if (failed(handlePort(*port)))
1404 }
else if (
const auto *multiPort = symbol->as_if<MultiPortSymbol>()) {
1405 for (
auto *port : multiPort->ports)
1406 if (failed(handlePort(*port)))
1408 }
else if (
const auto *ifacePort =
1409 symbol->as_if<slang::ast::InterfacePortSymbol>()) {
1410 if (failed(handleIfacePort(*ifacePort)))
1414 <<
"unsupported module port `" << symbol->name <<
"` ("
1415 << slang::ast::toString(symbol->kind) <<
")";
1421 lowering.numExplicitOutputs = outputIdx;
1422 lowering.numExplicitInputs = inputIdx;
1425 for (
auto &hierPath : hierPaths[module]) {
1426 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1427 auto hierType =
convertType(hierPath.valueSyms.front()->getType());
1431 if (
auto hierName = hierPath.hierName) {
1433 hierType = moore::RefType::get(cast<moore::UnpackedType>(hierType));
1434 if (hierPath.direction == ArgumentDirection::Out) {
1435 hierPath.idx = outputIdx++;
1438 hierPath.idx = inputIdx++;
1441 block->addArgument(hierType, hierLoc);
1445 auto moduleType = hw::ModuleType::get(getContext(), modulePorts);
1450 auto it = orderedRootOps.upper_bound(key);
1451 if (it == orderedRootOps.end())
1452 builder.setInsertionPointToEnd(intoModuleOp.getBody());
1454 builder.setInsertionPoint(it->second);
1458 moore::SVModuleOp::create(builder, loc, module->name, moduleType);
1459 orderedRootOps.insert(it, {key, moduleOp});
1460 moduleOp.getBodyRegion().push_back(block.release());
1461 lowering.op = moduleOp;
1465 symbolTable.insert(moduleOp);
1468 moduleWorklist.push(module);
1471 for (
const auto &port : lowering.ports)
1472 lowering.portsBySyntaxNode.insert({port.ast.getSyntax(), &port.ast});
1479 auto &lowering = *
modules[module];
1480 OpBuilder::InsertionGuard g(
builder);
1481 builder.setInsertionPointToEnd(lowering.op.getBody());
1490 timeScale =
module->getTimeScale().value_or(slang::TimeScale());
1491 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1496 for (
auto &hierPath :
hierPaths[module])
1497 if (hierPath.direction == slang::ast::ArgumentDirection::In &&
1499 auto arg = lowering.op.getBody()->getArgument(*hierPath.idx);
1500 for (
auto *sym : hierPath.valueSyms)
1508 DenseMap<const slang::ast::InstanceSymbol *, InterfaceLowering *>
1511 auto getIfacePortLowering =
1517 if (
auto it = ifacePortLowerings.find(ifaceInst);
1518 it != ifacePortLowerings.end())
1521 auto lowering = std::make_unique<InterfaceLowering>();
1525 ifacePortLowerings.try_emplace(ifaceInst, ptr);
1529 for (
auto &fp : lowering.ifacePorts) {
1532 auto *valueSym = fp.bodySym->as_if<slang::ast::ValueSymbol>();
1541 portValue = moore::VariableOp::create(
1543 moore::RefType::get(cast<moore::UnpackedType>(fp.type)), fp.name,
1552 if (fp.modportPortSym)
1553 if (
auto *mppSym = fp.modportPortSym->as_if<slang::ast::ValueSymbol>())
1554 if (mppSym != valueSym)
1557 if (!fp.ifaceInstance)
1560 auto *ifaceLowering = getIfacePortLowering(fp.ifaceInstance);
1563 ifaceLowering->expandedMembers[fp.bodySym] = val;
1565 ->expandedMembersByName[
builder.getStringAttr(fp.bodySym->name)] =
1571 llvm::scope_exit predeclaredInstancesGuard(
1581 if (failed(ModulePredeclaration(*this).predeclareScope(*module,
"")))
1585 for (
auto &member :
module->members()) {
1586 auto loc = convertLocation(member.location);
1587 if (failed(member.visit(ModuleVisitor(*
this, loc))))
1599 SmallVector<Value> outputs(lowering.numExplicitOutputs);
1600 for (
auto &port : lowering.ports) {
1602 if (
auto *expr = port.ast.getInternalExpr()) {
1603 value = convertLvalueExpression(*expr);
1604 }
else if (port.ast.internalSymbol) {
1605 if (
const auto *sym =
1606 port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
1607 value = valueSymbols.lookup(sym);
1610 return mlir::emitError(port.loc,
"unsupported port: `")
1612 <<
"` does not map to an internal symbol or expression";
1615 if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
1616 if (isa<moore::RefType>(value.getType()))
1617 value = moore::ReadOp::create(builder, value.getLoc(), value);
1618 outputs[*port.outputIdx] = value;
1624 Value portArg = port.arg;
1625 if (port.ast.direction != slang::ast::ArgumentDirection::In)
1626 portArg = moore::ReadOp::create(builder, port.loc, port.arg);
1627 moore::ContinuousAssignOp::create(builder, port.loc, value, portArg);
1632 for (
auto &fp : lowering.ifacePorts) {
1636 fp.bodySym ? fp.bodySym->as_if<slang::ast::ValueSymbol>() : nullptr;
1639 Value ref = valueSymbols.lookup(valueSym);
1642 outputs[*fp.outputIdx] =
1643 moore::ReadOp::create(builder, fp.loc, ref).getResult();
1648 for (
auto &hierPath : hierPaths[module]) {
1649 assert(!hierPath.valueSyms.empty() &&
"hierPath must have valueSyms");
1650 if (
auto hierValue = valueSymbols.lookup(hierPath.valueSyms.front()))
1651 if (hierPath.direction == slang::ast::ArgumentDirection::Out)
1652 outputs.push_back(hierValue);
1655 moore::OutputOp::create(builder, lowering.op.getLoc(), outputs);
1665 timeScale = package.getTimeScale().value_or(slang::TimeScale());
1666 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1668 OpBuilder::InsertionGuard g(
builder);
1671 for (
auto &member : package.members()) {
1673 if (failed(member.visit(PackageVisitor(*
this, loc))))
1684 auto &lowering =
functions[&subroutine];
1686 if (!lowering->op.getOperation())
1688 return lowering.get();
1691 if (!subroutine.thisVar) {
1693 SmallString<64> name;
1695 name += subroutine.name;
1697 SmallVector<Type, 1> noThis = {};
1704 const slang::ast::Type &thisTy = subroutine.thisVar->getType();
1705 moore::ClassDeclOp ownerDecl;
1707 if (
auto *classTy = thisTy.as_if<slang::ast::ClassType>()) {
1708 auto &ownerLowering =
classes[classTy];
1709 ownerDecl = ownerLowering->op;
1711 mlir::emitError(loc) <<
"expected 'this' to be a class type, got "
1712 << thisTy.toString();
1717 SmallString<64> qualName;
1718 qualName += ownerDecl.getSymName();
1720 qualName += subroutine.name;
1723 SmallVector<Type, 1> extraParams;
1725 auto classSym = mlir::FlatSymbolRefAttr::get(ownerDecl.getSymNameAttr());
1726 auto handleTy = moore::ClassHandleType::get(
getContext(), classSym);
1727 extraParams.push_back(handleTy);
1737 Context &
context,
const slang::ast::SubroutineSymbol &subroutine,
1738 ArrayRef<Type> prefixParams, ArrayRef<Type> suffixParams = {}) {
1739 using slang::ast::ArgumentDirection;
1741 SmallVector<Type> inputTypes;
1742 inputTypes.append(prefixParams.begin(), prefixParams.end());
1743 SmallVector<Type, 1> outputTypes;
1745 for (
const auto *arg : subroutine.getArguments()) {
1746 auto type =
context.convertType(arg->getType());
1749 if (arg->direction == ArgumentDirection::In) {
1750 inputTypes.push_back(type);
1752 inputTypes.push_back(
1753 moore::RefType::get(cast<moore::UnpackedType>(type)));
1757 inputTypes.append(suffixParams.begin(), suffixParams.end());
1759 const auto &returnType = subroutine.getReturnType();
1760 if (!returnType.isVoid()) {
1761 auto type =
context.convertType(returnType);
1764 outputTypes.push_back(type);
1767 return FunctionType::get(
context.getContext(), inputTypes, outputTypes);
1770static FailureOr<SmallVector<moore::DPIArgInfo>>
1772 const slang::ast::SubroutineSymbol &subroutine) {
1773 using slang::ast::ArgumentDirection;
1775 SmallVector<moore::DPIArgInfo> args;
1776 args.reserve(subroutine.getArguments().size() +
1777 (!subroutine.getReturnType().isVoid() ? 1 : 0));
1779 for (
const auto *arg : subroutine.getArguments()) {
1780 auto type =
context.convertType(arg->getType());
1783 moore::DPIArgDirection dir;
1784 switch (arg->direction) {
1785 case ArgumentDirection::In:
1786 dir = moore::DPIArgDirection::In;
1788 case ArgumentDirection::Out:
1789 dir = moore::DPIArgDirection::Out;
1791 case ArgumentDirection::InOut:
1792 dir = moore::DPIArgDirection::InOut;
1794 case ArgumentDirection::Ref:
1795 llvm_unreachable(
"'ref' is not legal for DPI functions");
1798 {StringAttr::get(
context.getContext(), arg->name), type, dir});
1801 if (!subroutine.getReturnType().isVoid()) {
1802 auto type =
context.convertType(subroutine.getReturnType());
1805 args.push_back({StringAttr::get(
context.getContext(),
"return"), type,
1806 moore::DPIArgDirection::Return});
1816 mlir::StringRef qualifiedName,
1817 llvm::SmallVectorImpl<Type> &extraParams) {
1821 OpBuilder::InsertionGuard g(
builder);
1827 builder.setInsertionPoint(it->second);
1832 SmallVector<Type> captureTypes;
1835 for (
auto *sym : capturesIt->second) {
1839 captureTypes.push_back(
1840 moore::RefType::get(cast<moore::UnpackedType>(type)));
1849 std::unique_ptr<FunctionLowering> lowering;
1850 Operation *insertedOp =
nullptr;
1851 if (!subroutine.thisVar &&
1852 subroutine.flags.has(slang::ast::MethodFlags::DPIImport)) {
1858 auto dpiOp = moore::DPIFuncOp::create(
1861 StringAttr::get(
getContext(), subroutine.name));
1862 SymbolTable::setSymbolVisibility(dpiOp, SymbolTable::Visibility::Private);
1863 lowering = std::make_unique<FunctionLowering>(dpiOp);
1865 }
else if (subroutine.subroutineKind == slang::ast::SubroutineKind::Task) {
1867 auto op = moore::CoroutineOp::create(
builder, loc, qualifiedName, funcTy);
1868 SymbolTable::setSymbolVisibility(op, SymbolTable::Visibility::Private);
1869 lowering = std::make_unique<FunctionLowering>(op);
1874 mlir::func::FuncOp::create(
builder, loc, qualifiedName, funcTy);
1875 SymbolTable::setSymbolVisibility(funcOp, SymbolTable::Visibility::Private);
1876 lowering = std::make_unique<FunctionLowering>(funcOp);
1877 insertedOp = funcOp;
1883 lowering->capturedSymbols.assign(capturesIt->second.begin(),
1884 capturesIt->second.end());
1889 functions[&subroutine] = std::move(lowering);
1903 auto *lowering =
functions.at(&subroutine).get();
1908 timeScale = subroutine.getTimeScale().value_or(slang::TimeScale());
1909 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
1914 if (subroutine.flags.has(slang::ast::MethodFlags::DPIImport))
1917 const bool isMethod = (subroutine.thisVar !=
nullptr);
1922 if (
const auto *classTy =
1923 subroutine.thisVar->getType().as_if<slang::ast::ClassType>()) {
1924 for (
auto &member : classTy->members()) {
1925 const auto *prop = member.as_if<slang::ast::ClassPropertySymbol>();
1928 const auto &propCanon = prop->getType().getCanonicalType();
1929 if (
const auto *vi =
1930 propCanon.as_if<slang::ast::VirtualInterfaceType>()) {
1940 SmallVector<moore::VariableOp> argVariables;
1941 auto &block = lowering->op.getFunctionBody().emplaceBlock();
1948 cast<FunctionType>(lowering->op.getFunctionType()).getInput(0);
1949 auto thisArg = block.addArgument(thisType, thisLoc);
1957 auto inputs = cast<FunctionType>(lowering->op.getFunctionType()).getInputs();
1958 auto astArgs = subroutine.getArguments();
1959 unsigned prefixCount = isMethod ? 1 : 0;
1960 auto valInputs = llvm::ArrayRef<Type>(inputs)
1961 .drop_front(prefixCount)
1962 .take_front(astArgs.size());
1964 for (
auto [astArg, type] : llvm::zip(astArgs, valInputs)) {
1966 auto blockArg = block.addArgument(type, loc);
1968 if (isa<moore::RefType>(type)) {
1971 OpBuilder::InsertionGuard g(
builder);
1972 builder.setInsertionPointToEnd(&block);
1974 auto shadowArg = moore::VariableOp::create(
1975 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
1976 StringAttr{}, blockArg);
1978 argVariables.push_back(shadowArg);
1981 const auto &argCanon = astArg->getType().getCanonicalType();
1982 if (
const auto *vi = argCanon.as_if<slang::ast::VirtualInterfaceType>())
1988 OpBuilder::InsertionGuard g(
builder);
1989 builder.setInsertionPointToEnd(&block);
1992 if (subroutine.returnValVar) {
1993 auto type =
convertType(*subroutine.returnValVar->getDeclaredType());
1996 returnVar = moore::VariableOp::create(
1997 builder, lowering->op->getLoc(),
1998 moore::RefType::get(cast<moore::UnpackedType>(type)), StringAttr{},
2000 valueSymbols.insert(subroutine.returnValVar, returnVar);
2008 for (
auto *sym : lowering->capturedSymbols) {
2012 auto refType = moore::RefType::get(cast<moore::UnpackedType>(type));
2014 auto blockArg = block.addArgument(refType, loc);
2020 llvm::scope_exit restoreThis([&] {
currentThisRef = savedThis; });
2028 if (isa<moore::CoroutineOp>(lowering->op.getOperation())) {
2029 moore::ReturnOp::create(
builder, lowering->op->getLoc());
2030 }
else if (returnVar && !subroutine.getReturnType().isVoid()) {
2032 moore::ReadOp::create(
builder, returnVar.getLoc(), returnVar);
2033 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(), read);
2035 mlir::func::ReturnOp::create(
builder, lowering->op->getLoc(),
2039 if (returnVar && returnVar.use_empty())
2040 returnVar.getDefiningOp()->erase();
2042 for (
auto var : argVariables) {
2043 if (llvm::all_of(var->getUsers(),
2044 [](
auto *user) { return isa<moore::ReadOp>(user); })) {
2045 for (
auto *user : llvm::make_early_inc_range(var->getUsers())) {
2046 user->getResult(0).replaceAllUsesWith(var.getInitial());
2058 const slang::ast::PrimitiveInstanceSymbol &prim) {
2059 if (prim.getDriveStrength().first.has_value() ||
2060 prim.getDriveStrength().second.has_value())
2062 <<
"primitive instances with explicit drive strengths are not "
2065 switch (prim.primitiveType.primitiveKind) {
2066 case slang::ast::PrimitiveSymbol::PrimitiveKind::NInput:
2069 case slang::ast::PrimitiveSymbol::PrimitiveKind::NOutput:
2072 case slang::ast::PrimitiveSymbol::PrimitiveKind::Fixed:
2077 <<
"unsupported instance of primitive `" << prim.primitiveType.name
2083 const slang::ast::PrimitiveInstanceSymbol &prim) {
2085 auto primName = prim.primitiveType.name;
2087 auto portConns = prim.getPortConnections();
2088 assert(portConns.size() >= 2 &&
2089 "n-input primitives should have at least 2 ports");
2093 portConns[0]->as<slang::ast::AssignmentExpression>().left();
2099 SmallVector<Value> inputVals;
2100 inputVals.reserve(portConns.size() - 1);
2101 for (
const auto *inputConn : portConns.subspan(1, portConns.size() - 1)) {
2105 inputVals.push_back(inputVal);
2108 Value nextInput = inputVals.front();
2110 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2112 for (Value inputVal : llvm::drop_begin(inputVals))
2114 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2118 for (Value inputVal : llvm::drop_begin(inputVals))
2120 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2124 for (Value inputVal : llvm::drop_begin(inputVals))
2126 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2129 .Case(
"nand", ([&] {
2130 for (Value inputVal : llvm::drop_begin(inputVals))
2132 moore::AndOp::create(
builder, loc, nextInput, inputVal);
2133 return moore::NotOp::create(
builder, loc, nextInput);
2136 for (Value inputVal : llvm::drop_begin(inputVals))
2138 moore::OrOp::create(
builder, loc, nextInput, inputVal);
2139 return moore::NotOp::create(
builder, loc, nextInput);
2141 .Case(
"xnor", ([&] {
2142 for (Value inputVal : llvm::drop_begin(inputVals))
2144 moore::XorOp::create(
builder, loc, nextInput, inputVal);
2145 return moore::NotOp::create(
builder, loc, nextInput);
2148 mlir::emitError(loc)
2149 <<
"unsupported primitive `" << primName <<
"`";
2156 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2161 if (prim.getDelay()) {
2162 const slang::ast::Expression *delayExpr;
2163 if (
const auto *delay3 =
2164 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2165 if (delay3->expr2 || delay3->expr3)
2166 return mlir::emitError(loc) <<
"only n-input primitives that specify a "
2167 "single delay are currently supported.";
2168 delayExpr = &delay3->expr1;
2169 }
else if (
const auto *delay =
2170 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2171 delayExpr = &delay->expr;
2173 llvm_unreachable(
"unexpected delay control type in primitive instance");
2176 *delayExpr, moore::TimeType::get(
getContext()));
2179 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal, result,
2182 moore::ContinuousAssignOp::create(
builder, loc, outputVal, result);
2189 const slang::ast::PrimitiveInstanceSymbol &prim) {
2191 auto primName = prim.primitiveType.name;
2193 auto portConns = prim.getPortConnections();
2194 assert(portConns.size() >= 2 &&
2195 "n-output primitives should have at least 2 ports");
2198 SmallVector<Value> outputVals;
2199 outputVals.reserve(portConns.size() - 1);
2200 for (
const auto *outputConn : portConns.subspan(0, portConns.size() - 1)) {
2201 auto &output = outputConn->as<slang::ast::AssignmentExpression>().left();
2205 outputVals.push_back(outputVal);
2213 llvm::StringSwitch<std::function<Value()>>(prim.primitiveType.name)
2215 ([&] {
return moore::NotOp::create(
builder, loc, inputVal); }))
2217 return moore::BoolCastOp::create(
builder, loc, inputVal);
2220 mlir::emitError(loc)
2221 <<
"unsupported primitive `" << primName <<
"`";
2229 if (prim.getDelay()) {
2230 const slang::ast::Expression *delayExpr;
2231 if (
const auto *delay3 =
2232 prim.getDelay()->as_if<slang::ast::Delay3Control>()) {
2233 if (delay3->expr2 || delay3->expr3)
2234 return mlir::emitError(loc)
2235 <<
"only n-output primitives that specify a "
2236 "single delay are currently supported.";
2237 delayExpr = &delay3->expr1;
2238 }
else if (
const auto *delay =
2239 prim.getDelay()->as_if<slang::ast::DelayControl>()) {
2240 delayExpr = &delay->expr;
2242 llvm_unreachable(
"unexpected delay control type in primitive instance");
2245 *delayExpr, moore::TimeType::get(
getContext()));
2250 for (
auto outputVal : outputVals) {
2251 auto dstType = cast<moore::RefType>(outputVal.getType()).getNestedType();
2256 moore::DelayedContinuousAssignOp::create(
builder, loc, outputVal,
2257 converted, delayVal);
2259 moore::ContinuousAssignOp::create(
builder, loc, outputVal, converted);
2266 const slang::ast::PrimitiveInstanceSymbol &prim) {
2267 auto primName = prim.primitiveType.name;
2272 if (primName ==
"pullup" || primName ==
"pulldown")
2276 mlir::emitError(loc) <<
"unsupported primitive `" << primName <<
"`";
2281 const slang::ast::PrimitiveInstanceSymbol &prim) {
2282 assert((prim.primitiveType.name ==
"pullup" ||
2283 prim.primitiveType.name ==
"pulldown") &&
2284 "expected pullup or pulldown primitive");
2286 assert(!prim.getDelay() &&
2287 "SystemVerilog does not allow pull gate primitives with delays");
2289 auto primName = prim.primitiveType.name;
2291 auto portConns = prim.getPortConnections();
2293 assert(portConns.size() == 1 &&
2294 "pullup/pulldown primitives should have exactly one port");
2297 portConns.front()->as<slang::ast::AssignmentExpression>().left());
2299 auto dstType = cast<moore::RefType>(portVal.getType()).getNestedType();
2300 auto dstTypeWidth = dstType.getBitSize();
2303 "expected fixed-width type for pullup/pulldown primitive");
2304 auto constVal = primName ==
"pullup" ? -1 : 0;
2305 auto c = moore::ConstantOp::create(
2307 moore::IntType::getInt(this->
getContext(), dstTypeWidth.value()),
2313 moore::ContinuousAssignOp::create(
builder, loc, portVal, converted);
2321mlir::StringAttr fullyQualifiedClassName(
Context &ctx,
2322 const slang::ast::Type &ty) {
2323 SmallString<64> name;
2324 SmallVector<llvm::StringRef, 8> parts;
2326 const slang::ast::Scope *scope = ty.getParentScope();
2328 const auto &sym = scope->asSymbol();
2330 case slang::ast::SymbolKind::Root:
2333 case slang::ast::SymbolKind::InstanceBody:
2334 case slang::ast::SymbolKind::Instance:
2335 case slang::ast::SymbolKind::Package:
2336 case slang::ast::SymbolKind::ClassType:
2337 if (!sym.name.empty())
2338 parts.push_back(sym.name);
2343 scope = sym.getParentScope();
2346 for (
auto p :
llvm::reverse(parts)) {
2351 return mlir::StringAttr::get(ctx.
getContext(), name);
2356std::pair<mlir::SymbolRefAttr, mlir::ArrayAttr>
2358 const slang::ast::ClassType &cls) {
2362 mlir::SymbolRefAttr base;
2363 if (
const auto *b = cls.getBaseClass())
2364 base = mlir::SymbolRefAttr::get(fullyQualifiedClassName(
context, *b));
2367 SmallVector<mlir::Attribute> impls;
2368 if (
auto ifaces = cls.getDeclaredInterfaces(); !ifaces.empty()) {
2369 impls.reserve(ifaces.size());
2370 for (
const auto *iface : ifaces)
2371 impls.push_back(
mlir::FlatSymbolRefAttr::
get(
2372 fullyQualifiedClassName(
context, *iface)));
2375 mlir::ArrayAttr implArr =
2376 impls.empty() ? mlir::ArrayAttr() :
mlir::ArrayAttr::
get(ctx, impls);
2378 return {base, implArr};
2383struct ClassDeclVisitorBase {
2389 :
context(ctx), builder(ctx.builder), classLowering(lowering) {}
2393 return context.convertLocation(sloc);
2399struct ClassPropertyVisitor : ClassDeclVisitorBase {
2400 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2403 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2404 if (!classLowering.
op.getBody().empty())
2407 OpBuilder::InsertionGuard ig(builder);
2409 Block *body = &classLowering.
op.getBody().emplaceBlock();
2410 builder.setInsertionPointToEnd(body);
2413 for (
const auto &mem : classAST.members()) {
2414 if (
const auto *prop = mem.as_if<slang::ast::ClassPropertySymbol>()) {
2415 if (failed(prop->visit(*
this)))
2424 LogicalResult visit(
const slang::ast::ClassPropertySymbol &prop) {
2426 auto ty =
context.convertType(prop.getType());
2430 if (prop.lifetime == slang::ast::VariableLifetime::Automatic) {
2431 moore::ClassPropertyDeclOp::create(builder, loc, prop.name, ty);
2439 if (!
context.globalVariables.lookup(&prop))
2440 return context.convertGlobalVariable(prop);
2445 LogicalResult visit(
const slang::ast::ClassType &cls) {
2446 return context.buildClassProperties(cls);
2450 template <
typename T>
2451 LogicalResult visit(T &&) {
2458struct ClassMethodVisitor : ClassDeclVisitorBase {
2459 using ClassDeclVisitorBase::ClassDeclVisitorBase;
2462 LogicalResult
run(
const slang::ast::ClassType &classAST) {
2466 if (classLowering.
op.getBody().empty())
2469 OpBuilder::InsertionGuard ig(builder);
2470 builder.setInsertionPointToEnd(&classLowering.
op.getBody().front());
2473 for (
const auto &mem : classAST.members()) {
2474 if (failed(mem.visit(*
this)))
2483 LogicalResult visit(
const slang::ast::ClassPropertySymbol &) {
2489 LogicalResult visit(
const slang::ast::ParameterSymbol &) {
return success(); }
2493 LogicalResult visit(
const slang::ast::TypeParameterSymbol &) {
2499 LogicalResult visit(
const slang::ast::TypeAliasType &) {
return success(); }
2502 LogicalResult visit(
const slang::ast::GenericClassDefSymbol &) {
2507 LogicalResult visit(
const slang::ast::TransparentMemberSymbol &) {
2512 LogicalResult visit(
const slang::ast::EmptyMemberSymbol &) {
2517 LogicalResult visit(
const slang::ast::SubroutineSymbol &fn) {
2518 if (fn.flags & slang::ast::MethodFlags::BuiltIn) {
2519 static bool remarkEmitted =
false;
2523 mlir::emitRemark(classLowering.
op.getLoc())
2524 <<
"Class builtin functions (needed for randomization, constraints, "
2525 "and covergroups) are not yet supported and will be dropped "
2527 remarkEmitted =
true;
2531 const mlir::UnitAttr isVirtual =
2532 (fn.flags & slang::ast::MethodFlags::Virtual)
2533 ? UnitAttr::get(
context.getContext())
2540 if (fn.flags & slang::ast::MethodFlags::Pure) {
2542 SmallVector<Type, 1> extraParams;
2544 mlir::FlatSymbolRefAttr::get(classLowering.
op.getSymNameAttr());
2546 moore::ClassHandleType::get(
context.getContext(), classSym);
2547 extraParams.push_back(handleTy);
2551 mlir::emitError(loc) <<
"Invalid function signature for " << fn.name;
2555 moore::ClassMethodDeclOp::create(builder, loc, fn.name, funcTy,
nullptr);
2559 auto *lowering =
context.declareFunction(fn);
2568 FunctionType fnTy = cast<FunctionType>(lowering->op.getFunctionType());
2570 moore::ClassMethodDeclOp::create(
2571 builder, loc, fn.name, fnTy,
2572 SymbolRefAttr::get(lowering->op.getNameAttr()));
2589 LogicalResult visit(
const slang::ast::MethodPrototypeSymbol &fn) {
2590 const auto *externImpl = fn.getSubroutine();
2594 <<
"Didn't find an implementation matching the forward declaration "
2599 return visit(*externImpl);
2603 LogicalResult visit(
const slang::ast::ClassType &cls) {
2604 if (failed(
context.buildClassProperties(cls)))
2606 return context.materializeClassMethods(cls);
2610 template <
typename T>
2611 LogicalResult visit(T &&node) {
2612 Location loc = UnknownLoc::get(
context.getContext());
2613 if constexpr (
requires { node.location; })
2615 mlir::emitError(loc) <<
"unsupported construct in ClassType members: "
2616 << slang::ast::toString(node.kind);
2624 auto &lowering =
classes[&cls];
2626 return lowering.get();
2627 lowering = std::make_unique<ClassLowering>();
2632 OpBuilder::InsertionGuard g(
builder);
2638 builder.setInsertionPoint(it->second);
2640 auto symName = fullyQualifiedClassName(*
this, cls);
2642 auto [base, impls] = buildBaseAndImplementsAttrs(*
this, cls);
2644 moore::ClassDeclOp::create(
builder, loc, symName, base, impls);
2646 SymbolTable::setSymbolVisibility(classDeclOp,
2647 SymbolTable::Visibility::Public);
2649 lowering->op = classDeclOp;
2652 return lowering.get();
2659 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2660 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2667 if (classdecl.getBaseClass()) {
2668 if (
const auto *baseClassDecl =
2669 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2680 return ClassPropertyVisitor(*
this, *lowering).run(classdecl);
2687 timeScale = classdecl.getTimeScale().value_or(slang::TimeScale());
2688 llvm::scope_exit timeScaleGuard([&] {
timeScale = prevTimeScale; });
2691 auto *lowering =
classes[&classdecl].get();
2698 if (classdecl.getBaseClass()) {
2699 if (
const auto *baseClassDecl =
2700 classdecl.getBaseClass()->as_if<slang::ast::ClassType>()) {
2706 return ClassMethodVisitor(*
this, *lowering).run(classdecl);
2716 OpBuilder::InsertionGuard g(
builder);
2722 builder.setInsertionPoint(it->second);
2726 SmallString<64> symName;
2730 if (
const auto *classVar = var.as_if<slang::ast::ClassPropertySymbol>()) {
2731 if (
const auto *parentScope = classVar->getParentScope()) {
2732 if (
const auto *parentClass =
2733 parentScope->asSymbol().as_if<slang::ast::ClassType>())
2734 symName = fullyQualifiedClassName(*
this, *parentClass);
2736 mlir::emitError(loc)
2737 <<
"Could not access parent class of class property "
2742 mlir::emitError(loc) <<
"Could not get parent scope of class property "
2747 symName += var.name;
2750 symName += var.name;
2759 auto varOp = moore::GlobalVariableOp::create(
builder, loc, symName,
2760 cast<moore::UnpackedType>(type));
2771 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 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 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
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.