11#include "mlir/IR/Operation.h"
12#include "mlir/IR/Value.h"
13#include "slang/ast/EvalContext.h"
14#include "slang/ast/SystemSubroutine.h"
15#include "slang/ast/types/AllTypes.h"
16#include "slang/syntax/AllSyntax.h"
17#include "llvm/ADT/ScopeExit.h"
20using namespace ImportVerilog;
25 if (svint.hasUnknown()) {
26 unsigned numWords = svint.getNumWords() / 2;
27 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
28 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
29 return FVInt(APInt(svint.getBitWidth(), value),
30 APInt(svint.getBitWidth(), unknown));
32 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
33 return FVInt(APInt(svint.getBitWidth(), value));
40 const slang::ConstantRange &range) {
41 auto &builder =
context.builder;
42 auto indexType = cast<moore::UnpackedType>(index.getType());
45 auto lo = range.lower();
46 auto hi = range.upper();
47 auto offset = range.isLittleEndian() ? lo : hi;
50 const bool needSigned = (lo < 0) || (hi < 0);
53 const uint64_t maxAbs = std::max<uint64_t>(std::abs(lo), std::abs(hi));
58 unsigned want = needSigned
59 ? (llvm::Log2_64_Ceil(std::max<uint64_t>(1, maxAbs)) + 1)
60 : std::max<unsigned>(1, llvm::Log2_64_Ceil(maxAbs + 1));
63 const unsigned bw = std::max<unsigned>(want, indexType.getBitSize().value());
66 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
67 index =
context.materializeConversion(intType, index, needSigned, loc);
70 if (range.isLittleEndian())
73 return moore::NegOp::create(builder, loc, index);
77 moore::ConstantOp::create(builder, loc, intType, offset, needSigned);
78 if (range.isLittleEndian())
79 return moore::SubOp::create(builder, loc, index, offsetConst);
81 return moore::SubOp::create(builder, loc, offsetConst, index);
86 static_assert(int(slang::TimeUnit::Seconds) == 0);
87 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
88 static_assert(int(slang::TimeUnit::Microseconds) == 2);
89 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
90 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
91 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
93 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
94 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
95 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
97 auto exp =
static_cast<unsigned>(
context.timeScale.base.unit);
100 auto scale =
static_cast<uint64_t
>(
context.timeScale.base.magnitude);
107 const slang::ast::ClassPropertySymbol &expr) {
108 auto loc =
context.convertLocation(expr.location);
109 auto builder =
context.builder;
110 auto type =
context.convertType(expr.getType());
111 auto fieldTy = cast<moore::UnpackedType>(type);
112 auto fieldRefTy = moore::RefType::get(fieldTy);
114 if (expr.lifetime == slang::ast::VariableLifetime::Static) {
117 if (!
context.globalVariables.lookup(&expr)) {
118 if (failed(
context.convertGlobalVariable(expr))) {
123 if (
auto globalOp =
context.globalVariables.lookup(&expr))
124 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
126 mlir::emitError(loc) <<
"Failed to access static member variable "
127 << expr.name <<
" as a global variable";
132 mlir::Value instRef =
context.getImplicitThisRef();
134 mlir::emitError(loc) <<
"class property '" << expr.name
135 <<
"' referenced without an implicit 'this'";
139 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.name);
141 moore::ClassHandleType classTy =
142 cast<moore::ClassHandleType>(instRef.getType());
144 auto targetClassHandle =
145 context.getAncestorClassWithProperty(classTy, expr.name, loc);
146 if (!targetClassHandle)
149 auto upcastRef =
context.materializeConversion(targetClassHandle, instRef,
150 false, instRef.getLoc());
154 Value fieldRef = moore::ClassPropertyRefOp::create(builder, loc, fieldRefTy,
155 upcastRef, fieldSym);
167 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
168 : context(context), loc(loc), builder(context.builder),
169 isLvalue(isLvalue) {}
175 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
183 Value materializeSymbolRvalue(
const slang::ast::ValueSymbol &sym) {
185 if (isa<moore::RefType>(value.getType())) {
186 auto readOp = moore::ReadOp::create(builder, loc, value);
189 return readOp.getResult();
195 auto ref = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
196 auto readOp = moore::ReadOp::create(builder, loc, ref);
199 return readOp.getResult();
202 if (
auto *
const property = sym.as_if<slang::ast::ClassPropertySymbol>()) {
204 auto readOp = moore::ReadOp::create(builder, loc, fieldRef);
207 return readOp.getResult();
213 Value visit(
const slang::ast::NewArrayExpression &expr) {
218 if (expr.initExpr()) {
220 <<
"unsupported expression: array `new` with initializer\n";
225 expr.sizeExpr(), context.
convertType(*expr.sizeExpr().type));
229 return moore::OpenUArrayCreateOp::create(builder, loc, type, initialSize);
233 Value visit(
const slang::ast::ElementSelectExpression &expr) {
235 auto value = convertLvalueOrRvalueExpression(expr.value());
240 auto derefType = value.getType();
242 derefType = cast<moore::RefType>(derefType).getNestedType();
244 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType,
245 moore::QueueType, moore::AssocArrayType, moore::StringType,
246 moore::OpenUnpackedArrayType>(derefType)) {
247 mlir::emitError(loc) <<
"unsupported expression: element select into "
248 << expr.value().type->toString() <<
"\n";
253 if (isa<moore::AssocArrayType>(derefType)) {
254 auto assocArray = cast<moore::AssocArrayType>(derefType);
255 auto expectedIndexType = assocArray.getIndexType();
261 if (givenIndex.getType() != expectedIndexType) {
263 <<
"Incorrect index type: expected index type of "
264 << expectedIndexType <<
" but was given " << givenIndex.getType();
268 return moore::AssocArrayExtractRefOp::create(
269 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
272 return moore::AssocArrayExtractOp::create(builder, loc, type, value,
277 if (isa<moore::StringType>(derefType)) {
279 mlir::emitError(loc) <<
"string index assignment not supported";
284 auto i32Type = moore::IntType::getInt(builder.getContext(), 32);
290 return moore::StringGetOp::create(builder, loc, value, index);
294 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
295 auto range = expr.value().type->getFixedRange();
296 if (
auto *constValue = expr.selector().getConstant();
297 constValue && constValue->isInteger()) {
298 assert(!constValue->hasUnknown());
299 assert(constValue->size() <= 32);
301 auto lowBit = constValue->integer().as<uint32_t>().value();
303 return llvm::TypeSwitch<Type, Value>(derefType)
304 .Case<moore::QueueType>([&](moore::QueueType) {
306 <<
"Unexpected LValue extract on Queue Type!";
310 return moore::ExtractRefOp::create(builder, loc, resultType,
312 range.translateIndex(lowBit));
315 return llvm::TypeSwitch<Type, Value>(derefType)
316 .Case<moore::QueueType>([&](moore::QueueType) {
318 <<
"Unexpected RValue extract on Queue Type!";
322 return moore::ExtractOp::create(builder, loc, resultType, value,
323 range.translateIndex(lowBit));
330 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
331 if (isa<moore::QueueType>(derefType)) {
334 if (isa<moore::RefType>(value.getType())) {
335 context.
currentQueue = moore::ReadOp::create(builder, loc, value);
346 return llvm::TypeSwitch<Type, Value>(derefType)
347 .Case<moore::QueueType>([&](moore::QueueType) {
348 return moore::DynQueueRefElementOp::create(builder, loc, resultType,
352 return moore::DynExtractRefOp::create(builder, loc, resultType,
357 return llvm::TypeSwitch<Type, Value>(derefType)
358 .Case<moore::QueueType>([&](moore::QueueType) {
359 return moore::DynQueueExtractOp::create(builder, loc, resultType,
360 value, lowBit, lowBit);
363 return moore::DynExtractOp::create(builder, loc, resultType, value,
370 Value visit(
const slang::ast::NullLiteral &expr) {
372 if (isa<moore::ClassHandleType, moore::ChandleType, moore::EventType,
373 moore::NullType>(type))
374 return moore::NullOp::create(builder, loc);
375 mlir::emitError(loc) <<
"No null value definition found for value of type "
381 Value visit(
const slang::ast::RangeSelectExpression &expr) {
383 auto value = convertLvalueOrRvalueExpression(expr.value());
387 auto derefType = value.getType();
389 derefType = cast<moore::RefType>(derefType).getNestedType();
391 if (isa<moore::QueueType>(derefType)) {
392 return handleQueueRangeSelectExpressions(expr, type, value);
394 return handleArrayRangeSelectExpressions(expr, type, value);
399 Value handleQueueRangeSelectExpressions(
400 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
402 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
408 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
411 mlir::emitError(loc) <<
"queue lvalue range selections are not supported";
414 return moore::DynQueueExtractOp::create(builder, loc, resultType, value,
420 Value handleArrayRangeSelectExpressions(
421 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
422 std::optional<int32_t> constLeft;
423 std::optional<int32_t> constRight;
424 if (
auto *constant = expr.left().getConstant())
425 constLeft = constant->integer().as<int32_t>();
426 if (
auto *constant = expr.right().getConstant())
427 constRight = constant->integer().as<int32_t>();
433 <<
"unsupported expression: range select with non-constant bounds";
453 int32_t offsetConst = 0;
454 auto range = expr.value().type->getFixedRange();
456 using slang::ast::RangeSelectionKind;
457 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
462 assert(constRight &&
"constness checked in slang");
463 offsetConst = *constRight;
474 offsetConst = *constLeft;
485 int32_t offsetAdd = 0;
490 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
491 range.isLittleEndian()) {
492 assert(constRight &&
"constness checked in slang");
493 offsetAdd = 1 - *constRight;
499 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
500 !range.isLittleEndian()) {
501 assert(constRight &&
"constness checked in slang");
502 offsetAdd = *constRight - 1;
506 if (offsetAdd != 0) {
508 offsetDyn = moore::AddOp::create(
509 builder, loc, offsetDyn,
510 moore::ConstantOp::create(
511 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
515 offsetConst += offsetAdd;
526 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
531 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
534 return moore::DynExtractOp::create(builder, loc, resultType, value,
538 offsetConst = range.translateIndex(offsetConst);
540 return moore::ExtractRefOp::create(builder, loc, resultType, value,
543 return moore::ExtractOp::create(builder, loc, resultType, value,
550 Value visit(
const slang::ast::ConcatenationExpression &expr) {
551 SmallVector<Value> operands;
552 if (expr.type->isString()) {
553 for (
auto *operand : expr.operands()) {
554 assert(!isLvalue &&
"checked by Slang");
555 auto value = convertLvalueOrRvalueExpression(*operand);
559 moore::StringType::get(context.
getContext()), value,
false,
563 operands.push_back(value);
565 return moore::StringConcatOp::create(builder, loc, operands);
567 if (expr.type->isQueue()) {
568 return handleQueueConcat(expr);
570 for (
auto *operand : expr.operands()) {
574 if (operand->type->isVoid())
576 auto value = convertLvalueOrRvalueExpression(*operand);
583 operands.push_back(value);
586 return moore::ConcatRefOp::create(builder, loc, operands);
588 return moore::ConcatOp::create(builder, loc, operands);
595 Value handleQueueConcat(
const slang::ast::ConcatenationExpression &expr) {
596 SmallVector<Value> operands;
599 cast<moore::QueueType>(context.
convertType(*expr.type, loc));
611 Value contigElements;
613 for (
auto *operand : expr.operands()) {
614 bool isSingleElement =
619 if (!isSingleElement && contigElements) {
620 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
624 assert(!isLvalue &&
"checked by Slang");
625 auto value = convertLvalueOrRvalueExpression(*operand);
633 moore::RefType::get(context.
getContext(), queueType);
635 if (!contigElements) {
637 moore::VariableOp::create(builder, loc, queueRefType, {}, {});
639 moore::QueuePushBackOp::create(builder, loc, contigElements, value);
647 if (!(isa<moore::QueueType>(value.getType()) &&
648 cast<moore::QueueType>(value.getType()).getElementType() ==
654 operands.push_back(value);
657 if (contigElements) {
658 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
661 return moore::QueueConcatOp::create(builder, loc, queueType, operands);
665 Value visit(
const slang::ast::MemberAccessExpression &expr) {
670 auto *valueType = expr.value().type.get();
671 auto memberName = builder.getStringAttr(expr.member.name);
677 if (valueType->isVirtualInterface()) {
678 auto memberType = dyn_cast<moore::UnpackedType>(type);
681 <<
"unsupported virtual interface member type: " << type;
684 auto resultRefType = moore::RefType::get(memberType);
692 auto memberRef = moore::StructExtractOp::create(
693 builder, loc, resultRefType, memberName, base);
696 return moore::ReadOp::create(builder, loc, memberRef);
700 if (valueType->isStruct()) {
702 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
704 auto value = convertLvalueOrRvalueExpression(expr.value());
709 return moore::StructExtractRefOp::create(builder, loc, resultType,
711 return moore::StructExtractOp::create(builder, loc, resultType,
716 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
718 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
720 auto value = convertLvalueOrRvalueExpression(expr.value());
725 return moore::UnionExtractRefOp::create(builder, loc, resultType,
727 return moore::UnionExtractOp::create(builder, loc, type, memberName,
732 if (valueType->isClass()) {
736 auto targetTy = cast<moore::ClassHandleType>(valTy);
748 if (expr.member.kind != slang::ast::SymbolKind::Parameter) {
754 moore::ClassHandleType upcastTargetTy =
768 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(),
770 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
774 Value fieldRef = moore::ClassPropertyRefOp::create(
775 builder, loc, fieldRefTy, baseVal, fieldSym);
778 return isLvalue ? fieldRef
779 : moore::ReadOp::create(builder, loc, fieldRef);
782 slang::ConstantValue constVal;
783 if (
auto param = expr.member.as_if<slang::ast::ParameterSymbol>()) {
784 constVal = param->getValue();
789 mlir::emitError(loc) <<
"Parameter " << expr.member.name
790 <<
" has no constant value";
794 mlir::emitError(loc,
"expression of type ")
795 << valueType->toString() <<
" has no member fields";
807struct RvalueExprVisitor :
public ExprVisitor {
809 : ExprVisitor(
context, loc, false) {}
810 using ExprVisitor::visit;
813 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
814 assert(!
context.lvalueStack.empty() &&
"parent assignments push lvalue");
815 auto lvalue =
context.lvalueStack.back();
816 return moore::ReadOp::create(builder, loc, lvalue);
820 Value visit(
const slang::ast::NamedValueExpression &expr) {
822 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
823 if (isa<moore::RefType>(value.getType())) {
824 auto readOp = moore::ReadOp::create(builder, loc, value);
825 if (
context.rvalueReadCallback)
826 context.rvalueReadCallback(readOp);
827 value = readOp.getResult();
833 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol)) {
834 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
835 return moore::ReadOp::create(builder, loc, value);
839 if (
auto *
const property =
840 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
842 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
849 if (
auto access =
context.virtualIfaceMembers.lookup(&expr.symbol);
851 auto type =
context.convertType(*expr.type);
854 auto memberType = dyn_cast<moore::UnpackedType>(type);
857 <<
"unsupported virtual interface member type: " << type;
861 Value base = materializeSymbolRvalue(*access.base);
863 auto d = mlir::emitError(loc,
"unknown name `")
864 << access.base->name <<
"`";
865 d.attachNote(
context.convertLocation(access.base->location))
866 <<
"no rvalue generated for virtual interface base";
870 auto fieldName = access.fieldName
872 : builder.getStringAttr(expr.symbol.name);
873 auto memberRefType = moore::RefType::get(memberType);
874 auto memberRef = moore::StructExtractOp::create(
875 builder, loc, memberRefType, fieldName, base);
876 auto readOp = moore::ReadOp::create(builder, loc, memberRef);
877 if (
context.rvalueReadCallback)
878 context.rvalueReadCallback(readOp);
879 return readOp.getResult();
883 auto constant =
context.evaluateConstant(expr);
884 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
889 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
890 d.attachNote(
context.convertLocation(expr.symbol.location))
891 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
896 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
897 auto hierLoc =
context.convertLocation(expr.symbol.location);
898 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
899 if (isa<moore::RefType>(value.getType())) {
900 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
901 if (
context.rvalueReadCallback)
902 context.rvalueReadCallback(readOp);
903 value = readOp.getResult();
910 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
911 << expr.symbol.name <<
"`";
912 d.attachNote(hierLoc) <<
"no rvalue generated for "
913 << slang::ast::toString(expr.symbol.kind);
919 Value visit(
const slang::ast::ArbitrarySymbolExpression &expr) {
920 const auto &canonTy = expr.type->getCanonicalType();
921 if (
const auto *vi = canonTy.as_if<slang::ast::VirtualInterfaceType>()) {
922 auto value =
context.materializeVirtualInterfaceValue(*vi, loc);
928 mlir::emitError(loc) <<
"unsupported arbitrary symbol expression of type "
929 << expr.type->toString();
934 Value visit(
const slang::ast::ConversionExpression &expr) {
935 auto type =
context.convertType(*expr.type);
938 return context.convertRvalueExpression(expr.operand(), type);
942 Value visit(
const slang::ast::AssignmentExpression &expr) {
943 auto lhs =
context.convertLvalueExpression(expr.left());
948 context.lvalueStack.push_back(lhs);
949 auto rhs =
context.convertRvalueExpression(
950 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
951 context.lvalueStack.pop_back();
958 if (!expr.isNonBlocking()) {
959 if (expr.timingControl)
960 if (failed(
context.convertTimingControl(*expr.timingControl)))
962 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
963 if (
context.variableAssignCallback)
964 context.variableAssignCallback(assignOp);
969 if (expr.timingControl) {
971 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
972 auto delay =
context.convertRvalueExpression(
973 ctrl->expr, moore::TimeType::get(builder.getContext()));
976 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
977 builder, loc, lhs, rhs, delay);
978 if (
context.variableAssignCallback)
979 context.variableAssignCallback(assignOp);
984 auto loc =
context.convertLocation(expr.timingControl->sourceRange);
986 <<
"unsupported non-blocking assignment timing control: "
987 << slang::ast::toString(expr.timingControl->kind);
990 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
991 if (
context.variableAssignCallback)
992 context.variableAssignCallback(assignOp);
998 template <
class ConcreteOp>
999 Value createReduction(Value arg,
bool invert) {
1000 arg =
context.convertToSimpleBitVector(arg);
1003 Value result = ConcreteOp::create(builder, loc, arg);
1005 result = moore::NotOp::create(builder, loc, result);
1010 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
1011 auto preValue = moore::ReadOp::create(builder, loc, arg);
1017 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
1020 auto one = moore::ConstantOp::create(
1021 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
1023 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
1024 : moore::SubOp::create(builder, loc, preValue, one).getResult();
1026 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
1027 if (
context.variableAssignCallback)
1028 context.variableAssignCallback(assignOp);
1037 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
1038 Value preValue = moore::ReadOp::create(builder, loc, arg);
1041 bool isTime = isa<moore::TimeType>(preValue.getType());
1043 preValue =
context.materializeConversion(
1044 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1045 preValue,
false, loc);
1047 moore::RealType realTy =
1048 llvm::dyn_cast<moore::RealType>(preValue.getType());
1053 if (realTy.getWidth() == moore::RealWidth::f32) {
1054 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
1055 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
1057 oneAttr = builder.getFloatAttr(builder.getF64Type(), oneVal);
1059 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
1062 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
1066 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
1067 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
1070 postValue =
context.materializeConversion(
1071 moore::TimeType::get(
context.getContext()), postValue,
false, loc);
1074 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
1076 if (
context.variableAssignCallback)
1077 context.variableAssignCallback(assignOp);
1084 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
1085 Type opFTy =
context.convertType(*expr.operand().type);
1087 using slang::ast::UnaryOperator;
1089 if (expr.op == UnaryOperator::Preincrement ||
1090 expr.op == UnaryOperator::Predecrement ||
1091 expr.op == UnaryOperator::Postincrement ||
1092 expr.op == UnaryOperator::Postdecrement)
1093 arg =
context.convertLvalueExpression(expr.operand());
1095 arg =
context.convertRvalueExpression(expr.operand(), opFTy);
1100 if (isa<moore::TimeType>(arg.getType()))
1101 arg =
context.materializeConversion(
1102 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1107 case UnaryOperator::Plus:
1109 case UnaryOperator::Minus:
1110 return moore::NegRealOp::create(builder, loc, arg);
1112 case UnaryOperator::Preincrement:
1113 return createRealIncrement(arg,
true,
false);
1114 case UnaryOperator::Predecrement:
1115 return createRealIncrement(arg,
false,
false);
1116 case UnaryOperator::Postincrement:
1117 return createRealIncrement(arg,
true,
true);
1118 case UnaryOperator::Postdecrement:
1119 return createRealIncrement(arg,
false,
true);
1121 case UnaryOperator::LogicalNot:
1122 arg =
context.convertToBool(arg);
1125 return moore::NotOp::create(builder, loc, arg);
1128 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
1129 <<
" not supported with real values!\n";
1135 Value visit(
const slang::ast::UnaryExpression &expr) {
1137 const auto *floatType =
1138 expr.operand().type->as_if<slang::ast::FloatingType>();
1141 return visitRealUOp(expr);
1143 using slang::ast::UnaryOperator;
1145 if (expr.op == UnaryOperator::Preincrement ||
1146 expr.op == UnaryOperator::Predecrement ||
1147 expr.op == UnaryOperator::Postincrement ||
1148 expr.op == UnaryOperator::Postdecrement)
1149 arg =
context.convertLvalueExpression(expr.operand());
1151 arg =
context.convertRvalueExpression(expr.operand());
1158 case UnaryOperator::Plus:
1159 return context.convertToSimpleBitVector(arg);
1161 case UnaryOperator::Minus:
1162 arg =
context.convertToSimpleBitVector(arg);
1165 return moore::NegOp::create(builder, loc, arg);
1167 case UnaryOperator::BitwiseNot:
1168 arg =
context.convertToSimpleBitVector(arg);
1171 return moore::NotOp::create(builder, loc, arg);
1173 case UnaryOperator::BitwiseAnd:
1174 return createReduction<moore::ReduceAndOp>(arg,
false);
1175 case UnaryOperator::BitwiseOr:
1176 return createReduction<moore::ReduceOrOp>(arg,
false);
1177 case UnaryOperator::BitwiseXor:
1178 return createReduction<moore::ReduceXorOp>(arg,
false);
1179 case UnaryOperator::BitwiseNand:
1180 return createReduction<moore::ReduceAndOp>(arg,
true);
1181 case UnaryOperator::BitwiseNor:
1182 return createReduction<moore::ReduceOrOp>(arg,
true);
1183 case UnaryOperator::BitwiseXnor:
1184 return createReduction<moore::ReduceXorOp>(arg,
true);
1186 case UnaryOperator::LogicalNot:
1187 arg =
context.convertToBool(arg);
1190 return moore::NotOp::create(builder, loc, arg);
1192 case UnaryOperator::Preincrement:
1193 return createIncrement(arg,
true,
false);
1194 case UnaryOperator::Predecrement:
1195 return createIncrement(arg,
false,
false);
1196 case UnaryOperator::Postincrement:
1197 return createIncrement(arg,
true,
true);
1198 case UnaryOperator::Postdecrement:
1199 return createIncrement(arg,
false,
true);
1202 mlir::emitError(loc,
"unsupported unary operator");
1207 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
1208 std::optional<Domain> domain = std::nullopt) {
1209 using slang::ast::BinaryOperator;
1213 lhs =
context.convertToBool(lhs, domain.value());
1214 rhs =
context.convertToBool(rhs, domain.value());
1216 lhs =
context.convertToBool(lhs);
1217 rhs =
context.convertToBool(rhs);
1224 case BinaryOperator::LogicalAnd:
1225 return moore::AndOp::create(builder, loc, lhs, rhs);
1227 case BinaryOperator::LogicalOr:
1228 return moore::OrOp::create(builder, loc, lhs, rhs);
1230 case BinaryOperator::LogicalImplication: {
1232 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1233 return moore::OrOp::create(builder, loc, notLHS, rhs);
1236 case BinaryOperator::LogicalEquivalence: {
1238 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1239 auto notRHS = moore::NotOp::create(builder, loc, rhs);
1240 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
1241 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
1242 return moore::OrOp::create(builder, loc, both, notBoth);
1246 llvm_unreachable(
"not a logical BinaryOperator");
1250 Value visitHandleBOp(
const slang::ast::BinaryExpression &expr) {
1252 auto lhs =
context.convertRvalueExpression(expr.left());
1255 auto rhs =
context.convertRvalueExpression(expr.right());
1259 using slang::ast::BinaryOperator;
1262 case BinaryOperator::Equality:
1263 return moore::HandleEqOp::create(builder, loc, lhs, rhs);
1264 case BinaryOperator::Inequality:
1265 return moore::HandleNeOp::create(builder, loc, lhs, rhs);
1266 case BinaryOperator::CaseEquality:
1267 return moore::HandleCaseEqOp::create(builder, loc, lhs, rhs);
1268 case BinaryOperator::CaseInequality:
1269 return moore::HandleCaseNeOp::create(builder, loc, lhs, rhs);
1272 mlir::emitError(loc)
1273 <<
"Binary operator " << slang::ast::toString(expr.op)
1274 <<
" not supported with class handle valued operands!\n";
1279 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
1281 auto lhs =
context.convertRvalueExpression(expr.left());
1284 auto rhs =
context.convertRvalueExpression(expr.right());
1288 if (isa<moore::TimeType>(lhs.getType()) ||
1289 isa<moore::TimeType>(rhs.getType())) {
1290 lhs =
context.materializeConversion(
1291 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1293 rhs =
context.materializeConversion(
1294 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1298 using slang::ast::BinaryOperator;
1300 case BinaryOperator::Add:
1301 return moore::AddRealOp::create(builder, loc, lhs, rhs);
1302 case BinaryOperator::Subtract:
1303 return moore::SubRealOp::create(builder, loc, lhs, rhs);
1304 case BinaryOperator::Multiply:
1305 return moore::MulRealOp::create(builder, loc, lhs, rhs);
1306 case BinaryOperator::Divide:
1307 return moore::DivRealOp::create(builder, loc, lhs, rhs);
1308 case BinaryOperator::Power:
1309 return moore::PowRealOp::create(builder, loc, lhs, rhs);
1311 case BinaryOperator::Equality:
1312 return moore::EqRealOp::create(builder, loc, lhs, rhs);
1313 case BinaryOperator::Inequality:
1314 return moore::NeRealOp::create(builder, loc, lhs, rhs);
1316 case BinaryOperator::GreaterThan:
1317 return moore::FgtOp::create(builder, loc, lhs, rhs);
1318 case BinaryOperator::LessThan:
1319 return moore::FltOp::create(builder, loc, lhs, rhs);
1320 case BinaryOperator::GreaterThanEqual:
1321 return moore::FgeOp::create(builder, loc, lhs, rhs);
1322 case BinaryOperator::LessThanEqual:
1323 return moore::FleOp::create(builder, loc, lhs, rhs);
1325 case BinaryOperator::LogicalAnd:
1326 case BinaryOperator::LogicalOr:
1327 case BinaryOperator::LogicalImplication:
1328 case BinaryOperator::LogicalEquivalence:
1329 return buildLogicalBOp(expr.op, lhs, rhs);
1332 mlir::emitError(loc) <<
"Binary operator "
1333 << slang::ast::toString(expr.op)
1334 <<
" not supported with real valued operands!\n";
1341 template <
class ConcreteOp>
1342 Value createBinary(Value lhs, Value rhs) {
1343 lhs =
context.convertToSimpleBitVector(lhs);
1346 rhs =
context.convertToSimpleBitVector(rhs);
1349 return ConcreteOp::create(builder, loc, lhs, rhs);
1353 Value visit(
const slang::ast::BinaryExpression &expr) {
1355 const auto *rhsFloatType =
1356 expr.right().type->as_if<slang::ast::FloatingType>();
1357 const auto *lhsFloatType =
1358 expr.left().type->as_if<slang::ast::FloatingType>();
1361 if (rhsFloatType || lhsFloatType)
1362 return visitRealBOp(expr);
1365 const auto rhsIsClass = expr.right().type->isClass();
1366 const auto lhsIsClass = expr.left().type->isClass();
1367 const auto rhsIsChandle = expr.right().type->isCHandle();
1368 const auto lhsIsChandle = expr.left().type->isCHandle();
1370 if (rhsIsClass || lhsIsClass || rhsIsChandle || lhsIsChandle)
1371 return visitHandleBOp(expr);
1373 auto lhs =
context.convertRvalueExpression(expr.left());
1376 auto rhs =
context.convertRvalueExpression(expr.right());
1381 Domain domain = Domain::TwoValued;
1382 if (expr.type->isFourState() || expr.left().type->isFourState() ||
1383 expr.right().type->isFourState())
1384 domain = Domain::FourValued;
1386 using slang::ast::BinaryOperator;
1388 case BinaryOperator::Add:
1389 return createBinary<moore::AddOp>(lhs, rhs);
1390 case BinaryOperator::Subtract:
1391 return createBinary<moore::SubOp>(lhs, rhs);
1392 case BinaryOperator::Multiply:
1393 return createBinary<moore::MulOp>(lhs, rhs);
1394 case BinaryOperator::Divide:
1395 if (expr.type->isSigned())
1396 return createBinary<moore::DivSOp>(lhs, rhs);
1398 return createBinary<moore::DivUOp>(lhs, rhs);
1399 case BinaryOperator::Mod:
1400 if (expr.type->isSigned())
1401 return createBinary<moore::ModSOp>(lhs, rhs);
1403 return createBinary<moore::ModUOp>(lhs, rhs);
1404 case BinaryOperator::Power: {
1409 auto rhsCast =
context.materializeConversion(
1410 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
1411 if (expr.type->isSigned())
1412 return createBinary<moore::PowSOp>(lhs, rhsCast);
1414 return createBinary<moore::PowUOp>(lhs, rhsCast);
1417 case BinaryOperator::BinaryAnd:
1418 return createBinary<moore::AndOp>(lhs, rhs);
1419 case BinaryOperator::BinaryOr:
1420 return createBinary<moore::OrOp>(lhs, rhs);
1421 case BinaryOperator::BinaryXor:
1422 return createBinary<moore::XorOp>(lhs, rhs);
1423 case BinaryOperator::BinaryXnor: {
1424 auto result = createBinary<moore::XorOp>(lhs, rhs);
1427 return moore::NotOp::create(builder, loc, result);
1430 case BinaryOperator::Equality:
1431 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1432 return moore::UArrayCmpOp::create(
1433 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1434 else if (isa<moore::StringType>(lhs.getType()))
1435 return moore::StringCmpOp::create(
1436 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
1437 else if (isa<moore::QueueType>(lhs.getType()))
1438 return moore::QueueCmpOp::create(
1439 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1441 return createBinary<moore::EqOp>(lhs, rhs);
1442 case BinaryOperator::Inequality:
1443 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1444 return moore::UArrayCmpOp::create(
1445 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1446 else if (isa<moore::StringType>(lhs.getType()))
1447 return moore::StringCmpOp::create(
1448 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
1449 else if (isa<moore::QueueType>(lhs.getType()))
1450 return moore::QueueCmpOp::create(
1451 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1453 return createBinary<moore::NeOp>(lhs, rhs);
1454 case BinaryOperator::CaseEquality:
1455 return createBinary<moore::CaseEqOp>(lhs, rhs);
1456 case BinaryOperator::CaseInequality:
1457 return createBinary<moore::CaseNeOp>(lhs, rhs);
1458 case BinaryOperator::WildcardEquality:
1459 return createBinary<moore::WildcardEqOp>(lhs, rhs);
1460 case BinaryOperator::WildcardInequality:
1461 return createBinary<moore::WildcardNeOp>(lhs, rhs);
1463 case BinaryOperator::GreaterThanEqual:
1464 if (expr.left().type->isSigned())
1465 return createBinary<moore::SgeOp>(lhs, rhs);
1466 else if (isa<moore::StringType>(lhs.getType()))
1467 return moore::StringCmpOp::create(
1468 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
1470 return createBinary<moore::UgeOp>(lhs, rhs);
1471 case BinaryOperator::GreaterThan:
1472 if (expr.left().type->isSigned())
1473 return createBinary<moore::SgtOp>(lhs, rhs);
1474 else if (isa<moore::StringType>(lhs.getType()))
1475 return moore::StringCmpOp::create(
1476 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
1478 return createBinary<moore::UgtOp>(lhs, rhs);
1479 case BinaryOperator::LessThanEqual:
1480 if (expr.left().type->isSigned())
1481 return createBinary<moore::SleOp>(lhs, rhs);
1482 else if (isa<moore::StringType>(lhs.getType()))
1483 return moore::StringCmpOp::create(
1484 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1486 return createBinary<moore::UleOp>(lhs, rhs);
1487 case BinaryOperator::LessThan:
1488 if (expr.left().type->isSigned())
1489 return createBinary<moore::SltOp>(lhs, rhs);
1490 else if (isa<moore::StringType>(lhs.getType()))
1491 return moore::StringCmpOp::create(
1492 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1494 return createBinary<moore::UltOp>(lhs, rhs);
1496 case BinaryOperator::LogicalAnd:
1497 case BinaryOperator::LogicalOr:
1498 case BinaryOperator::LogicalImplication:
1499 case BinaryOperator::LogicalEquivalence:
1500 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1502 case BinaryOperator::LogicalShiftLeft:
1503 return createBinary<moore::ShlOp>(lhs, rhs);
1504 case BinaryOperator::LogicalShiftRight:
1505 return createBinary<moore::ShrOp>(lhs, rhs);
1506 case BinaryOperator::ArithmeticShiftLeft:
1507 return createBinary<moore::ShlOp>(lhs, rhs);
1508 case BinaryOperator::ArithmeticShiftRight: {
1511 lhs =
context.convertToSimpleBitVector(lhs);
1512 rhs =
context.convertToSimpleBitVector(rhs);
1515 if (expr.type->isSigned())
1516 return moore::AShrOp::create(builder, loc, lhs, rhs);
1517 return moore::ShrOp::create(builder, loc, lhs, rhs);
1521 mlir::emitError(loc,
"unsupported binary operator");
1526 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1527 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1531 Value visit(
const slang::ast::IntegerLiteral &expr) {
1532 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1536 Value visit(
const slang::ast::TimeLiteral &expr) {
1541 double value = std::round(expr.getValue() * scale);
1551 static constexpr uint64_t limit =
1552 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1553 if (value > limit) {
1554 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1558 return moore::ConstantTimeOp::create(builder, loc,
1559 static_cast<uint64_t
>(value));
1563 Value visit(
const slang::ast::ReplicationExpression &expr) {
1564 auto type =
context.convertType(*expr.type);
1565 auto value =
context.convertRvalueExpression(expr.concat());
1568 return moore::ReplicateOp::create(builder, loc, type, value);
1572 Value visit(
const slang::ast::InsideExpression &expr) {
1573 auto lhs =
context.convertToSimpleBitVector(
1574 context.convertRvalueExpression(expr.left()));
1578 SmallVector<Value> conditions;
1581 for (
const auto *listExpr : expr.rangeList()) {
1585 if (
const auto *openRange =
1586 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
1588 auto lowBound =
context.convertToSimpleBitVector(
1589 context.convertRvalueExpression(openRange->left()));
1590 auto highBound =
context.convertToSimpleBitVector(
1591 context.convertRvalueExpression(openRange->right()));
1592 if (!lowBound || !highBound)
1594 Value leftValue, rightValue;
1597 if (openRange->left().type->isSigned() ||
1598 expr.left().type->isSigned()) {
1599 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
1601 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
1603 if (openRange->right().type->isSigned() ||
1604 expr.left().type->isSigned()) {
1605 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
1607 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
1609 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
1612 if (!listExpr->type->isIntegral()) {
1613 if (listExpr->type->isUnpackedArray()) {
1615 loc,
"unpacked arrays in 'inside' expressions not supported");
1619 loc,
"only simple bit vectors supported in 'inside' expressions");
1623 auto value =
context.convertToSimpleBitVector(
1624 context.convertRvalueExpression(*listExpr));
1627 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
1629 conditions.push_back(cond);
1633 auto result = conditions.back();
1634 conditions.pop_back();
1635 while (!conditions.empty()) {
1636 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1637 conditions.pop_back();
1643 Value visit(
const slang::ast::ConditionalExpression &expr) {
1644 auto type =
context.convertType(*expr.type);
1647 if (expr.conditions.size() > 1) {
1648 mlir::emitError(loc)
1649 <<
"unsupported conditional expression with more than one condition";
1652 const auto &cond = expr.conditions[0];
1654 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1658 context.convertToBool(
context.convertRvalueExpression(*cond.expr));
1661 auto conditionalOp =
1662 moore::ConditionalOp::create(builder, loc, type, value);
1665 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1666 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1668 OpBuilder::InsertionGuard g(builder);
1671 builder.setInsertionPointToStart(&trueBlock);
1672 auto trueValue =
context.convertRvalueExpression(expr.left(), type);
1675 moore::YieldOp::create(builder, loc, trueValue);
1678 builder.setInsertionPointToStart(&falseBlock);
1679 auto falseValue =
context.convertRvalueExpression(expr.right(), type);
1682 moore::YieldOp::create(builder, loc, falseValue);
1684 return conditionalOp.getResult();
1688 Value visit(
const slang::ast::CallExpression &expr) {
1690 auto constant =
context.evaluateConstant(expr);
1691 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1695 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1701 std::pair<Value, moore::ClassHandleType>
1702 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1704 moore::ClassHandleType handleTy;
1708 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1709 thisRef =
context.convertRvalueExpression(*recvExpr);
1714 thisRef =
context.getImplicitThisRef();
1716 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1717 <<
"' called without an object";
1721 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1722 return {thisRef, handleTy};
1726 mlir::CallOpInterface
1727 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1729 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1730 SmallVector<Value> &arguments,
1731 SmallVector<Type> &resultTypes) {
1734 auto funcTy = cast<FunctionType>(lowering->
op.getFunctionType());
1735 auto expected0 = funcTy.getInput(0);
1736 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1739 auto implicitThisRef =
context.materializeConversion(
1740 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1743 SmallVector<Value> explicitArguments;
1744 explicitArguments.reserve(arguments.size() + 1);
1745 explicitArguments.push_back(implicitThisRef);
1746 explicitArguments.append(arguments.begin(), arguments.end());
1749 const bool isVirtual =
1750 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1753 auto calleeSym = lowering->
op.getName();
1755 return moore::CallCoroutineOp::create(builder, loc, resultTypes,
1756 calleeSym, explicitArguments);
1757 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1761 auto funcName = subroutine->name;
1762 auto method = moore::VTableLoadMethodOp::create(
1763 builder, loc, funcTy, actualThisRef,
1764 SymbolRefAttr::get(
context.getContext(), funcName));
1765 return mlir::func::CallIndirectOp::create(builder, loc, method,
1770 Value visitCall(
const slang::ast::CallExpression &expr,
1771 const slang::ast::SubroutineSymbol *subroutine) {
1773 const bool isMethod = (subroutine->thisVar !=
nullptr);
1775 auto *lowering =
context.declareFunction(*subroutine);
1778 auto convertedFunction =
context.convertFunction(*subroutine);
1779 if (failed(convertedFunction))
1785 SmallVector<Value> arguments;
1786 for (
auto [callArg, declArg] :
1787 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1791 auto *expr = callArg;
1792 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
1793 expr = &assign->left();
1796 auto type =
context.convertType(declArg->getType());
1797 if (declArg->direction == slang::ast::ArgumentDirection::In) {
1798 value =
context.convertRvalueExpression(*expr, type);
1800 Value lvalue =
context.convertLvalueExpression(*expr);
1801 auto unpackedType = dyn_cast<moore::UnpackedType>(type);
1805 context.materializeConversion(moore::RefType::get(unpackedType),
1806 lvalue, expr->type->isSigned(), loc);
1810 arguments.push_back(value);
1814 auto materializeCaptureAtCall = [&](Value cap) -> Value {
1816 auto refTy = dyn_cast<moore::RefType>(cap.getType());
1818 lowering->
op.emitError(
1819 "expected captured value to be moore::RefType");
1826 Region *capRegion = [&]() -> Region * {
1827 if (
auto ba = dyn_cast<BlockArgument>(cap))
1828 return ba.getOwner()->getParent();
1829 if (
auto *def = cap.getDefiningOp())
1830 return def->getParentRegion();
1834 Region *callRegion =
1835 builder.getBlock() ? builder.getBlock()->getParent() :
nullptr;
1837 for (Region *r = callRegion; r; r = r->getParentRegion()) {
1838 if (r == capRegion) {
1845 lowering->
op.emitError()
1846 <<
"cannot materialize captured ref at call site; non-symbol "
1848 << (cap.getDefiningOp()
1849 ? cap.getDefiningOp()->getName().getStringRef()
1854 for (Value cap : lowering->captures) {
1855 Value mat = materializeCaptureAtCall(cap);
1858 arguments.push_back(mat);
1863 SmallVector<Type> resultTypes(
1864 cast<FunctionType>(lowering->
op.getFunctionType()).getResults().begin(),
1865 cast<FunctionType>(lowering->
op.getFunctionType()).getResults().end());
1867 mlir::CallOpInterface callOp;
1871 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
1872 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
1873 arguments, resultTypes);
1876 auto coroutine = cast<moore::CoroutineOp>(lowering->
op);
1878 moore::CallCoroutineOp::create(builder, loc, coroutine, arguments);
1881 auto funcOp = cast<mlir::func::FuncOp>(lowering->
op);
1882 callOp = mlir::func::CallOp::create(builder, loc, funcOp, arguments);
1885 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
1889 if (resultTypes.size() == 0)
1890 return mlir::UnrealizedConversionCastOp::create(
1891 builder, loc, moore::VoidType::get(
context.getContext()),
1899 Value visitCall(
const slang::ast::CallExpression &expr,
1900 const slang::ast::CallExpression::SystemCallInfo &info) {
1901 using ksn = slang::parsing::KnownSystemName;
1902 const auto &subroutine = *
info.subroutine;
1903 auto nameId = subroutine.knownNameId;
1915 return context.convertAssertionCallExpression(expr, info, loc);
1920 auto args = expr.arguments();
1928 if (nameId == ksn::SFormatF) {
1930 auto fmtValue =
context.convertFormatString(
1931 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1932 if (failed(fmtValue))
1934 return fmtValue.value();
1938 auto result =
context.convertSystemCall(subroutine, loc, args);
1942 auto ty =
context.convertType(*expr.type);
1943 return context.materializeConversion(ty, result, expr.type->isSigned(),
1948 Value visit(
const slang::ast::StringLiteral &expr) {
1949 auto type =
context.convertType(*expr.type);
1950 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
1954 Value visit(
const slang::ast::RealLiteral &expr) {
1955 auto fTy = mlir::Float64Type::get(
context.getContext());
1956 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
1957 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
1962 FailureOr<SmallVector<Value>>
1963 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
1964 std::variant<Type, ArrayRef<Type>> expectedTypes,
1965 unsigned replCount) {
1966 const auto &elts = expr.elements();
1967 const size_t elementCount = elts.size();
1970 const bool hasBroadcast =
1971 std::holds_alternative<Type>(expectedTypes) &&
1972 static_cast<bool>(std::get<Type>(expectedTypes));
1974 const bool hasPerElem =
1975 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
1976 !std::get<ArrayRef<Type>>(expectedTypes).empty();
1980 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1981 if (types.size() != elementCount) {
1982 mlir::emitError(loc)
1983 <<
"assignment pattern arity mismatch: expected " << types.size()
1984 <<
" elements, got " << elementCount;
1989 SmallVector<Value> converted;
1990 converted.reserve(elementCount * std::max(1u, replCount));
1993 if (!hasBroadcast && !hasPerElem) {
1995 for (
const auto *elementExpr : elts) {
1996 Value v =
context.convertRvalueExpression(*elementExpr);
1999 converted.push_back(v);
2001 }
else if (hasBroadcast) {
2003 Type want = std::get<Type>(expectedTypes);
2004 for (
const auto *elementExpr : elts) {
2005 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
2006 :
context.convertRvalueExpression(*elementExpr);
2009 converted.push_back(v);
2012 auto types = std::get<ArrayRef<Type>>(expectedTypes);
2013 for (
size_t i = 0; i < elementCount; ++i) {
2014 Type want = types[i];
2015 const auto *elementExpr = elts[i];
2016 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
2017 :
context.convertRvalueExpression(*elementExpr);
2020 converted.push_back(v);
2024 for (
unsigned i = 1; i < replCount; ++i)
2025 converted.append(converted.begin(), converted.begin() + elementCount);
2031 Value visitAssignmentPattern(
2032 const slang::ast::AssignmentPatternExpressionBase &expr,
2033 unsigned replCount = 1) {
2034 auto type =
context.convertType(*expr.type);
2035 const auto &elts = expr.elements();
2038 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2039 auto elements = convertElements(expr, {}, replCount);
2041 if (failed(elements))
2044 assert(intType.getWidth() == elements->size());
2045 std::reverse(elements->begin(), elements->end());
2046 return moore::ConcatOp::create(builder, loc, intType, *elements);
2050 if (
auto structType = dyn_cast<moore::StructType>(type)) {
2051 SmallVector<Type> expectedTy;
2052 expectedTy.reserve(structType.getMembers().size());
2053 for (
auto member : structType.getMembers())
2054 expectedTy.push_back(member.type);
2056 FailureOr<SmallVector<Value>> elements;
2057 if (expectedTy.size() == elts.size())
2058 elements = convertElements(expr, expectedTy, replCount);
2060 elements = convertElements(expr, {}, replCount);
2062 if (failed(elements))
2065 assert(structType.getMembers().size() == elements->size());
2066 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2070 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
2071 SmallVector<Type> expectedTy;
2072 expectedTy.reserve(structType.getMembers().size());
2073 for (
auto member : structType.getMembers())
2074 expectedTy.push_back(member.type);
2076 FailureOr<SmallVector<Value>> elements;
2077 if (expectedTy.size() == elts.size())
2078 elements = convertElements(expr, expectedTy, replCount);
2080 elements = convertElements(expr, {}, replCount);
2082 if (failed(elements))
2085 assert(structType.getMembers().size() == elements->size());
2087 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2091 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
2093 convertElements(expr, arrayType.getElementType(), replCount);
2095 if (failed(elements))
2098 assert(arrayType.getSize() == elements->size());
2099 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2103 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
2105 convertElements(expr, arrayType.getElementType(), replCount);
2107 if (failed(elements))
2110 assert(arrayType.getSize() == elements->size());
2111 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2114 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
2118 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
2119 return visitAssignmentPattern(expr);
2122 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
2123 return visitAssignmentPattern(expr);
2126 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
2128 context.evaluateConstant(expr.count()).integer().as<
unsigned>();
2129 assert(count &&
"Slang guarantees constant non-zero replication count");
2130 return visitAssignmentPattern(expr, *count);
2133 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2134 SmallVector<Value> operands;
2135 for (
auto stream : expr.streams()) {
2136 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2137 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2138 mlir::emitError(operandLoc)
2139 <<
"Moore only support streaming "
2140 "concatenation with fixed size 'with expression'";
2144 if (stream.constantWithWidth.has_value()) {
2145 value =
context.convertRvalueExpression(*stream.withExpr);
2146 auto type = cast<moore::UnpackedType>(value.getType());
2147 auto intType = moore::IntType::get(
2148 context.getContext(), type.getBitSize().value(), type.getDomain());
2150 value =
context.materializeConversion(intType, value,
false, loc);
2152 value =
context.convertRvalueExpression(*stream.operand);
2155 value =
context.convertToSimpleBitVector(value);
2158 operands.push_back(value);
2162 if (operands.size() == 1) {
2165 value = operands.front();
2167 value = moore::ConcatOp::create(builder, loc, operands).getResult();
2170 if (expr.getSliceSize() == 0) {
2174 auto type = cast<moore::IntType>(value.getType());
2175 SmallVector<Value> slicedOperands;
2176 auto iterMax = type.getWidth() / expr.getSliceSize();
2177 auto remainSize = type.getWidth() % expr.getSliceSize();
2179 for (
size_t i = 0; i < iterMax; i++) {
2180 auto extractResultType = moore::IntType::get(
2181 context.getContext(), expr.getSliceSize(), type.getDomain());
2183 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
2184 value, i * expr.getSliceSize());
2185 slicedOperands.push_back(extracted);
2189 auto extractResultType = moore::IntType::get(
2190 context.getContext(), remainSize, type.getDomain());
2193 moore::ExtractOp::create(builder, loc, extractResultType, value,
2194 iterMax * expr.getSliceSize());
2195 slicedOperands.push_back(extracted);
2198 return moore::ConcatOp::create(builder, loc, slicedOperands);
2201 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
2202 return context.convertAssertionExpression(expr.body, loc);
2205 Value visit(
const slang::ast::UnboundedLiteral &expr) {
2207 "slang checks $ only used within queue index expression");
2211 moore::QueueSizeBIOp::create(builder, loc,
context.getIndexedQueue());
2212 auto one = moore::ConstantOp::create(builder, loc, queueSize.getType(), 1);
2213 auto lastElement = moore::SubOp::create(builder, loc, queueSize, one);
2230 Value visit(
const slang::ast::NewClassExpression &expr) {
2231 auto type =
context.convertType(*expr.type);
2232 auto classTy = dyn_cast<moore::ClassHandleType>(type);
2238 if (!classTy && expr.isSuperClass) {
2239 newObj =
context.getImplicitThisRef();
2240 if (!newObj || !newObj.getType() ||
2241 !isa<moore::ClassHandleType>(newObj.getType())) {
2242 mlir::emitError(loc) <<
"implicit this ref was not set while "
2243 "converting new class function";
2246 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
2248 cast<moore::ClassDeclOp>(*
context.symbolTable.lookupNearestSymbolFrom(
2249 context.intoModuleOp, thisType.getClassSym()));
2250 auto baseClassSym = classDecl.getBase();
2251 classTy = circt::moore::ClassHandleType::get(
context.getContext(),
2252 baseClassSym.value());
2255 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
2258 const auto *constructor = expr.constructorCall();
2263 if (
const auto *callConstructor =
2264 constructor->as_if<slang::ast::CallExpression>())
2265 if (
const auto *subroutine =
2266 std::get_if<const slang::ast::SubroutineSymbol *>(
2267 &callConstructor->subroutine)) {
2270 if (!(*subroutine)->thisVar) {
2271 mlir::emitError(loc) <<
"Expected subroutine called by new to use an "
2272 "implicit this reference";
2275 if (failed(
context.convertFunction(**subroutine)))
2278 auto savedThis =
context.currentThisRef;
2279 context.currentThisRef = newObj;
2280 llvm::scope_exit restoreThis(
2281 [&] {
context.currentThisRef = savedThis; });
2283 if (!visitCall(*callConstructor, *subroutine))
2292 template <
typename T>
2293 Value visit(T &&node) {
2294 mlir::emitError(loc,
"unsupported expression: ")
2295 << slang::ast::toString(node.kind);
2299 Value visitInvalid(
const slang::ast::Expression &expr) {
2300 mlir::emitError(loc,
"invalid expression");
2311struct LvalueExprVisitor :
public ExprVisitor {
2313 : ExprVisitor(
context, loc, true) {}
2314 using ExprVisitor::visit;
2317 Value visit(
const slang::ast::NamedValueExpression &expr) {
2319 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2323 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2324 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2326 if (
auto *
const property =
2327 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
2331 if (
auto access =
context.virtualIfaceMembers.lookup(&expr.symbol);
2333 auto type =
context.convertType(*expr.type);
2336 auto memberType = dyn_cast<moore::UnpackedType>(type);
2338 mlir::emitError(loc)
2339 <<
"unsupported virtual interface member type: " << type;
2343 Value base = materializeSymbolRvalue(*access.base);
2345 auto d = mlir::emitError(loc,
"unknown name `")
2346 << access.base->name <<
"`";
2347 d.attachNote(
context.convertLocation(access.base->location))
2348 <<
"no rvalue generated for virtual interface base";
2352 auto fieldName = access.fieldName
2354 : builder.getStringAttr(expr.symbol.name);
2355 auto memberRefType = moore::RefType::get(memberType);
2356 return moore::StructExtractOp::create(builder, loc, memberRefType,
2360 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
2361 d.attachNote(
context.convertLocation(expr.symbol.location))
2362 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2367 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
2369 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2373 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2374 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2378 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
2379 << expr.symbol.name <<
"`";
2380 d.attachNote(
context.convertLocation(expr.symbol.location))
2381 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2385 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2386 SmallVector<Value> operands;
2387 for (
auto stream : expr.streams()) {
2388 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2389 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2390 mlir::emitError(operandLoc)
2391 <<
"Moore only support streaming "
2392 "concatenation with fixed size 'with expression'";
2396 if (stream.constantWithWidth.has_value()) {
2397 value =
context.convertLvalueExpression(*stream.withExpr);
2398 auto type = cast<moore::UnpackedType>(
2399 cast<moore::RefType>(value.getType()).getNestedType());
2400 auto intType = moore::RefType::get(moore::IntType::get(
2401 context.getContext(), type.getBitSize().value(), type.getDomain()));
2403 value =
context.materializeConversion(intType, value,
false, loc);
2405 value =
context.convertLvalueExpression(*stream.operand);
2410 operands.push_back(value);
2413 if (operands.size() == 1) {
2416 value = operands.front();
2418 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
2421 if (expr.getSliceSize() == 0) {
2425 auto type = cast<moore::IntType>(
2426 cast<moore::RefType>(value.getType()).getNestedType());
2427 SmallVector<Value> slicedOperands;
2428 auto widthSum = type.getWidth();
2429 auto domain = type.getDomain();
2430 auto iterMax = widthSum / expr.getSliceSize();
2431 auto remainSize = widthSum % expr.getSliceSize();
2433 for (
size_t i = 0; i < iterMax; i++) {
2434 auto extractResultType = moore::RefType::get(moore::IntType::get(
2435 context.getContext(), expr.getSliceSize(), domain));
2437 auto extracted = moore::ExtractRefOp::create(
2438 builder, loc, extractResultType, value, i * expr.getSliceSize());
2439 slicedOperands.push_back(extracted);
2443 auto extractResultType = moore::RefType::get(
2444 moore::IntType::get(
context.getContext(), remainSize, domain));
2447 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
2448 iterMax * expr.getSliceSize());
2449 slicedOperands.push_back(extracted);
2452 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
2456 template <
typename T>
2457 Value visit(T &&node) {
2458 return context.convertRvalueExpression(node);
2461 Value visitInvalid(
const slang::ast::Expression &expr) {
2462 mlir::emitError(loc,
"invalid expression");
2472Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
2473 Type requiredType) {
2475 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
2476 if (value && requiredType)
2484 return expr.visit(LvalueExprVisitor(*
this, loc));
2492 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
2493 if (type.getBitSize() == 1)
2495 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
2496 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
2497 mlir::emitError(value.getLoc(),
"expression of type ")
2498 << value.getType() <<
" cannot be cast to a boolean";
2504 const slang::ast::Type &astType,
2506 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2510 if (svreal.isShortReal() &&
2511 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2512 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2513 }
else if (svreal.isReal() &&
2514 floatType->floatKind == slang::ast::FloatingType::Real) {
2515 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2517 mlir::emitError(loc) <<
"invalid real constant";
2521 return moore::ConstantRealOp::create(
builder, loc, attr);
2526 const slang::ast::Type &astType,
2528 slang::ConstantValue intVal = stringLiteral.convertToInt();
2529 auto effectiveWidth = intVal.getEffectiveWidth();
2530 if (!effectiveWidth)
2533 auto intTy = moore::IntType::getInt(
getContext(), effectiveWidth.value());
2535 if (astType.isString()) {
2536 auto immInt = moore::ConstantStringOp::create(
builder, loc, intTy,
2537 stringLiteral.toString())
2539 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2546 const slang::ast::Type &astType, Location loc) {
2551 bool typeIsFourValued =
false;
2552 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2556 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2557 fvint.hasUnknown() || typeIsFourValued
2560 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2565 const slang::ConstantValue &constant,
2566 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2574 if (astType.elementType.isIntegral())
2575 bitWidth = astType.elementType.getBitWidth();
2579 bool typeIsFourValued =
false;
2582 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2593 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2595 auto arrType = moore::UnpackedArrayType::get(
2596 getContext(), constant.elements().size(), intType);
2598 llvm::SmallVector<mlir::Value> elemVals;
2599 moore::ConstantOp constOp;
2601 mlir::OpBuilder::InsertionGuard guard(
builder);
2604 for (
auto elem : constant.elements()) {
2606 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2607 elemVals.push_back(constOp.getResult());
2612 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2614 return arrayOp.getResult();
2618 const slang::ast::Type &type, Location loc) {
2620 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
2622 if (constant.isInteger())
2624 if (constant.isReal() || constant.isShortReal())
2626 if (constant.isString())
2634 using slang::ast::EvalFlags;
2635 slang::ast::EvalContext evalContext(
2637 slang::ast::LookupLocation::max),
2638 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
2639 return expr.eval(evalContext);
2648 auto type = moore::IntType::get(
getContext(), 1, domain);
2655 if (isa<moore::IntType>(value.getType()))
2662 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
2663 if (
auto sbvType = packed.getSimpleBitVector())
2666 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
2667 <<
" cannot be cast to a simple bit vector";
2676 if (isa<moore::IntType>(value.getType()))
2679 auto &builder =
context.builder;
2680 auto packedType = cast<moore::PackedType>(value.getType());
2681 auto intType = packedType.getSimpleBitVector();
2686 if (isa<moore::TimeType>(packedType) &&
2688 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
2689 auto scale = moore::ConstantOp::create(builder, loc, intType,
2691 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
2697 if (packedType.containsTimeType()) {
2698 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
2699 <<
" cannot be converted to " << intType
2700 <<
"; contains a time type";
2705 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
2713 Value value, Location loc) {
2714 if (value.getType() == packedType)
2717 auto &builder =
context.builder;
2718 auto intType = cast<moore::IntType>(value.getType());
2723 if (isa<moore::TimeType>(packedType) &&
2725 auto scale = moore::ConstantOp::create(builder, loc, intType,
2727 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
2728 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
2735 mlir::emitError(loc) <<
"unsupported conversion: " << intType
2736 <<
" cannot be converted to " << packedType
2737 <<
"; contains a time type";
2742 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
2748 moore::ClassHandleType expectedHandleTy) {
2749 auto loc = actualHandle.getLoc();
2751 auto actualTy = actualHandle.getType();
2752 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
2753 if (!actualHandleTy) {
2754 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
2760 if (actualHandleTy == expectedHandleTy)
2761 return actualHandle;
2763 if (!
context.isClassDerivedFrom(actualHandleTy, expectedHandleTy)) {
2764 mlir::emitError(loc)
2765 <<
"receiver class " << actualHandleTy.getClassSym()
2766 <<
" is not the same as, or derived from, expected base class "
2767 << expectedHandleTy.getClassSym().getRootReference();
2772 auto casted = moore::ClassUpcastOp::create(
context.builder, loc,
2773 expectedHandleTy, actualHandle)
2781 if (type == value.getType())
2786 auto dstPacked = dyn_cast<moore::PackedType>(type);
2787 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
2788 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
2789 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
2791 if (dstInt && srcInt) {
2799 auto resizedType = moore::IntType::get(
2800 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
2801 if (dstInt.getWidth() < srcInt.getWidth()) {
2802 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
2803 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
2805 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
2807 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
2811 if (dstInt.getDomain() != srcInt.getDomain()) {
2813 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
2815 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
2823 assert(value.getType() == type);
2828 if (isa<moore::StringType>(type) &&
2829 isa<moore::FormatStringType>(value.getType())) {
2830 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
2834 if (isa<moore::FormatStringType>(type) &&
2835 isa<moore::StringType>(value.getType())) {
2836 return builder.createOrFold<moore::FormatStringOp>(loc, value);
2841 if (isa<moore::QueueType>(type) && isa<moore::QueueType>(value.getType()) &&
2842 cast<moore::QueueType>(type).getElementType() ==
2843 cast<moore::QueueType>(value.getType()).getElementType())
2844 return builder.createOrFold<moore::QueueResizeOp>(loc, type, value);
2847 if (isa<moore::QueueType>(type) &&
2848 isa<moore::UnpackedArrayType>(value.getType())) {
2849 auto queueElType = dyn_cast<moore::QueueType>(type).getElementType();
2850 auto unpackedArrayElType =
2851 dyn_cast<moore::UnpackedArrayType>(value.getType()).getElementType();
2853 if (queueElType == unpackedArrayElType) {
2854 return builder.createOrFold<moore::QueueFromUnpackedArrayOp>(loc, type,
2860 if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2861 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
2862 loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2870 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
2873 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
2878 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
2882 return builder.createOrFold<moore::SIntToRealOp>(loc, type, twoValInt);
2883 return builder.createOrFold<moore::UIntToRealOp>(loc, type, twoValInt);
2886 auto getBuiltinFloatType = [&](moore::RealType type) -> Type {
2888 return mlir::Float32Type::get(
builder.getContext());
2890 return mlir::Float64Type::get(
builder.getContext());
2894 if (isa<moore::TimeType>(type) && isa<moore::RealType>(value.getType())) {
2896 moore::IntType::get(
builder.getContext(), 64, Domain::TwoValued);
2898 getBuiltinFloatType(cast<moore::RealType>(value.getType()));
2899 auto scale = moore::ConstantRealOp::create(
2900 builder, loc, value.getType(),
2902 auto scaled =
builder.createOrFold<moore::MulRealOp>(loc, value, scale);
2903 auto asInt = moore::RealToIntOp::create(
builder, loc, intType, scaled);
2904 auto asLogic = moore::IntToLogicOp::create(
builder, loc, asInt);
2905 return moore::LogicToTimeOp::create(
builder, loc, asLogic);
2909 if (isa<moore::RealType>(type) && isa<moore::TimeType>(value.getType())) {
2910 auto asLogic = moore::TimeToLogicOp::create(
builder, loc, value);
2911 auto asInt = moore::LogicToIntOp::create(
builder, loc, asLogic);
2912 auto asReal = moore::UIntToRealOp::create(
builder, loc, type, asInt);
2913 Type floatType = getBuiltinFloatType(cast<moore::RealType>(type));
2914 auto scale = moore::ConstantRealOp::create(
2917 return moore::DivRealOp::create(
builder, loc, asReal, scale);
2921 if (isa<moore::StringType>(type)) {
2922 if (
auto intType = dyn_cast<moore::IntType>(value.getType())) {
2924 value = moore::LogicToIntOp::create(
builder, loc, value);
2925 return moore::IntToStringOp::create(
builder, loc, value);
2930 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2931 if (isa<moore::StringType>(value.getType())) {
2932 value = moore::StringToIntOp::create(
builder, loc, intType.getTwoValued(),
2936 return moore::IntToLogicOp::create(
builder, loc, value);
2943 if (isa<moore::FormatStringType>(type)) {
2945 value, isSigned, loc);
2948 return moore::FormatStringOp::create(
builder, loc, asStr, {}, {}, {});
2951 if (isa<moore::RealType>(type) && isa<moore::RealType>(value.getType()))
2952 return builder.createOrFold<moore::ConvertRealOp>(loc, type, value);
2954 if (isa<moore::ClassHandleType>(type) &&
2955 isa<moore::ClassHandleType>(value.getType()))
2959 if (value.getType() != type)
2960 value = moore::ConversionOp::create(
builder, loc, type, value);
2966template <
typename OpTy>
2969 std::span<const slang::ast::Expression *const> args) {
2971 assert(args.size() == 1 &&
"real math builtin expects 1 argument");
2972 auto value =
context.convertRvalueExpression(*args[0]);
2975 return OpTy::create(
context.builder, loc, value);
2979 const slang::ast::SystemSubroutine &subroutine, Location loc,
2980 std::span<const slang::ast::Expression *const> args) {
2981 using ksn = slang::parsing::KnownSystemName;
2982 StringRef name = subroutine.name;
2983 auto nameId = subroutine.knownNameId;
2984 size_t numArgs = args.size();
2992 if (nameId == ksn::URandom || nameId == ksn::Random) {
2993 auto i32Ty = moore::IntType::getInt(
builder.getContext(), 32);
2994 auto minval = moore::ConstantOp::create(
builder, loc, i32Ty, 0);
2996 moore::ConstantOp::create(
builder, loc, i32Ty, APInt::getAllOnes(32));
3003 return moore::UrandomRangeBIOp::create(
builder, loc, minval, maxval, seed);
3006 if (nameId == ksn::URandomRange) {
3007 auto i32Ty = moore::IntType::getInt(
builder.getContext(), 32);
3017 minval = moore::ConstantOp::create(
builder, loc, i32Ty, 0);
3019 return moore::UrandomRangeBIOp::create(
builder, loc, minval, maxval,
3027 if (nameId == ksn::Time || nameId == ksn::STime || nameId == ksn::RealTime) {
3029 assert(numArgs == 0 &&
"time functions take no arguments");
3030 return moore::TimeBIOp::create(
builder, loc);
3037 if (nameId == ksn::Clog2) {
3039 assert(numArgs == 1 &&
"`$clog2` takes 1 argument");
3046 return moore::Clog2BIOp::create(
builder, loc, value);
3050 if (nameId == ksn::Ln)
3051 return convertRealMathBI<moore::LnBIOp>(*
this, loc, name, args);
3052 if (nameId == ksn::Log10)
3053 return convertRealMathBI<moore::Log10BIOp>(*
this, loc, name, args);
3054 if (nameId == ksn::Exp)
3055 return convertRealMathBI<moore::ExpBIOp>(*
this, loc, name, args);
3056 if (nameId == ksn::Sqrt)
3057 return convertRealMathBI<moore::SqrtBIOp>(*
this, loc, name, args);
3058 if (nameId == ksn::Floor)
3059 return convertRealMathBI<moore::FloorBIOp>(*
this, loc, name, args);
3060 if (nameId == ksn::Ceil)
3061 return convertRealMathBI<moore::CeilBIOp>(*
this, loc, name, args);
3062 if (nameId == ksn::Sin)
3063 return convertRealMathBI<moore::SinBIOp>(*
this, loc, name, args);
3064 if (nameId == ksn::Cos)
3065 return convertRealMathBI<moore::CosBIOp>(*
this, loc, name, args);
3066 if (nameId == ksn::Tan)
3067 return convertRealMathBI<moore::TanBIOp>(*
this, loc, name, args);
3068 if (nameId == ksn::Asin)
3069 return convertRealMathBI<moore::AsinBIOp>(*
this, loc, name, args);
3070 if (nameId == ksn::Acos)
3071 return convertRealMathBI<moore::AcosBIOp>(*
this, loc, name, args);
3072 if (nameId == ksn::Atan)
3073 return convertRealMathBI<moore::AtanBIOp>(*
this, loc, name, args);
3074 if (nameId == ksn::Sinh)
3075 return convertRealMathBI<moore::SinhBIOp>(*
this, loc, name, args);
3076 if (nameId == ksn::Cosh)
3077 return convertRealMathBI<moore::CoshBIOp>(*
this, loc, name, args);
3078 if (nameId == ksn::Tanh)
3079 return convertRealMathBI<moore::TanhBIOp>(*
this, loc, name, args);
3080 if (nameId == ksn::Asinh)
3081 return convertRealMathBI<moore::AsinhBIOp>(*
this, loc, name, args);
3082 if (nameId == ksn::Acosh)
3083 return convertRealMathBI<moore::AcoshBIOp>(*
this, loc, name, args);
3084 if (nameId == ksn::Atanh)
3085 return convertRealMathBI<moore::AtanhBIOp>(*
this, loc, name, args);
3091 if (nameId == ksn::Signed || nameId == ksn::Unsigned) {
3093 assert(numArgs == 1 &&
"`$signed`/`$unsigned` take 1 argument");
3099 if (nameId == ksn::RealToBits)
3100 return convertRealMathBI<moore::RealtobitsBIOp>(*
this, loc, name, args);
3101 if (nameId == ksn::BitsToReal)
3102 return convertRealMathBI<moore::BitstorealBIOp>(*
this, loc, name, args);
3103 if (nameId == ksn::ShortrealToBits)
3104 return convertRealMathBI<moore::ShortrealtobitsBIOp>(*
this, loc, name,
3106 if (nameId == ksn::BitsToShortreal)
3107 return convertRealMathBI<moore::BitstoshortrealBIOp>(*
this, loc, name,
3114 if (nameId == ksn::Len) {
3116 assert(numArgs == 1 &&
"`len` takes 1 argument");
3117 auto stringType = moore::StringType::get(
getContext());
3121 return moore::StringLenOp::create(
builder, loc, value);
3124 if (nameId == ksn::ToUpper) {
3126 assert(numArgs == 1 &&
"`toupper` takes 1 argument");
3127 auto stringType = moore::StringType::get(
getContext());
3131 return moore::StringToUpperOp::create(
builder, loc, value);
3134 if (nameId == ksn::ToLower) {
3136 assert(numArgs == 1 &&
"`tolower` takes 1 argument");
3137 auto stringType = moore::StringType::get(
getContext());
3141 return moore::StringToLowerOp::create(
builder, loc, value);
3144 if (nameId == ksn::Getc) {
3146 assert(numArgs == 2 &&
"`getc` takes 2 arguments");
3147 auto stringType = moore::StringType::get(
getContext());
3152 return moore::StringGetOp::create(
builder, loc, str, index);
3159 if (nameId == ksn::ArraySize) {
3161 assert(numArgs == 1 &&
"`size` takes 1 argument");
3162 if (args[0]->type->isQueue()) {
3166 return moore::QueueSizeBIOp::create(
builder, loc, value);
3168 if (args[0]->type->getCanonicalType().kind ==
3169 slang::ast::SymbolKind::DynamicArrayType) {
3173 return moore::OpenUArraySizeOp::create(
builder, loc, value);
3175 if (args[0]->type->isAssociativeArray()) {
3179 return moore::AssocArraySizeOp::create(
builder, loc, value);
3181 emitError(loc) <<
"unsupported member function `size` on type `"
3182 << args[0]->type->toString() <<
"`";
3186 if (nameId == ksn::Delete) {
3188 assert(numArgs == 1 &&
"`delete` takes 1 argument");
3189 if (args[0]->type->getCanonicalType().kind ==
3190 slang::ast::SymbolKind::DynamicArrayType) {
3194 return moore::OpenUArrayDeleteOp::create(
builder, loc, value);
3196 emitError(loc) <<
"unsupported member function `delete` on type `"
3197 << args[0]->type->toString() <<
"`";
3201 if (nameId == ksn::PopBack) {
3203 assert(numArgs == 1 &&
"`pop_back` takes 1 argument");
3204 assert(args[0]->type->isQueue() &&
"`pop_back` is only valid on queues");
3208 return moore::QueuePopBackOp::create(
builder, loc, value);
3211 if (nameId == ksn::PopFront) {
3213 assert(numArgs == 1 &&
"`pop_front` takes 1 argument");
3214 assert(args[0]->type->isQueue() &&
"`pop_front` is only valid on queues");
3218 return moore::QueuePopFrontOp::create(
builder, loc, value);
3225 if (nameId == ksn::Num) {
3226 if (args[0]->type->isAssociativeArray()) {
3227 assert(numArgs == 1 &&
"`num` takes 1 argument");
3231 return moore::AssocArraySizeOp::create(
builder, loc, value);
3233 emitError(loc) <<
"unsupported system call `" << name <<
"`";
3237 if (nameId == ksn::Exists) {
3239 assert(numArgs == 2 &&
"`exists` takes 2 arguments");
3240 assert(args[0]->type->isAssociativeArray() &&
3241 "`exists` is only valid on associative arrays");
3246 return moore::AssocArrayExistsOp::create(
builder, loc, array, key);
3253 if (nameId == ksn::First || nameId == ksn::Last || nameId == ksn::Next ||
3254 nameId == ksn::Prev) {
3255 if (args[0]->type->isAssociativeArray()) {
3256 assert(numArgs == 2 &&
"traversal methods take 2 arguments");
3261 if (nameId == ksn::First)
3262 return moore::AssocArrayFirstOp::create(
builder, loc, array, key);
3263 if (nameId == ksn::Last)
3264 return moore::AssocArrayLastOp::create(
builder, loc, array, key);
3265 if (nameId == ksn::Next)
3266 return moore::AssocArrayNextOp::create(
builder, loc, array, key);
3267 if (nameId == ksn::Prev)
3268 return moore::AssocArrayPrevOp::create(
builder, loc, array, key);
3269 llvm_unreachable(
"all traversal cases handled above");
3271 emitError(loc) <<
"unsupported system call `" << name <<
"`";
3276 emitError(loc) <<
"unsupported system call `" << name <<
"`";
3282 return context.symbolTable.lookupNearestSymbolFrom(
context.intoModuleOp, sym);
3286 const moore::ClassHandleType &baseTy) {
3287 if (!actualTy || !baseTy)
3290 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
3291 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
3293 if (actualSym == baseSym)
3296 auto *op =
resolve(*
this, actualSym);
3297 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
3300 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
3303 if (curBase == baseSym)
3305 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
3310moore::ClassHandleType
3312 llvm::StringRef fieldName, Location loc) {
3314 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
3318 auto *op =
resolve(*
this, classSym);
3319 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
3324 for (
auto &block : decl.getBody()) {
3325 for (
auto &opInBlock : block) {
3327 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
3328 if (prop.getSymName() == fieldName) {
3330 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
3337 classSym = decl.getBaseAttr();
3341 mlir::emitError(loc) <<
"unknown property `" << fieldName <<
"`";
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 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.
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.
llvm::SmallVector< Value, 4 > captures
bool isCoroutine()
Whether this is a coroutine (task) or a regular function.
mlir::FunctionOpInterface op