10#include "slang/ast/types/AllTypes.h"
11#include "slang/syntax/AllSyntax.h"
14using namespace ImportVerilog;
21 TypeVisitor(
Context &context, Location loc) : context(context), loc(loc) {}
24 Type getSimpleBitVectorType(
const slang::ast::IntegralType &type) {
25 return moore::IntType::get(context.
getContext(), type.bitWidth,
26 type.isFourState ? Domain::FourValued
31 Type visit(
const slang::ast::VoidType &type) {
32 return moore::VoidType::get(context.
getContext());
35 Type visit(
const slang::ast::ScalarType &type) {
36 return getSimpleBitVectorType(type);
39 Type visit(
const slang::ast::FloatingType &type) {
40 if (type.floatKind == slang::ast::FloatingType::Kind::RealTime)
41 return moore::TimeType::get(context.
getContext());
42 if (type.floatKind == slang::ast::FloatingType::Kind::Real)
43 return moore::RealType::get(context.
getContext(), moore::RealWidth::f64);
44 return moore::RealType::get(context.
getContext(), moore::RealWidth::f32);
47 Type visit(
const slang::ast::PredefinedIntegerType &type) {
48 if (type.integerKind == slang::ast::PredefinedIntegerType::Kind::Time)
49 return moore::TimeType::get(context.
getContext());
50 return getSimpleBitVectorType(type);
53 Type visit(
const slang::ast::PackedArrayType &type) {
55 if (type.elementType.as_if<slang::ast::ScalarType>())
56 return getSimpleBitVectorType(type);
59 auto innerType = type.elementType.visit(*
this);
63 return moore::ArrayType::get(type.range.width(),
64 cast<moore::PackedType>(innerType));
67 Type visit(
const slang::ast::QueueType &type) {
68 auto innerType = type.elementType.visit(*
this);
71 return moore::QueueType::get(cast<moore::UnpackedType>(innerType),
75 Type visit(
const slang::ast::AssociativeArrayType &type) {
76 auto innerType = type.elementType.visit(*
this);
79 if (!type.indexType) {
81 loc,
"unsupported type: associative arrays with wildcard index");
84 auto indexType = type.indexType->visit(*
this);
87 return moore::AssocArrayType::get(cast<moore::UnpackedType>(innerType),
88 cast<moore::UnpackedType>(indexType));
91 Type visit(
const slang::ast::FixedSizeUnpackedArrayType &type) {
92 auto innerType = type.elementType.visit(*
this);
95 return moore::UnpackedArrayType::get(type.range.width(),
96 cast<moore::UnpackedType>(innerType));
99 Type visit(
const slang::ast::DynamicArrayType &type) {
100 auto innerType = type.elementType.visit(*
this);
103 return moore::OpenUnpackedArrayType::get(
104 cast<moore::UnpackedType>(innerType));
107 Type visit(
const slang::ast::DPIOpenArrayType &type) {
108 auto innerType = type.elementType.visit(*
this);
112 return moore::OpenArrayType::get(cast<moore::PackedType>(innerType));
113 return moore::OpenUnpackedArrayType::get(
114 cast<moore::UnpackedType>(innerType));
118 Type visit(
const slang::ast::TypeAliasType &type) {
120 return type.targetType.getType().visit(*
this);
124 Type visit(
const slang::ast::EnumType &type) {
126 return type.baseType.visit(*
this);
131 collectMembers(
const slang::ast::Scope &structType,
132 SmallVectorImpl<moore::StructLikeMember> &members) {
133 for (
auto &field : structType.membersOfType<slang::ast::FieldSymbol>()) {
134 auto name = StringAttr::get(context.
getContext(), field.name);
138 members.push_back({name, cast<moore::UnpackedType>(innerType)});
144 Type visit(
const slang::ast::PackedStructType &type) {
145 SmallVector<moore::StructLikeMember> members;
146 if (failed(collectMembers(type, members)))
148 return moore::StructType::get(context.
getContext(), members);
151 Type visit(
const slang::ast::UnpackedStructType &type) {
152 SmallVector<moore::StructLikeMember> members;
153 if (failed(collectMembers(type, members)))
155 return moore::UnpackedStructType::get(context.
getContext(), members);
158 Type visit(
const slang::ast::PackedUnionType &type) {
159 SmallVector<moore::StructLikeMember> members;
160 if (failed(collectMembers(type, members)))
162 return moore::UnionType::get(context.
getContext(), members);
165 Type visit(
const slang::ast::UnpackedUnionType &type) {
166 SmallVector<moore::StructLikeMember> members;
167 if (failed(collectMembers(type, members)))
169 return moore::UnpackedUnionType::get(context.
getContext(), members);
172 Type visit(
const slang::ast::StringType &type) {
173 return moore::StringType::get(context.
getContext());
176 Type visit(
const slang::ast::CHandleType &type) {
177 return moore::ChandleType::get(context.
getContext());
180 Type visit(
const slang::ast::ClassType &type) {
185 mlir::emitError(loc) <<
"no lowering generated for class type `"
186 << type.toString() <<
"`";
189 mlir::StringAttr symName = lowering->
op.getSymNameAttr();
190 mlir::FlatSymbolRefAttr symRef = mlir::FlatSymbolRefAttr::get(symName);
191 return moore::ClassHandleType::get(context.
getContext(), symRef);
194 Type visit(
const slang::ast::NullType &type) {
195 return moore::NullType::get(context.
getContext());
198 Type visit(
const slang::ast::VirtualInterfaceType &type) {
205 Type visit(
const slang::ast::EventType &type) {
208 return moore::IntType::getInt(context.
getContext(), 1);
212 template <
typename T>
213 Type visit(T &&node) {
214 auto d = mlir::emitError(loc,
"unsupported type: ")
215 << slang::ast::toString(node.kind);
216 d.attachNote() << node.template as<slang::ast::Type>().toString();
224Type Context::convertType(
const slang::ast::Type &type, LocationAttr loc) {
227 return type.visit(TypeVisitor(*
this, loc));
232 if (
auto *ts = type.getTypeSyntax())
239 const slang::ast::VirtualInterfaceType &type, Location loc) {
240 const slang::ast::InstanceBodySymbol &ifaceBody = type.iface.body;
241 const slang::ast::ModportSymbol *modport = type.modport;
248 SmallVector<moore::StructLikeMember> members;
249 SmallVector<StringAttr, 8> fieldNames;
250 DenseMap<StringAttr, Type> fieldTypes;
252 auto addField = [&](StringRef name,
const slang::ast::Type &fieldAstType,
253 Location fieldLoc) -> LogicalResult {
254 auto nameAttr =
builder.getStringAttr(name);
256 Type loweredType =
convertType(fieldAstType, fieldLoc);
260 auto unpacked = dyn_cast<moore::UnpackedType>(loweredType);
262 mlir::emitError(fieldLoc)
263 <<
"unsupported virtual interface member type: " << loweredType;
267 auto refTy = moore::RefType::get(unpacked);
269 if (
auto it = fieldTypes.find(nameAttr); it != fieldTypes.end()) {
270 if (it->second != refTy) {
271 mlir::emitError(fieldLoc) <<
"virtual interface member `" << name
272 <<
"` has conflicting types (" << it->second
273 <<
" vs " << refTy <<
")";
279 fieldTypes.try_emplace(nameAttr, refTy);
280 members.push_back({nameAttr, refTy});
281 fieldNames.push_back(nameAttr);
286 for (
auto &member : modport->members()) {
287 const auto *mpp = member.as_if<slang::ast::ModportPortSymbol>();
290 <<
"unsupported modport member: "
291 << slang::ast::toString(member.kind);
292 if (!member.name.empty())
293 d <<
" `" << member.name <<
"`";
296 if (failed(addField(mpp->name, mpp->getType(),
301 for (
auto *symbol : ifaceBody.getPortList()) {
304 const auto *port = symbol->as_if<slang::ast::PortSymbol>();
307 <<
"unsupported interface port symbol: "
308 << slang::ast::toString(symbol->kind);
309 if (!symbol->name.empty())
310 d <<
" `" << symbol->name <<
"`";
313 if (failed(addField(port->name, port->getType(),
318 for (
auto &member : ifaceBody.members()) {
319 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
320 if (failed(addField(var->name, var->getType(),
325 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
326 if (failed(addField(net->name, net->getType(),
333 if (member.as_if<slang::ast::ModportSymbol>() ||
334 member.as_if<slang::ast::ParameterSymbol>() ||
335 member.as_if<slang::ast::TypeParameterSymbol>())
341 if (
const auto *value = member.as_if<slang::ast::ValueSymbol>()) {
343 <<
"unsupported interface member: "
344 << slang::ast::toString(value->kind);
345 if (!value->name.empty())
346 d <<
" `" << value->name <<
"`";
352 cache.type = moore::UnpackedStructType::get(
getContext(), members);
353 cache.fieldNames = fieldNames;
358 const slang::ast::VirtualInterfaceType &type, Location loc) {
359 if (!type.isRealIface) {
361 <<
"cannot materialize value for non-real virtual interface";
366 if (failed(loweredType))
369 const slang::ast::InstanceBodySymbol &ifaceBody = type.iface.body;
370 const slang::ast::ModportSymbol *modport = type.modport;
377 if (!ifaceLowering) {
378 mlir::emitError(loc) <<
"interface instance `" << type.iface.name
379 <<
"` was not expanded";
383 SmallVector<Value> fields;
384 fields.reserve(cache.fieldNames.size());
386 auto resolveInterfaceMember = [&](StringAttr nameAttr) -> FailureOr<Value> {
390 if (Value val = ifaceLowering->expandedMembersByName.lookup(nameAttr))
393 mlir::emitError(loc) <<
"unresolved interface member `"
394 << nameAttr.getValue() <<
"`";
399 DenseMap<StringAttr, const slang::ast::ModportPortSymbol *> portsByName;
400 for (
auto &sym : modport->members()) {
401 const auto *port = sym.as_if<slang::ast::ModportPortSymbol>();
404 <<
"unsupported modport member: "
405 << slang::ast::toString(sym.kind);
406 if (!sym.name.empty())
407 d <<
" `" << sym.name <<
"`";
410 auto nameAttr =
builder.getStringAttr(port->name);
411 portsByName.try_emplace(nameAttr, port);
414 for (
auto nameAttr : cache.fieldNames) {
415 const auto *port = portsByName.lookup(nameAttr);
418 <<
"unresolved modport member `" << nameAttr.getValue() <<
"`";
422 if (port->internalSymbol) {
424 ifaceLowering->expandedMembers.lookup(port->internalSymbol)) {
425 fields.push_back(val);
430 auto resolved = resolveInterfaceMember(
431 builder.getStringAttr(port->internalSymbol->name));
432 if (failed(resolved))
434 fields.push_back(*resolved);
438 const auto *connExpr = port->getConnectionExpr();
440 mlir::emitError(loc) <<
"modport member `" << nameAttr.getValue()
441 <<
"` has no connection";
448 for (
const auto &[sym, value] : ifaceLowering->expandedMembers) {
449 const auto *valueSym = sym->as_if<slang::ast::ValueSymbol>();
459 fields.push_back(val);
462 for (
auto nameAttr : cache.fieldNames) {
463 auto val = resolveInterfaceMember(nameAttr);
466 fields.push_back(*val);
470 return moore::StructCreateOp::create(
builder, loc, cache.type, fields)
475 const slang::ast::ValueSymbol &base,
476 const slang::ast::VirtualInterfaceType &type, Location loc) {
479 mlir::emitError(loc) <<
"internal error: no virtual interface member scope";
483 auto registerMember = [&](
const slang::ast::ValueSymbol &member,
484 StringRef fieldName) {
490 existing.base == &base && existing.fieldName == entry.
fieldName)
496 if (
const auto *modport = type.modport) {
497 for (
auto &sym : modport->members()) {
498 const auto *port = sym.as_if<slang::ast::ModportPortSymbol>();
501 <<
"unsupported modport member: "
502 << slang::ast::toString(sym.kind);
503 if (!sym.name.empty())
504 d <<
" `" << sym.name <<
"`";
507 registerMember(*port, port->name);
508 if (port->internalSymbol)
509 if (
const auto *internal =
510 port->internalSymbol->as_if<slang::ast::ValueSymbol>())
511 registerMember(*internal, port->name);
516 const slang::ast::InstanceBodySymbol &ifaceBody = type.iface.body;
520 for (
const auto *symbol : ifaceBody.getPortList()) {
523 const auto *port = symbol->as_if<slang::ast::PortSymbol>();
526 <<
"unsupported interface port symbol: "
527 << slang::ast::toString(symbol->kind);
528 if (!symbol->name.empty())
529 d <<
" `" << symbol->name <<
"`";
532 if (!port->internalSymbol)
534 if (
const auto *internal =
535 port->internalSymbol->as_if<slang::ast::ValueSymbol>())
536 registerMember(*internal, port->name);
540 for (
auto &member : ifaceBody.members()) {
541 if (
const auto *var = member.as_if<slang::ast::VariableSymbol>()) {
542 registerMember(*var, var->name);
545 if (
const auto *net = member.as_if<slang::ast::NetSymbol>()) {
546 registerMember(*net, net->name);
mlir::Type innerType(mlir::Type type)
Domain
The number of values each bit of a type can assume.
@ TwoValued
Two-valued types such as bit or int.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
circt::moore::ClassDeclOp op
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
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...
DenseMap< const slang::ast::InstanceBodySymbol *, VirtualInterfaceLowering > virtualIfaceLowerings
Cached virtual interface layouts (type + field order).
OpBuilder builder
The builder used to create IR operations.
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.
ClassLowering * declareClass(const slang::ast::ClassType &cls)
ValueSymbols valueSymbols
ValueSymbols::ScopeTy ValueSymbolScope
VirtualInterfaceMembers virtualIfaceMembers
DenseMap< const slang::ast::ModportSymbol *, VirtualInterfaceLowering > virtualIfaceModportLowerings
FailureOr< Value > materializeVirtualInterfaceValue(const slang::ast::VirtualInterfaceType &type, Location loc)
Materialize a Moore value representing a concrete interface instance as a virtual interface handle.
InterfaceInstances interfaceInstances
LogicalResult buildClassProperties(const slang::ast::ClassType &classdecl)
MLIRContext * getContext()
Return the MLIR context.
FailureOr< moore::UnpackedStructType > convertVirtualInterfaceType(const slang::ast::VirtualInterfaceType &type, Location loc)
Convert a Slang virtual interface type into the Moore type used to represent virtual interface handle...
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
A mapping entry for resolving Slang virtual interface member accesses.
const slang::ast::ValueSymbol * base
StringAttr fieldName
The name of the field in the lowered virtual interface handle struct that should be accessed for this...