14#include "mlir/IR/Operation.h"
15#include "mlir/IR/Value.h"
16#include "slang/ast/EvalContext.h"
17#include "slang/ast/SystemSubroutine.h"
18#include "slang/ast/types/AllTypes.h"
19#include "slang/syntax/AllSyntax.h"
20#include "llvm/ADT/ScopeExit.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/Support/SaveAndRestore.h"
25using namespace ImportVerilog;
30 if (svint.hasUnknown()) {
31 unsigned numWords = svint.getNumWords() / 2;
32 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
33 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
34 return FVInt(APInt(svint.getBitWidth(), value),
35 APInt(svint.getBitWidth(), unknown));
37 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
38 return FVInt(APInt(svint.getBitWidth(), value));
43static Value
getIsUnknown(OpBuilder &builder, Location loc, Value value,
44 moore::IntType valTy, MLIRContext *ctx) {
46 if (valTy.getWidth() > 1) {
47 auto mooreI1Type = moore::IntType::get(ctx, 1, valTy.getDomain());
48 bitVal = moore::ReduceXorOp::create(builder, loc, mooreI1Type, value);
50 auto xType = moore::IntType::get(ctx, 1, moore::Domain::FourValued);
53 return moore::CaseEqOp::create(builder, loc, bitVal, xConst).getResult();
59 moore::IntType valTy) {
60 if (valTy.getDomain() == moore::Domain::FourValued)
61 value = builder.createOrFold<moore::LogicToIntOp>(loc, value);
62 return builder.createOrFold<moore::ToBuiltinIntOp>(loc, value);
66 const slang::ConstantRange &range) {
67 auto &builder =
context.builder;
68 auto indexType = cast<moore::UnpackedType>(index.getType());
71 auto lo = range.lower();
72 auto hi = range.upper();
73 auto offset = range.isDescending() ? lo : hi;
76 const bool needSigned = (lo < 0) || (hi < 0);
79 const uint64_t maxAbs = std::max<uint64_t>(std::abs(lo), std::abs(hi));
84 unsigned want = needSigned
85 ? (llvm::Log2_64_Ceil(std::max<uint64_t>(1, maxAbs)) + 1)
86 : std::max<unsigned>(1, llvm::Log2_64_Ceil(maxAbs + 1));
89 const unsigned bw = std::max<unsigned>(want, indexType.getBitSize().value());
92 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
93 index =
context.materializeConversion(intType, index, needSigned, loc);
96 if (range.isDescending())
98 return moore::NegOp::create(builder, loc, index);
102 moore::ConstantOp::create(builder, loc, intType, offset, needSigned);
103 if (range.isDescending())
104 return moore::SubOp::create(builder, loc, index, offsetConst);
105 return moore::SubOp::create(builder, loc, offsetConst, index);
110 static_assert(int(slang::TimeUnit::Seconds) == 0);
111 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
112 static_assert(int(slang::TimeUnit::Microseconds) == 2);
113 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
114 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
115 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
117 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
118 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
119 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
121 auto exp =
static_cast<unsigned>(
context.timeScale.base.unit);
124 auto scale =
static_cast<uint64_t
>(
context.timeScale.base.magnitude);
133 Context &
context,
const slang::ast::HierarchicalValueExpression &expr) {
134 auto nameAttr =
context.builder.getStringAttr(expr.symbol.name);
135 for (
const auto &element : expr.ref.path) {
136 auto *inst = element.symbol->as_if<slang::ast::InstanceSymbol>();
139 auto *lowering =
context.interfaceInstances.lookup(inst);
142 if (
auto it = lowering->expandedMembers.find(&expr.symbol);
143 it != lowering->expandedMembers.end())
145 if (
auto it = lowering->expandedMembersByName.find(nameAttr);
146 it != lowering->expandedMembersByName.end())
153 const slang::ast::ClassPropertySymbol &expr) {
154 auto loc =
context.convertLocation(expr.location);
155 auto builder =
context.builder;
156 auto type =
context.convertType(expr.getType());
157 auto fieldTy = cast<moore::UnpackedType>(type);
158 auto fieldRefTy = moore::RefType::get(fieldTy);
160 if (expr.lifetime == slang::ast::VariableLifetime::Static) {
163 if (!
context.globalVariables.lookup(&expr)) {
164 if (failed(
context.convertGlobalVariable(expr))) {
169 if (
auto globalOp =
context.globalVariables.lookup(&expr))
170 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
172 mlir::emitError(loc) <<
"Failed to access static member variable "
173 << expr.name <<
" as a global variable";
178 mlir::Value instRef =
context.getImplicitThisRef();
180 mlir::emitError(loc) <<
"class property '" << expr.name
181 <<
"' referenced without an implicit 'this'";
185 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.name);
187 moore::ClassHandleType classTy =
188 cast<moore::ClassHandleType>(instRef.getType());
190 auto targetClassHandle =
191 context.getAncestorClassWithProperty(classTy, expr.name, loc);
192 if (!targetClassHandle)
195 auto upcastRef =
context.materializeConversion(targetClassHandle, instRef,
196 false, instRef.getLoc());
200 Value fieldRef = moore::ClassPropertyRefOp::create(builder, loc, fieldRefTy,
201 upcastRef, fieldSym);
219template <
typename RangeT>
221 assert(type.hasFixedRange());
222 const slang::ConstantRange &cstRange = type.getFixedRange();
223 if (cstRange.left < cstRange.right)
224 std::reverse(std::begin(range), std::end(range));
235 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
236 : context(context), loc(loc), builder(context.builder),
237 isLvalue(isLvalue) {}
243 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
251 Value materializeSymbolRvalue(
const slang::ast::ValueSymbol &sym) {
253 if (isa<moore::RefType>(value.getType())) {
254 auto readOp = moore::ReadOp::create(builder, loc, value);
257 return readOp.getResult();
263 auto ref = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
264 auto readOp = moore::ReadOp::create(builder, loc, ref);
267 return readOp.getResult();
270 if (
auto *
const property = sym.as_if<slang::ast::ClassPropertySymbol>()) {
272 auto readOp = moore::ReadOp::create(builder, loc, fieldRef);
275 return readOp.getResult();
281 Value visit(
const slang::ast::NewArrayExpression &expr) {
286 if (expr.initExpr()) {
288 <<
"unsupported expression: array `new` with initializer\n";
293 expr.sizeExpr(), context.
convertType(*expr.sizeExpr().type));
297 return moore::OpenUArrayCreateOp::create(builder, loc, type, initialSize);
301 Value visit(
const slang::ast::ElementSelectExpression &expr) {
303 auto value = convertLvalueOrRvalueExpression(expr.value());
308 auto derefType = value.getType();
310 derefType = cast<moore::RefType>(derefType).getNestedType();
312 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType,
313 moore::QueueType, moore::AssocArrayType, moore::StringType,
314 moore::OpenUnpackedArrayType, moore::StructType, moore::UnionType>(
316 mlir::emitError(loc) <<
"unsupported expression: element select into "
317 << expr.value().type->toString() <<
"\n";
321 if (!isLvalue && isa<moore::StructType, moore::UnionType>(derefType)) {
325 derefType = value.getType();
329 if (isa<moore::AssocArrayType>(derefType)) {
330 auto assocArray = cast<moore::AssocArrayType>(derefType);
331 auto expectedIndexType = assocArray.getIndexType();
337 if (givenIndex.getType() != expectedIndexType) {
339 <<
"Incorrect index type: expected index type of "
340 << expectedIndexType <<
" but was given " << givenIndex.getType();
344 return moore::AssocArrayExtractRefOp::create(
345 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
348 return moore::AssocArrayExtractOp::create(builder, loc, type, value,
353 if (isa<moore::StringType>(derefType)) {
355 mlir::emitError(loc) <<
"string index assignment not supported";
360 auto i32Type = moore::IntType::getInt(builder.getContext(), 32);
366 return moore::StringGetOp::create(builder, loc, value, index);
370 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
371 auto range = expr.value().type->getFixedRange();
372 if (
auto *constValue = expr.selector().getConstant();
373 constValue && constValue->isInteger()) {
374 assert(!constValue->hasUnknown());
375 assert(constValue->size() <= 32);
377 auto lowBit = constValue->integer().as<uint32_t>().value();
379 return llvm::TypeSwitch<Type, Value>(derefType)
380 .Case<moore::QueueType>([&](moore::QueueType) {
382 <<
"Unexpected LValue extract on Queue Type!";
386 return moore::ExtractRefOp::create(builder, loc, resultType,
388 range.translateIndex(lowBit));
390 return llvm::TypeSwitch<Type, Value>(derefType)
391 .Case<moore::QueueType>([&](moore::QueueType) {
392 mlir::emitError(loc) <<
"Unexpected RValue extract on Queue Type!";
396 return moore::ExtractOp::create(builder, loc, resultType, value,
397 range.translateIndex(lowBit));
404 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
405 if (isa<moore::QueueType>(derefType)) {
408 if (isa<moore::RefType>(value.getType())) {
409 context.
currentQueue = moore::ReadOp::create(builder, loc, value);
420 return llvm::TypeSwitch<Type, Value>(derefType)
421 .Case<moore::QueueType>([&](moore::QueueType) {
422 return moore::DynQueueRefElementOp::create(builder, loc, resultType,
426 return moore::DynExtractRefOp::create(builder, loc, resultType,
430 return llvm::TypeSwitch<Type, Value>(derefType)
431 .Case<moore::QueueType>([&](moore::QueueType) {
432 return moore::DynQueueExtractOp::create(builder, loc, resultType,
433 value, lowBit, lowBit);
436 return moore::DynExtractOp::create(builder, loc, resultType, value,
443 Value visit(
const slang::ast::NullLiteral &expr) {
445 if (isa<moore::ClassHandleType, moore::ChandleType, moore::EventType,
446 moore::NullType>(type))
447 return moore::NullOp::create(builder, loc);
448 mlir::emitError(loc) <<
"No null value definition found for value of type "
454 Value visit(
const slang::ast::RangeSelectExpression &expr) {
456 auto value = convertLvalueOrRvalueExpression(expr.value());
460 auto derefType = value.getType();
462 derefType = cast<moore::RefType>(derefType).getNestedType();
464 if (isa<moore::QueueType>(derefType)) {
465 return handleQueueRangeSelectExpressions(expr, type, value);
467 if (!isLvalue && isa<moore::StructType, moore::UnionType>(derefType)) {
473 return handleArrayRangeSelectExpressions(expr, type, value);
478 Value handleQueueRangeSelectExpressions(
479 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
481 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
487 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
490 mlir::emitError(loc) <<
"queue lvalue range selections are not supported";
493 return moore::DynQueueExtractOp::create(builder, loc, resultType, value,
499 Value handleArrayRangeSelectExpressions(
500 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
501 std::optional<int32_t> constLeft;
502 std::optional<int32_t> constRight;
503 if (
auto *constant = expr.left().getConstant())
504 constLeft = constant->integer().as<int32_t>();
505 if (
auto *constant = expr.right().getConstant())
506 constRight = constant->integer().as<int32_t>();
512 <<
"unsupported expression: range select with non-constant bounds";
532 int32_t offsetConst = 0;
533 auto range = expr.value().type->getFixedRange();
535 using slang::ast::RangeSelectionKind;
536 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
541 assert(constRight &&
"constness checked in slang");
542 offsetConst = *constRight;
553 offsetConst = *constLeft;
564 int32_t offsetAdd = 0;
569 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
570 range.isDescending()) {
571 assert(constRight &&
"constness checked in slang");
572 offsetAdd = 1 - *constRight;
578 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
579 !range.isDescending()) {
580 assert(constRight &&
"constness checked in slang");
581 offsetAdd = *constRight - 1;
585 if (offsetAdd != 0) {
587 offsetDyn = moore::AddOp::create(
588 builder, loc, offsetDyn,
589 moore::ConstantOp::create(
590 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
594 offsetConst += offsetAdd;
605 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
610 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
612 return moore::DynExtractOp::create(builder, loc, resultType, value,
615 offsetConst = range.translateIndex(offsetConst);
617 return moore::ExtractRefOp::create(builder, loc, resultType, value,
619 return moore::ExtractOp::create(builder, loc, resultType, value,
624 Value visit(
const slang::ast::ConcatenationExpression &expr) {
625 SmallVector<Value> operands;
626 if (expr.type->isString()) {
627 for (
auto *operand : expr.operands()) {
628 assert(!isLvalue &&
"checked by Slang");
629 auto value = convertLvalueOrRvalueExpression(*operand);
633 moore::StringType::get(context.
getContext()), value,
false,
637 operands.push_back(value);
639 return moore::StringConcatOp::create(builder, loc, operands);
641 if (expr.type->isQueue()) {
642 return handleQueueConcat(expr);
645 if (expr.type->isUnpackedArray()) {
646 assert(!isLvalue &&
"checked by Slang");
647 auto loweredType = context.
convertType(*expr.type, loc);
652 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(loweredType))
654 else if (
auto openType =
655 dyn_cast<moore::OpenUnpackedArrayType>(loweredType))
660 SmallVector<Value> operands;
661 for (
auto *operand : expr.operands()) {
662 if (operand->type->isVoid())
667 operands.push_back(value);
670 auto arrayType = moore::UnpackedArrayType::get(
672 return moore::ArrayCreateOp::create(builder, loc, arrayType, operands);
675 for (
auto *operand : expr.operands()) {
679 if (operand->type->isVoid())
681 auto value = convertLvalueOrRvalueExpression(*operand);
688 operands.push_back(value);
691 return moore::ConcatRefOp::create(builder, loc, operands);
692 return moore::ConcatOp::create(builder, loc, operands);
699 Value handleQueueConcat(
const slang::ast::ConcatenationExpression &expr) {
700 SmallVector<Value> operands;
703 cast<moore::QueueType>(context.
convertType(*expr.type, loc));
715 Value contigElements;
717 for (
auto *operand : expr.operands()) {
718 bool isSingleElement =
723 if (!isSingleElement && contigElements) {
724 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
728 assert(!isLvalue &&
"checked by Slang");
729 auto value = convertLvalueOrRvalueExpression(*operand);
737 moore::RefType::get(context.
getContext(), queueType);
739 if (!contigElements) {
741 moore::VariableOp::create(builder, loc, queueRefType, {}, {});
743 moore::QueuePushBackOp::create(builder, loc, contigElements, value);
751 if (!(isa<moore::QueueType>(value.getType()) &&
752 cast<moore::QueueType>(value.getType()).getElementType() ==
760 operands.push_back(value);
763 if (contigElements) {
764 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
767 return moore::QueueConcatOp::create(builder, loc, queueType, operands);
771 Value visit(
const slang::ast::MemberAccessExpression &expr) {
776 auto *valueType = expr.value().type.get();
777 auto memberName = builder.getStringAttr(expr.member.name);
783 if (valueType->isVirtualInterface()) {
784 auto memberType = dyn_cast<moore::UnpackedType>(type);
787 <<
"unsupported virtual interface member type: " << type;
790 auto resultRefType = moore::RefType::get(memberType);
798 auto memberRef = moore::StructExtractOp::create(
799 builder, loc, resultRefType, memberName, base);
802 return moore::ReadOp::create(builder, loc, memberRef);
806 if (valueType->isStruct()) {
808 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
810 auto value = convertLvalueOrRvalueExpression(expr.value());
815 return moore::StructExtractRefOp::create(builder, loc, resultType,
817 return moore::StructExtractOp::create(builder, loc, resultType,
822 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
824 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
826 auto value = convertLvalueOrRvalueExpression(expr.value());
831 return moore::UnionExtractRefOp::create(builder, loc, resultType,
833 return moore::UnionExtractOp::create(builder, loc, type, memberName,
838 if (valueType->isClass()) {
842 auto targetTy = cast<moore::ClassHandleType>(valTy);
854 if (expr.member.kind != slang::ast::SymbolKind::Parameter) {
860 moore::ClassHandleType upcastTargetTy =
874 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(),
876 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
880 Value fieldRef = moore::ClassPropertyRefOp::create(
881 builder, loc, fieldRefTy, baseVal, fieldSym);
884 return isLvalue ? fieldRef
885 : moore::ReadOp::create(builder, loc, fieldRef);
888 slang::ConstantValue constVal;
889 if (
auto param = expr.member.as_if<slang::ast::ParameterSymbol>()) {
890 constVal = param->getValue();
895 mlir::emitError(loc) <<
"Parameter " << expr.member.name
896 <<
" has no constant value";
900 mlir::emitError(loc,
"expression of type ")
901 << valueType->toString() <<
" has no member fields";
913struct RvalueExprVisitor :
public ExprVisitor {
915 : ExprVisitor(
context, loc, false) {}
916 using ExprVisitor::visit;
919 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
920 assert(!
context.lvalueStack.empty() &&
"parent assignments push lvalue");
921 auto lvalue =
context.lvalueStack.back();
922 return moore::ReadOp::create(builder, loc, lvalue);
926 Value visit(
const slang::ast::NamedValueExpression &expr) {
928 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
929 if (isa<moore::RefType>(value.getType())) {
930 auto readOp = moore::ReadOp::create(builder, loc, value);
931 if (
context.rvalueReadCallback)
932 context.rvalueReadCallback(readOp);
933 value = readOp.getResult();
939 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol)) {
940 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
941 return moore::ReadOp::create(builder, loc, value);
945 if (
auto *
const property =
946 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
948 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
955 if (
auto access =
context.virtualIfaceMembers.lookup(&expr.symbol);
957 auto type =
context.convertType(*expr.type);
960 auto memberType = dyn_cast<moore::UnpackedType>(type);
963 <<
"unsupported virtual interface member type: " << type;
967 Value base = materializeSymbolRvalue(*access.base);
969 auto d = mlir::emitError(loc,
"unknown name `")
970 << access.base->name <<
"`";
971 d.attachNote(
context.convertLocation(access.base->location))
972 <<
"no rvalue generated for virtual interface base";
976 auto fieldName = access.fieldName
978 : builder.getStringAttr(expr.symbol.name);
979 auto memberRefType = moore::RefType::get(memberType);
980 auto memberRef = moore::StructExtractOp::create(
981 builder, loc, memberRefType, fieldName, base);
982 auto readOp = moore::ReadOp::create(builder, loc, memberRef);
983 if (
context.rvalueReadCallback)
984 context.rvalueReadCallback(readOp);
985 return readOp.getResult();
989 auto constant =
context.evaluateConstant(expr);
990 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
995 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
996 d.attachNote(
context.convertLocation(expr.symbol.location))
997 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
1002 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
1003 auto hierLoc =
context.convertLocation(expr.symbol.location);
1009 if (!expr.ref.path.empty()) {
1010 if (
auto *inst = expr.ref.path.front()
1011 .symbol->as_if<slang::ast::InstanceSymbol>()) {
1013 expr.symbol.getParentScope()->getContainingInstance();
1014 if (&inst->body == symbolBody ||
1015 (symbolBody && inst->body.getDeclaringDefinition() ==
1016 symbolBody->getDeclaringDefinition())) {
1017 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
1018 if (isa<moore::RefType>(value.getType())) {
1019 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
1020 if (
context.rvalueReadCallback)
1021 context.rvalueReadCallback(readOp);
1022 value = readOp.getResult();
1032 if (
auto value =
context.resolveCapturedValue(expr.symbol)) {
1033 if (isa<moore::RefType>(value.getType())) {
1034 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
1035 if (
context.rvalueReadCallback)
1036 context.rvalueReadCallback(readOp);
1037 value = readOp.getResult();
1046 if (
auto key =
context.buildHierValueKey(expr)) {
1047 if (
auto it =
context.hierValueSymbols.find(*key);
1048 it !=
context.hierValueSymbols.end()) {
1049 auto value = it->second;
1050 if (isa<moore::RefType>(value.getType())) {
1051 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
1052 if (
context.rvalueReadCallback)
1053 context.rvalueReadCallback(readOp);
1054 value = readOp.getResult();
1061 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
1062 if (isa<moore::RefType>(value.getType())) {
1063 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
1064 if (
context.rvalueReadCallback)
1065 context.rvalueReadCallback(readOp);
1066 value = readOp.getResult();
1072 if (isa<moore::RefType>(value.getType())) {
1073 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
1074 if (
context.rvalueReadCallback)
1075 context.rvalueReadCallback(readOp);
1076 return readOp.getResult();
1084 slang::ConstantValue constant;
1085 switch (expr.symbol.kind) {
1086 case slang::ast::SymbolKind::Parameter:
1087 constant = expr.symbol.as<slang::ast::ParameterSymbol>().getValue(
1090 case slang::ast::SymbolKind::Specparam:
1091 constant = expr.symbol.as<slang::ast::SpecparamSymbol>().getValue(
1094 case slang::ast::SymbolKind::EnumValue:
1095 constant = expr.symbol.as<slang::ast::EnumValueSymbol>().getValue(
1099 constant =
context.evaluateConstant(expr);
1102 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1107 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
1108 << expr.symbol.name <<
"`";
1109 d.attachNote(hierLoc) <<
"no rvalue generated for "
1110 << slang::ast::toString(expr.symbol.kind);
1116 Value visit(
const slang::ast::ArbitrarySymbolExpression &expr) {
1117 const auto &canonTy = expr.type->getCanonicalType();
1118 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>()) {
1119 auto value =
context.materializeVirtualInterfaceValue(*vi, loc);
1125 mlir::emitError(loc) <<
"unsupported arbitrary symbol expression of type "
1126 << expr.type->toString();
1131 Value visit(
const slang::ast::ConversionExpression &expr) {
1132 auto type =
context.convertType(*expr.type);
1135 return context.convertRvalueExpression(expr.operand(), type);
1139 Value visit(
const slang::ast::AssignmentExpression &expr) {
1140 auto lhs =
context.convertLvalueExpression(expr.left());
1145 context.lvalueStack.push_back(lhs);
1146 auto rhs =
context.convertRvalueExpression(
1147 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
1148 context.lvalueStack.pop_back();
1155 if (!expr.isNonBlocking()) {
1156 if (expr.timingControl)
1157 if (failed(
context.convertTimingControl(*expr.timingControl)))
1159 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
1160 if (
context.variableAssignCallback)
1161 context.variableAssignCallback(assignOp);
1166 if (expr.timingControl) {
1168 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
1169 auto delay =
context.convertRvalueExpression(
1170 ctrl->expr, moore::TimeType::get(builder.getContext()));
1173 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
1174 builder, loc, lhs, rhs, delay);
1175 if (
context.variableAssignCallback)
1176 context.variableAssignCallback(assignOp);
1181 auto loc =
context.convertLocation(expr.timingControl->sourceRange);
1182 mlir::emitError(loc)
1183 <<
"unsupported non-blocking assignment timing control: "
1184 << slang::ast::toString(expr.timingControl->kind);
1187 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
1188 if (
context.variableAssignCallback)
1189 context.variableAssignCallback(assignOp);
1195 template <
class ConcreteOp>
1196 Value createReduction(Value arg,
bool invert) {
1197 arg =
context.convertToSimpleBitVector(arg);
1200 Value result = ConcreteOp::create(builder, loc, arg);
1202 result = moore::NotOp::create(builder, loc, result);
1207 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
1208 auto preValue = moore::ReadOp::create(builder, loc, arg);
1214 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
1217 auto one = moore::ConstantOp::create(
1218 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
1220 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
1221 : moore::SubOp::create(builder, loc, preValue, one).getResult();
1223 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
1224 if (
context.variableAssignCallback)
1225 context.variableAssignCallback(assignOp);
1234 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
1235 Value preValue = moore::ReadOp::create(builder, loc, arg);
1238 bool isTime = isa<moore::TimeType>(preValue.getType());
1240 preValue =
context.materializeConversion(
1241 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1242 preValue,
false, loc);
1244 moore::RealType realTy =
1245 llvm::dyn_cast<moore::RealType>(preValue.getType());
1250 if (realTy.getWidth() == moore::RealWidth::f32) {
1251 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
1252 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
1254 oneAttr = builder.getFloatAttr(builder.getF64Type(), oneVal);
1256 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
1259 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
1263 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
1264 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
1267 postValue =
context.materializeConversion(
1268 moore::TimeType::get(
context.getContext()), postValue,
false, loc);
1271 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
1273 if (
context.variableAssignCallback)
1274 context.variableAssignCallback(assignOp);
1281 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
1282 Type opFTy =
context.convertType(*expr.operand().type);
1284 using slang::ast::UnaryOperator;
1286 if (expr.op == UnaryOperator::Preincrement ||
1287 expr.op == UnaryOperator::Predecrement ||
1288 expr.op == UnaryOperator::Postincrement ||
1289 expr.op == UnaryOperator::Postdecrement)
1290 arg =
context.convertLvalueExpression(expr.operand());
1292 arg =
context.convertRvalueExpression(expr.operand(), opFTy);
1297 if (isa<moore::TimeType>(arg.getType()))
1298 arg =
context.materializeConversion(
1299 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1304 case UnaryOperator::Plus:
1306 case UnaryOperator::Minus:
1307 return moore::NegRealOp::create(builder, loc, arg);
1309 case UnaryOperator::Preincrement:
1310 return createRealIncrement(arg,
true,
false);
1311 case UnaryOperator::Predecrement:
1312 return createRealIncrement(arg,
false,
false);
1313 case UnaryOperator::Postincrement:
1314 return createRealIncrement(arg,
true,
true);
1315 case UnaryOperator::Postdecrement:
1316 return createRealIncrement(arg,
false,
true);
1318 case UnaryOperator::LogicalNot:
1319 arg =
context.convertToBool(arg);
1322 return moore::NotOp::create(builder, loc, arg);
1325 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
1326 <<
" not supported with real values!\n";
1332 Value visit(
const slang::ast::UnaryExpression &expr) {
1334 const auto *floatType =
1335 expr.operand().type->as_if<slang::ast::FloatingType>();
1338 return visitRealUOp(expr);
1340 using slang::ast::UnaryOperator;
1342 if (expr.op == UnaryOperator::Preincrement ||
1343 expr.op == UnaryOperator::Predecrement ||
1344 expr.op == UnaryOperator::Postincrement ||
1345 expr.op == UnaryOperator::Postdecrement)
1346 arg =
context.convertLvalueExpression(expr.operand());
1348 arg =
context.convertRvalueExpression(expr.operand());
1355 case UnaryOperator::Plus:
1356 return context.convertToSimpleBitVector(arg);
1358 case UnaryOperator::Minus:
1359 arg =
context.convertToSimpleBitVector(arg);
1362 return moore::NegOp::create(builder, loc, arg);
1364 case UnaryOperator::BitwiseNot:
1365 arg =
context.convertToSimpleBitVector(arg);
1368 return moore::NotOp::create(builder, loc, arg);
1370 case UnaryOperator::BitwiseAnd:
1371 return createReduction<moore::ReduceAndOp>(arg,
false);
1372 case UnaryOperator::BitwiseOr:
1373 return createReduction<moore::ReduceOrOp>(arg,
false);
1374 case UnaryOperator::BitwiseXor:
1375 return createReduction<moore::ReduceXorOp>(arg,
false);
1376 case UnaryOperator::BitwiseNand:
1377 return createReduction<moore::ReduceAndOp>(arg,
true);
1378 case UnaryOperator::BitwiseNor:
1379 return createReduction<moore::ReduceOrOp>(arg,
true);
1380 case UnaryOperator::BitwiseXnor:
1381 return createReduction<moore::ReduceXorOp>(arg,
true);
1383 case UnaryOperator::LogicalNot:
1384 arg =
context.convertToBool(arg);
1387 return moore::NotOp::create(builder, loc, arg);
1389 case UnaryOperator::Preincrement:
1390 return createIncrement(arg,
true,
false);
1391 case UnaryOperator::Predecrement:
1392 return createIncrement(arg,
false,
false);
1393 case UnaryOperator::Postincrement:
1394 return createIncrement(arg,
true,
true);
1395 case UnaryOperator::Postdecrement:
1396 return createIncrement(arg,
false,
true);
1399 mlir::emitError(loc,
"unsupported unary operator");
1404 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
1405 std::optional<Domain> domain = std::nullopt) {
1406 using slang::ast::BinaryOperator;
1410 lhs =
context.convertToBool(lhs, domain.value());
1411 rhs =
context.convertToBool(rhs, domain.value());
1413 lhs =
context.convertToBool(lhs);
1414 rhs =
context.convertToBool(rhs);
1421 case BinaryOperator::LogicalAnd:
1422 return moore::AndOp::create(builder, loc, lhs, rhs);
1424 case BinaryOperator::LogicalOr:
1425 return moore::OrOp::create(builder, loc, lhs, rhs);
1427 case BinaryOperator::LogicalImplication: {
1429 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1430 return moore::OrOp::create(builder, loc, notLHS, rhs);
1433 case BinaryOperator::LogicalEquivalence: {
1435 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1436 auto notRHS = moore::NotOp::create(builder, loc, rhs);
1437 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
1438 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
1439 return moore::OrOp::create(builder, loc, both, notBoth);
1443 llvm_unreachable(
"not a logical BinaryOperator");
1447 Value visitHandleBOp(
const slang::ast::BinaryExpression &expr) {
1449 auto lhs =
context.convertRvalueExpression(expr.left());
1452 auto rhs =
context.convertRvalueExpression(expr.right());
1456 using slang::ast::BinaryOperator;
1459 case BinaryOperator::Equality:
1460 return moore::HandleEqOp::create(builder, loc, lhs, rhs);
1461 case BinaryOperator::Inequality:
1462 return moore::HandleNeOp::create(builder, loc, lhs, rhs);
1463 case BinaryOperator::CaseEquality:
1464 return moore::HandleCaseEqOp::create(builder, loc, lhs, rhs);
1465 case BinaryOperator::CaseInequality:
1466 return moore::HandleCaseNeOp::create(builder, loc, lhs, rhs);
1469 mlir::emitError(loc)
1470 <<
"Binary operator " << slang::ast::toString(expr.op)
1471 <<
" not supported with class handle valued operands!\n";
1476 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
1478 auto lhs =
context.convertRvalueExpression(expr.left());
1481 auto rhs =
context.convertRvalueExpression(expr.right());
1485 if (isa<moore::TimeType>(lhs.getType()) ||
1486 isa<moore::TimeType>(rhs.getType())) {
1487 lhs =
context.materializeConversion(
1488 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1490 rhs =
context.materializeConversion(
1491 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1495 using slang::ast::BinaryOperator;
1497 case BinaryOperator::Add:
1498 return moore::AddRealOp::create(builder, loc, lhs, rhs);
1499 case BinaryOperator::Subtract:
1500 return moore::SubRealOp::create(builder, loc, lhs, rhs);
1501 case BinaryOperator::Multiply:
1502 return moore::MulRealOp::create(builder, loc, lhs, rhs);
1503 case BinaryOperator::Divide:
1504 return moore::DivRealOp::create(builder, loc, lhs, rhs);
1505 case BinaryOperator::Power:
1506 return moore::PowRealOp::create(builder, loc, lhs, rhs);
1508 case BinaryOperator::Equality:
1509 return moore::EqRealOp::create(builder, loc, lhs, rhs);
1510 case BinaryOperator::Inequality:
1511 return moore::NeRealOp::create(builder, loc, lhs, rhs);
1513 case BinaryOperator::GreaterThan:
1514 return moore::FgtOp::create(builder, loc, lhs, rhs);
1515 case BinaryOperator::LessThan:
1516 return moore::FltOp::create(builder, loc, lhs, rhs);
1517 case BinaryOperator::GreaterThanEqual:
1518 return moore::FgeOp::create(builder, loc, lhs, rhs);
1519 case BinaryOperator::LessThanEqual:
1520 return moore::FleOp::create(builder, loc, lhs, rhs);
1522 case BinaryOperator::LogicalAnd:
1523 case BinaryOperator::LogicalOr:
1524 case BinaryOperator::LogicalImplication:
1525 case BinaryOperator::LogicalEquivalence: {
1526 Domain domain = Domain::TwoValued;
1527 if (expr.left().type->isFourState() || expr.right().type->isFourState())
1528 domain = Domain::FourValued;
1529 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1533 mlir::emitError(loc) <<
"Binary operator "
1534 << slang::ast::toString(expr.op)
1535 <<
" not supported with real valued operands!\n";
1542 template <
class ConcreteOp>
1543 Value createBinary(Value lhs, Value rhs) {
1544 lhs =
context.convertToSimpleBitVector(lhs);
1547 rhs =
context.convertToSimpleBitVector(rhs);
1550 return ConcreteOp::create(builder, loc, lhs, rhs);
1554 Value visit(
const slang::ast::BinaryExpression &expr) {
1555 if (expr.left().kind == slang::ast::ExpressionKind::TypeReference &&
1556 expr.right().kind == slang::ast::ExpressionKind::TypeReference) {
1558 expr.left().as<slang::ast::TypeReferenceExpression>().targetType;
1560 expr.right().as<slang::ast::TypeReferenceExpression>().targetType;
1561 bool value = lhsType.isMatching(rhsType);
1563 using slang::ast::BinaryOperator;
1565 case BinaryOperator::Equality:
1566 case BinaryOperator::CaseEquality:
1568 case BinaryOperator::Inequality:
1569 case BinaryOperator::CaseInequality:
1573 mlir::emitError(loc,
"unsupported type reference binary operator");
1577 auto type = moore::IntType::get(
context.getContext(), 1,
1578 moore::Domain::TwoValued);
1579 return moore::ConstantOp::create(builder, loc, type, value,
1584 const auto *rhsFloatType =
1585 expr.right().type->as_if<slang::ast::FloatingType>();
1586 const auto *lhsFloatType =
1587 expr.left().type->as_if<slang::ast::FloatingType>();
1590 if (rhsFloatType || lhsFloatType)
1591 return visitRealBOp(expr);
1594 const auto rhsIsClass = expr.right().type->isClass();
1595 const auto lhsIsClass = expr.left().type->isClass();
1596 const auto rhsIsChandle = expr.right().type->isCHandle();
1597 const auto lhsIsChandle = expr.left().type->isCHandle();
1599 if (rhsIsClass || lhsIsClass || rhsIsChandle || lhsIsChandle)
1600 return visitHandleBOp(expr);
1602 auto lhs =
context.convertRvalueExpression(expr.left());
1605 auto rhs =
context.convertRvalueExpression(expr.right());
1610 Domain domain = Domain::TwoValued;
1611 if (expr.type->isFourState() || expr.left().type->isFourState() ||
1612 expr.right().type->isFourState())
1613 domain = Domain::FourValued;
1615 using slang::ast::BinaryOperator;
1617 case BinaryOperator::Add:
1618 return createBinary<moore::AddOp>(lhs, rhs);
1619 case BinaryOperator::Subtract:
1620 return createBinary<moore::SubOp>(lhs, rhs);
1621 case BinaryOperator::Multiply:
1622 return createBinary<moore::MulOp>(lhs, rhs);
1623 case BinaryOperator::Divide:
1624 if (expr.type->isSigned())
1625 return createBinary<moore::DivSOp>(lhs, rhs);
1627 return createBinary<moore::DivUOp>(lhs, rhs);
1628 case BinaryOperator::Mod:
1629 if (expr.type->isSigned())
1630 return createBinary<moore::ModSOp>(lhs, rhs);
1632 return createBinary<moore::ModUOp>(lhs, rhs);
1633 case BinaryOperator::Power: {
1638 auto rhsCast =
context.materializeConversion(
1639 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
1640 if (expr.type->isSigned())
1641 return createBinary<moore::PowSOp>(lhs, rhsCast);
1642 return createBinary<moore::PowUOp>(lhs, rhsCast);
1645 case BinaryOperator::BinaryAnd:
1646 return createBinary<moore::AndOp>(lhs, rhs);
1647 case BinaryOperator::BinaryOr:
1648 return createBinary<moore::OrOp>(lhs, rhs);
1649 case BinaryOperator::BinaryXor:
1650 return createBinary<moore::XorOp>(lhs, rhs);
1651 case BinaryOperator::BinaryXnor: {
1652 auto result = createBinary<moore::XorOp>(lhs, rhs);
1655 return moore::NotOp::create(builder, loc, result);
1658 case BinaryOperator::Equality:
1659 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1660 return moore::UArrayCmpOp::create(
1661 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1662 else if (isa<moore::StringType>(lhs.getType()))
1663 return moore::StringCmpOp::create(
1664 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
1665 else if (isa<moore::QueueType>(lhs.getType()))
1666 return moore::QueueCmpOp::create(
1667 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1669 return createBinary<moore::EqOp>(lhs, rhs);
1670 case BinaryOperator::Inequality:
1671 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1672 return moore::UArrayCmpOp::create(
1673 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1674 else if (isa<moore::StringType>(lhs.getType()))
1675 return moore::StringCmpOp::create(
1676 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
1677 else if (isa<moore::QueueType>(lhs.getType()))
1678 return moore::QueueCmpOp::create(
1679 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1681 return createBinary<moore::NeOp>(lhs, rhs);
1682 case BinaryOperator::CaseEquality:
1683 return createBinary<moore::CaseEqOp>(lhs, rhs);
1684 case BinaryOperator::CaseInequality:
1685 return createBinary<moore::CaseNeOp>(lhs, rhs);
1686 case BinaryOperator::WildcardEquality:
1687 return createBinary<moore::WildcardEqOp>(lhs, rhs);
1688 case BinaryOperator::WildcardInequality:
1689 return createBinary<moore::WildcardNeOp>(lhs, rhs);
1691 case BinaryOperator::GreaterThanEqual:
1692 if (expr.left().type->isSigned())
1693 return createBinary<moore::SgeOp>(lhs, rhs);
1694 else if (isa<moore::StringType>(lhs.getType()))
1695 return moore::StringCmpOp::create(
1696 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
1698 return createBinary<moore::UgeOp>(lhs, rhs);
1699 case BinaryOperator::GreaterThan:
1700 if (expr.left().type->isSigned())
1701 return createBinary<moore::SgtOp>(lhs, rhs);
1702 else if (isa<moore::StringType>(lhs.getType()))
1703 return moore::StringCmpOp::create(
1704 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
1706 return createBinary<moore::UgtOp>(lhs, rhs);
1707 case BinaryOperator::LessThanEqual:
1708 if (expr.left().type->isSigned())
1709 return createBinary<moore::SleOp>(lhs, rhs);
1710 else if (isa<moore::StringType>(lhs.getType()))
1711 return moore::StringCmpOp::create(
1712 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1714 return createBinary<moore::UleOp>(lhs, rhs);
1715 case BinaryOperator::LessThan:
1716 if (expr.left().type->isSigned())
1717 return createBinary<moore::SltOp>(lhs, rhs);
1718 else if (isa<moore::StringType>(lhs.getType()))
1719 return moore::StringCmpOp::create(
1720 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1722 return createBinary<moore::UltOp>(lhs, rhs);
1724 case BinaryOperator::LogicalAnd:
1725 case BinaryOperator::LogicalOr:
1726 case BinaryOperator::LogicalImplication:
1727 case BinaryOperator::LogicalEquivalence:
1728 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1730 case BinaryOperator::LogicalShiftLeft:
1731 return createBinary<moore::ShlOp>(lhs, rhs);
1732 case BinaryOperator::LogicalShiftRight:
1733 return createBinary<moore::ShrOp>(lhs, rhs);
1734 case BinaryOperator::ArithmeticShiftLeft:
1735 return createBinary<moore::ShlOp>(lhs, rhs);
1736 case BinaryOperator::ArithmeticShiftRight: {
1739 lhs =
context.convertToSimpleBitVector(lhs);
1740 rhs =
context.convertToSimpleBitVector(rhs);
1743 if (expr.type->isSigned())
1744 return moore::AShrOp::create(builder, loc, lhs, rhs);
1745 return moore::ShrOp::create(builder, loc, lhs, rhs);
1749 mlir::emitError(loc,
"unsupported binary operator");
1754 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1755 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1759 Value visit(
const slang::ast::IntegerLiteral &expr) {
1760 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1764 Value visit(
const slang::ast::TimeLiteral &expr) {
1769 double value = std::round(expr.getValue() * scale);
1779 static constexpr uint64_t limit =
1780 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1781 if (value > limit) {
1782 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1786 return moore::ConstantTimeOp::create(builder, loc,
1787 static_cast<uint64_t
>(value));
1791 Value visit(
const slang::ast::ReplicationExpression &expr) {
1792 auto type =
context.convertType(*expr.type);
1793 auto value =
context.convertRvalueExpression(expr.concat());
1796 return moore::ReplicateOp::create(builder, loc, type, value);
1800 Value visit(
const slang::ast::InsideExpression &expr) {
1801 auto lhs =
context.convertToSimpleBitVector(
1802 context.convertRvalueExpression(expr.left()));
1807 SmallVector<Value> conditions;
1810 for (
const auto *listExpr : expr.rangeList()) {
1811 auto cond =
context.convertInsideCheck(lhs, loc, *listExpr);
1815 conditions.push_back(cond);
1819 auto result = conditions.back();
1820 conditions.pop_back();
1821 while (!conditions.empty()) {
1822 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1823 conditions.pop_back();
1829 Value visit(
const slang::ast::ConditionalExpression &expr) {
1830 auto type =
context.convertType(*expr.type);
1833 if (expr.conditions.size() > 1) {
1834 mlir::emitError(loc)
1835 <<
"unsupported conditional expression with more than one condition";
1838 const auto &cond = expr.conditions[0];
1840 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1844 context.convertToBool(
context.convertRvalueExpression(*cond.expr));
1847 auto conditionalOp =
1848 moore::ConditionalOp::create(builder, loc, type, value);
1851 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1852 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1854 OpBuilder::InsertionGuard g(builder);
1857 builder.setInsertionPointToStart(&trueBlock);
1858 auto trueValue =
context.convertRvalueExpression(expr.left(), type);
1861 moore::YieldOp::create(builder, loc, trueValue);
1864 builder.setInsertionPointToStart(&falseBlock);
1865 auto falseValue =
context.convertRvalueExpression(expr.right(), type);
1868 moore::YieldOp::create(builder, loc, falseValue);
1870 return conditionalOp.getResult();
1874 Value visit(
const slang::ast::CallExpression &expr) {
1876 auto constant =
context.evaluateConstant(expr);
1877 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1881 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1887 std::pair<Value, moore::ClassHandleType>
1888 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1890 moore::ClassHandleType handleTy;
1894 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1895 thisRef =
context.convertRvalueExpression(*recvExpr);
1900 thisRef =
context.getImplicitThisRef();
1902 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1903 <<
"' called without an object";
1907 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1908 return {thisRef, handleTy};
1912 mlir::CallOpInterface
1913 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1915 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1916 SmallVector<Value> &arguments,
1917 SmallVector<Type> &resultTypes) {
1920 auto funcTy = cast<FunctionType>(lowering->
op.getFunctionType());
1921 auto expected0 = funcTy.getInput(0);
1922 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1925 auto implicitThisRef =
context.materializeConversion(
1926 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1929 SmallVector<Value> explicitArguments;
1930 explicitArguments.reserve(arguments.size() + 1);
1931 explicitArguments.push_back(implicitThisRef);
1932 explicitArguments.append(arguments.begin(), arguments.end());
1935 const bool isVirtual =
1936 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1939 auto calleeSym = lowering->
op.getNameAttr().getValue();
1940 if (isa<moore::CoroutineOp>(lowering->
op.getOperation()))
1941 return moore::CallCoroutineOp::create(builder, loc, resultTypes,
1942 calleeSym, explicitArguments);
1943 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1947 auto funcName = subroutine->name;
1948 auto method = moore::VTableLoadMethodOp::create(
1949 builder, loc, funcTy, actualThisRef,
1950 SymbolRefAttr::get(
context.getContext(), funcName));
1951 return mlir::func::CallIndirectOp::create(builder, loc, method,
1956 Value visitCall(
const slang::ast::CallExpression &expr,
1957 const slang::ast::SubroutineSymbol *subroutine) {
1959 const bool isMethod = (subroutine->thisVar !=
nullptr);
1961 auto *lowering =
context.declareFunction(*subroutine);
1965 if (isa<moore::DPIFuncOp>(lowering->
op.getOperation())) {
1966 SmallVector<Value> operands;
1967 SmallVector<Value> resultTargets;
1969 for (
auto [callArg, declArg] :
1970 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1971 auto *actual = callArg;
1972 if (
const auto *assign =
1973 actual->as_if<slang::ast::AssignmentExpression>())
1974 actual = &assign->left();
1976 auto argType =
context.convertType(declArg->getType());
1980 switch (declArg->direction) {
1981 case slang::ast::ArgumentDirection::In: {
1982 auto value =
context.convertRvalueExpression(*actual, argType);
1985 operands.push_back(value);
1988 case slang::ast::ArgumentDirection::Out: {
1989 auto lvalue =
context.convertLvalueExpression(*actual);
1992 resultTargets.push_back(lvalue);
1995 case slang::ast::ArgumentDirection::InOut:
1996 case slang::ast::ArgumentDirection::Ref: {
1997 auto lvalue =
context.convertLvalueExpression(*actual);
2000 auto value =
context.convertRvalueExpression(*actual, argType);
2003 operands.push_back(value);
2004 resultTargets.push_back(lvalue);
2010 SmallVector<Type> resultTypes(
2011 cast<FunctionType>(lowering->
op.getFunctionType()).getResults());
2012 auto callOp = moore::FuncDPICallOp::create(
2013 builder, loc, resultTypes,
2014 SymbolRefAttr::get(lowering->
op.getNameAttr()), operands);
2016 unsigned resultIndex = 0;
2017 unsigned targetIndex = 0;
2018 for (
const auto *declArg : subroutine->getArguments()) {
2019 auto argType =
context.convertType(declArg->getType());
2023 switch (declArg->direction) {
2024 case slang::ast::ArgumentDirection::Out:
2025 case slang::ast::ArgumentDirection::InOut:
2026 case slang::ast::ArgumentDirection::Ref: {
2027 auto lvalue = resultTargets[targetIndex++];
2028 auto refTy = dyn_cast<moore::RefType>(lvalue.getType());
2030 lowering->
op->emitError(
2031 "expected DPI output target to be moore::RefType");
2034 auto converted =
context.materializeConversion(
2035 refTy.getNestedType(), callOp->getResult(resultIndex++),
2036 declArg->getType().isSigned(), loc);
2039 moore::BlockingAssignOp::create(builder, loc, lvalue, converted);
2047 if (!subroutine->getReturnType().isVoid())
2048 return callOp->getResult(resultIndex);
2050 return mlir::UnrealizedConversionCastOp::create(
2051 builder, loc, moore::VoidType::get(
context.getContext()),
2067 SmallVector<Writeback> writebacks;
2068 SmallVector<Value> arguments;
2070 for (
auto [callArg, declArg] :
2071 llvm::zip(expr.arguments(), subroutine->getArguments())) {
2075 auto *expr = callArg;
2076 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
2077 expr = &assign->left();
2080 auto type =
context.convertType(declArg->getType());
2081 if (declArg->direction == slang::ast::ArgumentDirection::In) {
2082 value =
context.convertRvalueExpression(*expr, type);
2084 Value lvalue =
context.convertLvalueExpression(*expr);
2087 auto unpackedType = dyn_cast<moore::UnpackedType>(type);
2090 auto refType = moore::RefType::get(unpackedType);
2092 if (declArg->direction == slang::ast::ArgumentDirection::Ref) {
2096 if (lvalue.getType() != refType) {
2097 mlir::emitError(loc)
2098 <<
"ref argument `" << declArg->name <<
"` expects " << refType
2099 <<
" but call provides " << lvalue.getType();
2103 }
else if (lvalue.getType() == refType) {
2107 if (declArg->direction == slang::ast::ArgumentDirection::InOut) {
2108 copyIn = moore::ReadOp::create(builder, loc, lvalue);
2109 copyIn =
context.materializeConversion(unpackedType, copyIn,
2110 expr->type->isSigned(), loc);
2114 value = moore::VariableOp::create(builder, loc, refType, StringAttr{},
2116 writebacks.push_back({value, lvalue, declArg->getType().isSigned()});
2121 arguments.push_back(value);
2128 for (
auto *sym : lowering->capturedSymbols) {
2129 Value val =
context.valueSymbols.lookup(sym);
2131 mlir::emitError(loc) <<
"failed to resolve captured variable `"
2132 << sym->name <<
"` at call site";
2135 arguments.push_back(val);
2139 SmallVector<Type> resultTypes(
2140 cast<FunctionType>(lowering->
op.getFunctionType()).getResults().begin(),
2141 cast<FunctionType>(lowering->
op.getFunctionType()).getResults().end());
2143 mlir::CallOpInterface callOp;
2147 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
2148 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
2149 arguments, resultTypes);
2150 }
else if (isa<moore::CoroutineOp>(lowering->
op.getOperation())) {
2152 auto coroutine = cast<moore::CoroutineOp>(lowering->
op.getOperation());
2154 moore::CallCoroutineOp::create(builder, loc, coroutine, arguments);
2157 auto funcOp = cast<mlir::func::FuncOp>(lowering->
op.getOperation());
2158 callOp = mlir::func::CallOp::create(builder, loc, funcOp, arguments);
2163 for (
auto &writeback : writebacks) {
2164 Value rvalue = moore::ReadOp::create(builder, loc, writeback.temp);
2166 cast<moore::RefType>(writeback.lvalue.getType()).getNestedType();
2167 rvalue =
context.materializeConversion(dstType, rvalue,
2168 writeback.declIsSigned, loc);
2171 moore::BlockingAssignOp::create(builder, loc, writeback.lvalue, rvalue);
2174 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
2178 if (resultTypes.size() == 0)
2179 return mlir::UnrealizedConversionCastOp::create(
2180 builder, loc, moore::VoidType::get(
context.getContext()),
2188 Value visitCall(
const slang::ast::CallExpression &expr,
2189 const slang::ast::CallExpression::SystemCallInfo &info) {
2190 using ksn = slang::parsing::KnownSystemName;
2191 const auto &subroutine = *
info.subroutine;
2192 auto nameId = subroutine.knownNameId;
2203 return context.convertSampledValueCallExpression(expr, info, loc);
2208 auto args = expr.arguments();
2216 if (nameId == ksn::SFormatF) {
2218 auto fmtValue =
context.convertFormatString(
2219 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
2220 if (failed(fmtValue))
2222 return fmtValue.value();
2226 auto result =
context.convertSystemCall(subroutine, loc, args);
2230 auto ty =
context.convertType(*expr.type);
2234 bool isSigned = expr.type->isSigned();
2235 if (nameId == ksn::CountOnes || nameId == ksn::IsUnknown ||
2236 nameId == ksn::OneHot || nameId == ksn::OneHot0)
2238 return context.materializeConversion(ty, result, isSigned, loc);
2242 Value visit(
const slang::ast::StringLiteral &expr) {
2243 auto type =
context.convertType(*expr.type);
2244 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
2248 Value visit(
const slang::ast::RealLiteral &expr) {
2249 auto fTy = mlir::Float64Type::get(
context.getContext());
2250 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
2251 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
2256 FailureOr<SmallVector<Value>>
2257 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
2258 std::variant<Type, ArrayRef<Type>> expectedTypes,
2259 unsigned replCount) {
2260 const auto &elts = expr.elements();
2261 const size_t elementCount = elts.size();
2264 const bool hasBroadcast =
2265 std::holds_alternative<Type>(expectedTypes) &&
2266 static_cast<bool>(std::get<Type>(expectedTypes));
2268 const bool hasPerElem =
2269 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
2270 !std::get<ArrayRef<Type>>(expectedTypes).empty();
2274 auto types = std::get<ArrayRef<Type>>(expectedTypes);
2275 if (types.size() != elementCount) {
2276 mlir::emitError(loc)
2277 <<
"assignment pattern arity mismatch: expected " << types.size()
2278 <<
" elements, got " << elementCount;
2283 SmallVector<Value> converted;
2284 converted.reserve(elementCount * std::max(1u, replCount));
2287 if (!hasBroadcast && !hasPerElem) {
2289 for (
const auto *elementExpr : elts) {
2290 Value v =
context.convertRvalueExpression(*elementExpr);
2293 converted.push_back(v);
2295 }
else if (hasBroadcast) {
2297 Type want = std::get<Type>(expectedTypes);
2298 for (
const auto *elementExpr : elts) {
2299 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
2300 :
context.convertRvalueExpression(*elementExpr);
2303 converted.push_back(v);
2306 auto types = std::get<ArrayRef<Type>>(expectedTypes);
2307 for (
size_t i = 0; i < elementCount; ++i) {
2308 Type want = types[i];
2309 const auto *elementExpr = elts[i];
2310 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
2311 :
context.convertRvalueExpression(*elementExpr);
2314 converted.push_back(v);
2318 for (
unsigned i = 1; i < replCount; ++i)
2319 converted.append(converted.begin(), converted.begin() + elementCount);
2325 Value visitAssignmentPattern(
2326 const slang::ast::AssignmentPatternExpressionBase &expr,
2327 unsigned replCount = 1) {
2328 auto type =
context.convertType(*expr.type);
2329 const auto &elts = expr.elements();
2332 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2333 auto elements = convertElements(expr, {}, replCount);
2335 if (failed(elements))
2338 assert(intType.getWidth() == elements->size());
2340 return moore::ConcatOp::create(builder, loc, intType, *elements);
2344 if (
auto structType = dyn_cast<moore::StructType>(type)) {
2345 SmallVector<Type> expectedTy;
2346 expectedTy.reserve(structType.getMembers().size());
2347 for (
auto member : structType.getMembers())
2348 expectedTy.push_back(member.type);
2350 FailureOr<SmallVector<Value>> elements;
2351 if (expectedTy.size() == elts.size())
2352 elements = convertElements(expr, expectedTy, replCount);
2354 elements = convertElements(expr, {}, replCount);
2356 if (failed(elements))
2359 assert(structType.getMembers().size() == elements->size());
2360 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2364 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
2365 SmallVector<Type> expectedTy;
2366 expectedTy.reserve(structType.getMembers().size());
2367 for (
auto member : structType.getMembers())
2368 expectedTy.push_back(member.type);
2370 FailureOr<SmallVector<Value>> elements;
2371 if (expectedTy.size() == elts.size())
2372 elements = convertElements(expr, expectedTy, replCount);
2374 elements = convertElements(expr, {}, replCount);
2376 if (failed(elements))
2379 assert(structType.getMembers().size() == elements->size());
2381 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2385 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
2387 convertElements(expr, arrayType.getElementType(), replCount);
2389 if (failed(elements))
2392 assert(arrayType.getSize() == elements->size());
2394 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2398 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
2400 convertElements(expr, arrayType.getElementType(), replCount);
2402 if (failed(elements))
2405 assert(arrayType.getSize() == elements->size());
2406 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2410 if (
auto openType = dyn_cast<moore::OpenUnpackedArrayType>(type)) {
2412 convertElements(expr, openType.getElementType(), replCount);
2414 if (failed(elements))
2417 auto arrayType = moore::UnpackedArrayType::get(
2418 context.getContext(), elements->size(), openType.getElementType());
2419 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2422 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
2426 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
2427 return visitAssignmentPattern(expr);
2430 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
2431 return visitAssignmentPattern(expr);
2434 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
2436 context.evaluateConstant(expr.count()).integer().as<
unsigned>();
2437 assert(count &&
"Slang guarantees constant non-zero replication count");
2438 return visitAssignmentPattern(expr, *count);
2441 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2442 SmallVector<Value> operands;
2443 for (
auto stream : expr.streams()) {
2444 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2445 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2446 mlir::emitError(operandLoc)
2447 <<
"Moore only support streaming "
2448 "concatenation with fixed size 'with expression'";
2452 if (stream.constantWithWidth.has_value()) {
2453 value =
context.convertRvalueExpression(*stream.withExpr);
2454 auto type = cast<moore::UnpackedType>(value.getType());
2455 auto intType = moore::IntType::get(
2456 context.getContext(), type.getBitSize().value(), type.getDomain());
2458 value =
context.materializeConversion(intType, value,
false, loc);
2460 value =
context.convertRvalueExpression(*stream.operand);
2463 value =
context.convertToSimpleBitVector(value);
2466 operands.push_back(value);
2470 if (operands.size() == 1) {
2473 value = operands.front();
2475 value = moore::ConcatOp::create(builder, loc, operands).getResult();
2478 if (expr.getSliceSize() == 0) {
2482 auto type = cast<moore::IntType>(value.getType());
2483 SmallVector<Value> slicedOperands;
2484 auto iterMax = type.getWidth() / expr.getSliceSize();
2485 auto remainSize = type.getWidth() % expr.getSliceSize();
2487 for (
size_t i = 0; i < iterMax; i++) {
2488 auto extractResultType = moore::IntType::get(
2489 context.getContext(), expr.getSliceSize(), type.getDomain());
2491 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
2492 value, i * expr.getSliceSize());
2493 slicedOperands.push_back(extracted);
2497 auto extractResultType = moore::IntType::get(
2498 context.getContext(), remainSize, type.getDomain());
2501 moore::ExtractOp::create(builder, loc, extractResultType, value,
2502 iterMax * expr.getSliceSize());
2503 slicedOperands.push_back(extracted);
2506 return moore::ConcatOp::create(builder, loc, slicedOperands);
2509 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
2510 return context.convertAssertionExpression(expr.body, loc);
2513 Value visit(
const slang::ast::UnboundedLiteral &expr) {
2515 "slang checks $ only used within queue index expression");
2519 moore::QueueSizeBIOp::create(builder, loc,
context.getIndexedQueue());
2520 auto one = moore::ConstantOp::create(builder, loc, queueSize.getType(), 1);
2521 auto lastElement = moore::SubOp::create(builder, loc, queueSize, one);
2538 Value visit(
const slang::ast::NewClassExpression &expr) {
2539 auto type =
context.convertType(*expr.type);
2540 auto classTy = dyn_cast<moore::ClassHandleType>(type);
2546 if (!classTy && expr.isSuperClass) {
2547 newObj =
context.getImplicitThisRef();
2548 if (!newObj || !newObj.getType() ||
2549 !isa<moore::ClassHandleType>(newObj.getType())) {
2550 mlir::emitError(loc) <<
"implicit this ref was not set while "
2551 "converting new class function";
2554 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
2556 cast<moore::ClassDeclOp>(*
context.symbolTable.lookupNearestSymbolFrom(
2557 context.intoModuleOp, thisType.getClassSym()));
2558 auto baseClassSym = classDecl.getBase();
2559 classTy = circt::moore::ClassHandleType::get(
context.getContext(),
2560 baseClassSym.value());
2563 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
2566 const auto *constructor = expr.constructorCall();
2571 if (
const auto *callConstructor =
2572 constructor->as_if<slang::ast::CallExpression>())
2573 if (
const auto *subroutine =
2574 std::get_if<const slang::ast::SubroutineSymbol *>(
2575 &callConstructor->subroutine)) {
2576 if (!(*subroutine)->thisVar) {
2577 mlir::emitError(loc)
2578 <<
"unsupported constructor call without `this` argument";
2582 llvm::SaveAndRestore saveThis(
context.currentThisRef, newObj);
2583 if (!visitCall(*callConstructor, *subroutine))
2591 template <
typename T>
2592 Value visit(T &&node) {
2593 mlir::emitError(loc,
"unsupported expression: ")
2594 << slang::ast::toString(node.kind);
2598 Value visitInvalid(
const slang::ast::Expression &expr) {
2599 mlir::emitError(loc,
"invalid expression");
2610struct LvalueExprVisitor :
public ExprVisitor {
2612 : ExprVisitor(
context, loc, true) {}
2613 using ExprVisitor::visit;
2616 Value visit(
const slang::ast::NamedValueExpression &expr) {
2618 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2622 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2623 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2625 if (
auto *
const property =
2626 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
2630 if (
auto access =
context.virtualIfaceMembers.lookup(&expr.symbol);
2632 auto type =
context.convertType(*expr.type);
2635 auto memberType = dyn_cast<moore::UnpackedType>(type);
2637 mlir::emitError(loc)
2638 <<
"unsupported virtual interface member type: " << type;
2642 Value base = materializeSymbolRvalue(*access.base);
2644 auto d = mlir::emitError(loc,
"unknown name `")
2645 << access.base->name <<
"`";
2646 d.attachNote(
context.convertLocation(access.base->location))
2647 <<
"no rvalue generated for virtual interface base";
2651 auto fieldName = access.fieldName
2653 : builder.getStringAttr(expr.symbol.name);
2654 auto memberRefType = moore::RefType::get(memberType);
2655 return moore::StructExtractOp::create(builder, loc, memberRefType,
2659 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
2660 d.attachNote(
context.convertLocation(expr.symbol.location))
2661 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2666 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
2669 if (!expr.ref.path.empty()) {
2670 if (
auto *inst = expr.ref.path.front()
2671 .symbol->as_if<slang::ast::InstanceSymbol>()) {
2673 expr.symbol.getParentScope()->getContainingInstance();
2674 if (&inst->body == symbolBody ||
2675 (symbolBody && inst->body.getDeclaringDefinition() ==
2676 symbolBody->getDeclaringDefinition())) {
2677 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2684 if (
auto value =
context.resolveCapturedValue(expr.symbol))
2690 if (
auto key =
context.buildHierValueKey(expr)) {
2691 if (
auto it =
context.hierValueSymbols.find(*key);
2692 it !=
context.hierValueSymbols.end())
2697 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2704 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2705 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2709 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
2710 << expr.symbol.name <<
"`";
2711 d.attachNote(
context.convertLocation(expr.symbol.location))
2712 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2716 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2717 SmallVector<Value> operands;
2718 for (
auto stream : expr.streams()) {
2719 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2720 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2721 mlir::emitError(operandLoc)
2722 <<
"Moore only support streaming "
2723 "concatenation with fixed size 'with expression'";
2727 if (stream.constantWithWidth.has_value()) {
2728 value =
context.convertLvalueExpression(*stream.withExpr);
2729 auto type = cast<moore::UnpackedType>(
2730 cast<moore::RefType>(value.getType()).getNestedType());
2731 auto intType = moore::RefType::get(moore::IntType::get(
2732 context.getContext(), type.getBitSize().value(), type.getDomain()));
2734 value =
context.materializeConversion(intType, value,
false, loc);
2736 value =
context.convertLvalueExpression(*stream.operand);
2741 operands.push_back(value);
2744 if (operands.size() == 1) {
2747 value = operands.front();
2749 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
2752 if (expr.getSliceSize() == 0) {
2756 auto type = cast<moore::IntType>(
2757 cast<moore::RefType>(value.getType()).getNestedType());
2758 SmallVector<Value> slicedOperands;
2759 auto widthSum = type.getWidth();
2760 auto domain = type.getDomain();
2761 auto iterMax = widthSum / expr.getSliceSize();
2762 auto remainSize = widthSum % expr.getSliceSize();
2764 for (
size_t i = 0; i < iterMax; i++) {
2765 auto extractResultType = moore::RefType::get(moore::IntType::get(
2766 context.getContext(), expr.getSliceSize(), domain));
2768 auto extracted = moore::ExtractRefOp::create(
2769 builder, loc, extractResultType, value, i * expr.getSliceSize());
2770 slicedOperands.push_back(extracted);
2774 auto extractResultType = moore::RefType::get(
2775 moore::IntType::get(
context.getContext(), remainSize, domain));
2778 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
2779 iterMax * expr.getSliceSize());
2780 slicedOperands.push_back(extracted);
2783 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
2787 template <
typename T>
2788 Value visit(T &&node) {
2789 return context.convertRvalueExpression(node);
2792 Value visitInvalid(
const slang::ast::Expression &expr) {
2793 mlir::emitError(loc,
"invalid expression");
2803Value Context::resolveCapturedValue(
const slang::ast::ValueSymbol &sym) {
2811std::optional<std::pair<const slang::ast::InstanceSymbol *, mlir::StringAttr>>
2813 const slang::ast::HierarchicalValueExpression &expr) {
2814 if (expr.ref.path.empty())
2815 return std::nullopt;
2817 const slang::ast::InstanceSymbol *firstInst =
nullptr;
2818 SmallVector<StringRef, 4> names;
2819 for (
auto &elem : expr.ref.path) {
2820 if (
auto *inst = elem.symbol->as_if<slang::ast::InstanceSymbol>()) {
2824 names.push_back(inst->name);
2828 names.push_back(expr.symbol.name);
2829 std::string hierName = llvm::join(names,
".");
2832 return std::nullopt;
2833 return std::make_pair(firstInst,
builder.getStringAttr(hierName));
2841 Type requiredType) {
2843 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
2844 if (value && requiredType)
2852 return expr.visit(LvalueExprVisitor(*
this, loc));
2860 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
2861 if (type.getBitSize() == 1)
2863 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
2864 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
2865 mlir::emitError(value.getLoc(),
"expression of type ")
2866 << value.getType() <<
" cannot be cast to a boolean";
2872 const slang::ast::Type &astType,
2874 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2878 if (svreal.isShortReal() &&
2879 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2880 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2881 }
else if (svreal.isReal() &&
2882 floatType->floatKind == slang::ast::FloatingType::Real) {
2883 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2885 mlir::emitError(loc) <<
"invalid real constant";
2889 return moore::ConstantRealOp::create(
builder, loc, attr);
2894 const slang::ast::Type &astType,
2896 if (!astType.isString())
2898 const std::string &str = stringLiteral.str();
2899 auto intTy = moore::IntType::getInt(
getContext(),
2900 static_cast<unsigned>(str.size() * 8));
2902 moore::ConstantStringOp::create(
builder, loc, intTy, str).getResult();
2903 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2908 const slang::ast::Type &astType, Location loc) {
2913 bool typeIsFourValued =
false;
2914 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2918 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2919 fvint.hasUnknown() || typeIsFourValued
2922 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2927 const slang::ConstantValue &constant,
2928 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2935 if (astType.elementType.isString()) {
2936 auto arrayType = dyn_cast<moore::UnpackedArrayType>(type);
2940 SmallVector<Value> elemVals;
2941 for (
const auto &elem : constant.elements()) {
2942 if (!elem.isString())
2947 elemVals.push_back(value);
2949 if (elemVals.size() != arrayType.getSize())
2951 return moore::ArrayCreateOp::create(
builder, loc, arrayType, elemVals);
2956 if (astType.elementType.isIntegral())
2957 bitWidth = astType.elementType.getBitWidth();
2961 bool typeIsFourValued =
false;
2964 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2975 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2977 auto arrType = moore::UnpackedArrayType::get(
2978 getContext(), constant.elements().size(), intType);
2980 llvm::SmallVector<mlir::Value> elemVals;
2981 moore::ConstantOp constOp;
2983 mlir::OpBuilder::InsertionGuard guard(
builder);
2986 for (
auto elem : constant.elements()) {
2988 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2989 elemVals.push_back(constOp.getResult());
2994 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2996 return arrayOp.getResult();
3000 const slang::ast::Type &type, Location loc) {
3002 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
3004 if (constant.isInteger())
3006 if (constant.isReal() || constant.isShortReal())
3008 if (constant.isString())
3016 using slang::ast::EvalFlags;
3017 slang::ast::EvalContext evalContext(
3019 slang::ast::LookupLocation::max),
3020 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
3021 return expr.eval(evalContext);
3030 auto type = moore::IntType::get(
getContext(), 1, domain);
3037 if (isa<moore::IntType>(value.getType()))
3044 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
3045 if (
auto sbvType = packed.getSimpleBitVector())
3048 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
3049 <<
" cannot be cast to a simple bit vector";
3055 if (isa<moore::IntType>(value.getType()))
3058 auto packedType = cast<moore::PackedType>(value.getType());
3059 auto intType = packedType.getSimpleBitVector();
3064 if (isa<moore::TimeType>(packedType) &&
3066 value =
builder.createOrFold<moore::TimeToLogicOp>(loc, value);
3067 auto scale = moore::ConstantOp::create(
builder, loc, intType,
3069 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
3075 if (packedType.containsTimeType()) {
3077 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
3078 <<
" cannot be converted to " << intType
3079 <<
"; contains a time type";
3084 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
3092 Value value, Location loc,
3094 if (value.getType() == packedType)
3097 auto &builder =
context.builder;
3098 auto intType = cast<moore::IntType>(value.getType());
3103 if (isa<moore::TimeType>(packedType) &&
3105 auto scale = moore::ConstantOp::create(builder, loc, intType,
3107 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
3108 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
3116 mlir::emitError(loc) <<
"unsupported conversion: " << intType
3117 <<
" cannot be converted to " << packedType
3118 <<
"; contains a time type";
3123 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
3129 moore::ClassHandleType expectedHandleTy) {
3130 auto loc = actualHandle.getLoc();
3132 auto actualTy = actualHandle.getType();
3133 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
3134 if (!actualHandleTy) {
3135 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
3141 if (actualHandleTy == expectedHandleTy)
3142 return actualHandle;
3144 if (!
context.isClassDerivedFrom(actualHandleTy, expectedHandleTy)) {
3145 mlir::emitError(loc)
3146 <<
"receiver class " << actualHandleTy.getClassSym()
3147 <<
" is not the same as, or derived from, expected base class "
3148 << expectedHandleTy.getClassSym().getRootReference();
3153 auto casted = moore::ClassUpcastOp::create(
context.builder, loc,
3154 expectedHandleTy, actualHandle)
3160 Location loc,
bool fallible) {
3162 if (type == value.getType())
3167 if (isa<moore::NullType>(value.getType())) {
3168 if (isa<moore::ChandleType>(type))
3169 return moore::NullChandleOp::create(
builder, loc);
3170 if (
auto classType = dyn_cast<moore::ClassHandleType>(type))
3171 return moore::NullClassOp::create(
builder, loc, classType);
3172 if (type == moore::IntType::getInt(value.getContext(), 1))
3173 return moore::ConstantOp::create(
builder, loc, cast<moore::IntType>(type),
3179 auto dstPacked = dyn_cast<moore::PackedType>(type);
3180 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
3181 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
3182 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
3184 if (dstInt && srcInt) {
3192 auto resizedType = moore::IntType::get(
3193 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
3194 if (dstInt.getWidth() < srcInt.getWidth()) {
3195 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
3196 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
3198 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
3200 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
3204 if (dstInt.getDomain() != srcInt.getDomain()) {
3206 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
3208 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
3217 assert(value.getType() == type);
3222 if (isa<moore::StringType>(type) &&
3223 isa<moore::FormatStringType>(value.getType())) {
3224 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
3228 if (isa<moore::FormatStringType>(type) &&
3229 isa<moore::StringType>(value.getType())) {
3230 return builder.createOrFold<moore::FormatStringOp>(loc, value);
3235 if (isa<moore::QueueType>(type) && isa<moore::QueueType>(value.getType()) &&
3236 cast<moore::QueueType>(type).getElementType() ==
3237 cast<moore::QueueType>(value.getType()).getElementType())
3238 return builder.createOrFold<moore::QueueResizeOp>(loc, type, value);
3241 if (isa<moore::QueueType>(type) &&
3242 isa<moore::UnpackedArrayType>(value.getType())) {
3243 auto queueElType = dyn_cast<moore::QueueType>(type).getElementType();
3244 auto unpackedArrayElType =
3245 dyn_cast<moore::UnpackedArrayType>(value.getType()).getElementType();
3247 if (queueElType == unpackedArrayElType) {
3248 return builder.createOrFold<moore::QueueFromUnpackedArrayOp>(loc, type,
3253 auto srcUArray = dyn_cast<moore::UnpackedArrayType>(value.getType());
3254 auto dstOpenUArray = dyn_cast<moore::OpenUnpackedArrayType>(type);
3255 if (srcUArray && dstOpenUArray) {
3256 auto openUnpackedArrayElType = dstOpenUArray.getElementType();
3257 auto unpackedArrayElType = srcUArray.getElementType();
3259 if (openUnpackedArrayElType == unpackedArrayElType)
3260 return builder.createOrFold<moore::OpenUArrayFromUnpackedArrayOp>(
3264 if (dstInt && isa<moore::RealType>(value.getType())) {
3265 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
3266 loc, dstInt.getTwoValued(), value);
3271 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
3274 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
3279 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
3283 return builder.createOrFold<moore::SIntToRealOp>(loc, type, twoValInt);
3284 return builder.createOrFold<moore::UIntToRealOp>(loc, type, twoValInt);
3287 auto getBuiltinFloatType = [&](moore::RealType type) -> Type {
3289 return mlir::Float32Type::get(
builder.getContext());
3291 return mlir::Float64Type::get(
builder.getContext());
3295 if (isa<moore::TimeType>(type) && isa<moore::RealType>(value.getType())) {
3297 moore::IntType::get(
builder.getContext(), 64, Domain::TwoValued);
3299 getBuiltinFloatType(cast<moore::RealType>(value.getType()));
3300 auto scale = moore::ConstantRealOp::create(
3301 builder, loc, value.getType(),
3303 auto scaled =
builder.createOrFold<moore::MulRealOp>(loc, value, scale);
3304 auto asInt = moore::RealToIntOp::create(
builder, loc, intType, scaled);
3305 auto asLogic = moore::IntToLogicOp::create(
builder, loc, asInt);
3306 return moore::LogicToTimeOp::create(
builder, loc, asLogic);
3310 if (isa<moore::RealType>(type) && isa<moore::TimeType>(value.getType())) {
3311 auto asLogic = moore::TimeToLogicOp::create(
builder, loc, value);
3312 auto asInt = moore::LogicToIntOp::create(
builder, loc, asLogic);
3313 auto asReal = moore::UIntToRealOp::create(
builder, loc, type, asInt);
3314 Type floatType = getBuiltinFloatType(cast<moore::RealType>(type));
3315 auto scale = moore::ConstantRealOp::create(
3318 return moore::DivRealOp::create(
builder, loc, asReal, scale);
3322 if (isa<moore::StringType>(type)) {
3323 if (
auto intType = dyn_cast<moore::IntType>(value.getType())) {
3325 value = moore::LogicToIntOp::create(
builder, loc, value);
3326 return moore::IntToStringOp::create(
builder, loc, value);
3331 if (
auto intType = dyn_cast<moore::IntType>(type)) {
3332 if (isa<moore::StringType>(value.getType())) {
3333 value = moore::StringToIntOp::create(
builder, loc, intType.getTwoValued(),
3337 return moore::IntToLogicOp::create(
builder, loc, value);
3344 if (isa<moore::FormatStringType>(type)) {
3346 value, isSigned, loc);
3349 return moore::FormatStringOp::create(
builder, loc, asStr, {}, {}, {});
3352 if (isa<moore::RealType>(type) && isa<moore::RealType>(value.getType()))
3353 return builder.createOrFold<moore::ConvertRealOp>(loc, type, value);
3355 if (isa<moore::ClassHandleType>(type) &&
3356 isa<moore::ClassHandleType>(value.getType()))
3360 mlir::emitError(loc) <<
"unsupported conversion from " << value.getType()
3367template <
typename OpTy>
3370 std::span<const slang::ast::Expression *const> args) {
3372 assert(args.size() == 1 &&
"real math builtin expects 1 argument");
3373 auto value =
context.convertRvalueExpression(*args[0]);
3376 return OpTy::create(
context.builder, loc, value);
3381template <
typename OpTy>
3384 std::span<const slang::ast::Expression *const> args) {
3386 assert(args.size() == 2 &&
"real math builtin expects 2 arguments");
3389 auto lhs =
context.convertRvalueExpression(*args[0], realType);
3390 auto rhs =
context.convertRvalueExpression(*args[1], realType);
3393 return OpTy::create(
context.builder, loc, lhs, rhs);
3399 auto &builder =
context.builder;
3400 auto newBlockAfter = [&](Block *after) -> Block * {
3401 auto block = std::make_unique<Block>();
3402 block->insertAfter(after);
3403 return block.release();
3406 for (
auto [destExpr, value, matched] : result.assignments) {
3407 auto lhs =
context.convertLvalueExpression(*destExpr);
3410 auto cond = moore::ToBuiltinIntOp::create(builder, loc, matched);
3412 auto *assignBlock = newBlockAfter(builder.getInsertionBlock());
3413 auto *continuedBlock = newBlockAfter(assignBlock);
3414 mlir::cf::CondBranchOp::create(builder, loc, cond, assignBlock,
3417 builder.setInsertionPointToEnd(assignBlock);
3418 moore::BlockingAssignOp::create(builder, loc, lhs, value);
3419 mlir::cf::BranchOp::create(builder, loc, continuedBlock);
3421 builder.setInsertionPointToEnd(continuedBlock);
3451 slang::parsing::KnownSystemName method,
3453 using ksn = slang::parsing::KnownSystemName;
3454 const auto &enumType = type.getCanonicalType().as<slang::ast::EnumType>();
3458 bool isName = method == ksn::Name;
3462 auto valueType = dyn_cast_or_null<moore::PackedType>(
convertType(enumType));
3465 auto posType = moore::IntType::getInt(
getContext(), 32);
3467 isName ? Type(moore::StringType::get(
getContext())) : Type(valueType);
3471 OpBuilder::InsertionGuard guard(
builder);
3477 builder.setInsertionPoint(it->second);
3482 StringRef typeName = type.name;
3483 auto helperName = StringAttr::get(
3484 getContext(), Twine(
"enum.") + slang::parsing::toString(method) +
"." +
3485 (typeName.empty() ?
"anon" : typeName));
3487 SmallVector<Type> argTypes{valueType};
3489 argTypes.push_back(posType);
3491 mlir::func::FuncOp::create(
builder, helperLoc, helperName,
3492 builder.getFunctionType(argTypes, resultType));
3493 SymbolTable::setSymbolVisibility(funcOp, SymbolTable::Visibility::Private);
3501 auto &bodyRegion = funcOp.getBody();
3502 auto *entryBlock = funcOp.addEntryBlock();
3503 auto value = entryBlock->getArgument(0);
3504 builder.setInsertionPointToEnd(entryBlock);
3505 SmallVector<Value> enumerandValues;
3506 for (
const auto &enumerand : enumType.values()) {
3511 enumerandValues.push_back(constant);
3519 auto tableType = moore::ArrayType::get(enumerandValues.size(), valueType);
3520 table = moore::ArrayCreateOp::create(
3521 builder, helperLoc, tableType,
3522 SmallVector<Value>(llvm::reverse(enumerandValues)));
3529 auto *matchBlock = &bodyRegion.emplaceBlock();
3530 matchBlock->addArgument(isName ? resultType : Type(posType), helperLoc);
3534 for (
auto [position, enumerand] : llvm::enumerate(enumType.values())) {
3536 auto matches = moore::CaseEqOp::create(
builder, enumerandLoc, value,
3537 enumerandValues[position]);
3539 moore::ToBuiltinIntOp::create(
builder, enumerandLoc, matches);
3544 moore::IntType::getInt(
getContext(), enumerand.name.size() * 8);
3545 auto bytes = moore::ConstantStringOp::create(
builder, enumerandLoc,
3546 intType, enumerand.name);
3547 matchResult = moore::IntToStringOp::create(
builder, enumerandLoc, bytes);
3549 matchResult = moore::ConstantOp::create(
builder, enumerandLoc, posType,
3550 static_cast<int64_t
>(position));
3553 auto *mismatchBlock = &bodyRegion.emplaceBlock();
3554 mlir::cf::CondBranchOp::create(
builder, enumerandLoc, condition, matchBlock,
3555 ValueRange{matchResult}, mismatchBlock,
3557 builder.setInsertionPointToEnd(mismatchBlock);
3565 auto intType = moore::IntType::getInt(
getContext(), 0);
3567 moore::ConstantStringOp::create(
builder, helperLoc, intType,
"");
3568 Value
empty = moore::IntToStringOp::create(
builder, helperLoc, bytes);
3569 mlir::cf::BranchOp::create(
builder, helperLoc, matchBlock,
empty);
3575 mlir::func::ReturnOp::create(
builder, helperLoc, fallback);
3578 builder.setInsertionPointToEnd(matchBlock);
3579 Value result = matchBlock->getArgument(0);
3586 moore::ConstantOp::create(
builder, helperLoc, posType,
3587 static_cast<int64_t
>(enumerandValues.size()));
3588 Value step = moore::ModUOp::create(
builder, helperLoc,
3589 funcOp.getArgument(1), numValues);
3590 if (method == ksn::Prev)
3591 step = moore::SubOp::create(
builder, helperLoc, numValues, step);
3592 Value offset = moore::AddOp::create(
builder, helperLoc, result, step);
3594 moore::ModUOp::create(
builder, helperLoc, offset, numValues);
3595 result = moore::DynExtractOp::create(
builder, helperLoc, valueType, table,
3598 mlir::func::ReturnOp::create(
builder, helperLoc, result);
3602 matchBlock->moveBefore(&bodyRegion, bodyRegion.end());
3607 const slang::ast::SystemSubroutine &subroutine, Location loc,
3608 std::span<const slang::ast::Expression *const> args) {
3609 using ksn = slang::parsing::KnownSystemName;
3610 StringRef name = subroutine.name;
3611 auto nameId = subroutine.knownNameId;
3612 size_t numArgs = args.size();
3620 if (nameId == ksn::URandom || nameId == ksn::Random) {
3621 auto i32Ty = moore::IntType::getInt(
builder.getContext(), 32);
3622 auto minval = moore::ConstantOp::create(
builder, loc, i32Ty, 0);
3624 moore::ConstantOp::create(
builder, loc, i32Ty, APInt::getAllOnes(32));
3631 return moore::UrandomRangeBIOp::create(
builder, loc, minval, maxval, seed);
3634 if (nameId == ksn::URandomRange) {
3635 auto i32Ty = moore::IntType::getInt(
builder.getContext(), 32);
3645 minval = moore::ConstantOp::create(
builder, loc, i32Ty, 0);
3647 return moore::UrandomRangeBIOp::create(
builder, loc, minval, maxval,
3655 if (nameId == ksn::Time || nameId == ksn::STime || nameId == ksn::RealTime) {
3657 assert(numArgs == 0 &&
"time functions take no arguments");
3658 return moore::TimeBIOp::create(
builder, loc);
3665 if (nameId == ksn::Clog2) {
3667 assert(numArgs == 1 &&
"`$clog2` takes 1 argument");
3674 return moore::Clog2BIOp::create(
builder, loc, value);
3681 if (nameId == ksn::IsUnknown) {
3682 assert(numArgs == 1 &&
"`$isunknown` takes 1 argument");
3687 if (!isa<moore::IntType>(value.getType())) {
3688 if (!isa<moore::PackedType>(value.getType())) {
3689 mlir::emitError(loc) <<
"expected integer argument for `$isunknown`";
3697 auto valTy = dyn_cast<moore::IntType>(value.getType());
3701 if (nameId == ksn::OneHot0 || nameId == ksn::OneHot) {
3702 assert(numArgs == 1 &&
"`$onehot`/`$onehot0` takes 1 argument");
3706 if (!isa<moore::IntType>(value.getType())) {
3707 if (!isa<moore::PackedType>(value.getType())) {
3708 mlir::emitError(loc)
3709 <<
"expected integer argument for `$onehot`/`$onehot0`";
3717 auto valTy = dyn_cast<moore::IntType>(value.getType());
3719 mlir::emitError(loc) <<
"expected integer argument for `"
3720 << subroutine.name <<
"`";
3727 if (valTy.getDomain() == Domain::FourValued) {
3728 Value isUnknownMoore =
3731 builder.createOrFold<moore::ToBuiltinIntOp>(loc, isUnknownMoore);
3739 auto minusOne = comb::SubOp::create(
builder, loc, intVal, one);
3740 auto anded = comb::AndOp::create(
builder, loc, intVal, minusOne);
3742 Value result = comb::ICmpOp::create(
builder, loc, comb::ICmpPredicate::eq,
3743 anded, zero,
false);
3746 if (nameId == ksn::OneHot) {
3747 auto isNotZero = comb::ICmpOp::create(
3748 builder, loc, comb::ICmpPredicate::ne, intVal, zero,
false);
3749 result = comb::AndOp::create(
builder, loc, result, isNotZero);
3756 result = comb::MuxOp::create(
builder, loc, isUnknown, zeroI1, result);
3757 Value resultMoore = moore::FromBuiltinIntOp::create(
builder, loc, result);
3758 return moore::IntToLogicOp::create(
builder, loc, resultMoore).getResult();
3760 return moore::FromBuiltinIntOp::create(
builder, loc, result);
3763 if (nameId == ksn::CountOnes) {
3764 assert(numArgs == 1 &&
"`$countones` takes 1 argument");
3768 if (!isa<moore::IntType>(value.getType())) {
3769 if (!isa<moore::PackedType>(value.getType())) {
3770 mlir::emitError(loc) <<
"expected integer argument for `$countones`";
3778 auto valTy = dyn_cast<moore::IntType>(value.getType());
3780 mlir::emitError(loc) <<
"expected integer argument for `$countones`";
3788 auto builtinIntTy = cast<IntegerType>(intVal.getType());
3789 unsigned width = builtinIntTy.getWidth();
3790 unsigned resultWidth = llvm::Log2_32_Ceil(width + 1);
3791 auto i1Ty =
builder.getI1Type();
3792 unsigned padWidth = resultWidth - 1;
3794 builder.getIntegerType(padWidth), 0);
3798 Value sum = comb::ConcatOp::create(
builder, loc, ValueRange{zeros, bit0});
3800 for (
unsigned i = 1; i < width; ++i) {
3803 comb::ConcatOp::create(
builder, loc, ValueRange{zeros, bit});
3804 sum = comb::AddOp::create(
builder, loc, sum, extended);
3808 return moore::FromBuiltinIntOp::create(
builder, loc, sum);
3812 if (nameId == ksn::Ln)
3813 return convertRealMathBI<moore::LnBIOp>(*
this, loc, name, args);
3814 if (nameId == ksn::Log10)
3815 return convertRealMathBI<moore::Log10BIOp>(*
this, loc, name, args);
3816 if (nameId == ksn::Exp)
3817 return convertRealMathBI<moore::ExpBIOp>(*
this, loc, name, args);
3818 if (nameId == ksn::Sqrt)
3819 return convertRealMathBI<moore::SqrtBIOp>(*
this, loc, name, args);
3820 if (nameId == ksn::Floor)
3821 return convertRealMathBI<moore::FloorBIOp>(*
this, loc, name, args);
3822 if (nameId == ksn::Ceil)
3823 return convertRealMathBI<moore::CeilBIOp>(*
this, loc, name, args);
3824 if (nameId == ksn::Sin)
3825 return convertRealMathBI<moore::SinBIOp>(*
this, loc, name, args);
3826 if (nameId == ksn::Cos)
3827 return convertRealMathBI<moore::CosBIOp>(*
this, loc, name, args);
3828 if (nameId == ksn::Tan)
3829 return convertRealMathBI<moore::TanBIOp>(*
this, loc, name, args);
3830 if (nameId == ksn::Asin)
3831 return convertRealMathBI<moore::AsinBIOp>(*
this, loc, name, args);
3832 if (nameId == ksn::Acos)
3833 return convertRealMathBI<moore::AcosBIOp>(*
this, loc, name, args);
3834 if (nameId == ksn::Atan)
3835 return convertRealMathBI<moore::AtanBIOp>(*
this, loc, name, args);
3836 if (nameId == ksn::Sinh)
3837 return convertRealMathBI<moore::SinhBIOp>(*
this, loc, name, args);
3838 if (nameId == ksn::Cosh)
3839 return convertRealMathBI<moore::CoshBIOp>(*
this, loc, name, args);
3840 if (nameId == ksn::Tanh)
3841 return convertRealMathBI<moore::TanhBIOp>(*
this, loc, name, args);
3842 if (nameId == ksn::Asinh)
3843 return convertRealMathBI<moore::AsinhBIOp>(*
this, loc, name, args);
3844 if (nameId == ksn::Acosh)
3845 return convertRealMathBI<moore::AcoshBIOp>(*
this, loc, name, args);
3846 if (nameId == ksn::Atanh)
3847 return convertRealMathBI<moore::AtanhBIOp>(*
this, loc, name, args);
3849 if (nameId == ksn::Pow)
3850 return convertRealMathTwoBI<moore::PowRealOp>(*
this, loc, name, args);
3851 if (nameId == ksn::Atan2)
3852 return convertRealMathTwoBI<moore::Atan2BIOp>(*
this, loc, name, args);
3853 if (nameId == ksn::Hypot)
3854 return convertRealMathTwoBI<moore::HypotBIOp>(*
this, loc, name, args);
3860 if (nameId == ksn::Itor) {
3861 assert(numArgs == 1 &&
"`$itor` takes 1 argument");
3866 if (nameId == ksn::Rtoi) {
3867 assert(numArgs == 1 &&
"`$rtoi` takes 1 argument");
3868 auto intType = moore::IntType::get(
getContext(), 32, Domain::TwoValued);
3872 if (nameId == ksn::Signed || nameId == ksn::Unsigned) {
3874 assert(numArgs == 1 &&
"`$signed`/`$unsigned` take 1 argument");
3880 if (nameId == ksn::RealToBits)
3881 return convertRealMathBI<moore::RealtobitsBIOp>(*
this, loc, name, args);
3882 if (nameId == ksn::BitsToReal)
3883 return convertRealMathBI<moore::BitstorealBIOp>(*
this, loc, name, args);
3884 if (nameId == ksn::ShortrealToBits)
3885 return convertRealMathBI<moore::ShortrealtobitsBIOp>(*
this, loc, name,
3887 if (nameId == ksn::BitsToShortreal)
3888 return convertRealMathBI<moore::BitstoshortrealBIOp>(*
this, loc, name,
3891 if (nameId == ksn::Cast) {
3892 assert(numArgs == 2 &&
"`cast` takes 2 arguments");
3893 auto *dstExpr = args[0];
3898 if (
auto *assign = dstExpr->as_if<slang::ast::AssignmentExpression>())
3899 dstExpr = &assign->left();
3908 if (isa<moore::ClassHandleType>(dstType) ||
3909 isa<moore::ClassHandleType>(src.getType())) {
3910 auto i1Ty = moore::IntType::getInt(
builder.getContext(), 1);
3911 return moore::ConstantOp::create(
builder, loc, i1Ty, 0,
3915 dstType, src, args[1]->type->isSigned(), loc,
true);
3916 auto i1Ty = moore::IntType::getInt(
builder.getContext(), 1);
3918 return moore::ConstantOp::create(
builder, loc, i1Ty, 0,
3920 moore::BlockingAssignOp::create(
builder, loc, dst, converted);
3921 return moore::ConstantOp::create(
builder, loc, i1Ty, 1,
3929 if (nameId == ksn::Len) {
3931 assert(numArgs == 1 &&
"`len` takes 1 argument");
3932 auto stringType = moore::StringType::get(
getContext());
3936 return moore::StringLenOp::create(
builder, loc, value);
3939 if (nameId == ksn::Getc) {
3941 assert(numArgs == 2 &&
"`getc` takes 2 arguments");
3942 auto stringType = moore::StringType::get(
getContext());
3947 return moore::StringGetOp::create(
builder, loc, str, index);
3950 if (nameId == ksn::ToUpper) {
3952 assert(numArgs == 1 &&
"`toupper` takes 1 argument");
3953 auto stringType = moore::StringType::get(
getContext());
3957 return moore::StringToUpperOp::create(
builder, loc, value);
3960 if (nameId == ksn::ToLower) {
3962 assert(numArgs == 1 &&
"`tolower` takes 1 argument");
3963 auto stringType = moore::StringType::get(
getContext());
3967 return moore::StringToLowerOp::create(
builder, loc, value);
3970 if (nameId == ksn::Compare || nameId == ksn::ICompare) {
3973 auto stringType = moore::StringType::get(
getContext());
3978 if (nameId == ksn::Compare)
3979 return moore::StringCompareOp::create(
builder, loc, lhs, rhs);
3980 return moore::StringICompareOp::create(
builder, loc, lhs, rhs);
3983 if (nameId == ksn::Substr) {
3985 assert(numArgs == 3 &&
"`substr` takes 3 arguments");
3986 auto stringType = moore::StringType::get(
getContext());
3990 if (!str || !start || !end)
3992 return moore::StringSubstrOp::create(
builder, loc, str, start, end);
3995 if (nameId == ksn::AToI || nameId == ksn::AToHex || nameId == ksn::AToOct ||
3996 nameId == ksn::AToBin) {
3998 assert(numArgs == 1 &&
"`atoi/hex/oct/bin` takes 1 argument");
3999 auto stringType = moore::StringType::get(
getContext());
4003 auto integerType = moore::IntType::getLogic(
builder.getContext(), 32);
4006 return moore::StringAtoiOp::create(
builder, loc, integerType, str);
4008 return moore::StringAtohexOp::create(
builder, loc, integerType, str);
4010 return moore::StringAtooctOp::create(
builder, loc, integerType, str);
4012 return moore::StringAtobinOp::create(
builder, loc, integerType, str);
4014 llvm_unreachable(
"unexpected string to integer conversion");
4018 if (nameId == ksn::AToReal) {
4020 assert(numArgs == 1 &&
"`atoreal` takes 1 argument");
4021 auto stringType = moore::StringType::get(
getContext());
4026 return moore::StringAtorealOp::create(
builder, loc, realType, str);
4033 if (nameId == ksn::ArraySize) {
4035 assert(numArgs == 1 &&
"`size` takes 1 argument");
4036 if (args[0]->type->isQueue()) {
4040 return moore::QueueSizeBIOp::create(
builder, loc, value);
4042 if (args[0]->type->getCanonicalType().kind ==
4043 slang::ast::SymbolKind::DynamicArrayType) {
4047 return moore::OpenUArraySizeOp::create(
builder, loc, value);
4049 if (args[0]->type->isAssociativeArray()) {
4053 return moore::AssocArraySizeOp::create(
builder, loc, value);
4055 emitError(loc) <<
"unsupported member function `size` on type `"
4056 << args[0]->type->toString() <<
"`";
4060 if (nameId == ksn::Delete) {
4062 assert(numArgs == 1 &&
"`delete` takes 1 argument");
4063 if (args[0]->type->getCanonicalType().kind ==
4064 slang::ast::SymbolKind::DynamicArrayType) {
4068 return moore::OpenUArrayDeleteOp::create(
builder, loc, value);
4070 emitError(loc) <<
"unsupported member function `delete` on type `"
4071 << args[0]->type->toString() <<
"`";
4075 if (nameId == ksn::PopBack) {
4077 assert(numArgs == 1 &&
"`pop_back` takes 1 argument");
4078 assert(args[0]->type->isQueue() &&
"`pop_back` is only valid on queues");
4082 return moore::QueuePopBackOp::create(
builder, loc, value);
4085 if (nameId == ksn::PopFront) {
4087 assert(numArgs == 1 &&
"`pop_front` takes 1 argument");
4088 assert(args[0]->type->isQueue() &&
"`pop_front` is only valid on queues");
4092 return moore::QueuePopFrontOp::create(
builder, loc, value);
4099 if (nameId == ksn::Num) {
4100 if (args[0]->type->isAssociativeArray()) {
4101 assert(numArgs == 1 &&
"`num` takes 1 argument");
4105 return moore::AssocArraySizeOp::create(
builder, loc, value);
4107 emitError(loc) <<
"unsupported system call `" << name <<
"`";
4111 if (nameId == ksn::Exists) {
4113 assert(numArgs == 2 &&
"`exists` takes 2 arguments");
4114 assert(args[0]->type->isAssociativeArray() &&
4115 "`exists` is only valid on associative arrays");
4120 return moore::AssocArrayExistsOp::create(
builder, loc, array, key);
4123 if ((nameId == ksn::First || nameId == ksn::Last || nameId == ksn::Next ||
4124 nameId == ksn::Prev) &&
4125 args[0]->type->isAssociativeArray()) {
4126 assert(numArgs == 2 &&
"traversal methods take 2 arguments");
4131 if (nameId == ksn::First)
4132 return moore::AssocArrayFirstOp::create(
builder, loc, array, key);
4133 if (nameId == ksn::Last)
4134 return moore::AssocArrayLastOp::create(
builder, loc, array, key);
4135 if (nameId == ksn::Next)
4136 return moore::AssocArrayNextOp::create(
builder, loc, array, key);
4137 if (nameId == ksn::Prev)
4138 return moore::AssocArrayPrevOp::create(
builder, loc, array, key);
4139 llvm_unreachable(
"all traversal cases handled above");
4146 if (nameId == ksn::FOpen) {
4147 assert(numArgs >= 1 && numArgs <= 2 &&
"`$fopen` takes 1 or 2 arguments");
4152 moore::FOpenModeAttr modeAttr;
4154 auto *strLit = args[1]
4155 ->unwrapImplicitConversions()
4156 .as_if<slang::ast::StringLiteral>();
4158 return emitError(loc) <<
"$fopen mode must be a string literal",
4162 llvm::StringSwitch<std::optional<moore::FOpenMode>>(
4164 .Cases({
"r",
"rb"}, moore::FOpenMode::Read)
4165 .Cases({
"w",
"wb"}, moore::FOpenMode::Write)
4166 .Cases({
"a",
"ab"}, moore::FOpenMode::Append)
4167 .Cases({
"r+",
"r+b",
"rb+"}, moore::FOpenMode::ReadUpdate)
4168 .Cases({
"w+",
"w+b",
"wb+"}, moore::FOpenMode::WriteUpdate)
4169 .Cases({
"a+",
"a+b",
"ab+"}, moore::FOpenMode::AppendUpdate)
4170 .Default(std::nullopt);
4173 return emitError(loc)
4174 <<
"invalid $fopen mode '" << strLit->getValue() <<
"'",
4176 modeAttr = moore::FOpenModeAttr::get(
getContext(), *mode);
4178 return moore::FOpenBIOp::create(
builder, loc, filename, modeAttr);
4185 if (nameId == ksn::TestPlusArgs) {
4187 assert(numArgs == 1 &&
"`$test$plusargs` takes 1 argument");
4189 args[0]->unwrapImplicitConversions().as_if<slang::ast::StringLiteral>();
4191 return emitError(loc) <<
"`$test$plusargs` argument must be a string "
4194 auto foundTy = moore::IntType::getInt(
getContext(), 1);
4195 return moore::PlusArgsTestBIOp::create(
4196 builder, loc, foundTy,
builder.getStringAttr(strLit->getValue()));
4199 if (nameId == ksn::ValuePlusArgs) {
4203 assert(numArgs == 2 &&
"`$value$plusargs` takes 2 arguments");
4205 args[0]->unwrapImplicitConversions().as_if<slang::ast::StringLiteral>();
4207 return emitError(loc) <<
"`$value$plusargs` format must be a string "
4212 const auto *valueArg = args[1];
4213 if (
const auto *assign =
4214 valueArg->as_if<slang::ast::AssignmentExpression>())
4215 valueArg = &assign->left();
4219 auto resultType = cast<moore::RefType>(lvalue.getType()).getNestedType();
4220 auto foundTy = moore::IntType::getInt(
getContext(), 1);
4221 auto op = moore::PlusArgsValueBIOp::create(
4222 builder, loc, foundTy, resultType,
4223 builder.getStringAttr(strLit->getValue()));
4224 moore::BlockingAssignOp::create(
builder, loc, lvalue, op.getResult());
4225 return op.getFound();
4228 if (nameId == ksn::FScanf) {
4230 *args[0], moore::IntType::getInt(
builder.getContext(), 32));
4234 args[1]->unwrapImplicitConversions().as_if<slang::ast::StringLiteral>();
4236 return (mlir::emitError(loc)
4237 <<
"$fscanf requires a string literal format string"),
4240 moore::ScanBeginFScanFOp::create(
builder, loc, fd).getCursor();
4247 return moore::ScanEndOp::create(
builder, loc, result->finalCursor)
4251 if (nameId == ksn::SScanf) {
4257 args[1]->unwrapImplicitConversions().as_if<slang::ast::StringLiteral>();
4259 return (mlir::emitError(loc)
4260 <<
"$sscanf requires a string literal format string"),
4263 moore::ScanBeginSScanFOp::create(
builder, loc, str).getCursor();
4270 return moore::ScanEndOp::create(
builder, loc, result->finalCursor)
4279 assert(!(nameId == ksn::First || nameId == ksn::Last || nameId == ksn::Num) ||
4280 !args[0]->type->isEnum());
4282 if (nameId == ksn::Name && args[0]->type->isEnum()) {
4283 assert(numArgs == 1 &&
"`name` takes 1 argument");
4290 return mlir::func::CallOp::create(
builder, loc, helper, ValueRange{value})
4294 if ((nameId == ksn::Next || nameId == ksn::Prev) && args[0]->type->isEnum()) {
4295 assert(numArgs >= 1 && numArgs <= 2 &&
"`next`/`prev` take 1 or 2 args");
4301 auto posType = moore::IntType::getInt(
getContext(), 32);
4306 count = moore::ConstantOp::create(
builder, loc, posType, 1);
4313 return mlir::func::CallOp::create(
builder, loc, helper,
4314 ValueRange{value, count})
4319 emitError(loc) <<
"unsupported system call `" << name <<
"`";
4325 return context.symbolTable.lookupNearestSymbolFrom(
context.intoModuleOp, sym);
4329 const moore::ClassHandleType &baseTy) {
4330 if (!actualTy || !baseTy)
4333 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
4334 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
4336 if (actualSym == baseSym)
4339 auto *op =
resolve(*
this, actualSym);
4340 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
4343 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
4346 if (curBase == baseSym)
4348 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
4353moore::ClassHandleType
4355 llvm::StringRef fieldName, Location loc) {
4357 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
4361 auto *op =
resolve(*
this, classSym);
4362 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
4367 for (
auto &block : decl.getBody()) {
4368 for (
auto &opInBlock : block) {
4370 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
4371 if (prop.getSymName() == fieldName) {
4373 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
4380 classSym = decl.getBaseAttr();
4384 mlir::emitError(loc) <<
"unknown property `" << fieldName <<
"`";
4393 const slang::ast::Expression &expr) {
4396 if (
const auto *valueRange = expr.as_if<slang::ast::ValueRangeExpression>()) {
4401 if (!insideLhs || !lowBound || !highBound)
4404 Value rangeLhs, rangeRhs;
4407 if (valueRange->left().type->isSigned() ||
4408 insideLhs.getType().isSignedInteger()) {
4409 rangeLhs = moore::SgeOp::create(
builder, loc, insideLhs, lowBound);
4411 rangeLhs = moore::UgeOp::create(
builder, loc, insideLhs, lowBound);
4414 if (valueRange->right().type->isSigned() ||
4415 insideLhs.getType().isSignedInteger()) {
4416 rangeRhs = moore::SleOp::create(
builder, loc, insideLhs, highBound);
4418 rangeRhs = moore::UleOp::create(
builder, loc, insideLhs, highBound);
4421 return moore::AndOp::create(
builder, loc, rangeLhs, rangeRhs);
4425 if (!expr.type->isIntegral()) {
4426 if (expr.type->isUnpackedArray()) {
4427 mlir::emitError(loc,
4428 "unpacked arrays in 'inside' expressions not supported");
4432 loc,
"only simple bit vectors supported in 'inside' expressions");
4439 return moore::WildcardEqOp::create(
builder, loc, insideLhs, value);
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Value convertRealMathBI(Context &context, Location loc, StringRef name, std::span< const slang::ast::Expression *const > args)
Helper function to convert real math builtin functions that take exactly one argument.
static Value convertRealMathTwoBI(Context &context, Location loc, StringRef name, std::span< const slang::ast::Expression *const > args)
Helper function to convert real math builtin functions that take exactly two arguments.
static mlir::Value maybeUpcastHandle(Context &context, mlir::Value actualHandle, moore::ClassHandleType expectedHandleTy)
Check whether the actual handle is a subclass of another handle type and return a properly upcast ver...
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
static Value lookupExpandedInterfaceMember(Context &context, const slang::ast::HierarchicalValueExpression &expr)
Resolve a hierarchical value that refers to a member of an expanded interface instance.
static void ensureDescendingOrder(RangeT &range, const slang::ast::Type &type)
Ensures that the given range is in "descending" order.
static Value visitClassProperty(Context &context, const slang::ast::ClassPropertySymbol &expr)
static Value materializeSBVToPackedConversion(Context &context, moore::PackedType packedType, Value value, Location loc, bool fallible)
Create the necessary operations to convert from a simple bit vector IntType to an equivalent PackedTy...
static LogicalResult emitScanAssignments(Context &context, const Context::ScanStringResult &result, Location loc)
static Value getIsUnknown(OpBuilder &builder, Location loc, Value value, moore::IntType valTy, MLIRContext *ctx)
Check if a Moore integer value contains any unknown (x/z) bits.
static uint64_t getTimeScaleInFemtoseconds(Context &context)
Get the currently active timescale as an integer number of femtoseconds.
static Value coerceToBuiltinInt(OpBuilder &builder, Location loc, Value value, moore::IntType valTy)
Coerce a Moore integer value to a builtin integer, handling four-valued inputs by first mapping x/z t...
static FVInt convertSVIntToFVInt(const slang::SVInt &svint)
Convert a Slang SVInt to a CIRCT FVInt.
static InstancePath empty
Four-valued arbitrary precision integers.
static FVInt getAllX(unsigned numBits)
Construct an FVInt with all bits set to X.
A packed SystemVerilog type.
bool containsTimeType() const
Check if this is a TimeType, or an aggregate that contains a nested TimeType.
IntType getSimpleBitVector() const
Get the simple bit vector type equivalent to this packed type.
An unpacked SystemVerilog type.
Value getSelectIndex(Context &context, Location loc, Value index, const slang::ConstantRange &range)
Map an index into an array, with bounds range, to a bit offset of the underlying bit storage.
Domain
The number of values each bit of a type can assume.
@ FourValued
Four-valued types such as logic or integer.
@ TwoValued
Two-valued types such as bit or int.
bool isIntType(Type type, unsigned width)
Check if a type is an IntType type of the given width.
@ f32
A standard 32-Bit floating point number ("float")
@ f64
A 64-bit double-precision floation point number ("double")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
FailureOr< ScanStringResult > convertScanString(StringRef formatStr, Value initialCursor, std::span< const slang::ast::Expression *const > destinations, Location loc)
Convert a scan format string into a consuming chain of moore.scan.
Value convertLvalueExpression(const slang::ast::Expression &expr)
Value materializeConstant(const slang::ConstantValue &constant, const slang::ast::Type &type, Location loc)
Helper function to materialize a ConstantValue as an SSA value.
slang::ConstantValue evaluateConstant(const slang::ast::Expression &expr)
Evaluate the constant value of an expression.
Value convertInsideCheck(Value insideLhs, Location loc, const slang::ast::Expression &expr)
Convert the inside/set-membership expression.
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
OpBuilder builder
The builder used to create IR operations.
Value materializeFixedSizeUnpackedArrayType(const slang::ConstantValue &constant, const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc)
Helper function to materialize an unpacked array of SVInts as an SSA value.
std::function< void(moore::ReadOp)> rvalueReadCallback
A listener called for every variable or net being read.
bool isClassDerivedFrom(const moore::ClassHandleType &actualTy, const moore::ClassHandleType &baseTy)
Checks whether one class (actualTy) is derived from another class (baseTy).
Value convertSystemCall(const slang::ast::SystemSubroutine &subroutine, Location loc, std::span< const slang::ast::Expression *const > args)
Convert system function calls.
DenseMap< std::pair< const slang::ast::EnumType *, slang::parsing::KnownSystemName >, mlir::func::FuncOp > enumHelpers
Helper functions generated for the enum built-in methods, keyed by the canonical enum type and the me...
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.
Value materializeSVInt(const slang::SVInt &svint, const slang::ast::Type &type, Location loc)
Helper function to materialize an SVInt as an SSA value.
Value materializeSVReal(const slang::ConstantValue &svreal, const slang::ast::Type &type, Location loc)
Helper function to materialize a real value as an SSA value.
Value convertToBool(Value value)
Helper function to convert a value to its "truthy" boolean value.
ValueSymbols valueSymbols
mlir::func::FuncOp getOrCreateEnumHelper(const slang::ast::Type &type, slang::parsing::KnownSystemName method, Location loc)
Get the helper function implementing one of the name, next, and prev built-in methods for the given e...
moore::ClassHandleType getAncestorClassWithProperty(const moore::ClassHandleType &actualTy, StringRef fieldName, Location loc)
Tries to find the closest base class of actualTy that carries a property with name fieldName.
Value materializePackedToSBVConversion(Value value, Location loc, bool fallible)
Helper function to convert a PackedType value to its simple bit vector representation,...
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
Value convertToSimpleBitVector(Value value)
Helper function to convert a value to its simple bit vector representation, if it has one.
Value materializeString(const slang::ConstantValue &string, const slang::ast::Type &astType, Location loc)
Helper function to materialize a string as an SSA value.
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.
Value currentQueue
Variable that tracks the queue which we are currently converting the index expression for.
std::map< LocationKey, Operation * > orderedRootOps
The top-level operations ordered by their Slang source location.
FunctionLowering * currentFunctionLowering
The function currently being converted, if any.
mlir::ModuleOp intoModuleOp
SymbolTable symbolTable
A symbol table of the MLIR module we are emitting into.
std::optional< std::pair< const slang::ast::InstanceSymbol *, mlir::StringAttr > > buildHierValueKey(const slang::ast::HierarchicalValueExpression &expr)
Build a composite key for hierValueSymbols from a hierarchical value expression.
MLIRContext * getContext()
Return the MLIR context.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Function lowering information.
SmallVector< const slang::ast::ValueSymbol *, 4 > capturedSymbols
The AST symbols captured by this function, determined by the capture analysis pre-pass.
mlir::FunctionOpInterface op
static LocationKey get(const slang::SourceLocation &loc, const slang::SourceManager &mgr)