12#include "mlir/IR/Operation.h"
13#include "mlir/IR/Value.h"
14#include "slang/ast/EvalContext.h"
15#include "slang/ast/SystemSubroutine.h"
16#include "slang/ast/types/AllTypes.h"
17#include "slang/syntax/AllSyntax.h"
18#include "llvm/ADT/ScopeExit.h"
19#include "llvm/Support/SaveAndRestore.h"
22using namespace ImportVerilog;
27 if (svint.hasUnknown()) {
28 unsigned numWords = svint.getNumWords() / 2;
29 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
30 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
31 return FVInt(APInt(svint.getBitWidth(), value),
32 APInt(svint.getBitWidth(), unknown));
34 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
35 return FVInt(APInt(svint.getBitWidth(), value));
42 const slang::ConstantRange &range) {
43 auto &builder =
context.builder;
44 auto indexType = cast<moore::UnpackedType>(index.getType());
47 auto lo = range.lower();
48 auto hi = range.upper();
49 auto offset = range.isLittleEndian() ? lo : hi;
52 const bool needSigned = (lo < 0) || (hi < 0);
55 const uint64_t maxAbs = std::max<uint64_t>(std::abs(lo), std::abs(hi));
60 unsigned want = needSigned
61 ? (llvm::Log2_64_Ceil(std::max<uint64_t>(1, maxAbs)) + 1)
62 : std::max<unsigned>(1, llvm::Log2_64_Ceil(maxAbs + 1));
65 const unsigned bw = std::max<unsigned>(want, indexType.getBitSize().value());
68 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
69 index =
context.materializeConversion(intType, index, needSigned, loc);
72 if (range.isLittleEndian())
75 return moore::NegOp::create(builder, loc, index);
79 moore::ConstantOp::create(builder, loc, intType, offset, needSigned);
80 if (range.isLittleEndian())
81 return moore::SubOp::create(builder, loc, index, offsetConst);
83 return moore::SubOp::create(builder, loc, offsetConst, index);
88 static_assert(int(slang::TimeUnit::Seconds) == 0);
89 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
90 static_assert(int(slang::TimeUnit::Microseconds) == 2);
91 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
92 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
93 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
95 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
96 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
97 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
99 auto exp =
static_cast<unsigned>(
context.timeScale.base.unit);
102 auto scale =
static_cast<uint64_t
>(
context.timeScale.base.magnitude);
111 Context &
context,
const slang::ast::HierarchicalValueExpression &expr) {
112 auto nameAttr =
context.builder.getStringAttr(expr.symbol.name);
113 for (
const auto &element : expr.ref.path) {
114 auto *inst = element.symbol->as_if<slang::ast::InstanceSymbol>();
117 auto *lowering =
context.interfaceInstances.lookup(inst);
120 if (
auto it = lowering->expandedMembers.find(&expr.symbol);
121 it != lowering->expandedMembers.end())
123 if (
auto it = lowering->expandedMembersByName.find(nameAttr);
124 it != lowering->expandedMembersByName.end())
131 const slang::ast::ClassPropertySymbol &expr) {
132 auto loc =
context.convertLocation(expr.location);
133 auto builder =
context.builder;
134 auto type =
context.convertType(expr.getType());
135 auto fieldTy = cast<moore::UnpackedType>(type);
136 auto fieldRefTy = moore::RefType::get(fieldTy);
138 if (expr.lifetime == slang::ast::VariableLifetime::Static) {
141 if (!
context.globalVariables.lookup(&expr)) {
142 if (failed(
context.convertGlobalVariable(expr))) {
147 if (
auto globalOp =
context.globalVariables.lookup(&expr))
148 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
150 mlir::emitError(loc) <<
"Failed to access static member variable "
151 << expr.name <<
" as a global variable";
156 mlir::Value instRef =
context.getImplicitThisRef();
158 mlir::emitError(loc) <<
"class property '" << expr.name
159 <<
"' referenced without an implicit 'this'";
163 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.name);
165 moore::ClassHandleType classTy =
166 cast<moore::ClassHandleType>(instRef.getType());
168 auto targetClassHandle =
169 context.getAncestorClassWithProperty(classTy, expr.name, loc);
170 if (!targetClassHandle)
173 auto upcastRef =
context.materializeConversion(targetClassHandle, instRef,
174 false, instRef.getLoc());
178 Value fieldRef = moore::ClassPropertyRefOp::create(builder, loc, fieldRefTy,
179 upcastRef, fieldSym);
191 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
192 : context(context), loc(loc), builder(context.builder),
193 isLvalue(isLvalue) {}
199 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
207 Value materializeSymbolRvalue(
const slang::ast::ValueSymbol &sym) {
209 if (isa<moore::RefType>(value.getType())) {
210 auto readOp = moore::ReadOp::create(builder, loc, value);
213 return readOp.getResult();
219 auto ref = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
220 auto readOp = moore::ReadOp::create(builder, loc, ref);
223 return readOp.getResult();
226 if (
auto *
const property = sym.as_if<slang::ast::ClassPropertySymbol>()) {
228 auto readOp = moore::ReadOp::create(builder, loc, fieldRef);
231 return readOp.getResult();
237 Value visit(
const slang::ast::NewArrayExpression &expr) {
242 if (expr.initExpr()) {
244 <<
"unsupported expression: array `new` with initializer\n";
249 expr.sizeExpr(), context.
convertType(*expr.sizeExpr().type));
253 return moore::OpenUArrayCreateOp::create(builder, loc, type, initialSize);
257 Value visit(
const slang::ast::ElementSelectExpression &expr) {
259 auto value = convertLvalueOrRvalueExpression(expr.value());
264 auto derefType = value.getType();
266 derefType = cast<moore::RefType>(derefType).getNestedType();
268 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType,
269 moore::QueueType, moore::AssocArrayType, moore::StringType,
270 moore::OpenUnpackedArrayType>(derefType)) {
271 mlir::emitError(loc) <<
"unsupported expression: element select into "
272 << expr.value().type->toString() <<
"\n";
277 if (isa<moore::AssocArrayType>(derefType)) {
278 auto assocArray = cast<moore::AssocArrayType>(derefType);
279 auto expectedIndexType = assocArray.getIndexType();
285 if (givenIndex.getType() != expectedIndexType) {
287 <<
"Incorrect index type: expected index type of "
288 << expectedIndexType <<
" but was given " << givenIndex.getType();
292 return moore::AssocArrayExtractRefOp::create(
293 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
296 return moore::AssocArrayExtractOp::create(builder, loc, type, value,
301 if (isa<moore::StringType>(derefType)) {
303 mlir::emitError(loc) <<
"string index assignment not supported";
308 auto i32Type = moore::IntType::getInt(builder.getContext(), 32);
314 return moore::StringGetOp::create(builder, loc, value, index);
318 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
319 auto range = expr.value().type->getFixedRange();
320 if (
auto *constValue = expr.selector().getConstant();
321 constValue && constValue->isInteger()) {
322 assert(!constValue->hasUnknown());
323 assert(constValue->size() <= 32);
325 auto lowBit = constValue->integer().as<uint32_t>().value();
327 return llvm::TypeSwitch<Type, Value>(derefType)
328 .Case<moore::QueueType>([&](moore::QueueType) {
330 <<
"Unexpected LValue extract on Queue Type!";
334 return moore::ExtractRefOp::create(builder, loc, resultType,
336 range.translateIndex(lowBit));
339 return llvm::TypeSwitch<Type, Value>(derefType)
340 .Case<moore::QueueType>([&](moore::QueueType) {
342 <<
"Unexpected RValue extract on Queue Type!";
346 return moore::ExtractOp::create(builder, loc, resultType, value,
347 range.translateIndex(lowBit));
354 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
355 if (isa<moore::QueueType>(derefType)) {
358 if (isa<moore::RefType>(value.getType())) {
359 context.
currentQueue = moore::ReadOp::create(builder, loc, value);
370 return llvm::TypeSwitch<Type, Value>(derefType)
371 .Case<moore::QueueType>([&](moore::QueueType) {
372 return moore::DynQueueRefElementOp::create(builder, loc, resultType,
376 return moore::DynExtractRefOp::create(builder, loc, resultType,
381 return llvm::TypeSwitch<Type, Value>(derefType)
382 .Case<moore::QueueType>([&](moore::QueueType) {
383 return moore::DynQueueExtractOp::create(builder, loc, resultType,
384 value, lowBit, lowBit);
387 return moore::DynExtractOp::create(builder, loc, resultType, value,
394 Value visit(
const slang::ast::NullLiteral &expr) {
396 if (isa<moore::ClassHandleType, moore::ChandleType, moore::EventType,
397 moore::NullType>(type))
398 return moore::NullOp::create(builder, loc);
399 mlir::emitError(loc) <<
"No null value definition found for value of type "
405 Value visit(
const slang::ast::RangeSelectExpression &expr) {
407 auto value = convertLvalueOrRvalueExpression(expr.value());
411 auto derefType = value.getType();
413 derefType = cast<moore::RefType>(derefType).getNestedType();
415 if (isa<moore::QueueType>(derefType)) {
416 return handleQueueRangeSelectExpressions(expr, type, value);
418 return handleArrayRangeSelectExpressions(expr, type, value);
423 Value handleQueueRangeSelectExpressions(
424 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
426 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
432 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
435 mlir::emitError(loc) <<
"queue lvalue range selections are not supported";
438 return moore::DynQueueExtractOp::create(builder, loc, resultType, value,
444 Value handleArrayRangeSelectExpressions(
445 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
446 std::optional<int32_t> constLeft;
447 std::optional<int32_t> constRight;
448 if (
auto *constant = expr.left().getConstant())
449 constLeft = constant->integer().as<int32_t>();
450 if (
auto *constant = expr.right().getConstant())
451 constRight = constant->integer().as<int32_t>();
457 <<
"unsupported expression: range select with non-constant bounds";
477 int32_t offsetConst = 0;
478 auto range = expr.value().type->getFixedRange();
480 using slang::ast::RangeSelectionKind;
481 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
486 assert(constRight &&
"constness checked in slang");
487 offsetConst = *constRight;
498 offsetConst = *constLeft;
509 int32_t offsetAdd = 0;
514 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
515 range.isLittleEndian()) {
516 assert(constRight &&
"constness checked in slang");
517 offsetAdd = 1 - *constRight;
523 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
524 !range.isLittleEndian()) {
525 assert(constRight &&
"constness checked in slang");
526 offsetAdd = *constRight - 1;
530 if (offsetAdd != 0) {
532 offsetDyn = moore::AddOp::create(
533 builder, loc, offsetDyn,
534 moore::ConstantOp::create(
535 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
539 offsetConst += offsetAdd;
550 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
555 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
558 return moore::DynExtractOp::create(builder, loc, resultType, value,
562 offsetConst = range.translateIndex(offsetConst);
564 return moore::ExtractRefOp::create(builder, loc, resultType, value,
567 return moore::ExtractOp::create(builder, loc, resultType, value,
574 Value visit(
const slang::ast::ConcatenationExpression &expr) {
575 SmallVector<Value> operands;
576 if (expr.type->isString()) {
577 for (
auto *operand : expr.operands()) {
578 assert(!isLvalue &&
"checked by Slang");
579 auto value = convertLvalueOrRvalueExpression(*operand);
583 moore::StringType::get(context.
getContext()), value,
false,
587 operands.push_back(value);
589 return moore::StringConcatOp::create(builder, loc, operands);
591 if (expr.type->isQueue()) {
592 return handleQueueConcat(expr);
594 for (
auto *operand : expr.operands()) {
598 if (operand->type->isVoid())
600 auto value = convertLvalueOrRvalueExpression(*operand);
607 operands.push_back(value);
610 return moore::ConcatRefOp::create(builder, loc, operands);
612 return moore::ConcatOp::create(builder, loc, operands);
619 Value handleQueueConcat(
const slang::ast::ConcatenationExpression &expr) {
620 SmallVector<Value> operands;
623 cast<moore::QueueType>(context.
convertType(*expr.type, loc));
635 Value contigElements;
637 for (
auto *operand : expr.operands()) {
638 bool isSingleElement =
643 if (!isSingleElement && contigElements) {
644 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
648 assert(!isLvalue &&
"checked by Slang");
649 auto value = convertLvalueOrRvalueExpression(*operand);
657 moore::RefType::get(context.
getContext(), queueType);
659 if (!contigElements) {
661 moore::VariableOp::create(builder, loc, queueRefType, {}, {});
663 moore::QueuePushBackOp::create(builder, loc, contigElements, value);
671 if (!(isa<moore::QueueType>(value.getType()) &&
672 cast<moore::QueueType>(value.getType()).getElementType() ==
678 operands.push_back(value);
681 if (contigElements) {
682 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
685 return moore::QueueConcatOp::create(builder, loc, queueType, operands);
689 Value visit(
const slang::ast::MemberAccessExpression &expr) {
694 auto *valueType = expr.value().type.get();
695 auto memberName = builder.getStringAttr(expr.member.name);
701 if (valueType->isVirtualInterface()) {
702 auto memberType = dyn_cast<moore::UnpackedType>(type);
705 <<
"unsupported virtual interface member type: " << type;
708 auto resultRefType = moore::RefType::get(memberType);
716 auto memberRef = moore::StructExtractOp::create(
717 builder, loc, resultRefType, memberName, base);
720 return moore::ReadOp::create(builder, loc, memberRef);
724 if (valueType->isStruct()) {
726 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
728 auto value = convertLvalueOrRvalueExpression(expr.value());
733 return moore::StructExtractRefOp::create(builder, loc, resultType,
735 return moore::StructExtractOp::create(builder, loc, resultType,
740 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
742 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
744 auto value = convertLvalueOrRvalueExpression(expr.value());
749 return moore::UnionExtractRefOp::create(builder, loc, resultType,
751 return moore::UnionExtractOp::create(builder, loc, type, memberName,
756 if (valueType->isClass()) {
760 auto targetTy = cast<moore::ClassHandleType>(valTy);
772 if (expr.member.kind != slang::ast::SymbolKind::Parameter) {
778 moore::ClassHandleType upcastTargetTy =
792 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(),
794 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
798 Value fieldRef = moore::ClassPropertyRefOp::create(
799 builder, loc, fieldRefTy, baseVal, fieldSym);
802 return isLvalue ? fieldRef
803 : moore::ReadOp::create(builder, loc, fieldRef);
806 slang::ConstantValue constVal;
807 if (
auto param = expr.member.as_if<slang::ast::ParameterSymbol>()) {
808 constVal = param->getValue();
813 mlir::emitError(loc) <<
"Parameter " << expr.member.name
814 <<
" has no constant value";
818 mlir::emitError(loc,
"expression of type ")
819 << valueType->toString() <<
" has no member fields";
831struct RvalueExprVisitor :
public ExprVisitor {
833 : ExprVisitor(
context, loc, false) {}
834 using ExprVisitor::visit;
837 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
838 assert(!
context.lvalueStack.empty() &&
"parent assignments push lvalue");
839 auto lvalue =
context.lvalueStack.back();
840 return moore::ReadOp::create(builder, loc, lvalue);
844 Value visit(
const slang::ast::NamedValueExpression &expr) {
846 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
847 if (isa<moore::RefType>(value.getType())) {
848 auto readOp = moore::ReadOp::create(builder, loc, value);
849 if (
context.rvalueReadCallback)
850 context.rvalueReadCallback(readOp);
851 value = readOp.getResult();
857 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol)) {
858 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
859 return moore::ReadOp::create(builder, loc, value);
863 if (
auto *
const property =
864 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
866 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
873 if (
auto access =
context.virtualIfaceMembers.lookup(&expr.symbol);
875 auto type =
context.convertType(*expr.type);
878 auto memberType = dyn_cast<moore::UnpackedType>(type);
881 <<
"unsupported virtual interface member type: " << type;
885 Value base = materializeSymbolRvalue(*access.base);
887 auto d = mlir::emitError(loc,
"unknown name `")
888 << access.base->name <<
"`";
889 d.attachNote(
context.convertLocation(access.base->location))
890 <<
"no rvalue generated for virtual interface base";
894 auto fieldName = access.fieldName
896 : builder.getStringAttr(expr.symbol.name);
897 auto memberRefType = moore::RefType::get(memberType);
898 auto memberRef = moore::StructExtractOp::create(
899 builder, loc, memberRefType, fieldName, base);
900 auto readOp = moore::ReadOp::create(builder, loc, memberRef);
901 if (
context.rvalueReadCallback)
902 context.rvalueReadCallback(readOp);
903 return readOp.getResult();
907 auto constant =
context.evaluateConstant(expr);
908 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
913 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
914 d.attachNote(
context.convertLocation(expr.symbol.location))
915 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
920 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
921 auto hierLoc =
context.convertLocation(expr.symbol.location);
922 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
923 if (isa<moore::RefType>(value.getType())) {
924 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
925 if (
context.rvalueReadCallback)
926 context.rvalueReadCallback(readOp);
927 value = readOp.getResult();
933 if (isa<moore::RefType>(value.getType())) {
934 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
935 if (
context.rvalueReadCallback)
936 context.rvalueReadCallback(readOp);
937 return readOp.getResult();
944 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
945 << expr.symbol.name <<
"`";
946 d.attachNote(hierLoc) <<
"no rvalue generated for "
947 << slang::ast::toString(expr.symbol.kind);
953 Value visit(
const slang::ast::ArbitrarySymbolExpression &expr) {
954 const auto &canonTy = expr.type->getCanonicalType();
955 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>()) {
956 auto value =
context.materializeVirtualInterfaceValue(*vi, loc);
962 mlir::emitError(loc) <<
"unsupported arbitrary symbol expression of type "
963 << expr.type->toString();
968 Value visit(
const slang::ast::ConversionExpression &expr) {
969 auto type =
context.convertType(*expr.type);
972 return context.convertRvalueExpression(expr.operand(), type);
976 Value visit(
const slang::ast::AssignmentExpression &expr) {
977 auto lhs =
context.convertLvalueExpression(expr.left());
982 context.lvalueStack.push_back(lhs);
983 auto rhs =
context.convertRvalueExpression(
984 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
985 context.lvalueStack.pop_back();
992 if (!expr.isNonBlocking()) {
993 if (expr.timingControl)
994 if (failed(
context.convertTimingControl(*expr.timingControl)))
996 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
997 if (
context.variableAssignCallback)
998 context.variableAssignCallback(assignOp);
1003 if (expr.timingControl) {
1005 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
1006 auto delay =
context.convertRvalueExpression(
1007 ctrl->expr, moore::TimeType::get(builder.getContext()));
1010 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
1011 builder, loc, lhs, rhs, delay);
1012 if (
context.variableAssignCallback)
1013 context.variableAssignCallback(assignOp);
1018 auto loc =
context.convertLocation(expr.timingControl->sourceRange);
1019 mlir::emitError(loc)
1020 <<
"unsupported non-blocking assignment timing control: "
1021 << slang::ast::toString(expr.timingControl->kind);
1024 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
1025 if (
context.variableAssignCallback)
1026 context.variableAssignCallback(assignOp);
1032 template <
class ConcreteOp>
1033 Value createReduction(Value arg,
bool invert) {
1034 arg =
context.convertToSimpleBitVector(arg);
1037 Value result = ConcreteOp::create(builder, loc, arg);
1039 result = moore::NotOp::create(builder, loc, result);
1044 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
1045 auto preValue = moore::ReadOp::create(builder, loc, arg);
1051 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
1054 auto one = moore::ConstantOp::create(
1055 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
1057 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
1058 : moore::SubOp::create(builder, loc, preValue, one).getResult();
1060 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
1061 if (
context.variableAssignCallback)
1062 context.variableAssignCallback(assignOp);
1071 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
1072 Value preValue = moore::ReadOp::create(builder, loc, arg);
1075 bool isTime = isa<moore::TimeType>(preValue.getType());
1077 preValue =
context.materializeConversion(
1078 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1079 preValue,
false, loc);
1081 moore::RealType realTy =
1082 llvm::dyn_cast<moore::RealType>(preValue.getType());
1087 if (realTy.getWidth() == moore::RealWidth::f32) {
1088 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
1089 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
1091 oneAttr = builder.getFloatAttr(builder.getF64Type(), oneVal);
1093 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
1096 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
1100 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
1101 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
1104 postValue =
context.materializeConversion(
1105 moore::TimeType::get(
context.getContext()), postValue,
false, loc);
1108 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
1110 if (
context.variableAssignCallback)
1111 context.variableAssignCallback(assignOp);
1118 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
1119 Type opFTy =
context.convertType(*expr.operand().type);
1121 using slang::ast::UnaryOperator;
1123 if (expr.op == UnaryOperator::Preincrement ||
1124 expr.op == UnaryOperator::Predecrement ||
1125 expr.op == UnaryOperator::Postincrement ||
1126 expr.op == UnaryOperator::Postdecrement)
1127 arg =
context.convertLvalueExpression(expr.operand());
1129 arg =
context.convertRvalueExpression(expr.operand(), opFTy);
1134 if (isa<moore::TimeType>(arg.getType()))
1135 arg =
context.materializeConversion(
1136 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1141 case UnaryOperator::Plus:
1143 case UnaryOperator::Minus:
1144 return moore::NegRealOp::create(builder, loc, arg);
1146 case UnaryOperator::Preincrement:
1147 return createRealIncrement(arg,
true,
false);
1148 case UnaryOperator::Predecrement:
1149 return createRealIncrement(arg,
false,
false);
1150 case UnaryOperator::Postincrement:
1151 return createRealIncrement(arg,
true,
true);
1152 case UnaryOperator::Postdecrement:
1153 return createRealIncrement(arg,
false,
true);
1155 case UnaryOperator::LogicalNot:
1156 arg =
context.convertToBool(arg);
1159 return moore::NotOp::create(builder, loc, arg);
1162 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
1163 <<
" not supported with real values!\n";
1169 Value visit(
const slang::ast::UnaryExpression &expr) {
1171 const auto *floatType =
1172 expr.operand().type->as_if<slang::ast::FloatingType>();
1175 return visitRealUOp(expr);
1177 using slang::ast::UnaryOperator;
1179 if (expr.op == UnaryOperator::Preincrement ||
1180 expr.op == UnaryOperator::Predecrement ||
1181 expr.op == UnaryOperator::Postincrement ||
1182 expr.op == UnaryOperator::Postdecrement)
1183 arg =
context.convertLvalueExpression(expr.operand());
1185 arg =
context.convertRvalueExpression(expr.operand());
1192 case UnaryOperator::Plus:
1193 return context.convertToSimpleBitVector(arg);
1195 case UnaryOperator::Minus:
1196 arg =
context.convertToSimpleBitVector(arg);
1199 return moore::NegOp::create(builder, loc, arg);
1201 case UnaryOperator::BitwiseNot:
1202 arg =
context.convertToSimpleBitVector(arg);
1205 return moore::NotOp::create(builder, loc, arg);
1207 case UnaryOperator::BitwiseAnd:
1208 return createReduction<moore::ReduceAndOp>(arg,
false);
1209 case UnaryOperator::BitwiseOr:
1210 return createReduction<moore::ReduceOrOp>(arg,
false);
1211 case UnaryOperator::BitwiseXor:
1212 return createReduction<moore::ReduceXorOp>(arg,
false);
1213 case UnaryOperator::BitwiseNand:
1214 return createReduction<moore::ReduceAndOp>(arg,
true);
1215 case UnaryOperator::BitwiseNor:
1216 return createReduction<moore::ReduceOrOp>(arg,
true);
1217 case UnaryOperator::BitwiseXnor:
1218 return createReduction<moore::ReduceXorOp>(arg,
true);
1220 case UnaryOperator::LogicalNot:
1221 arg =
context.convertToBool(arg);
1224 return moore::NotOp::create(builder, loc, arg);
1226 case UnaryOperator::Preincrement:
1227 return createIncrement(arg,
true,
false);
1228 case UnaryOperator::Predecrement:
1229 return createIncrement(arg,
false,
false);
1230 case UnaryOperator::Postincrement:
1231 return createIncrement(arg,
true,
true);
1232 case UnaryOperator::Postdecrement:
1233 return createIncrement(arg,
false,
true);
1236 mlir::emitError(loc,
"unsupported unary operator");
1241 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
1242 std::optional<Domain> domain = std::nullopt) {
1243 using slang::ast::BinaryOperator;
1247 lhs =
context.convertToBool(lhs, domain.value());
1248 rhs =
context.convertToBool(rhs, domain.value());
1250 lhs =
context.convertToBool(lhs);
1251 rhs =
context.convertToBool(rhs);
1258 case BinaryOperator::LogicalAnd:
1259 return moore::AndOp::create(builder, loc, lhs, rhs);
1261 case BinaryOperator::LogicalOr:
1262 return moore::OrOp::create(builder, loc, lhs, rhs);
1264 case BinaryOperator::LogicalImplication: {
1266 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1267 return moore::OrOp::create(builder, loc, notLHS, rhs);
1270 case BinaryOperator::LogicalEquivalence: {
1272 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1273 auto notRHS = moore::NotOp::create(builder, loc, rhs);
1274 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
1275 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
1276 return moore::OrOp::create(builder, loc, both, notBoth);
1280 llvm_unreachable(
"not a logical BinaryOperator");
1284 Value visitHandleBOp(
const slang::ast::BinaryExpression &expr) {
1286 auto lhs =
context.convertRvalueExpression(expr.left());
1289 auto rhs =
context.convertRvalueExpression(expr.right());
1293 using slang::ast::BinaryOperator;
1296 case BinaryOperator::Equality:
1297 return moore::HandleEqOp::create(builder, loc, lhs, rhs);
1298 case BinaryOperator::Inequality:
1299 return moore::HandleNeOp::create(builder, loc, lhs, rhs);
1300 case BinaryOperator::CaseEquality:
1301 return moore::HandleCaseEqOp::create(builder, loc, lhs, rhs);
1302 case BinaryOperator::CaseInequality:
1303 return moore::HandleCaseNeOp::create(builder, loc, lhs, rhs);
1306 mlir::emitError(loc)
1307 <<
"Binary operator " << slang::ast::toString(expr.op)
1308 <<
" not supported with class handle valued operands!\n";
1313 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
1315 auto lhs =
context.convertRvalueExpression(expr.left());
1318 auto rhs =
context.convertRvalueExpression(expr.right());
1322 if (isa<moore::TimeType>(lhs.getType()) ||
1323 isa<moore::TimeType>(rhs.getType())) {
1324 lhs =
context.materializeConversion(
1325 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1327 rhs =
context.materializeConversion(
1328 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1332 using slang::ast::BinaryOperator;
1334 case BinaryOperator::Add:
1335 return moore::AddRealOp::create(builder, loc, lhs, rhs);
1336 case BinaryOperator::Subtract:
1337 return moore::SubRealOp::create(builder, loc, lhs, rhs);
1338 case BinaryOperator::Multiply:
1339 return moore::MulRealOp::create(builder, loc, lhs, rhs);
1340 case BinaryOperator::Divide:
1341 return moore::DivRealOp::create(builder, loc, lhs, rhs);
1342 case BinaryOperator::Power:
1343 return moore::PowRealOp::create(builder, loc, lhs, rhs);
1345 case BinaryOperator::Equality:
1346 return moore::EqRealOp::create(builder, loc, lhs, rhs);
1347 case BinaryOperator::Inequality:
1348 return moore::NeRealOp::create(builder, loc, lhs, rhs);
1350 case BinaryOperator::GreaterThan:
1351 return moore::FgtOp::create(builder, loc, lhs, rhs);
1352 case BinaryOperator::LessThan:
1353 return moore::FltOp::create(builder, loc, lhs, rhs);
1354 case BinaryOperator::GreaterThanEqual:
1355 return moore::FgeOp::create(builder, loc, lhs, rhs);
1356 case BinaryOperator::LessThanEqual:
1357 return moore::FleOp::create(builder, loc, lhs, rhs);
1359 case BinaryOperator::LogicalAnd:
1360 case BinaryOperator::LogicalOr:
1361 case BinaryOperator::LogicalImplication:
1362 case BinaryOperator::LogicalEquivalence:
1363 return buildLogicalBOp(expr.op, lhs, rhs);
1366 mlir::emitError(loc) <<
"Binary operator "
1367 << slang::ast::toString(expr.op)
1368 <<
" not supported with real valued operands!\n";
1375 template <
class ConcreteOp>
1376 Value createBinary(Value lhs, Value rhs) {
1377 lhs =
context.convertToSimpleBitVector(lhs);
1380 rhs =
context.convertToSimpleBitVector(rhs);
1383 return ConcreteOp::create(builder, loc, lhs, rhs);
1387 Value visit(
const slang::ast::BinaryExpression &expr) {
1389 const auto *rhsFloatType =
1390 expr.right().type->as_if<slang::ast::FloatingType>();
1391 const auto *lhsFloatType =
1392 expr.left().type->as_if<slang::ast::FloatingType>();
1395 if (rhsFloatType || lhsFloatType)
1396 return visitRealBOp(expr);
1399 const auto rhsIsClass = expr.right().type->isClass();
1400 const auto lhsIsClass = expr.left().type->isClass();
1401 const auto rhsIsChandle = expr.right().type->isCHandle();
1402 const auto lhsIsChandle = expr.left().type->isCHandle();
1404 if (rhsIsClass || lhsIsClass || rhsIsChandle || lhsIsChandle)
1405 return visitHandleBOp(expr);
1407 auto lhs =
context.convertRvalueExpression(expr.left());
1410 auto rhs =
context.convertRvalueExpression(expr.right());
1415 Domain domain = Domain::TwoValued;
1416 if (expr.type->isFourState() || expr.left().type->isFourState() ||
1417 expr.right().type->isFourState())
1418 domain = Domain::FourValued;
1420 using slang::ast::BinaryOperator;
1422 case BinaryOperator::Add:
1423 return createBinary<moore::AddOp>(lhs, rhs);
1424 case BinaryOperator::Subtract:
1425 return createBinary<moore::SubOp>(lhs, rhs);
1426 case BinaryOperator::Multiply:
1427 return createBinary<moore::MulOp>(lhs, rhs);
1428 case BinaryOperator::Divide:
1429 if (expr.type->isSigned())
1430 return createBinary<moore::DivSOp>(lhs, rhs);
1432 return createBinary<moore::DivUOp>(lhs, rhs);
1433 case BinaryOperator::Mod:
1434 if (expr.type->isSigned())
1435 return createBinary<moore::ModSOp>(lhs, rhs);
1437 return createBinary<moore::ModUOp>(lhs, rhs);
1438 case BinaryOperator::Power: {
1443 auto rhsCast =
context.materializeConversion(
1444 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
1445 if (expr.type->isSigned())
1446 return createBinary<moore::PowSOp>(lhs, rhsCast);
1448 return createBinary<moore::PowUOp>(lhs, rhsCast);
1451 case BinaryOperator::BinaryAnd:
1452 return createBinary<moore::AndOp>(lhs, rhs);
1453 case BinaryOperator::BinaryOr:
1454 return createBinary<moore::OrOp>(lhs, rhs);
1455 case BinaryOperator::BinaryXor:
1456 return createBinary<moore::XorOp>(lhs, rhs);
1457 case BinaryOperator::BinaryXnor: {
1458 auto result = createBinary<moore::XorOp>(lhs, rhs);
1461 return moore::NotOp::create(builder, loc, result);
1464 case BinaryOperator::Equality:
1465 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1466 return moore::UArrayCmpOp::create(
1467 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1468 else if (isa<moore::StringType>(lhs.getType()))
1469 return moore::StringCmpOp::create(
1470 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
1471 else if (isa<moore::QueueType>(lhs.getType()))
1472 return moore::QueueCmpOp::create(
1473 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1475 return createBinary<moore::EqOp>(lhs, rhs);
1476 case BinaryOperator::Inequality:
1477 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1478 return moore::UArrayCmpOp::create(
1479 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1480 else if (isa<moore::StringType>(lhs.getType()))
1481 return moore::StringCmpOp::create(
1482 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
1483 else if (isa<moore::QueueType>(lhs.getType()))
1484 return moore::QueueCmpOp::create(
1485 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1487 return createBinary<moore::NeOp>(lhs, rhs);
1488 case BinaryOperator::CaseEquality:
1489 return createBinary<moore::CaseEqOp>(lhs, rhs);
1490 case BinaryOperator::CaseInequality:
1491 return createBinary<moore::CaseNeOp>(lhs, rhs);
1492 case BinaryOperator::WildcardEquality:
1493 return createBinary<moore::WildcardEqOp>(lhs, rhs);
1494 case BinaryOperator::WildcardInequality:
1495 return createBinary<moore::WildcardNeOp>(lhs, rhs);
1497 case BinaryOperator::GreaterThanEqual:
1498 if (expr.left().type->isSigned())
1499 return createBinary<moore::SgeOp>(lhs, rhs);
1500 else if (isa<moore::StringType>(lhs.getType()))
1501 return moore::StringCmpOp::create(
1502 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
1504 return createBinary<moore::UgeOp>(lhs, rhs);
1505 case BinaryOperator::GreaterThan:
1506 if (expr.left().type->isSigned())
1507 return createBinary<moore::SgtOp>(lhs, rhs);
1508 else if (isa<moore::StringType>(lhs.getType()))
1509 return moore::StringCmpOp::create(
1510 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
1512 return createBinary<moore::UgtOp>(lhs, rhs);
1513 case BinaryOperator::LessThanEqual:
1514 if (expr.left().type->isSigned())
1515 return createBinary<moore::SleOp>(lhs, rhs);
1516 else if (isa<moore::StringType>(lhs.getType()))
1517 return moore::StringCmpOp::create(
1518 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1520 return createBinary<moore::UleOp>(lhs, rhs);
1521 case BinaryOperator::LessThan:
1522 if (expr.left().type->isSigned())
1523 return createBinary<moore::SltOp>(lhs, rhs);
1524 else if (isa<moore::StringType>(lhs.getType()))
1525 return moore::StringCmpOp::create(
1526 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1528 return createBinary<moore::UltOp>(lhs, rhs);
1530 case BinaryOperator::LogicalAnd:
1531 case BinaryOperator::LogicalOr:
1532 case BinaryOperator::LogicalImplication:
1533 case BinaryOperator::LogicalEquivalence:
1534 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1536 case BinaryOperator::LogicalShiftLeft:
1537 return createBinary<moore::ShlOp>(lhs, rhs);
1538 case BinaryOperator::LogicalShiftRight:
1539 return createBinary<moore::ShrOp>(lhs, rhs);
1540 case BinaryOperator::ArithmeticShiftLeft:
1541 return createBinary<moore::ShlOp>(lhs, rhs);
1542 case BinaryOperator::ArithmeticShiftRight: {
1545 lhs =
context.convertToSimpleBitVector(lhs);
1546 rhs =
context.convertToSimpleBitVector(rhs);
1549 if (expr.type->isSigned())
1550 return moore::AShrOp::create(builder, loc, lhs, rhs);
1551 return moore::ShrOp::create(builder, loc, lhs, rhs);
1555 mlir::emitError(loc,
"unsupported binary operator");
1560 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1561 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1565 Value visit(
const slang::ast::IntegerLiteral &expr) {
1566 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1570 Value visit(
const slang::ast::TimeLiteral &expr) {
1575 double value = std::round(expr.getValue() * scale);
1585 static constexpr uint64_t limit =
1586 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1587 if (value > limit) {
1588 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1592 return moore::ConstantTimeOp::create(builder, loc,
1593 static_cast<uint64_t
>(value));
1597 Value visit(
const slang::ast::ReplicationExpression &expr) {
1598 auto type =
context.convertType(*expr.type);
1599 auto value =
context.convertRvalueExpression(expr.concat());
1602 return moore::ReplicateOp::create(builder, loc, type, value);
1606 Value visit(
const slang::ast::InsideExpression &expr) {
1607 auto lhs =
context.convertToSimpleBitVector(
1608 context.convertRvalueExpression(expr.left()));
1613 SmallVector<Value> conditions;
1616 for (
const auto *listExpr : expr.rangeList()) {
1617 auto cond =
context.convertInsideCheck(lhs, loc, *listExpr);
1621 conditions.push_back(cond);
1625 auto result = conditions.back();
1626 conditions.pop_back();
1627 while (!conditions.empty()) {
1628 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1629 conditions.pop_back();
1635 Value visit(
const slang::ast::ConditionalExpression &expr) {
1636 auto type =
context.convertType(*expr.type);
1639 if (expr.conditions.size() > 1) {
1640 mlir::emitError(loc)
1641 <<
"unsupported conditional expression with more than one condition";
1644 const auto &cond = expr.conditions[0];
1646 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1650 context.convertToBool(
context.convertRvalueExpression(*cond.expr));
1653 auto conditionalOp =
1654 moore::ConditionalOp::create(builder, loc, type, value);
1657 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1658 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1660 OpBuilder::InsertionGuard g(builder);
1663 builder.setInsertionPointToStart(&trueBlock);
1664 auto trueValue =
context.convertRvalueExpression(expr.left(), type);
1667 moore::YieldOp::create(builder, loc, trueValue);
1670 builder.setInsertionPointToStart(&falseBlock);
1671 auto falseValue =
context.convertRvalueExpression(expr.right(), type);
1674 moore::YieldOp::create(builder, loc, falseValue);
1676 return conditionalOp.getResult();
1680 Value visit(
const slang::ast::CallExpression &expr) {
1682 auto constant =
context.evaluateConstant(expr);
1683 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1687 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1693 std::pair<Value, moore::ClassHandleType>
1694 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1696 moore::ClassHandleType handleTy;
1700 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1701 thisRef =
context.convertRvalueExpression(*recvExpr);
1706 thisRef =
context.getImplicitThisRef();
1708 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1709 <<
"' called without an object";
1713 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1714 return {thisRef, handleTy};
1718 mlir::CallOpInterface
1719 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1721 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1722 SmallVector<Value> &arguments,
1723 SmallVector<Type> &resultTypes) {
1726 auto funcTy = cast<FunctionType>(lowering->
op.getFunctionType());
1727 auto expected0 = funcTy.getInput(0);
1728 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1731 auto implicitThisRef =
context.materializeConversion(
1732 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1735 SmallVector<Value> explicitArguments;
1736 explicitArguments.reserve(arguments.size() + 1);
1737 explicitArguments.push_back(implicitThisRef);
1738 explicitArguments.append(arguments.begin(), arguments.end());
1741 const bool isVirtual =
1742 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1745 auto calleeSym = lowering->
op.getNameAttr().getValue();
1746 if (isa<moore::CoroutineOp>(lowering->
op.getOperation()))
1747 return moore::CallCoroutineOp::create(builder, loc, resultTypes,
1748 calleeSym, explicitArguments);
1749 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1753 auto funcName = subroutine->name;
1754 auto method = moore::VTableLoadMethodOp::create(
1755 builder, loc, funcTy, actualThisRef,
1756 SymbolRefAttr::get(
context.getContext(), funcName));
1757 return mlir::func::CallIndirectOp::create(builder, loc, method,
1762 Value visitCall(
const slang::ast::CallExpression &expr,
1763 const slang::ast::SubroutineSymbol *subroutine) {
1765 const bool isMethod = (subroutine->thisVar !=
nullptr);
1767 auto *lowering =
context.declareFunction(*subroutine);
1771 if (isa<moore::DPIFuncOp>(lowering->
op.getOperation())) {
1772 SmallVector<Value> operands;
1773 SmallVector<Value> resultTargets;
1775 for (
auto [callArg, declArg] :
1776 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1777 auto *actual = callArg;
1778 if (
const auto *assign =
1779 actual->as_if<slang::ast::AssignmentExpression>())
1780 actual = &assign->left();
1782 auto argType =
context.convertType(declArg->getType());
1786 switch (declArg->direction) {
1787 case slang::ast::ArgumentDirection::In: {
1788 auto value =
context.convertRvalueExpression(*actual, argType);
1791 operands.push_back(value);
1794 case slang::ast::ArgumentDirection::Out: {
1795 auto lvalue =
context.convertLvalueExpression(*actual);
1798 resultTargets.push_back(lvalue);
1801 case slang::ast::ArgumentDirection::InOut:
1802 case slang::ast::ArgumentDirection::Ref: {
1803 auto lvalue =
context.convertLvalueExpression(*actual);
1806 auto value =
context.convertRvalueExpression(*actual, argType);
1809 operands.push_back(value);
1810 resultTargets.push_back(lvalue);
1816 SmallVector<Type> resultTypes(
1817 cast<FunctionType>(lowering->
op.getFunctionType()).getResults());
1818 auto callOp = moore::FuncDPICallOp::create(
1819 builder, loc, resultTypes,
1820 SymbolRefAttr::get(lowering->
op.getNameAttr()), operands);
1822 unsigned resultIndex = 0;
1823 unsigned targetIndex = 0;
1824 for (
const auto *declArg : subroutine->getArguments()) {
1825 auto argType =
context.convertType(declArg->getType());
1829 switch (declArg->direction) {
1830 case slang::ast::ArgumentDirection::Out:
1831 case slang::ast::ArgumentDirection::InOut:
1832 case slang::ast::ArgumentDirection::Ref: {
1833 auto lvalue = resultTargets[targetIndex++];
1834 auto refTy = dyn_cast<moore::RefType>(lvalue.getType());
1836 lowering->
op->emitError(
1837 "expected DPI output target to be moore::RefType");
1840 auto converted =
context.materializeConversion(
1841 refTy.getNestedType(), callOp->getResult(resultIndex++),
1842 declArg->getType().isSigned(), loc);
1845 moore::BlockingAssignOp::create(builder, loc, lvalue, converted);
1853 if (!subroutine->getReturnType().isVoid())
1854 return callOp->getResult(resultIndex);
1856 return mlir::UnrealizedConversionCastOp::create(
1857 builder, loc, moore::VoidType::get(
context.getContext()),
1865 SmallVector<Value> arguments;
1866 for (
auto [callArg, declArg] :
1867 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1871 auto *expr = callArg;
1872 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
1873 expr = &assign->left();
1876 auto type =
context.convertType(declArg->getType());
1877 if (declArg->direction == slang::ast::ArgumentDirection::In) {
1878 value =
context.convertRvalueExpression(*expr, type);
1880 Value lvalue =
context.convertLvalueExpression(*expr);
1881 auto unpackedType = dyn_cast<moore::UnpackedType>(type);
1885 context.materializeConversion(moore::RefType::get(unpackedType),
1886 lvalue, expr->type->isSigned(), loc);
1890 arguments.push_back(value);
1897 for (
auto *sym : lowering->capturedSymbols) {
1898 Value val =
context.valueSymbols.lookup(sym);
1900 mlir::emitError(loc) <<
"failed to resolve captured variable `"
1901 << sym->name <<
"` at call site";
1904 arguments.push_back(val);
1908 SmallVector<Type> resultTypes(
1909 cast<FunctionType>(lowering->
op.getFunctionType()).getResults().begin(),
1910 cast<FunctionType>(lowering->
op.getFunctionType()).getResults().end());
1912 mlir::CallOpInterface callOp;
1916 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
1917 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
1918 arguments, resultTypes);
1919 }
else if (isa<moore::CoroutineOp>(lowering->
op.getOperation())) {
1921 auto coroutine = cast<moore::CoroutineOp>(lowering->
op.getOperation());
1923 moore::CallCoroutineOp::create(builder, loc, coroutine, arguments);
1926 auto funcOp = cast<mlir::func::FuncOp>(lowering->
op.getOperation());
1927 callOp = mlir::func::CallOp::create(builder, loc, funcOp, arguments);
1930 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
1934 if (resultTypes.size() == 0)
1935 return mlir::UnrealizedConversionCastOp::create(
1936 builder, loc, moore::VoidType::get(
context.getContext()),
1944 Value visitCall(
const slang::ast::CallExpression &expr,
1945 const slang::ast::CallExpression::SystemCallInfo &info) {
1946 using ksn = slang::parsing::KnownSystemName;
1947 const auto &subroutine = *
info.subroutine;
1948 auto nameId = subroutine.knownNameId;
1960 return context.convertAssertionCallExpression(expr, info, loc);
1965 auto args = expr.arguments();
1973 if (nameId == ksn::SFormatF) {
1975 auto fmtValue =
context.convertFormatString(
1976 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1977 if (failed(fmtValue))
1979 return fmtValue.value();
1983 auto result =
context.convertSystemCall(subroutine, loc, args);
1987 auto ty =
context.convertType(*expr.type);
1988 return context.materializeConversion(ty, result, expr.type->isSigned(),
1993 Value visit(
const slang::ast::StringLiteral &expr) {
1994 auto type =
context.convertType(*expr.type);
1995 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
1999 Value visit(
const slang::ast::RealLiteral &expr) {
2000 auto fTy = mlir::Float64Type::get(
context.getContext());
2001 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
2002 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
2007 FailureOr<SmallVector<Value>>
2008 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
2009 std::variant<Type, ArrayRef<Type>> expectedTypes,
2010 unsigned replCount) {
2011 const auto &elts = expr.elements();
2012 const size_t elementCount = elts.size();
2015 const bool hasBroadcast =
2016 std::holds_alternative<Type>(expectedTypes) &&
2017 static_cast<bool>(std::get<Type>(expectedTypes));
2019 const bool hasPerElem =
2020 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
2021 !std::get<ArrayRef<Type>>(expectedTypes).empty();
2025 auto types = std::get<ArrayRef<Type>>(expectedTypes);
2026 if (types.size() != elementCount) {
2027 mlir::emitError(loc)
2028 <<
"assignment pattern arity mismatch: expected " << types.size()
2029 <<
" elements, got " << elementCount;
2034 SmallVector<Value> converted;
2035 converted.reserve(elementCount * std::max(1u, replCount));
2038 if (!hasBroadcast && !hasPerElem) {
2040 for (
const auto *elementExpr : elts) {
2041 Value v =
context.convertRvalueExpression(*elementExpr);
2044 converted.push_back(v);
2046 }
else if (hasBroadcast) {
2048 Type want = std::get<Type>(expectedTypes);
2049 for (
const auto *elementExpr : elts) {
2050 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
2051 :
context.convertRvalueExpression(*elementExpr);
2054 converted.push_back(v);
2057 auto types = std::get<ArrayRef<Type>>(expectedTypes);
2058 for (
size_t i = 0; i < elementCount; ++i) {
2059 Type want = types[i];
2060 const auto *elementExpr = elts[i];
2061 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
2062 :
context.convertRvalueExpression(*elementExpr);
2065 converted.push_back(v);
2069 for (
unsigned i = 1; i < replCount; ++i)
2070 converted.append(converted.begin(), converted.begin() + elementCount);
2076 Value visitAssignmentPattern(
2077 const slang::ast::AssignmentPatternExpressionBase &expr,
2078 unsigned replCount = 1) {
2079 auto type =
context.convertType(*expr.type);
2080 const auto &elts = expr.elements();
2083 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2084 auto elements = convertElements(expr, {}, replCount);
2086 if (failed(elements))
2089 assert(intType.getWidth() == elements->size());
2090 std::reverse(elements->begin(), elements->end());
2091 return moore::ConcatOp::create(builder, loc, intType, *elements);
2095 if (
auto structType = dyn_cast<moore::StructType>(type)) {
2096 SmallVector<Type> expectedTy;
2097 expectedTy.reserve(structType.getMembers().size());
2098 for (
auto member : structType.getMembers())
2099 expectedTy.push_back(member.type);
2101 FailureOr<SmallVector<Value>> elements;
2102 if (expectedTy.size() == elts.size())
2103 elements = convertElements(expr, expectedTy, replCount);
2105 elements = convertElements(expr, {}, replCount);
2107 if (failed(elements))
2110 assert(structType.getMembers().size() == elements->size());
2111 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2115 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
2116 SmallVector<Type> expectedTy;
2117 expectedTy.reserve(structType.getMembers().size());
2118 for (
auto member : structType.getMembers())
2119 expectedTy.push_back(member.type);
2121 FailureOr<SmallVector<Value>> elements;
2122 if (expectedTy.size() == elts.size())
2123 elements = convertElements(expr, expectedTy, replCount);
2125 elements = convertElements(expr, {}, replCount);
2127 if (failed(elements))
2130 assert(structType.getMembers().size() == elements->size());
2132 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2136 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
2138 convertElements(expr, arrayType.getElementType(), replCount);
2140 if (failed(elements))
2143 assert(arrayType.getSize() == elements->size());
2144 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2148 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
2150 convertElements(expr, arrayType.getElementType(), replCount);
2152 if (failed(elements))
2155 assert(arrayType.getSize() == elements->size());
2156 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2159 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
2163 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
2164 return visitAssignmentPattern(expr);
2167 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
2168 return visitAssignmentPattern(expr);
2171 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
2173 context.evaluateConstant(expr.count()).integer().as<
unsigned>();
2174 assert(count &&
"Slang guarantees constant non-zero replication count");
2175 return visitAssignmentPattern(expr, *count);
2178 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2179 SmallVector<Value> operands;
2180 for (
auto stream : expr.streams()) {
2181 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2182 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2183 mlir::emitError(operandLoc)
2184 <<
"Moore only support streaming "
2185 "concatenation with fixed size 'with expression'";
2189 if (stream.constantWithWidth.has_value()) {
2190 value =
context.convertRvalueExpression(*stream.withExpr);
2191 auto type = cast<moore::UnpackedType>(value.getType());
2192 auto intType = moore::IntType::get(
2193 context.getContext(), type.getBitSize().value(), type.getDomain());
2195 value =
context.materializeConversion(intType, value,
false, loc);
2197 value =
context.convertRvalueExpression(*stream.operand);
2200 value =
context.convertToSimpleBitVector(value);
2203 operands.push_back(value);
2207 if (operands.size() == 1) {
2210 value = operands.front();
2212 value = moore::ConcatOp::create(builder, loc, operands).getResult();
2215 if (expr.getSliceSize() == 0) {
2219 auto type = cast<moore::IntType>(value.getType());
2220 SmallVector<Value> slicedOperands;
2221 auto iterMax = type.getWidth() / expr.getSliceSize();
2222 auto remainSize = type.getWidth() % expr.getSliceSize();
2224 for (
size_t i = 0; i < iterMax; i++) {
2225 auto extractResultType = moore::IntType::get(
2226 context.getContext(), expr.getSliceSize(), type.getDomain());
2228 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
2229 value, i * expr.getSliceSize());
2230 slicedOperands.push_back(extracted);
2234 auto extractResultType = moore::IntType::get(
2235 context.getContext(), remainSize, type.getDomain());
2238 moore::ExtractOp::create(builder, loc, extractResultType, value,
2239 iterMax * expr.getSliceSize());
2240 slicedOperands.push_back(extracted);
2243 return moore::ConcatOp::create(builder, loc, slicedOperands);
2246 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
2247 return context.convertAssertionExpression(expr.body, loc);
2250 Value visit(
const slang::ast::UnboundedLiteral &expr) {
2252 "slang checks $ only used within queue index expression");
2256 moore::QueueSizeBIOp::create(builder, loc,
context.getIndexedQueue());
2257 auto one = moore::ConstantOp::create(builder, loc, queueSize.getType(), 1);
2258 auto lastElement = moore::SubOp::create(builder, loc, queueSize, one);
2275 Value visit(
const slang::ast::NewClassExpression &expr) {
2276 auto type =
context.convertType(*expr.type);
2277 auto classTy = dyn_cast<moore::ClassHandleType>(type);
2283 if (!classTy && expr.isSuperClass) {
2284 newObj =
context.getImplicitThisRef();
2285 if (!newObj || !newObj.getType() ||
2286 !isa<moore::ClassHandleType>(newObj.getType())) {
2287 mlir::emitError(loc) <<
"implicit this ref was not set while "
2288 "converting new class function";
2291 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
2293 cast<moore::ClassDeclOp>(*
context.symbolTable.lookupNearestSymbolFrom(
2294 context.intoModuleOp, thisType.getClassSym()));
2295 auto baseClassSym = classDecl.getBase();
2296 classTy = circt::moore::ClassHandleType::get(
context.getContext(),
2297 baseClassSym.value());
2300 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
2303 const auto *constructor = expr.constructorCall();
2308 if (
const auto *callConstructor =
2309 constructor->as_if<slang::ast::CallExpression>())
2310 if (
const auto *subroutine =
2311 std::get_if<const slang::ast::SubroutineSymbol *>(
2312 &callConstructor->subroutine)) {
2313 if (!(*subroutine)->thisVar) {
2314 mlir::emitError(loc)
2315 <<
"unsupported constructor call without `this` argument";
2319 llvm::SaveAndRestore saveThis(
context.currentThisRef, newObj);
2320 if (!visitCall(*callConstructor, *subroutine))
2328 template <
typename T>
2329 Value visit(T &&node) {
2330 mlir::emitError(loc,
"unsupported expression: ")
2331 << slang::ast::toString(node.kind);
2335 Value visitInvalid(
const slang::ast::Expression &expr) {
2336 mlir::emitError(loc,
"invalid expression");
2347struct LvalueExprVisitor :
public ExprVisitor {
2349 : ExprVisitor(
context, loc, true) {}
2350 using ExprVisitor::visit;
2353 Value visit(
const slang::ast::NamedValueExpression &expr) {
2355 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2359 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2360 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2362 if (
auto *
const property =
2363 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
2367 if (
auto access =
context.virtualIfaceMembers.lookup(&expr.symbol);
2369 auto type =
context.convertType(*expr.type);
2372 auto memberType = dyn_cast<moore::UnpackedType>(type);
2374 mlir::emitError(loc)
2375 <<
"unsupported virtual interface member type: " << type;
2379 Value base = materializeSymbolRvalue(*access.base);
2381 auto d = mlir::emitError(loc,
"unknown name `")
2382 << access.base->name <<
"`";
2383 d.attachNote(
context.convertLocation(access.base->location))
2384 <<
"no rvalue generated for virtual interface base";
2388 auto fieldName = access.fieldName
2390 : builder.getStringAttr(expr.symbol.name);
2391 auto memberRefType = moore::RefType::get(memberType);
2392 return moore::StructExtractOp::create(builder, loc, memberRefType,
2396 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
2397 d.attachNote(
context.convertLocation(expr.symbol.location))
2398 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2403 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
2405 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2412 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2413 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2417 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
2418 << expr.symbol.name <<
"`";
2419 d.attachNote(
context.convertLocation(expr.symbol.location))
2420 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2424 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2425 SmallVector<Value> operands;
2426 for (
auto stream : expr.streams()) {
2427 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2428 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2429 mlir::emitError(operandLoc)
2430 <<
"Moore only support streaming "
2431 "concatenation with fixed size 'with expression'";
2435 if (stream.constantWithWidth.has_value()) {
2436 value =
context.convertLvalueExpression(*stream.withExpr);
2437 auto type = cast<moore::UnpackedType>(
2438 cast<moore::RefType>(value.getType()).getNestedType());
2439 auto intType = moore::RefType::get(moore::IntType::get(
2440 context.getContext(), type.getBitSize().value(), type.getDomain()));
2442 value =
context.materializeConversion(intType, value,
false, loc);
2444 value =
context.convertLvalueExpression(*stream.operand);
2449 operands.push_back(value);
2452 if (operands.size() == 1) {
2455 value = operands.front();
2457 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
2460 if (expr.getSliceSize() == 0) {
2464 auto type = cast<moore::IntType>(
2465 cast<moore::RefType>(value.getType()).getNestedType());
2466 SmallVector<Value> slicedOperands;
2467 auto widthSum = type.getWidth();
2468 auto domain = type.getDomain();
2469 auto iterMax = widthSum / expr.getSliceSize();
2470 auto remainSize = widthSum % expr.getSliceSize();
2472 for (
size_t i = 0; i < iterMax; i++) {
2473 auto extractResultType = moore::RefType::get(moore::IntType::get(
2474 context.getContext(), expr.getSliceSize(), domain));
2476 auto extracted = moore::ExtractRefOp::create(
2477 builder, loc, extractResultType, value, i * expr.getSliceSize());
2478 slicedOperands.push_back(extracted);
2482 auto extractResultType = moore::RefType::get(
2483 moore::IntType::get(
context.getContext(), remainSize, domain));
2486 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
2487 iterMax * expr.getSliceSize());
2488 slicedOperands.push_back(extracted);
2491 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
2495 template <
typename T>
2496 Value visit(T &&node) {
2497 return context.convertRvalueExpression(node);
2500 Value visitInvalid(
const slang::ast::Expression &expr) {
2501 mlir::emitError(loc,
"invalid expression");
2511Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
2512 Type requiredType) {
2514 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
2515 if (value && requiredType)
2523 return expr.visit(LvalueExprVisitor(*
this, loc));
2531 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
2532 if (type.getBitSize() == 1)
2534 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
2535 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
2536 mlir::emitError(value.getLoc(),
"expression of type ")
2537 << value.getType() <<
" cannot be cast to a boolean";
2543 const slang::ast::Type &astType,
2545 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2549 if (svreal.isShortReal() &&
2550 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2551 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2552 }
else if (svreal.isReal() &&
2553 floatType->floatKind == slang::ast::FloatingType::Real) {
2554 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2556 mlir::emitError(loc) <<
"invalid real constant";
2560 return moore::ConstantRealOp::create(
builder, loc, attr);
2565 const slang::ast::Type &astType,
2567 slang::ConstantValue intVal = stringLiteral.convertToInt();
2568 auto effectiveWidth = intVal.getEffectiveWidth();
2569 if (!effectiveWidth)
2572 auto intTy = moore::IntType::getInt(
getContext(), effectiveWidth.value());
2574 if (astType.isString()) {
2575 auto immInt = moore::ConstantStringOp::create(
builder, loc, intTy,
2576 stringLiteral.toString())
2578 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2585 const slang::ast::Type &astType, Location loc) {
2590 bool typeIsFourValued =
false;
2591 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2595 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2596 fvint.hasUnknown() || typeIsFourValued
2599 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2604 const slang::ConstantValue &constant,
2605 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2613 if (astType.elementType.isIntegral())
2614 bitWidth = astType.elementType.getBitWidth();
2618 bool typeIsFourValued =
false;
2621 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2632 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2634 auto arrType = moore::UnpackedArrayType::get(
2635 getContext(), constant.elements().size(), intType);
2637 llvm::SmallVector<mlir::Value> elemVals;
2638 moore::ConstantOp constOp;
2640 mlir::OpBuilder::InsertionGuard guard(
builder);
2643 for (
auto elem : constant.elements()) {
2645 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2646 elemVals.push_back(constOp.getResult());
2651 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2653 return arrayOp.getResult();
2657 const slang::ast::Type &type, Location loc) {
2659 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
2661 if (constant.isInteger())
2663 if (constant.isReal() || constant.isShortReal())
2665 if (constant.isString())
2673 using slang::ast::EvalFlags;
2674 slang::ast::EvalContext evalContext(
2676 slang::ast::LookupLocation::max),
2677 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
2678 return expr.eval(evalContext);
2687 auto type = moore::IntType::get(
getContext(), 1, domain);
2694 if (isa<moore::IntType>(value.getType()))
2701 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
2702 if (
auto sbvType = packed.getSimpleBitVector())
2705 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
2706 <<
" cannot be cast to a simple bit vector";
2715 if (isa<moore::IntType>(value.getType()))
2718 auto &builder =
context.builder;
2719 auto packedType = cast<moore::PackedType>(value.getType());
2720 auto intType = packedType.getSimpleBitVector();
2725 if (isa<moore::TimeType>(packedType) &&
2727 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
2728 auto scale = moore::ConstantOp::create(builder, loc, intType,
2730 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
2736 if (packedType.containsTimeType()) {
2737 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
2738 <<
" cannot be converted to " << intType
2739 <<
"; contains a time type";
2744 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
2752 Value value, Location loc) {
2753 if (value.getType() == packedType)
2756 auto &builder =
context.builder;
2757 auto intType = cast<moore::IntType>(value.getType());
2762 if (isa<moore::TimeType>(packedType) &&
2764 auto scale = moore::ConstantOp::create(builder, loc, intType,
2766 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
2767 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
2774 mlir::emitError(loc) <<
"unsupported conversion: " << intType
2775 <<
" cannot be converted to " << packedType
2776 <<
"; contains a time type";
2781 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
2787 moore::ClassHandleType expectedHandleTy) {
2788 auto loc = actualHandle.getLoc();
2790 auto actualTy = actualHandle.getType();
2791 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
2792 if (!actualHandleTy) {
2793 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
2799 if (actualHandleTy == expectedHandleTy)
2800 return actualHandle;
2802 if (!
context.isClassDerivedFrom(actualHandleTy, expectedHandleTy)) {
2803 mlir::emitError(loc)
2804 <<
"receiver class " << actualHandleTy.getClassSym()
2805 <<
" is not the same as, or derived from, expected base class "
2806 << expectedHandleTy.getClassSym().getRootReference();
2811 auto casted = moore::ClassUpcastOp::create(
context.builder, loc,
2812 expectedHandleTy, actualHandle)
2820 if (type == value.getType())
2825 auto dstPacked = dyn_cast<moore::PackedType>(type);
2826 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
2827 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
2828 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
2830 if (dstInt && srcInt) {
2838 auto resizedType = moore::IntType::get(
2839 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
2840 if (dstInt.getWidth() < srcInt.getWidth()) {
2841 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
2842 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
2844 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
2846 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
2850 if (dstInt.getDomain() != srcInt.getDomain()) {
2852 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
2854 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
2862 assert(value.getType() == type);
2867 if (isa<moore::StringType>(type) &&
2868 isa<moore::FormatStringType>(value.getType())) {
2869 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
2873 if (isa<moore::FormatStringType>(type) &&
2874 isa<moore::StringType>(value.getType())) {
2875 return builder.createOrFold<moore::FormatStringOp>(loc, value);
2880 if (isa<moore::QueueType>(type) && isa<moore::QueueType>(value.getType()) &&
2881 cast<moore::QueueType>(type).getElementType() ==
2882 cast<moore::QueueType>(value.getType()).getElementType())
2883 return builder.createOrFold<moore::QueueResizeOp>(loc, type, value);
2886 if (isa<moore::QueueType>(type) &&
2887 isa<moore::UnpackedArrayType>(value.getType())) {
2888 auto queueElType = dyn_cast<moore::QueueType>(type).getElementType();
2889 auto unpackedArrayElType =
2890 dyn_cast<moore::UnpackedArrayType>(value.getType()).getElementType();
2892 if (queueElType == unpackedArrayElType) {
2893 return builder.createOrFold<moore::QueueFromUnpackedArrayOp>(loc, type,
2899 if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2900 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
2901 loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2909 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
2912 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
2917 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
2921 return builder.createOrFold<moore::SIntToRealOp>(loc, type, twoValInt);
2922 return builder.createOrFold<moore::UIntToRealOp>(loc, type, twoValInt);
2925 auto getBuiltinFloatType = [&](moore::RealType type) -> Type {
2927 return mlir::Float32Type::get(
builder.getContext());
2929 return mlir::Float64Type::get(
builder.getContext());
2933 if (isa<moore::TimeType>(type) && isa<moore::RealType>(value.getType())) {
2935 moore::IntType::get(
builder.getContext(), 64, Domain::TwoValued);
2937 getBuiltinFloatType(cast<moore::RealType>(value.getType()));
2938 auto scale = moore::ConstantRealOp::create(
2939 builder, loc, value.getType(),
2941 auto scaled =
builder.createOrFold<moore::MulRealOp>(loc, value, scale);
2942 auto asInt = moore::RealToIntOp::create(
builder, loc, intType, scaled);
2943 auto asLogic = moore::IntToLogicOp::create(
builder, loc, asInt);
2944 return moore::LogicToTimeOp::create(
builder, loc, asLogic);
2948 if (isa<moore::RealType>(type) && isa<moore::TimeType>(value.getType())) {
2949 auto asLogic = moore::TimeToLogicOp::create(
builder, loc, value);
2950 auto asInt = moore::LogicToIntOp::create(
builder, loc, asLogic);
2951 auto asReal = moore::UIntToRealOp::create(
builder, loc, type, asInt);
2952 Type floatType = getBuiltinFloatType(cast<moore::RealType>(type));
2953 auto scale = moore::ConstantRealOp::create(
2956 return moore::DivRealOp::create(
builder, loc, asReal, scale);
2960 if (isa<moore::StringType>(type)) {
2961 if (
auto intType = dyn_cast<moore::IntType>(value.getType())) {
2963 value = moore::LogicToIntOp::create(
builder, loc, value);
2964 return moore::IntToStringOp::create(
builder, loc, value);
2969 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2970 if (isa<moore::StringType>(value.getType())) {
2971 value = moore::StringToIntOp::create(
builder, loc, intType.getTwoValued(),
2975 return moore::IntToLogicOp::create(
builder, loc, value);
2982 if (isa<moore::FormatStringType>(type)) {
2984 value, isSigned, loc);
2987 return moore::FormatStringOp::create(
builder, loc, asStr, {}, {}, {});
2990 if (isa<moore::RealType>(type) && isa<moore::RealType>(value.getType()))
2991 return builder.createOrFold<moore::ConvertRealOp>(loc, type, value);
2993 if (isa<moore::ClassHandleType>(type) &&
2994 isa<moore::ClassHandleType>(value.getType()))
2998 if (value.getType() != type)
2999 value = moore::ConversionOp::create(
builder, loc, type, value);
3005template <
typename OpTy>
3008 std::span<const slang::ast::Expression *const> args) {
3010 assert(args.size() == 1 &&
"real math builtin expects 1 argument");
3011 auto value =
context.convertRvalueExpression(*args[0]);
3014 return OpTy::create(
context.builder, loc, value);
3018 const slang::ast::SystemSubroutine &subroutine, Location loc,
3019 std::span<const slang::ast::Expression *const> args) {
3020 using ksn = slang::parsing::KnownSystemName;
3021 StringRef name = subroutine.name;
3022 auto nameId = subroutine.knownNameId;
3023 size_t numArgs = args.size();
3031 if (nameId == ksn::URandom || nameId == ksn::Random) {
3032 auto i32Ty = moore::IntType::getInt(
builder.getContext(), 32);
3033 auto minval = moore::ConstantOp::create(
builder, loc, i32Ty, 0);
3035 moore::ConstantOp::create(
builder, loc, i32Ty, APInt::getAllOnes(32));
3042 return moore::UrandomRangeBIOp::create(
builder, loc, minval, maxval, seed);
3045 if (nameId == ksn::URandomRange) {
3046 auto i32Ty = moore::IntType::getInt(
builder.getContext(), 32);
3056 minval = moore::ConstantOp::create(
builder, loc, i32Ty, 0);
3058 return moore::UrandomRangeBIOp::create(
builder, loc, minval, maxval,
3066 if (nameId == ksn::Time || nameId == ksn::STime || nameId == ksn::RealTime) {
3068 assert(numArgs == 0 &&
"time functions take no arguments");
3069 return moore::TimeBIOp::create(
builder, loc);
3076 if (nameId == ksn::Clog2) {
3078 assert(numArgs == 1 &&
"`$clog2` takes 1 argument");
3085 return moore::Clog2BIOp::create(
builder, loc, value);
3089 if (nameId == ksn::Ln)
3090 return convertRealMathBI<moore::LnBIOp>(*
this, loc, name, args);
3091 if (nameId == ksn::Log10)
3092 return convertRealMathBI<moore::Log10BIOp>(*
this, loc, name, args);
3093 if (nameId == ksn::Exp)
3094 return convertRealMathBI<moore::ExpBIOp>(*
this, loc, name, args);
3095 if (nameId == ksn::Sqrt)
3096 return convertRealMathBI<moore::SqrtBIOp>(*
this, loc, name, args);
3097 if (nameId == ksn::Floor)
3098 return convertRealMathBI<moore::FloorBIOp>(*
this, loc, name, args);
3099 if (nameId == ksn::Ceil)
3100 return convertRealMathBI<moore::CeilBIOp>(*
this, loc, name, args);
3101 if (nameId == ksn::Sin)
3102 return convertRealMathBI<moore::SinBIOp>(*
this, loc, name, args);
3103 if (nameId == ksn::Cos)
3104 return convertRealMathBI<moore::CosBIOp>(*
this, loc, name, args);
3105 if (nameId == ksn::Tan)
3106 return convertRealMathBI<moore::TanBIOp>(*
this, loc, name, args);
3107 if (nameId == ksn::Asin)
3108 return convertRealMathBI<moore::AsinBIOp>(*
this, loc, name, args);
3109 if (nameId == ksn::Acos)
3110 return convertRealMathBI<moore::AcosBIOp>(*
this, loc, name, args);
3111 if (nameId == ksn::Atan)
3112 return convertRealMathBI<moore::AtanBIOp>(*
this, loc, name, args);
3113 if (nameId == ksn::Sinh)
3114 return convertRealMathBI<moore::SinhBIOp>(*
this, loc, name, args);
3115 if (nameId == ksn::Cosh)
3116 return convertRealMathBI<moore::CoshBIOp>(*
this, loc, name, args);
3117 if (nameId == ksn::Tanh)
3118 return convertRealMathBI<moore::TanhBIOp>(*
this, loc, name, args);
3119 if (nameId == ksn::Asinh)
3120 return convertRealMathBI<moore::AsinhBIOp>(*
this, loc, name, args);
3121 if (nameId == ksn::Acosh)
3122 return convertRealMathBI<moore::AcoshBIOp>(*
this, loc, name, args);
3123 if (nameId == ksn::Atanh)
3124 return convertRealMathBI<moore::AtanhBIOp>(*
this, loc, name, args);
3130 if (nameId == ksn::Signed || nameId == ksn::Unsigned) {
3132 assert(numArgs == 1 &&
"`$signed`/`$unsigned` take 1 argument");
3138 if (nameId == ksn::RealToBits)
3139 return convertRealMathBI<moore::RealtobitsBIOp>(*
this, loc, name, args);
3140 if (nameId == ksn::BitsToReal)
3141 return convertRealMathBI<moore::BitstorealBIOp>(*
this, loc, name, args);
3142 if (nameId == ksn::ShortrealToBits)
3143 return convertRealMathBI<moore::ShortrealtobitsBIOp>(*
this, loc, name,
3145 if (nameId == ksn::BitsToShortreal)
3146 return convertRealMathBI<moore::BitstoshortrealBIOp>(*
this, loc, name,
3153 if (nameId == ksn::Len) {
3155 assert(numArgs == 1 &&
"`len` takes 1 argument");
3156 auto stringType = moore::StringType::get(
getContext());
3160 return moore::StringLenOp::create(
builder, loc, value);
3163 if (nameId == ksn::ToUpper) {
3165 assert(numArgs == 1 &&
"`toupper` takes 1 argument");
3166 auto stringType = moore::StringType::get(
getContext());
3170 return moore::StringToUpperOp::create(
builder, loc, value);
3173 if (nameId == ksn::ToLower) {
3175 assert(numArgs == 1 &&
"`tolower` takes 1 argument");
3176 auto stringType = moore::StringType::get(
getContext());
3180 return moore::StringToLowerOp::create(
builder, loc, value);
3183 if (nameId == ksn::Getc) {
3185 assert(numArgs == 2 &&
"`getc` takes 2 arguments");
3186 auto stringType = moore::StringType::get(
getContext());
3191 return moore::StringGetOp::create(
builder, loc, str, index);
3198 if (nameId == ksn::ArraySize) {
3200 assert(numArgs == 1 &&
"`size` takes 1 argument");
3201 if (args[0]->type->isQueue()) {
3205 return moore::QueueSizeBIOp::create(
builder, loc, value);
3207 if (args[0]->type->getCanonicalType().kind ==
3208 slang::ast::SymbolKind::DynamicArrayType) {
3212 return moore::OpenUArraySizeOp::create(
builder, loc, value);
3214 if (args[0]->type->isAssociativeArray()) {
3218 return moore::AssocArraySizeOp::create(
builder, loc, value);
3220 emitError(loc) <<
"unsupported member function `size` on type `"
3221 << args[0]->type->toString() <<
"`";
3225 if (nameId == ksn::Delete) {
3227 assert(numArgs == 1 &&
"`delete` takes 1 argument");
3228 if (args[0]->type->getCanonicalType().kind ==
3229 slang::ast::SymbolKind::DynamicArrayType) {
3233 return moore::OpenUArrayDeleteOp::create(
builder, loc, value);
3235 emitError(loc) <<
"unsupported member function `delete` on type `"
3236 << args[0]->type->toString() <<
"`";
3240 if (nameId == ksn::PopBack) {
3242 assert(numArgs == 1 &&
"`pop_back` takes 1 argument");
3243 assert(args[0]->type->isQueue() &&
"`pop_back` is only valid on queues");
3247 return moore::QueuePopBackOp::create(
builder, loc, value);
3250 if (nameId == ksn::PopFront) {
3252 assert(numArgs == 1 &&
"`pop_front` takes 1 argument");
3253 assert(args[0]->type->isQueue() &&
"`pop_front` is only valid on queues");
3257 return moore::QueuePopFrontOp::create(
builder, loc, value);
3264 if (nameId == ksn::Num) {
3265 if (args[0]->type->isAssociativeArray()) {
3266 assert(numArgs == 1 &&
"`num` takes 1 argument");
3270 return moore::AssocArraySizeOp::create(
builder, loc, value);
3272 emitError(loc) <<
"unsupported system call `" << name <<
"`";
3276 if (nameId == ksn::Exists) {
3278 assert(numArgs == 2 &&
"`exists` takes 2 arguments");
3279 assert(args[0]->type->isAssociativeArray() &&
3280 "`exists` is only valid on associative arrays");
3285 return moore::AssocArrayExistsOp::create(
builder, loc, array, key);
3292 if (nameId == ksn::First || nameId == ksn::Last || nameId == ksn::Next ||
3293 nameId == ksn::Prev) {
3294 if (args[0]->type->isAssociativeArray()) {
3295 assert(numArgs == 2 &&
"traversal methods take 2 arguments");
3300 if (nameId == ksn::First)
3301 return moore::AssocArrayFirstOp::create(
builder, loc, array, key);
3302 if (nameId == ksn::Last)
3303 return moore::AssocArrayLastOp::create(
builder, loc, array, key);
3304 if (nameId == ksn::Next)
3305 return moore::AssocArrayNextOp::create(
builder, loc, array, key);
3306 if (nameId == ksn::Prev)
3307 return moore::AssocArrayPrevOp::create(
builder, loc, array, key);
3308 llvm_unreachable(
"all traversal cases handled above");
3310 emitError(loc) <<
"unsupported system call `" << name <<
"`";
3315 emitError(loc) <<
"unsupported system call `" << name <<
"`";
3321 return context.symbolTable.lookupNearestSymbolFrom(
context.intoModuleOp, sym);
3325 const moore::ClassHandleType &baseTy) {
3326 if (!actualTy || !baseTy)
3329 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
3330 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
3332 if (actualSym == baseSym)
3335 auto *op =
resolve(*
this, actualSym);
3336 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
3339 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
3342 if (curBase == baseSym)
3344 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
3349moore::ClassHandleType
3351 llvm::StringRef fieldName, Location loc) {
3353 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
3357 auto *op =
resolve(*
this, classSym);
3358 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
3363 for (
auto &block : decl.getBody()) {
3364 for (
auto &opInBlock : block) {
3366 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
3367 if (prop.getSymName() == fieldName) {
3369 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
3376 classSym = decl.getBaseAttr();
3380 mlir::emitError(loc) <<
"unknown property `" << fieldName <<
"`";
3389 const slang::ast::Expression &expr) {
3392 if (
const auto *valueRange = expr.as_if<slang::ast::ValueRangeExpression>()) {
3397 if (!insideLhs || !lowBound || !highBound)
3400 Value rangeLhs, rangeRhs;
3403 if (valueRange->left().type->isSigned() ||
3404 insideLhs.getType().isSignedInteger()) {
3405 rangeLhs = moore::SgeOp::create(
builder, loc, insideLhs, lowBound);
3407 rangeLhs = moore::UgeOp::create(
builder, loc, insideLhs, lowBound);
3410 if (valueRange->right().type->isSigned() ||
3411 insideLhs.getType().isSignedInteger()) {
3412 rangeRhs = moore::SleOp::create(
builder, loc, insideLhs, highBound);
3414 rangeRhs = moore::UleOp::create(
builder, loc, insideLhs, highBound);
3417 return moore::AndOp::create(
builder, loc, rangeLhs, rangeRhs);
3421 if (!expr.type->isIntegral()) {
3422 if (expr.type->isUnpackedArray()) {
3423 mlir::emitError(loc,
3424 "unpacked arrays in 'inside' expressions not supported");
3428 loc,
"only simple bit vectors supported in 'inside' expressions");
3435 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 materializeSBVToPackedConversion(Context &context, moore::PackedType packedType, Value value, Location loc)
Create the necessary operations to convert from a simple bit vector IntType to an equivalent PackedTy...
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 Value visitClassProperty(Context &context, const slang::ast::ClassPropertySymbol &expr)
static uint64_t getTimeScaleInFemtoseconds(Context &context)
Get the currently active timescale as an integer number of femtoseconds.
static Value materializePackedToSBVConversion(Context &context, Value value, Location loc)
Create the necessary operations to convert from a PackedType to the corresponding simple bit vector I...
static 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.
static FVInt convertSVIntToFVInt(const slang::SVInt &svint)
Convert a Slang SVInt to a CIRCT FVInt.
Four-valued arbitrary precision integers.
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.
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")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
Value materializeConversion(Type type, Value value, bool isSigned, Location loc)
Helper function to insert the necessary operations to cast a value from one type to another.
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.
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
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 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.
Value currentQueue
Variable that tracks the queue which we are currently converting the index expression for.
MLIRContext * getContext()
Return the MLIR context.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Function lowering information.
mlir::FunctionOpInterface op